parse guarded record patterns

e.g.

    case foo when
        { x: 4 } -> ...
        { x, y } -> ...
This commit is contained in:
Folkert 2019-12-23 21:52:12 +01:00
parent f47c2677ee
commit 1b2636bee6
3 changed files with 75 additions and 18 deletions

View file

@ -290,7 +290,7 @@ fn expr_to_pattern<'a>(arena: &'a Bump, expr: &Expr<'a>) -> Result<Pattern<'a>,
for loc_assigned_field in loc_assigned_fields {
let region = loc_assigned_field.region;
let value = assigned_field_to_pattern(arena, &loc_assigned_field.value)?;
let value = assigned_expr_field_to_pattern(arena, &loc_assigned_field.value)?;
loc_patterns.push(Located { region, value });
}
@ -331,7 +331,8 @@ fn expr_to_pattern<'a>(arena: &'a Bump, expr: &Expr<'a>) -> Result<Pattern<'a>,
}
}
pub fn assigned_field_to_pattern<'a>(
/// use for expressions like { x: a + b }
pub fn assigned_expr_field_to_pattern<'a>(
arena: &'a Bump,
assigned_field: &AssignedField<'a, Expr<'a>>,
) -> Result<Pattern<'a>, Fail> {
@ -354,11 +355,46 @@ pub fn assigned_field_to_pattern<'a>(
}
AssignedField::LabelOnly(name) => Pattern::Identifier(name.value),
AssignedField::SpaceBefore(nested, spaces) => Pattern::SpaceBefore(
arena.alloc(assigned_field_to_pattern(arena, nested)?),
arena.alloc(assigned_expr_field_to_pattern(arena, nested)?),
spaces,
),
AssignedField::SpaceAfter(nested, spaces) => Pattern::SpaceAfter(
arena.alloc(assigned_field_to_pattern(arena, nested)?),
arena.alloc(assigned_expr_field_to_pattern(arena, nested)?),
spaces,
),
AssignedField::Malformed(string) => Pattern::Malformed(string),
})
}
/// Used for patterns like { x: Just _ }
pub fn assigned_pattern_field_to_pattern<'a>(
arena: &'a Bump,
assigned_field: &AssignedField<'a, Pattern<'a>>,
) -> Result<Pattern<'a>, Fail> {
// the assigned fields always store spaces, but this slice is often empty
Ok(match assigned_field {
AssignedField::LabeledValue(name, spaces, value) => {
let pattern = value.value.clone();
let result = arena.alloc(Located {
region: value.region,
value: pattern,
});
if spaces.is_empty() {
Pattern::RecordField(name.value, result)
} else {
Pattern::SpaceAfter(
arena.alloc(Pattern::RecordField(name.value, result)),
spaces,
)
}
}
AssignedField::LabelOnly(name) => Pattern::Identifier(name.value),
AssignedField::SpaceBefore(nested, spaces) => Pattern::SpaceBefore(
arena.alloc(assigned_pattern_field_to_pattern(arena, nested)?),
spaces,
),
AssignedField::SpaceAfter(nested, spaces) => Pattern::SpaceAfter(
arena.alloc(assigned_pattern_field_to_pattern(arena, nested)?),
spaces,
),
AssignedField::Malformed(string) => Pattern::Malformed(string),
@ -744,15 +780,19 @@ fn underscore_pattern<'a>() -> impl Parser<'a, Pattern<'a>> {
}
fn record_destructure<'a>(min_indent: u16) -> impl Parser<'a, Pattern<'a>> {
map!(
collection!(
char('{'),
loc!(ident_pattern()),
char(','),
char('}'),
min_indent
),
Pattern::RecordDestructure
then(
record!(loc!(pattern(min_indent)), min_indent),
move |arena, state, assigned_fields| {
let mut patterns = Vec::with_capacity_in(assigned_fields.len(), arena);
for assigned_field in assigned_fields {
match assigned_pattern_field_to_pattern(arena, &assigned_field.value) {
Ok(pattern) => patterns.push(Located::at(assigned_field.region, pattern)),
Err(e) => return Err((e, state)),
}
}
Ok((Pattern::RecordDestructure(patterns), state))
},
)
}
@ -1269,7 +1309,7 @@ pub fn record_literal<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>> {
for loc_assigned_field in assigned_fields {
let region = loc_assigned_field.region;
match assigned_field_to_pattern(arena, &loc_assigned_field.value) {
match assigned_expr_field_to_pattern(arena, &loc_assigned_field.value) {
Ok(value) => loc_patterns.push(Located { region, value }),
// an Expr became a pattern that should not be.
Err(e) => return Err((e, state)),
@ -1304,7 +1344,7 @@ pub fn record_literal<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>> {
for loc_assigned_field in assigned_fields {
let region = loc_assigned_field.region;
match assigned_field_to_pattern(arena, &loc_assigned_field.value) {
match assigned_expr_field_to_pattern(arena, &loc_assigned_field.value) {
Ok(value) => loc_patterns.push(Located { region, value }),
// an Expr became a pattern that should not be.
Err(e) => return Err((e, state)),