diff --git a/src/ast.rs b/src/ast.rs index b50d4ec..c1cbf26 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -3,13 +3,25 @@ pub mod macro_matcher; /// A value with an annotation. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, PartialEq, Eq)] pub struct Anno(pub T, pub A); +impl std::fmt::Debug for Anno { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + ::fmt(&self.1, f)?; + f.write_str(": ")?; + ::fmt(&self.0, f) + } +} + /// An annotation: extra data added on to important AST nodes. pub trait Annotation: Clone + std::fmt::Display + std::fmt::Debug + PartialEq + Eq {} impl Annotation for T {} +// +// TODO: Identifier interning +// + /// A literal value (boolean, character, integer, string) #[derive(Clone, Debug, PartialEq, Eq)] pub enum Literal { @@ -18,7 +30,7 @@ pub enum Literal { /// A character literal: 'a', '\u{1f988}' Char(char), /// An integer literal: 0, 123, 0x10 - Int(i128), + Int(u128), /// A string literal: Str(String), } @@ -66,13 +78,18 @@ pub enum Ty { /// `[..Args, Rety]` Fn(Vec), } +impl Default for Ty { + fn default() -> Self { + Self::Tuple(vec![]) + } +} /// A `let` binding /// ```ignore /// let Pat (= Expr)? /// `````` #[derive(Clone, Debug, PartialEq, Eq)] -pub struct Let(pub Pat, pub Option, A>>); +pub struct Let(pub Pat, pub Vec, A>>); /// A `const` binding (which defines its name before executing) /// ```ignore @@ -86,7 +103,7 @@ pub struct Const(pub Pat, pub Anno, A>); /// fn Ident? (Pat) Expr /// ``` #[derive(Clone, Debug, PartialEq, Eq)] -pub struct Fn(pub Option, pub Pat, pub Anno, A>); +pub struct Fn(pub Option, pub Pat, pub Ty, pub Anno, A>); /// A match expression /// ```ignore @@ -107,7 +124,7 @@ pub struct MatchArm(pub Pat, pub Anno, A>); /// Expr { (Ident (: Expr)?),* } /// ``` #[derive(Clone, Debug, PartialEq, Eq)] -pub struct Make(pub Box, A>>, pub Vec>); +pub struct Make(pub Anno, A>, pub Vec>); /// A single "arm" of a make expression /// ```ignore @@ -154,11 +171,29 @@ pub enum Expr { Op(Op, Vec>), } +impl Default for Expr { + fn default() -> Self { + Self::Op(Op::Tuple, vec![]) + } +} + impl Expr { pub fn anno(self, annotation: A) -> Anno, A> { Anno(self, annotation) } + pub fn and_do(self, annotation: A, other: Anno, A>) -> Self { + let Self::Op(Op::Do, mut exprs) = self else { + return Self::Op(Op::Do, vec![self.anno(annotation), other]); + }; + let Anno(Self::Op(Op::Do, mut other), _) = other else { + exprs.push(other); + return Self::Op(Op::Do, exprs); + }; + exprs.append(&mut other); + Self::Op(Op::Do, exprs) + } + pub fn is_place(&self) -> bool { matches!( self, @@ -271,17 +306,20 @@ impl Display for Const { impl Display for Fn { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { - Self(Some(name), pat, expr) => write!(f, "fn {name} {pat} {expr}"), - Self(None, pat, expr) => write!(f, "|{pat}| {expr}"), + Self(Some(name), pat, rety, expr) => write!(f, "fn {name} {pat} -> {rety} {expr}"), + Self(None, pat, rety, expr) => write!(f, "|{pat}| -> {rety} {expr}"), } } } impl Display for Let { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - Self(pat, Some(expr)) => write!(f, "let {pat} = {expr}"), - Self(pat, None) => write!(f, "let ({pat})"), + let Self(pat, exprs) = self; + match exprs.as_slice() { + [] => write!(f, "let {pat}"), + [value] => write!(f, "let {pat} = {value}"), + [value, fail] => write!(f, "let {pat} = {value} else {fail}"), + other => f.delimit(fmt!("let! {pat} ("), ")").list(other, ", "), } } } @@ -314,7 +352,7 @@ impl Display for Struct { match pat { Pat::Struct(name, bind) => match bind.as_ref() { Pat::Tuple(parts) => f - .delimit_indented(fmt!("{name} {{"), "}") + .delimit_indented(fmt!("struct {name} {{"), "}") .list_wrap("\n", parts, ",\n", ",\n"), other => write!(f, "{name} {{ {other} }}"), }, @@ -338,6 +376,9 @@ impl Display for Expr { Self::Fn(v) => v.fmt(f), Self::Op(op @ (Op::If | Op::While), exprs) => match exprs.as_slice() { + [cond, pass, Anno(Expr::Op(Op::Tuple, e), _)] if e.is_empty() => { + write!(f, "{op}{cond} {pass}") + } [cond, pass, fail] => write!(f, "{op}{cond} {pass} else {fail}"), other => f.delimit(fmt!("({op}, "), ")").list(other, ", "), }, diff --git a/src/ast/macro_matcher.rs b/src/ast/macro_matcher.rs index 93cbd7e..946bb76 100644 --- a/src/ast/macro_matcher.rs +++ b/src/ast/macro_matcher.rs @@ -93,14 +93,17 @@ impl Match for Const { impl Match for Fn { fn recurse(sub: &mut Subst, pat: &Self, expr: &Self) -> bool { - let (Self(pat_id, pat_arg, pat_body), Self(expr_id, expr_arg, expr_body)) = (pat, expr); + let ( + Self(pat_id, pat_arg, _pat_rety, pat_body), + Self(expr_id, expr_arg, _expr_rety, expr_body), + ) = (pat, expr); pat_id == expr_id && Match::recurse(sub, pat_arg, expr_arg) && Match::recurse(sub, pat_body, expr_body) } fn apply(&mut self, sub: &Subst) { - let Self(_, pat, body) = self; + let Self(_, pat, _rety, body) = self; pat.apply(sub); body.apply(sub); } diff --git a/src/parser.rs b/src/parser.rs index ffe2334..bdd5f88 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -200,15 +200,14 @@ impl<'t> Parse<'t> for Literal { .expect("should have one char in char literal"), ), TKind::Integer => { - let Token { lexeme, kind: _, span } = p.take().expect("should have Token"); - // TODO: more complex int parsing - let int = lexeme - .int() - .ok_or(ParseError::Expected(TKind::Integer, span))?; - Literal::Int(int as _) + let Token { lexeme, span, .. } = p.take().expect("should have Token"); + let Lexeme::Integer(int, _) = lexeme else { + Err(ParseError::Expected(TKind::Integer, span))? + }; + Literal::Int(int) } TKind::String => Literal::Str({ - let Token { lexeme, kind: _, span } = p.take().expect("should have Token"); + let Token { lexeme, span, .. } = p.take().expect("should have Token"); lexeme .string() .ok_or(ParseError::Expected(TKind::String, span))? @@ -368,7 +367,10 @@ impl<'t> Parse<'t> for Ty { _ => Err(ParseError::NotType(tok.kind, tok.span))?, }; - Ok(head) + Ok(match p.next_if(TKind::Arrow) { + Ok(_) => Ty::Fn(vec![head, p.parse(())?]), + _ => head, + }) } } @@ -435,21 +437,23 @@ impl Prec { /// PseudoOperator: fake operators used to give certain tokens special behavior. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Ps { - Id, // Identifier - Mid, // MetaIdentifier - Lit, // Literal - Let, // let Pat = Expr - Const, // const Pat = Expr - Struct, // struct { Pat } | struct ( Pat ) - Fn, // fn ( Pat,* ) Expr - Lambda0, // || Expr - Lambda, // | Pat,* | Expr - DoubleRef, // && Expr - Make, // Expr{ Expr,* } - Match, // match Expr { MatchArm,* } - Mod, // mod Ty Expr - End, // Produces an empty value. - Op(Op), // A normal [ast::Op] + Id, // Identifier + Mid, // MetaIdentifier + Lit, // Literal + Let, // let Pat = Expr + Const, // const Pat = Expr + Struct, // struct { Pat } | struct ( Pat ) + For, // for Pat in Expr Expr else Expr + Fn, // fn ( Pat,* ) Expr + Lambda0, // || Expr + Lambda, // | Pat,* | Expr + DoubleRef, // && Expr + Make, // Expr{ Expr,* } + Match, // match Expr { MatchArm,* } + Mod, // mod Ty Expr + ImplicitDo, // An implicit semicolon + End, // Produces an empty value. + Op(Op), // A normal [ast::Op] } fn from_prefix(token: &Token) -> PResult<(Ps, Prec)> { @@ -464,6 +468,7 @@ fn from_prefix(token: &Token) -> PResult<(Ps, Prec)> { } TKind::Public => (Ps::Op(Op::Pub), Prec::Body), + TKind::For => (Ps::For, Prec::Body), TKind::Fn => (Ps::Fn, Prec::Body), TKind::Match => (Ps::Match, Prec::Body), TKind::Macro => (Ps::Op(Op::Macro), Prec::Assign), @@ -533,6 +538,22 @@ fn from_infix(token: &Token) -> PResult<(Ps, Prec)> { TKind::Star => (Ps::Op(Op::Mul), Prec::Term), TKind::Slash => (Ps::Op(Op::Div), Prec::Term), TKind::Rem => (Ps::Op(Op::Rem), Prec::Term), + + TKind::True + | TKind::False + | TKind::Character + | TKind::Integer + | TKind::String + | TKind::Identifier + | TKind::Public + | TKind::Module + | TKind::Fn + | TKind::Do + | TKind::While + | TKind::If + | TKind::For + | TKind::Break + | TKind::Return => (Ps::ImplicitDo, Prec::Do), kind => Err(ParseError::NotInfix(kind, token.span))?, }) } @@ -565,6 +586,7 @@ impl<'t> Parse<'t> for Fn { Ok(Token { lexeme, .. }) => Ok(Self( lexeme.string(), p.parse(PPrec::Typed)?, + p.opt_if((), TKind::Arrow)?.unwrap_or_default(), p.parse(Prec::Body.next())?, )), _ => Ok(Self( @@ -575,6 +597,7 @@ impl<'t> Parse<'t> for Fn { TKind::Comma, TKind::RParen, )?), + p.opt_if((), TKind::Arrow)?.unwrap_or_default(), p.parse(Prec::Body.next())?, )), } @@ -585,10 +608,17 @@ impl<'t> Parse<'t> for Let { type Prec = (); fn parse(p: &mut Parser<'t>, _level: Self::Prec) -> PResult { - Ok(Self( - p.consume().parse(PPrec::Alt)?, - p.opt_if(Prec::Tuple.value(), TKind::Eq)?, - )) + let pat = p.consume().parse(PPrec::Tuple)?; + if p.next_if(TKind::Eq).is_err() { + return Ok(Self(pat, vec![])); + } + + let body = p.parse(Prec::Tuple.value())?; + if p.next_if(TKind::Else).is_err() { + return Ok(Self(pat, vec![body])); + } + + Ok(Self(pat, vec![body, p.parse(Prec::Body.next())?])) } } @@ -634,10 +664,106 @@ impl<'t> Parse<'t> for MakeArm { impl<'t> Parse<'t> for Mod { type Prec = (); fn parse(p: &mut Parser<'t>, _level: Self::Prec) -> PResult { - Ok(Mod(p.consume().parse(())?, p.parse(Prec::Body.value())?)) + let ty = p.consume().parse(())?; + let body = p.parse(Prec::Body.value())?; + Ok(Mod(ty, body)) } } +fn parse_for<'t>(p: &mut Parser<'t>, _level: ()) -> PResult { + // for Pat + let pat = p.consume().parse(PPrec::Tuple)?; + // in Expr + let iter: Anno = p.consume_if(TKind::In)?.parse(Prec::Logical.next())?; + let cspan = iter.1; + // Expr + let pass: Anno = p.parse(Prec::Body.next())?; + let pspan = pass.1; + // else Expr? + let fail = match p.next_if(TKind::Else) { + Ok(_) => p.parse(Prec::Body.next())?, + _ => Expr::Op(Op::Tuple, vec![]).anno(pspan), + }; + let fspan = fail.1; + /* + for `pat in `iter `pass else `fail + ==> + match (`iter).into_iter() { + #iter => loop match #iter.next() { + None => break `fail, + Some(`pat) => `pass, + }, + } + */ + // let mut tmp_p = Parser::new(Lexer::new( + // "match `iter.into_iter() { + // `iterator => loop match `iterator.next() { + // None => break `fail, + // Some(`pat) => `pass, + // }, + // }", + // )); + + // let mut template: Expr = tmp_p.parse(Prec::MIN)?; + + // let mut subst = Subst:: { exp: Default::default(), pat: Default::default() }; + // subst.exp.extend([ + // ("iterator".into(), Expr::Id("#iter".into())), + // ("iter".into(), iter.0), + // ("fail".into(), fail.0), + // ("pass".into(), pass.0), + // ]); + // subst.pat.extend([ + // ("iterator".into(), Pat::Name("#iter".into())), + // ("pat".into(), pat), + // ]); + + // template.apply(&subst); + // Ok(template) + + Ok(Expr::Match(Box::new(Match( + Expr::Op( + Op::Dot, + vec![ + iter, + Expr::Op(Op::Call, vec![Expr::Id("into_iter".into()).anno(cspan)]).anno(cspan), + ], + ) + .anno(cspan), + vec![MatchArm( + Pat::Name("#iter".into()), + Expr::Op( + Op::Loop, + vec![ + Expr::Match(Box::new(Match( + Expr::Op( + Op::Dot, + vec![ + Expr::Id("#iter".into()).anno(cspan), + Expr::Op(Op::Call, vec![Expr::Id("next".into()).anno(cspan)]) + .anno(cspan), + ], + ) + .anno(cspan), + vec![ + MatchArm( + Pat::Name("None".into()), + Expr::Op(Op::Break, vec![fail]).anno(fspan), + ), + MatchArm( + Pat::TupStruct("Some".into(), Box::new(Pat::Tuple(vec![pat]))), + pass, + ), + ], + ))) + .anno(pspan), + ], + ) + .anno(pspan), + )], + )))) +} + impl<'t> Parse<'t> for Expr { type Prec = usize; @@ -662,6 +788,7 @@ impl<'t> Parse<'t> for Expr { Ps::Mid => Expr::MetId(p.consume().next()?.lexeme.to_string()), Ps::Lit => Expr::Lit(p.parse(())?), Ps::Let => Expr::Let(p.parse(())?), + Ps::For => parse_for(p, ())?, Ps::Const => Expr::Const(p.parse(())?), Ps::Struct => Expr::Struct(p.parse(())?), Ps::Match => Expr::Match(p.parse(())?), @@ -694,11 +821,15 @@ impl<'t> Parse<'t> for Expr { p.consume() .opt(PPrec::Tuple, TKind::Bar)? .unwrap_or(Pat::Tuple(vec![])), + p.opt_if((), TKind::Arrow)?.unwrap_or_default(), + p.parse(Prec::Body.next())?, + ))), + Ps::Lambda0 => Expr::Fn(Box::new(Fn( + None, + Pat::Tuple(vec![]), + p.consume().opt_if((), TKind::Arrow)?.unwrap_or_default(), p.parse(Prec::Body.next())?, ))), - Ps::Lambda0 => Expr::Fn(Box::new(Fn(None, Pat::Tuple(vec![]), { - p.consume().parse(Prec::Body.next())? - }))), Ps::DoubleRef => p.consume().parse(prec.next()).map(|Anno(expr, span)| { Expr::Op( Op::Refer, @@ -724,12 +855,14 @@ impl<'t> Parse<'t> for Expr { Ps::Make => match &head { Expr::Op(Op::Path, _) | Expr::Id(_) | Expr::MetId(_) => { Expr::Make(Box::new(Make( - head.anno(span).into(), + head.anno(span), p.consume().list(vec![], (), TKind::Comma, TKind::RCurly)?, ))) } _ => break, }, + Ps::Op(Op::Do) => head.and_do(span, p.consume().parse(prec.next())?), + Ps::ImplicitDo => head.and_do(span, p.parse(prec.next())?), Ps::Op(Op::Index) => Expr::Op( Op::Index, p.consume() @@ -740,13 +873,11 @@ impl<'t> Parse<'t> for Expr { p.consume() .list(vec![head.anno(span)], 0, TKind::Comma, TKind::RParen)?, ), - Ps::Op(op @ (Op::Do | Op::Tuple | Op::Dot | Op::Path | Op::LogAnd | Op::LogOr)) => { - Expr::Op( - op, - p.consume() - .list_bare(vec![head.anno(span)], prec.next(), kind)?, - ) - } + Ps::Op(op @ (Op::Tuple | Op::Dot | Op::Path | Op::LogAnd | Op::LogOr)) => Expr::Op( + op, + p.consume() + .list_bare(vec![head.anno(span)], prec.next(), kind)?, + ), Ps::Op(op @ Op::Try) => { p.consume(); Expr::Op(op, vec![head.anno(span)])