Un-macro map

This commit is contained in:
Jackson Wambolt 2024-04-15 19:56:30 -05:00
parent 41d7d02e2a
commit 3394aab650
No known key found for this signature in database
GPG Key ID: 76F29A42FEE8811C
5 changed files with 90 additions and 97 deletions

View File

@ -11,10 +11,10 @@ use crate::ident::{integer_ident, lowercase_ident, parse_ident, Accessor, Ident}
use crate::keyword; use crate::keyword;
use crate::parser::{ use crate::parser::{
self, and, backtrackable, between, byte, byte_indent, increment_min_indent, indented_seq, self, and, backtrackable, between, byte, byte_indent, increment_min_indent, indented_seq,
line_min_indent, optional, reset_min_indent, sep_by1, sep_by1_e, set_min_indent, skip_first, line_min_indent, map, optional, reset_min_indent, sep_by1, sep_by1_e, set_min_indent,
skip_second, specialize_err, specialize_err_ref, then, two_bytes, EClosure, EExpect, EExpr, skip_first, skip_second, specialize_err, specialize_err_ref, then, two_bytes, EClosure,
EIf, EInParens, EList, ENumber, EPattern, ERecord, EString, EType, EWhen, Either, ParseResult, EExpect, EExpr, EIf, EInParens, EList, ENumber, EPattern, ERecord, EString, EType, EWhen,
Parser, Either, ParseResult, Parser,
}; };
use crate::pattern::{closure_param, loc_implements_parser}; use crate::pattern::{closure_param, loc_implements_parser};
use crate::state::State; use crate::state::State;
@ -163,8 +163,8 @@ fn record_field_access_chain<'a>() -> impl Parser<'a, Vec<'a, Accessor<'a>>, EEx
specialize_err( specialize_err(
|_, pos| EExpr::Access(pos), |_, pos| EExpr::Access(pos),
one_of!( one_of!(
map!(lowercase_ident(), Accessor::RecordField), map(lowercase_ident(), Accessor::RecordField),
map!(integer_ident(), Accessor::TupleIndex), map(integer_ident(), Accessor::TupleIndex),
) )
) )
)) ))
@ -1483,7 +1483,7 @@ mod ability {
/// Parses a single ability demand line; see `parse_demand`. /// Parses a single ability demand line; see `parse_demand`.
fn parse_demand_help<'a>() -> impl Parser<'a, AbilityMember<'a>, EAbility<'a>> { fn parse_demand_help<'a>() -> impl Parser<'a, AbilityMember<'a>, EAbility<'a>> {
map!( map(
// Require the type to be more indented than the name // Require the type to be more indented than the name
absolute_indented_seq( absolute_indented_seq(
specialize_err(|_, pos| EAbility::DemandName(pos), loc!(lowercase_ident())), specialize_err(|_, pos| EAbility::DemandName(pos), loc!(lowercase_ident())),
@ -1491,17 +1491,15 @@ mod ability {
and( and(
// TODO: do we get anything from picking up spaces here? // TODO: do we get anything from picking up spaces here?
space0_e(EAbility::DemandName), space0_e(EAbility::DemandName),
byte(b':', EAbility::DemandColon) byte(b':', EAbility::DemandColon),
), ),
specialize_err(EAbility::Type, type_annotation::located(true)) specialize_err(EAbility::Type, type_annotation::located(true)),
) ),
), ),
|(name, typ): (Loc<&'a str>, Loc<TypeAnnotation<'a>>)| { |(name, typ): (Loc<&'a str>, Loc<TypeAnnotation<'a>>)| AbilityMember {
AbilityMember { name: name.map_owned(Spaced::Item),
name: name.map_owned(Spaced::Item), typ,
typ, },
}
}
) )
} }
@ -2457,7 +2455,7 @@ mod when {
guard: loc_first_guard, guard: loc_first_guard,
})); }));
let branch_parser = map!( let branch_parser = map(
and( and(
then( then(
branch_alternatives(options, Some(pattern_indent_level)), branch_alternatives(options, Some(pattern_indent_level)),
@ -2470,7 +2468,7 @@ mod when {
} }
}, },
), ),
branch_result(original_indent + 1) branch_result(original_indent + 1),
), ),
|((patterns, guard), expr)| { |((patterns, guard), expr)| {
let patterns: Vec<'a, _> = patterns; let patterns: Vec<'a, _> = patterns;
@ -2479,7 +2477,7 @@ mod when {
value: expr, value: expr,
guard, guard,
} }
} },
); );
while !state.bytes().is_empty() { while !state.bytes().is_empty() {
@ -2514,7 +2512,7 @@ mod when {
and( and(
branch_alternatives_help(pattern_indent_level), branch_alternatives_help(pattern_indent_level),
one_of![ one_of![
map!( map(
skip_first( skip_first(
parser::keyword(keyword::IF, EWhen::IfToken), parser::keyword(keyword::IF, EWhen::IfToken),
// TODO we should require space before the expression but not after // TODO we should require space before the expression but not after
@ -3199,7 +3197,7 @@ fn string_like_literal_help<'a>() -> impl Parser<'a, Expr<'a>, EString<'a>> {
} }
fn positive_number_literal_help<'a>() -> impl Parser<'a, Expr<'a>, ENumber> { fn positive_number_literal_help<'a>() -> impl Parser<'a, Expr<'a>, ENumber> {
map!( map(
crate::number_literal::positive_number_literal(), crate::number_literal::positive_number_literal(),
|literal| { |literal| {
use crate::number_literal::NumLiteral::*; use crate::number_literal::NumLiteral::*;
@ -3217,12 +3215,12 @@ fn positive_number_literal_help<'a>() -> impl Parser<'a, Expr<'a>, ENumber> {
is_negative, is_negative,
}, },
} }
} },
) )
} }
fn number_literal_help<'a>() -> impl Parser<'a, Expr<'a>, ENumber> { fn number_literal_help<'a>() -> impl Parser<'a, Expr<'a>, ENumber> {
map!(crate::number_literal::number_literal(), |literal| { map(crate::number_literal::number_literal(), |literal| {
use crate::number_literal::NumLiteral::*; use crate::number_literal::NumLiteral::*;
match literal { match literal {

View File

@ -9,7 +9,7 @@ use crate::header::{
use crate::ident::{self, lowercase_ident, unqualified_ident, uppercase, UppercaseIdent}; use crate::ident::{self, lowercase_ident, unqualified_ident, uppercase, UppercaseIdent};
use crate::parser::Progress::{self, *}; use crate::parser::Progress::{self, *};
use crate::parser::{ use crate::parser::{
and, backtrackable, byte, increment_min_indent, optional, reset_min_indent, skip_first, and, backtrackable, byte, increment_min_indent, map, optional, reset_min_indent, skip_first,
skip_second, specialize_err, two_bytes, EExposes, EGenerates, EGeneratesWith, EHeader, skip_second, specialize_err, two_bytes, EExposes, EGenerates, EGeneratesWith, EHeader,
EImports, EPackages, EProvides, ERequires, ETypedIdent, Parser, SourceError, SpaceProblem, EImports, EPackages, EProvides, ERequires, ETypedIdent, Parser, SourceError, SpaceProblem,
SyntaxError, SyntaxError,
@ -54,35 +54,35 @@ pub fn header<'a>() -> impl Parser<'a, Module<'a>, EHeader<'a>> {
record!(Module { record!(Module {
comments: space0_e(EHeader::IndentStart), comments: space0_e(EHeader::IndentStart),
header: one_of![ header: one_of![
map!( map(
skip_first( skip_first(
keyword("interface", EHeader::Start), keyword("interface", EHeader::Start),
increment_min_indent(interface_header()) increment_min_indent(interface_header())
), ),
Header::Interface Header::Interface
), ),
map!( map(
skip_first( skip_first(
keyword("app", EHeader::Start), keyword("app", EHeader::Start),
increment_min_indent(app_header()) increment_min_indent(app_header())
), ),
Header::App Header::App
), ),
map!( map(
skip_first( skip_first(
keyword("package", EHeader::Start), keyword("package", EHeader::Start),
increment_min_indent(package_header()) increment_min_indent(package_header())
), ),
Header::Package Header::Package
), ),
map!( map(
skip_first( skip_first(
keyword("platform", EHeader::Start), keyword("platform", EHeader::Start),
increment_min_indent(platform_header()) increment_min_indent(platform_header())
), ),
Header::Platform Header::Platform
), ),
map!( map(
skip_first( skip_first(
keyword("hosted", EHeader::Start), keyword("hosted", EHeader::Start),
increment_min_indent(hosted_header()) increment_min_indent(hosted_header())
@ -220,9 +220,9 @@ fn provides_to_package<'a>() -> impl Parser<'a, To<'a>, EProvides<'a>> {
one_of![ one_of![
specialize_err( specialize_err(
|_, pos| EProvides::Identifier(pos), |_, pos| EProvides::Identifier(pos),
map!(lowercase_ident(), To::ExistingPackage) map(lowercase_ident(), To::ExistingPackage)
), ),
specialize_err(EProvides::Package, map!(package_name(), To::NewPackage)) specialize_err(EProvides::Package, map(package_name(), To::NewPackage))
] ]
} }
@ -309,7 +309,7 @@ where
F: Copy, F: Copy,
E: 'a, E: 'a,
{ {
loc!(map!( loc!(map(
specialize_err(|_, pos| to_expectation(pos), ident::uppercase()), specialize_err(|_, pos| to_expectation(pos), ident::uppercase()),
Spaced::Item Spaced::Item
)) ))
@ -323,7 +323,7 @@ where
F: Copy, F: Copy,
E: 'a, E: 'a,
{ {
loc!(map!( loc!(map(
specialize_err(|_, pos| to_expectation(pos), unqualified_ident()), specialize_err(|_, pos| to_expectation(pos), unqualified_ident()),
|n| Spaced::Item(ExposedName::new(n)) |n| Spaced::Item(ExposedName::new(n))
)) ))
@ -358,7 +358,7 @@ fn requires_rigids<'a>(
byte(b'{', ERequires::ListStart), byte(b'{', ERequires::ListStart),
specialize_err( specialize_err(
|_, pos| ERequires::Rigid(pos), |_, pos| ERequires::Rigid(pos),
loc!(map!(ident::uppercase(), Spaced::Item)) loc!(map(ident::uppercase(), Spaced::Item))
), ),
byte(b',', ERequires::ListEnd), byte(b',', ERequires::ListEnd),
byte(b'}', ERequires::ListEnd), byte(b'}', ERequires::ListEnd),
@ -413,24 +413,22 @@ fn spaces_around_keyword<'a, K: Keyword, E>(
where where
E: 'a + SpaceProblem, E: 'a + SpaceProblem,
{ {
map!( map(
and( and(
skip_second( skip_second(
// parse any leading space before the keyword // parse any leading space before the keyword
backtrackable(space0_e(indent_problem1)), backtrackable(space0_e(indent_problem1)),
// parse the keyword // parse the keyword
crate::parser::keyword(K::KEYWORD, expectation) crate::parser::keyword(K::KEYWORD, expectation),
), ),
// parse the trailing space // parse the trailing space
space0_e(indent_problem2) space0_e(indent_problem2),
), ),
|(before, after)| { move |(before, after)| Spaces {
Spaces { before,
before, item: keyword_item,
item: keyword_item, after,
after, },
}
}
) )
} }
@ -465,7 +463,7 @@ where
F: Copy, F: Copy,
E: 'a, E: 'a,
{ {
loc!(map!( loc!(map(
specialize_err(|_, pos| to_expectation(pos), module_name()), specialize_err(|_, pos| to_expectation(pos), module_name()),
Spaced::Item Spaced::Item
)) ))
@ -560,25 +558,25 @@ fn typed_ident<'a>() -> impl Parser<'a, Spaced<'a, TypedIdent<'a>>, ETypedIdent<
// e.g. // e.g.
// //
// printLine : Str -> Effect {} // printLine : Str -> Effect {}
map!( map(
and( and(
and( and(
loc!(specialize_err( loc!(specialize_err(
|_, pos| ETypedIdent::Identifier(pos), |_, pos| ETypedIdent::Identifier(pos),
lowercase_ident() lowercase_ident()
)), )),
space0_e(ETypedIdent::IndentHasType) space0_e(ETypedIdent::IndentHasType),
), ),
skip_first( skip_first(
byte(b':', ETypedIdent::HasType), byte(b':', ETypedIdent::HasType),
space0_before_e( space0_before_e(
specialize_err( specialize_err(
ETypedIdent::Type, ETypedIdent::Type,
reset_min_indent(type_annotation::located(true)) reset_min_indent(type_annotation::located(true)),
), ),
ETypedIdent::IndentType, ETypedIdent::IndentType,
) ),
) ),
), ),
|((ident, spaces_before_colon), ann)| { |((ident, spaces_before_colon), ann)| {
Spaced::Item(TypedIdent { Spaced::Item(TypedIdent {
@ -586,7 +584,7 @@ fn typed_ident<'a>() -> impl Parser<'a, Spaced<'a, TypedIdent<'a>>, ETypedIdent<
spaces_before_colon, spaces_before_colon,
ann, ann,
}) })
} },
) )
} }
@ -611,7 +609,7 @@ fn imports_entry<'a>() -> impl Parser<'a, Spaced<'a, ImportsEntry<'a>>, EImports
); );
one_of!( one_of!(
map!( map(
and( and(
and( and(
// e.g. `pf.` // e.g. `pf.`
@ -649,7 +647,7 @@ fn imports_entry<'a>() -> impl Parser<'a, Spaced<'a, ImportsEntry<'a>>, EImports
} }
) )
.trace("normal_import"), .trace("normal_import"),
map!( map(
and( and(
and( and(
// e.g. "filename" // e.g. "filename"

View File

@ -2194,7 +2194,7 @@ macro_rules! byte_check_indent {
/// # NotFound(Position), /// # NotFound(Position),
/// # } /// # }
/// # let arena = Bump::new(); /// # let arena = Bump::new();
/// let parser = map!( /// let parser = map(
/// word("hello", Problem::NotFound), /// word("hello", Problem::NotFound),
/// |_output| "new output!" /// |_output| "new output!"
/// ); /// );
@ -2210,20 +2210,19 @@ macro_rules! byte_check_indent {
/// assert_eq!(progress, Progress::NoProgress); /// assert_eq!(progress, Progress::NoProgress);
/// assert_eq!(err, Problem::NotFound(Position::zero())); /// assert_eq!(err, Problem::NotFound(Position::zero()));
/// ``` /// ```
#[macro_export] pub fn map<'a, Output, MappedOutput, E: 'a>(
macro_rules! map { parser: impl Parser<'a, Output, E>,
($parser:expr, $transform:expr) => { transform: impl Fn(Output) -> MappedOutput,
move |arena, state, min_indent| { ) -> impl Parser<'a, MappedOutput, E> {
#[allow(clippy::redundant_closure_call)] move |arena, state, min_indent| {
$parser parser
.parse(arena, state, min_indent) .parse(arena, state, min_indent)
.map(|(progress, output, next_state)| (progress, $transform(output), next_state)) .map(|(progress, output, next_state)| (progress, transform(output), next_state))
} }
};
} }
/// Maps/transforms the `Ok` result of parsing using the given function. /// Maps/transforms the `Ok` result of parsing using the given function.
/// Similar to [`map!`], but the transform function also takes a bump allocator. /// Similar to [`map`], but the transform function also takes a bump allocator.
/// ///
/// # Example /// # Example
/// ///
@ -2580,9 +2579,7 @@ where
} }
/// Maps/transforms the `Ok` result of parsing using the given function. /// Maps/transforms the `Ok` result of parsing using the given function.
/// Similar to [`map!`], but the transform function also takes a bump allocator. /// Similar to [`map`], but the transform function also takes a bump allocator.
///
/// Function version of the [`map_with_arena!`] macro.
/// ///
/// For some reason, some usages won't compile unless they use this instead of the macro version. /// For some reason, some usages won't compile unless they use this instead of the macro version.
/// This is likely because the lifetime `'a` is not defined at the call site. /// This is likely because the lifetime `'a` is not defined at the call site.

View File

@ -4,8 +4,8 @@ use crate::ident::{lowercase_ident, parse_ident, Accessor, Ident};
use crate::keyword; use crate::keyword;
use crate::parser::Progress::{self, *}; use crate::parser::Progress::{self, *};
use crate::parser::{ use crate::parser::{
self, backtrackable, byte, fail_when, optional, skip_first, specialize_err, specialize_err_ref, self, backtrackable, byte, fail_when, map, optional, skip_first, specialize_err,
then, three_bytes, two_bytes, EPattern, PInParens, PList, PRecord, Parser, specialize_err_ref, then, three_bytes, two_bytes, EPattern, PInParens, PList, PRecord, Parser,
}; };
use crate::state::State; use crate::state::State;
use crate::string_literal::StrLikeLiteral; use crate::string_literal::StrLikeLiteral;
@ -232,7 +232,7 @@ fn loc_pattern_in_parens_help<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, PInPare
fn number_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, EPattern<'a>> { fn number_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, EPattern<'a>> {
specialize_err( specialize_err(
EPattern::NumLiteral, EPattern::NumLiteral,
map!(crate::number_literal::number_literal(), |literal| { map(crate::number_literal::number_literal(), |literal| {
use crate::number_literal::NumLiteral::*; use crate::number_literal::NumLiteral::*;
match literal { match literal {
@ -269,7 +269,7 @@ fn string_like_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, EPattern<'a>>
} }
fn list_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, PList<'a>> { fn list_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, PList<'a>> {
map!( map(
collection_trailing_sep_e!( collection_trailing_sep_e!(
byte(b'[', PList::Open), byte(b'[', PList::Open),
list_element_pattern(), list_element_pattern(),
@ -277,7 +277,7 @@ fn list_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, PList<'a>> {
byte(b']', PList::End), byte(b']', PList::End),
Pattern::SpaceBefore Pattern::SpaceBefore
), ),
Pattern::List Pattern::List,
) )
} }
@ -502,15 +502,15 @@ fn loc_ident_pattern_help<'a>(
} }
fn underscore_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, EPattern<'a>> { fn underscore_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, EPattern<'a>> {
map!( map(
skip_first( skip_first(
byte(b'_', EPattern::Underscore), byte(b'_', EPattern::Underscore),
optional(lowercase_ident_pattern()) optional(lowercase_ident_pattern()),
), ),
|output| match output { |output| match output {
Some(name) => Pattern::Underscore(name), Some(name) => Pattern::Underscore(name),
None => Pattern::Underscore(""), None => Pattern::Underscore(""),
} },
) )
} }
@ -520,7 +520,7 @@ fn lowercase_ident_pattern<'a>() -> impl Parser<'a, &'a str, EPattern<'a>> {
#[inline(always)] #[inline(always)]
fn record_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, PRecord<'a>> { fn record_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, PRecord<'a>> {
map!( map(
collection_trailing_sep_e!( collection_trailing_sep_e!(
byte(b'{', PRecord::Open), byte(b'{', PRecord::Open),
record_pattern_field(), record_pattern_field(),
@ -528,7 +528,7 @@ fn record_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, PRecord<'a>> {
byte(b'}', PRecord::End), byte(b'}', PRecord::End),
Pattern::SpaceBefore Pattern::SpaceBefore
), ),
Pattern::RecordDestructure Pattern::RecordDestructure,
) )
} }

View File

@ -9,8 +9,8 @@ use crate::expr::{record_field, FoundApplyValue};
use crate::ident::{lowercase_ident, lowercase_ident_keyword_e}; use crate::ident::{lowercase_ident, lowercase_ident_keyword_e};
use crate::keyword; use crate::keyword;
use crate::parser::{ use crate::parser::{
absolute_column_min_indent, and, increment_min_indent, skip_first, skip_second, then, ERecord, absolute_column_min_indent, and, increment_min_indent, map, skip_first, skip_second, then,
ETypeAbilityImpl, ERecord, ETypeAbilityImpl,
}; };
use crate::parser::{ use crate::parser::{
allocated, backtrackable, byte, fail, optional, specialize_err, specialize_err_ref, two_bytes, allocated, backtrackable, byte, fail, optional, specialize_err, specialize_err_ref, two_bytes,
@ -136,7 +136,7 @@ fn term<'a>(stop_at_surface_has: bool) -> impl Parser<'a, Loc<TypeAnnotation<'a>
), ),
// Inline alias notation, e.g. [Nil, Cons a (List a)] as List a // Inline alias notation, e.g. [Nil, Cons a (List a)] as List a
one_of![ one_of![
map!( map(
and( and(
skip_second( skip_second(
backtrackable(space0_e(EType::TIndentEnd)), backtrackable(space0_e(EType::TIndentEnd)),
@ -170,7 +170,7 @@ fn term<'a>(stop_at_surface_has: bool) -> impl Parser<'a, Loc<TypeAnnotation<'a>
/// The `*` type variable, e.g. in (List *) Wildcard, /// The `*` type variable, e.g. in (List *) Wildcard,
fn loc_wildcard<'a>() -> impl Parser<'a, Loc<TypeAnnotation<'a>>, EType<'a>> { fn loc_wildcard<'a>() -> impl Parser<'a, Loc<TypeAnnotation<'a>>, EType<'a>> {
map!(loc!(byte(b'*', EType::TWildcard)), |loc_val: Loc<()>| { map(loc!(byte(b'*', EType::TWildcard)), |loc_val: Loc<()>| {
loc_val.map(|_| TypeAnnotation::Wildcard) loc_val.map(|_| TypeAnnotation::Wildcard)
}) })
} }
@ -398,12 +398,12 @@ fn record_type<'a>(
} }
fn applied_type<'a>(stop_at_surface_has: bool) -> impl Parser<'a, TypeAnnotation<'a>, EType<'a>> { fn applied_type<'a>(stop_at_surface_has: bool) -> impl Parser<'a, TypeAnnotation<'a>, EType<'a>> {
map!( map(
and( and(
specialize_err(EType::TApply, concrete_type()), specialize_err(EType::TApply, concrete_type()),
// Optionally parse space-separated arguments for the constructor, // Optionally parse space-separated arguments for the constructor,
// e.g. `Str Float` in `Map Str Float` // e.g. `Str Float` in `Map Str Float`
loc_applied_args_e(stop_at_surface_has) loc_applied_args_e(stop_at_surface_has),
), ),
|(ctor, args): (TypeAnnotation<'a>, Vec<'a, Loc<TypeAnnotation<'a>>>)| { |(ctor, args): (TypeAnnotation<'a>, Vec<'a, Loc<TypeAnnotation<'a>>>)| {
match &ctor { match &ctor {
@ -418,7 +418,7 @@ fn applied_type<'a>(stop_at_surface_has: bool) -> impl Parser<'a, TypeAnnotation
TypeAnnotation::Malformed(_) => ctor, TypeAnnotation::Malformed(_) => ctor,
_ => unreachable!(), _ => unreachable!(),
} }
} },
) )
.trace("type_annotation:applied_type") .trace("type_annotation:applied_type")
} }
@ -431,7 +431,7 @@ fn loc_applied_args_e<'a>(
// Hash & Eq & ... // Hash & Eq & ...
fn ability_chain<'a>() -> impl Parser<'a, Vec<'a, Loc<TypeAnnotation<'a>>>, EType<'a>> { fn ability_chain<'a>() -> impl Parser<'a, Vec<'a, Loc<TypeAnnotation<'a>>>, EType<'a>> {
map!( map(
and( and(
space0_before_optional_after( space0_before_optional_after(
specialize_err(EType::TApply, loc!(concrete_type())), specialize_err(EType::TApply, loc!(concrete_type())),
@ -445,37 +445,37 @@ fn ability_chain<'a>() -> impl Parser<'a, Vec<'a, Loc<TypeAnnotation<'a>>>, ETyp
EType::TIndentStart, EType::TIndentStart,
EType::TIndentEnd, EType::TIndentEnd,
) )
)) )),
), ),
|(first_ability, mut other_abilities): ( |(first_ability, mut other_abilities): (
Loc<TypeAnnotation<'a>>, Loc<TypeAnnotation<'a>>,
Vec<'a, Loc<TypeAnnotation<'a>>> Vec<'a, Loc<TypeAnnotation<'a>>>,
)| { )| {
other_abilities.insert(0, first_ability); other_abilities.insert(0, first_ability);
other_abilities other_abilities
} },
) )
} }
fn implements_clause<'a>() -> impl Parser<'a, Loc<ImplementsClause<'a>>, EType<'a>> { fn implements_clause<'a>() -> impl Parser<'a, Loc<ImplementsClause<'a>>, EType<'a>> {
map!( map(
// Suppose we are trying to parse "a implements Hash" // Suppose we are trying to parse "a implements Hash"
and( and(
space0_around_ee( space0_around_ee(
// Parse "a", with appropriate spaces // Parse "a", with appropriate spaces
specialize_err( specialize_err(
|_, pos| EType::TBadTypeVariable(pos), |_, pos| EType::TBadTypeVariable(pos),
loc!(map!(lowercase_ident(), Spaced::Item)), loc!(map(lowercase_ident(), Spaced::Item)),
), ),
EType::TIndentStart, EType::TIndentStart,
EType::TIndentEnd EType::TIndentEnd,
), ),
skip_first( skip_first(
// Parse "implements"; we don't care about this keyword // Parse "implements"; we don't care about this keyword
word(crate::keyword::IMPLEMENTS, EType::TImplementsClause), word(crate::keyword::IMPLEMENTS, EType::TImplementsClause),
// Parse "Hash & ..."; this may be qualified from another module like "Hash.Hash" // Parse "Hash & ..."; this may be qualified from another module like "Hash.Hash"
absolute_column_min_indent(ability_chain()) absolute_column_min_indent(ability_chain()),
) ),
), ),
|(var, abilities): (Loc<Spaced<'a, &'a str>>, Vec<'a, Loc<TypeAnnotation<'a>>>)| { |(var, abilities): (Loc<Spaced<'a, &'a str>>, Vec<'a, Loc<TypeAnnotation<'a>>>)| {
let abilities_region = Region::span_across( let abilities_region = Region::span_across(
@ -488,7 +488,7 @@ fn implements_clause<'a>() -> impl Parser<'a, Loc<ImplementsClause<'a>>, EType<'
abilities: abilities.into_bump_slice(), abilities: abilities.into_bump_slice(),
}; };
Loc::at(region, implements_clause) Loc::at(region, implements_clause)
} },
) )
} }
@ -530,7 +530,7 @@ pub fn implements_abilities<'a>() -> impl Parser<'a, Loc<ImplementsAbilities<'a>
word(crate::keyword::IMPLEMENTS, EType::TImplementsClause), word(crate::keyword::IMPLEMENTS, EType::TImplementsClause),
// Parse "Hash"; this may be qualified from another module like "Hash.Hash" // Parse "Hash"; this may be qualified from another module like "Hash.Hash"
space0_before_e( space0_before_e(
loc!(map!( loc!(map(
collection_trailing_sep_e!( collection_trailing_sep_e!(
byte(b'[', EType::TStart), byte(b'[', EType::TStart),
loc!(parse_implements_ability()), loc!(parse_implements_ability()),
@ -549,7 +549,7 @@ fn parse_implements_ability<'a>() -> impl Parser<'a, ImplementsAbility<'a>, ETyp
increment_min_indent(record!(ImplementsAbility::ImplementsAbility { increment_min_indent(record!(ImplementsAbility::ImplementsAbility {
ability: loc!(specialize_err(EType::TApply, concrete_type())), ability: loc!(specialize_err(EType::TApply, concrete_type())),
impls: optional(backtrackable(space0_before_e( impls: optional(backtrackable(space0_before_e(
loc!(map!( loc!(map(
specialize_err( specialize_err(
EType::TAbilityImpl, EType::TAbilityImpl,
collection_trailing_sep_e!( collection_trailing_sep_e!(