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

@ -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 => {

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 { 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)),

View file

@ -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",