mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-03 19:58:18 +00:00
Merge pull request #6548 from roboteng/parser-docs
Parser docs examples
This commit is contained in:
commit
30b5943b54
9 changed files with 1221 additions and 326 deletions
2
.github/workflows/ci_manager.yml
vendored
2
.github/workflows/ci_manager.yml
vendored
|
@ -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
|
||||
|
|
3
.github/workflows/ubuntu_x86_64.yml
vendored
3
.github/workflows/ubuntu_x86_64.yml
vendored
|
@ -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
|
||||
|
||||
|
|
|
@ -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()
|
||||
),
|
||||
|
|
|
@ -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()
|
||||
)),
|
||||
|
|
|
@ -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
|
@ -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)?;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)?;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue