ast: fn main, structification
parser: unified post/infix, context-full grammar repl: modes
This commit is contained in:
242
src/parser.rs
242
src/parser.rs
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user