mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 08:34:33 +00:00
parse guarded record patterns
e.g. case foo when { x: 4 } -> ... { x, y } -> ...
This commit is contained in:
parent
f47c2677ee
commit
1b2636bee6
3 changed files with 75 additions and 18 deletions
|
@ -329,6 +329,8 @@ fn add_constraints<'a>(
|
|||
) {
|
||||
use crate::parse::ast::Pattern::*;
|
||||
|
||||
dbg!(pattern);
|
||||
|
||||
match pattern {
|
||||
Underscore | Malformed(_) | QualifiedIdentifier(_) => {
|
||||
// Neither the _ pattern nor malformed ones add any constraints.
|
||||
|
@ -397,7 +399,7 @@ fn add_constraints<'a>(
|
|||
&loc_pattern.value,
|
||||
scope,
|
||||
loc_pattern.region,
|
||||
expected,
|
||||
expected.clone(),
|
||||
state,
|
||||
var_store,
|
||||
);
|
||||
|
@ -421,8 +423,7 @@ fn add_constraints<'a>(
|
|||
&guard.value,
|
||||
scope,
|
||||
guard.region,
|
||||
// expect the pattern to equal the field
|
||||
PExpected::NoExpectation(pat_type),
|
||||
expected,
|
||||
state,
|
||||
var_store,
|
||||
);
|
||||
|
@ -436,6 +437,7 @@ fn add_constraints<'a>(
|
|||
Constraint::Pattern(region, PatternCategory::Record, record_type, expected);
|
||||
|
||||
state.constraints.push(record_con);
|
||||
dbg!(&state.constraints);
|
||||
}
|
||||
|
||||
GlobalTag(_) | PrivateTag(_) | Apply(_, _) | RecordField(_, _) | EmptyRecordLiteral => {
|
||||
|
|
|
@ -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)),
|
||||
|
|
|
@ -956,7 +956,22 @@ mod test_infer {
|
|||
indoc!(
|
||||
r#"
|
||||
case { x : 4 , y : 3.14 } when
|
||||
{ x: 4 } -> x
|
||||
{ x, y } -> x
|
||||
{ y } -> 42
|
||||
"#
|
||||
),
|
||||
"Int",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn record_pattern_match_infer() {
|
||||
infer_eq(
|
||||
indoc!(
|
||||
r#"
|
||||
case foo when
|
||||
{x:4}-> x
|
||||
"#
|
||||
),
|
||||
"Int",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue