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::parser::{
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,
skip_second, specialize_err, specialize_err_ref, then, two_bytes, EClosure, EExpect, EExpr,
EIf, EInParens, EList, ENumber, EPattern, ERecord, EString, EType, EWhen, Either, ParseResult,
Parser,
line_min_indent, map, optional, reset_min_indent, sep_by1, sep_by1_e, set_min_indent,
skip_first, skip_second, specialize_err, specialize_err_ref, then, two_bytes, EClosure,
EExpect, EExpr, EIf, EInParens, EList, ENumber, EPattern, ERecord, EString, EType, EWhen,
Either, ParseResult, Parser,
};
use crate::pattern::{closure_param, loc_implements_parser};
use crate::state::State;
@ -163,8 +163,8 @@ fn record_field_access_chain<'a>() -> impl Parser<'a, Vec<'a, Accessor<'a>>, EEx
specialize_err(
|_, pos| EExpr::Access(pos),
one_of!(
map!(lowercase_ident(), Accessor::RecordField),
map!(integer_ident(), Accessor::TupleIndex),
map(lowercase_ident(), Accessor::RecordField),
map(integer_ident(), Accessor::TupleIndex),
)
)
))
@ -1483,7 +1483,7 @@ mod ability {
/// Parses a single ability demand line; see `parse_demand`.
fn parse_demand_help<'a>() -> impl Parser<'a, AbilityMember<'a>, EAbility<'a>> {
map!(
map(
// Require the type to be more indented than the name
absolute_indented_seq(
specialize_err(|_, pos| EAbility::DemandName(pos), loc!(lowercase_ident())),
@ -1491,17 +1491,15 @@ mod ability {
and(
// TODO: do we get anything from picking up spaces here?
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>>)| {
AbilityMember {
name: name.map_owned(Spaced::Item),
typ,
}
}
|(name, typ): (Loc<&'a str>, Loc<TypeAnnotation<'a>>)| AbilityMember {
name: name.map_owned(Spaced::Item),
typ,
},
)
}
@ -2457,7 +2455,7 @@ mod when {
guard: loc_first_guard,
}));
let branch_parser = map!(
let branch_parser = map(
and(
then(
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)| {
let patterns: Vec<'a, _> = patterns;
@ -2479,7 +2477,7 @@ mod when {
value: expr,
guard,
}
}
},
);
while !state.bytes().is_empty() {
@ -2514,7 +2512,7 @@ mod when {
and(
branch_alternatives_help(pattern_indent_level),
one_of![
map!(
map(
skip_first(
parser::keyword(keyword::IF, EWhen::IfToken),
// 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> {
map!(
map(
crate::number_literal::positive_number_literal(),
|literal| {
use crate::number_literal::NumLiteral::*;
@ -3217,12 +3215,12 @@ fn positive_number_literal_help<'a>() -> impl Parser<'a, Expr<'a>, ENumber> {
is_negative,
},
}
}
},
)
}
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::*;
match literal {

View File

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

View File

@ -2194,7 +2194,7 @@ macro_rules! byte_check_indent {
/// # NotFound(Position),
/// # }
/// # let arena = Bump::new();
/// let parser = map!(
/// let parser = map(
/// word("hello", Problem::NotFound),
/// |_output| "new output!"
/// );
@ -2210,20 +2210,19 @@ macro_rules! byte_check_indent {
/// assert_eq!(progress, Progress::NoProgress);
/// assert_eq!(err, Problem::NotFound(Position::zero()));
/// ```
#[macro_export]
macro_rules! map {
($parser:expr, $transform:expr) => {
move |arena, state, min_indent| {
#[allow(clippy::redundant_closure_call)]
$parser
.parse(arena, state, min_indent)
.map(|(progress, output, next_state)| (progress, $transform(output), next_state))
}
};
pub fn map<'a, Output, MappedOutput, E: 'a>(
parser: impl Parser<'a, Output, E>,
transform: impl Fn(Output) -> MappedOutput,
) -> impl Parser<'a, MappedOutput, E> {
move |arena, state, min_indent| {
parser
.parse(arena, state, min_indent)
.map(|(progress, output, next_state)| (progress, transform(output), next_state))
}
}
/// 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
///
@ -2580,9 +2579,7 @@ where
}
/// Maps/transforms the `Ok` result of parsing using the given function.
/// Similar to [`map!`], but the transform function also takes a bump allocator.
///
/// Function version of the [`map_with_arena!`] macro.
/// Similar to [`map`], but the transform function also takes a bump allocator.
///
/// 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.

View File

@ -4,8 +4,8 @@ use crate::ident::{lowercase_ident, parse_ident, Accessor, Ident};
use crate::keyword;
use crate::parser::Progress::{self, *};
use crate::parser::{
self, backtrackable, byte, fail_when, optional, skip_first, specialize_err, specialize_err_ref,
then, three_bytes, two_bytes, EPattern, PInParens, PList, PRecord, Parser,
self, backtrackable, byte, fail_when, map, optional, skip_first, specialize_err,
specialize_err_ref, then, three_bytes, two_bytes, EPattern, PInParens, PList, PRecord, Parser,
};
use crate::state::State;
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>> {
specialize_err(
EPattern::NumLiteral,
map!(crate::number_literal::number_literal(), |literal| {
map(crate::number_literal::number_literal(), |literal| {
use crate::number_literal::NumLiteral::*;
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>> {
map!(
map(
collection_trailing_sep_e!(
byte(b'[', PList::Open),
list_element_pattern(),
@ -277,7 +277,7 @@ fn list_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, PList<'a>> {
byte(b']', PList::End),
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>> {
map!(
map(
skip_first(
byte(b'_', EPattern::Underscore),
optional(lowercase_ident_pattern())
optional(lowercase_ident_pattern()),
),
|output| match output {
Some(name) => Pattern::Underscore(name),
None => Pattern::Underscore(""),
}
},
)
}
@ -520,7 +520,7 @@ fn lowercase_ident_pattern<'a>() -> impl Parser<'a, &'a str, EPattern<'a>> {
#[inline(always)]
fn record_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, PRecord<'a>> {
map!(
map(
collection_trailing_sep_e!(
byte(b'{', PRecord::Open),
record_pattern_field(),
@ -528,7 +528,7 @@ fn record_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, PRecord<'a>> {
byte(b'}', PRecord::End),
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::keyword;
use crate::parser::{
absolute_column_min_indent, and, increment_min_indent, skip_first, skip_second, then, ERecord,
ETypeAbilityImpl,
absolute_column_min_indent, and, increment_min_indent, map, skip_first, skip_second, then,
ERecord, ETypeAbilityImpl,
};
use crate::parser::{
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
one_of![
map!(
map(
and(
skip_second(
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,
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)
})
}
@ -398,12 +398,12 @@ fn record_type<'a>(
}
fn applied_type<'a>(stop_at_surface_has: bool) -> impl Parser<'a, TypeAnnotation<'a>, EType<'a>> {
map!(
map(
and(
specialize_err(EType::TApply, concrete_type()),
// Optionally parse space-separated arguments for the constructor,
// 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>>>)| {
match &ctor {
@ -418,7 +418,7 @@ fn applied_type<'a>(stop_at_surface_has: bool) -> impl Parser<'a, TypeAnnotation
TypeAnnotation::Malformed(_) => ctor,
_ => unreachable!(),
}
}
},
)
.trace("type_annotation:applied_type")
}
@ -431,7 +431,7 @@ fn loc_applied_args_e<'a>(
// Hash & Eq & ...
fn ability_chain<'a>() -> impl Parser<'a, Vec<'a, Loc<TypeAnnotation<'a>>>, EType<'a>> {
map!(
map(
and(
space0_before_optional_after(
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::TIndentEnd,
)
))
)),
),
|(first_ability, mut other_abilities): (
Loc<TypeAnnotation<'a>>,
Vec<'a, Loc<TypeAnnotation<'a>>>
Vec<'a, Loc<TypeAnnotation<'a>>>,
)| {
other_abilities.insert(0, first_ability);
other_abilities
}
},
)
}
fn implements_clause<'a>() -> impl Parser<'a, Loc<ImplementsClause<'a>>, EType<'a>> {
map!(
map(
// Suppose we are trying to parse "a implements Hash"
and(
space0_around_ee(
// Parse "a", with appropriate spaces
specialize_err(
|_, pos| EType::TBadTypeVariable(pos),
loc!(map!(lowercase_ident(), Spaced::Item)),
loc!(map(lowercase_ident(), Spaced::Item)),
),
EType::TIndentStart,
EType::TIndentEnd
EType::TIndentEnd,
),
skip_first(
// Parse "implements"; we don't care about this keyword
word(crate::keyword::IMPLEMENTS, EType::TImplementsClause),
// 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>>>)| {
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(),
};
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),
// Parse "Hash"; this may be qualified from another module like "Hash.Hash"
space0_before_e(
loc!(map!(
loc!(map(
collection_trailing_sep_e!(
byte(b'[', EType::TStart),
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 {
ability: loc!(specialize_err(EType::TApply, concrete_type())),
impls: optional(backtrackable(space0_before_e(
loc!(map!(
loc!(map(
specialize_err(
EType::TAbilityImpl,
collection_trailing_sep_e!(