doughlang: let else, fn rety
ast: - `let Pat (= Expr (else Expr)?)?`, - `fn (args) -> Ty`, coagulating `do`, `if/while` formatting fixes parser: - int cleanup, - fn rety parsing, - experimental `for` desugar, - experimental semicolon elision (TODO: it sucks), - let-else parsing - `do` coagulation impl (still not 100% there) TODO: - Fix `do` coagulation - codify `do` elision rules - `for` needs lib support - this is fine because we have no codegen yet - Ty matching in macro_matcher - Or rip out macro_matcher? Who knows what the future holds.
This commit is contained in:
209
src/parser.rs
209
src/parser.rs
@@ -200,15 +200,14 @@ impl<'t> Parse<'t> for Literal {
|
||||
.expect("should have one char in char literal"),
|
||||
),
|
||||
TKind::Integer => {
|
||||
let Token { lexeme, kind: _, span } = p.take().expect("should have Token");
|
||||
// TODO: more complex int parsing
|
||||
let int = lexeme
|
||||
.int()
|
||||
.ok_or(ParseError::Expected(TKind::Integer, span))?;
|
||||
Literal::Int(int as _)
|
||||
let Token { lexeme, span, .. } = p.take().expect("should have Token");
|
||||
let Lexeme::Integer(int, _) = lexeme else {
|
||||
Err(ParseError::Expected(TKind::Integer, span))?
|
||||
};
|
||||
Literal::Int(int)
|
||||
}
|
||||
TKind::String => Literal::Str({
|
||||
let Token { lexeme, kind: _, span } = p.take().expect("should have Token");
|
||||
let Token { lexeme, span, .. } = p.take().expect("should have Token");
|
||||
lexeme
|
||||
.string()
|
||||
.ok_or(ParseError::Expected(TKind::String, span))?
|
||||
@@ -368,7 +367,10 @@ impl<'t> Parse<'t> for Ty {
|
||||
_ => Err(ParseError::NotType(tok.kind, tok.span))?,
|
||||
};
|
||||
|
||||
Ok(head)
|
||||
Ok(match p.next_if(TKind::Arrow) {
|
||||
Ok(_) => Ty::Fn(vec![head, p.parse(())?]),
|
||||
_ => head,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -435,21 +437,23 @@ impl Prec {
|
||||
/// PseudoOperator: fake operators used to give certain tokens special behavior.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub enum Ps {
|
||||
Id, // Identifier
|
||||
Mid, // MetaIdentifier
|
||||
Lit, // Literal
|
||||
Let, // let Pat = Expr
|
||||
Const, // const Pat = Expr
|
||||
Struct, // struct { Pat } | struct ( Pat )
|
||||
Fn, // fn ( Pat,* ) Expr
|
||||
Lambda0, // || Expr
|
||||
Lambda, // | Pat,* | Expr
|
||||
DoubleRef, // && Expr
|
||||
Make, // Expr{ Expr,* }
|
||||
Match, // match Expr { MatchArm,* }
|
||||
Mod, // mod Ty Expr
|
||||
End, // Produces an empty value.
|
||||
Op(Op), // A normal [ast::Op]
|
||||
Id, // Identifier
|
||||
Mid, // MetaIdentifier
|
||||
Lit, // Literal
|
||||
Let, // let Pat = Expr
|
||||
Const, // const Pat = Expr
|
||||
Struct, // struct { Pat } | struct ( Pat )
|
||||
For, // for Pat in Expr Expr else Expr
|
||||
Fn, // fn ( Pat,* ) Expr
|
||||
Lambda0, // || Expr
|
||||
Lambda, // | Pat,* | Expr
|
||||
DoubleRef, // && Expr
|
||||
Make, // Expr{ Expr,* }
|
||||
Match, // match Expr { MatchArm,* }
|
||||
Mod, // mod Ty Expr
|
||||
ImplicitDo, // An implicit semicolon
|
||||
End, // Produces an empty value.
|
||||
Op(Op), // A normal [ast::Op]
|
||||
}
|
||||
|
||||
fn from_prefix(token: &Token) -> PResult<(Ps, Prec)> {
|
||||
@@ -464,6 +468,7 @@ fn from_prefix(token: &Token) -> PResult<(Ps, Prec)> {
|
||||
}
|
||||
|
||||
TKind::Public => (Ps::Op(Op::Pub), Prec::Body),
|
||||
TKind::For => (Ps::For, Prec::Body),
|
||||
TKind::Fn => (Ps::Fn, Prec::Body),
|
||||
TKind::Match => (Ps::Match, Prec::Body),
|
||||
TKind::Macro => (Ps::Op(Op::Macro), Prec::Assign),
|
||||
@@ -533,6 +538,22 @@ fn from_infix(token: &Token) -> PResult<(Ps, Prec)> {
|
||||
TKind::Star => (Ps::Op(Op::Mul), Prec::Term),
|
||||
TKind::Slash => (Ps::Op(Op::Div), Prec::Term),
|
||||
TKind::Rem => (Ps::Op(Op::Rem), Prec::Term),
|
||||
|
||||
TKind::True
|
||||
| TKind::False
|
||||
| TKind::Character
|
||||
| TKind::Integer
|
||||
| TKind::String
|
||||
| TKind::Identifier
|
||||
| TKind::Public
|
||||
| TKind::Module
|
||||
| TKind::Fn
|
||||
| TKind::Do
|
||||
| TKind::While
|
||||
| TKind::If
|
||||
| TKind::For
|
||||
| TKind::Break
|
||||
| TKind::Return => (Ps::ImplicitDo, Prec::Do),
|
||||
kind => Err(ParseError::NotInfix(kind, token.span))?,
|
||||
})
|
||||
}
|
||||
@@ -565,6 +586,7 @@ impl<'t> Parse<'t> for Fn {
|
||||
Ok(Token { lexeme, .. }) => Ok(Self(
|
||||
lexeme.string(),
|
||||
p.parse(PPrec::Typed)?,
|
||||
p.opt_if((), TKind::Arrow)?.unwrap_or_default(),
|
||||
p.parse(Prec::Body.next())?,
|
||||
)),
|
||||
_ => Ok(Self(
|
||||
@@ -575,6 +597,7 @@ impl<'t> Parse<'t> for Fn {
|
||||
TKind::Comma,
|
||||
TKind::RParen,
|
||||
)?),
|
||||
p.opt_if((), TKind::Arrow)?.unwrap_or_default(),
|
||||
p.parse(Prec::Body.next())?,
|
||||
)),
|
||||
}
|
||||
@@ -585,10 +608,17 @@ 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)?,
|
||||
))
|
||||
let pat = p.consume().parse(PPrec::Tuple)?;
|
||||
if p.next_if(TKind::Eq).is_err() {
|
||||
return Ok(Self(pat, vec![]));
|
||||
}
|
||||
|
||||
let body = p.parse(Prec::Tuple.value())?;
|
||||
if p.next_if(TKind::Else).is_err() {
|
||||
return Ok(Self(pat, vec![body]));
|
||||
}
|
||||
|
||||
Ok(Self(pat, vec![body, p.parse(Prec::Body.next())?]))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -634,10 +664,106 @@ impl<'t> Parse<'t> for MakeArm {
|
||||
impl<'t> Parse<'t> for Mod {
|
||||
type Prec = ();
|
||||
fn parse(p: &mut Parser<'t>, _level: Self::Prec) -> PResult<Self> {
|
||||
Ok(Mod(p.consume().parse(())?, p.parse(Prec::Body.value())?))
|
||||
let ty = p.consume().parse(())?;
|
||||
let body = p.parse(Prec::Body.value())?;
|
||||
Ok(Mod(ty, body))
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_for<'t>(p: &mut Parser<'t>, _level: ()) -> PResult<Expr> {
|
||||
// for Pat
|
||||
let pat = p.consume().parse(PPrec::Tuple)?;
|
||||
// in Expr
|
||||
let iter: Anno<Expr> = p.consume_if(TKind::In)?.parse(Prec::Logical.next())?;
|
||||
let cspan = iter.1;
|
||||
// Expr
|
||||
let pass: Anno<Expr> = p.parse(Prec::Body.next())?;
|
||||
let pspan = pass.1;
|
||||
// else Expr?
|
||||
let fail = match p.next_if(TKind::Else) {
|
||||
Ok(_) => p.parse(Prec::Body.next())?,
|
||||
_ => Expr::Op(Op::Tuple, vec![]).anno(pspan),
|
||||
};
|
||||
let fspan = fail.1;
|
||||
/*
|
||||
for `pat in `iter `pass else `fail
|
||||
==>
|
||||
match (`iter).into_iter() {
|
||||
#iter => loop match #iter.next() {
|
||||
None => break `fail,
|
||||
Some(`pat) => `pass,
|
||||
},
|
||||
}
|
||||
*/
|
||||
// let mut tmp_p = Parser::new(Lexer::new(
|
||||
// "match `iter.into_iter() {
|
||||
// `iterator => loop match `iterator.next() {
|
||||
// None => break `fail,
|
||||
// Some(`pat) => `pass,
|
||||
// },
|
||||
// }",
|
||||
// ));
|
||||
|
||||
// let mut template: Expr = tmp_p.parse(Prec::MIN)?;
|
||||
|
||||
// let mut subst = Subst::<Span> { exp: Default::default(), pat: Default::default() };
|
||||
// subst.exp.extend([
|
||||
// ("iterator".into(), Expr::Id("#iter".into())),
|
||||
// ("iter".into(), iter.0),
|
||||
// ("fail".into(), fail.0),
|
||||
// ("pass".into(), pass.0),
|
||||
// ]);
|
||||
// subst.pat.extend([
|
||||
// ("iterator".into(), Pat::Name("#iter".into())),
|
||||
// ("pat".into(), pat),
|
||||
// ]);
|
||||
|
||||
// template.apply(&subst);
|
||||
// Ok(template)
|
||||
|
||||
Ok(Expr::Match(Box::new(Match(
|
||||
Expr::Op(
|
||||
Op::Dot,
|
||||
vec![
|
||||
iter,
|
||||
Expr::Op(Op::Call, vec![Expr::Id("into_iter".into()).anno(cspan)]).anno(cspan),
|
||||
],
|
||||
)
|
||||
.anno(cspan),
|
||||
vec![MatchArm(
|
||||
Pat::Name("#iter".into()),
|
||||
Expr::Op(
|
||||
Op::Loop,
|
||||
vec![
|
||||
Expr::Match(Box::new(Match(
|
||||
Expr::Op(
|
||||
Op::Dot,
|
||||
vec![
|
||||
Expr::Id("#iter".into()).anno(cspan),
|
||||
Expr::Op(Op::Call, vec![Expr::Id("next".into()).anno(cspan)])
|
||||
.anno(cspan),
|
||||
],
|
||||
)
|
||||
.anno(cspan),
|
||||
vec![
|
||||
MatchArm(
|
||||
Pat::Name("None".into()),
|
||||
Expr::Op(Op::Break, vec![fail]).anno(fspan),
|
||||
),
|
||||
MatchArm(
|
||||
Pat::TupStruct("Some".into(), Box::new(Pat::Tuple(vec![pat]))),
|
||||
pass,
|
||||
),
|
||||
],
|
||||
)))
|
||||
.anno(pspan),
|
||||
],
|
||||
)
|
||||
.anno(pspan),
|
||||
)],
|
||||
))))
|
||||
}
|
||||
|
||||
impl<'t> Parse<'t> for Expr {
|
||||
type Prec = usize;
|
||||
|
||||
@@ -662,6 +788,7 @@ impl<'t> Parse<'t> for Expr {
|
||||
Ps::Mid => Expr::MetId(p.consume().next()?.lexeme.to_string()),
|
||||
Ps::Lit => Expr::Lit(p.parse(())?),
|
||||
Ps::Let => Expr::Let(p.parse(())?),
|
||||
Ps::For => parse_for(p, ())?,
|
||||
Ps::Const => Expr::Const(p.parse(())?),
|
||||
Ps::Struct => Expr::Struct(p.parse(())?),
|
||||
Ps::Match => Expr::Match(p.parse(())?),
|
||||
@@ -694,11 +821,15 @@ impl<'t> Parse<'t> for Expr {
|
||||
p.consume()
|
||||
.opt(PPrec::Tuple, TKind::Bar)?
|
||||
.unwrap_or(Pat::Tuple(vec![])),
|
||||
p.opt_if((), TKind::Arrow)?.unwrap_or_default(),
|
||||
p.parse(Prec::Body.next())?,
|
||||
))),
|
||||
Ps::Lambda0 => Expr::Fn(Box::new(Fn(
|
||||
None,
|
||||
Pat::Tuple(vec![]),
|
||||
p.consume().opt_if((), TKind::Arrow)?.unwrap_or_default(),
|
||||
p.parse(Prec::Body.next())?,
|
||||
))),
|
||||
Ps::Lambda0 => Expr::Fn(Box::new(Fn(None, Pat::Tuple(vec![]), {
|
||||
p.consume().parse(Prec::Body.next())?
|
||||
}))),
|
||||
Ps::DoubleRef => p.consume().parse(prec.next()).map(|Anno(expr, span)| {
|
||||
Expr::Op(
|
||||
Op::Refer,
|
||||
@@ -724,12 +855,14 @@ impl<'t> Parse<'t> for Expr {
|
||||
Ps::Make => match &head {
|
||||
Expr::Op(Op::Path, _) | Expr::Id(_) | Expr::MetId(_) => {
|
||||
Expr::Make(Box::new(Make(
|
||||
head.anno(span).into(),
|
||||
head.anno(span),
|
||||
p.consume().list(vec![], (), TKind::Comma, TKind::RCurly)?,
|
||||
)))
|
||||
}
|
||||
_ => break,
|
||||
},
|
||||
Ps::Op(Op::Do) => head.and_do(span, p.consume().parse(prec.next())?),
|
||||
Ps::ImplicitDo => head.and_do(span, p.parse(prec.next())?),
|
||||
Ps::Op(Op::Index) => Expr::Op(
|
||||
Op::Index,
|
||||
p.consume()
|
||||
@@ -740,13 +873,11 @@ impl<'t> Parse<'t> for Expr {
|
||||
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.consume()
|
||||
.list_bare(vec![head.anno(span)], prec.next(), kind)?,
|
||||
)
|
||||
}
|
||||
Ps::Op(op @ (Op::Tuple | Op::Dot | Op::Path | Op::LogAnd | Op::LogOr)) => Expr::Op(
|
||||
op,
|
||||
p.consume()
|
||||
.list_bare(vec![head.anno(span)], prec.next(), kind)?,
|
||||
),
|
||||
Ps::Op(op @ Op::Try) => {
|
||||
p.consume();
|
||||
Expr::Op(op, vec![head.anno(span)])
|
||||
|
||||
Reference in New Issue
Block a user