New Lambda Syntax with |...|

This adds parser support for the new lambda syntax.  It does not remove
the existing syntax, nor will the new syntax be retained in formatting.
That will be done in a separate PR to keep the two respective PRs
relatively small and easy to review.
This commit is contained in:
Anthony Bullard 2025-01-15 05:50:34 -06:00
parent 4e66910ef8
commit 8e1e1520e3
No known key found for this signature in database
6 changed files with 172 additions and 50 deletions

View file

@ -2335,6 +2335,53 @@ pub fn parse_top_level_defs<'a>(
// PARSER HELPERS
fn closure_help<'a>(check_for_arrow: CheckForArrow) -> impl Parser<'a, Expr<'a>, EClosure<'a>> {
one_of!(
closure_new_syntax_help(),
closure_old_syntax_help(check_for_arrow),
)
}
fn closure_new_syntax_help<'a>() -> impl Parser<'a, Expr<'a>, EClosure<'a>> {
move |arena: &'a Bump, state: State<'a>, min_indent: u32| {
let parser = map_with_arena(
indented_seq_skip_first(
error_on_pizza(byte_indent(b'|', EClosure::Bar), EClosure::Start),
and(
sep_by1_e(
byte_indent(b',', EClosure::Comma),
space0_around_ee(
specialize_err(EClosure::Pattern, closure_param()),
EClosure::IndentArg,
EClosure::IndentArrow,
),
EClosure::Arg,
),
skip_first(
// Parse the -> which separates params from body
byte(b'|', EClosure::Bar),
// Parse the body
block(
CheckForArrow(false),
true,
EClosure::IndentBody,
EClosure::Body,
),
),
),
),
|arena: &'a Bump, (params, body)| {
let params: Vec<'a, Loc<Pattern<'a>>> = params;
let params: &'a [Loc<Pattern<'a>>] = params.into_bump_slice();
Expr::Closure(params, arena.alloc(body))
},
);
parser.parse(arena, state, min_indent)
}
}
fn closure_old_syntax_help<'a>(
check_for_arrow: CheckForArrow,
) -> impl Parser<'a, Expr<'a>, EClosure<'a>> {
// closure_help_help(options)
map_with_arena(
// After the first token, all other tokens must be indented past the start of the line
@ -2371,6 +2418,19 @@ fn closure_help<'a>(check_for_arrow: CheckForArrow) -> impl Parser<'a, Expr<'a>,
)
}
fn error_on_pizza<'a, T, E: 'a>(
p: impl Parser<'a, T, E>,
f: impl Fn(Position) -> E,
) -> impl Parser<'a, T, E> {
move |arena: &'a Bump, state: State<'a>, min_indent: u32| {
if state.bytes().starts_with(b"|>") || state.bytes().starts_with(b"||") {
Err((NoProgress, f(state.pos())))
} else {
p.parse(arena, state, min_indent)
}
}
}
mod when {
use parser::indented_seq_skip_first;

View file

@ -1214,6 +1214,7 @@ impl<'a> Normalize<'a> for EClosure<'a> {
EClosure::IndentArrow(_) => EClosure::IndentArrow(Position::zero()),
EClosure::IndentBody(_) => EClosure::IndentBody(Position::zero()),
EClosure::IndentArg(_) => EClosure::IndentArg(Position::zero()),
EClosure::Bar(_) => EClosure::Bar(Position::zero()),
}
}
}

View file

@ -747,6 +747,7 @@ impl<'a> EInParens<'a> {
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum EClosure<'a> {
Bar(Position),
Space(BadInputError, Position),
Start(Position),
Arrow(Position),
@ -768,7 +769,8 @@ impl<'a> EClosure<'a> {
EClosure::Body(expr, _) => expr.get_region(),
// Cases with Position values
EClosure::Space(_, p)
EClosure::Bar(p)
| EClosure::Space(_, p)
| EClosure::Start(p)
| EClosure::Arrow(p)
| EClosure::Comma(p)