ast: fn main, structification

parser: unified post/infix, context-full grammar
repl: modes
This commit is contained in:
John 2025-09-21 02:57:20 -04:00
parent 434fa225e7
commit 8640ec4261
4 changed files with 342 additions and 151 deletions

View File

@ -58,7 +58,7 @@ pub struct MakeArm<A: Annotation = Span>(pub String, pub Option<Anno<Expr<A>, A>
/// (Pat |)* Pat? => Expr
/// ```
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct MatchArm<A: Annotation = Span>(pub Vec<Pat>, pub Anno<Expr<A>, A>);
pub struct MatchArm<A: Annotation = Span>(pub Pat, pub Anno<Expr<A>, A>);
/// In-universe types
#[derive(Clone, Debug, PartialEq, Eq)]
@ -77,6 +77,22 @@ pub enum Ty {
Fn(Vec<Ty>),
}
/// A `const` binding (which defines its name before executing)
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Const<A: Annotation = Span>(pub Pat, pub Anno<Expr<A>, A>);
/// A function definition `fn Ident? (Pat,*) Expr`
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Fn<A: Annotation = Span>(pub Option<String>, pub Pat, pub Anno<Expr<A>, A>);
/// A `let` binding: `let Pat (= Expr)?`
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Let<A: Annotation = Span>(pub Pat, pub Option<Anno<Expr<A>, A>>);
/// `match Expr { MatchArm,* }``
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Match<A: Annotation = Span>(pub Anno<Expr<A>, A>, pub Vec<MatchArm<A>>);
/// Expressions: The beating heart of Dough
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum Expr<A: Annotation = Span> {
@ -87,15 +103,15 @@ pub enum Expr<A: Annotation = Span> {
/// A literal bool, string, char, or int
Lit(Literal),
/// let Pat<NoTopAlt> = expr
Let(Pat, Option<Box<Anno<Self, A>>>),
Let(Box<Let<A>>),
/// `const Pat<NoTopAlt> (= Expr)?` (Basically let rec)
Const(Pat, Box<Anno<Self, A>>),
/// `| Pat<Tuple> | Expr` | `|| Expr` | `fn (Pat,*) Expr`
Fn(Pat, Box<Anno<Self, A>>),
Const(Box<Const<A>>),
/// `| Pat<Tuple> | Expr` | `|| Expr` | `fn Ident? (Pat,*) Expr`
Fn(Box<Fn<A>>),
/// Expr { (Ident (: Expr)?),* }
Make(Box<Anno<Self, A>>, Vec<MakeArm<A>>),
/// match Expr { MatchArm,* }
Match(Box<Anno<Self, A>>, Vec<MatchArm<A>>),
Match(Box<Match<A>>),
/// Op Expr | Expr Op | Expr (Op Expr)+ | Op Expr Expr else Expr
Op(Op, Vec<Anno<Self, A>>),
}
@ -205,22 +221,52 @@ impl<T: Display + Annotation, A: Annotation> Display for Anno<T, A> {
}
}
impl<A: Annotation> Display for Const<A> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self(pat, expr) = self;
write!(f, "const {pat} = {expr}")
}
}
impl<A: Annotation> Display for Fn<A> {
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<A: Annotation> Display for Let<A> {
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<A: Annotation> Display for Match<A> {
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<A: Annotation> Display for Expr<A> {
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<A: Annotation> Display for MakeArm<A> {
impl<A: Annotation> Display for MatchArm<A> {
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}")
}
}

View File

@ -78,6 +78,60 @@ impl<M: Match<A> + Annotation, A: Annotation> Match<A> for Anno<M, A> {
}
}
impl<A: Annotation> Match<A> for Const<A> {
fn recurse(sub: &mut Subst<A>, 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<A>) {
let Self(pat, expr) = self;
pat.apply(sub);
expr.apply(sub);
}
}
impl<A: Annotation> Match<A> for Fn<A> {
fn recurse(sub: &mut Subst<A>, 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<A>) {
let Self(_, pat, body) = self;
pat.apply(sub);
body.apply(sub);
}
}
impl<A: Annotation> Match<A> for Let<A> {
fn recurse(sub: &mut Subst<A>, 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<A>) {
let Self(pat, expr) = self;
pat.apply(sub);
expr.apply(sub);
}
}
impl<A: Annotation> Match<A> for crate::ast::Match<A> {
fn recurse(sub: &mut Subst<A>, 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<A>) {
let Self(pat, expr) = self;
pat.apply(sub);
expr.apply(sub);
}
}
impl<A: Annotation> Match<A> for Expr<A> {
fn recurse(sub: &mut Subst<A>, pat: &Self, expr: &Self) -> bool {
match (pat, expr) {
@ -87,25 +141,17 @@ impl<A: Annotation> Match<A> for Expr<A> {
(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<A: Annotation> Match<A> for Expr<A> {
}
}
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) => {

View File

@ -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<dyn Error>> {
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<dyn Error>> {
})?;
} 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);
fn lex() -> Result<(), Box<dyn Error>> {
read_and("\x1b[93m", " >", "?>", |line| {
let mut lexer = Lexer::new(line);
if line.trim().is_empty() {
return Ok(Response::Break);
}
loop {
match lexer.scan() {
Ok(Token { lexeme, kind, span: Span { head, tail } }) => {
println!(
"{kind:?}\x1b[11G {head:<4} {tail:<4} {}",
lexeme.escape_debug()
)
Err(LexError { res: "EOF", .. }) => {
break Ok(Response::Accept);
}
Err(e) => {
eprintln!("{e}");
break;
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()
),
}
}
})?;
Ok(())
}
fn exprs() -> Result<(), Box<dyn Error>> {
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::<Anno<Expr>>(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<dyn Error>> {
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::<Pat>(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<dyn Error>> {

View File

@ -121,6 +121,7 @@ impl<'t> Parser<'t> {
sep: TKind,
end: TKind,
) -> PResult<Vec<P>> {
// 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<Self> {
@ -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<Self> {
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<Self> {
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<Self> {
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<Self> {
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<Self> {
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<Self> {
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<Self> {
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<Self> {
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(
Ps::Fn => Expr::Fn(p.parse(())?),
Ps::Lambda => Expr::Fn(Box::new(Fn(
None,
p.consume()
.list(vec![], PPrec::Tuple, TKind::Comma, TKind::Bar)?,
),
.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(
// 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<P> {
where Self: Sized {
let start = p.span();
let anno = Anno(p.parse(level)?, start.merge(p.span()));
println!("{}:\t{anno}", anno.1);
Ok(anno)
}
}