ast: fn main, structification

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

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(
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<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)
}
}