From e8ae2e12f82ef6249aab6b99bb9a3e812fc79090 Mon Sep 17 00:00:00 2001 From: Jackson Wambolt Date: Sun, 14 Apr 2024 20:52:29 -0500 Subject: [PATCH 01/18] Un-macro skip_second --- crates/compiler/parse/src/expr.rs | 18 +++++----- crates/compiler/parse/src/header.rs | 4 +-- crates/compiler/parse/src/module.rs | 23 +++++++------ crates/compiler/parse/src/parser.rs | 35 +++++++++++--------- crates/compiler/parse/src/string_literal.rs | 16 ++++----- crates/compiler/parse/src/type_annotation.rs | 6 ++-- 6 files changed, 55 insertions(+), 47 deletions(-) diff --git a/crates/compiler/parse/src/expr.rs b/crates/compiler/parse/src/expr.rs index c98168247d..979a44a45d 100644 --- a/crates/compiler/parse/src/expr.rs +++ b/crates/compiler/parse/src/expr.rs @@ -11,9 +11,9 @@ use crate::ident::{integer_ident, lowercase_ident, parse_ident, Accessor, Ident} use crate::keyword; use crate::parser::{ self, backtrackable, byte, byte_indent, increment_min_indent, line_min_indent, optional, - reset_min_indent, sep_by1, sep_by1_e, set_min_indent, specialize_err, specialize_err_ref, then, - two_bytes, EClosure, EExpect, EExpr, EIf, EInParens, EList, ENumber, EPattern, ERecord, - EString, EType, EWhen, Either, ParseResult, Parser, + reset_min_indent, sep_by1, sep_by1_e, set_min_indent, 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; @@ -43,9 +43,9 @@ pub fn test_parse_expr<'a>( arena: &'a bumpalo::Bump, state: State<'a>, ) -> Result>, EExpr<'a>> { - let parser = skip_second!( + let parser = skip_second( space0_before_optional_after(loc_expr(true), EExpr::IndentStart, EExpr::IndentEnd), - expr_end() + expr_end(), ); match parser.parse(arena, state, min_indent) { @@ -2629,9 +2629,9 @@ mod when { } fn if_branch<'a>() -> impl Parser<'a, (Loc>, Loc>), EIf<'a>> { - skip_second!( + skip_second( and!( - skip_second!( + skip_second( space0_around_ee( specialize_err_ref(EIf::Condition, loc_expr(true)), EIf::IndentCondition, @@ -2645,7 +2645,7 @@ fn if_branch<'a>() -> impl Parser<'a, (Loc>, Loc>), EIf<'a>> { EIf::IndentElseToken, ) ), - parser::keyword(keyword::ELSE, EIf::Else) + parser::keyword(keyword::ELSE, EIf::Else), ) } @@ -3073,7 +3073,7 @@ fn record_help<'a>() -> impl Parser<'a, RecordHelp<'a>, ERecord<'a>> { reset_min_indent(record!(RecordHelp { // You can optionally have an identifier followed by an '&' to // make this a record update, e.g. { Foo.user & username: "blah" }. - update: optional(backtrackable(skip_second!( + update: optional(backtrackable(skip_second( spaces_around( // We wrap the ident in an Expr here, // so that we have a Spaceable value to work with, diff --git a/crates/compiler/parse/src/header.rs b/crates/compiler/parse/src/header.rs index 318dbe0129..b03266973b 100644 --- a/crates/compiler/parse/src/header.rs +++ b/crates/compiler/parse/src/header.rs @@ -4,7 +4,7 @@ use crate::ast::{ use crate::blankspace::space0_e; use crate::expr::merge_spaces; use crate::ident::{lowercase_ident, UppercaseIdent}; -use crate::parser::{byte, specialize_err, EPackageEntry, EPackageName, Parser}; +use crate::parser::{byte, skip_second, specialize_err, EPackageEntry, EPackageName, Parser}; use crate::parser::{optional, then}; use crate::string_literal; use roc_module::symbol::{ModuleId, Symbol}; @@ -344,7 +344,7 @@ pub fn package_entry<'a>() -> impl Parser<'a, Spaced<'a, PackageEntry<'a>>, EPac // (Indirect dependencies don't have a shorthand.) and!( optional(and!( - skip_second!( + skip_second( and!( specialize_err(|_, pos| EPackageEntry::Shorthand(pos), lowercase_ident()), space0_e(EPackageEntry::IndentPackage) diff --git a/crates/compiler/parse/src/module.rs b/crates/compiler/parse/src/module.rs index 2dbc5160ed..c0df3c3186 100644 --- a/crates/compiler/parse/src/module.rs +++ b/crates/compiler/parse/src/module.rs @@ -9,9 +9,9 @@ use crate::header::{ use crate::ident::{self, lowercase_ident, unqualified_ident, uppercase, UppercaseIdent}; use crate::parser::Progress::{self, *}; use crate::parser::{ - backtrackable, byte, increment_min_indent, optional, reset_min_indent, specialize_err, - two_bytes, EExposes, EGenerates, EGeneratesWith, EHeader, EImports, EPackages, EProvides, - ERequires, ETypedIdent, Parser, SourceError, SpaceProblem, SyntaxError, + backtrackable, byte, increment_min_indent, optional, reset_min_indent, skip_second, + specialize_err, two_bytes, EExposes, EGenerates, EGeneratesWith, EHeader, EImports, EPackages, + EProvides, ERequires, ETypedIdent, Parser, SourceError, SpaceProblem, SyntaxError, }; use crate::state::State; use crate::string_literal::{self, parse_str_literal}; @@ -30,9 +30,9 @@ fn end_of_file<'a>() -> impl Parser<'a, (), SyntaxError<'a>> { #[inline(always)] pub fn module_defs<'a>() -> impl Parser<'a, Defs<'a>, SyntaxError<'a>> { - skip_second!( - specialize_err(SyntaxError::Expr, crate::expr::toplevel_defs(),), - end_of_file() + skip_second( + specialize_err(SyntaxError::Expr, crate::expr::toplevel_defs()), + end_of_file(), ) } @@ -345,7 +345,7 @@ fn requires<'a>( #[inline(always)] fn platform_requires<'a>() -> impl Parser<'a, PlatformRequires<'a>, ERequires<'a>> { record!(PlatformRequires { - rigids: skip_second!(requires_rigids(), space0_e(ERequires::ListStart)), + rigids: skip_second(requires_rigids(), space0_e(ERequires::ListStart)), signature: requires_typed_ident() }) } @@ -369,7 +369,7 @@ fn requires_rigids<'a>( fn requires_typed_ident<'a>() -> impl Parser<'a, Loc>>, ERequires<'a>> { skip_first!( byte(b'{', ERequires::ListStart), - skip_second!( + skip_second( reset_min_indent(space0_around_ee( specialize_err(ERequires::TypedIdent, loc!(typed_ident()),), ERequires::ListStart, @@ -414,10 +414,13 @@ where { map!( and!( - skip_second!( + skip_second( + // parse any leading space before the keyword backtrackable(space0_e(indent_problem1)), + // parse the keyword crate::parser::keyword(K::KEYWORD, expectation) ), + // parse the trailing space space0_e(indent_problem2) ), |(before, after)| { @@ -611,7 +614,7 @@ fn imports_entry<'a>() -> impl Parser<'a, Spaced<'a, ImportsEntry<'a>>, EImports and!( and!( // e.g. `pf.` - optional(backtrackable(skip_second!( + optional(backtrackable(skip_second( shortname(), byte(b'.', EImports::ShorthandDot) ))), diff --git a/crates/compiler/parse/src/parser.rs b/crates/compiler/parse/src/parser.rs index cdc67c19ff..52c67b32f3 100644 --- a/crates/compiler/parse/src/parser.rs +++ b/crates/compiler/parse/src/parser.rs @@ -1427,7 +1427,7 @@ macro_rules! skip_first { /// # use bumpalo::Bump; /// # let arena = Bump::new(); /// # fn foo<'a>(arena: &'a Bump) { -/// let parser = skip_second!( +/// let parser = skip_second( /// lowercase_ident(), /// word(", world", |_| ()) /// ); @@ -1439,19 +1439,21 @@ macro_rules! skip_first { /// # } /// # foo(&arena); /// ``` -#[macro_export] -macro_rules! skip_second { - ($p1:expr, $p2:expr) => { - move |arena, state: $crate::state::State<'a>, min_indent: u32| match $p1 - .parse(arena, state, min_indent) - { - Ok((p1, out1, state)) => match $p2.parse(arena, state, min_indent) { - Ok((p2, _, state)) => Ok((p1.or(p2), out1, state)), - Err((p2, fail)) => Err((p1.or(p2), fail)), - }, - Err((progress, fail)) => Err((progress, fail)), - } - }; +pub fn skip_second<'a, P1, First, P2, Second, E>(p1: P1, p2: P2) -> impl Parser<'a, First, E> +where + E: 'a, + P1: Parser<'a, First, E>, + P2: Parser<'a, Second, E>, +{ + move |arena, state: crate::state::State<'a>, min_indent: u32| match p1 + .parse(arena, state, min_indent) + { + Ok((p1, out1, state)) => match p2.parse(arena, state, min_indent) { + Ok((p2, _, state)) => Ok((p1.or(p2), out1, state)), + Err((p2, fail)) => Err((p1.or(p2), fail)), + }, + Err((progress, fail)) => Err((progress, fail)), + } } #[macro_export] @@ -2535,7 +2537,10 @@ macro_rules! either { #[macro_export] macro_rules! between { ($opening_brace:expr, $parser:expr, $closing_brace:expr) => { - skip_first!($opening_brace, skip_second!($parser, $closing_brace)) + skip_first!( + $opening_brace, + $crate::parser::skip_second($parser, $closing_brace) + ) }; } diff --git a/crates/compiler/parse/src/string_literal.rs b/crates/compiler/parse/src/string_literal.rs index 3309c0ec25..f3eb4b3dad 100644 --- a/crates/compiler/parse/src/string_literal.rs +++ b/crates/compiler/parse/src/string_literal.rs @@ -2,8 +2,8 @@ use crate::ast::{EscapedChar, SingleQuoteLiteral, StrLiteral, StrSegment}; use crate::expr; use crate::parser::Progress::{self, *}; use crate::parser::{ - allocated, byte, loc, reset_min_indent, specialize_err_ref, then, BadInputError, ESingleQuote, - EString, Parser, + allocated, byte, loc, reset_min_indent, skip_second, specialize_err_ref, then, BadInputError, + ESingleQuote, EString, Parser, }; use crate::state::State; use bumpalo::collections::vec::Vec; @@ -374,12 +374,12 @@ pub fn parse_str_like_literal<'a>() -> impl Parser<'a, StrLikeLiteral<'a>, EStri // Parse an arbitrary expression, then give a // canonicalization error if that expression variant // is not allowed inside a string interpolation. - let (_progress, loc_expr, new_state) = skip_second!( + let (_progress, loc_expr, new_state) = skip_second( specialize_err_ref( EString::Format, - loc(allocated(reset_min_indent(expr::expr_help()))) + loc(allocated(reset_min_indent(expr::expr_help()))), ), - byte(b')', EString::FormatEnd) + byte(b')', EString::FormatEnd), ) .parse(arena, state, min_indent)?; @@ -483,12 +483,12 @@ pub fn parse_str_like_literal<'a>() -> impl Parser<'a, StrLikeLiteral<'a>, EStri let original_byte_count = state.bytes().len(); // Parse an arbitrary expression, followed by ')' - let (_progress, loc_expr, new_state) = skip_second!( + let (_progress, loc_expr, new_state) = skip_second( specialize_err_ref( EString::Format, - loc(allocated(reset_min_indent(expr::expr_help()))) + loc(allocated(reset_min_indent(expr::expr_help()))), ), - byte(b')', EString::FormatEnd) + byte(b')', EString::FormatEnd), ) .parse(arena, state, min_indent)?; diff --git a/crates/compiler/parse/src/type_annotation.rs b/crates/compiler/parse/src/type_annotation.rs index 806bdd7ff8..2025b5e704 100644 --- a/crates/compiler/parse/src/type_annotation.rs +++ b/crates/compiler/parse/src/type_annotation.rs @@ -9,7 +9,7 @@ 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, increment_min_indent, then, ERecord, ETypeAbilityImpl, + absolute_column_min_indent, increment_min_indent, skip_second, then, ERecord, ETypeAbilityImpl, }; use crate::parser::{ allocated, backtrackable, byte, fail, optional, specialize_err, specialize_err_ref, two_bytes, @@ -137,7 +137,7 @@ fn term<'a>(stop_at_surface_has: bool) -> impl Parser<'a, Loc one_of![ map!( and!( - skip_second!( + skip_second( backtrackable(space0_e(EType::TIndentEnd)), crate::parser::keyword(keyword::AS, EType::TEnd) ), @@ -596,7 +596,7 @@ fn expression<'a>( ] )) .trace("type_annotation:expression:rest_args"), - skip_second!( + skip_second( space0_e(EType::TIndentStart), two_bytes(b'-', b'>', EType::TStart) ) From 8a144149e222dfd88775700b255d8e7cca4dbc47 Mon Sep 17 00:00:00 2001 From: Jackson Wambolt Date: Sun, 14 Apr 2024 21:25:04 -0500 Subject: [PATCH 02/18] Un-macro skip_first --- crates/compiler/parse/src/expr.rs | 18 +++++------ crates/compiler/parse/src/module.rs | 30 ++++++++--------- crates/compiler/parse/src/parser.rs | 34 +++++++++++--------- crates/compiler/parse/src/pattern.rs | 6 ++-- crates/compiler/parse/src/type_annotation.rs | 19 +++++------ 5 files changed, 55 insertions(+), 52 deletions(-) diff --git a/crates/compiler/parse/src/expr.rs b/crates/compiler/parse/src/expr.rs index 979a44a45d..232cb42ed4 100644 --- a/crates/compiler/parse/src/expr.rs +++ b/crates/compiler/parse/src/expr.rs @@ -11,7 +11,7 @@ use crate::ident::{integer_ident, lowercase_ident, parse_ident, Accessor, Ident} use crate::keyword; use crate::parser::{ self, backtrackable, byte, byte_indent, increment_min_indent, line_min_indent, optional, - reset_min_indent, sep_by1, sep_by1_e, set_min_indent, skip_second, specialize_err, + 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, }; @@ -157,7 +157,7 @@ fn loc_expr_in_parens_etc_help<'a>() -> impl Parser<'a, Loc>, EExpr<'a> } fn record_field_access_chain<'a>() -> impl Parser<'a, Vec<'a, Accessor<'a>>, EExpr<'a>> { - zero_or_more!(skip_first!( + zero_or_more!(skip_first( byte(b'.', EExpr::Access), specialize_err( |_, pos| EExpr::Access(pos), @@ -1486,7 +1486,7 @@ mod ability { // Require the type to be more indented than the name absolute_indented_seq!( specialize_err(|_, pos| EAbility::DemandName(pos), loc!(lowercase_ident())), - skip_first!( + skip_first( and!( // TODO: do we get anything from picking up spaces here? space0_e(EAbility::DemandName), @@ -1903,9 +1903,9 @@ fn parse_expr_end<'a>( min_indent }; - let parser = skip_first!( + let parser = skip_first( crate::blankspace::check_indent(EExpr::IndentEnd), - loc_term_or_underscore(options) + loc_term_or_underscore(options), ); match parser.parse(arena, state.clone(), inner_min_indent) { @@ -2379,7 +2379,7 @@ fn closure_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EClo ), EClosure::Arg, ), - skip_first!( + skip_first( // Parse the -> which separates params from body two_bytes(b'-', b'>', EClosure::Arrow), // Parse the body @@ -2514,7 +2514,7 @@ mod when { branch_alternatives_help(pattern_indent_level), one_of![ map!( - skip_first!( + skip_first( parser::keyword(keyword::IF, EWhen::IfToken), // TODO we should require space before the expression but not after space0_around_ee( @@ -2616,12 +2616,12 @@ mod when { /// Parsing the righthandside of a branch in a when conditional. fn branch_result<'a>(indent: u32) -> impl Parser<'a, Loc>, EWhen<'a>> { move |arena, state, _min_indent| { - skip_first!( + skip_first( two_bytes(b'-', b'>', EWhen::Arrow), space0_before_e( specialize_err_ref(EWhen::Branch, loc_expr(true)), EWhen::IndentBranch, - ) + ), ) .parse(arena, state, indent) } diff --git a/crates/compiler/parse/src/module.rs b/crates/compiler/parse/src/module.rs index c0df3c3186..f8718ac3d1 100644 --- a/crates/compiler/parse/src/module.rs +++ b/crates/compiler/parse/src/module.rs @@ -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::{ - backtrackable, byte, increment_min_indent, optional, reset_min_indent, skip_second, + backtrackable, byte, increment_min_indent, 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>> { comments: space0_e(EHeader::IndentStart), header: one_of![ map!( - skip_first!( + skip_first( keyword("interface", EHeader::Start), increment_min_indent(interface_header()) ), Header::Interface ), map!( - skip_first!( + skip_first( keyword("app", EHeader::Start), increment_min_indent(app_header()) ), Header::App ), map!( - skip_first!( + skip_first( keyword("package", EHeader::Start), increment_min_indent(package_header()) ), Header::Package ), map!( - skip_first!( + skip_first( keyword("platform", EHeader::Start), increment_min_indent(platform_header()) ), Header::Platform ), map!( - skip_first!( + skip_first( keyword("hosted", EHeader::Start), increment_min_indent(hosted_header()) ), @@ -278,7 +278,7 @@ fn provides_exposed<'a>() -> impl Parser< #[inline(always)] fn provides_types<'a>( ) -> impl Parser<'a, Collection<'a, Loc>>>, EProvides<'a>> { - skip_first!( + skip_first( // We only support spaces here, not newlines, because this is not intended // to be the design forever. Someday it will hopefully work like Elm, // where platform authors can provide functions like Browser.sandbox which @@ -296,7 +296,7 @@ fn provides_types<'a>( byte(b',', EProvides::ListEnd), byte(b'}', EProvides::ListEnd), Spaced::SpaceBefore - ) + ), ) } @@ -367,16 +367,16 @@ fn requires_rigids<'a>( #[inline(always)] fn requires_typed_ident<'a>() -> impl Parser<'a, Loc>>, ERequires<'a>> { - skip_first!( + skip_first( byte(b'{', ERequires::ListStart), skip_second( reset_min_indent(space0_around_ee( - specialize_err(ERequires::TypedIdent, loc!(typed_ident()),), + specialize_err(ERequires::TypedIdent, loc!(typed_ident())), ERequires::ListStart, - ERequires::ListEnd + ERequires::ListEnd, )), - byte(b'}', ERequires::ListStart) - ) + byte(b'}', ERequires::ListStart), + ), ) } @@ -568,7 +568,7 @@ fn typed_ident<'a>() -> impl Parser<'a, Spaced<'a, TypedIdent<'a>>, ETypedIdent< )), space0_e(ETypedIdent::IndentHasType) ), - skip_first!( + skip_first( byte(b':', ETypedIdent::HasType), space0_before_e( specialize_err( @@ -622,7 +622,7 @@ fn imports_entry<'a>() -> impl Parser<'a, Spaced<'a, ImportsEntry<'a>>, EImports module_name_help(EImports::ModuleName) ), // e.g. `.{ Task, after}` - optional(skip_first!( + optional(skip_first( byte(b'.', EImports::ExposingDot), collection_trailing_sep_e!( byte(b'{', EImports::SetStart), diff --git a/crates/compiler/parse/src/parser.rs b/crates/compiler/parse/src/parser.rs index 52c67b32f3..4a44dae260 100644 --- a/crates/compiler/parse/src/parser.rs +++ b/crates/compiler/parse/src/parser.rs @@ -1387,7 +1387,7 @@ macro_rules! loc { /// # use bumpalo::Bump; /// # let arena = Bump::new(); /// # fn foo<'a>(arena: &'a Bump) { -/// let parser = skip_first!( +/// let parser = skip_first( /// word("hello, ", |_| ()), /// lowercase_ident() /// ); @@ -1399,19 +1399,21 @@ macro_rules! loc { /// # } /// # foo(&arena); /// ``` -#[macro_export] -macro_rules! skip_first { - ($p1:expr, $p2:expr) => { - move |arena, state: $crate::state::State<'a>, min_indent: u32| match $p1 - .parse(arena, state, min_indent) - { - Ok((p1, _, state)) => match $p2.parse(arena, state, min_indent) { - Ok((p2, out2, state)) => Ok((p1.or(p2), out2, state)), - Err((p2, fail)) => Err((p1.or(p2), fail)), - }, - Err((progress, fail)) => Err((progress, fail)), - } - }; +pub fn skip_first<'a, P1, First, P2, Second, E>(p1: P1, p2: P2) -> impl Parser<'a, Second, E> +where + P1: Parser<'a, First, E>, + P2: Parser<'a, Second, E>, + E: 'a, +{ + move |arena, state: crate::state::State<'a>, min_indent: u32| match p1 + .parse(arena, state, min_indent) + { + Ok((p1, _, state)) => match p2.parse(arena, state, min_indent) { + Ok((p2, out2, state)) => Ok((p1.or(p2), out2, state)), + Err((p2, fail)) => Err((p1.or(p2), fail)), + }, + Err((progress, fail)) => Err((progress, fail)), + } } /// If the first one parses, parse the second one; if it also parses, use the @@ -2537,9 +2539,9 @@ macro_rules! either { #[macro_export] macro_rules! between { ($opening_brace:expr, $parser:expr, $closing_brace:expr) => { - skip_first!( + $crate::parser::skip_first( $opening_brace, - $crate::parser::skip_second($parser, $closing_brace) + $crate::parser::skip_second($parser, $closing_brace), ) }; } diff --git a/crates/compiler/parse/src/pattern.rs b/crates/compiler/parse/src/pattern.rs index 65319495c5..bb30abe852 100644 --- a/crates/compiler/parse/src/pattern.rs +++ b/crates/compiler/parse/src/pattern.rs @@ -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, specialize_err, specialize_err_ref, then, - three_bytes, two_bytes, EPattern, PInParens, PList, PRecord, Parser, + self, backtrackable, byte, fail_when, 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; @@ -503,7 +503,7 @@ fn loc_ident_pattern_help<'a>( fn underscore_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, EPattern<'a>> { map!( - skip_first!( + skip_first( byte(b'_', EPattern::Underscore), optional(lowercase_ident_pattern()) ), diff --git a/crates/compiler/parse/src/type_annotation.rs b/crates/compiler/parse/src/type_annotation.rs index 2025b5e704..f6947fb54d 100644 --- a/crates/compiler/parse/src/type_annotation.rs +++ b/crates/compiler/parse/src/type_annotation.rs @@ -9,7 +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, increment_min_indent, skip_second, then, ERecord, ETypeAbilityImpl, + absolute_column_min_indent, increment_min_indent, skip_first, skip_second, then, ERecord, + ETypeAbilityImpl, }; use crate::parser::{ allocated, backtrackable, byte, fail, optional, specialize_err, specialize_err_ref, two_bytes, @@ -437,7 +438,7 @@ fn ability_chain<'a>() -> impl Parser<'a, Vec<'a, Loc>>, ETyp EType::TIndentStart, EType::TIndentEnd, ), - zero_or_more!(skip_first!( + zero_or_more!(skip_first( byte(b'&', EType::TImplementsClause), space0_before_optional_after( specialize_err(EType::TApply, loc!(concrete_type())), @@ -469,7 +470,7 @@ fn implements_clause<'a>() -> impl Parser<'a, Loc>, EType<' EType::TIndentStart, EType::TIndentEnd ), - skip_first!( + 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" @@ -505,7 +506,7 @@ fn implements_clause_chain<'a>( // Parse the first clause (there must be one), then the rest let (_, first_clause, state) = implements_clause().parse(arena, state, min_indent)?; - let (_, mut clauses, state) = zero_or_more!(skip_first!( + let (_, mut clauses, state) = zero_or_more!(skip_first( byte(b',', EType::TImplementsClause), implements_clause() )) @@ -524,7 +525,7 @@ fn implements_clause_chain<'a>( /// Parse a implements-abilities clause, e.g. `implements [Eq, Hash]`. pub fn implements_abilities<'a>() -> impl Parser<'a, Loc>, EType<'a>> { - increment_min_indent(skip_first!( + increment_min_indent(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" @@ -540,7 +541,7 @@ pub fn implements_abilities<'a>() -> impl Parser<'a, Loc ImplementsAbilities::Implements )), EType::TIndentEnd, - ) + ), )) } @@ -584,7 +585,7 @@ fn expression<'a>( .parse(arena, state, min_indent)?; let result = and![ - zero_or_more!(skip_first!( + zero_or_more!(skip_first( byte(b',', EType::TFunctionArgument), one_of![ space0_around_ee( @@ -635,9 +636,9 @@ fn expression<'a>( } Err(err) => { if !is_trailing_comma_valid { - let (_, comma, _) = optional(backtrackable(skip_first!( + let (_, comma, _) = optional(backtrackable(skip_first( space0_e(EType::TIndentStart), - byte(b',', EType::TStart) + byte(b',', EType::TStart), ))) .trace("check trailing comma") .parse(arena, state.clone(), min_indent)?; From 60fa7ebe9ef5bbeaeca37ba34a22581497dcc807 Mon Sep 17 00:00:00 2001 From: Jackson Wambolt Date: Sun, 14 Apr 2024 21:34:32 -0500 Subject: [PATCH 03/18] Un-macro between --- crates/compiler/parse/src/expr.rs | 12 ++++++------ crates/compiler/parse/src/parser.rs | 20 +++++++++----------- crates/compiler/parse/src/string_literal.rs | 8 ++++---- 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/crates/compiler/parse/src/expr.rs b/crates/compiler/parse/src/expr.rs index 232cb42ed4..900605d367 100644 --- a/crates/compiler/parse/src/expr.rs +++ b/crates/compiler/parse/src/expr.rs @@ -10,10 +10,10 @@ use crate::blankspace::{ use crate::ident::{integer_ident, lowercase_ident, parse_ident, Accessor, Ident}; use crate::keyword; use crate::parser::{ - self, backtrackable, byte, byte_indent, increment_min_indent, 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, + self, backtrackable, between, byte, byte_indent, increment_min_indent, 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, }; use crate::pattern::{closure_param, loc_implements_parser}; use crate::state::State; @@ -3068,7 +3068,7 @@ struct RecordHelp<'a> { } fn record_help<'a>() -> impl Parser<'a, RecordHelp<'a>, ERecord<'a>> { - between!( + between( byte(b'{', ERecord::Open), reset_min_indent(record!(RecordHelp { // You can optionally have an identifier followed by an '&' to @@ -3089,7 +3089,7 @@ fn record_help<'a>() -> impl Parser<'a, RecordHelp<'a>, ERecord<'a>> { RecordField::SpaceBefore ), })), - byte(b'}', ERecord::End) + byte(b'}', ERecord::End), ) } diff --git a/crates/compiler/parse/src/parser.rs b/crates/compiler/parse/src/parser.rs index 4a44dae260..39a561acd8 100644 --- a/crates/compiler/parse/src/parser.rs +++ b/crates/compiler/parse/src/parser.rs @@ -1502,14 +1502,14 @@ macro_rules! collection_inner { #[macro_export] macro_rules! collection_trailing_sep_e { ($opening_brace:expr, $elem:expr, $delimiter:expr, $closing_brace:expr, $space_before:expr) => { - between!( + $crate::parser::between( $opening_brace, $crate::parser::reset_min_indent($crate::collection_inner!( $elem, $delimiter, $space_before )), - $closing_brace + $closing_brace, ) }; } @@ -2524,7 +2524,7 @@ macro_rules! either { /// # } /// # let arena = Bump::new(); /// # fn foo<'a>(arena: &'a Bump) { -/// let parser = between!( +/// let parser = between( /// byte(b'(', Problem::NotFound), /// word("hello", Problem::NotFound), /// byte(b')', Problem::NotFound) @@ -2536,14 +2536,12 @@ macro_rules! either { /// # } /// # foo(&arena); /// ``` -#[macro_export] -macro_rules! between { - ($opening_brace:expr, $parser:expr, $closing_brace:expr) => { - $crate::parser::skip_first( - $opening_brace, - $crate::parser::skip_second($parser, $closing_brace), - ) - }; +pub fn between<'a, Before, Inner, After, Err: 'a>( + opening_brace: impl Parser<'a, Before, Err>, + inner: impl Parser<'a, Inner, Err>, + closing_brace: impl Parser<'a, After, Err>, +) -> impl Parser<'a, Inner, Err> { + skip_first(opening_brace, skip_second(inner, closing_brace)) } /// Runs two parsers in succession. If both parsers succeed, the output is a tuple of both outputs. diff --git a/crates/compiler/parse/src/string_literal.rs b/crates/compiler/parse/src/string_literal.rs index f3eb4b3dad..a55b7078aa 100644 --- a/crates/compiler/parse/src/string_literal.rs +++ b/crates/compiler/parse/src/string_literal.rs @@ -2,8 +2,8 @@ use crate::ast::{EscapedChar, SingleQuoteLiteral, StrLiteral, StrSegment}; use crate::expr; use crate::parser::Progress::{self, *}; use crate::parser::{ - allocated, byte, loc, reset_min_indent, skip_second, specialize_err_ref, then, BadInputError, - ESingleQuote, EString, Parser, + allocated, between, byte, loc, reset_min_indent, skip_second, specialize_err_ref, then, + BadInputError, ESingleQuote, EString, Parser, }; use crate::state::State; use bumpalo::collections::vec::Vec; @@ -403,10 +403,10 @@ pub fn parse_str_like_literal<'a>() -> impl Parser<'a, StrLikeLiteral<'a>, EStri // Parse the hex digits, surrounded by parens, then // give a canonicalization error if the digits form // an invalid unicode code point. - let (_progress, loc_digits, new_state) = between!( + let (_progress, loc_digits, new_state) = between( byte(b'(', EString::CodePtOpen), loc(ascii_hex_digits()), - byte(b')', EString::CodePtEnd) + byte(b')', EString::CodePtEnd), ) .parse(arena, state, min_indent)?; From 1b4b0a0aa12f97edc826969b6c8e0d77711edac4 Mon Sep 17 00:00:00 2001 From: Jackson Wambolt Date: Sun, 14 Apr 2024 23:59:40 -0500 Subject: [PATCH 04/18] Un-macro indented_seq --- crates/compiler/parse/src/expr.rs | 15 +++++----- crates/compiler/parse/src/parser.rs | 45 +++++++++++++++-------------- 2 files changed, 31 insertions(+), 29 deletions(-) diff --git a/crates/compiler/parse/src/expr.rs b/crates/compiler/parse/src/expr.rs index 900605d367..d71fe84479 100644 --- a/crates/compiler/parse/src/expr.rs +++ b/crates/compiler/parse/src/expr.rs @@ -10,10 +10,11 @@ use crate::blankspace::{ use crate::ident::{integer_ident, lowercase_ident, parse_ident, Accessor, Ident}; use crate::keyword; use crate::parser::{ - self, backtrackable, between, byte, byte_indent, increment_min_indent, 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, + self, 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, }; use crate::pattern::{closure_param, loc_implements_parser}; use crate::state::State; @@ -2362,7 +2363,7 @@ fn closure_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EClo // closure_help_help(options) map_with_arena!( // After the first token, all other tokens must be indented past the start of the line - indented_seq!( + indented_seq( // All closures start with a '\' - e.g. (\x -> x + 1) byte_indent(b'\\', EClosure::Start), // Once we see the '\', we're committed to parsing this as a closure. @@ -2406,7 +2407,7 @@ mod when { pub fn expr_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EWhen<'a>> { map_with_arena!( and!( - indented_seq!( + indented_seq( parser::keyword(keyword::WHEN, EWhen::When), space0_around_e_no_after_indent_check( specialize_err_ref(EWhen::Condition, expr_start(options)), @@ -2417,7 +2418,7 @@ mod when { // ambiguity. The formatter will fix it up. // // We require that branches are indented relative to the line containing the `is`. - indented_seq!( + indented_seq( parser::keyword(keyword::IS, EWhen::Is), branches(options) ) diff --git a/crates/compiler/parse/src/parser.rs b/crates/compiler/parse/src/parser.rs index 39a561acd8..4e98f8f4a4 100644 --- a/crates/compiler/parse/src/parser.rs +++ b/crates/compiler/parse/src/parser.rs @@ -1686,32 +1686,33 @@ macro_rules! record { }; } -/// Similar to [`and!`], but we modify the `min_indent` of the second parser to be -/// 1 greater than the `line_indent()` at the start of the first parser. -#[macro_export] -macro_rules! indented_seq { - ($p1:expr, $p2:expr) => { - move |arena: &'a bumpalo::Bump, state: $crate::state::State<'a>, _min_indent: u32| { - let start_indent = state.line_indent(); +/// Similar to [`and`], but we modify the `min_indent` of the second parser +/// (`parser`) to be 1 greater than the `line_indent()` at the start of the +/// first parser (`before`). +pub fn indented_seq<'a, O, E: 'a>( + before: impl Parser<'a, (), E>, + parser: impl Parser<'a, O, E>, +) -> impl Parser<'a, O, E> { + move |arena: &'a bumpalo::Bump, state: crate::state::State<'a>, _min_indent: u32| { + let start_indent = state.line_indent(); - // TODO: we should account for min_indent here, but this doesn't currently work - // because min_indent is sometimes larger than it really should be, which is in turn - // due to uses of `increment_indent`. - // - // let p1_indent = std::cmp::max(start_indent, min_indent); + // TODO: we should account for min_indent here, but this doesn't currently work + // because min_indent is sometimes larger than it really should be, which is in turn + // due to uses of `increment_indent`. + // + // let p1_indent = std::cmp::max(start_indent, min_indent); - let p1_indent = start_indent; - let p2_indent = p1_indent + 1; + let p1_indent = start_indent; + let p2_indent = p1_indent + 1; - match $p1.parse(arena, state, p1_indent) { - Ok((p1, (), state)) => match $p2.parse(arena, state, p2_indent) { - Ok((p2, out2, state)) => Ok((p1.or(p2), out2, state)), - Err((p2, fail)) => Err((p1.or(p2), fail)), - }, - Err((progress, fail)) => Err((progress, fail)), - } + match before.parse(arena, state, p1_indent) { + Ok((p1, (), state)) => match parser.parse(arena, state, p2_indent) { + Ok((p2, out2, state)) => Ok((p1.or(p2), out2, state)), + Err((p2, fail)) => Err((p1.or(p2), fail)), + }, + Err((progress, fail)) => Err((progress, fail)), } - }; + } } /// Similar to [`and!`], but we modify the `min_indent` of the second parser to be From 64290a8cf65f444134399664a735cea730194488 Mon Sep 17 00:00:00 2001 From: Jackson Wambolt Date: Mon, 15 Apr 2024 00:07:20 -0500 Subject: [PATCH 05/18] Un-macro absolute_indented_seq --- crates/compiler/parse/src/expr.rs | 4 ++-- crates/compiler/parse/src/parser.rs | 30 ++++++++++++++--------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/crates/compiler/parse/src/expr.rs b/crates/compiler/parse/src/expr.rs index d71fe84479..44fbf3af5a 100644 --- a/crates/compiler/parse/src/expr.rs +++ b/crates/compiler/parse/src/expr.rs @@ -1478,14 +1478,14 @@ mod ability { use super::*; use crate::{ ast::{AbilityMember, Spaceable, Spaced}, - parser::EAbility, + parser::{absolute_indented_seq, EAbility}, }; /// Parses a single ability demand line; see `parse_demand`. fn parse_demand_help<'a>() -> impl Parser<'a, AbilityMember<'a>, EAbility<'a>> { map!( // 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())), skip_first( and!( diff --git a/crates/compiler/parse/src/parser.rs b/crates/compiler/parse/src/parser.rs index 4e98f8f4a4..214503307d 100644 --- a/crates/compiler/parse/src/parser.rs +++ b/crates/compiler/parse/src/parser.rs @@ -1717,24 +1717,24 @@ pub fn indented_seq<'a, O, E: 'a>( /// Similar to [`and!`], but we modify the `min_indent` of the second parser to be /// 1 greater than the `column()` at the start of the first parser. -#[macro_export] -macro_rules! absolute_indented_seq { - ($p1:expr, $p2:expr) => { - move |arena: &'a bumpalo::Bump, state: $crate::state::State<'a>, _min_indent: u32| { - let start_indent = state.column(); +pub fn absolute_indented_seq<'a, Output1, Output2, E: 'a>( + p1: impl Parser<'a, Output1, E>, + p2: impl Parser<'a, Output2, E>, +) -> impl Parser<'a, (Output1, Output2), E> { + move |arena: &'a bumpalo::Bump, state: crate::state::State<'a>, _min_indent: u32| { + let start_indent = state.column(); - let p1_indent = start_indent; - let p2_indent = p1_indent + 1; + let p1_indent = start_indent; + let p2_indent = p1_indent + 1; - match $p1.parse(arena, state, p1_indent) { - Ok((p1, out1, state)) => match $p2.parse(arena, state, p2_indent) { - Ok((p2, out2, state)) => Ok((p1.or(p2), (out1, out2), state)), - Err((p2, fail)) => Err((p1.or(p2), fail)), - }, - Err((progress, fail)) => Err((progress, fail)), - } + match p1.parse(arena, state, p1_indent) { + Ok((p1, out1, state)) => match p2.parse(arena, state, p2_indent) { + Ok((p2, out2, state)) => Ok((p1.or(p2), (out1, out2), state)), + Err((p2, fail)) => Err((p1.or(p2), fail)), + }, + Err((progress, fail)) => Err((progress, fail)), } - }; + } } /// Returns the result of the first parser that makes progress, even if it failed. From 41d7d02e2a880407a879022645dbb445555d76b9 Mon Sep 17 00:00:00 2001 From: Jackson Wambolt Date: Mon, 15 Apr 2024 19:44:47 -0500 Subject: [PATCH 06/18] Un-macro add --- crates/compiler/parse/src/blankspace.rs | 6 +- crates/compiler/parse/src/expr.rs | 52 ++++----- crates/compiler/parse/src/header.rs | 8 +- crates/compiler/parse/src/module.rs | 25 ++--- crates/compiler/parse/src/parser.rs | 108 +++++-------------- crates/compiler/parse/src/type_annotation.rs | 28 ++--- 6 files changed, 89 insertions(+), 138 deletions(-) diff --git a/crates/compiler/parse/src/blankspace.rs b/crates/compiler/parse/src/blankspace.rs index be518b62aa..6aa2b6a7b3 100644 --- a/crates/compiler/parse/src/blankspace.rs +++ b/crates/compiler/parse/src/blankspace.rs @@ -138,7 +138,7 @@ where E: 'a + SpaceProblem, { parser::map_with_arena( - and!(spaces(), parser), + and(spaces(), parser), |arena: &'a Bump, (space_list, loc_expr): (&'a [CommentOrNewline<'a>], Loc)| { if space_list.is_empty() { loc_expr @@ -161,7 +161,7 @@ where E: 'a + SpaceProblem, { parser::map_with_arena( - and!(space0_e(indent_problem), parser), + and(space0_e(indent_problem), parser), |arena: &'a Bump, (space_list, loc_expr): (&'a [CommentOrNewline<'a>], Loc)| { if space_list.is_empty() { loc_expr @@ -184,7 +184,7 @@ where E: 'a + SpaceProblem, { parser::map_with_arena( - and!(parser, space0_e(indent_problem)), + and(parser, space0_e(indent_problem)), |arena: &'a Bump, (loc_expr, space_list): (Loc, &'a [CommentOrNewline<'a>])| { if space_list.is_empty() { loc_expr diff --git a/crates/compiler/parse/src/expr.rs b/crates/compiler/parse/src/expr.rs index 44fbf3af5a..c6e0045fd3 100644 --- a/crates/compiler/parse/src/expr.rs +++ b/crates/compiler/parse/src/expr.rs @@ -10,7 +10,7 @@ use crate::blankspace::{ use crate::ident::{integer_ident, lowercase_ident, parse_ident, Accessor, Ident}; use crate::keyword; use crate::parser::{ - self, 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, skip_second, specialize_err, specialize_err_ref, then, two_bytes, EClosure, EExpect, EExpr, EIf, EInParens, EList, ENumber, EPattern, ERecord, EString, EType, EWhen, Either, ParseResult, @@ -132,7 +132,7 @@ fn loc_expr_in_parens_help<'a>() -> impl Parser<'a, Loc>, EInParens<'a> fn loc_expr_in_parens_etc_help<'a>() -> impl Parser<'a, Loc>, EExpr<'a>> { map_with_arena!( - loc!(and!( + loc!(and( specialize_err(EExpr::InParens, loc_expr_in_parens_help()), record_field_access_chain() )), @@ -273,7 +273,7 @@ fn loc_possibly_negative_or_negated_term<'a>( let initial = state.clone(); let (_, (loc_op, loc_expr), state) = - and!(loc!(unary_negate()), loc_term(options)).parse(arena, state, min_indent)?; + and(loc!(unary_negate()), loc_term(options)).parse(arena, state, min_indent)?; let loc_expr = numeric_negate_expression(arena, initial, loc_op, loc_expr, &[]); @@ -282,7 +282,7 @@ fn loc_possibly_negative_or_negated_term<'a>( // this will parse negative numbers, which the unary negate thing up top doesn't (for now) loc!(specialize_err(EExpr::Number, number_literal_help())), loc!(map_with_arena!( - and!( + and( loc!(byte(b'!', EExpr::Start)), space0_before_e(loc_term(options), EExpr::IndentStart) ), @@ -1296,7 +1296,7 @@ fn opaque_signature_with_space_before<'a>() -> impl Parser< ), EExpr<'a>, > { - and!( + and( specialize_err( EExpr::Type, space0_before_e( @@ -1306,8 +1306,8 @@ fn opaque_signature_with_space_before<'a>() -> impl Parser< ), optional(backtrackable(specialize_err( EExpr::Type, - space0_before_e(type_annotation::implements_abilities(), EType::TIndentStart,), - ))) + space0_before_e(type_annotation::implements_abilities(), EType::TIndentStart), + ))), ) } @@ -1488,7 +1488,7 @@ mod ability { absolute_indented_seq( specialize_err(|_, pos| EAbility::DemandName(pos), loc!(lowercase_ident())), skip_first( - and!( + and( // TODO: do we get anything from picking up spaces here? space0_e(EAbility::DemandName), byte(b':', EAbility::DemandColon) @@ -2368,7 +2368,7 @@ fn closure_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EClo byte_indent(b'\\', EClosure::Start), // Once we see the '\', we're committed to parsing this as a closure. // It may turn out to be malformed, but it is definitely a closure. - and!( + and( // Parse the params // Params are comma-separated sep_by1_e( @@ -2406,7 +2406,7 @@ mod when { /// Parser for when expressions. pub fn expr_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EWhen<'a>> { map_with_arena!( - and!( + and( indented_seq( parser::keyword(keyword::WHEN, EWhen::When), space0_around_e_no_after_indent_check( @@ -2458,7 +2458,7 @@ mod when { })); let branch_parser = map!( - and!( + and( then( branch_alternatives(options, Some(pattern_indent_level)), move |_arena, state, _, ((indent_column, loc_patterns), loc_guard)| { @@ -2511,7 +2511,7 @@ mod when { check_for_arrow: false, ..options }; - and!( + and( branch_alternatives_help(pattern_indent_level), one_of![ map!( @@ -2530,7 +2530,7 @@ mod when { Some ), |_, s, _| Ok((NoProgress, None, s)) - ] + ], ) } @@ -2631,20 +2631,20 @@ mod when { fn if_branch<'a>() -> impl Parser<'a, (Loc>, Loc>), EIf<'a>> { skip_second( - and!( + and( skip_second( space0_around_ee( specialize_err_ref(EIf::Condition, loc_expr(true)), EIf::IndentCondition, EIf::IndentThenToken, ), - parser::keyword(keyword::THEN, EIf::Then) + parser::keyword(keyword::THEN, EIf::Then), ), space0_around_ee( specialize_err_ref(EIf::ThenBranch, loc_expr(true)), EIf::IndentThenBranch, EIf::IndentElseToken, - ) + ), ), parser::keyword(keyword::ELSE, EIf::Else), ) @@ -2727,9 +2727,9 @@ fn if_expr_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EIf< // try to parse another `if` // NOTE this drops spaces between the `else` and the `if` - let optional_if = and!( + let optional_if = and( backtrackable(space0_e(EIf::IndentIf)), - parser::keyword(keyword::IF, EIf::If) + parser::keyword(keyword::IF, EIf::If), ); match optional_if.parse(arena, state.clone(), min_indent) { @@ -2981,13 +2981,13 @@ pub fn record_field<'a>() -> impl Parser<'a, RecordField<'a>, ERecord<'a>> { use RecordField::*; map_with_arena!( - and!( + and( specialize_err(|_, pos| ERecord::Field(pos), loc!(lowercase_ident())), - and!( + and( spaces(), optional(either!( - and!(byte(b':', ERecord::Colon), record_field_expr()), - and!( + and(byte(b':', ERecord::Colon), record_field_expr()), + and( byte(b'?', ERecord::QuestionMark), spaces_before(specialize_err_ref(ERecord::Expr, loc_expr(false))) ) @@ -3029,10 +3029,10 @@ enum RecordFieldExpr<'a> { fn record_field_expr<'a>() -> impl Parser<'a, RecordFieldExpr<'a>, ERecord<'a>> { map_with_arena!( - and!( + and( spaces(), either!( - and!( + and( two_bytes(b'<', b'-', ERecord::Arrow), spaces_before(specialize_err_ref(ERecord::Expr, loc_expr(false))) ), @@ -3096,10 +3096,10 @@ fn record_help<'a>() -> impl Parser<'a, RecordHelp<'a>, ERecord<'a>> { fn record_literal_help<'a>() -> impl Parser<'a, Expr<'a>, EExpr<'a>> { then( - and!( + and( specialize_err(EExpr::Record, record_help()), // there can be field access, e.g. `{ x : 4 }.x` - record_field_access_chain() + record_field_access_chain(), ), move |arena, state, _, (record, accessors)| { let expr_result = match record.update { diff --git a/crates/compiler/parse/src/header.rs b/crates/compiler/parse/src/header.rs index b03266973b..d7bee7cba9 100644 --- a/crates/compiler/parse/src/header.rs +++ b/crates/compiler/parse/src/header.rs @@ -4,7 +4,7 @@ use crate::ast::{ use crate::blankspace::space0_e; use crate::expr::merge_spaces; use crate::ident::{lowercase_ident, UppercaseIdent}; -use crate::parser::{byte, skip_second, specialize_err, EPackageEntry, EPackageName, Parser}; +use crate::parser::{and, byte, skip_second, specialize_err, EPackageEntry, EPackageName, Parser}; use crate::parser::{optional, then}; use crate::string_literal; use roc_module::symbol::{ModuleId, Symbol}; @@ -342,10 +342,10 @@ pub fn package_entry<'a>() -> impl Parser<'a, Spaced<'a, PackageEntry<'a>>, EPac // e.g. "uc" in `uc: roc/unicode 1.0.0` // // (Indirect dependencies don't have a shorthand.) - and!( - optional(and!( + and( + optional(and( skip_second( - and!( + and( specialize_err(|_, pos| EPackageEntry::Shorthand(pos), lowercase_ident()), space0_e(EPackageEntry::IndentPackage) ), diff --git a/crates/compiler/parse/src/module.rs b/crates/compiler/parse/src/module.rs index f8718ac3d1..f203d25b02 100644 --- a/crates/compiler/parse/src/module.rs +++ b/crates/compiler/parse/src/module.rs @@ -9,9 +9,10 @@ use crate::header::{ use crate::ident::{self, lowercase_ident, unqualified_ident, uppercase, UppercaseIdent}; use crate::parser::Progress::{self, *}; use crate::parser::{ - backtrackable, byte, increment_min_indent, 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, + and, backtrackable, byte, increment_min_indent, 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, }; use crate::state::State; use crate::string_literal::{self, parse_str_literal}; @@ -413,7 +414,7 @@ where E: 'a + SpaceProblem, { map!( - and!( + and( skip_second( // parse any leading space before the keyword backtrackable(space0_e(indent_problem1)), @@ -560,8 +561,8 @@ fn typed_ident<'a>() -> impl Parser<'a, Spaced<'a, TypedIdent<'a>>, ETypedIdent< // // printLine : Str -> Effect {} map!( - and!( - and!( + and( + and( loc!(specialize_err( |_, pos| ETypedIdent::Identifier(pos), lowercase_ident() @@ -611,8 +612,8 @@ fn imports_entry<'a>() -> impl Parser<'a, Spaced<'a, ImportsEntry<'a>>, EImports one_of!( map!( - and!( - and!( + and( + and( // e.g. `pf.` optional(backtrackable(skip_second( shortname(), @@ -649,14 +650,14 @@ fn imports_entry<'a>() -> impl Parser<'a, Spaced<'a, ImportsEntry<'a>>, EImports ) .trace("normal_import"), map!( - and!( - and!( + and( + and( // e.g. "filename" // TODO: str literal allows for multiline strings. We probably don't want that for file names. specialize_err(|_, pos| EImports::StrLiteral(pos), parse_str_literal()), // e.g. as - and!( - and!( + and( + and( space0_e(EImports::AsKeyword), two_bytes(b'a', b's', EImports::AsKeyword) ), diff --git a/crates/compiler/parse/src/parser.rs b/crates/compiler/parse/src/parser.rs index 214503307d..015249c42c 100644 --- a/crates/compiler/parse/src/parser.rs +++ b/crates/compiler/parse/src/parser.rs @@ -1462,8 +1462,8 @@ where macro_rules! collection_inner { ($elem:expr, $delimiter:expr, $space_before:expr) => { map_with_arena!( - and!( - and!( + $crate::parser::and( + $crate::parser::and( $crate::blankspace::spaces(), $crate::parser::trailing_sep_by0( $delimiter, @@ -1622,49 +1622,47 @@ where /// Runs two parsers in succession. If both parsers succeed, the output is a tuple of both outputs. /// Both parsers must have the same error type. /// -/// # Examples +/// # Example +/// /// ``` /// # #![forbid(unused_imports)] /// # use roc_parse::state::State; -/// # use crate::roc_parse::parser::{Parser, Progress, word, byte}; +/// # use crate::roc_parse::parser::{Parser, Progress, and, word}; /// # use roc_region::all::Position; -/// # use roc_parse::and; /// # use bumpalo::Bump; /// # #[derive(Debug, PartialEq)] /// # enum Problem { /// # NotFound(Position), /// # } /// # let arena = Bump::new(); -/// # fn foo<'a>(arena: &'a Bump) { -/// let parser = and!( -/// word("hello", Problem::NotFound), -/// byte(b',', Problem::NotFound) -/// ); +/// let parser1 = word("hello", Problem::NotFound); +/// let parser2 = word(", ", Problem::NotFound); +/// let parser = and(parser1, parser2); /// +/// // Success case /// let (progress, output, state) = parser.parse(&arena, State::new("hello, world".as_bytes()), 0).unwrap(); /// assert_eq!(progress, Progress::MadeProgress); -/// assert_eq!(output, ((), ())); -/// assert_eq!(state.pos().offset, 6); +/// assert_eq!(output, ((),())); +/// assert_eq!(state.pos(), Position::new(7)); /// -/// let (progress, err) = parser.parse(&arena, State::new("hello! world".as_bytes()), 0).unwrap_err(); +/// // Error case +/// let (progress, err) = parser.parse(&arena, State::new("hello!! world".as_bytes()), 0).unwrap_err(); /// assert_eq!(progress, Progress::MadeProgress); /// assert_eq!(err, Problem::NotFound(Position::new(5))); -/// # } -/// # foo(&arena); /// ``` -#[macro_export] -macro_rules! and { - ($p1:expr, $p2:expr) => { - move |arena: &'a bumpalo::Bump, state: $crate::state::State<'a>, min_indent: u32| match $p1 - .parse(arena, state, min_indent) - { - Ok((p1, out1, state)) => match $p2.parse(arena, state, min_indent) { - Ok((p2, out2, state)) => Ok((p1.or(p2), (out1, out2), state)), - Err((p2, fail)) => Err((p1.or(p2), fail)), - }, - Err((progress, fail)) => Err((progress, fail)), - } - }; +pub fn and<'a, Output1, Output2, E: 'a>( + p1: impl Parser<'a, Output1, E>, + p2: impl Parser<'a, Output2, E>, +) -> impl Parser<'a, (Output1, Output2), E> { + move |arena: &'a bumpalo::Bump, state: crate::state::State<'a>, min_indent: u32| match p1 + .parse(arena, state, min_indent) + { + Ok((p1, out1, state)) => match p2.parse(arena, state, min_indent) { + Ok((p2, out2, state)) => Ok((p1.or(p2), (out1, out2), state)), + Err((p2, fail)) => Err((p1.or(p2), fail)), + }, + Err((progress, fail)) => Err((progress, fail)), + } } /// Take as input something that looks like a struct literal where values are parsers @@ -1715,7 +1713,7 @@ pub fn indented_seq<'a, O, E: 'a>( } } -/// Similar to [`and!`], but we modify the `min_indent` of the second parser to be +/// Similar to [`and`], but we modify the `min_indent` of the second parser to be /// 1 greater than the `column()` at the start of the first parser. pub fn absolute_indented_seq<'a, Output1, Output2, E: 'a>( p1: impl Parser<'a, Output1, E>, @@ -2173,9 +2171,9 @@ where #[macro_export] macro_rules! byte_check_indent { ($byte_to_match:expr, $problem:expr, $min_indent:expr, $indent_problem:expr) => { - and!( + $crate::parser::and( byte($byte_to_match, $problem), - $crate::parser::check_indent($min_indent, $indent_problem) + $crate::parser::check_indent($min_indent, $indent_problem), ) }; } @@ -2545,54 +2543,6 @@ pub fn between<'a, Before, Inner, After, Err: 'a>( skip_first(opening_brace, skip_second(inner, closing_brace)) } -/// Runs two parsers in succession. If both parsers succeed, the output is a tuple of both outputs. -/// Both parsers must have the same error type. -/// -/// This is a function version of the [`and!`] macro. -/// For some reason, some usages won't compile unless they use this instead of the macro version. -/// -/// # Example -/// -/// ``` -/// # #![forbid(unused_imports)] -/// # use roc_parse::state::State; -/// # use crate::roc_parse::parser::{Parser, Progress, and, word}; -/// # use roc_region::all::Position; -/// # use bumpalo::Bump; -/// # #[derive(Debug, PartialEq)] -/// # enum Problem { -/// # NotFound(Position), -/// # } -/// # let arena = Bump::new(); -/// let parser1 = word("hello", Problem::NotFound); -/// let parser2 = word(", ", Problem::NotFound); -/// let parser = and(parser1, parser2); -/// -/// // Success case -/// let (progress, output, state) = parser.parse(&arena, State::new("hello, world".as_bytes()), 0).unwrap(); -/// assert_eq!(progress, Progress::MadeProgress); -/// assert_eq!(output, ((),())); -/// assert_eq!(state.pos(), Position::new(7)); -/// -/// // Error case -/// let (progress, err) = parser.parse(&arena, State::new("hello!! world".as_bytes()), 0).unwrap_err(); -/// assert_eq!(progress, Progress::MadeProgress); -/// assert_eq!(err, Problem::NotFound(Position::new(5))); -/// ``` -#[inline(always)] -pub fn and<'a, P1, P2, A, B, E>(p1: P1, p2: P2) -> impl Parser<'a, (A, B), E> -where - P1: Parser<'a, A, E>, - P2: Parser<'a, B, E>, - P1: 'a, - P2: 'a, - A: 'a, - B: 'a, - E: 'a, -{ - and!(p1, p2) -} - /// Adds location info. This is a function version the [`loc!`] macro. /// /// For some reason, some usages won't compile unless they use this instead of the macro version. diff --git a/crates/compiler/parse/src/type_annotation.rs b/crates/compiler/parse/src/type_annotation.rs index f6947fb54d..80dee60d51 100644 --- a/crates/compiler/parse/src/type_annotation.rs +++ b/crates/compiler/parse/src/type_annotation.rs @@ -9,7 +9,7 @@ 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, increment_min_indent, skip_first, skip_second, then, ERecord, + absolute_column_min_indent, and, increment_min_indent, skip_first, skip_second, then, ERecord, ETypeAbilityImpl, }; use crate::parser::{ @@ -117,7 +117,7 @@ fn parse_type_alias_after_as<'a>() -> impl Parser<'a, TypeHeader<'a>, EType<'a>> fn term<'a>(stop_at_surface_has: bool) -> impl Parser<'a, Loc>, EType<'a>> { map_with_arena!( - and!( + and( one_of!( loc_wildcard(), loc_inferred(), @@ -137,7 +137,7 @@ fn term<'a>(stop_at_surface_has: bool) -> impl Parser<'a, Loc // Inline alias notation, e.g. [Nil, Cons a (List a)] as List a one_of![ map!( - and!( + and( skip_second( backtrackable(space0_e(EType::TIndentEnd)), crate::parser::keyword(keyword::AS, EType::TEnd) @@ -209,7 +209,7 @@ fn loc_applied_arg<'a>( stop_at_surface_has: bool, ) -> impl Parser<'a, Loc>, EType<'a>> { map_with_arena!( - and!( + and( backtrackable(space0_e(EType::TIndentStart)), one_of!( loc_wildcard(), @@ -242,7 +242,7 @@ fn loc_type_in_parens<'a>( stop_at_surface_has: bool, ) -> impl Parser<'a, Loc>, ETypeInParens<'a>> { then( - loc!(and!( + loc!(and( collection_trailing_sep_e!( byte(b'(', ETypeInParens::Open), specialize_err_ref(ETypeInParens::Type, expression(true, false)), @@ -399,7 +399,7 @@ fn record_type<'a>( fn applied_type<'a>(stop_at_surface_has: bool) -> impl Parser<'a, TypeAnnotation<'a>, EType<'a>> { map!( - and!( + and( specialize_err(EType::TApply, concrete_type()), // Optionally parse space-separated arguments for the constructor, // e.g. `Str Float` in `Map Str Float` @@ -432,7 +432,7 @@ fn loc_applied_args_e<'a>( // Hash & Eq & ... fn ability_chain<'a>() -> impl Parser<'a, Vec<'a, Loc>>, EType<'a>> { map!( - and!( + and( space0_before_optional_after( specialize_err(EType::TApply, loc!(concrete_type())), EType::TIndentStart, @@ -460,7 +460,7 @@ fn ability_chain<'a>() -> impl Parser<'a, Vec<'a, Loc>>, ETyp fn implements_clause<'a>() -> impl Parser<'a, Loc>, EType<'a>> { map!( // Suppose we are trying to parse "a implements Hash" - and!( + and( space0_around_ee( // Parse "a", with appropriate spaces specialize_err( @@ -497,9 +497,9 @@ fn implements_clause<'a>() -> impl Parser<'a, Loc>, EType<' fn implements_clause_chain<'a>( ) -> impl Parser<'a, (&'a [CommentOrNewline<'a>], &'a [Loc>]), EType<'a>> { move |arena, state: State<'a>, min_indent: u32| { - let (_, (spaces_before, ()), state) = and!( + let (_, (spaces_before, ()), state) = and( space0_e(EType::TIndentStart), - word(crate::keyword::WHERE, EType::TWhereBar) + word(crate::keyword::WHERE, EType::TWhereBar), ) .parse(arena, state, min_indent)?; @@ -584,7 +584,7 @@ fn expression<'a>( let (p1, first, state) = space0_before_e(term(stop_at_surface_has), EType::TIndentStart) .parse(arena, state, min_indent)?; - let result = and![ + let result = and( zero_or_more!(skip_first( byte(b',', EType::TFunctionArgument), one_of![ @@ -599,10 +599,10 @@ fn expression<'a>( .trace("type_annotation:expression:rest_args"), skip_second( space0_e(EType::TIndentStart), - two_bytes(b'-', b'>', EType::TStart) + two_bytes(b'-', b'>', EType::TStart), ) - .trace("type_annotation:expression:arrow") - ] + .trace("type_annotation:expression:arrow"), + ) .parse(arena, state.clone(), min_indent); let (progress, annot, state) = match result { From 3394aab650666205ccf4254b3bf91153c03a124c Mon Sep 17 00:00:00 2001 From: Jackson Wambolt Date: Mon, 15 Apr 2024 19:56:30 -0500 Subject: [PATCH 07/18] Un-macro map --- crates/compiler/parse/src/expr.rs | 44 +++++++-------- crates/compiler/parse/src/module.rs | 58 ++++++++++---------- crates/compiler/parse/src/parser.rs | 27 ++++----- crates/compiler/parse/src/pattern.rs | 20 +++---- crates/compiler/parse/src/type_annotation.rs | 38 ++++++------- 5 files changed, 90 insertions(+), 97 deletions(-) diff --git a/crates/compiler/parse/src/expr.rs b/crates/compiler/parse/src/expr.rs index c6e0045fd3..431cf38f69 100644 --- a/crates/compiler/parse/src/expr.rs +++ b/crates/compiler/parse/src/expr.rs @@ -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>)| { - AbilityMember { - name: name.map_owned(Spaced::Item), - typ, - } - } + |(name, typ): (Loc<&'a str>, Loc>)| 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 { diff --git a/crates/compiler/parse/src/module.rs b/crates/compiler/parse/src/module.rs index f203d25b02..3804997c85 100644 --- a/crates/compiler/parse/src/module.rs +++ b/crates/compiler/parse/src/module.rs @@ -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" diff --git a/crates/compiler/parse/src/parser.rs b/crates/compiler/parse/src/parser.rs index 015249c42c..86b5d0d4e7 100644 --- a/crates/compiler/parse/src/parser.rs +++ b/crates/compiler/parse/src/parser.rs @@ -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. diff --git a/crates/compiler/parse/src/pattern.rs b/crates/compiler/parse/src/pattern.rs index bb30abe852..a256cb3cc7 100644 --- a/crates/compiler/parse/src/pattern.rs +++ b/crates/compiler/parse/src/pattern.rs @@ -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>, 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, ) } diff --git a/crates/compiler/parse/src/type_annotation.rs b/crates/compiler/parse/src/type_annotation.rs index 80dee60d51..8e3ccd0842 100644 --- a/crates/compiler/parse/src/type_annotation.rs +++ b/crates/compiler/parse/src/type_annotation.rs @@ -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 ), // 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 /// The `*` type variable, e.g. in (List *) Wildcard, fn loc_wildcard<'a>() -> impl Parser<'a, Loc>, 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>>)| { 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>>, 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>>, ETyp EType::TIndentStart, EType::TIndentEnd, ) - )) + )), ), |(first_ability, mut other_abilities): ( Loc>, - Vec<'a, Loc>> + Vec<'a, Loc>>, )| { other_abilities.insert(0, first_ability); other_abilities - } + }, ) } fn implements_clause<'a>() -> impl Parser<'a, Loc>, 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>, Vec<'a, Loc>>)| { let abilities_region = Region::span_across( @@ -488,7 +488,7 @@ fn implements_clause<'a>() -> impl Parser<'a, Loc>, EType<' abilities: abilities.into_bump_slice(), }; Loc::at(region, implements_clause) - } + }, ) } @@ -530,7 +530,7 @@ pub fn implements_abilities<'a>() -> impl Parser<'a, Loc 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!( From 5c0b2a093883eb9febf59dc2f3b71c37ad414294 Mon Sep 17 00:00:00 2001 From: Jackson Wambolt Date: Mon, 15 Apr 2024 20:06:06 -0500 Subject: [PATCH 08/18] Un-macro loc --- crates/compiler/parse/src/expr.rs | 82 ++++++++++---------- crates/compiler/parse/src/header.rs | 10 ++- crates/compiler/parse/src/module.rs | 50 ++++++------ crates/compiler/parse/src/parser.rs | 68 ++++------------ crates/compiler/parse/src/pattern.rs | 36 ++++----- crates/compiler/parse/src/string_literal.rs | 2 +- crates/compiler/parse/src/type_annotation.rs | 54 ++++++------- 7 files changed, 130 insertions(+), 172 deletions(-) diff --git a/crates/compiler/parse/src/expr.rs b/crates/compiler/parse/src/expr.rs index 431cf38f69..838e0854be 100644 --- a/crates/compiler/parse/src/expr.rs +++ b/crates/compiler/parse/src/expr.rs @@ -11,7 +11,7 @@ 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, map, optional, reset_min_indent, sep_by1, sep_by1_e, set_min_indent, + line_min_indent, loc, 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, @@ -94,7 +94,7 @@ pub fn expr_help<'a>() -> impl Parser<'a, Expr<'a>, EExpr<'a>> { fn loc_expr_in_parens_help<'a>() -> impl Parser<'a, Loc>, EInParens<'a>> { then( - loc!(collection_trailing_sep_e!( + loc(collection_trailing_sep_e!( byte(b'(', EInParens::Open), specialize_err_ref(EInParens::Expr, loc_expr(false)), byte(b',', EInParens::End), @@ -132,7 +132,7 @@ fn loc_expr_in_parens_help<'a>() -> impl Parser<'a, Loc>, EInParens<'a> fn loc_expr_in_parens_etc_help<'a>() -> impl Parser<'a, Loc>, EExpr<'a>> { map_with_arena!( - loc!(and( + loc(and( specialize_err(EExpr::InParens, loc_expr_in_parens_help()), record_field_access_chain() )), @@ -177,19 +177,19 @@ fn loc_term_or_underscore_or_conditional<'a>( ) -> impl Parser<'a, Loc>, EExpr<'a>> { one_of!( loc_expr_in_parens_etc_help(), - loc!(specialize_err(EExpr::If, if_expr_help(options))), - loc!(specialize_err(EExpr::When, when::expr_help(options))), - loc!(specialize_err(EExpr::Str, string_like_literal_help())), - loc!(specialize_err( + loc(specialize_err(EExpr::If, if_expr_help(options))), + loc(specialize_err(EExpr::When, when::expr_help(options))), + loc(specialize_err(EExpr::Str, string_like_literal_help())), + loc(specialize_err( EExpr::Number, positive_number_literal_help() )), - loc!(specialize_err(EExpr::Closure, closure_help(options))), - loc!(crash_kw()), - loc!(underscore_expression()), - loc!(record_literal_help()), - loc!(specialize_err(EExpr::List, list_literal_help())), - loc!(map_with_arena!( + loc(specialize_err(EExpr::Closure, closure_help(options))), + loc(crash_kw()), + loc(underscore_expression()), + loc(record_literal_help()), + loc(specialize_err(EExpr::List, list_literal_help())), + loc(map_with_arena!( assign_or_destructure_identifier(), ident_to_expr )), @@ -203,16 +203,16 @@ fn loc_term_or_underscore<'a>( ) -> impl Parser<'a, Loc>, EExpr<'a>> { one_of!( loc_expr_in_parens_etc_help(), - loc!(specialize_err(EExpr::Str, string_like_literal_help())), - loc!(specialize_err( + loc(specialize_err(EExpr::Str, string_like_literal_help())), + loc(specialize_err( EExpr::Number, positive_number_literal_help() )), - loc!(specialize_err(EExpr::Closure, closure_help(options))), - loc!(underscore_expression()), - loc!(record_literal_help()), - loc!(specialize_err(EExpr::List, list_literal_help())), - loc!(map_with_arena!( + loc(specialize_err(EExpr::Closure, closure_help(options))), + loc(underscore_expression()), + loc(record_literal_help()), + loc(specialize_err(EExpr::List, list_literal_help())), + loc(map_with_arena!( assign_or_destructure_identifier(), ident_to_expr )), @@ -222,15 +222,15 @@ fn loc_term_or_underscore<'a>( fn loc_term<'a>(options: ExprParseOptions) -> impl Parser<'a, Loc>, EExpr<'a>> { one_of!( loc_expr_in_parens_etc_help(), - loc!(specialize_err(EExpr::Str, string_like_literal_help())), - loc!(specialize_err( + loc(specialize_err(EExpr::Str, string_like_literal_help())), + loc(specialize_err( EExpr::Number, positive_number_literal_help() )), - loc!(specialize_err(EExpr::Closure, closure_help(options))), - loc!(record_literal_help()), - loc!(specialize_err(EExpr::List, list_literal_help())), - loc!(map_with_arena!( + loc(specialize_err(EExpr::Closure, closure_help(options))), + loc(record_literal_help()), + loc(specialize_err(EExpr::List, list_literal_help())), + loc(map_with_arena!( assign_or_destructure_identifier(), ident_to_expr )), @@ -273,17 +273,17 @@ fn loc_possibly_negative_or_negated_term<'a>( let initial = state.clone(); let (_, (loc_op, loc_expr), state) = - and(loc!(unary_negate()), loc_term(options)).parse(arena, state, min_indent)?; + and(loc(unary_negate()), loc_term(options)).parse(arena, state, min_indent)?; let loc_expr = numeric_negate_expression(arena, initial, loc_op, loc_expr, &[]); Ok((MadeProgress, loc_expr, state)) }, // this will parse negative numbers, which the unary negate thing up top doesn't (for now) - loc!(specialize_err(EExpr::Number, number_literal_help())), - loc!(map_with_arena!( + loc(specialize_err(EExpr::Number, number_literal_help())), + loc(map_with_arena!( and( - loc!(byte(b'!', EExpr::Start)), + loc(byte(b'!', EExpr::Start)), space0_before_e(loc_term(options), EExpr::IndentStart) ), |arena: &'a Bump, (loc_op, loc_expr): (Loc<_>, _)| { @@ -323,12 +323,12 @@ fn unary_negate<'a>() -> impl Parser<'a, (), EExpr<'a>> { fn expr_start<'a>(options: ExprParseOptions) -> impl Parser<'a, Loc>, EExpr<'a>> { one_of![ - loc!(specialize_err(EExpr::If, if_expr_help(options))), - loc!(specialize_err(EExpr::When, when::expr_help(options))), - loc!(specialize_err(EExpr::Expect, expect_help(options))), - loc!(specialize_err(EExpr::Dbg, dbg_help(options))), - loc!(specialize_err(EExpr::Closure, closure_help(options))), - loc!(expr_operator_chain(options)), + loc(specialize_err(EExpr::If, if_expr_help(options))), + loc(specialize_err(EExpr::When, when::expr_help(options))), + loc(specialize_err(EExpr::Expect, expect_help(options))), + loc(specialize_err(EExpr::Dbg, dbg_help(options))), + loc(specialize_err(EExpr::Closure, closure_help(options))), + loc(expr_operator_chain(options)), fail_expr_start_e() ] .trace("expr_start") @@ -1486,7 +1486,7 @@ mod ability { map( // Require the type to be more indented than the name absolute_indented_seq( - specialize_err(|_, pos| EAbility::DemandName(pos), loc!(lowercase_ident())), + specialize_err(|_, pos| EAbility::DemandName(pos), loc(lowercase_ident())), skip_first( and( // TODO: do we get anything from picking up spaces here? @@ -2010,7 +2010,7 @@ fn parse_expr_end<'a>( let before_op = state.clone(); // try an operator let line_indent = state.line_indent(); - match loc!(operator()).parse(arena, state.clone(), min_indent) { + match loc(operator()).parse(arena, state.clone(), min_indent) { Err((MadeProgress, f)) => Err((MadeProgress, f)), Ok((_, loc_op, state)) => { expr_state.consume_spaces(arena); @@ -2980,7 +2980,7 @@ pub fn record_field<'a>() -> impl Parser<'a, RecordField<'a>, ERecord<'a>> { map_with_arena!( and( - specialize_err(|_, pos| ERecord::Field(pos), loc!(lowercase_ident())), + specialize_err(|_, pos| ERecord::Field(pos), loc(lowercase_ident())), and( spaces(), optional(either!( @@ -3078,12 +3078,12 @@ fn record_help<'a>() -> impl Parser<'a, RecordHelp<'a>, ERecord<'a>> { // so that we have a Spaceable value to work with, // and then in canonicalization verify that it's an Expr::Var // (and not e.g. an `Expr::Access`) and extract its string. - loc!(record_updateable_identifier()), + loc(record_updateable_identifier()), ), byte(b'&', ERecord::Ampersand) ))), fields: collection_inner!( - loc!(record_field()), + loc(record_field()), byte(b',', ERecord::End), RecordField::SpaceBefore ), diff --git a/crates/compiler/parse/src/header.rs b/crates/compiler/parse/src/header.rs index d7bee7cba9..f0074c999d 100644 --- a/crates/compiler/parse/src/header.rs +++ b/crates/compiler/parse/src/header.rs @@ -4,7 +4,9 @@ use crate::ast::{ use crate::blankspace::space0_e; use crate::expr::merge_spaces; use crate::ident::{lowercase_ident, UppercaseIdent}; -use crate::parser::{and, byte, skip_second, specialize_err, EPackageEntry, EPackageName, Parser}; +use crate::parser::{ + and, byte, loc, skip_second, specialize_err, EPackageEntry, EPackageName, Parser, +}; use crate::parser::{optional, then}; use crate::string_literal; use roc_module::symbol::{ModuleId, Symbol}; @@ -353,7 +355,7 @@ pub fn package_entry<'a>() -> impl Parser<'a, Spaced<'a, PackageEntry<'a>>, EPac ), space0_e(EPackageEntry::IndentPackage) )), - loc!(specialize_err(EPackageEntry::BadPackage, package_name())) + loc(specialize_err(EPackageEntry::BadPackage, package_name())) ), move |arena, (opt_shorthand, package_or_path)| { let entry = match opt_shorthand { @@ -380,9 +382,9 @@ pub fn package_entry<'a>() -> impl Parser<'a, Spaced<'a, PackageEntry<'a>>, EPac pub fn package_name<'a>() -> impl Parser<'a, PackageName<'a>, EPackageName<'a>> { then( - loc!(specialize_err( + loc(specialize_err( EPackageName::BadPath, - string_literal::parse_str_literal() + string_literal::parse_str_literal(), )), move |_arena, state, progress, text| match text.value { StrLiteral::PlainLine(text) => Ok((progress, PackageName(text), state)), diff --git a/crates/compiler/parse/src/module.rs b/crates/compiler/parse/src/module.rs index 3804997c85..c5b5e6f8fb 100644 --- a/crates/compiler/parse/src/module.rs +++ b/crates/compiler/parse/src/module.rs @@ -9,10 +9,10 @@ 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, 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, + and, backtrackable, byte, increment_min_indent, loc, 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, }; use crate::state::State; use crate::string_literal::{self, parse_str_literal}; @@ -97,7 +97,7 @@ pub fn header<'a>() -> impl Parser<'a, Module<'a>, EHeader<'a>> { fn interface_header<'a>() -> impl Parser<'a, InterfaceHeader<'a>, EHeader<'a>> { record!(InterfaceHeader { before_name: space0_e(EHeader::IndentStart), - name: loc!(module_name_help(EHeader::ModuleName)), + name: loc(module_name_help(EHeader::ModuleName)), exposes: specialize_err(EHeader::Exposes, exposes_values()), imports: specialize_err(EHeader::Imports, imports()), }) @@ -108,7 +108,7 @@ fn interface_header<'a>() -> impl Parser<'a, InterfaceHeader<'a>, EHeader<'a>> { fn hosted_header<'a>() -> impl Parser<'a, HostedHeader<'a>, EHeader<'a>> { record!(HostedHeader { before_name: space0_e(EHeader::IndentStart), - name: loc!(module_name_help(EHeader::ModuleName)), + name: loc(module_name_help(EHeader::ModuleName)), exposes: specialize_err(EHeader::Exposes, exposes_values()), imports: specialize_err(EHeader::Imports, imports()), generates: specialize_err(EHeader::Generates, generates()), @@ -180,7 +180,7 @@ fn module_name<'a>() -> impl Parser<'a, ModuleName<'a>, ()> { fn app_header<'a>() -> impl Parser<'a, AppHeader<'a>, EHeader<'a>> { record!(AppHeader { before_name: space0_e(EHeader::IndentStart), - name: loc!(crate::parser::specialize_err( + name: loc(crate::parser::specialize_err( EHeader::AppName, string_literal::parse_str_literal() )), @@ -195,7 +195,7 @@ fn app_header<'a>() -> impl Parser<'a, AppHeader<'a>, EHeader<'a>> { fn package_header<'a>() -> impl Parser<'a, PackageHeader<'a>, EHeader<'a>> { record!(PackageHeader { before_name: space0_e(EHeader::IndentStart), - name: loc!(specialize_err(EHeader::PackageName, package_name())), + name: loc(specialize_err(EHeader::PackageName, package_name())), exposes: specialize_err(EHeader::Exposes, exposes_modules()), packages: specialize_err(EHeader::Packages, packages()), }) @@ -206,7 +206,7 @@ fn package_header<'a>() -> impl Parser<'a, PackageHeader<'a>, EHeader<'a>> { fn platform_header<'a>() -> impl Parser<'a, PlatformHeader<'a>, EHeader<'a>> { record!(PlatformHeader { before_name: space0_e(EHeader::IndentStart), - name: loc!(specialize_err(EHeader::PlatformName, package_name())), + name: loc(specialize_err(EHeader::PlatformName, package_name())), requires: specialize_err(EHeader::Requires, requires()), exposes: specialize_err(EHeader::Exposes, exposes_modules()), packages: specialize_err(EHeader::Packages, packages()), @@ -249,7 +249,7 @@ fn provides_to<'a>() -> impl Parser<'a, ProvidesTo<'a>, EProvides<'a>> { EProvides::IndentTo, EProvides::IndentListStart ), - to: loc!(provides_to_package()), + to: loc(provides_to_package()), }) .trace("provides_to") } @@ -309,9 +309,9 @@ where F: Copy, E: 'a, { - loc!(map( - specialize_err(|_, pos| to_expectation(pos), ident::uppercase()), - Spaced::Item + loc(map( + specialize_err(move |_, pos| to_expectation(pos), ident::uppercase()), + Spaced::Item, )) } @@ -323,9 +323,9 @@ where F: Copy, E: 'a, { - loc!(map( - specialize_err(|_, pos| to_expectation(pos), unqualified_ident()), - |n| Spaced::Item(ExposedName::new(n)) + loc(map( + specialize_err(move |_, 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), @@ -372,7 +372,7 @@ fn requires_typed_ident<'a>() -> impl Parser<'a, Loc>> byte(b'{', ERequires::ListStart), skip_second( reset_min_indent(space0_around_ee( - specialize_err(ERequires::TypedIdent, loc!(typed_ident())), + specialize_err(ERequires::TypedIdent, loc(typed_ident())), ERequires::ListStart, ERequires::ListEnd, )), @@ -463,9 +463,9 @@ where F: Copy, E: 'a, { - loc!(map( - specialize_err(|_, pos| to_expectation(pos), module_name()), - Spaced::Item + loc(map( + specialize_err(move |_, pos| to_expectation(pos), module_name()), + Spaced::Item, )) } @@ -484,7 +484,7 @@ fn packages<'a>() -> impl Parser< ), item: collection_trailing_sep_e!( byte(b'{', EPackages::ListStart), - specialize_err(EPackages::PackageEntry, loc!(package_entry())), + specialize_err(EPackages::PackageEntry, loc(package_entry())), byte(b',', EPackages::ListEnd), byte(b'}', EPackages::ListEnd), Spaced::SpaceBefore @@ -544,7 +544,7 @@ fn imports<'a>() -> impl Parser< ), item: collection_trailing_sep_e!( byte(b'[', EImports::ListStart), - loc!(imports_entry()), + loc(imports_entry()), byte(b',', EImports::ListEnd), byte(b']', EImports::ListEnd), Spaced::SpaceBefore @@ -561,9 +561,9 @@ fn typed_ident<'a>() -> impl Parser<'a, Spaced<'a, TypedIdent<'a>>, ETypedIdent< map( and( and( - loc!(specialize_err( + loc(specialize_err( |_, pos| ETypedIdent::Identifier(pos), - lowercase_ident() + lowercase_ident(), )), space0_e(ETypedIdent::IndentHasType), ), diff --git a/crates/compiler/parse/src/parser.rs b/crates/compiler/parse/src/parser.rs index 86b5d0d4e7..ac59f924b9 100644 --- a/crates/compiler/parse/src/parser.rs +++ b/crates/compiler/parse/src/parser.rs @@ -1335,8 +1335,7 @@ where /// ``` /// # #![forbid(unused_imports)] /// # use roc_parse::state::State; -/// # use crate::roc_parse::parser::{Parser, Progress, word}; -/// # use roc_parse::loc; +/// # use crate::roc_parse::parser::{Parser, Progress, word, loc}; /// # use roc_region::all::{Loc, Position}; /// # use bumpalo::Bump; /// # #[derive(Debug, PartialEq)] @@ -1345,7 +1344,7 @@ where /// # } /// # let arena = Bump::new(); /// # fn foo<'a>(arena: &'a Bump) { -/// let parser = loc!(word("hello", Problem::NotFound)); +/// let parser = loc(word("hello", Problem::NotFound)); /// /// let (progress, output, state) = parser.parse(&arena, State::new("hello, world".as_bytes()), 0).unwrap(); /// assert_eq!(progress, Progress::MadeProgress); @@ -1354,25 +1353,22 @@ where /// # } /// # foo(&arena); /// ``` -#[macro_export] -macro_rules! loc { - ($parser:expr) => { - move |arena, state: $crate::state::State<'a>, min_indent: u32| { - use roc_region::all::{Loc, Region}; +pub fn loc<'a, Output, E: 'a>( + parser: impl Parser<'a, Output, E>, +) -> impl Parser<'a, Loc, E> { + move |arena, state: crate::state::State<'a>, min_indent: u32| { + let start = state.pos(); - let start = state.pos(); + match parser.parse(arena, state, min_indent) { + Ok((progress, value, state)) => { + let end = state.pos(); + let region = Region::new(start, end); - match $parser.parse(arena, state, min_indent) { - Ok((progress, value, state)) => { - let end = state.pos(); - let region = Region::new(start, end); - - Ok((progress, Loc { region, value }, state)) - } - Err(err) => Err(err), + Ok((progress, Loc { region, value }, state)) } + Err(err) => Err(err), } - }; + } } /// If the first one parses, ignore its output and move on to parse with the second one. @@ -2542,42 +2538,6 @@ pub fn between<'a, Before, Inner, After, Err: 'a>( skip_first(opening_brace, skip_second(inner, closing_brace)) } -/// Adds location info. This is a function version the [`loc!`] macro. -/// -/// 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. -/// -/// # Examples -/// ``` -/// # #![forbid(unused_imports)] -/// # use roc_parse::state::State; -/// # use crate::roc_parse::parser::{Parser, Progress, word, loc}; -/// # use roc_region::all::{Loc, Position}; -/// # use bumpalo::Bump; -/// # #[derive(Debug, PartialEq)] -/// # enum Problem { -/// # NotFound(Position), -/// # } -/// # let arena = Bump::new(); -/// # fn foo<'a>(arena: &'a Bump) { -/// let parser = loc(word("hello", Problem::NotFound)); -/// -/// let (progress, output, state) = parser.parse(&arena, State::new("hello, world".as_bytes()), 0).unwrap(); -/// assert_eq!(progress, Progress::MadeProgress); -/// assert_eq!(output, Loc::new(0, 5, ())); -/// assert_eq!(state.pos().offset, 5); -/// # } -/// # foo(&arena); -/// ``` -#[inline(always)] -pub fn loc<'a, P, Val, Error>(parser: P) -> impl Parser<'a, Loc, Error> -where - P: Parser<'a, Val, Error>, - Error: 'a, -{ - loc!(parser) -} - /// Maps/transforms the `Ok` result of parsing using the given function. /// Similar to [`map`], but the transform function also takes a bump allocator. /// diff --git a/crates/compiler/parse/src/pattern.rs b/crates/compiler/parse/src/pattern.rs index a256cb3cc7..ba9cf10b91 100644 --- a/crates/compiler/parse/src/pattern.rs +++ b/crates/compiler/parse/src/pattern.rs @@ -4,7 +4,7 @@ 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, map, optional, skip_first, specialize_err, + self, backtrackable, byte, fail_when, loc, map, optional, skip_first, specialize_err, specialize_err_ref, then, three_bytes, two_bytes, EPattern, PInParens, PList, PRecord, Parser, }; use crate::state::State; @@ -32,9 +32,9 @@ pub fn closure_param<'a>() -> impl Parser<'a, Loc>, EPattern<'a>> { // An ident is the most common param, e.g. \foo -> ... loc_ident_pattern_help(true), // Underscore is also common, e.g. \_ -> ... - loc!(underscore_pattern_help()), + loc(underscore_pattern_help()), // You can destructure records in params, e.g. \{ x, y } -> ... - loc!(specialize_err( + loc(specialize_err( EPattern::Record, crate::pattern::record_pattern_help() )), @@ -87,15 +87,15 @@ fn loc_pattern_help_help<'a>( ) -> impl Parser<'a, Loc>, EPattern<'a>> { one_of!( specialize_err(EPattern::PInParens, loc_pattern_in_parens_help()), - loc!(underscore_pattern_help()), + loc(underscore_pattern_help()), loc_ident_pattern_help(can_have_arguments), - loc!(specialize_err( + loc(specialize_err( EPattern::Record, crate::pattern::record_pattern_help() )), - loc!(specialize_err(EPattern::List, list_pattern_help())), - loc!(number_pattern_help()), - loc!(string_like_pattern_help()), + loc(specialize_err(EPattern::List, list_pattern_help())), + loc(number_pattern_help()), + loc(string_like_pattern_help()), ) } @@ -109,7 +109,7 @@ fn pattern_as<'a>() -> impl Parser<'a, PatternAs<'a>, EPattern<'a>> { let position = state.pos(); - match loc!(lowercase_ident()).parse(arena, state, min_indent) { + match loc(lowercase_ident()).parse(arena, state, min_indent) { Ok((_, identifier, state)) => Ok(( MadeProgress, PatternAs { @@ -199,7 +199,7 @@ pub fn loc_implements_parser<'a>() -> impl Parser<'a, Loc>, EPatt fn loc_pattern_in_parens_help<'a>() -> impl Parser<'a, Loc>, PInParens<'a>> { then( - loc!(collection_trailing_sep_e!( + loc(collection_trailing_sep_e!( byte(b'(', PInParens::Open), specialize_err_ref(PInParens::Pattern, loc_pattern_help()), byte(b',', PInParens::End), @@ -290,16 +290,13 @@ fn list_element_pattern<'a>() -> impl Parser<'a, Loc>, PList<'a>> { } fn three_list_rest_pattern_error<'a>() -> impl Parser<'a, Loc>, PList<'a>> { - fail_when( - PList::Rest, - loc!(three_bytes(b'.', b'.', b'.', PList::Rest)), - ) + fail_when(PList::Rest, loc(three_bytes(b'.', b'.', b'.', PList::Rest))) } fn list_rest_pattern<'a>() -> impl Parser<'a, Loc>, PList<'a>> { move |arena: &'a Bump, state: State<'a>, min_indent: u32| { let (_, loc_word, state) = - loc!(two_bytes(b'.', b'.', PList::Open)).parse(arena, state, min_indent)?; + loc(two_bytes(b'.', b'.', PList::Open)).parse(arena, state, min_indent)?; let no_as = Loc::at(loc_word.region, Pattern::ListRest(None)); @@ -334,9 +331,8 @@ fn loc_ident_pattern_help<'a>( move |arena: &'a Bump, state: State<'a>, min_indent: u32| { let original_state = state.clone(); - let (_, loc_ident, state) = - specialize_err(|_, pos| EPattern::Start(pos), loc!(parse_ident)) - .parse(arena, state, min_indent)?; + let (_, loc_ident, state) = specialize_err(|_, pos| EPattern::Start(pos), loc(parse_ident)) + .parse(arena, state, min_indent)?; match loc_ident.value { Ident::Tag(tag) => { @@ -539,9 +535,9 @@ fn record_pattern_field<'a>() -> impl Parser<'a, Loc>, PRecord<'a>> // You must have a field name, e.g. "email" // using the initial pos is important for error reporting let pos = state.pos(); - let (progress, loc_label, state) = loc!(specialize_err( + let (progress, loc_label, state) = loc(specialize_err( move |_, _| PRecord::Field(pos), - lowercase_ident() + lowercase_ident(), )) .parse(arena, state, min_indent)?; debug_assert_eq!(progress, MadeProgress); diff --git a/crates/compiler/parse/src/string_literal.rs b/crates/compiler/parse/src/string_literal.rs index a55b7078aa..97d4c2cd4e 100644 --- a/crates/compiler/parse/src/string_literal.rs +++ b/crates/compiler/parse/src/string_literal.rs @@ -73,7 +73,7 @@ pub enum StrLikeLiteral<'a> { pub fn parse_str_literal<'a>() -> impl Parser<'a, StrLiteral<'a>, EString<'a>> { then( - loc!(parse_str_like_literal()), + loc(parse_str_like_literal()), |_arena, state, progress, str_like| match str_like.value { StrLikeLiteral::SingleQuote(_) => Err(( progress, diff --git a/crates/compiler/parse/src/type_annotation.rs b/crates/compiler/parse/src/type_annotation.rs index 8e3ccd0842..eed7fd393d 100644 --- a/crates/compiler/parse/src/type_annotation.rs +++ b/crates/compiler/parse/src/type_annotation.rs @@ -9,7 +9,7 @@ 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, map, skip_first, skip_second, then, + absolute_column_min_indent, and, increment_min_indent, loc, map, skip_first, skip_second, then, ERecord, ETypeAbilityImpl, }; use crate::parser::{ @@ -41,7 +41,7 @@ fn tag_union_type<'a>( move |arena, state, min_indent| { let (_, tags, state) = collection_trailing_sep_e!( byte(b'[', ETypeTagUnion::Open), - loc!(tag_type(false)), + loc(tag_type(false)), byte(b',', ETypeTagUnion::End), byte(b']', ETypeTagUnion::End), Tag::SpaceBefore @@ -122,16 +122,16 @@ fn term<'a>(stop_at_surface_has: bool) -> impl Parser<'a, Loc loc_wildcard(), loc_inferred(), specialize_err(EType::TInParens, loc_type_in_parens(stop_at_surface_has)), - loc!(specialize_err( + loc(specialize_err( EType::TRecord, record_type(stop_at_surface_has) )), - loc!(specialize_err( + loc(specialize_err( EType::TTagUnion, tag_union_type(stop_at_surface_has) )), - loc!(applied_type(stop_at_surface_has)), - loc!(parse_type_variable(stop_at_surface_has)), + loc(applied_type(stop_at_surface_has)), + loc(parse_type_variable(stop_at_surface_has)), fail(EType::TStart), ), // Inline alias notation, e.g. [Nil, Cons a (List a)] as List a @@ -170,7 +170,7 @@ fn term<'a>(stop_at_surface_has: bool) -> impl Parser<'a, Loc /// The `*` type variable, e.g. in (List *) Wildcard, fn loc_wildcard<'a>() -> impl Parser<'a, Loc>, 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) }) } @@ -215,16 +215,16 @@ fn loc_applied_arg<'a>( loc_wildcard(), loc_inferred(), specialize_err(EType::TInParens, loc_type_in_parens(stop_at_surface_has)), - loc!(specialize_err( + loc(specialize_err( EType::TRecord, record_type(stop_at_surface_has) )), - loc!(specialize_err( + loc(specialize_err( EType::TTagUnion, tag_union_type(stop_at_surface_has) )), - loc!(specialize_err(EType::TApply, concrete_type())), - loc!(parse_type_variable(stop_at_surface_has)) + loc(specialize_err(EType::TApply, concrete_type())), + loc(parse_type_variable(stop_at_surface_has)) ) ), |arena: &'a Bump, (spaces, argument): (&'a [_], Loc>)| { @@ -242,7 +242,7 @@ fn loc_type_in_parens<'a>( stop_at_surface_has: bool, ) -> impl Parser<'a, Loc>, ETypeInParens<'a>> { then( - loc!(and( + loc(and( collection_trailing_sep_e!( byte(b'(', ETypeInParens::Open), specialize_err_ref(ETypeInParens::Type, expression(true, false)), @@ -252,8 +252,8 @@ fn loc_type_in_parens<'a>( ), optional(allocated(specialize_err_ref( ETypeInParens::Type, - term(stop_at_surface_has) - ))) + term(stop_at_surface_has), + ))), )), |_arena, state, progress, item| { let Loc { @@ -281,7 +281,7 @@ fn loc_type_in_parens<'a>( fn tag_type<'a>(stop_at_surface_has: bool) -> impl Parser<'a, Tag<'a>, ETypeTagUnion<'a>> { move |arena, state: State<'a>, min_indent: u32| { let (_, name, state) = - loc!(parse_tag_name(ETypeTagUnion::End)).parse(arena, state, min_indent)?; + loc(parse_tag_name(ETypeTagUnion::End)).parse(arena, state, min_indent)?; let (_, args, state) = specialize_err_ref(ETypeTagUnion::Type, loc_applied_args_e(stop_at_surface_has)) @@ -320,9 +320,9 @@ fn record_type_field<'a>() -> impl Parser<'a, AssignedField<'a, TypeAnnotation<' // You must have a field name, e.g. "email" // using the initial pos is important for error reporting let pos = state.pos(); - let (progress, loc_label, state) = loc!(specialize_err( + let (progress, loc_label, state) = loc(specialize_err( move |_, _| ETypeRecord::Field(pos), - lowercase_ident_keyword_e() + lowercase_ident_keyword_e(), )) .parse(arena, state, min_indent)?; debug_assert_eq!(progress, MadeProgress); @@ -384,7 +384,7 @@ fn record_type<'a>( record!(TypeAnnotation::Record { fields: collection_trailing_sep_e!( byte(b'{', ETypeRecord::Open), - loc!(record_type_field()), + loc(record_type_field()), byte(b',', ETypeRecord::End), byte(b'}', ETypeRecord::End), AssignedField::SpaceBefore @@ -434,14 +434,14 @@ fn ability_chain<'a>() -> impl Parser<'a, Vec<'a, Loc>>, ETyp map( and( space0_before_optional_after( - specialize_err(EType::TApply, loc!(concrete_type())), + specialize_err(EType::TApply, loc(concrete_type())), EType::TIndentStart, EType::TIndentEnd, ), zero_or_more!(skip_first( byte(b'&', EType::TImplementsClause), space0_before_optional_after( - specialize_err(EType::TApply, loc!(concrete_type())), + specialize_err(EType::TApply, loc(concrete_type())), EType::TIndentStart, EType::TIndentEnd, ) @@ -465,7 +465,7 @@ fn implements_clause<'a>() -> impl Parser<'a, Loc>, EType<' // 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, @@ -530,15 +530,15 @@ pub fn implements_abilities<'a>() -> impl Parser<'a, Loc 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()), + loc(parse_implements_ability()), byte(b',', EType::TEnd), byte(b']', EType::TEnd), ImplementsAbility::SpaceBefore ), - ImplementsAbilities::Implements + ImplementsAbilities::Implements, )), EType::TIndentEnd, ), @@ -547,14 +547,14 @@ pub fn implements_abilities<'a>() -> impl Parser<'a, Loc fn parse_implements_ability<'a>() -> impl Parser<'a, ImplementsAbility<'a>, EType<'a>> { 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( - loc!(map( + loc(map( specialize_err( EType::TAbilityImpl, collection_trailing_sep_e!( byte(b'{', ETypeAbilityImpl::Open), - specialize_err(|e: ERecord<'_>, _| e.into(), loc!(ability_impl_field())), + specialize_err(|e: ERecord<'_>, _| e.into(), loc(ability_impl_field())), byte(b',', ETypeAbilityImpl::End), byte(b'}', ETypeAbilityImpl::End), AssignedField::SpaceBefore From f6c977fb964b4d3635bb9b69c2dbd00071c53a1b Mon Sep 17 00:00:00 2001 From: Jackson Wambolt Date: Mon, 15 Apr 2024 20:29:02 -0500 Subject: [PATCH 09/18] Un-macro succeed This implementation requires that the type of the value impls `Clone`, which means the function version of `succeed` cannot be used to succeed with values of non-`Clone` types. If this becomes an issue, we could either bring back the macro version, or create a new `succeed_with` function that takes a `Fn() -> T` argument. `succeed_with` could then be used to succeed with values that aren't `Clone` by creating the value on-demand each time the parser is run. --- crates/compiler/parse/src/blankspace.rs | 5 +++-- crates/compiler/parse/src/parser.rs | 13 +++++-------- crates/compiler/parse/src/type_annotation.rs | 6 +++--- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/crates/compiler/parse/src/blankspace.rs b/crates/compiler/parse/src/blankspace.rs index 6aa2b6a7b3..25a0f38eeb 100644 --- a/crates/compiler/parse/src/blankspace.rs +++ b/crates/compiler/parse/src/blankspace.rs @@ -1,5 +1,6 @@ use crate::ast::CommentOrNewline; use crate::ast::Spaceable; +use crate::parser::succeed; use crate::parser::Progress; use crate::parser::SpaceProblem; use crate::parser::{self, and, backtrackable, BadInputError, Parser, Progress::*}; @@ -70,7 +71,7 @@ where parser, one_of![ backtrackable(space0_e(indent_after_problem)), - succeed!(&[] as &[_]), + succeed(&[] as &[_]), ], ), ), @@ -89,7 +90,7 @@ where spaces(), and( parser, - one_of![backtrackable(spaces()), succeed!(&[] as &[_]),], + one_of![backtrackable(spaces()), succeed(&[] as &[_]),], ), ), spaces_around_help, diff --git a/crates/compiler/parse/src/parser.rs b/crates/compiler/parse/src/parser.rs index ac59f924b9..cb91388b5c 100644 --- a/crates/compiler/parse/src/parser.rs +++ b/crates/compiler/parse/src/parser.rs @@ -1521,7 +1521,7 @@ macro_rules! collection_trailing_sep_e { /// # use bumpalo::Bump; /// # let arena = Bump::new(); /// # fn foo<'a>(arena: &'a Bump) { -/// let parser = succeed!("different"); +/// let parser = succeed("different"); /// /// let (progress, output, state) = Parser::<&'a str,()>::parse(&parser, &arena, State::new("hello, world".as_bytes()), 0).unwrap(); /// assert_eq!(progress, Progress::NoProgress); @@ -1530,13 +1530,10 @@ macro_rules! collection_trailing_sep_e { /// # } /// # foo(&arena); /// ``` -#[macro_export] -macro_rules! succeed { - ($value:expr) => { - move |_arena: &'a bumpalo::Bump, state: $crate::state::State<'a>, _min_indent: u32| { - Ok((NoProgress, $value, state)) - } - }; +pub fn succeed<'a, T: Clone, E: 'a>(value: T) -> impl Parser<'a, T, E> { + move |_arena: &'a bumpalo::Bump, state: crate::state::State<'a>, _min_indent: u32| { + Ok((NoProgress, value.clone(), state)) + } } /// Creates a parser that always fails. diff --git a/crates/compiler/parse/src/type_annotation.rs b/crates/compiler/parse/src/type_annotation.rs index eed7fd393d..10fb3ddb2e 100644 --- a/crates/compiler/parse/src/type_annotation.rs +++ b/crates/compiler/parse/src/type_annotation.rs @@ -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, loc, map, skip_first, skip_second, then, - ERecord, ETypeAbilityImpl, + absolute_column_min_indent, and, increment_min_indent, loc, map, skip_first, skip_second, + succeed, then, ERecord, ETypeAbilityImpl, }; use crate::parser::{ allocated, backtrackable, byte, fail, optional, specialize_err, specialize_err_ref, two_bytes, @@ -146,7 +146,7 @@ fn term<'a>(stop_at_surface_has: bool) -> impl Parser<'a, Loc ), Some ), - succeed!(None) + succeed(None) ] ), |arena: &'a Bump, From a9724dda5e3b1b088851f69f44dd291397148cdf Mon Sep 17 00:00:00 2001 From: Jackson Wambolt Date: Mon, 15 Apr 2024 20:35:08 -0500 Subject: [PATCH 10/18] Un-macro map_with_arena --- crates/compiler/parse/src/expr.rs | 84 ++++++++++---------- crates/compiler/parse/src/header.rs | 15 ++-- crates/compiler/parse/src/parser.rs | 74 +++-------------- crates/compiler/parse/src/pattern.rs | 9 ++- crates/compiler/parse/src/type_annotation.rs | 16 ++-- 5 files changed, 74 insertions(+), 124 deletions(-) diff --git a/crates/compiler/parse/src/expr.rs b/crates/compiler/parse/src/expr.rs index 838e0854be..3f06f977ad 100644 --- a/crates/compiler/parse/src/expr.rs +++ b/crates/compiler/parse/src/expr.rs @@ -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, loc, 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, + line_min_indent, loc, map, map_with_arena, 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; @@ -131,10 +131,10 @@ fn loc_expr_in_parens_help<'a>() -> impl Parser<'a, Loc>, EInParens<'a> } fn loc_expr_in_parens_etc_help<'a>() -> impl Parser<'a, Loc>, EExpr<'a>> { - map_with_arena!( + map_with_arena( loc(and( specialize_err(EExpr::InParens, loc_expr_in_parens_help()), - record_field_access_chain() + record_field_access_chain(), )), move |arena: &'a Bump, value: Loc<(Loc>, Vec<'a, Accessor<'a>>)>| { let Loc { @@ -153,7 +153,7 @@ fn loc_expr_in_parens_etc_help<'a>() -> impl Parser<'a, Loc>, EExpr<'a> } Loc::at(region, value) - } + }, ) } @@ -189,7 +189,7 @@ fn loc_term_or_underscore_or_conditional<'a>( loc(underscore_expression()), loc(record_literal_help()), loc(specialize_err(EExpr::List, list_literal_help())), - loc(map_with_arena!( + loc(map_with_arena( assign_or_destructure_identifier(), ident_to_expr )), @@ -212,7 +212,7 @@ fn loc_term_or_underscore<'a>( loc(underscore_expression()), loc(record_literal_help()), loc(specialize_err(EExpr::List, list_literal_help())), - loc(map_with_arena!( + loc(map_with_arena( assign_or_destructure_identifier(), ident_to_expr )), @@ -230,7 +230,7 @@ fn loc_term<'a>(options: ExprParseOptions) -> impl Parser<'a, Loc>, EEx loc(specialize_err(EExpr::Closure, closure_help(options))), loc(record_literal_help()), loc(specialize_err(EExpr::List, list_literal_help())), - loc(map_with_arena!( + loc(map_with_arena( assign_or_destructure_identifier(), ident_to_expr )), @@ -281,7 +281,7 @@ fn loc_possibly_negative_or_negated_term<'a>( }, // this will parse negative numbers, which the unary negate thing up top doesn't (for now) loc(specialize_err(EExpr::Number, number_literal_help())), - loc(map_with_arena!( + loc(map_with_arena( and( loc(byte(b'!', EExpr::Start)), space0_before_e(loc_term(options), EExpr::IndentStart) @@ -2359,7 +2359,7 @@ pub fn toplevel_defs<'a>() -> impl Parser<'a, Defs<'a>, EExpr<'a>> { fn closure_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EClosure<'a>> { // closure_help_help(options) - map_with_arena!( + map_with_arena( // After the first token, all other tokens must be indented past the start of the line indented_seq( // All closures start with a '\' - e.g. (\x -> x + 1) @@ -2384,16 +2384,16 @@ fn closure_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EClo // Parse the body space0_before_e( specialize_err_ref(EClosure::Body, expr_start(options)), - EClosure::IndentBody - ) - ) - ) + EClosure::IndentBody, + ), + ), + ), ), |arena: &'a Bump, (params, body)| { let params: Vec<'a, Loc>> = params; let params: &'a [Loc>] = params.into_bump_slice(); Expr::Closure(params, arena.alloc(body)) - } + }, ) } @@ -2403,7 +2403,7 @@ mod when { /// Parser for when expressions. pub fn expr_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EWhen<'a>> { - map_with_arena!( + map_with_arena( and( indented_seq( parser::keyword(keyword::WHEN, EWhen::When), @@ -2847,7 +2847,7 @@ fn ident_to_expr<'a>(arena: &'a Bump, src: Ident<'a>) -> Expr<'a> { } fn list_literal_help<'a>() -> impl Parser<'a, Expr<'a>, EList<'a>> { - map_with_arena!( + map_with_arena( collection_trailing_sep_e!( byte(b'[', EList::Open), specialize_err_ref(EList::Expr, loc_expr(false)), @@ -2858,7 +2858,7 @@ fn list_literal_help<'a>() -> impl Parser<'a, Expr<'a>, EList<'a>> { |arena, elements: Collection<'a, _>| { let elements = elements.ptrify_items(arena); Expr::List(elements) - } + }, ) .trace("list_literal") } @@ -2978,7 +2978,7 @@ impl<'a> Spaceable<'a> for RecordField<'a> { pub fn record_field<'a>() -> impl Parser<'a, RecordField<'a>, ERecord<'a>> { use RecordField::*; - map_with_arena!( + map_with_arena( and( specialize_err(|_, pos| ERecord::Field(pos), loc(lowercase_ident())), and( @@ -2989,8 +2989,8 @@ pub fn record_field<'a>() -> impl Parser<'a, RecordField<'a>, ERecord<'a>> { byte(b'?', ERecord::QuestionMark), spaces_before(specialize_err_ref(ERecord::Expr, loc_expr(false))) ) - )) - ) + )), + ), ), |arena: &'a bumpalo::Bump, (loc_label, (spaces, opt_loc_val))| { match opt_loc_val { @@ -3016,7 +3016,7 @@ pub fn record_field<'a>() -> impl Parser<'a, RecordField<'a>, ERecord<'a>> { } } } - } + }, ) } @@ -3026,7 +3026,7 @@ enum RecordFieldExpr<'a> { } fn record_field_expr<'a>() -> impl Parser<'a, RecordFieldExpr<'a>, ERecord<'a>> { - map_with_arena!( + map_with_arena( and( spaces(), either!( @@ -3035,29 +3035,27 @@ fn record_field_expr<'a>() -> impl Parser<'a, RecordFieldExpr<'a>, ERecord<'a>> spaces_before(specialize_err_ref(ERecord::Expr, loc_expr(false))) ), specialize_err_ref(ERecord::Expr, loc_expr(false)) - ) + ), ), - |arena: &'a bumpalo::Bump, (spaces, either)| { - match either { - Either::First((_, loc_expr)) => RecordFieldExpr::Apply(spaces, loc_expr), - Either::Second(loc_expr) => RecordFieldExpr::Value({ - if spaces.is_empty() { - loc_expr - } else { - arena - .alloc(loc_expr.value) - .with_spaces_before(spaces, loc_expr.region) - } - }), - } - } + |arena: &'a bumpalo::Bump, (spaces, either)| match either { + Either::First((_, loc_expr)) => RecordFieldExpr::Apply(spaces, loc_expr), + Either::Second(loc_expr) => RecordFieldExpr::Value({ + if spaces.is_empty() { + loc_expr + } else { + arena + .alloc(loc_expr.value) + .with_spaces_before(spaces, loc_expr.region) + } + }), + }, ) } fn record_updateable_identifier<'a>() -> impl Parser<'a, Expr<'a>, ERecord<'a>> { specialize_err( |_, pos| ERecord::Updateable(pos), - map_with_arena!(parse_ident, ident_to_expr), + map_with_arena(parse_ident, ident_to_expr), ) } @@ -3184,7 +3182,7 @@ fn apply_expr_access_chain<'a>( } fn string_like_literal_help<'a>() -> impl Parser<'a, Expr<'a>, EString<'a>> { - map_with_arena!( + map_with_arena( crate::string_literal::parse_str_like_literal(), |arena, lit| match lit { StrLikeLiteral::Str(s) => Expr::Str(s), @@ -3192,7 +3190,7 @@ fn string_like_literal_help<'a>() -> impl Parser<'a, Expr<'a>, EString<'a>> { // TODO: preserve the original escaping Expr::SingleQuote(s.to_str_in(arena)) } - } + }, ) } diff --git a/crates/compiler/parse/src/header.rs b/crates/compiler/parse/src/header.rs index f0074c999d..5045e471e8 100644 --- a/crates/compiler/parse/src/header.rs +++ b/crates/compiler/parse/src/header.rs @@ -5,7 +5,8 @@ use crate::blankspace::space0_e; use crate::expr::merge_spaces; use crate::ident::{lowercase_ident, UppercaseIdent}; use crate::parser::{ - and, byte, loc, skip_second, specialize_err, EPackageEntry, EPackageName, Parser, + and, byte, loc, map_with_arena, skip_second, specialize_err, EPackageEntry, EPackageName, + Parser, }; use crate::parser::{optional, then}; use crate::string_literal; @@ -339,7 +340,7 @@ pub struct PackageEntry<'a> { } pub fn package_entry<'a>() -> impl Parser<'a, Spaced<'a, PackageEntry<'a>>, EPackageEntry<'a>> { - map_with_arena!( + map_with_arena( // You may optionally have a package shorthand, // e.g. "uc" in `uc: roc/unicode 1.0.0` // @@ -349,13 +350,13 @@ pub fn package_entry<'a>() -> impl Parser<'a, Spaced<'a, PackageEntry<'a>>, EPac skip_second( and( specialize_err(|_, pos| EPackageEntry::Shorthand(pos), lowercase_ident()), - space0_e(EPackageEntry::IndentPackage) + space0_e(EPackageEntry::IndentPackage), ), - byte(b':', EPackageEntry::Colon) + byte(b':', EPackageEntry::Colon), ), - space0_e(EPackageEntry::IndentPackage) + space0_e(EPackageEntry::IndentPackage), )), - loc(specialize_err(EPackageEntry::BadPackage, package_name())) + loc(specialize_err(EPackageEntry::BadPackage, package_name())), ), move |arena, (opt_shorthand, package_or_path)| { let entry = match opt_shorthand { @@ -376,7 +377,7 @@ pub fn package_entry<'a>() -> impl Parser<'a, Spaced<'a, PackageEntry<'a>>, EPac }; Spaced::Item(entry) - } + }, ) } diff --git a/crates/compiler/parse/src/parser.rs b/crates/compiler/parse/src/parser.rs index cb91388b5c..4d8c2bbdc9 100644 --- a/crates/compiler/parse/src/parser.rs +++ b/crates/compiler/parse/src/parser.rs @@ -1457,24 +1457,24 @@ where #[macro_export] macro_rules! collection_inner { ($elem:expr, $delimiter:expr, $space_before:expr) => { - map_with_arena!( + $crate::parser::map_with_arena( $crate::parser::and( $crate::parser::and( $crate::blankspace::spaces(), $crate::parser::trailing_sep_by0( $delimiter, - $crate::blankspace::spaces_before_optional_after($elem,) - ) + $crate::blankspace::spaces_before_optional_after($elem), + ), ), - $crate::blankspace::spaces() + $crate::blankspace::spaces(), ), |arena: &'a bumpalo::Bump, ((spaces, mut parsed_elems), mut final_comments): ( ( &'a [$crate::ast::CommentOrNewline<'a>], - bumpalo::collections::vec::Vec<'a, Loc<_>> + bumpalo::collections::vec::Vec<'a, Loc<_>>, ), - &'a [$crate::ast::CommentOrNewline<'a>] + &'a [$crate::ast::CommentOrNewline<'a>], )| { if !spaces.is_empty() { if let Some(first) = parsed_elems.first_mut() { @@ -1490,7 +1490,7 @@ macro_rules! collection_inner { parsed_elems.into_bump_slice(), final_comments, ) - } + }, ) }; } @@ -2214,53 +2214,6 @@ pub fn map<'a, Output, MappedOutput, E: 'a>( } } -/// Maps/transforms the `Ok` result of parsing using the given function. -/// Similar to [`map`], but the transform function also takes a bump allocator. -/// -/// # Example -/// -/// ``` -/// # #![forbid(unused_imports)] -/// # use roc_parse::state::State; -/// # use crate::roc_parse::parser::{Parser, Progress, word}; -/// # use roc_region::all::Position; -/// # use roc_parse::map_with_arena; -/// # use bumpalo::Bump; -/// # #[derive(Debug, PartialEq)] -/// # enum Problem { -/// # NotFound(Position), -/// # } -/// # let arena = Bump::new(); -/// let parser = map_with_arena!( -/// word("hello", Problem::NotFound), -/// |_arena, _output| "new output!" -/// ); -/// -/// // Success case -/// let (progress, output, state) = parser.parse(&arena, State::new("hello, world".as_bytes()), 0).unwrap(); -/// assert_eq!(progress, Progress::MadeProgress); -/// assert_eq!(output, "new output!"); -/// assert_eq!(state.pos(), Position::new(5)); -/// -/// // Error case -/// let (progress, err) = parser.parse(&arena, State::new("bye, world".as_bytes()), 0).unwrap_err(); -/// assert_eq!(progress, Progress::NoProgress); -/// assert_eq!(err, Problem::NotFound(Position::zero())); -/// ``` -#[macro_export] -macro_rules! map_with_arena { - ($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(arena, output), next_state) - }) - } - }; -} - /// Applies the parser as many times as possible. /// This parser will only fail if the given parser makes partial progress. #[macro_export] @@ -2538,9 +2491,6 @@ pub fn between<'a, Before, Inner, After, Err: 'a>( /// Maps/transforms the `Ok` result of parsing using the given function. /// 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. -/// /// # Example /// /// ``` @@ -2577,14 +2527,14 @@ pub fn map_with_arena<'a, P, F, Before, After, E>( ) -> impl Parser<'a, After, E> where P: Parser<'a, Before, E>, - P: 'a, F: Fn(&'a Bump, Before) -> After, - F: 'a, - Before: 'a, - After: 'a, E: 'a, { - map_with_arena!(parser, transform) + move |arena, state, min_indent| { + parser + .parse(arena, state, min_indent) + .map(|(progress, output, next_state)| (progress, transform(arena, output), next_state)) + } } /// Creates a new parser that does not progress but still forwards the output of diff --git a/crates/compiler/parse/src/pattern.rs b/crates/compiler/parse/src/pattern.rs index ba9cf10b91..d9cd18c767 100644 --- a/crates/compiler/parse/src/pattern.rs +++ b/crates/compiler/parse/src/pattern.rs @@ -4,8 +4,9 @@ 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, loc, map, optional, skip_first, specialize_err, - specialize_err_ref, then, three_bytes, two_bytes, EPattern, PInParens, PList, PRecord, Parser, + self, backtrackable, byte, fail_when, loc, map, map_with_arena, 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; @@ -255,7 +256,7 @@ fn number_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, EPattern<'a>> { fn string_like_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, EPattern<'a>> { specialize_err( |_, pos| EPattern::Start(pos), - map_with_arena!( + map_with_arena( crate::string_literal::parse_str_like_literal(), |arena, lit| match lit { StrLikeLiteral::Str(s) => Pattern::StrLiteral(s), @@ -263,7 +264,7 @@ fn string_like_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, EPattern<'a>> // TODO: preserve the original escaping Pattern::SingleQuote(s.to_str_in(arena)) } - } + }, ), ) } diff --git a/crates/compiler/parse/src/type_annotation.rs b/crates/compiler/parse/src/type_annotation.rs index 10fb3ddb2e..1a78d4fbc3 100644 --- a/crates/compiler/parse/src/type_annotation.rs +++ b/crates/compiler/parse/src/type_annotation.rs @@ -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, loc, map, skip_first, skip_second, - succeed, then, ERecord, ETypeAbilityImpl, + absolute_column_min_indent, and, increment_min_indent, loc, map, map_with_arena, skip_first, + skip_second, succeed, then, ERecord, ETypeAbilityImpl, }; use crate::parser::{ allocated, backtrackable, byte, fail, optional, specialize_err, specialize_err_ref, two_bytes, @@ -116,7 +116,7 @@ fn parse_type_alias_after_as<'a>() -> impl Parser<'a, TypeHeader<'a>, EType<'a>> } fn term<'a>(stop_at_surface_has: bool) -> impl Parser<'a, Loc>, EType<'a>> { - map_with_arena!( + map_with_arena( and( one_of!( loc_wildcard(), @@ -147,7 +147,7 @@ fn term<'a>(stop_at_surface_has: bool) -> impl Parser<'a, Loc Some ), succeed(None) - ] + ], ), |arena: &'a Bump, (loc_ann, opt_as): (Loc>, Option<(&'a [_], TypeHeader<'a>)>)| { @@ -163,7 +163,7 @@ fn term<'a>(stop_at_surface_has: bool) -> impl Parser<'a, Loc None => loc_ann, } - } + }, ) .trace("type_annotation:term") } @@ -208,7 +208,7 @@ fn loc_inferred<'a>() -> impl Parser<'a, Loc>, EType<'a>> { fn loc_applied_arg<'a>( stop_at_surface_has: bool, ) -> impl Parser<'a, Loc>, EType<'a>> { - map_with_arena!( + map_with_arena( and( backtrackable(space0_e(EType::TIndentStart)), one_of!( @@ -225,7 +225,7 @@ fn loc_applied_arg<'a>( )), loc(specialize_err(EType::TApply, concrete_type())), loc(parse_type_variable(stop_at_surface_has)) - ) + ), ), |arena: &'a Bump, (spaces, argument): (&'a [_], Loc>)| { if spaces.is_empty() { @@ -234,7 +234,7 @@ fn loc_applied_arg<'a>( let Loc { region, value } = argument; arena.alloc(value).with_spaces_before(spaces, region) } - } + }, ) } From f88e46fc32f7abac624a7e523be935ee35d4bd48 Mon Sep 17 00:00:00 2001 From: Jackson Wambolt Date: Mon, 15 Apr 2024 20:39:29 -0500 Subject: [PATCH 11/18] Un-macro zero_or_more --- crates/compiler/parse/src/expr.rs | 10 +-- crates/compiler/parse/src/module.rs | 10 +-- crates/compiler/parse/src/parser.rs | 92 ++++++++++---------- crates/compiler/parse/src/pattern.rs | 10 +-- crates/compiler/parse/src/type_annotation.rs | 18 ++-- 5 files changed, 70 insertions(+), 70 deletions(-) diff --git a/crates/compiler/parse/src/expr.rs b/crates/compiler/parse/src/expr.rs index 3f06f977ad..117cb22c9e 100644 --- a/crates/compiler/parse/src/expr.rs +++ b/crates/compiler/parse/src/expr.rs @@ -13,8 +13,8 @@ use crate::parser::{ self, and, backtrackable, between, byte, byte_indent, increment_min_indent, indented_seq, line_min_indent, loc, map, map_with_arena, 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, + zero_or_more, 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; @@ -158,15 +158,15 @@ fn loc_expr_in_parens_etc_help<'a>() -> impl Parser<'a, Loc>, EExpr<'a> } fn record_field_access_chain<'a>() -> impl Parser<'a, Vec<'a, Accessor<'a>>, EExpr<'a>> { - zero_or_more!(skip_first( + zero_or_more(skip_first( byte(b'.', EExpr::Access), specialize_err( |_, pos| EExpr::Access(pos), one_of!( map(lowercase_ident(), Accessor::RecordField), map(integer_ident(), Accessor::TupleIndex), - ) - ) + ), + ), )) } diff --git a/crates/compiler/parse/src/module.rs b/crates/compiler/parse/src/module.rs index c5b5e6f8fb..88c5f2470b 100644 --- a/crates/compiler/parse/src/module.rs +++ b/crates/compiler/parse/src/module.rs @@ -10,9 +10,9 @@ use crate::ident::{self, lowercase_ident, unqualified_ident, uppercase, Uppercas use crate::parser::Progress::{self, *}; use crate::parser::{ and, backtrackable, byte, increment_min_indent, loc, 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, + skip_first, skip_second, specialize_err, two_bytes, zero_or_more, EExposes, EGenerates, + EGeneratesWith, EHeader, EImports, EPackages, EProvides, ERequires, ETypedIdent, Parser, + SourceError, SpaceProblem, SyntaxError, }; use crate::state::State; use crate::string_literal::{self, parse_str_literal}; @@ -284,12 +284,12 @@ fn provides_types<'a>( // to be the design forever. Someday it will hopefully work like Elm, // where platform authors can provide functions like Browser.sandbox which // present an API based on ordinary-looking type variables. - zero_or_more!(byte( + zero_or_more(byte( b' ', // HACK: If this errors, EProvides::Provides is not an accurate reflection // of what went wrong. However, this is both skipped and zero_or_more, // so this error should never be visible to anyone in practice! - EProvides::Provides + EProvides::Provides, )), collection_trailing_sep_e!( byte(b'{', EProvides::ListStart), diff --git a/crates/compiler/parse/src/parser.rs b/crates/compiler/parse/src/parser.rs index 4d8c2bbdc9..a6b5889103 100644 --- a/crates/compiler/parse/src/parser.rs +++ b/crates/compiler/parse/src/parser.rs @@ -2216,63 +2216,63 @@ pub fn map<'a, Output, MappedOutput, E: 'a>( /// Applies the parser as many times as possible. /// This parser will only fail if the given parser makes partial progress. -#[macro_export] -macro_rules! zero_or_more { - ($parser:expr) => { - move |arena, state: State<'a>, min_indent: u32| { - use bumpalo::collections::Vec; +pub fn zero_or_more<'a, Output, E: 'a>( + parser: impl Parser<'a, Output, E>, +) -> impl Parser<'a, bumpalo::collections::Vec<'a, Output>, E> { + move |arena, state: State<'a>, min_indent: u32| { + let original_state = state.clone(); - let original_state = state.clone(); + let start_bytes_len = state.bytes().len(); - let start_bytes_len = state.bytes().len(); + match parser.parse(arena, state, min_indent) { + Ok((_, first_output, next_state)) => { + let mut state = next_state; + let mut buf = Vec::with_capacity_in(1, arena); - match $parser.parse(arena, state, min_indent) { - Ok((_, first_output, next_state)) => { - let mut state = next_state; - let mut buf = Vec::with_capacity_in(1, arena); + buf.push(first_output); - buf.push(first_output); - - loop { - let old_state = state.clone(); - match $parser.parse(arena, state, min_indent) { - Ok((_, next_output, next_state)) => { - state = next_state; - buf.push(next_output); - } - Err((fail_progress, fail)) => { - match fail_progress { - MadeProgress => { - // made progress on an element and then failed; that's an error - return Err((MadeProgress, fail)); - } - NoProgress => { - // the next element failed with no progress - // report whether we made progress before - let progress = Progress::from_lengths(start_bytes_len, old_state.bytes().len()); - return Ok((progress, buf, old_state)); - } + loop { + let old_state = state.clone(); + match parser.parse(arena, state, min_indent) { + Ok((_, next_output, next_state)) => { + state = next_state; + buf.push(next_output); + } + Err((fail_progress, fail)) => { + match fail_progress { + MadeProgress => { + // made progress on an element and then failed; that's an error + return Err((MadeProgress, fail)); + } + NoProgress => { + // the next element failed with no progress + // report whether we made progress before + let progress = Progress::from_lengths( + start_bytes_len, + old_state.bytes().len(), + ); + return Ok((progress, buf, old_state)); } } } } } - Err((fail_progress, fail)) => { - match fail_progress { - MadeProgress => { - // made progress on an element and then failed; that's an error - Err((MadeProgress, fail)) - } - NoProgress => { - // the first element failed (with no progress), but that's OK - // because we only need to parse 0 elements - Ok((NoProgress, Vec::new_in(arena), original_state)) - } + } + Err((fail_progress, fail)) => { + match fail_progress { + MadeProgress => { + // made progress on an element and then failed; that's an error + Err((MadeProgress, fail)) + } + NoProgress => { + // the first element failed (with no progress), but that's OK + // because we only need to parse 0 elements + Ok((NoProgress, Vec::new_in(arena), original_state)) } } } } - }; + } } /// Creates a parser that matches one or more times. @@ -2285,7 +2285,7 @@ macro_rules! zero_or_more { /// # use roc_parse::state::State; /// # use crate::roc_parse::parser::{Parser, Progress, Progress::{MadeProgress, NoProgress}, word}; /// # use roc_region::all::Position; -/// # use roc_parse::one_or_more; +/// # use roc_parse::one_or_more!; /// # use bumpalo::Bump; /// # #[derive(Debug, PartialEq)] /// # enum Problem { @@ -2293,7 +2293,7 @@ macro_rules! zero_or_more { /// # } /// # let arena = Bump::new(); /// # fn foo<'a>(arena: &'a Bump) { -/// let parser = one_or_more!( +/// let parser = one_or_more( /// word("hello, ", Problem::NotFound), /// Problem::NotFound /// ); diff --git a/crates/compiler/parse/src/pattern.rs b/crates/compiler/parse/src/pattern.rs index d9cd18c767..02ea356e17 100644 --- a/crates/compiler/parse/src/pattern.rs +++ b/crates/compiler/parse/src/pattern.rs @@ -2,11 +2,11 @@ use crate::ast::{Implements, Pattern, PatternAs, Spaceable}; use crate::blankspace::{space0_e, spaces, spaces_before}; use crate::ident::{lowercase_ident, parse_ident, Accessor, Ident}; use crate::keyword; -use crate::parser::Progress::{self, *}; +use crate::parser::Progress::*; use crate::parser::{ self, backtrackable, byte, fail_when, loc, map, map_with_arena, optional, skip_first, - specialize_err, specialize_err_ref, then, three_bytes, two_bytes, EPattern, PInParens, PList, - PRecord, Parser, + specialize_err, specialize_err_ref, then, three_bytes, two_bytes, zero_or_more, EPattern, + PInParens, PList, PRecord, Parser, }; use crate::state::State; use crate::string_literal::StrLikeLiteral; @@ -125,13 +125,13 @@ fn pattern_as<'a>() -> impl Parser<'a, PatternAs<'a>, EPattern<'a>> { } fn loc_tag_pattern_args_help<'a>() -> impl Parser<'a, Vec<'a, Loc>>, EPattern<'a>> { - zero_or_more!(loc_tag_pattern_arg(false)) + zero_or_more(loc_tag_pattern_arg(false)) } /// Like `loc_tag_pattern_args_help`, but stops if a "implements" keyword is seen (indicating an ability). fn loc_type_def_tag_pattern_args_help<'a>( ) -> impl Parser<'a, Vec<'a, Loc>>, EPattern<'a>> { - zero_or_more!(loc_tag_pattern_arg(true)) + zero_or_more(loc_tag_pattern_arg(true)) } fn loc_tag_pattern_arg<'a>( diff --git a/crates/compiler/parse/src/type_annotation.rs b/crates/compiler/parse/src/type_annotation.rs index 1a78d4fbc3..f05e09d215 100644 --- a/crates/compiler/parse/src/type_annotation.rs +++ b/crates/compiler/parse/src/type_annotation.rs @@ -10,12 +10,12 @@ use crate::ident::{lowercase_ident, lowercase_ident_keyword_e}; use crate::keyword; use crate::parser::{ absolute_column_min_indent, and, increment_min_indent, loc, map, map_with_arena, skip_first, - skip_second, succeed, then, ERecord, ETypeAbilityImpl, + skip_second, succeed, then, zero_or_more, ERecord, ETypeAbilityImpl, }; use crate::parser::{ allocated, backtrackable, byte, fail, optional, specialize_err, specialize_err_ref, two_bytes, word, EType, ETypeApply, ETypeInParens, ETypeInlineAlias, ETypeRecord, ETypeTagUnion, Parser, - Progress::{self, *}, + Progress::*, }; use crate::state::State; use bumpalo::collections::vec::Vec; @@ -426,7 +426,7 @@ fn applied_type<'a>(stop_at_surface_has: bool) -> impl Parser<'a, TypeAnnotation fn loc_applied_args_e<'a>( stop_at_surface_has: bool, ) -> impl Parser<'a, Vec<'a, Loc>>, EType<'a>> { - zero_or_more!(loc_applied_arg(stop_at_surface_has)) + zero_or_more(loc_applied_arg(stop_at_surface_has)) } // Hash & Eq & ... @@ -438,13 +438,13 @@ fn ability_chain<'a>() -> impl Parser<'a, Vec<'a, Loc>>, ETyp EType::TIndentStart, EType::TIndentEnd, ), - zero_or_more!(skip_first( + zero_or_more(skip_first( byte(b'&', EType::TImplementsClause), space0_before_optional_after( specialize_err(EType::TApply, loc(concrete_type())), EType::TIndentStart, EType::TIndentEnd, - ) + ), )), ), |(first_ability, mut other_abilities): ( @@ -506,9 +506,9 @@ fn implements_clause_chain<'a>( // Parse the first clause (there must be one), then the rest let (_, first_clause, state) = implements_clause().parse(arena, state, min_indent)?; - let (_, mut clauses, state) = zero_or_more!(skip_first( + let (_, mut clauses, state) = zero_or_more(skip_first( byte(b',', EType::TImplementsClause), - implements_clause() + implements_clause(), )) .parse(arena, state, min_indent)?; @@ -585,7 +585,7 @@ fn expression<'a>( .parse(arena, state, min_indent)?; let result = and( - zero_or_more!(skip_first( + zero_or_more(skip_first( byte(b',', EType::TFunctionArgument), one_of![ space0_around_ee( @@ -594,7 +594,7 @@ fn expression<'a>( EType::TIndentEnd ), fail(EType::TFunctionArgument) - ] + ], )) .trace("type_annotation:expression:rest_args"), skip_second( From 2f776f366f3a2d0920c42d9453c66c331e30be0d Mon Sep 17 00:00:00 2001 From: Jackson Wambolt Date: Mon, 15 Apr 2024 20:43:12 -0500 Subject: [PATCH 12/18] Un-macro one_or_more --- crates/compiler/parse/src/parser.rs | 54 ++++++++++++++--------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/crates/compiler/parse/src/parser.rs b/crates/compiler/parse/src/parser.rs index a6b5889103..899fa8f8b9 100644 --- a/crates/compiler/parse/src/parser.rs +++ b/crates/compiler/parse/src/parser.rs @@ -2311,39 +2311,39 @@ pub fn zero_or_more<'a, Output, E: 'a>( /// # } /// # foo(&arena); /// ``` -#[macro_export] -macro_rules! one_or_more { - ($parser:expr, $to_error:expr) => { - move |arena, state: State<'a>, min_indent: u32| { - use bumpalo::collections::Vec; +pub fn one_or_more<'a, Output, E: 'a>( + parser: impl Parser<'a, Output, E>, + to_error: impl Fn(Position) -> E, +) -> impl Parser<'a, bumpalo::collections::Vec<'a, Output>, E> { + move |arena, state: State<'a>, min_indent: u32| match parser.parse( + arena, + state.clone(), + min_indent, + ) { + Ok((_, first_output, next_state)) => { + let mut state = next_state; + let mut buf = Vec::with_capacity_in(1, arena); - match $parser.parse(arena, state.clone(), min_indent) { - Ok((_, first_output, next_state)) => { - let mut state = next_state; - let mut buf = Vec::with_capacity_in(1, arena); + buf.push(first_output); - buf.push(first_output); - - loop { - let old_state = state.clone(); - match $parser.parse(arena, state, min_indent) { - Ok((_, next_output, next_state)) => { - state = next_state; - buf.push(next_output); - } - Err((NoProgress, _)) => { - return Ok((MadeProgress, buf, old_state)); - } - Err((MadeProgress, fail)) => { - return Err((MadeProgress, fail)); - } - } + loop { + let old_state = state.clone(); + match parser.parse(arena, state, min_indent) { + Ok((_, next_output, next_state)) => { + state = next_state; + buf.push(next_output); + } + Err((NoProgress, _)) => { + return Ok((MadeProgress, buf, old_state)); + } + Err((MadeProgress, fail)) => { + return Err((MadeProgress, fail)); } } - Err((progress, _)) => Err((progress, $to_error(state.pos()))), } } - }; + Err((progress, _)) => Err((progress, to_error(state.pos()))), + } } /// Creates a parser that debug prints the result of parsing. From 02c98f751972d58fed8c175cedadfd6a5974810a Mon Sep 17 00:00:00 2001 From: Jackson Wambolt Date: Mon, 15 Apr 2024 21:09:39 -0500 Subject: [PATCH 13/18] Un-macro either --- crates/compiler/parse/src/expr.rs | 24 ++++++------- crates/compiler/parse/src/parser.rs | 38 ++++++++++---------- crates/compiler/parse/src/pattern.rs | 6 ++-- crates/compiler/parse/src/type_annotation.rs | 8 ++--- 4 files changed, 37 insertions(+), 39 deletions(-) diff --git a/crates/compiler/parse/src/expr.rs b/crates/compiler/parse/src/expr.rs index 117cb22c9e..fad0aa6a4d 100644 --- a/crates/compiler/parse/src/expr.rs +++ b/crates/compiler/parse/src/expr.rs @@ -10,11 +10,11 @@ use crate::blankspace::{ 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, loc, map, map_with_arena, optional, reset_min_indent, sep_by1, sep_by1_e, - set_min_indent, skip_first, skip_second, specialize_err, specialize_err_ref, then, two_bytes, - zero_or_more, EClosure, EExpect, EExpr, EIf, EInParens, EList, ENumber, EPattern, ERecord, - EString, EType, EWhen, Either, ParseResult, Parser, + self, and, backtrackable, between, byte, byte_indent, either, increment_min_indent, + indented_seq, line_min_indent, loc, map, map_with_arena, optional, reset_min_indent, sep_by1, + sep_by1_e, set_min_indent, skip_first, skip_second, specialize_err, specialize_err_ref, then, + two_bytes, zero_or_more, 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; @@ -622,7 +622,7 @@ pub fn parse_single_def<'a>( let parse_expect_vanilla = crate::parser::keyword(crate::keyword::EXPECT, EExpect::Expect); let parse_expect_fx = crate::parser::keyword(crate::keyword::EXPECT_FX, EExpect::Expect); - let parse_expect = either!(parse_expect_fx, parse_expect_vanilla); + let parse_expect = either(parse_expect_fx, parse_expect_vanilla); match space0_after_e(crate::pattern::loc_pattern_help(), EPattern::IndentEnd).parse( arena, @@ -2983,12 +2983,12 @@ pub fn record_field<'a>() -> impl Parser<'a, RecordField<'a>, ERecord<'a>> { specialize_err(|_, pos| ERecord::Field(pos), loc(lowercase_ident())), and( spaces(), - optional(either!( + optional(either( and(byte(b':', ERecord::Colon), record_field_expr()), and( byte(b'?', ERecord::QuestionMark), - spaces_before(specialize_err_ref(ERecord::Expr, loc_expr(false))) - ) + spaces_before(specialize_err_ref(ERecord::Expr, loc_expr(false))), + ), )), ), ), @@ -3029,12 +3029,12 @@ fn record_field_expr<'a>() -> impl Parser<'a, RecordFieldExpr<'a>, ERecord<'a>> map_with_arena( and( spaces(), - either!( + either( and( two_bytes(b'<', b'-', ERecord::Arrow), - spaces_before(specialize_err_ref(ERecord::Expr, loc_expr(false))) + spaces_before(specialize_err_ref(ERecord::Expr, loc_expr(false))), ), - specialize_err_ref(ERecord::Expr, loc_expr(false)) + specialize_err_ref(ERecord::Expr, loc_expr(false)), ), ), |arena: &'a bumpalo::Bump, (spaces, either)| match either { diff --git a/crates/compiler/parse/src/parser.rs b/crates/compiler/parse/src/parser.rs index 899fa8f8b9..ee7b0d32e8 100644 --- a/crates/compiler/parse/src/parser.rs +++ b/crates/compiler/parse/src/parser.rs @@ -2403,7 +2403,7 @@ macro_rules! debug { /// # } /// # let arena = Bump::new(); /// # fn foo<'a>(arena: &'a Bump) { -/// let parser = either!( +/// let parser = either( /// word("hello", Problem::NotFound), /// word("bye", Problem::NotFound) /// ); @@ -2426,27 +2426,25 @@ macro_rules! debug { /// # } /// # foo(&arena); /// ``` -#[macro_export] -macro_rules! either { - ($p1:expr, $p2:expr) => { - move |arena: &'a bumpalo::Bump, state: $crate::state::State<'a>, min_indent: u32| { - let original_state = state.clone(); - match $p1.parse(arena, state, min_indent) { - Ok((progress, output, state)) => { - Ok((progress, $crate::parser::Either::First(output), state)) - } - Err((NoProgress, _)) => { - match $p2.parse(arena, original_state.clone(), min_indent) { - Ok((progress, output, state)) => { - Ok((progress, $crate::parser::Either::Second(output), state)) - } - Err((progress, fail)) => Err((progress, fail)), - } - } - Err((MadeProgress, fail)) => Err((MadeProgress, fail)), +pub fn either<'a, OutputLeft, OutputRight, E: 'a>( + p1: impl Parser<'a, OutputLeft, E>, + p2: impl Parser<'a, OutputRight, E>, +) -> impl Parser<'a, Either, E> { + move |arena: &'a bumpalo::Bump, state: crate::state::State<'a>, min_indent: u32| { + let original_state = state.clone(); + match p1.parse(arena, state, min_indent) { + Ok((progress, output, state)) => { + Ok((progress, crate::parser::Either::First(output), state)) } + Err((NoProgress, _)) => match p2.parse(arena, original_state.clone(), min_indent) { + Ok((progress, output, state)) => { + Ok((progress, crate::parser::Either::Second(output), state)) + } + Err((progress, fail)) => Err((progress, fail)), + }, + Err((MadeProgress, fail)) => Err((MadeProgress, fail)), } - }; + } } /// Given three parsers, parse them all but ignore the output of the first and last one. diff --git a/crates/compiler/parse/src/pattern.rs b/crates/compiler/parse/src/pattern.rs index 02ea356e17..aa5a286229 100644 --- a/crates/compiler/parse/src/pattern.rs +++ b/crates/compiler/parse/src/pattern.rs @@ -2,12 +2,12 @@ use crate::ast::{Implements, Pattern, PatternAs, Spaceable}; use crate::blankspace::{space0_e, spaces, spaces_before}; use crate::ident::{lowercase_ident, parse_ident, Accessor, Ident}; use crate::keyword; -use crate::parser::Progress::*; use crate::parser::{ self, backtrackable, byte, fail_when, loc, map, map_with_arena, optional, skip_first, specialize_err, specialize_err_ref, then, three_bytes, two_bytes, zero_or_more, EPattern, PInParens, PList, PRecord, Parser, }; +use crate::parser::{either, Progress::*}; use crate::state::State; use crate::string_literal::StrLikeLiteral; use bumpalo::collections::string::String; @@ -547,9 +547,9 @@ fn record_pattern_field<'a>() -> impl Parser<'a, Loc>, PRecord<'a>> // Having a value is optional; both `{ email }` and `{ email: blah }` work. // (This is true in both literals and types.) - let (_, opt_loc_val, state) = optional(either!( + let (_, opt_loc_val, state) = optional(either( byte(b':', PRecord::Colon), - byte(b'?', PRecord::Optional) + byte(b'?', PRecord::Optional), )) .parse(arena, state, min_indent)?; diff --git a/crates/compiler/parse/src/type_annotation.rs b/crates/compiler/parse/src/type_annotation.rs index f05e09d215..0b9d4261fd 100644 --- a/crates/compiler/parse/src/type_annotation.rs +++ b/crates/compiler/parse/src/type_annotation.rs @@ -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, loc, map, map_with_arena, skip_first, - skip_second, succeed, then, zero_or_more, ERecord, ETypeAbilityImpl, + absolute_column_min_indent, and, either, increment_min_indent, loc, map, map_with_arena, + skip_first, skip_second, succeed, then, zero_or_more, ERecord, ETypeAbilityImpl, }; use crate::parser::{ allocated, backtrackable, byte, fail, optional, specialize_err, specialize_err_ref, two_bytes, @@ -332,9 +332,9 @@ fn record_type_field<'a>() -> impl Parser<'a, AssignedField<'a, TypeAnnotation<' // Having a value is optional; both `{ email }` and `{ email: blah }` work. // (This is true in both literals and types.) - let (_, opt_loc_val, state) = optional(either!( + let (_, opt_loc_val, state) = optional(either( byte(b':', ETypeRecord::Colon), - byte(b'?', ETypeRecord::Optional) + byte(b'?', ETypeRecord::Optional), )) .parse(arena, state, min_indent)?; From 1c916202e71ca35fafcd184ea0ee3f5ce51aa2a6 Mon Sep 17 00:00:00 2001 From: Jackson Wambolt Date: Mon, 15 Apr 2024 22:02:55 -0500 Subject: [PATCH 14/18] Un-macro collection_inner --- crates/compiler/parse/src/expr.rs | 12 ++--- crates/compiler/parse/src/parser.rs | 80 +++++++++++++++-------------- 2 files changed, 48 insertions(+), 44 deletions(-) diff --git a/crates/compiler/parse/src/expr.rs b/crates/compiler/parse/src/expr.rs index fad0aa6a4d..fb57c1be0f 100644 --- a/crates/compiler/parse/src/expr.rs +++ b/crates/compiler/parse/src/expr.rs @@ -10,11 +10,11 @@ use crate::blankspace::{ use crate::ident::{integer_ident, lowercase_ident, parse_ident, Accessor, Ident}; use crate::keyword; use crate::parser::{ - self, and, backtrackable, between, byte, byte_indent, either, increment_min_indent, - indented_seq, line_min_indent, loc, map, map_with_arena, optional, reset_min_indent, sep_by1, - sep_by1_e, set_min_indent, skip_first, skip_second, specialize_err, specialize_err_ref, then, - two_bytes, zero_or_more, EClosure, EExpect, EExpr, EIf, EInParens, EList, ENumber, EPattern, - ERecord, EString, EType, EWhen, Either, ParseResult, Parser, + self, and, backtrackable, between, byte, byte_indent, collection_inner, either, + increment_min_indent, indented_seq, line_min_indent, loc, map, map_with_arena, optional, + reset_min_indent, sep_by1, sep_by1_e, set_min_indent, skip_first, skip_second, specialize_err, + specialize_err_ref, then, two_bytes, zero_or_more, 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; @@ -3080,7 +3080,7 @@ fn record_help<'a>() -> impl Parser<'a, RecordHelp<'a>, ERecord<'a>> { ), byte(b'&', ERecord::Ampersand) ))), - fields: collection_inner!( + fields: collection_inner( loc(record_field()), byte(b',', ERecord::End), RecordField::SpaceBefore diff --git a/crates/compiler/parse/src/parser.rs b/crates/compiler/parse/src/parser.rs index ee7b0d32e8..f04e8f4225 100644 --- a/crates/compiler/parse/src/parser.rs +++ b/crates/compiler/parse/src/parser.rs @@ -1454,45 +1454,49 @@ where } } -#[macro_export] -macro_rules! collection_inner { - ($elem:expr, $delimiter:expr, $space_before:expr) => { - $crate::parser::map_with_arena( - $crate::parser::and( - $crate::parser::and( - $crate::blankspace::spaces(), - $crate::parser::trailing_sep_by0( - $delimiter, - $crate::blankspace::spaces_before_optional_after($elem), - ), +pub fn collection_inner<'a, Elem: 'a + crate::ast::Spaceable<'a> + Clone, E: 'a + SpaceProblem>( + elem: impl Parser<'a, Loc, E> + 'a, + delimiter: impl Parser<'a, (), E>, + space_before: impl Fn(&'a Elem, &'a [crate::ast::CommentOrNewline<'a>]) -> Elem, +) -> impl Parser<'a, crate::ast::Collection<'a, Loc>, E> { + map_with_arena( + and( + and( + crate::blankspace::spaces(), + trailing_sep_by0( + delimiter, + crate::blankspace::spaces_before_optional_after(elem), ), - $crate::blankspace::spaces(), ), - |arena: &'a bumpalo::Bump, - ((spaces, mut parsed_elems), mut final_comments): ( - ( - &'a [$crate::ast::CommentOrNewline<'a>], - bumpalo::collections::vec::Vec<'a, Loc<_>>, - ), - &'a [$crate::ast::CommentOrNewline<'a>], - )| { - if !spaces.is_empty() { - if let Some(first) = parsed_elems.first_mut() { - first.value = $space_before(arena.alloc(first.value), spaces) - } else { - debug_assert!(final_comments.is_empty()); - final_comments = spaces; - } - } + crate::blankspace::spaces(), + ), + #[allow(clippy::type_complexity)] + move |arena: &'a bumpalo::Bump, + out: ( + ( + &'a [crate::ast::CommentOrNewline<'a>], + bumpalo::collections::Vec<'a, Loc>, + ), + &'a [crate::ast::CommentOrNewline<'a>], + )| { + let ((spaces, mut parsed_elems), mut final_comments) = out; - $crate::ast::Collection::with_items_and_comments( - arena, - parsed_elems.into_bump_slice(), - final_comments, - ) - }, - ) - }; + if !spaces.is_empty() { + if let Some(first) = parsed_elems.first_mut() { + first.value = space_before(arena.alloc(first.value.clone()), spaces); + } else { + debug_assert!(final_comments.is_empty()); + final_comments = spaces; + } + } + + crate::ast::Collection::with_items_and_comments( + arena, + parsed_elems.into_bump_slice(), + final_comments, + ) + }, + ) } #[macro_export] @@ -1500,10 +1504,10 @@ macro_rules! collection_trailing_sep_e { ($opening_brace:expr, $elem:expr, $delimiter:expr, $closing_brace:expr, $space_before:expr) => { $crate::parser::between( $opening_brace, - $crate::parser::reset_min_indent($crate::collection_inner!( + $crate::parser::reset_min_indent($crate::parser::collection_inner( $elem, $delimiter, - $space_before + $space_before, )), $closing_brace, ) From dd2c786eb9311869464ed37536911e3170e5f4ad Mon Sep 17 00:00:00 2001 From: Jackson Wambolt Date: Mon, 15 Apr 2024 22:18:10 -0500 Subject: [PATCH 15/18] Un-macro collection_trailing_sep_e --- crates/compiler/parse/src/expr.rs | 19 +++++------ crates/compiler/parse/src/module.rs | 34 ++++++++++---------- crates/compiler/parse/src/parser.rs | 29 +++++++++-------- crates/compiler/parse/src/pattern.rs | 18 +++++------ crates/compiler/parse/src/type_annotation.rs | 21 ++++++------ 5 files changed, 63 insertions(+), 58 deletions(-) diff --git a/crates/compiler/parse/src/expr.rs b/crates/compiler/parse/src/expr.rs index fb57c1be0f..ca1a8d9942 100644 --- a/crates/compiler/parse/src/expr.rs +++ b/crates/compiler/parse/src/expr.rs @@ -10,11 +10,12 @@ use crate::blankspace::{ use crate::ident::{integer_ident, lowercase_ident, parse_ident, Accessor, Ident}; use crate::keyword; use crate::parser::{ - self, and, backtrackable, between, byte, byte_indent, collection_inner, either, - increment_min_indent, indented_seq, line_min_indent, loc, map, map_with_arena, optional, - reset_min_indent, sep_by1, sep_by1_e, set_min_indent, skip_first, skip_second, specialize_err, - specialize_err_ref, then, two_bytes, zero_or_more, EClosure, EExpect, EExpr, EIf, EInParens, - EList, ENumber, EPattern, ERecord, EString, EType, EWhen, Either, ParseResult, Parser, + self, and, backtrackable, between, byte, byte_indent, collection_inner, + collection_trailing_sep_e, either, increment_min_indent, indented_seq, line_min_indent, loc, + map, map_with_arena, optional, reset_min_indent, sep_by1, sep_by1_e, set_min_indent, + skip_first, skip_second, specialize_err, specialize_err_ref, then, two_bytes, zero_or_more, + 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; @@ -94,12 +95,12 @@ pub fn expr_help<'a>() -> impl Parser<'a, Expr<'a>, EExpr<'a>> { fn loc_expr_in_parens_help<'a>() -> impl Parser<'a, Loc>, EInParens<'a>> { then( - loc(collection_trailing_sep_e!( + loc(collection_trailing_sep_e( byte(b'(', EInParens::Open), specialize_err_ref(EInParens::Expr, loc_expr(false)), byte(b',', EInParens::End), byte(b')', EInParens::End), - Expr::SpaceBefore + Expr::SpaceBefore, )), move |arena, state, _, loc_elements| { let elements = loc_elements.value; @@ -2848,12 +2849,12 @@ fn ident_to_expr<'a>(arena: &'a Bump, src: Ident<'a>) -> Expr<'a> { fn list_literal_help<'a>() -> impl Parser<'a, Expr<'a>, EList<'a>> { map_with_arena( - collection_trailing_sep_e!( + collection_trailing_sep_e( byte(b'[', EList::Open), specialize_err_ref(EList::Expr, loc_expr(false)), byte(b',', EList::End), byte(b']', EList::End), - Expr::SpaceBefore + Expr::SpaceBefore, ), |arena, elements: Collection<'a, _>| { let elements = elements.ptrify_items(arena); diff --git a/crates/compiler/parse/src/module.rs b/crates/compiler/parse/src/module.rs index 88c5f2470b..dce26c8782 100644 --- a/crates/compiler/parse/src/module.rs +++ b/crates/compiler/parse/src/module.rs @@ -9,10 +9,10 @@ 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, loc, map, optional, reset_min_indent, - skip_first, skip_second, specialize_err, two_bytes, zero_or_more, EExposes, EGenerates, - EGeneratesWith, EHeader, EImports, EPackages, EProvides, ERequires, ETypedIdent, Parser, - SourceError, SpaceProblem, SyntaxError, + and, backtrackable, byte, collection_trailing_sep_e, increment_min_indent, loc, map, optional, + reset_min_indent, skip_first, skip_second, specialize_err, two_bytes, zero_or_more, EExposes, + EGenerates, EGeneratesWith, EHeader, EImports, EPackages, EProvides, ERequires, ETypedIdent, + Parser, SourceError, SpaceProblem, SyntaxError, }; use crate::state::State; use crate::string_literal::{self, parse_str_literal}; @@ -235,7 +235,7 @@ fn provides_to<'a>() -> impl Parser<'a, ProvidesTo<'a>, EProvides<'a>> { EProvides::IndentProvides, EProvides::IndentListStart ), - entries: collection_trailing_sep_e!( + entries: collection_trailing_sep_e( byte(b'[', EProvides::ListStart), exposes_entry(EProvides::Identifier), byte(b',', EProvides::ListEnd), @@ -266,7 +266,7 @@ fn provides_exposed<'a>() -> impl Parser< EProvides::IndentProvides, EProvides::IndentListStart ), - item: collection_trailing_sep_e!( + item: collection_trailing_sep_e( byte(b'[', EProvides::ListStart), exposes_entry(EProvides::Identifier), byte(b',', EProvides::ListEnd), @@ -291,12 +291,12 @@ fn provides_types<'a>( // so this error should never be visible to anyone in practice! EProvides::Provides, )), - collection_trailing_sep_e!( + collection_trailing_sep_e( byte(b'{', EProvides::ListStart), provides_type_entry(EProvides::Identifier), byte(b',', EProvides::ListEnd), byte(b'}', EProvides::ListEnd), - Spaced::SpaceBefore + Spaced::SpaceBefore, ), ) } @@ -354,15 +354,15 @@ fn platform_requires<'a>() -> impl Parser<'a, PlatformRequires<'a>, ERequires<'a #[inline(always)] fn requires_rigids<'a>( ) -> impl Parser<'a, Collection<'a, Loc>>>, ERequires<'a>> { - collection_trailing_sep_e!( + collection_trailing_sep_e( 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), - Spaced::SpaceBefore + Spaced::SpaceBefore, ) } @@ -394,7 +394,7 @@ fn exposes_values<'a>() -> impl Parser< EExposes::IndentExposes, EExposes::IndentListStart ), - item: collection_trailing_sep_e!( + item: collection_trailing_sep_e( byte(b'[', EExposes::ListStart), exposes_entry(EExposes::Identifier), byte(b',', EExposes::ListEnd), @@ -445,7 +445,7 @@ fn exposes_modules<'a>() -> impl Parser< EExposes::IndentExposes, EExposes::IndentListStart ), - item: collection_trailing_sep_e!( + item: collection_trailing_sep_e( byte(b'[', EExposes::ListStart), exposes_module(EExposes::Identifier), byte(b',', EExposes::ListEnd), @@ -482,7 +482,7 @@ fn packages<'a>() -> impl Parser< EPackages::IndentPackages, EPackages::IndentListStart ), - item: collection_trailing_sep_e!( + item: collection_trailing_sep_e( byte(b'{', EPackages::ListStart), specialize_err(EPackages::PackageEntry, loc(package_entry())), byte(b',', EPackages::ListEnd), @@ -519,7 +519,7 @@ fn generates_with<'a>() -> impl Parser< EGeneratesWith::IndentWith, EGeneratesWith::IndentListStart ), - item: collection_trailing_sep_e!( + item: collection_trailing_sep_e( byte(b'[', EGeneratesWith::ListStart), exposes_entry(EGeneratesWith::Identifier), byte(b',', EGeneratesWith::ListEnd), @@ -542,7 +542,7 @@ fn imports<'a>() -> impl Parser< EImports::IndentImports, EImports::IndentListStart ), - item: collection_trailing_sep_e!( + item: collection_trailing_sep_e( byte(b'[', EImports::ListStart), loc(imports_entry()), byte(b',', EImports::ListEnd), @@ -623,7 +623,7 @@ fn imports_entry<'a>() -> impl Parser<'a, Spaced<'a, ImportsEntry<'a>>, EImports // e.g. `.{ Task, after}` optional(skip_first( byte(b'.', EImports::ExposingDot), - collection_trailing_sep_e!( + collection_trailing_sep_e( byte(b'{', EImports::SetStart), exposes_entry(EImports::Identifier), byte(b',', EImports::SetEnd), diff --git a/crates/compiler/parse/src/parser.rs b/crates/compiler/parse/src/parser.rs index f04e8f4225..705cf0ae09 100644 --- a/crates/compiler/parse/src/parser.rs +++ b/crates/compiler/parse/src/parser.rs @@ -1499,19 +1499,22 @@ pub fn collection_inner<'a, Elem: 'a + crate::ast::Spaceable<'a> + Clone, E: 'a ) } -#[macro_export] -macro_rules! collection_trailing_sep_e { - ($opening_brace:expr, $elem:expr, $delimiter:expr, $closing_brace:expr, $space_before:expr) => { - $crate::parser::between( - $opening_brace, - $crate::parser::reset_min_indent($crate::parser::collection_inner( - $elem, - $delimiter, - $space_before, - )), - $closing_brace, - ) - }; +pub fn collection_trailing_sep_e< + 'a, + Elem: 'a + crate::ast::Spaceable<'a> + Clone, + E: 'a + SpaceProblem, +>( + opening_brace: impl Parser<'a, (), E>, + elem: impl Parser<'a, Loc, E> + 'a, + delimiter: impl Parser<'a, (), E>, + closing_brace: impl Parser<'a, (), E>, + space_before: impl Fn(&'a Elem, &'a [crate::ast::CommentOrNewline<'a>]) -> Elem, +) -> impl Parser<'a, crate::ast::Collection<'a, Loc>, E> { + between( + opening_brace, + reset_min_indent(collection_inner(elem, delimiter, space_before)), + closing_brace, + ) } /// Creates a parser that always succeeds with the given argument as output. diff --git a/crates/compiler/parse/src/pattern.rs b/crates/compiler/parse/src/pattern.rs index aa5a286229..cc4e56cc9f 100644 --- a/crates/compiler/parse/src/pattern.rs +++ b/crates/compiler/parse/src/pattern.rs @@ -3,9 +3,9 @@ use crate::blankspace::{space0_e, spaces, spaces_before}; use crate::ident::{lowercase_ident, parse_ident, Accessor, Ident}; use crate::keyword; use crate::parser::{ - self, backtrackable, byte, fail_when, loc, map, map_with_arena, optional, skip_first, - specialize_err, specialize_err_ref, then, three_bytes, two_bytes, zero_or_more, EPattern, - PInParens, PList, PRecord, Parser, + self, backtrackable, byte, collection_trailing_sep_e, fail_when, loc, map, map_with_arena, + optional, skip_first, specialize_err, specialize_err_ref, then, three_bytes, two_bytes, + zero_or_more, EPattern, PInParens, PList, PRecord, Parser, }; use crate::parser::{either, Progress::*}; use crate::state::State; @@ -200,12 +200,12 @@ pub fn loc_implements_parser<'a>() -> impl Parser<'a, Loc>, EPatt fn loc_pattern_in_parens_help<'a>() -> impl Parser<'a, Loc>, PInParens<'a>> { then( - loc(collection_trailing_sep_e!( + loc(collection_trailing_sep_e( byte(b'(', PInParens::Open), specialize_err_ref(PInParens::Pattern, loc_pattern_help()), byte(b',', PInParens::End), byte(b')', PInParens::End), - Pattern::SpaceBefore + Pattern::SpaceBefore, )), move |_arena, state, _, loc_elements| { let elements = loc_elements.value; @@ -271,12 +271,12 @@ 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( - collection_trailing_sep_e!( + collection_trailing_sep_e( byte(b'[', PList::Open), list_element_pattern(), byte(b',', PList::End), byte(b']', PList::End), - Pattern::SpaceBefore + Pattern::SpaceBefore, ), Pattern::List, ) @@ -518,12 +518,12 @@ 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( - collection_trailing_sep_e!( + collection_trailing_sep_e( byte(b'{', PRecord::Open), record_pattern_field(), byte(b',', PRecord::End), byte(b'}', PRecord::End), - Pattern::SpaceBefore + Pattern::SpaceBefore, ), Pattern::RecordDestructure, ) diff --git a/crates/compiler/parse/src/type_annotation.rs b/crates/compiler/parse/src/type_annotation.rs index 0b9d4261fd..246332f5ca 100644 --- a/crates/compiler/parse/src/type_annotation.rs +++ b/crates/compiler/parse/src/type_annotation.rs @@ -9,8 +9,9 @@ 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, either, increment_min_indent, loc, map, map_with_arena, - skip_first, skip_second, succeed, then, zero_or_more, ERecord, ETypeAbilityImpl, + absolute_column_min_indent, and, collection_trailing_sep_e, either, increment_min_indent, loc, + map, map_with_arena, skip_first, skip_second, succeed, then, zero_or_more, ERecord, + ETypeAbilityImpl, }; use crate::parser::{ allocated, backtrackable, byte, fail, optional, specialize_err, specialize_err_ref, two_bytes, @@ -39,12 +40,12 @@ fn tag_union_type<'a>( stop_at_surface_has: bool, ) -> impl Parser<'a, TypeAnnotation<'a>, ETypeTagUnion<'a>> { move |arena, state, min_indent| { - let (_, tags, state) = collection_trailing_sep_e!( + let (_, tags, state) = collection_trailing_sep_e( byte(b'[', ETypeTagUnion::Open), loc(tag_type(false)), byte(b',', ETypeTagUnion::End), byte(b']', ETypeTagUnion::End), - Tag::SpaceBefore + Tag::SpaceBefore, ) .parse(arena, state, min_indent)?; @@ -243,12 +244,12 @@ fn loc_type_in_parens<'a>( ) -> impl Parser<'a, Loc>, ETypeInParens<'a>> { then( loc(and( - collection_trailing_sep_e!( + collection_trailing_sep_e( byte(b'(', ETypeInParens::Open), specialize_err_ref(ETypeInParens::Type, expression(true, false)), byte(b',', ETypeInParens::End), byte(b')', ETypeInParens::End), - TypeAnnotation::SpaceBefore + TypeAnnotation::SpaceBefore, ), optional(allocated(specialize_err_ref( ETypeInParens::Type, @@ -382,7 +383,7 @@ fn record_type<'a>( stop_at_surface_has: bool, ) -> impl Parser<'a, TypeAnnotation<'a>, ETypeRecord<'a>> { record!(TypeAnnotation::Record { - fields: collection_trailing_sep_e!( + fields: collection_trailing_sep_e( byte(b'{', ETypeRecord::Open), loc(record_type_field()), byte(b',', ETypeRecord::End), @@ -531,12 +532,12 @@ pub fn implements_abilities<'a>() -> impl Parser<'a, Loc // Parse "Hash"; this may be qualified from another module like "Hash.Hash" space0_before_e( loc(map( - collection_trailing_sep_e!( + collection_trailing_sep_e( byte(b'[', EType::TStart), loc(parse_implements_ability()), byte(b',', EType::TEnd), byte(b']', EType::TEnd), - ImplementsAbility::SpaceBefore + ImplementsAbility::SpaceBefore, ), ImplementsAbilities::Implements, )), @@ -552,7 +553,7 @@ fn parse_implements_ability<'a>() -> impl Parser<'a, ImplementsAbility<'a>, ETyp loc(map( specialize_err( EType::TAbilityImpl, - collection_trailing_sep_e!( + collection_trailing_sep_e( byte(b'{', ETypeAbilityImpl::Open), specialize_err(|e: ERecord<'_>, _| e.into(), loc(ability_impl_field())), byte(b',', ETypeAbilityImpl::End), From f001cf98e655c4c97ee5cc1d39992334a4b6e41b Mon Sep 17 00:00:00 2001 From: Jackson Wambolt Date: Tue, 16 Apr 2024 18:08:51 -0500 Subject: [PATCH 16/18] Clarify doc for `indented_seq` Previously said that `indented_seq` was similar to `and`, but it's more like `skip_first`. `and` returns a tuple of both parsers' outputs, but `indented_seq` only returns the output of the second parser, just like `skip_first`. --- crates/compiler/parse/src/parser.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/compiler/parse/src/parser.rs b/crates/compiler/parse/src/parser.rs index 705cf0ae09..3a9f91e940 100644 --- a/crates/compiler/parse/src/parser.rs +++ b/crates/compiler/parse/src/parser.rs @@ -1684,9 +1684,9 @@ macro_rules! record { }; } -/// Similar to [`and`], but we modify the `min_indent` of the second parser -/// (`parser`) to be 1 greater than the `line_indent()` at the start of the -/// first parser (`before`). +/// Similar to [`skip_first`], but we modify the `min_indent` of the second +/// parser (`parser`) to be 1 greater than the `line_indent()` at the start of +/// the first parser (`before`). pub fn indented_seq<'a, O, E: 'a>( before: impl Parser<'a, (), E>, parser: impl Parser<'a, O, E>, From f44064e9465c5f57ba6cab9afac0774ebc50f52e Mon Sep 17 00:00:00 2001 From: Jackson Wambolt Date: Fri, 19 Apr 2024 01:06:41 -0500 Subject: [PATCH 17/18] Fix failing parser doctests --- crates/compiler/parse/src/parser.rs | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/crates/compiler/parse/src/parser.rs b/crates/compiler/parse/src/parser.rs index 3a9f91e940..4aec646169 100644 --- a/crates/compiler/parse/src/parser.rs +++ b/crates/compiler/parse/src/parser.rs @@ -1377,9 +1377,8 @@ pub fn loc<'a, Output, E: 'a>( /// ``` /// # #![forbid(unused_imports)] /// # use roc_parse::state::State; -/// # use crate::roc_parse::parser::{Parser, Progress, word}; +/// # use crate::roc_parse::parser::{Parser, Progress, word, skip_first}; /// # use roc_parse::ident::lowercase_ident; -/// # use roc_parse::skip_first; /// # use bumpalo::Bump; /// # let arena = Bump::new(); /// # fn foo<'a>(arena: &'a Bump) { @@ -1419,9 +1418,8 @@ where /// ``` /// # #![forbid(unused_imports)] /// # use roc_parse::state::State; -/// # use crate::roc_parse::parser::{Parser, Progress, word}; +/// # use crate::roc_parse::parser::{Parser, Progress, word, skip_second}; /// # use roc_parse::ident::lowercase_ident; -/// # use roc_parse::skip_second; /// # use bumpalo::Bump; /// # let arena = Bump::new(); /// # fn foo<'a>(arena: &'a Bump) { @@ -1523,8 +1521,7 @@ pub fn collection_trailing_sep_e< /// ``` /// # #![forbid(unused_imports)] /// # use roc_parse::state::State; -/// # use crate::roc_parse::parser::{Parser, Progress, Progress::NoProgress}; -/// # use roc_parse::succeed; +/// # use crate::roc_parse::parser::{Parser, Progress, succeed}; /// # use bumpalo::Bump; /// # let arena = Bump::new(); /// # fn foo<'a>(arena: &'a Bump) { @@ -2185,9 +2182,8 @@ macro_rules! byte_check_indent { /// ``` /// # #![forbid(unused_imports)] /// # use roc_parse::state::State; -/// # use crate::roc_parse::parser::{Parser, Progress, word}; +/// # use crate::roc_parse::parser::{Parser, Progress, word, map}; /// # use roc_region::all::Position; -/// # use roc_parse::map; /// # use bumpalo::Bump; /// # #[derive(Debug, PartialEq)] /// # enum Problem { @@ -2290,9 +2286,8 @@ pub fn zero_or_more<'a, Output, E: 'a>( /// ``` /// # #![forbid(unused_imports)] /// # use roc_parse::state::State; -/// # use crate::roc_parse::parser::{Parser, Progress, Progress::{MadeProgress, NoProgress}, word}; +/// # use crate::roc_parse::parser::{Parser, Progress, word, one_or_more}; /// # use roc_region::all::Position; -/// # use roc_parse::one_or_more!; /// # use bumpalo::Bump; /// # #[derive(Debug, PartialEq)] /// # enum Problem { @@ -2400,9 +2395,8 @@ macro_rules! debug { /// ``` /// # #![forbid(unused_imports)] /// # use roc_parse::state::State; -/// # use crate::roc_parse::parser::{Parser, Progress, Progress::{MadeProgress, NoProgress}, word, Either}; +/// # use crate::roc_parse::parser::{Parser, Progress, word, either, Either}; /// # use roc_region::all::Position; -/// # use roc_parse::either; /// # use bumpalo::Bump; /// # #[derive(Debug, PartialEq)] /// # enum Problem { @@ -2463,9 +2457,8 @@ pub fn either<'a, OutputLeft, OutputRight, E: 'a>( /// ``` /// # #![forbid(unused_imports)] /// # use roc_parse::state::State; -/// # use crate::roc_parse::parser::{Parser, Progress, word, byte}; +/// # use crate::roc_parse::parser::{Parser, Progress, word, byte, between}; /// # use roc_region::all::Position; -/// # use roc_parse::{between, skip_first, skip_second}; /// # use bumpalo::Bump; /// # #[derive(Debug, PartialEq)] /// # enum Problem { From f8432f7510a9e2aa6d218035c5b524f3933b6a33 Mon Sep 17 00:00:00 2001 From: Anton-4 <17049058+Anton-4@users.noreply.github.com> Date: Sat, 22 Jun 2024 20:09:15 +0200 Subject: [PATCH 18/18] fmt --- crates/compiler/parse/src/expr.rs | 27 ++++++------- crates/compiler/parse/src/header.rs | 10 ++--- crates/compiler/parse/src/module.rs | 41 +++++++++----------- crates/compiler/parse/src/parser.rs | 1 - crates/compiler/parse/src/pattern.rs | 2 +- crates/compiler/parse/src/type_annotation.rs | 8 ++-- 6 files changed, 41 insertions(+), 48 deletions(-) diff --git a/crates/compiler/parse/src/expr.rs b/crates/compiler/parse/src/expr.rs index 93e4b5d1cf..272346ca04 100644 --- a/crates/compiler/parse/src/expr.rs +++ b/crates/compiler/parse/src/expr.rs @@ -15,11 +15,11 @@ use crate::ident::{ use crate::module::module_name_help; use crate::parser::{ self, and, backtrackable, between, byte, byte_indent, collection_inner, - collection_trailing_sep_e, either, increment_min_indent, line_min_indent, loc, - map, map_with_arena, optional, reset_min_indent, sep_by1, sep_by1_e, set_min_indent, - skip_first, skip_second, specialize_err, specialize_err_ref, then, two_bytes, zero_or_more, - EClosure, EExpect, EExpr, EIf, EInParens, EList, ENumber, EPattern, ERecord, EString, EType, - EWhen, Either, ParseResult, Parser, EImport, EImportParams, indented_seq_skip_first + collection_trailing_sep_e, either, increment_min_indent, indented_seq_skip_first, + line_min_indent, loc, map, map_with_arena, optional, reset_min_indent, sep_by1, sep_by1_e, + set_min_indent, skip_first, skip_second, specialize_err, specialize_err_ref, then, two_bytes, + zero_or_more, EClosure, EExpect, EExpr, EIf, EImport, EImportParams, EInParens, EList, ENumber, + EPattern, ERecord, EString, EType, EWhen, Either, ParseResult, Parser, }; use crate::pattern::{closure_param, loc_implements_parser}; use crate::state::State; @@ -961,9 +961,9 @@ fn import<'a>() -> impl Parser<'a, (Loc>, &'a [CommentOrNewline<'a> and( loc(skip_first( parser::keyword(keyword::IMPORT, EImport::Import), - increment_min_indent(one_of!(import_body(), import_ingested_file_body())) + increment_min_indent(one_of!(import_body(), import_ingested_file_body())), )), - space0_e(EImport::EndNewline) + space0_e(EImport::EndNewline), ), |_arena, state, progress, (import, spaces_after)| { if !spaces_after.is_empty() || state.has_reached_end() { @@ -985,7 +985,7 @@ fn import_body<'a>() -> impl Parser<'a, ValueDef<'a>, EImport<'a>> { alias: optional(import_as()), exposed: optional(import_exposing()) }), - ValueDef::ModuleImport + ValueDef::ModuleImport, ) } @@ -993,7 +993,7 @@ fn import_params<'a>() -> impl Parser<'a, ModuleImportParams<'a>, EImportParams< then( and( backtrackable(space0_e(EImportParams::Indent)), - specialize_err(EImportParams::Record, record_help()) + specialize_err(EImportParams::Record, record_help()), ), |arena, state, _, (before, record): (_, RecordHelp<'a>)| { if let Some(update) = record.update { @@ -1090,7 +1090,7 @@ fn import_exposed_name<'a>( ) -> impl Parser<'a, crate::ast::Spaced<'a, crate::header::ExposedName<'a>>, EImport<'a>> { map( specialize_err(|_, pos| EImport::ExposedName(pos), unqualified_ident()), - |n| Spaced::Item(crate::header::ExposedName::new(n)) + |n| Spaced::Item(crate::header::ExposedName::new(n)), ) } @@ -1106,7 +1106,7 @@ fn import_ingested_file_body<'a>() -> impl Parser<'a, ValueDef<'a>, EImport<'a>> name: import_ingested_file_as(), annotation: optional(import_ingested_file_annotation()) }), - ValueDef::IngestedFileImport + ValueDef::IngestedFileImport, ) } @@ -1120,10 +1120,7 @@ fn import_ingested_file_as<'a>( EImport::IndentAs, EImport::IndentIngestedName ), - item: specialize_err( - |(), pos| EImport::IngestedName(pos), - loc(lowercase_ident()) - ) + item: specialize_err(|(), pos| EImport::IngestedName(pos), loc(lowercase_ident())) }) } diff --git a/crates/compiler/parse/src/header.rs b/crates/compiler/parse/src/header.rs index eed707b16e..6bbda2cea7 100644 --- a/crates/compiler/parse/src/header.rs +++ b/crates/compiler/parse/src/header.rs @@ -5,8 +5,8 @@ use crate::blankspace::space0_e; use crate::expr::merge_spaces; use crate::ident::{lowercase_ident, UppercaseIdent}; use crate::parser::{ - and, byte, loc, map_with_arena, skip_second, specialize_err, EPackageEntry, EPackageName, - Parser, skip_first + and, byte, loc, map_with_arena, skip_first, skip_second, specialize_err, EPackageEntry, + EPackageName, Parser, }; use crate::parser::{optional, then}; use crate::string_literal; @@ -388,10 +388,10 @@ pub fn package_entry<'a>() -> impl Parser<'a, Spaced<'a, PackageEntry<'a>>, EPac and( optional(skip_first( crate::parser::keyword(crate::keyword::PLATFORM, EPackageEntry::Platform), - space0_e(EPackageEntry::IndentPackage) + space0_e(EPackageEntry::IndentPackage), )), - loc(specialize_err(EPackageEntry::BadPackage, package_name())) - ) + loc(specialize_err(EPackageEntry::BadPackage, package_name())), + ), ), move |arena, (opt_shorthand, (platform_marker, package_or_path))| { let entry = match opt_shorthand { diff --git a/crates/compiler/parse/src/module.rs b/crates/compiler/parse/src/module.rs index 9da3da766b..3a895cdd2a 100644 --- a/crates/compiler/parse/src/module.rs +++ b/crates/compiler/parse/src/module.rs @@ -11,10 +11,10 @@ use crate::header::{ use crate::ident::{self, lowercase_ident, unqualified_ident, uppercase, UppercaseIdent}; use crate::parser::Progress::{self, *}; use crate::parser::{ - and, backtrackable, byte, collection_trailing_sep_e, increment_min_indent, loc, map, optional, - reset_min_indent, skip_first, skip_second, specialize_err, two_bytes, zero_or_more, EExposes, - EGenerates, EGeneratesWith, EHeader, EImports, EPackages, EProvides, ERequires, ETypedIdent, - Parser, SourceError, SpaceProblem, SyntaxError, map_with_arena, succeed, EParams + and, backtrackable, byte, collection_trailing_sep_e, increment_min_indent, loc, map, + map_with_arena, optional, reset_min_indent, skip_first, skip_second, specialize_err, succeed, + two_bytes, zero_or_more, EExposes, EGenerates, EGeneratesWith, EHeader, EImports, EPackages, + EParams, EProvides, ERequires, ETypedIdent, Parser, SourceError, SpaceProblem, SyntaxError, }; use crate::pattern::record_pattern_fields; use crate::state::State; @@ -150,14 +150,14 @@ fn interface_header<'a>() -> impl Parser<'a, ModuleHeader<'a>, EHeader<'a>> { and( skip_second( space0_e(EHeader::IndentStart), - loc(module_name_help(EHeader::ModuleName)) + loc(module_name_help(EHeader::ModuleName)), ), - specialize_err(EHeader::Exposes, exposes_kw()) + specialize_err(EHeader::Exposes, exposes_kw()), ), |arena: &'a bumpalo::Bump, (before_name, kw): (&'a [CommentOrNewline<'a>], Spaces<'a, ExposesKeyword>)| { merge_n_spaces!(arena, before_name, kw.before, kw.after) - } + }, ); record!(ModuleHeader { @@ -439,7 +439,7 @@ fn old_package_header<'a>() -> impl Parser<'a, PackageHeader<'a>, EHeader<'a>> { before_packages, packages: old.packages.map(|kw| kw.item), } - } + }, ) .trace("old_package_header") } @@ -653,7 +653,7 @@ fn exposes_list<'a>() -> impl Parser<'a, Collection<'a, Loc( exposes_module(EExposes::Identifier), byte(b',', EExposes::ListEnd), byte(b']', EExposes::ListEnd), - Spaced::SpaceBefore + Spaced::SpaceBefore, ) } @@ -757,7 +757,7 @@ fn packages_collection<'a>( specialize_err(EPackages::PackageEntry, loc(package_entry())), byte(b',', EPackages::ListEnd), byte(b'}', EPackages::ListEnd), - Spaced::SpaceBefore + Spaced::SpaceBefore, ) } @@ -877,21 +877,18 @@ fn imports_entry<'a>() -> impl Parser<'a, Spaced<'a, ImportsEntry<'a>>, EImports Option>>>>, ); - let spaced_import = - |((opt_shortname, module_name), opt_values): Temp<'a>| { - let exposed_values = opt_values.unwrap_or_else(Collection::empty); + let spaced_import = |((opt_shortname, module_name), opt_values): Temp<'a>| { + let exposed_values = opt_values.unwrap_or_else(Collection::empty); - let entry = match opt_shortname { - Some(shortname) => { - ImportsEntry::Package(shortname, module_name, exposed_values) - } + let entry = match opt_shortname { + Some(shortname) => ImportsEntry::Package(shortname, module_name, exposed_values), - None => ImportsEntry::Module(module_name, exposed_values), - }; - - Spaced::Item(entry) + None => ImportsEntry::Module(module_name, exposed_values), }; + Spaced::Item(entry) + }; + one_of!( map( and( diff --git a/crates/compiler/parse/src/parser.rs b/crates/compiler/parse/src/parser.rs index b8ca6205fb..93a6b1554e 100644 --- a/crates/compiler/parse/src/parser.rs +++ b/crates/compiler/parse/src/parser.rs @@ -1793,7 +1793,6 @@ pub fn indented_seq<'a, Output1, Output2, E: 'a>( } } - /// Similar to [`and`], but we modify the `min_indent` of the second parser to be /// 1 greater than the `column()` at the start of the first parser. pub fn absolute_indented_seq<'a, Output1, Output2, E: 'a>( diff --git a/crates/compiler/parse/src/pattern.rs b/crates/compiler/parse/src/pattern.rs index 93837d57b6..a9dbf051d7 100644 --- a/crates/compiler/parse/src/pattern.rs +++ b/crates/compiler/parse/src/pattern.rs @@ -475,7 +475,7 @@ pub fn record_pattern_fields<'a>() -> impl Parser<'a, Collection<'a, Loc( fn applied_type<'a>(stop_at_surface_has: bool) -> impl Parser<'a, TypeAnnotation<'a>, EType<'a>> { map( -indented_seq( + indented_seq( specialize_err(EType::TApply, concrete_type()), // Optionally parse space-separated arguments for the constructor, // e.g. `Str Float` in `Map Str Float`