From 8640ec4261ba2851e98e824bacacdd700e6e31e2 Mon Sep 17 00:00:00 2001 From: John Date: Sun, 21 Sep 2025 02:57:20 -0400 Subject: [PATCH] ast: `fn main`, structification parser: unified post/infix, context-full grammar repl: modes --- src/ast.rs | 76 +++++++++--- src/ast/macro_matcher.rs | 82 +++++++++---- src/main.rs | 93 ++++++++++++--- src/parser.rs | 242 ++++++++++++++++++++++----------------- 4 files changed, 342 insertions(+), 151 deletions(-) diff --git a/src/ast.rs b/src/ast.rs index 81dde31..d27f1e2 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -58,7 +58,7 @@ pub struct MakeArm(pub String, pub Option, A> /// (Pat |)* Pat? => Expr /// ``` #[derive(Clone, Debug, PartialEq, Eq)] -pub struct MatchArm(pub Vec, pub Anno, A>); +pub struct MatchArm(pub Pat, pub Anno, A>); /// In-universe types #[derive(Clone, Debug, PartialEq, Eq)] @@ -77,6 +77,22 @@ pub enum Ty { Fn(Vec), } +/// A `const` binding (which defines its name before executing) +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Const(pub Pat, pub Anno, A>); + +/// A function definition `fn Ident? (Pat,*) Expr` +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Fn(pub Option, pub Pat, pub Anno, A>); + +/// A `let` binding: `let Pat (= Expr)?` +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Let(pub Pat, pub Option, A>>); + +/// `match Expr { MatchArm,* }`` +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Match(pub Anno, A>, pub Vec>); + /// Expressions: The beating heart of Dough #[derive(Clone, Debug, PartialEq, Eq)] pub enum Expr { @@ -87,15 +103,15 @@ pub enum Expr { /// A literal bool, string, char, or int Lit(Literal), /// let Pat = expr - Let(Pat, Option>>), + Let(Box>), /// `const Pat (= Expr)?` (Basically let rec) - Const(Pat, Box>), - /// `| Pat | Expr` | `|| Expr` | `fn (Pat,*) Expr` - Fn(Pat, Box>), + Const(Box>), + /// `| Pat | Expr` | `|| Expr` | `fn Ident? (Pat,*) Expr` + Fn(Box>), /// Expr { (Ident (: Expr)?),* } Make(Box>, Vec>), /// match Expr { MatchArm,* } - Match(Box>, Vec>), + Match(Box>), /// Op Expr | Expr Op | Expr (Op Expr)+ | Op Expr Expr else Expr Op(Op, Vec>), } @@ -205,22 +221,52 @@ impl Display for Anno { } } +impl Display for Const { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Self(pat, expr) = self; + write!(f, "const {pat} = {expr}") + } +} + +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}"), + } + } +} + +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})"), + } + } +} + +impl Display for Match { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let Self(expr, match_arms) = self; + f.delimit_indented(fmt!("match {expr} {{"), "}") + .list_wrap("\n", match_arms, ",\n", ",\n") + } +} + impl Display for Expr { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::Id(id) => id.fmt(f), Self::MetId(id) => write!(f, "`{id}"), Self::Lit(literal) => literal.fmt(f), - Self::Let(pat, Some(expr)) => write!(f, "let {pat} = {expr}"), - Self::Let(pat, None) => write!(f, "let ({pat})"), - Self::Const(pat, expr) => write!(f, "const {pat} = {expr}"), + Self::Let(v) => v.fmt(f), + Self::Const(v) => v.fmt(f), Self::Make(expr, make_arms) => { f.delimit(fmt!("({expr} {{"), "})").list(make_arms, ", ") } - Self::Match(expr, match_arms) => f - .delimit_indented(fmt!("match {expr} {{"), "}") - .list_wrap("\n", match_arms, ",\n", ",\n"), - Self::Fn(pat, expr) => write!(f, "fn {pat} {expr}"), + Self::Match(v) => v.fmt(f), + Self::Fn(v) => v.fmt(f), Self::Op(op @ (Op::If | Op::While), exprs) => match exprs.as_slice() { [cond, pass, fail] => write!(f, "{op}{cond} {pass} else {fail}"), @@ -315,8 +361,8 @@ impl Display for MakeArm { impl Display for MatchArm { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let Self(pats, expr) = self; - f.delimit("", fmt!(" => {expr}")).list(pats, " | ") + let Self(pat, expr) = self; + write!(f, "{pat} => {expr}") } } diff --git a/src/ast/macro_matcher.rs b/src/ast/macro_matcher.rs index 25dce0e..db1cd1a 100644 --- a/src/ast/macro_matcher.rs +++ b/src/ast/macro_matcher.rs @@ -78,6 +78,60 @@ impl + Annotation, A: Annotation> Match for Anno { } } +impl Match for Const { + fn recurse(sub: &mut Subst, pat: &Self, expr: &Self) -> bool { + let (Self(pat_pat, pat_expr), Self(expr_pat, expr_expr)) = (pat, expr); + Match::recurse(sub, pat_pat, expr_pat) && Match::recurse(sub, pat_expr, expr_expr) + } + + fn apply(&mut self, sub: &Subst) { + let Self(pat, expr) = self; + pat.apply(sub); + expr.apply(sub); + } +} + +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); + 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; + pat.apply(sub); + body.apply(sub); + } +} + +impl Match for Let { + fn recurse(sub: &mut Subst, pat: &Self, expr: &Self) -> bool { + let (Self(pat_pat, pat_expr), Self(expr_pat, expr_expr)) = (pat, expr); + Match::recurse(sub, pat_pat, expr_pat) && Match::recurse(sub, pat_expr, expr_expr) + } + + fn apply(&mut self, sub: &Subst) { + let Self(pat, expr) = self; + pat.apply(sub); + expr.apply(sub); + } +} + +impl Match for crate::ast::Match { + fn recurse(sub: &mut Subst, pat: &Self, expr: &Self) -> bool { + let (Self(pat_expr, pat_arms), Self(expr_expr, expr_arms)) = (pat, expr); + Match::recurse(sub, pat_expr, expr_expr) && Match::recurse(sub, pat_arms, expr_arms) + } + + fn apply(&mut self, sub: &Subst) { + let Self(pat, expr) = self; + pat.apply(sub); + expr.apply(sub); + } +} + impl Match for Expr { fn recurse(sub: &mut Subst, pat: &Self, expr: &Self) -> bool { match (pat, expr) { @@ -87,25 +141,17 @@ impl Match for Expr { (Expr::Id(_), _) => false, (Expr::Lit(pat), Expr::Lit(expr)) => pat == expr, (Expr::Lit(_), _) => false, - (Expr::Let(pat_pat, pat_expr), Expr::Let(expr_pat, expr_expr)) => { - Match::recurse(sub, pat_pat, expr_pat) && Match::recurse(sub, pat_expr, expr_expr) - } + (Expr::Let(pat), Expr::Let(expr)) => Match::recurse(sub, pat, expr), (Expr::Let(..), _) => false, - (Expr::Const(pat_pat, pat_expr), Expr::Const(expr_pat, expr_expr)) => { - Match::recurse(sub, pat_pat, expr_pat) && Match::recurse(sub, pat_expr, expr_expr) - } + (Expr::Const(pat), Expr::Const(expr)) => Match::recurse(sub, pat, expr), (Expr::Const(..), _) => false, (Expr::Make(pat, pat_arms), Expr::Make(expr, expr_arms)) => { Match::recurse(sub, pat, expr) && Match::recurse(sub, pat_arms, expr_arms) } (Expr::Make(..), _) => false, - (Expr::Match(pat, pat_arms), Expr::Match(expr, expr_arms)) => { - Match::recurse(sub, pat, expr) && Match::recurse(sub, pat_arms, expr_arms) - } + (Expr::Match(pat), Expr::Match(expr)) => Match::recurse(sub, pat, expr), (Expr::Match(..), _) => false, - (Expr::Fn(pat_pats, pat_expr), Expr::Fn(expr_pats, expr_expr)) => { - Match::recurse(sub, pat_pats, expr_pats) && Match::recurse(sub, pat_expr, expr_expr) - } + (Expr::Fn(pat), Expr::Fn(expr)) => Match::recurse(sub, pat, expr), (Expr::Fn(..), _) => false, (Expr::Op(pat_op, pat_exprs), Expr::Op(expr_op, expr_exprs)) => { Match::recurse(sub, pat_op, expr_op) && Match::recurse(sub, pat_exprs, expr_exprs) @@ -122,24 +168,20 @@ impl Match for Expr { } } Expr::Id(_) | Expr::Lit(_) => {} - Expr::Let(pat, expr) => { - pat.apply(sub); + Expr::Let(expr) => { expr.apply(sub); } - Expr::Const(pat, expr) => { - pat.apply(sub); + Expr::Const(expr) => { expr.apply(sub); } Expr::Make(expr, make_arms) => { expr.apply(sub); make_arms.apply(sub); } - Expr::Match(expr, match_arms) => { + Expr::Match(expr) => { expr.apply(sub); - match_arms.apply(sub); } - Expr::Fn(pats, expr) => { - pats.apply(sub); + Expr::Fn(expr) => { expr.apply(sub); } Expr::Op(op, exprs) => { diff --git a/src/main.rs b/src/main.rs index 724ae62..cc80380 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,4 +1,8 @@ //! Tests the lexer +use doughlang::{ + ast::{Anno, Pat}, + parser::PPrec, +}; #[allow(unused_imports)] use doughlang::{ ast::{ @@ -25,7 +29,19 @@ fn main() -> Result<(), Box> { print!("\x1b[H\x1b[2J"); Ok(Response::Deny) } + "lex" => { + lex()?; + Ok(Response::Deny) + } + "expr" => { + exprs()?; + Ok(Response::Deny) + } "pat" => { + pats()?; + Ok(Response::Deny) + } + "macro" => { if let Err(e) = subst() { println!("\x1b[31m{e}\x1b[0m"); } @@ -38,28 +54,79 @@ fn main() -> Result<(), Box> { })?; } else { let doc = std::io::read_to_string(stdin())?; - lex(&doc); + // lex(&doc); parse(&doc); } Ok(()) } -fn lex(document: &str) { - let mut lexer = Lexer::new(document); - loop { - match lexer.scan() { - Ok(Token { lexeme, kind, span: Span { head, tail } }) => { - println!( +fn lex() -> Result<(), Box> { + read_and("\x1b[93m", " >", "?>", |line| { + let mut lexer = Lexer::new(line); + if line.trim().is_empty() { + return Ok(Response::Break); + } + loop { + match lexer.scan() { + Err(LexError { res: "EOF", .. }) => { + break Ok(Response::Accept); + } + Err(e) => { + println!("\x1b[31m{e}\x1b[0m"); + break Ok(Response::Deny); + } + Ok(Token { lexeme, kind, span: Span { head, tail } }) => println!( "{kind:?}\x1b[11G {head:<4} {tail:<4} {}", lexeme.escape_debug() - ) - } - Err(e) => { - eprintln!("{e}"); - break; + ), } } - } + })?; + Ok(()) +} + +fn exprs() -> Result<(), Box> { + read_and("\x1b[93m", " >", "?>", |line| { + let mut parser = Parser::new(Lexer::new(line)); + if line.trim().is_empty() { + return Ok(Response::Break); + } + loop { + match parser.parse::>(0) { + Err(ParseError::FromLexer(LexError { res: "EOF", .. })) => { + break Ok(Response::Accept); + } + Err(e) => { + println!("\x1b[31m{e}\x1b[0m"); + break Ok(Response::Deny); + } + Ok(v) => println!("{v}\n{v:#?}"), + } + } + })?; + Ok(()) +} + +fn pats() -> Result<(), Box> { + read_and("\x1b[94m", " >", "?>", |line| { + let mut parser = Parser::new(Lexer::new(line)); + if line.trim().is_empty() { + return Ok(Response::Break); + } + loop { + match parser.parse::(PPrec::Max) { + Err(ParseError::FromLexer(LexError { res: "EOF", .. })) => { + break Ok(Response::Accept); + } + Err(e) => { + println!("\x1b[31m{e}\x1b[0m"); + break Ok(Response::Deny); + } + Ok(v) => println!("{v}\n{v:#?}"), + } + } + })?; + Ok(()) } fn subst() -> Result<(), Box> { diff --git a/src/parser.rs b/src/parser.rs index e89cabe..a65d731 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -121,6 +121,7 @@ impl<'t> Parser<'t> { sep: TKind, end: TKind, ) -> PResult> { + // TODO: This loses lexer errors while self.peek_if(end).is_none() { elems.push(self.parse(level)?); if self.next_if(sep).is_err() { @@ -167,6 +168,11 @@ impl<'t> Parser<'t> { Ok(out) } + pub fn consume_if(&mut self, next: TKind) -> PResult<&mut Self> { + self.next_if(next)?; + Ok(self) + } + /// Consumes the currently peeked token without returning it. pub fn consume(&mut self) -> &mut Self { self.next_tok = None; @@ -217,6 +223,18 @@ pub enum PPrec { Max, } +impl PPrec { + fn next(self) -> Self { + match self { + Self::Min => Self::Min, + Self::Typed => Self::Min, + Self::Tuple => Self::Typed, + Self::Alt => Self::Tuple, + Self::Max => Self::Alt, + } + } +} + impl<'t> Parse<'t> for Pat { type Prec = PPrec; fn parse(p: &mut Parser<'t>, level: PPrec) -> PResult { @@ -240,13 +258,13 @@ impl<'t> Parse<'t> for Pat { TKind::LParen => { Pat::Tuple( p.consume() - .list(vec![], PPrec::Tuple, TKind::Comma, TKind::RParen)?, + .list(vec![], PPrec::Max, TKind::Comma, TKind::RParen)?, ) } TKind::LBrack => { Pat::Slice( p.consume() - .list(vec![], PPrec::Tuple, TKind::Comma, TKind::RBrack)?, + .list(vec![], PPrec::Max, TKind::Comma, TKind::RBrack)?, ) } _ => Err(ParseError::NotPattern(tok.kind, tok.span))?, @@ -257,14 +275,16 @@ impl<'t> Parse<'t> for Pat { let kind = tok.kind; head = match kind { - TKind::Colon if level > PPrec::Typed => { + TKind::Colon if level >= PPrec::Typed => { Pat::Typed(head.into(), p.consume().parse(())?) } - TKind::Comma if level > PPrec::Tuple => { - Pat::Tuple(p.consume().list_bare(vec![head], PPrec::Tuple, kind)?) - } - TKind::Bar if level > PPrec::Alt => { - Pat::Alt(p.consume().list_bare(vec![head], PPrec::Alt, kind)?) + TKind::Comma if level >= PPrec::Tuple => Pat::Tuple(p.consume().list_bare( + vec![head], + PPrec::Tuple.next(), + kind, + )?), + TKind::Bar if level >= PPrec::Alt => { + Pat::Alt(p.consume().list_bare(vec![head], PPrec::Alt.next(), kind)?) } _ => break, } @@ -305,32 +325,9 @@ impl<'t> Parse<'t> for Ty { } } -impl<'t> Parse<'t> for MatchArm { - type Prec = usize; - fn parse(p: &mut Parser<'t>, level: usize) -> PResult { - p.next_if(TKind::Bar).ok(); - Ok(MatchArm( - p.list(vec![], PPrec::Max, TKind::Bar, TKind::FatArrow)?, - p.parse(level)?, - )) - } -} - -impl<'t> Parse<'t> for MakeArm { - type Prec = (); - fn parse(p: &mut Parser<'t>, _level: ()) -> PResult { - Ok(MakeArm(p.next_if(TKind::Identifier)?.lexeme, { - p.next_if(TKind::Colon) - .ok() - .map(|_| p.parse(Prec::Min.value())) - .transpose()? - })) - } -} - /// Organizes the precedence hierarchy for syntactic elements #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] -enum Prec { +pub enum Prec { Min, /// The Semicolon Operator gets its own precedence level Do, @@ -462,7 +459,7 @@ fn from_infix(token: &Token) -> PResult<(Ps, Prec)> { TKind::Question => (Ps::Op(Op::Try), Prec::Unary), TKind::LParen => (Ps::Op(Op::Call), Prec::Extend), TKind::LBrack => (Ps::Op(Op::Index), Prec::Extend), - // TKind::LCurly => (Ps::Make, Prec::Make), + TKind::LCurly => (Ps::Make, Prec::Make), TKind::RParen | TKind::RBrack | TKind::RCurly => (Ps::End, Prec::Max), TKind::Eq => (Ps::Op(Op::Set), Prec::Assign), TKind::XorXor => (Ps::Op(Op::LogXor), Prec::Logical), @@ -488,13 +485,79 @@ fn from_infix(token: &Token) -> PResult<(Ps, Prec)> { }) } -#[allow(clippy::match_single_binding, unused)] -fn from_postfix(token: &Token) -> PResult<(Ps, Prec)> { - Ok(match token.kind { - TKind::LCurly => (Ps::Make, Prec::Make), - kind => Err(ParseError::NotPostfix(kind, token.span))?, - // _ => (Ps::End, Prec::Max), - }) +impl<'t> Parse<'t> for Const { + type Prec = (); + + fn parse(p: &mut Parser<'t>, _level: Self::Prec) -> PResult { + Ok(Self( + p.consume().parse(PPrec::Alt)?, + p.consume_if(TKind::Eq)?.parse(Prec::Tuple.value())?, + )) + } +} + +impl<'t> Parse<'t> for Fn { + type Prec = (); + + fn parse(p: &mut Parser<'t>, _level: Self::Prec) -> PResult { + Ok(Self( + p.consume() + .next_if(TKind::Identifier) + .map(|id| id.lexeme) + .ok(), + Pat::Tuple(p.consume_if(TKind::LParen)?.list( + vec![], + PPrec::Tuple, + TKind::Comma, + TKind::RParen, + )?), + p.parse(Prec::Body.next())?, + )) + } +} + +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)?, + )) + } +} + +impl<'t> Parse<'t> for Match { + type Prec = (); + + fn parse(p: &mut Parser<'t>, _level: Self::Prec) -> PResult { + Ok(Self(p.consume().parse(Prec::Logical.value())?, { + p.next_if(TKind::LCurly)?; + p.list(vec![], Prec::Body.next(), TKind::Comma, TKind::RCurly)? + })) + } +} +impl<'t> Parse<'t> for MatchArm { + type Prec = usize; + fn parse(p: &mut Parser<'t>, level: usize) -> PResult { + p.next_if(TKind::Bar).ok(); + Ok(MatchArm( + p.parse(PPrec::Max)?, + p.consume_if(TKind::FatArrow)?.parse(level)?, + )) + } +} + +impl<'t> Parse<'t> for MakeArm { + type Prec = (); + fn parse(p: &mut Parser<'t>, _level: ()) -> PResult { + Ok(MakeArm(p.next_if(TKind::Identifier)?.lexeme, { + p.next_if(TKind::Colon) + .ok() + .map(|_| p.parse(Prec::Body.value())) + .transpose()? + })) + } } impl<'t> Parse<'t> for Expr { @@ -520,14 +583,8 @@ impl<'t> Parse<'t> for Expr { Ps::Id => Expr::Id(p.take_lexeme().expect("should have ident")), Ps::Mid => Expr::MetId(p.consume().next()?.lexeme), Ps::Lit => Expr::Lit(p.parse(())?), - Ps::Let => Expr::Let( - p.consume().parse(PPrec::Alt)?, - p.opt_if(prec.value(), TKind::Eq)?, - ), - Ps::Const => Expr::Const(p.consume().parse(PPrec::Tuple)?, { - p.next_if(TKind::Eq)?; - p.parse(prec.next())? - }), + Ps::Let => Expr::Let(p.parse(())?), + Ps::Const => Expr::Const(p.parse(())?), Ps::Op(Op::Macro) => Expr::Op( Op::Macro, vec![p.consume().parse(prec.next())?, { @@ -535,10 +592,7 @@ impl<'t> Parse<'t> for Expr { p.parse(prec.next())? }], ), - Ps::Match => Expr::Match(p.consume().parse(Prec::Logical.value())?, { - p.next_if(TKind::LCurly)?; - p.list(vec![], prec.next(), TKind::Comma, TKind::RCurly)? - }), + Ps::Match => Expr::Match(p.parse(())?), Ps::Op(Op::Block) => Expr::Op( Op::Block, p.consume().opt(MIN, TKind::RCurly)?.into_iter().collect(), @@ -564,27 +618,17 @@ impl<'t> Parse<'t> for Expr { ]; Expr::Op(op, exprs) } - Ps::Fn => { - // TODO: move this to 'item' parsing - p.consume().next_if(TKind::LParen)?; - Expr::Fn( - Pat::Tuple(p.consume().list( - vec![], - PPrec::Tuple, - TKind::Comma, - TKind::RParen, - )?), - p.parse(prec.next())?, - ) - } - Ps::Lambda => Expr::Fn( - Pat::Tuple( - p.consume() - .list(vec![], PPrec::Tuple, TKind::Comma, TKind::Bar)?, - ), + Ps::Fn => Expr::Fn(p.parse(())?), + Ps::Lambda => Expr::Fn(Box::new(Fn( + None, + p.consume() + .opt(PPrec::Tuple, TKind::Bar)? + .unwrap_or(Pat::Tuple(vec![])), p.parse(Prec::Body.next())?, - ), - Ps::Lambda0 => Expr::Fn(Pat::Tuple(vec![]), p.consume().parse(Prec::Body.next())?), + ))), + Ps::Lambda0 => Expr::Fn(Box::new(Fn(None, Pat::Tuple(vec![]), { + p.consume().parse(Prec::Body.next())? + }))), Ps::DoubleRef => Expr::Op( Op::Refer, vec![Expr::Op(Op::Refer, vec![p.consume().parse(prec.next())?]).anno(span)], @@ -594,25 +638,7 @@ impl<'t> Parse<'t> for Expr { _ => unimplemented!("prefix {op:?}"), }; - // Postfix - while let Ok(tok) = p.peek() - && let Ok((op, prec)) = from_postfix(tok) - && level <= prec.prev() - && op != Ps::End - { - // let kind = tok.kind; - let span = span.merge(p.span()); - // p.consume(); - head = match (op, &head) { - (Ps::Make, Expr::Op(Op::Path, _) | Expr::Id(_) | Expr::MetId(_)) => Expr::Make( - head.anno(span).into(), - p.consume().list(vec![], (), TKind::Comma, TKind::RCurly)?, - ), - _ => break, - }; - } - - // Infix + // Infix and Postfix while let Ok(tok) = p.peek() && let Ok((op, prec)) = from_infix(tok) && level <= prec.prev() @@ -621,26 +647,37 @@ impl<'t> Parse<'t> for Expr { let kind = tok.kind; let span = span.merge(p.span()); - p.consume(); - head = match op { - Ps::Make => Expr::Make( - head.anno(span).into(), - p.consume().list(vec![], (), TKind::Comma, TKind::RCurly)?, - ), + // Make (structor expressions) are context-sensitive + Ps::Make => match &head { + Expr::Op(Op::Path, _) | Expr::Id(_) | Expr::MetId(_) => Expr::Make( + head.anno(span).into(), + p.consume().list(vec![], (), TKind::Comma, TKind::RCurly)?, + ), + _ => break, + }, Ps::Op(Op::Index) => Expr::Op( Op::Index, - p.list(vec![head.anno(span)], 0, TKind::Comma, TKind::RBrack)?, + p.consume() + .list(vec![head.anno(span)], 0, TKind::Comma, TKind::RBrack)?, ), Ps::Op(Op::Call) => Expr::Op( Op::Call, - p.list(vec![head.anno(span)], 0, TKind::Comma, TKind::RParen)?, + 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.list_bare(vec![head.anno(span)], prec.next(), kind)?) + Expr::Op( + op, + p.consume() + .list_bare(vec![head.anno(span)], prec.next(), kind)?, + ) } - Ps::Op(op @ Op::Try) => Expr::Op(op, vec![head.anno(span)]), - Ps::Op(op) => Expr::Op(op, vec![head.anno(span), p.parse(prec.next())?]), + Ps::Op(op @ Op::Try) => { + p.consume(); + Expr::Op(op, vec![head.anno(span)]) + } + Ps::Op(op) => Expr::Op(op, vec![head.anno(span), p.consume().parse(prec.next())?]), _ => unimplemented!("infix {op:?}"), } } @@ -655,7 +692,6 @@ impl<'t, P: Parse<'t> + Annotation> Parse<'t> for Anno

{ where Self: Sized { let start = p.span(); let anno = Anno(p.parse(level)?, start.merge(p.span())); - println!("{}:\t{anno}", anno.1); Ok(anno) } }