Merge pull request #4567 from joshuawarner32/tuple-type-annotation

Implement tuple type parsing
This commit is contained in:
Ayaz 2022-11-24 14:42:11 -06:00 committed by GitHub
commit 848c18f996
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 721 additions and 69 deletions

View file

@ -533,6 +533,13 @@ pub enum TypeAnnotation<'a> {
ext: Option<&'a Loc<TypeAnnotation<'a>>>,
},
Tuple {
fields: Collection<'a, Loc<TypeAnnotation<'a>>>,
/// The row type variable in an open record, e.g. the `r` in `{ name: Str }r`.
/// This is None if it's a closed record annotation like `{ name: Str }`.
ext: Option<&'a Loc<TypeAnnotation<'a>>>,
},
/// A tag union, e.g. `[
TagUnion {
/// The row type variable in an open tag union, e.g. the `a` in `[Foo, Bar]a`.

View file

@ -674,6 +674,9 @@ pub enum ETypeTagUnion<'a> {
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ETypeInParens<'a> {
/// e.g. (), which isn't a valid type
Empty(Position),
End(Position),
Open(Position),
///

View file

@ -116,7 +116,7 @@ fn term<'a>(stop_at_surface_has: bool) -> impl Parser<'a, Loc<TypeAnnotation<'a>
one_of!(
loc_wildcard(),
loc_inferred(),
specialize(EType::TInParens, loc_type_in_parens()),
specialize(EType::TInParens, loc_type_in_parens(stop_at_surface_has)),
loc!(specialize(EType::TRecord, record_type(stop_at_surface_has))),
loc!(specialize(
EType::TTagUnion,
@ -185,7 +185,7 @@ fn loc_applied_arg<'a>(
one_of!(
loc_wildcard(),
loc_inferred(),
specialize(EType::TInParens, loc_type_in_parens()),
specialize(EType::TInParens, loc_type_in_parens(stop_at_surface_has)),
loc!(specialize(EType::TRecord, record_type(stop_at_surface_has))),
loc!(specialize(
EType::TTagUnion,
@ -206,16 +206,45 @@ fn loc_applied_arg<'a>(
)
}
fn loc_type_in_parens<'a>() -> impl Parser<'a, Loc<TypeAnnotation<'a>>, ETypeInParens<'a>> {
between!(
word1(b'(', ETypeInParens::Open),
space0_around_ee(
specialize_ref(ETypeInParens::Type, expression(true, false)),
ETypeInParens::IndentOpen,
ETypeInParens::IndentEnd,
),
word1(b')', ETypeInParens::IndentEnd)
fn loc_type_in_parens<'a>(
stop_at_surface_has: bool,
) -> impl Parser<'a, Loc<TypeAnnotation<'a>>, ETypeInParens<'a>> {
then(
loc!(and!(
collection_trailing_sep_e!(
word1(b'(', ETypeInParens::Open),
specialize_ref(ETypeInParens::Type, expression(true, false)),
word1(b',', ETypeInParens::End),
word1(b')', ETypeInParens::End),
ETypeInParens::Open,
ETypeInParens::IndentEnd,
TypeAnnotation::SpaceBefore
),
optional(allocated(specialize_ref(
ETypeInParens::Type,
term(stop_at_surface_has)
)))
)),
|_arena, state, progress, item| {
let Loc {
region,
value: (fields, ext),
} = item;
if fields.len() > 1 || ext.is_some() {
Ok((
MadeProgress,
Loc::at(region, TypeAnnotation::Tuple { fields, ext }),
state,
))
} else if fields.len() == 1 {
Ok((MadeProgress, fields.items[0], state))
} else {
debug_assert!(fields.is_empty());
Err((progress, ETypeInParens::Empty(state.pos())))
}
},
)
.trace("type_annotation:type_in_parens")
}
#[inline(always)]
@ -322,29 +351,24 @@ fn record_type_field<'a>() -> impl Parser<'a, AssignedField<'a, TypeAnnotation<'
fn record_type<'a>(
stop_at_surface_has: bool,
) -> impl Parser<'a, TypeAnnotation<'a>, ETypeRecord<'a>> {
use crate::type_annotation::TypeAnnotation::*;
(move |arena, state, min_indent| {
let (_, fields, state) = collection_trailing_sep_e!(
// word1_check_indent!(b'{', TRecord::Open, min_indent, TRecord::IndentOpen),
word1(b'{', ETypeRecord::Open),
loc!(record_type_field()),
word1(b',', ETypeRecord::End),
// word1_check_indent!(b'}', TRecord::End, min_indent, TRecord::IndentEnd),
word1(b'}', ETypeRecord::End),
ETypeRecord::Open,
ETypeRecord::IndentEnd,
AssignedField::SpaceBefore
)
.parse(arena, state, min_indent)?;
let field_term = specialize_ref(ETypeRecord::Type, term(stop_at_surface_has));
let (_, ext, state) = optional(allocated(field_term)).parse(arena, state, min_indent)?;
let result = Record { fields, ext };
Ok((MadeProgress, result, state))
})
map!(
and!(
collection_trailing_sep_e!(
word1(b'{', ETypeRecord::Open),
loc!(record_type_field()),
word1(b',', ETypeRecord::End),
word1(b'}', ETypeRecord::End),
ETypeRecord::Open,
ETypeRecord::IndentEnd,
AssignedField::SpaceBefore
),
optional(allocated(specialize_ref(
ETypeRecord::Type,
term(stop_at_surface_has)
)))
),
|(fields, ext)| { TypeAnnotation::Record { fields, ext } }
)
.trace("type_annotation:record_type")
}