Allow function types in records

This commit is contained in:
Joshua Warner 2021-12-16 17:03:08 -08:00
parent 5e7e77dbb1
commit 7b9c8ed939
6 changed files with 339 additions and 39 deletions

View file

@ -232,7 +232,7 @@ fn record_type_field<'a>(
))
.parse(arena, state)?;
let val_parser = specialize_ref(ETypeRecord::Type, term(min_indent));
let val_parser = specialize_ref(ETypeRecord::Type, expression(min_indent));
match opt_loc_val {
Some(First(_)) => {
@ -353,7 +353,8 @@ fn expression<'a>(min_indent: u16) -> impl Parser<'a, Located<TypeAnnotation<'a>
)
.parse(arena, state)?;
let (p2, rest, state) = zero_or_more!(skip_first!(
let (p2, pre_func, state) = optional(and![
zero_or_more!(skip_first!(
word1(b',', EType::TFunctionArgument),
one_of![
space0_around_ee(
@ -370,20 +371,19 @@ fn expression<'a>(min_indent: u16) -> impl Parser<'a, Located<TypeAnnotation<'a>
))
]
))
.trace("type_annotation:expression:rest_args")
.parse(arena, state)?;
.trace("type_annotation:expression:rest_args"),
// TODO this space0 is dropped, so newlines just before the function arrow when there
// is only one argument are not seen by the formatter. Can we do better?
let (p3, is_function, state) = optional(skip_first!(
skip_second!(
space0_e(min_indent, EType::TSpace, EType::TIndentStart),
word2(b'-', b'>', EType::TStart)
))
)
.trace("type_annotation:expression:arrow")
])
.parse(arena, state)?;
if is_function.is_some() {
let (p4, return_type, state) = space0_before_e(
if let Some((rest, _dropped_spaces)) = pre_func {
let (p3, return_type, state) = space0_before_e(
term(min_indent),
min_indent,
EType::TSpace,
@ -401,17 +401,11 @@ fn expression<'a>(min_indent: u16) -> impl Parser<'a, Located<TypeAnnotation<'a>
region: return_type.region,
value: TypeAnnotation::Function(output, arena.alloc(return_type)),
};
let progress = p1.or(p2).or(p3).or(p4);
let progress = p1.or(p2).or(p3);
Ok((progress, result, state))
} else {
let progress = p1.or(p2).or(p3);
// if there is no function arrow, there cannot be more than 1 "argument"
if rest.is_empty() {
Ok((progress, first, state))
} else {
// e.g. `Int,Int` without an arrow and return type
panic!()
}
// We ran into trouble parsing the function bits; just return the single term
Ok((p1, first, state))
}
})
.trace("type_annotation:expression")

View file

@ -0,0 +1,171 @@
Platform {
header: PlatformHeader {
name: |L 0-0, C 9-21| PackageName {
account: "examples",
pkg: "cli",
},
requires: PlatformRequires {
rigids: [],
signature: |L 1-1, C 17-34| TypedIdent {
ident: |L 1-1, C 17-21| "main",
spaces_before_colon: [],
ann: |L 1-1, C 24-34| Apply(
"",
"Task",
[
|L 1-1, C 29-31| Record {
fields: [],
ext: None,
},
|L 1-1, C 32-34| TagUnion {
ext: None,
tags: [],
},
],
),
},
},
exposes: [],
packages: [],
imports: [
|L 4-4, C 14-27| Module(
ModuleName(
"Task",
),
[
|L 4-4, C 21-25| ExposedName(
"Task",
),
],
),
],
provides: [
|L 5-5, C 15-26| ExposedName(
"mainForHost",
),
],
effects: Effects {
spaces_before_effects_keyword: [
Newline,
],
spaces_after_effects_keyword: [],
spaces_after_type_name: [
Newline,
],
effect_shortname: "fx",
effect_type_name: "Effect",
entries: [
|L 8-8, C 12-32| SpaceBefore(
TypedIdent {
ident: |L 8-8, C 12-19| "getLine",
spaces_before_colon: [],
ann: |L 8-8, C 22-32| Apply(
"",
"Effect",
[
|L 8-8, C 29-32| Apply(
"",
"Str",
[],
),
],
),
},
[
Newline,
],
),
|L 9-9, C 12-38| SpaceBefore(
TypedIdent {
ident: |L 9-9, C 12-19| "putLine",
spaces_before_colon: [],
ann: |L 9-9, C 29-38| Function(
[
|L 9-9, C 22-25| Apply(
"",
"Str",
[],
),
],
|L 9-9, C 29-38| Apply(
"",
"Effect",
[
|L 9-9, C 36-38| Record {
fields: [],
ext: None,
},
],
),
),
},
[
Newline,
],
),
|L 10-10, C 12-48| SpaceBefore(
SpaceAfter(
TypedIdent {
ident: |L 10-10, C 12-24| "twoArguments",
spaces_before_colon: [],
ann: |L 10-10, C 39-48| Function(
[
|L 10-10, C 27-30| Apply(
"",
"Int",
[],
),
|L 10-10, C 32-35| Apply(
"",
"Int",
[],
),
],
|L 10-10, C 39-48| Apply(
"",
"Effect",
[
|L 10-10, C 46-48| Record {
fields: [],
ext: None,
},
],
),
),
},
[
Newline,
],
),
[
Newline,
],
),
],
},
before_header: [],
after_platform_keyword: [],
before_requires: [
Newline,
],
after_requires: [],
before_exposes: [
LineComment(
" TODO FIXME",
),
],
after_exposes: [],
before_packages: [
Newline,
],
after_packages: [],
before_imports: [
Newline,
],
after_imports: [],
before_provides: [
Newline,
],
after_provides: [],
},
}

View file

@ -0,0 +1,12 @@
platform examples/cli
requires {}{ main : Task {} [] } # TODO FIXME
exposes []
packages {}
imports [ Task.{ Task } ]
provides [ mainForHost ]
effects fx.Effect
{
getLine : Effect Str,
putLine : Str -> Effect {},
twoArguments : Int, Int -> Effect {}
}

View file

@ -0,0 +1,112 @@
Defs(
[
|L 0-6, C 0-5| Annotation(
|L 0-0, C 0-1| Identifier(
"f",
),
|L 1-6, C 4-5| SpaceBefore(
Record {
fields: [
|L 2-2, C 8-28| SpaceBefore(
RequiredValue(
|L 2-2, C 8-15| "getLine",
[],
|L 2-2, C 18-28| Apply(
"",
"Effect",
[
|L 2-2, C 25-28| Apply(
"",
"Str",
[],
),
],
),
),
[
Newline,
],
),
|L 3-3, C 8-35| SpaceBefore(
RequiredValue(
|L 3-3, C 8-15| "putLine",
[],
|L 3-3, C 25-35| Function(
[
|L 3-3, C 18-21| Apply(
"",
"Str",
[],
),
],
|L 3-3, C 25-35| Apply(
"",
"Effect",
[
|L 3-3, C 32-35| Apply(
"",
"Int",
[],
),
],
),
),
),
[
Newline,
],
),
|L 4-4, C 8-17| SpaceBefore(
RequiredValue(
|L 4-4, C 8-12| "text",
[],
|L 4-4, C 14-17| Apply(
"",
"Str",
[],
),
),
[
Newline,
],
),
|L 5-5, C 8-20| SpaceBefore(
SpaceAfter(
RequiredValue(
|L 5-5, C 8-13| "value",
[],
|L 5-5, C 15-20| Apply(
"",
"Int",
[
|L 5-5, C 19-20| Wildcard,
],
),
),
[
Newline,
],
),
[
Newline,
],
),
],
ext: None,
},
[
Newline,
],
),
),
],
|L 8-8, C 0-2| SpaceBefore(
Num(
"42",
),
[
Newline,
Newline,
],
),
)

View file

@ -0,0 +1,9 @@
f :
{
getLine : Effect Str,
putLine : Str -> Effect Int,
text: Str,
value: Int *
}
42

View file

@ -140,6 +140,7 @@ mod test_parse {
pass/float_with_underscores.expr,
pass/full_app_header_trailing_commas.header,
pass/full_app_header.header,
pass/function_effect_types.header,
pass/highest_float.expr,
pass/highest_int.expr,
pass/if_def.expr,
@ -197,6 +198,7 @@ mod test_parse {
pass/qualified_global_tag.expr,
pass/qualified_var.expr,
pass/record_destructure_def.expr,
pass/record_func_type_decl.expr,
pass/record_update.expr,
pass/record_with_if.expr,
pass/single_arg_closure.expr,