mirror of
https://github.com/roc-lang/roc.git
synced 2025-10-03 16:44: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::*;
|
use crate::parse::ast::Pattern::*;
|
||||||
|
|
||||||
|
dbg!(pattern);
|
||||||
|
|
||||||
match pattern {
|
match pattern {
|
||||||
Underscore | Malformed(_) | QualifiedIdentifier(_) => {
|
Underscore | Malformed(_) | QualifiedIdentifier(_) => {
|
||||||
// Neither the _ pattern nor malformed ones add any constraints.
|
// Neither the _ pattern nor malformed ones add any constraints.
|
||||||
|
@ -397,7 +399,7 @@ fn add_constraints<'a>(
|
||||||
&loc_pattern.value,
|
&loc_pattern.value,
|
||||||
scope,
|
scope,
|
||||||
loc_pattern.region,
|
loc_pattern.region,
|
||||||
expected,
|
expected.clone(),
|
||||||
state,
|
state,
|
||||||
var_store,
|
var_store,
|
||||||
);
|
);
|
||||||
|
@ -421,8 +423,7 @@ fn add_constraints<'a>(
|
||||||
&guard.value,
|
&guard.value,
|
||||||
scope,
|
scope,
|
||||||
guard.region,
|
guard.region,
|
||||||
// expect the pattern to equal the field
|
expected,
|
||||||
PExpected::NoExpectation(pat_type),
|
|
||||||
state,
|
state,
|
||||||
var_store,
|
var_store,
|
||||||
);
|
);
|
||||||
|
@ -436,6 +437,7 @@ fn add_constraints<'a>(
|
||||||
Constraint::Pattern(region, PatternCategory::Record, record_type, expected);
|
Constraint::Pattern(region, PatternCategory::Record, record_type, expected);
|
||||||
|
|
||||||
state.constraints.push(record_con);
|
state.constraints.push(record_con);
|
||||||
|
dbg!(&state.constraints);
|
||||||
}
|
}
|
||||||
|
|
||||||
GlobalTag(_) | PrivateTag(_) | Apply(_, _) | RecordField(_, _) | EmptyRecordLiteral => {
|
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 {
|
for loc_assigned_field in loc_assigned_fields {
|
||||||
let region = loc_assigned_field.region;
|
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 });
|
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,
|
arena: &'a Bump,
|
||||||
assigned_field: &AssignedField<'a, Expr<'a>>,
|
assigned_field: &AssignedField<'a, Expr<'a>>,
|
||||||
) -> Result<Pattern<'a>, Fail> {
|
) -> Result<Pattern<'a>, Fail> {
|
||||||
|
@ -354,11 +355,46 @@ pub fn assigned_field_to_pattern<'a>(
|
||||||
}
|
}
|
||||||
AssignedField::LabelOnly(name) => Pattern::Identifier(name.value),
|
AssignedField::LabelOnly(name) => Pattern::Identifier(name.value),
|
||||||
AssignedField::SpaceBefore(nested, spaces) => Pattern::SpaceBefore(
|
AssignedField::SpaceBefore(nested, spaces) => Pattern::SpaceBefore(
|
||||||
arena.alloc(assigned_field_to_pattern(arena, nested)?),
|
arena.alloc(assigned_expr_field_to_pattern(arena, nested)?),
|
||||||
spaces,
|
spaces,
|
||||||
),
|
),
|
||||||
AssignedField::SpaceAfter(nested, spaces) => Pattern::SpaceAfter(
|
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,
|
spaces,
|
||||||
),
|
),
|
||||||
AssignedField::Malformed(string) => Pattern::Malformed(string),
|
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>> {
|
fn record_destructure<'a>(min_indent: u16) -> impl Parser<'a, Pattern<'a>> {
|
||||||
map!(
|
then(
|
||||||
collection!(
|
record!(loc!(pattern(min_indent)), min_indent),
|
||||||
char('{'),
|
move |arena, state, assigned_fields| {
|
||||||
loc!(ident_pattern()),
|
let mut patterns = Vec::with_capacity_in(assigned_fields.len(), arena);
|
||||||
char(','),
|
for assigned_field in assigned_fields {
|
||||||
char('}'),
|
match assigned_pattern_field_to_pattern(arena, &assigned_field.value) {
|
||||||
min_indent
|
Ok(pattern) => patterns.push(Located::at(assigned_field.region, pattern)),
|
||||||
),
|
Err(e) => return Err((e, state)),
|
||||||
Pattern::RecordDestructure
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
for loc_assigned_field in assigned_fields {
|
||||||
let region = loc_assigned_field.region;
|
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 }),
|
Ok(value) => loc_patterns.push(Located { region, value }),
|
||||||
// an Expr became a pattern that should not be.
|
// an Expr became a pattern that should not be.
|
||||||
Err(e) => return Err((e, state)),
|
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 {
|
for loc_assigned_field in assigned_fields {
|
||||||
let region = loc_assigned_field.region;
|
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 }),
|
Ok(value) => loc_patterns.push(Located { region, value }),
|
||||||
// an Expr became a pattern that should not be.
|
// an Expr became a pattern that should not be.
|
||||||
Err(e) => return Err((e, state)),
|
Err(e) => return Err((e, state)),
|
||||||
|
|
|
@ -956,7 +956,22 @@ mod test_infer {
|
||||||
indoc!(
|
indoc!(
|
||||||
r#"
|
r#"
|
||||||
case { x : 4 , y : 3.14 } when
|
case { x : 4 , y : 3.14 } when
|
||||||
|
{ x: 4 } -> x
|
||||||
{ x, y } -> x
|
{ x, y } -> x
|
||||||
|
{ y } -> 42
|
||||||
|
"#
|
||||||
|
),
|
||||||
|
"Int",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn record_pattern_match_infer() {
|
||||||
|
infer_eq(
|
||||||
|
indoc!(
|
||||||
|
r#"
|
||||||
|
case foo when
|
||||||
|
{x:4}-> x
|
||||||
"#
|
"#
|
||||||
),
|
),
|
||||||
"Int",
|
"Int",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue