doughlang: Expressions in patterns
ast: - Document operators - Parameterize Pat with Annotation - Consolidate Path and Lit into "Value" (Expr) - Consolidate NamedRecord/Namedtuple into PatOp::TypePrefixed - Allow Pat<Pat,*> patterns - Additional helper functions on Expr and Pat lexer: - Support inner-doc comment syntax `//!` - Cleans up `///` or `//!` prefix parser: - Make Parse::Prec `Default` - Allow expression elision after `..`/`..=` - Fix Parser::consume not updating elide_do state - Add token splitting, to make `&&Expr` and `&&Pat` easier - error: Embed Pat precedence in ParseError
This commit is contained in:
@@ -76,6 +76,7 @@ pub enum Ps {
|
||||
Lit, // Literal
|
||||
Use, // use Use
|
||||
Def, // any definition (let, const, static, struct, enum, fn, ...)
|
||||
Doc, // Documentation Comment
|
||||
For, // for Pat in Expr Expr else Expr
|
||||
Lambda0, // || Expr
|
||||
Lambda, // | Pat,* | Expr
|
||||
@@ -90,6 +91,8 @@ pub enum Ps {
|
||||
/// and its [precedence level](Prec)
|
||||
fn from_prefix(token: &Token) -> PResult<(Ps, Prec)> {
|
||||
Ok(match token.kind {
|
||||
TKind::OutDoc => (Ps::Doc, Prec::Max),
|
||||
TKind::InDoc => (Ps::Doc, Prec::Max),
|
||||
TKind::Do => (Ps::Op(Op::Do), Prec::Do),
|
||||
TKind::Semi => (Ps::End, Prec::Body),
|
||||
|
||||
@@ -207,12 +210,9 @@ impl<'t> Parse<'t> for Expr {
|
||||
fn parse(p: &mut Parser<'t>, level: usize) -> PResult<Self> {
|
||||
const MIN: usize = Prec::MIN;
|
||||
|
||||
// TODO: in-tree doc comments
|
||||
while p.next_if(TKind::Doc)?.is_ok() {}
|
||||
|
||||
// Prefix
|
||||
let tok @ &Token { kind, span, .. } = p.peek()?;
|
||||
let ((op, prec), span) = (from_prefix(tok)?, span);
|
||||
let (op, prec) = from_prefix(tok)?;
|
||||
no_eof(move || {
|
||||
let mut head = match op {
|
||||
// "End" is produced when an "empty" expression is syntactically required.
|
||||
@@ -227,11 +227,19 @@ impl<'t> Parse<'t> for Expr {
|
||||
Ps::Lit => Expr::Lit(p.parse(())?),
|
||||
Ps::Use => Expr::Use(p.consume().parse(())?),
|
||||
Ps::Def => Expr::Bind(p.parse(None)?),
|
||||
Ps::Doc => {
|
||||
let comment = Literal::Str(p.take_lexeme()?.string().unwrap());
|
||||
let comment = Expr::Lit(comment).anno(span);
|
||||
let next = p.parse(level)?;
|
||||
Expr::Op(Op::Meta, vec![comment, next])
|
||||
}
|
||||
Ps::For => parse_for(p, ())?,
|
||||
Ps::Lambda | Ps::Lambda0 => {
|
||||
p.consume();
|
||||
|
||||
let args = if op == Ps::Lambda {
|
||||
p.opt(PPrec::Tuple, TKind::Bar)?
|
||||
.map(Pat::to_tuple)
|
||||
.unwrap_or(Pat::Op(PatOp::Tuple, vec![]))
|
||||
} else {
|
||||
Pat::Op(PatOp::Tuple, vec![])
|
||||
@@ -246,7 +254,6 @@ impl<'t> Parse<'t> for Expr {
|
||||
vec![p.parse(Prec::Body.next())?],
|
||||
)))
|
||||
}
|
||||
Ps::For => parse_for(p, ())?,
|
||||
Ps::Op(Op::Match) => parse_match(p)?,
|
||||
Ps::Op(Op::Meta) => Expr::Op(
|
||||
Op::Meta,
|
||||
@@ -260,10 +267,10 @@ impl<'t> Parse<'t> for Expr {
|
||||
),
|
||||
Ps::Op(Op::Block) => Expr::Op(
|
||||
Op::Block,
|
||||
p.consume().opt(MIN, TKind::RCurly)?.into_iter().collect(),
|
||||
p.consume().opt(MIN, kind.flip())?.into_iter().collect(),
|
||||
),
|
||||
Ps::Op(Op::Array) => parse_array(p)?,
|
||||
Ps::Op(Op::Group) => match p.consume().opt(MIN, TKind::RParen)? {
|
||||
Ps::Op(Op::Group) => match p.consume().opt(MIN, kind.flip())? {
|
||||
Some(value) => Expr::Op(Op::Group, vec![value]),
|
||||
None => Expr::Op(Op::Tuple, vec![]),
|
||||
},
|
||||
@@ -295,12 +302,11 @@ impl<'t> Parse<'t> for Expr {
|
||||
};
|
||||
|
||||
// Infix and Postfix
|
||||
while let Ok(Some(tok)) = p.peek().allow_eof()
|
||||
while let Ok(Some(tok @ &Token { kind, .. })) = p.peek().allow_eof()
|
||||
&& let Ok((op, prec)) = from_infix(tok)
|
||||
&& level <= prec.prev()
|
||||
&& op != Ps::End
|
||||
{
|
||||
let kind = tok.kind;
|
||||
let span = span.merge(p.span());
|
||||
|
||||
head = match op {
|
||||
@@ -320,7 +326,7 @@ impl<'t> Parse<'t> for Expr {
|
||||
span,
|
||||
match p.consume().peek().allow_eof()? {
|
||||
Some(_) => p.parse(prec.next())?,
|
||||
None => Anno(Default::default(), span),
|
||||
None => Anno(Expr::Omitted, span),
|
||||
},
|
||||
),
|
||||
Ps::Op(Op::Index) => Expr::Op(
|
||||
@@ -328,15 +334,14 @@ impl<'t> Parse<'t> for Expr {
|
||||
p.consume()
|
||||
.list(vec![head.anno(span)], 0, TKind::Comma, TKind::RBrack)?,
|
||||
),
|
||||
Ps::Op(Op::Call) => Expr::Op(
|
||||
Op::Call,
|
||||
vec![
|
||||
head.anno(span),
|
||||
p.consume()
|
||||
.opt(0, TKind::RParen)?
|
||||
.unwrap_or_else(|| Expr::Op(Op::Tuple, vec![]).anno(span)),
|
||||
],
|
||||
),
|
||||
Ps::Op(Op::Call) => {
|
||||
let head = head.anno(span);
|
||||
let args = match p.consume().opt::<Anno<Expr>>(0, TKind::RParen)? {
|
||||
None => Expr::Op(Op::Tuple, vec![]).anno(span),
|
||||
Some(Anno(expr, span)) => expr.to_tuple(span).anno(span),
|
||||
};
|
||||
Expr::Op(Op::Call, vec![head, args])
|
||||
}
|
||||
Ps::Op(op @ (Op::Tuple | Op::Dot | Op::LogAnd | Op::LogOr)) => Expr::Op(
|
||||
op,
|
||||
p.consume()
|
||||
@@ -445,7 +450,7 @@ fn from_bind(p: &mut Parser<'_>) -> PResult<(BindOp, PPrec, Option<TKind>, Optio
|
||||
TKind::Enum => (BindOp::Enum, PPrec::Tuple, None, None, None),
|
||||
TKind::Fn => (BindOp::Fn, PPrec::Fn, None, Some(Prec::Body), None),
|
||||
TKind::Mod => (BindOp::Mod, PPrec::Max, None, Some(Prec::Body), None),
|
||||
TKind::Impl => (BindOp::Impl, PPrec::Max, None, Some(Prec::Body), None),
|
||||
TKind::Impl => (BindOp::Impl, PPrec::Fn, None, Some(Prec::Body), None),
|
||||
TKind::Bar => (BindOp::Match, PPrec::Alt, Some(TKind::FatArrow), Some(Prec::Body), None),
|
||||
// no consume!
|
||||
_ => return Ok((BindOp::Match, PPrec::Alt, Some(TKind::FatArrow), Some(Prec::Body), None)),
|
||||
@@ -481,11 +486,14 @@ impl<'t> Parse<'t> for Bind {
|
||||
return Ok(Self(level, generics, pat, vec![]));
|
||||
};
|
||||
|
||||
// `=>` for match, `=`? for everything else
|
||||
if let Some(arrow) = arrow
|
||||
&& p.next_if(arrow).allow_eof()?.is_none_or(|v| v.is_err())
|
||||
{
|
||||
return Ok(Self(level, generics, pat, vec![]));
|
||||
// `=>` for match, `=` for `let`, `type`
|
||||
if let Some(arrow) = arrow {
|
||||
if p.next_if(arrow).allow_eof()?.is_none_or(|v| v.is_err()) {
|
||||
return Ok(Self(level, generics, pat, vec![]));
|
||||
}
|
||||
} else {
|
||||
// Allow prefix `=`? for the rest of them
|
||||
p.next_if(TKind::Eq).allow_eof()?;
|
||||
}
|
||||
|
||||
// `=` Expr
|
||||
|
||||
Reference in New Issue
Block a user