Merge pull request #6548 from roboteng/parser-docs

Parser docs examples
This commit is contained in:
Anton-4 2024-03-26 19:35:39 +01:00 committed by GitHub
commit 30b5943b54
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 1221 additions and 326 deletions

View file

@ -34,7 +34,7 @@ jobs:
if git diff --name-only origin/${{ github.base_ref }} HEAD | grep -qvE '(\.md$|\.css$|\.html$|^AUTHORS$|\.rs|\.roc)'; then
echo "should_run_tests=y" >> $GITHUB_OUTPUT
else
if git diff --unified=0 origin/${{ github.base_ref }} HEAD '*.rs' | grep -E --color=never '^[+-]' | grep -qvE '^(\+\+\+|\-\-\-|[+-]\s*($|\/\/|\/\*.*\*\/\s*$))'; then
if git diff --unified=0 origin/${{ github.base_ref }} HEAD '*.rs' | grep -E --color=never '^[+-]' | grep -qvE '^(\+\+\+|\-\-\-|[+-]\s*($|\/\/[^\/]|\/\*.*\*\/\s*$))'; then
echo "should_run_tests=y" >> $GITHUB_OUTPUT
else
echo "should_run_tests=n" >> $GITHUB_OUTPUT

View file

@ -38,6 +38,9 @@ jobs:
# see #5904 for skipped test
run: cargo test --locked --release -- --skip cli_run::expects_dev_and_test && sccache --show-stats
- name: tests examples in docs
run: cargo test --doc --release
- name: check that the platform`s produced dylib is loadable
run: cd examples/platform-switching/rust-platform && LD_LIBRARY_PATH=. cargo test --release --locked

View file

@ -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, increment_min_indent, line_min_indent, optional, reset_min_indent,
sep_by1, sep_by1_e, set_min_indent, specialize, specialize_ref, then, word1, word1_indent,
word2, EClosure, EExpect, EExpr, EIf, EInParens, EList, ENumber, EPattern, ERecord, EString,
EType, EWhen, Either, ParseResult, 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,
};
use crate::pattern::{closure_param, loc_implements_parser};
use crate::state::State;
@ -80,10 +80,10 @@ pub fn expr_help<'a>() -> impl Parser<'a, Expr<'a>, EExpr<'a>> {
fn loc_expr_in_parens_help<'a>() -> impl Parser<'a, Loc<Expr<'a>>, EInParens<'a>> {
then(
loc!(collection_trailing_sep_e!(
word1(b'(', EInParens::Open),
specialize_ref(EInParens::Expr, loc_expr(false)),
word1(b',', EInParens::End),
word1(b')', EInParens::End),
byte(b'(', EInParens::Open),
specialize_err_ref(EInParens::Expr, loc_expr(false)),
byte(b',', EInParens::End),
byte(b')', EInParens::End),
Expr::SpaceBefore
)),
move |arena, state, _, loc_elements| {
@ -118,7 +118,7 @@ fn loc_expr_in_parens_help<'a>() -> impl Parser<'a, Loc<Expr<'a>>, EInParens<'a>
fn loc_expr_in_parens_etc_help<'a>() -> impl Parser<'a, Loc<Expr<'a>>, EExpr<'a>> {
map_with_arena!(
loc!(and!(
specialize(EExpr::InParens, loc_expr_in_parens_help()),
specialize_err(EExpr::InParens, loc_expr_in_parens_help()),
record_field_access_chain()
)),
move |arena: &'a Bump, value: Loc<(Loc<Expr<'a>>, Vec<'a, Accessor<'a>>)>| {
@ -144,8 +144,8 @@ fn loc_expr_in_parens_etc_help<'a>() -> impl Parser<'a, Loc<Expr<'a>>, EExpr<'a>
fn record_field_access_chain<'a>() -> impl Parser<'a, Vec<'a, Accessor<'a>>, EExpr<'a>> {
zero_or_more!(skip_first!(
word1(b'.', EExpr::Access),
specialize(
byte(b'.', EExpr::Access),
specialize_err(
|_, pos| EExpr::Access(pos),
one_of!(
map!(lowercase_ident(), Accessor::RecordField),
@ -162,15 +162,18 @@ fn loc_term_or_underscore_or_conditional<'a>(
) -> impl Parser<'a, Loc<Expr<'a>>, EExpr<'a>> {
one_of!(
loc_expr_in_parens_etc_help(),
loc!(specialize(EExpr::If, if_expr_help(options))),
loc!(specialize(EExpr::When, when::expr_help(options))),
loc!(specialize(EExpr::Str, string_like_literal_help())),
loc!(specialize(EExpr::Number, positive_number_literal_help())),
loc!(specialize(EExpr::Closure, closure_help(options))),
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(EExpr::List, list_literal_help())),
loc!(specialize_err(EExpr::List, list_literal_help())),
loc!(map_with_arena!(
assign_or_destructure_identifier(),
ident_to_expr
@ -185,12 +188,15 @@ fn loc_term_or_underscore<'a>(
) -> impl Parser<'a, Loc<Expr<'a>>, EExpr<'a>> {
one_of!(
loc_expr_in_parens_etc_help(),
loc!(specialize(EExpr::Str, string_like_literal_help())),
loc!(specialize(EExpr::Number, positive_number_literal_help())),
loc!(specialize(EExpr::Closure, closure_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!(underscore_expression()),
loc!(record_literal_help()),
loc!(specialize(EExpr::List, list_literal_help())),
loc!(specialize_err(EExpr::List, list_literal_help())),
loc!(map_with_arena!(
assign_or_destructure_identifier(),
ident_to_expr
@ -201,11 +207,14 @@ fn loc_term_or_underscore<'a>(
fn loc_term<'a>(options: ExprParseOptions) -> impl Parser<'a, Loc<Expr<'a>>, EExpr<'a>> {
one_of!(
loc_expr_in_parens_etc_help(),
loc!(specialize(EExpr::Str, string_like_literal_help())),
loc!(specialize(EExpr::Number, positive_number_literal_help())),
loc!(specialize(EExpr::Closure, closure_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!(record_literal_help()),
loc!(specialize(EExpr::List, list_literal_help())),
loc!(specialize_err(EExpr::List, list_literal_help())),
loc!(map_with_arena!(
assign_or_destructure_identifier(),
ident_to_expr
@ -217,9 +226,10 @@ fn underscore_expression<'a>() -> impl Parser<'a, Expr<'a>, EExpr<'a>> {
move |arena: &'a Bump, state: State<'a>, min_indent: u32| {
let start = state.pos();
let (_, _, next_state) = word1(b'_', EExpr::Underscore).parse(arena, state, min_indent)?;
let (_, _, next_state) = byte(b'_', EExpr::Underscore).parse(arena, state, min_indent)?;
let lowercase_ident_expr = { specialize(move |_, _| EExpr::End(start), lowercase_ident()) };
let lowercase_ident_expr =
{ specialize_err(move |_, _| EExpr::End(start), lowercase_ident()) };
let (_, output, final_state) =
optional(lowercase_ident_expr).parse(arena, next_state, min_indent)?;
@ -233,7 +243,7 @@ fn underscore_expression<'a>() -> impl Parser<'a, Expr<'a>, EExpr<'a>> {
fn crash_kw<'a>() -> impl Parser<'a, Expr<'a>, EExpr<'a>> {
move |arena: &'a Bump, state: State<'a>, min_indent: u32| {
let (_, _, next_state) = crate::parser::keyword_e(crate::keyword::CRASH, EExpr::Crash)
let (_, _, next_state) = crate::parser::keyword(crate::keyword::CRASH, EExpr::Crash)
.parse(arena, state, min_indent)?;
Ok((MadeProgress, Expr::Crash, next_state))
@ -255,10 +265,10 @@ fn loc_possibly_negative_or_negated_term<'a>(
Ok((MadeProgress, loc_expr, state))
},
// this will parse negative numbers, which the unary negate thing up top doesn't (for now)
loc!(specialize(EExpr::Number, number_literal_help())),
loc!(specialize_err(EExpr::Number, number_literal_help())),
loc!(map_with_arena!(
and!(
loc!(word1(b'!', EExpr::Start)),
loc!(byte(b'!', EExpr::Start)),
space0_before_e(loc_term(options), EExpr::IndentStart)
),
|arena: &'a Bump, (loc_op, loc_expr): (Loc<_>, _)| {
@ -298,11 +308,11 @@ fn unary_negate<'a>() -> impl Parser<'a, (), EExpr<'a>> {
fn expr_start<'a>(options: ExprParseOptions) -> impl Parser<'a, Loc<Expr<'a>>, EExpr<'a>> {
one_of![
loc!(specialize(EExpr::If, if_expr_help(options))),
loc!(specialize(EExpr::When, when::expr_help(options))),
loc!(specialize(EExpr::Expect, expect_help(options))),
loc!(specialize(EExpr::Dbg, dbg_help(options))),
loc!(specialize(EExpr::Closure, closure_help(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()
]
@ -576,8 +586,8 @@ pub fn parse_single_def<'a>(
let start = state.pos();
let parse_expect_vanilla = crate::parser::keyword_e(crate::keyword::EXPECT, EExpect::Expect);
let parse_expect_fx = crate::parser::keyword_e(crate::keyword::EXPECT_FX, EExpect::Expect);
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);
match space0_after_e(crate::pattern::loc_pattern_help(), EPattern::IndentEnd).parse(
@ -1073,7 +1083,7 @@ fn parse_defs_expr<'a>(
}
fn alias_signature_with_space_before<'a>() -> impl Parser<'a, Loc<TypeAnnotation<'a>>, EExpr<'a>> {
increment_min_indent(specialize(
increment_min_indent(specialize_err(
EExpr::Type,
space0_before_e(type_annotation::located(false), EType::TIndentStart),
))
@ -1088,14 +1098,14 @@ fn opaque_signature_with_space_before<'a>() -> impl Parser<
EExpr<'a>,
> {
and!(
specialize(
specialize_err(
EExpr::Type,
space0_before_e(
type_annotation::located_opaque_signature(true),
EType::TIndentStart,
),
),
optional(backtrackable(specialize(
optional(backtrackable(specialize_err(
EExpr::Type,
space0_before_e(type_annotation::implements_abilities(), EType::TIndentStart,),
)))
@ -1221,7 +1231,7 @@ fn finish_parsing_alias_or_opaque<'a>(
match expr_to_pattern_help(arena, &call.value) {
Ok(good) => {
let parser = specialize(
let parser = specialize_err(
EExpr::Type,
space0_before_e(
set_min_indent(indented_more, type_annotation::located(false)),
@ -1277,14 +1287,14 @@ mod ability {
map!(
// Require the type to be more indented than the name
absolute_indented_seq!(
specialize(|_, 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?
space0_e(EAbility::DemandName),
word1(b':', EAbility::DemandColon)
byte(b':', EAbility::DemandColon)
),
specialize(EAbility::Type, type_annotation::located(true))
specialize_err(EAbility::Type, type_annotation::located(true))
)
),
|(name, typ): (Loc<&'a str>, Loc<TypeAnnotation<'a>>)| {
@ -1757,10 +1767,10 @@ fn parse_expr_end<'a>(
if options.accept_multi_backpassing && state.bytes().starts_with(b",") {
state = state.advance(1);
let (_, mut patterns, state) = specialize_ref(
let (_, mut patterns, state) = specialize_err_ref(
EExpr::Pattern,
crate::parser::sep_by0(
word1(b',', EPattern::Start),
byte(b',', EPattern::Start),
space0_around_ee(
crate::pattern::loc_pattern_help(),
EPattern::Start,
@ -1787,7 +1797,7 @@ fn parse_expr_end<'a>(
patterns.insert(0, loc_pattern);
match word2(b'<', b'-', EExpr::BackpassArrow).parse(
match two_bytes(b'<', b'-', EExpr::BackpassArrow).parse(
arena,
state.clone(),
min_indent,
@ -2064,16 +2074,16 @@ fn closure_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EClo
// 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)
word1_indent(b'\\', EClosure::Start),
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!(
// Parse the params
// Params are comma-separated
sep_by1_e(
word1(b',', EClosure::Comma),
byte(b',', EClosure::Comma),
space0_around_ee(
specialize(EClosure::Pattern, closure_param()),
specialize_err(EClosure::Pattern, closure_param()),
EClosure::IndentArg,
EClosure::IndentArrow,
),
@ -2081,10 +2091,10 @@ fn closure_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EClo
),
skip_first!(
// Parse the -> which separates params from body
word2(b'-', b'>', EClosure::Arrow),
two_bytes(b'-', b'>', EClosure::Arrow),
// Parse the body
space0_before_e(
specialize_ref(EClosure::Body, expr_start(options)),
specialize_err_ref(EClosure::Body, expr_start(options)),
EClosure::IndentBody
)
)
@ -2107,9 +2117,9 @@ mod when {
map_with_arena!(
and!(
indented_seq!(
parser::keyword_e(keyword::WHEN, EWhen::When),
parser::keyword(keyword::WHEN, EWhen::When),
space0_around_e_no_after_indent_check(
specialize_ref(EWhen::Condition, expr_start(options)),
specialize_err_ref(EWhen::Condition, expr_start(options)),
EWhen::IndentCondition,
)
),
@ -2118,7 +2128,7 @@ mod when {
//
// We require that branches are indented relative to the line containing the `is`.
indented_seq!(
parser::keyword_e(keyword::IS, EWhen::Is),
parser::keyword(keyword::IS, EWhen::Is),
branches(options)
)
),
@ -2215,10 +2225,10 @@ mod when {
one_of![
map!(
skip_first!(
parser::keyword_e(keyword::IF, EWhen::IfToken),
parser::keyword(keyword::IF, EWhen::IfToken),
// TODO we should require space before the expression but not after
space0_around_ee(
specialize_ref(
specialize_err_ref(
EWhen::IfGuard,
increment_min_indent(expr_start(options))
),
@ -2239,7 +2249,7 @@ mod when {
backtrackable(space0_e(EWhen::IndentPattern)).parse(arena, state, min_indent)?;
let (_, loc_pattern, state) = space0_after_e(
specialize(EWhen::Pattern, crate::pattern::loc_pattern_help()),
specialize_err(EWhen::Pattern, crate::pattern::loc_pattern_help()),
EWhen::IndentPattern,
)
.parse(arena, state, min_indent)?;
@ -2284,7 +2294,7 @@ mod when {
let pattern_indent_column = state.column();
let parser =
sep_by1(word1(b'|', EWhen::Bar), branch_single_alternative());
sep_by1(byte(b'|', EWhen::Bar), branch_single_alternative());
match parser.parse(arena, state.clone(), pattern_indent) {
Err((MadeProgress, fail)) => Err((MadeProgress, fail)),
@ -2317,9 +2327,9 @@ mod when {
fn branch_result<'a>(indent: u32) -> impl Parser<'a, Loc<Expr<'a>>, EWhen<'a>> {
move |arena, state, _min_indent| {
skip_first!(
word2(b'-', b'>', EWhen::Arrow),
two_bytes(b'-', b'>', EWhen::Arrow),
space0_before_e(
specialize_ref(EWhen::Branch, loc_expr(true)),
specialize_err_ref(EWhen::Branch, loc_expr(true)),
EWhen::IndentBranch,
)
)
@ -2333,19 +2343,19 @@ fn if_branch<'a>() -> impl Parser<'a, (Loc<Expr<'a>>, Loc<Expr<'a>>), EIf<'a>> {
and!(
skip_second!(
space0_around_ee(
specialize_ref(EIf::Condition, loc_expr(true)),
specialize_err_ref(EIf::Condition, loc_expr(true)),
EIf::IndentCondition,
EIf::IndentThenToken,
),
parser::keyword_e(keyword::THEN, EIf::Then)
parser::keyword(keyword::THEN, EIf::Then)
),
space0_around_ee(
specialize_ref(EIf::ThenBranch, loc_expr(true)),
specialize_err_ref(EIf::ThenBranch, loc_expr(true)),
EIf::IndentThenBranch,
EIf::IndentElseToken,
)
),
parser::keyword_e(keyword::ELSE, EIf::Else)
parser::keyword(keyword::ELSE, EIf::Else)
)
}
@ -2354,10 +2364,10 @@ fn expect_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EExpe
let start_column = state.column();
let (_, _, state) =
parser::keyword_e(keyword::EXPECT, EExpect::Expect).parse(arena, state, min_indent)?;
parser::keyword(keyword::EXPECT, EExpect::Expect).parse(arena, state, min_indent)?;
let (_, condition, state) = space0_before_e(
specialize_ref(
specialize_err_ref(
EExpect::Condition,
set_min_indent(start_column + 1, expr_start(options)),
),
@ -2366,7 +2376,7 @@ fn expect_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EExpe
.parse(arena, state, start_column + 1)
.map_err(|(_, f)| (MadeProgress, f))?;
let parse_cont = specialize_ref(
let parse_cont = specialize_err_ref(
EExpect::Continuation,
space0_before_e(expr_start(options), EExpr::IndentEnd),
);
@ -2384,10 +2394,10 @@ fn dbg_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EExpect<
let start_column = state.column();
let (_, _, state) =
parser::keyword_e(keyword::DBG, EExpect::Dbg).parse(arena, state, min_indent)?;
parser::keyword(keyword::DBG, EExpect::Dbg).parse(arena, state, min_indent)?;
let (_, condition, state) = space0_before_e(
specialize_ref(
specialize_err_ref(
EExpect::Condition,
set_min_indent(start_column + 1, expr_start(options)),
),
@ -2396,7 +2406,7 @@ fn dbg_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EExpect<
.parse(arena, state, start_column + 1)
.map_err(|(_, f)| (MadeProgress, f))?;
let parse_cont = specialize_ref(
let parse_cont = specialize_err_ref(
EExpect::Continuation,
space0_before_e(expr_start(options), EExpr::IndentEnd),
);
@ -2412,7 +2422,7 @@ fn dbg_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EExpect<
fn if_expr_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EIf<'a>> {
move |arena: &'a Bump, state, min_indent| {
let (_, _, state) =
parser::keyword_e(keyword::IF, EIf::If).parse(arena, state, min_indent)?;
parser::keyword(keyword::IF, EIf::If).parse(arena, state, min_indent)?;
let mut branches = Vec::with_capacity_in(1, arena);
@ -2428,7 +2438,7 @@ fn if_expr_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EIf<
// NOTE this drops spaces between the `else` and the `if`
let optional_if = and!(
backtrackable(space0_e(EIf::IndentIf)),
parser::keyword_e(keyword::IF, EIf::If)
parser::keyword(keyword::IF, EIf::If)
);
match optional_if.parse(arena, state.clone(), min_indent) {
@ -2441,7 +2451,7 @@ fn if_expr_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EIf<
};
let (_, else_branch, state) = space0_before_e(
specialize_ref(EIf::ElseBranch, expr_start(options)),
specialize_err_ref(EIf::ElseBranch, expr_start(options)),
EIf::IndentElseBranch,
)
.parse(arena, state_final_else, min_indent)
@ -2549,10 +2559,10 @@ 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!(
word1(b'[', EList::Open),
specialize_ref(EList::Expr, loc_expr(false)),
word1(b',', EList::End),
word1(b']', EList::End),
byte(b'[', EList::Open),
specialize_err_ref(EList::Expr, loc_expr(false)),
byte(b',', EList::End),
byte(b']', EList::End),
Expr::SpaceBefore
),
|arena, elements: Collection<'a, _>| {
@ -2680,14 +2690,14 @@ pub fn record_field<'a>() -> impl Parser<'a, RecordField<'a>, ERecord<'a>> {
map_with_arena!(
and!(
specialize(|_, pos| ERecord::Field(pos), loc!(lowercase_ident())),
specialize_err(|_, pos| ERecord::Field(pos), loc!(lowercase_ident())),
and!(
spaces(),
optional(either!(
and!(word1(b':', ERecord::Colon), record_field_expr()),
and!(byte(b':', ERecord::Colon), record_field_expr()),
and!(
word1(b'?', ERecord::QuestionMark),
spaces_before(specialize_ref(ERecord::Expr, loc_expr(false)))
byte(b'?', ERecord::QuestionMark),
spaces_before(specialize_err_ref(ERecord::Expr, loc_expr(false)))
)
))
)
@ -2731,10 +2741,10 @@ fn record_field_expr<'a>() -> impl Parser<'a, RecordFieldExpr<'a>, ERecord<'a>>
spaces(),
either!(
and!(
word2(b'<', b'-', ERecord::Arrow),
spaces_before(specialize_ref(ERecord::Expr, loc_expr(false)))
two_bytes(b'<', b'-', ERecord::Arrow),
spaces_before(specialize_err_ref(ERecord::Expr, loc_expr(false)))
),
specialize_ref(ERecord::Expr, loc_expr(false))
specialize_err_ref(ERecord::Expr, loc_expr(false))
)
),
|arena: &'a bumpalo::Bump, (spaces, either)| {
@ -2755,7 +2765,7 @@ fn record_field_expr<'a>() -> impl Parser<'a, RecordFieldExpr<'a>, ERecord<'a>>
}
fn record_updateable_identifier<'a>() -> impl Parser<'a, Expr<'a>, ERecord<'a>> {
specialize(
specialize_err(
|_, pos| ERecord::Updateable(pos),
map_with_arena!(parse_ident, ident_to_expr),
)
@ -2768,7 +2778,7 @@ struct RecordHelp<'a> {
fn record_help<'a>() -> impl Parser<'a, RecordHelp<'a>, ERecord<'a>> {
between!(
word1(b'{', ERecord::Open),
byte(b'{', ERecord::Open),
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" }.
@ -2780,22 +2790,22 @@ fn record_help<'a>() -> impl Parser<'a, RecordHelp<'a>, ERecord<'a>> {
// (and not e.g. an `Expr::Access`) and extract its string.
loc!(record_updateable_identifier()),
),
word1(b'&', ERecord::Ampersand)
byte(b'&', ERecord::Ampersand)
))),
fields: collection_inner!(
loc!(record_field()),
word1(b',', ERecord::End),
byte(b',', ERecord::End),
RecordField::SpaceBefore
),
})),
word1(b'}', ERecord::End)
byte(b'}', ERecord::End)
)
}
fn record_literal_help<'a>() -> impl Parser<'a, Expr<'a>, EExpr<'a>> {
then(
and!(
specialize(EExpr::Record, record_help()),
specialize_err(EExpr::Record, record_help()),
// there can be field access, e.g. `{ x : 4 }.x`
record_field_access_chain()
),

View file

@ -4,8 +4,8 @@ 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::{optional, then};
use crate::parser::{specialize, word1, EPackageEntry, EPackageName, Parser};
use crate::string_literal;
use roc_module::symbol::{ModuleId, Symbol};
use roc_region::all::Loc;
@ -346,14 +346,14 @@ pub fn package_entry<'a>() -> impl Parser<'a, Spaced<'a, PackageEntry<'a>>, EPac
optional(and!(
skip_second!(
and!(
specialize(|_, pos| EPackageEntry::Shorthand(pos), lowercase_ident()),
specialize_err(|_, pos| EPackageEntry::Shorthand(pos), lowercase_ident()),
space0_e(EPackageEntry::IndentPackage)
),
word1(b':', EPackageEntry::Colon)
byte(b':', EPackageEntry::Colon)
),
space0_e(EPackageEntry::IndentPackage)
)),
loc!(specialize(EPackageEntry::BadPackage, package_name()))
loc!(specialize_err(EPackageEntry::BadPackage, package_name()))
),
move |arena, (opt_shorthand, package_or_path)| {
let entry = match opt_shorthand {
@ -380,7 +380,7 @@ 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(
loc!(specialize_err(
EPackageName::BadPath,
string_literal::parse_str_literal()
)),

View file

@ -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, increment_min_indent, optional, reset_min_indent, specialize, word1, word2,
EExposes, EGenerates, EGeneratesWith, EHeader, EImports, EPackages, EProvides, ERequires,
ETypedIdent, Parser, SourceError, SpaceProblem, SyntaxError,
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,
};
use crate::state::State;
use crate::string_literal::{self, parse_str_literal};
@ -31,7 +31,7 @@ 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(SyntaxError::Expr, crate::expr::toplevel_defs(),),
specialize_err(SyntaxError::Expr, crate::expr::toplevel_defs(),),
end_of_file()
)
}
@ -48,42 +48,42 @@ pub fn parse_header<'a>(
}
pub fn header<'a>() -> impl Parser<'a, Module<'a>, EHeader<'a>> {
use crate::parser::keyword_e;
use crate::parser::keyword;
record!(Module {
comments: space0_e(EHeader::IndentStart),
header: one_of![
map!(
skip_first!(
keyword_e("interface", EHeader::Start),
keyword("interface", EHeader::Start),
increment_min_indent(interface_header())
),
Header::Interface
),
map!(
skip_first!(
keyword_e("app", EHeader::Start),
keyword("app", EHeader::Start),
increment_min_indent(app_header())
),
Header::App
),
map!(
skip_first!(
keyword_e("package", EHeader::Start),
keyword("package", EHeader::Start),
increment_min_indent(package_header())
),
Header::Package
),
map!(
skip_first!(
keyword_e("platform", EHeader::Start),
keyword("platform", EHeader::Start),
increment_min_indent(platform_header())
),
Header::Platform
),
map!(
skip_first!(
keyword_e("hosted", EHeader::Start),
keyword("hosted", EHeader::Start),
increment_min_indent(hosted_header())
),
Header::Hosted
@ -97,8 +97,8 @@ 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)),
exposes: specialize(EHeader::Exposes, exposes_values()),
imports: specialize(EHeader::Imports, imports()),
exposes: specialize_err(EHeader::Exposes, exposes_values()),
imports: specialize_err(EHeader::Imports, imports()),
})
.trace("interface_header")
}
@ -108,10 +108,10 @@ 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)),
exposes: specialize(EHeader::Exposes, exposes_values()),
imports: specialize(EHeader::Imports, imports()),
generates: specialize(EHeader::Generates, generates()),
generates_with: specialize(EHeader::GeneratesWith, generates_with()),
exposes: specialize_err(EHeader::Exposes, exposes_values()),
imports: specialize_err(EHeader::Imports, imports()),
generates: specialize_err(EHeader::Generates, generates()),
generates_with: specialize_err(EHeader::GeneratesWith, generates_with()),
})
.trace("hosted_header")
}
@ -179,13 +179,13 @@ 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(
name: loc!(crate::parser::specialize_err(
EHeader::AppName,
string_literal::parse_str_literal()
)),
packages: optional(specialize(EHeader::Packages, packages())),
imports: optional(specialize(EHeader::Imports, imports())),
provides: specialize(EHeader::Provides, provides_to()),
packages: optional(specialize_err(EHeader::Packages, packages())),
imports: optional(specialize_err(EHeader::Imports, imports())),
provides: specialize_err(EHeader::Provides, provides_to()),
})
.trace("app_header")
}
@ -194,9 +194,9 @@ 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(EHeader::PackageName, package_name())),
exposes: specialize(EHeader::Exposes, exposes_modules()),
packages: specialize(EHeader::Packages, packages()),
name: loc!(specialize_err(EHeader::PackageName, package_name())),
exposes: specialize_err(EHeader::Exposes, exposes_modules()),
packages: specialize_err(EHeader::Packages, packages()),
})
.trace("package_header")
}
@ -205,23 +205,23 @@ 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(EHeader::PlatformName, package_name())),
requires: specialize(EHeader::Requires, requires()),
exposes: specialize(EHeader::Exposes, exposes_modules()),
packages: specialize(EHeader::Packages, packages()),
imports: specialize(EHeader::Imports, imports()),
provides: specialize(EHeader::Provides, provides_exposed()),
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()),
imports: specialize_err(EHeader::Imports, imports()),
provides: specialize_err(EHeader::Provides, provides_exposed()),
})
.trace("platform_header")
}
fn provides_to_package<'a>() -> impl Parser<'a, To<'a>, EProvides<'a>> {
one_of![
specialize(
specialize_err(
|_, pos| EProvides::Identifier(pos),
map!(lowercase_ident(), To::ExistingPackage)
),
specialize(EProvides::Package, map!(package_name(), To::NewPackage))
specialize_err(EProvides::Package, map!(package_name(), To::NewPackage))
]
}
@ -235,10 +235,10 @@ fn provides_to<'a>() -> impl Parser<'a, ProvidesTo<'a>, EProvides<'a>> {
EProvides::IndentListStart
),
entries: collection_trailing_sep_e!(
word1(b'[', EProvides::ListStart),
byte(b'[', EProvides::ListStart),
exposes_entry(EProvides::Identifier),
word1(b',', EProvides::ListEnd),
word1(b']', EProvides::ListEnd),
byte(b',', EProvides::ListEnd),
byte(b']', EProvides::ListEnd),
Spaced::SpaceBefore
),
types: optional(backtrackable(provides_types())),
@ -266,10 +266,10 @@ fn provides_exposed<'a>() -> impl Parser<
EProvides::IndentListStart
),
item: collection_trailing_sep_e!(
word1(b'[', EProvides::ListStart),
byte(b'[', EProvides::ListStart),
exposes_entry(EProvides::Identifier),
word1(b',', EProvides::ListEnd),
word1(b']', EProvides::ListEnd),
byte(b',', EProvides::ListEnd),
byte(b']', EProvides::ListEnd),
Spaced::SpaceBefore
),
})
@ -283,7 +283,7 @@ 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!(word1(
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,
@ -291,10 +291,10 @@ fn provides_types<'a>(
EProvides::Provides
)),
collection_trailing_sep_e!(
word1(b'{', EProvides::ListStart),
byte(b'{', EProvides::ListStart),
provides_type_entry(EProvides::Identifier),
word1(b',', EProvides::ListEnd),
word1(b'}', EProvides::ListEnd),
byte(b',', EProvides::ListEnd),
byte(b'}', EProvides::ListEnd),
Spaced::SpaceBefore
)
)
@ -309,7 +309,7 @@ where
E: 'a,
{
loc!(map!(
specialize(|_, pos| to_expectation(pos), ident::uppercase()),
specialize_err(|_, pos| to_expectation(pos), ident::uppercase()),
Spaced::Item
))
}
@ -323,7 +323,7 @@ where
E: 'a,
{
loc!(map!(
specialize(|_, pos| to_expectation(pos), unqualified_ident()),
specialize_err(|_, pos| to_expectation(pos), unqualified_ident()),
|n| Spaced::Item(ExposedName::new(n))
))
}
@ -354,13 +354,13 @@ fn platform_requires<'a>() -> impl Parser<'a, PlatformRequires<'a>, ERequires<'a
fn requires_rigids<'a>(
) -> impl Parser<'a, Collection<'a, Loc<Spaced<'a, UppercaseIdent<'a>>>>, ERequires<'a>> {
collection_trailing_sep_e!(
word1(b'{', ERequires::ListStart),
specialize(
byte(b'{', ERequires::ListStart),
specialize_err(
|_, pos| ERequires::Rigid(pos),
loc!(map!(ident::uppercase(), Spaced::Item))
),
word1(b',', ERequires::ListEnd),
word1(b'}', ERequires::ListEnd),
byte(b',', ERequires::ListEnd),
byte(b'}', ERequires::ListEnd),
Spaced::SpaceBefore
)
}
@ -368,14 +368,14 @@ fn requires_rigids<'a>(
#[inline(always)]
fn requires_typed_ident<'a>() -> impl Parser<'a, Loc<Spaced<'a, TypedIdent<'a>>>, ERequires<'a>> {
skip_first!(
word1(b'{', ERequires::ListStart),
byte(b'{', ERequires::ListStart),
skip_second!(
reset_min_indent(space0_around_ee(
specialize(ERequires::TypedIdent, loc!(typed_ident()),),
specialize_err(ERequires::TypedIdent, loc!(typed_ident()),),
ERequires::ListStart,
ERequires::ListEnd
)),
word1(b'}', ERequires::ListStart)
byte(b'}', ERequires::ListStart)
)
)
}
@ -394,10 +394,10 @@ fn exposes_values<'a>() -> impl Parser<
EExposes::IndentListStart
),
item: collection_trailing_sep_e!(
word1(b'[', EExposes::ListStart),
byte(b'[', EExposes::ListStart),
exposes_entry(EExposes::Identifier),
word1(b',', EExposes::ListEnd),
word1(b']', EExposes::ListEnd),
byte(b',', EExposes::ListEnd),
byte(b']', EExposes::ListEnd),
Spaced::SpaceBefore
)
})
@ -416,7 +416,7 @@ where
and!(
skip_second!(
backtrackable(space0_e(indent_problem1)),
crate::parser::keyword_e(K::KEYWORD, expectation)
crate::parser::keyword(K::KEYWORD, expectation)
),
space0_e(indent_problem2)
),
@ -444,10 +444,10 @@ fn exposes_modules<'a>() -> impl Parser<
EExposes::IndentListStart
),
item: collection_trailing_sep_e!(
word1(b'[', EExposes::ListStart),
byte(b'[', EExposes::ListStart),
exposes_module(EExposes::Identifier),
word1(b',', EExposes::ListEnd),
word1(b']', EExposes::ListEnd),
byte(b',', EExposes::ListEnd),
byte(b']', EExposes::ListEnd),
Spaced::SpaceBefore
),
})
@ -462,7 +462,7 @@ where
E: 'a,
{
loc!(map!(
specialize(|_, pos| to_expectation(pos), module_name()),
specialize_err(|_, pos| to_expectation(pos), module_name()),
Spaced::Item
))
}
@ -481,10 +481,10 @@ fn packages<'a>() -> impl Parser<
EPackages::IndentListStart
),
item: collection_trailing_sep_e!(
word1(b'{', EPackages::ListStart),
specialize(EPackages::PackageEntry, loc!(package_entry())),
word1(b',', EPackages::ListEnd),
word1(b'}', EPackages::ListEnd),
byte(b'{', EPackages::ListStart),
specialize_err(EPackages::PackageEntry, loc!(package_entry())),
byte(b',', EPackages::ListEnd),
byte(b'}', EPackages::ListEnd),
Spaced::SpaceBefore
)
})
@ -500,7 +500,7 @@ fn generates<'a>(
EGenerates::IndentGenerates,
EGenerates::IndentTypeStart
),
item: specialize(|(), pos| EGenerates::Identifier(pos), uppercase())
item: specialize_err(|(), pos| EGenerates::Identifier(pos), uppercase())
})
}
@ -518,10 +518,10 @@ fn generates_with<'a>() -> impl Parser<
EGeneratesWith::IndentListStart
),
item: collection_trailing_sep_e!(
word1(b'[', EGeneratesWith::ListStart),
byte(b'[', EGeneratesWith::ListStart),
exposes_entry(EGeneratesWith::Identifier),
word1(b',', EGeneratesWith::ListEnd),
word1(b']', EGeneratesWith::ListEnd),
byte(b',', EGeneratesWith::ListEnd),
byte(b']', EGeneratesWith::ListEnd),
Spaced::SpaceBefore
)
})
@ -541,10 +541,10 @@ fn imports<'a>() -> impl Parser<
EImports::IndentListStart
),
item: collection_trailing_sep_e!(
word1(b'[', EImports::ListStart),
byte(b'[', EImports::ListStart),
loc!(imports_entry()),
word1(b',', EImports::ListEnd),
word1(b']', EImports::ListEnd),
byte(b',', EImports::ListEnd),
byte(b']', EImports::ListEnd),
Spaced::SpaceBefore
)
})
@ -559,16 +559,16 @@ fn typed_ident<'a>() -> impl Parser<'a, Spaced<'a, TypedIdent<'a>>, ETypedIdent<
map!(
and!(
and!(
loc!(specialize(
loc!(specialize_err(
|_, pos| ETypedIdent::Identifier(pos),
lowercase_ident()
)),
space0_e(ETypedIdent::IndentHasType)
),
skip_first!(
word1(b':', ETypedIdent::HasType),
byte(b':', ETypedIdent::HasType),
space0_before_e(
specialize(
specialize_err(
ETypedIdent::Type,
reset_min_indent(type_annotation::located(true))
),
@ -587,7 +587,7 @@ fn typed_ident<'a>() -> impl Parser<'a, Spaced<'a, TypedIdent<'a>>, ETypedIdent<
}
fn shortname<'a>() -> impl Parser<'a, &'a str, EImports> {
specialize(|_, pos| EImports::Shorthand(pos), lowercase_ident())
specialize_err(|_, pos| EImports::Shorthand(pos), lowercase_ident())
}
fn module_name_help<'a, F, E>(to_expectation: F) -> impl Parser<'a, ModuleName<'a>, E>
@ -596,7 +596,7 @@ where
E: 'a,
F: 'a,
{
specialize(move |_, pos| to_expectation(pos), module_name())
specialize_err(move |_, pos| to_expectation(pos), module_name())
}
#[inline(always)]
@ -613,19 +613,19 @@ fn imports_entry<'a>() -> impl Parser<'a, Spaced<'a, ImportsEntry<'a>>, EImports
// e.g. `pf.`
optional(backtrackable(skip_second!(
shortname(),
word1(b'.', EImports::ShorthandDot)
byte(b'.', EImports::ShorthandDot)
))),
// e.g. `Task`
module_name_help(EImports::ModuleName)
),
// e.g. `.{ Task, after}`
optional(skip_first!(
word1(b'.', EImports::ExposingDot),
byte(b'.', EImports::ExposingDot),
collection_trailing_sep_e!(
word1(b'{', EImports::SetStart),
byte(b'{', EImports::SetStart),
exposes_entry(EImports::Identifier),
word1(b',', EImports::SetEnd),
word1(b'}', EImports::SetEnd),
byte(b',', EImports::SetEnd),
byte(b'}', EImports::SetEnd),
Spaced::SpaceBefore
)
))
@ -650,18 +650,18 @@ fn imports_entry<'a>() -> impl Parser<'a, Spaced<'a, ImportsEntry<'a>>, EImports
and!(
// e.g. "filename"
// TODO: str literal allows for multiline strings. We probably don't want that for file names.
specialize(|_, pos| EImports::StrLiteral(pos), parse_str_literal()),
specialize_err(|_, pos| EImports::StrLiteral(pos), parse_str_literal()),
// e.g. as
and!(
and!(
space0_e(EImports::AsKeyword),
word2(b'a', b's', EImports::AsKeyword)
two_bytes(b'a', b's', EImports::AsKeyword)
),
space0_e(EImports::AsKeyword)
)
),
// e.g. file : Str
specialize(|_, pos| EImports::TypedIdent(pos), typed_ident())
specialize_err(|_, pos| EImports::TypedIdent(pos), typed_ident())
),
|((file_name, _), typed_ident)| {
// TODO: look at blacking block strings during parsing.

File diff suppressed because it is too large Load diff

View file

@ -4,8 +4,8 @@ use crate::ident::{lowercase_ident, parse_ident, Accessor, Ident};
use crate::keyword;
use crate::parser::Progress::{self, *};
use crate::parser::{
self, backtrackable, fail_when, optional, specialize, specialize_ref, then, word1, word2,
word3, EPattern, PInParens, PList, PRecord, Parser,
self, backtrackable, byte, fail_when, optional, specialize_err, specialize_err_ref, then,
three_bytes, two_bytes, EPattern, PInParens, PList, PRecord, Parser,
};
use crate::state::State;
use crate::string_literal::StrLikeLiteral;
@ -33,13 +33,13 @@ pub fn closure_param<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, EPattern<'a>> {
// Underscore is also common, e.g. \_ -> ...
loc!(underscore_pattern_help()),
// You can destructure records in params, e.g. \{ x, y } -> ...
loc!(specialize(
loc!(specialize_err(
EPattern::Record,
crate::pattern::record_pattern_help()
)),
// If you wrap it in parens, you can match any arbitrary pattern at all.
// e.g. \User.UserId userId -> ...
specialize(EPattern::PInParens, loc_pattern_in_parens_help())
specialize_err(EPattern::PInParens, loc_pattern_in_parens_help())
)
}
@ -75,14 +75,14 @@ pub fn loc_pattern_help<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, EPattern<'a>>
fn loc_pattern_help_help<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, EPattern<'a>> {
one_of!(
specialize(EPattern::PInParens, loc_pattern_in_parens_help()),
specialize_err(EPattern::PInParens, loc_pattern_in_parens_help()),
loc!(underscore_pattern_help()),
loc_ident_pattern_help(true),
loc!(specialize(
loc!(specialize_err(
EPattern::Record,
crate::pattern::record_pattern_help()
)),
loc!(specialize(EPattern::List, list_pattern_help())),
loc!(specialize_err(EPattern::List, list_pattern_help())),
loc!(number_pattern_help()),
loc!(string_like_pattern_help()),
)
@ -91,7 +91,7 @@ fn loc_pattern_help_help<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, EPattern<'a>
fn pattern_as<'a>() -> impl Parser<'a, PatternAs<'a>, EPattern<'a>> {
move |arena, state: State<'a>, min_indent| {
let (_, _, state) =
parser::keyword_e(keyword::AS, EPattern::AsKeyword).parse(arena, state, min_indent)?;
parser::keyword(keyword::AS, EPattern::AsKeyword).parse(arena, state, min_indent)?;
let (_, spaces, state) =
space0_e(EPattern::AsIdentifier).parse(arena, state, min_indent)?;
@ -176,11 +176,11 @@ pub fn loc_implements_parser<'a>() -> impl Parser<'a, Loc<Implements<'a>>, EPatt
fn loc_parse_tag_pattern_arg<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, EPattern<'a>> {
one_of!(
specialize(EPattern::PInParens, loc_pattern_in_parens_help()),
specialize_err(EPattern::PInParens, loc_pattern_in_parens_help()),
loc!(underscore_pattern_help()),
// Make sure `Foo Bar 1` is parsed as `Foo (Bar) 1`, and not `Foo (Bar 1)`
loc_ident_pattern_help(false),
loc!(specialize(
loc!(specialize_err(
EPattern::Record,
crate::pattern::record_pattern_help()
)),
@ -192,10 +192,10 @@ fn loc_parse_tag_pattern_arg<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, EPattern
fn loc_pattern_in_parens_help<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, PInParens<'a>> {
then(
loc!(collection_trailing_sep_e!(
word1(b'(', PInParens::Open),
specialize_ref(PInParens::Pattern, loc_pattern_help()),
word1(b',', PInParens::End),
word1(b')', PInParens::End),
byte(b'(', PInParens::Open),
specialize_err_ref(PInParens::Pattern, loc_pattern_help()),
byte(b',', PInParens::End),
byte(b')', PInParens::End),
Pattern::SpaceBefore
)),
move |_arena, state, _, loc_elements| {
@ -222,7 +222,7 @@ fn loc_pattern_in_parens_help<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, PInPare
}
fn number_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, EPattern<'a>> {
specialize(
specialize_err(
EPattern::NumLiteral,
map!(crate::number_literal::number_literal(), |literal| {
use crate::number_literal::NumLiteral::*;
@ -245,7 +245,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(
specialize_err(
|_, pos| EPattern::Start(pos),
map_with_arena!(
crate::string_literal::parse_str_like_literal(),
@ -263,10 +263,10 @@ 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!(
word1(b'[', PList::Open),
byte(b'[', PList::Open),
list_element_pattern(),
word1(b',', PList::End),
word1(b']', PList::End),
byte(b',', PList::End),
byte(b']', PList::End),
Pattern::SpaceBefore
),
Pattern::List
@ -277,18 +277,21 @@ fn list_element_pattern<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, PList<'a>> {
one_of!(
three_list_rest_pattern_error(),
list_rest_pattern(),
specialize_ref(PList::Pattern, loc_pattern_help()),
specialize_err_ref(PList::Pattern, loc_pattern_help()),
)
}
fn three_list_rest_pattern_error<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, PList<'a>> {
fail_when(PList::Rest, loc!(word3(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<Pattern<'a>>, PList<'a>> {
move |arena: &'a Bump, state: State<'a>, min_indent: u32| {
let (_, loc_word, state) =
loc!(word2(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));
@ -323,8 +326,9 @@ 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(|_, 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) => {
@ -449,7 +453,7 @@ fn loc_ident_pattern_help<'a>(
fn underscore_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, EPattern<'a>> {
map!(
skip_first!(
word1(b'_', EPattern::Underscore),
byte(b'_', EPattern::Underscore),
optional(lowercase_ident_pattern())
),
|output| match output {
@ -460,17 +464,17 @@ fn underscore_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, EPattern<'a>> {
}
fn lowercase_ident_pattern<'a>() -> impl Parser<'a, &'a str, EPattern<'a>> {
specialize(move |_, pos| EPattern::End(pos), lowercase_ident())
specialize_err(move |_, pos| EPattern::End(pos), lowercase_ident())
}
#[inline(always)]
fn record_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, PRecord<'a>> {
map!(
collection_trailing_sep_e!(
word1(b'{', PRecord::Open),
byte(b'{', PRecord::Open),
record_pattern_field(),
word1(b',', PRecord::End),
word1(b'}', PRecord::End),
byte(b',', PRecord::End),
byte(b'}', PRecord::End),
Pattern::SpaceBefore
),
Pattern::RecordDestructure
@ -484,7 +488,7 @@ fn record_pattern_field<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, 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(
let (progress, loc_label, state) = loc!(specialize_err(
move |_, _| PRecord::Field(pos),
lowercase_ident()
))
@ -496,14 +500,14 @@ fn record_pattern_field<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, 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!(
word1(b':', PRecord::Colon),
word1(b'?', PRecord::Optional)
byte(b':', PRecord::Colon),
byte(b'?', PRecord::Optional)
))
.parse(arena, state, min_indent)?;
match opt_loc_val {
Some(First(_)) => {
let val_parser = specialize_ref(PRecord::Pattern, loc_pattern_help());
let val_parser = specialize_err_ref(PRecord::Pattern, loc_pattern_help());
let (_, loc_val, state) =
spaces_before(val_parser).parse(arena, state, min_indent)?;
@ -529,7 +533,7 @@ fn record_pattern_field<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, PRecord<'a>>
))
}
Some(Second(_)) => {
let val_parser = specialize_ref(PRecord::Expr, crate::expr::loc_expr(false));
let val_parser = specialize_err_ref(PRecord::Expr, crate::expr::loc_expr(false));
let (_, loc_val, state) =
spaces_before(val_parser).parse(arena, state, min_indent)?;

View file

@ -2,7 +2,7 @@ use crate::ast::{EscapedChar, SingleQuoteLiteral, StrLiteral, StrSegment};
use crate::expr;
use crate::parser::Progress::{self, *};
use crate::parser::{
allocated, loc, reset_min_indent, specialize_ref, then, word1, BadInputError, ESingleQuote,
allocated, byte, loc, reset_min_indent, specialize_err_ref, then, BadInputError, ESingleQuote,
EString, Parser,
};
use crate::state::State;
@ -175,11 +175,11 @@ pub fn parse_str_like_literal<'a>() -> impl Parser<'a, StrLikeLiteral<'a>, EStri
let mut preceded_by_dollar = false;
while let Some(&byte) = bytes.next() {
while let Some(&one_byte) = bytes.next() {
// This is for the byte we just grabbed from the iterator.
segment_parsed_bytes += 1;
match byte {
match one_byte {
b'"' if !is_single_quote => {
if segment_parsed_bytes == 1 && segments.is_empty() {
// special case of the empty string
@ -375,11 +375,11 @@ pub fn parse_str_like_literal<'a>() -> impl Parser<'a, StrLikeLiteral<'a>, EStri
// canonicalization error if that expression variant
// is not allowed inside a string interpolation.
let (_progress, loc_expr, new_state) = skip_second!(
specialize_ref(
specialize_err_ref(
EString::Format,
loc(allocated(reset_min_indent(expr::expr_help())))
),
word1(b')', EString::FormatEnd)
byte(b')', EString::FormatEnd)
)
.parse(arena, state, min_indent)?;
@ -404,9 +404,9 @@ pub fn parse_str_like_literal<'a>() -> impl Parser<'a, StrLikeLiteral<'a>, EStri
// give a canonicalization error if the digits form
// an invalid unicode code point.
let (_progress, loc_digits, new_state) = between!(
word1(b'(', EString::CodePtOpen),
byte(b'(', EString::CodePtOpen),
loc(ascii_hex_digits()),
word1(b')', EString::CodePtEnd)
byte(b')', EString::CodePtEnd)
)
.parse(arena, state, min_indent)?;
@ -484,11 +484,11 @@ pub fn parse_str_like_literal<'a>() -> impl Parser<'a, StrLikeLiteral<'a>, EStri
// Parse an arbitrary expression, followed by ')'
let (_progress, loc_expr, new_state) = skip_second!(
specialize_ref(
specialize_err_ref(
EString::Format,
loc(allocated(reset_min_indent(expr::expr_help())))
),
word1(b')', EString::FormatEnd)
byte(b')', EString::FormatEnd)
)
.parse(arena, state, min_indent)?;
@ -510,7 +510,7 @@ pub fn parse_str_like_literal<'a>() -> impl Parser<'a, StrLikeLiteral<'a>, EStri
// iff the '$' is followed by '(', this is string interpolation.
// We'll check for the '(' on the next iteration of the loop.
preceded_by_dollar = byte == b'$';
preceded_by_dollar = one_byte == b'$';
}
// We ran out of characters before finding a closed quote

View file

@ -12,8 +12,8 @@ use crate::parser::{
absolute_column_min_indent, increment_min_indent, then, ERecord, ETypeAbilityImpl,
};
use crate::parser::{
allocated, backtrackable, fail, optional, specialize, specialize_ref, word, word1, word2,
EType, ETypeApply, ETypeInParens, ETypeInlineAlias, ETypeRecord, ETypeTagUnion, Parser,
allocated, backtrackable, byte, fail, optional, specialize_err, specialize_err_ref, two_bytes,
word, EType, ETypeApply, ETypeInParens, ETypeInlineAlias, ETypeRecord, ETypeTagUnion, Parser,
Progress::{self, *},
};
use crate::state::State;
@ -39,16 +39,16 @@ fn tag_union_type<'a>(
) -> impl Parser<'a, TypeAnnotation<'a>, ETypeTagUnion<'a>> {
move |arena, state, min_indent| {
let (_, tags, state) = collection_trailing_sep_e!(
word1(b'[', ETypeTagUnion::Open),
byte(b'[', ETypeTagUnion::Open),
loc!(tag_type(false)),
word1(b',', ETypeTagUnion::End),
word1(b']', ETypeTagUnion::End),
byte(b',', ETypeTagUnion::End),
byte(b']', ETypeTagUnion::End),
Tag::SpaceBefore
)
.parse(arena, state, min_indent)?;
// This could be an open tag union, e.g. `[Foo, Bar]a`
let (_, ext, state) = optional(allocated(specialize_ref(
let (_, ext, state) = optional(allocated(specialize_err_ref(
ETypeTagUnion::Type,
term(stop_at_surface_has),
)))
@ -114,9 +114,12 @@ fn term<'a>(stop_at_surface_has: bool) -> impl Parser<'a, Loc<TypeAnnotation<'a>
one_of!(
loc_wildcard(),
loc_inferred(),
specialize(EType::TInParens, loc_type_in_parens(stop_at_surface_has)),
loc!(specialize(EType::TRecord, record_type(stop_at_surface_has))),
loc!(specialize(
specialize_err(EType::TInParens, loc_type_in_parens(stop_at_surface_has)),
loc!(specialize_err(
EType::TRecord,
record_type(stop_at_surface_has)
)),
loc!(specialize_err(
EType::TTagUnion,
tag_union_type(stop_at_surface_has)
)),
@ -130,7 +133,7 @@ fn term<'a>(stop_at_surface_has: bool) -> impl Parser<'a, Loc<TypeAnnotation<'a>
and!(
skip_second!(
backtrackable(space0_e(EType::TIndentEnd)),
crate::parser::keyword_e(keyword::AS, EType::TEnd)
crate::parser::keyword(keyword::AS, EType::TEnd)
),
parse_type_alias_after_as()
),
@ -160,7 +163,7 @@ fn term<'a>(stop_at_surface_has: bool) -> impl Parser<'a, Loc<TypeAnnotation<'a>
/// The `*` type variable, e.g. in (List *) Wildcard,
fn loc_wildcard<'a>() -> impl Parser<'a, Loc<TypeAnnotation<'a>>, EType<'a>> {
map!(loc!(word1(b'*', EType::TWildcard)), |loc_val: Loc<()>| {
map!(loc!(byte(b'*', EType::TWildcard)), |loc_val: Loc<()>| {
loc_val.map(|_| TypeAnnotation::Wildcard)
})
}
@ -204,13 +207,16 @@ fn loc_applied_arg<'a>(
one_of!(
loc_wildcard(),
loc_inferred(),
specialize(EType::TInParens, loc_type_in_parens(stop_at_surface_has)),
loc!(specialize(EType::TRecord, record_type(stop_at_surface_has))),
loc!(specialize(
specialize_err(EType::TInParens, loc_type_in_parens(stop_at_surface_has)),
loc!(specialize_err(
EType::TRecord,
record_type(stop_at_surface_has)
)),
loc!(specialize_err(
EType::TTagUnion,
tag_union_type(stop_at_surface_has)
)),
loc!(specialize(EType::TApply, concrete_type())),
loc!(specialize_err(EType::TApply, concrete_type())),
loc!(parse_type_variable(stop_at_surface_has))
)
),
@ -231,13 +237,13 @@ fn loc_type_in_parens<'a>(
then(
loc!(and!(
collection_trailing_sep_e!(
word1(b'(', ETypeInParens::Open),
specialize_ref(ETypeInParens::Type, expression(true, false)),
word1(b',', ETypeInParens::End),
word1(b')', ETypeInParens::End),
byte(b'(', ETypeInParens::Open),
specialize_err_ref(ETypeInParens::Type, expression(true, false)),
byte(b',', ETypeInParens::End),
byte(b')', ETypeInParens::End),
TypeAnnotation::SpaceBefore
),
optional(allocated(specialize_ref(
optional(allocated(specialize_err_ref(
ETypeInParens::Type,
term(stop_at_surface_has)
)))
@ -271,7 +277,7 @@ fn tag_type<'a>(stop_at_surface_has: bool) -> impl Parser<'a, Tag<'a>, ETypeTagU
loc!(parse_tag_name(ETypeTagUnion::End)).parse(arena, state, min_indent)?;
let (_, args, state) =
specialize_ref(ETypeTagUnion::Type, loc_applied_args_e(stop_at_surface_has))
specialize_err_ref(ETypeTagUnion::Type, loc_applied_args_e(stop_at_surface_has))
.parse(arena, state, min_indent)?;
let result = Tag::Apply {
@ -307,7 +313,7 @@ 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(
let (progress, loc_label, state) = loc!(specialize_err(
move |_, _| ETypeRecord::Field(pos),
lowercase_ident_keyword_e()
))
@ -320,12 +326,12 @@ 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!(
word1(b':', ETypeRecord::Colon),
word1(b'?', ETypeRecord::Optional)
byte(b':', ETypeRecord::Colon),
byte(b'?', ETypeRecord::Optional)
))
.parse(arena, state, min_indent)?;
let val_parser = specialize_ref(ETypeRecord::Type, expression(true, false));
let val_parser = specialize_err_ref(ETypeRecord::Type, expression(true, false));
match opt_loc_val {
Some(First(_)) => {
@ -370,13 +376,13 @@ fn record_type<'a>(
) -> impl Parser<'a, TypeAnnotation<'a>, ETypeRecord<'a>> {
record!(TypeAnnotation::Record {
fields: collection_trailing_sep_e!(
word1(b'{', ETypeRecord::Open),
byte(b'{', ETypeRecord::Open),
loc!(record_type_field()),
word1(b',', ETypeRecord::End),
word1(b'}', ETypeRecord::End),
byte(b',', ETypeRecord::End),
byte(b'}', ETypeRecord::End),
AssignedField::SpaceBefore
),
ext: optional(allocated(specialize_ref(
ext: optional(allocated(specialize_err_ref(
ETypeRecord::Type,
term(stop_at_surface_has)
)))
@ -387,7 +393,7 @@ fn record_type<'a>(
fn applied_type<'a>(stop_at_surface_has: bool) -> impl Parser<'a, TypeAnnotation<'a>, EType<'a>> {
map!(
and!(
specialize(EType::TApply, concrete_type()),
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)
@ -421,14 +427,14 @@ fn ability_chain<'a>() -> impl Parser<'a, Vec<'a, Loc<TypeAnnotation<'a>>>, ETyp
map!(
and!(
space0_before_optional_after(
specialize(EType::TApply, loc!(concrete_type())),
specialize_err(EType::TApply, loc!(concrete_type())),
EType::TIndentStart,
EType::TIndentEnd,
),
zero_or_more!(skip_first!(
word1(b'&', EType::TImplementsClause),
byte(b'&', EType::TImplementsClause),
space0_before_optional_after(
specialize(EType::TApply, loc!(concrete_type())),
specialize_err(EType::TApply, loc!(concrete_type())),
EType::TIndentStart,
EType::TIndentEnd,
)
@ -450,7 +456,7 @@ fn implements_clause<'a>() -> impl Parser<'a, Loc<ImplementsClause<'a>>, EType<'
and!(
space0_around_ee(
// Parse "a", with appropriate spaces
specialize(
specialize_err(
|_, pos| EType::TBadTypeVariable(pos),
loc!(map!(lowercase_ident(), Spaced::Item)),
),
@ -494,7 +500,7 @@ fn implements_clause_chain<'a>(
let (_, first_clause, state) = implements_clause().parse(arena, state, min_indent)?;
let (_, mut clauses, state) = zero_or_more!(skip_first!(
word1(b',', EType::TImplementsClause),
byte(b',', EType::TImplementsClause),
implements_clause()
))
.parse(arena, state, min_indent)?;
@ -519,10 +525,10 @@ pub fn implements_abilities<'a>() -> impl Parser<'a, Loc<ImplementsAbilities<'a>
space0_before_e(
loc!(map!(
collection_trailing_sep_e!(
word1(b'[', EType::TStart),
byte(b'[', EType::TStart),
loc!(parse_implements_ability()),
word1(b',', EType::TEnd),
word1(b']', EType::TEnd),
byte(b',', EType::TEnd),
byte(b']', EType::TEnd),
ImplementsAbility::SpaceBefore
),
ImplementsAbilities::Implements
@ -534,16 +540,16 @@ pub fn implements_abilities<'a>() -> impl Parser<'a, Loc<ImplementsAbilities<'a>
fn parse_implements_ability<'a>() -> impl Parser<'a, ImplementsAbility<'a>, EType<'a>> {
increment_min_indent(record!(ImplementsAbility::ImplementsAbility {
ability: loc!(specialize(EType::TApply, concrete_type())),
ability: loc!(specialize_err(EType::TApply, concrete_type())),
impls: optional(backtrackable(space0_before_e(
loc!(map!(
specialize(
specialize_err(
EType::TAbilityImpl,
collection_trailing_sep_e!(
word1(b'{', ETypeAbilityImpl::Open),
specialize(|e: ERecord<'_>, _| e.into(), loc!(ability_impl_field())),
word1(b',', ETypeAbilityImpl::End),
word1(b'}', ETypeAbilityImpl::End),
byte(b'{', ETypeAbilityImpl::Open),
specialize_err(|e: ERecord<'_>, _| e.into(), loc!(ability_impl_field())),
byte(b',', ETypeAbilityImpl::End),
byte(b'}', ETypeAbilityImpl::End),
AssignedField::SpaceBefore
)
),
@ -573,7 +579,7 @@ fn expression<'a>(
let result = and![
zero_or_more!(skip_first!(
word1(b',', EType::TFunctionArgument),
byte(b',', EType::TFunctionArgument),
one_of![
space0_around_ee(
term(stop_at_surface_has),
@ -586,7 +592,7 @@ fn expression<'a>(
.trace("type_annotation:expression:rest_args"),
skip_second!(
space0_e(EType::TIndentStart),
word2(b'-', b'>', EType::TStart)
two_bytes(b'-', b'>', EType::TStart)
)
.trace("type_annotation:expression:arrow")
]
@ -625,7 +631,7 @@ fn expression<'a>(
if !is_trailing_comma_valid {
let (_, comma, _) = optional(backtrackable(skip_first!(
space0_e(EType::TIndentStart),
word1(b',', EType::TStart)
byte(b',', EType::TStart)
)))
.trace("check trailing comma")
.parse(arena, state.clone(), min_indent)?;