ast: Give for loops a dedicated node and remove eager desugar
This commit is contained in:
@@ -184,6 +184,7 @@ pub enum Use {
|
|||||||
/// fn Pat Expr
|
/// fn Pat Expr
|
||||||
/// mod Pat Expr
|
/// mod Pat Expr
|
||||||
/// impl Pat Expr
|
/// impl Pat Expr
|
||||||
|
/// for Pat in Expr Expr (else Expr)?
|
||||||
/// Pat => Expr // in match
|
/// Pat => Expr // in match
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
@@ -214,6 +215,8 @@ pub enum BindOp {
|
|||||||
Struct,
|
Struct,
|
||||||
/// An enum definition
|
/// An enum definition
|
||||||
Enum,
|
Enum,
|
||||||
|
/// A `for Pat in Expr Expr (else Expr)?` binding
|
||||||
|
For,
|
||||||
/// A `Pat => Expr` binding
|
/// A `Pat => Expr` binding
|
||||||
Match,
|
Match,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -190,6 +190,13 @@ impl<A: Annotation> Display for Bind<A> {
|
|||||||
},
|
},
|
||||||
_ => pat.fmt(f),
|
_ => pat.fmt(f),
|
||||||
},
|
},
|
||||||
|
BindOp::For => match exprs.as_slice() {
|
||||||
|
[iter, pass, Anno(Expr::Op(Op::Tuple, e), _)] if e.is_empty() => {
|
||||||
|
write!(f, "{pat} in {iter} {pass}")
|
||||||
|
}
|
||||||
|
[iter, pass, fail] => write!(f, "{pat} in {iter} {pass} else {fail}"),
|
||||||
|
other => f.delimit(fmt!("{pat} in [["), "]]!?").list(other, ", "),
|
||||||
|
},
|
||||||
_ => match exprs.as_slice() {
|
_ => match exprs.as_slice() {
|
||||||
[] => write!(f, "{pat}"),
|
[] => write!(f, "{pat}"),
|
||||||
[value] => write!(f, "{pat} = {value}"),
|
[value] => write!(f, "{pat} = {value}"),
|
||||||
@@ -212,6 +219,7 @@ impl Display for BindOp {
|
|||||||
Self::Fn => "fn ",
|
Self::Fn => "fn ",
|
||||||
Self::Mod => "mod ",
|
Self::Mod => "mod ",
|
||||||
Self::Impl => "impl ",
|
Self::Impl => "impl ",
|
||||||
|
Self::For => "for ",
|
||||||
Self::Match => "",
|
Self::Match => "",
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -398,19 +398,12 @@ fn parse_match(p: &mut Parser<'_>) -> PResult<Expr> {
|
|||||||
Ok(expr)
|
Ok(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parses and desugars a `for` loop expression
|
/// Parses a `for` loop expression
|
||||||
///
|
|
||||||
/// Assumes the existence of the following items:
|
|
||||||
///
|
|
||||||
/// 1. `enum<T> Option { None, Some(T) }`
|
|
||||||
/// 2. `fn T::into_iter(&mut self) -> U`
|
|
||||||
/// 3. `U::next() -> Option<V>`
|
|
||||||
fn parse_for(p: &mut Parser<'_>, _level: ()) -> PResult<Expr> {
|
fn parse_for(p: &mut Parser<'_>, _level: ()) -> PResult<Expr> {
|
||||||
// for Pat
|
// for Pat
|
||||||
let pat = p.consume().parse(PPrec::Tuple)?;
|
let pat = p.consume().parse(PPrec::Tuple)?;
|
||||||
// in Expr
|
// in Expr
|
||||||
let iter: Anno<Expr> = p.expect(TKind::In)?.parse(Prec::Logical.next())?;
|
let iter: Anno<Expr> = p.expect(TKind::In)?.parse(Prec::Logical.next())?;
|
||||||
let cspan = iter.1;
|
|
||||||
// Expr
|
// Expr
|
||||||
let pass: Anno<Expr> = p.parse(Prec::Body.next())?;
|
let pass: Anno<Expr> = p.parse(Prec::Body.next())?;
|
||||||
let pspan = pass.1;
|
let pspan = pass.1;
|
||||||
@@ -419,8 +412,8 @@ fn parse_for(p: &mut Parser<'_>, _level: ()) -> PResult<Expr> {
|
|||||||
Some(Ok(_)) => p.parse(Prec::Body.next())?,
|
Some(Ok(_)) => p.parse(Prec::Body.next())?,
|
||||||
_ => Expr::Op(Op::Tuple, vec![]).anno(pspan),
|
_ => Expr::Op(Op::Tuple, vec![]).anno(pspan),
|
||||||
};
|
};
|
||||||
let fspan = fail.1;
|
|
||||||
/*
|
/*
|
||||||
|
TODO: desugar for into loop-match:
|
||||||
for `pat in `iter `pass else `fail
|
for `pat in `iter `pass else `fail
|
||||||
==>
|
==>
|
||||||
match (`iter).into_iter() {
|
match (`iter).into_iter() {
|
||||||
@@ -431,70 +424,12 @@ fn parse_for(p: &mut Parser<'_>, _level: ()) -> PResult<Expr> {
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// TODO: A better way to do this kind of substitution desugaring
|
Ok(Expr::Bind(Box::new(Bind(
|
||||||
// without losing span information!
|
BindOp::For,
|
||||||
Ok(Expr::Op(
|
|
||||||
Op::Match,
|
|
||||||
vec![
|
|
||||||
Expr::Op(
|
|
||||||
Op::Dot,
|
|
||||||
vec![
|
|
||||||
iter,
|
|
||||||
Expr::Op(Op::Call, vec![Expr::Id("into_iter".into()).anno(cspan)]).anno(cspan),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
.anno(cspan),
|
|
||||||
Expr::Bind(Box::new(Bind(
|
|
||||||
BindOp::Match,
|
|
||||||
vec![],
|
vec![],
|
||||||
Pat::Name("#iter".into()),
|
pat,
|
||||||
vec![
|
vec![iter, pass, fail],
|
||||||
Expr::Op(
|
))))
|
||||||
Op::Loop,
|
|
||||||
vec![
|
|
||||||
Expr::Op(
|
|
||||||
Op::Match,
|
|
||||||
vec![
|
|
||||||
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),
|
|
||||||
Expr::Bind(Box::new(Bind(
|
|
||||||
BindOp::Match,
|
|
||||||
vec![],
|
|
||||||
Pat::Name("None".into()),
|
|
||||||
vec![Expr::Op(Op::Break, vec![fail]).anno(fspan)],
|
|
||||||
)))
|
|
||||||
.anno(fspan),
|
|
||||||
Expr::Bind(Box::new(Bind(
|
|
||||||
BindOp::Match,
|
|
||||||
vec![],
|
|
||||||
Pat::NamedTuple(
|
|
||||||
"Some".into(),
|
|
||||||
Box::new(Pat::Op(PatOp::Tuple, vec![pat])),
|
|
||||||
),
|
|
||||||
vec![pass],
|
|
||||||
)))
|
|
||||||
.anno(pspan),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
.anno(pspan),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
.anno(pspan),
|
|
||||||
],
|
|
||||||
)))
|
|
||||||
.anno(pspan),
|
|
||||||
],
|
|
||||||
))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the [BindOp], [pattern precedence](PPrec), [arrow TKind](TKind), [body precedence](Prec),
|
/// Returns the [BindOp], [pattern precedence](PPrec), [arrow TKind](TKind), [body precedence](Prec),
|
||||||
|
|||||||
Reference in New Issue
Block a user