mirror of
https://github.com/roc-lang/roc.git
synced 2025-08-03 03:42:17 +00:00
misc improvements
This commit is contained in:
parent
ef68183a92
commit
59ab438c1e
8 changed files with 402 additions and 367 deletions
|
@ -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,
|
||||
|
@ -2076,16 +2086,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,
|
||||
),
|
||||
|
@ -2093,10 +2103,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
|
||||
)
|
||||
)
|
||||
|
@ -2119,9 +2129,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,
|
||||
)
|
||||
),
|
||||
|
@ -2130,7 +2140,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)
|
||||
)
|
||||
),
|
||||
|
@ -2227,10 +2237,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))
|
||||
),
|
||||
|
@ -2251,7 +2261,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)?;
|
||||
|
@ -2296,7 +2306,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)),
|
||||
|
@ -2329,9 +2339,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,
|
||||
)
|
||||
)
|
||||
|
@ -2345,19 +2355,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)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -2366,10 +2376,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)),
|
||||
),
|
||||
|
@ -2378,7 +2388,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),
|
||||
);
|
||||
|
@ -2396,10 +2406,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)),
|
||||
),
|
||||
|
@ -2408,7 +2418,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),
|
||||
);
|
||||
|
@ -2424,7 +2434,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);
|
||||
|
||||
|
@ -2440,7 +2450,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) {
|
||||
|
@ -2453,7 +2463,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)
|
||||
|
@ -2554,10 +2564,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, _>| {
|
||||
|
@ -2685,14 +2695,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)))
|
||||
)
|
||||
))
|
||||
)
|
||||
|
@ -2736,10 +2746,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)| {
|
||||
|
@ -2760,7 +2770,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),
|
||||
)
|
||||
|
@ -2773,7 +2783,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" }.
|
||||
|
@ -2785,22 +2795,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.
|
||||
|
|
|
@ -821,8 +821,8 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates a parser that allocates its output and returns a reference to it.
|
||||
/// The new parser acts the same if its inner parser fails
|
||||
/// Allocates the output of the given parser and returns a reference to it.
|
||||
/// This also happens if the given parser fails.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@ -864,8 +864,8 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates a parser from two other parsers.
|
||||
/// However, the second parser is created based on the results of the first parser
|
||||
/// Apply transform function to turn output of given parser into another parser.
|
||||
/// Can be used to chain two parsers.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
|
@ -929,6 +929,7 @@ where
|
|||
/// # }
|
||||
/// # let arena = Bump::new();
|
||||
/// let parser_inner = word("hello", Problem::NotFound);
|
||||
///
|
||||
/// let parser = then(parser_inner,
|
||||
/// |arena, new_state, progress, output| {
|
||||
/// // arbitrary check
|
||||
|
@ -959,14 +960,14 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates a parser that matches a word exactly, useful when finding a keyword.
|
||||
/// This only matches if the next char is whitespace, the start of a comment, or the end of the file.
|
||||
/// Matches a word/string exactly, useful when finding a keyword.
|
||||
/// This only matches if the next char is whitespace, the start of a comment, or the end of a line.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// # #![forbid(unused_imports)]
|
||||
/// # use roc_parse::state::State;
|
||||
/// # use crate::roc_parse::parser::{Parser, Progress, keyword_e};
|
||||
/// # use crate::roc_parse::parser::{Parser, Progress, keyword};
|
||||
/// # use roc_region::all::Position;
|
||||
/// # use bumpalo::Bump;
|
||||
/// # #[derive(Debug, PartialEq)]
|
||||
|
@ -974,7 +975,7 @@ where
|
|||
/// # NotFound(Position),
|
||||
/// # }
|
||||
/// # let arena = Bump::new();
|
||||
/// let parser = keyword_e("when", Problem::NotFound);
|
||||
/// let parser = keyword("when", Problem::NotFound);
|
||||
///
|
||||
/// // Success case
|
||||
/// let (progress, output, state) = parser.parse(&arena, State::new("when".as_bytes()), 0).unwrap();
|
||||
|
@ -982,20 +983,23 @@ where
|
|||
/// assert_eq!(output, ());
|
||||
/// assert_eq!(state.pos().offset, 4);
|
||||
///
|
||||
/// Error case
|
||||
/// // Error case
|
||||
/// let (progress, err) = parser.parse(&arena, State::new("whence".as_bytes()), 0).unwrap_err();
|
||||
/// assert_eq!(progress, Progress::NoProgress);
|
||||
/// assert_eq!(err, Problem::NotFound(Position::zero()));
|
||||
/// ```
|
||||
pub fn keyword_e<'a, ToError, E>(keyword: &'static str, if_error: ToError) -> impl Parser<'a, (), E>
|
||||
pub fn keyword<'a, ToError, E>(
|
||||
keyword_str: &'static str,
|
||||
if_error: ToError,
|
||||
) -> impl Parser<'a, (), E>
|
||||
where
|
||||
ToError: Fn(Position) -> E,
|
||||
E: 'a,
|
||||
{
|
||||
move |_, mut state: State<'a>, _min_indent| {
|
||||
let width = keyword.len();
|
||||
let width = keyword_str.len();
|
||||
|
||||
if !state.bytes().starts_with(keyword.as_bytes()) {
|
||||
if !state.bytes().starts_with(keyword_str.as_bytes()) {
|
||||
return Err((NoProgress, if_error(state.pos())));
|
||||
}
|
||||
|
||||
|
@ -1270,7 +1274,8 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates a parser that only fails if its inner parser partially matches
|
||||
/// Make the given parser optional, it can complete or not consume anything,
|
||||
/// but it can't error with progress made.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
|
@ -1286,13 +1291,13 @@ where
|
|||
/// # let arena = Bump::new();
|
||||
/// let parser = optional(word("hello", Problem::NotFound));
|
||||
///
|
||||
/// // Success case
|
||||
/// // Parser completed case
|
||||
/// let (progress, output, state) = parser.parse(&arena, State::new("hello, world".as_bytes()), 0).unwrap();
|
||||
/// assert_eq!(progress, Progress::MadeProgress);
|
||||
/// assert_eq!(output, Some(()));
|
||||
/// assert_eq!(state.pos().offset, 5);
|
||||
///
|
||||
/// // Error case
|
||||
/// // No progress case
|
||||
/// let (progress, output, state) = parser.parse(&arena, State::new("bye, world".as_bytes()), 0).unwrap();
|
||||
/// assert_eq!(progress, Progress::NoProgress);
|
||||
/// assert_eq!(output, None);
|
||||
|
@ -1318,10 +1323,11 @@ where
|
|||
|
||||
// MACRO COMBINATORS
|
||||
//
|
||||
// Using some combinators together results in combinatorial type explosion
|
||||
// which makes things take forever to compile. Using macros instead avoids this!
|
||||
// Using some combinators together results in combinatorial type explosion,
|
||||
// this takes forever to compile. Using macros instead avoids this!
|
||||
|
||||
/// Wraps the output of the parser in a [`Loc`](../roc_region/all/struct.Loc.html) struct, providing location information
|
||||
/// Wraps the output of the given parser in a [`Loc`](../roc_region/all/struct.Loc.html) struct,
|
||||
/// to provide location information.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
|
@ -1502,7 +1508,7 @@ macro_rules! collection_trailing_sep_e {
|
|||
};
|
||||
}
|
||||
|
||||
/// Creates a parser that always succeeds with the given output
|
||||
/// Creates a parser that always succeeds with the given argument as output.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
|
@ -1532,7 +1538,7 @@ macro_rules! succeed {
|
|||
}
|
||||
|
||||
/// Creates a parser that always fails.
|
||||
/// If the inner parser succeeds, the error can be customized with the given function
|
||||
/// If the given parser succeeds, the error is customized with the given function.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
|
@ -1549,12 +1555,12 @@ macro_rules! succeed {
|
|||
/// # let arena = Bump::new();
|
||||
/// let parser = fail_when(Problem::OtherProblem, word("hello", Problem::NotFound));
|
||||
///
|
||||
/// // Success case
|
||||
/// // When given parser succeeds:
|
||||
/// let (progress, err) = Parser::<(), Problem>::parse(&parser, &arena, State::new("hello, world".as_bytes()), 0).unwrap_err();
|
||||
/// assert_eq!(progress, Progress::MadeProgress);
|
||||
/// assert_eq!(err, Problem::OtherProblem(Position::new(0)));
|
||||
///
|
||||
/// // Error case
|
||||
/// // When given parser errors:
|
||||
/// let (progress, err) = Parser::<(), Problem>::parse(&parser, &arena, State::new("bye, world".as_bytes()), 0).unwrap_err();
|
||||
/// assert_eq!(progress, Progress::NoProgress);
|
||||
/// assert_eq!(err, Problem::NotFound(Position::new(0)));
|
||||
|
@ -1576,7 +1582,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates a parser that always fails with the same output.
|
||||
/// Creates a parser that always fails using the given error function.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
|
@ -1607,14 +1613,14 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates a new parser from two other parsers.
|
||||
/// The two parsers can have different outputs, but must have the same error type.
|
||||
/// Runs two parsers in succession. If both parsers succeed, the output is a tuple of both outputs.
|
||||
/// Both parsers must have the same error type.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// # #![forbid(unused_imports)]
|
||||
/// # use roc_parse::state::State;
|
||||
/// # use crate::roc_parse::parser::{Parser, Progress, word, word1};
|
||||
/// # use crate::roc_parse::parser::{Parser, Progress, word, byte};
|
||||
/// # use roc_region::all::Position;
|
||||
/// # use roc_parse::and;
|
||||
/// # use bumpalo::Bump;
|
||||
|
@ -1626,7 +1632,7 @@ where
|
|||
/// # fn foo<'a>(arena: &'a Bump) {
|
||||
/// let parser = and!(
|
||||
/// word("hello", Problem::NotFound),
|
||||
/// word1(b',', Problem::NotFound)
|
||||
/// byte(b',', Problem::NotFound)
|
||||
/// );
|
||||
///
|
||||
/// let (progress, output, state) = parser.parse(&arena, State::new("hello, world".as_bytes()), 0).unwrap();
|
||||
|
@ -1724,15 +1730,14 @@ macro_rules! absolute_indented_seq {
|
|||
};
|
||||
}
|
||||
|
||||
/// Creates a new parser that returns the result of the first parser that makes progress,
|
||||
/// whether or not that parser succeeds.
|
||||
/// If no parsers make progress, then the last parser's result is returned.
|
||||
/// Returns the result of the first parser that makes progress, even if it failed.
|
||||
/// If no parsers make progress, the last parser's result is returned.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// # #![forbid(unused_imports)]
|
||||
/// # use roc_parse::state::State;
|
||||
/// # use crate::roc_parse::parser::{Parser, Progress, word, word1};
|
||||
/// # use crate::roc_parse::parser::{Parser, Progress, word, byte};
|
||||
/// # use roc_region::all::Position;
|
||||
/// # use roc_parse::one_of;
|
||||
/// # use bumpalo::Bump;
|
||||
|
@ -1744,7 +1749,7 @@ macro_rules! absolute_indented_seq {
|
|||
/// # fn foo<'a>(arena: &'a Bump) {
|
||||
/// let parser1 = one_of!(
|
||||
/// word("hello", Problem::NotFound),
|
||||
/// word1(b'h', Problem::NotFound)
|
||||
/// byte(b'h', Problem::NotFound)
|
||||
/// );
|
||||
/// let (progress, output, state) = parser1.parse(&arena, State::new("hello, world".as_bytes()), 0).unwrap();
|
||||
/// assert_eq!(progress, Progress::MadeProgress);
|
||||
|
@ -1753,7 +1758,7 @@ macro_rules! absolute_indented_seq {
|
|||
///
|
||||
/// let parser2 = one_of!(
|
||||
/// // swapped the order of the parsers
|
||||
/// word1(b'h', Problem::NotFound),
|
||||
/// byte(b'h', Problem::NotFound),
|
||||
/// word("hello", Problem::NotFound)
|
||||
/// );
|
||||
/// let (progress, output, state) = parser2.parse(&arena, State::new("hello! world".as_bytes()), 0).unwrap();
|
||||
|
@ -1826,15 +1831,14 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates a new parser that changes the `Err` type.
|
||||
/// This can be used as `.map`, but for errors.
|
||||
/// It has no effect, if the inner parser succeeds.
|
||||
/// Transforms a possible error, like `map_err` in Rust.
|
||||
/// It has no effect if the given parser succeeds.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// # #![forbid(unused_imports)]
|
||||
/// # use roc_parse::state::State;
|
||||
/// # use crate::roc_parse::parser::{Parser, Progress, word, specialize};
|
||||
/// # use crate::roc_parse::parser::{Parser, Progress, word, specialize_err};
|
||||
/// # use roc_region::all::Position;
|
||||
/// # use bumpalo::Bump;
|
||||
/// # #[derive(Debug, PartialEq)]
|
||||
|
@ -1843,7 +1847,7 @@ where
|
|||
/// # Other(Position),
|
||||
/// # }
|
||||
/// # let arena = Bump::new();
|
||||
/// let parser = specialize(
|
||||
/// let parser = specialize_err(
|
||||
/// |_prev_err, pos| Problem::Other(pos),
|
||||
/// word("bye", Problem::NotFound)
|
||||
/// );
|
||||
|
@ -1852,7 +1856,7 @@ where
|
|||
/// assert_eq!(progress, Progress::NoProgress);
|
||||
/// assert_eq!(err, Problem::Other(Position::new(0)));
|
||||
/// ```
|
||||
pub fn specialize<'a, F, P, T, X, Y>(map_error: F, parser: P) -> impl Parser<'a, T, Y>
|
||||
pub fn specialize_err<'a, F, P, T, X, Y>(map_error: F, parser: P) -> impl Parser<'a, T, Y>
|
||||
where
|
||||
F: Fn(X, Position) -> Y,
|
||||
P: Parser<'a, T, X>,
|
||||
|
@ -1867,16 +1871,16 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Creates a new parser that changes the `Err` type.
|
||||
/// This can be used as `.map`, but for errors.
|
||||
/// Similar to [`specialize`], the error is allocated, and the mapping function receives a reference to the error.
|
||||
/// It has no effect, if the inner parser succeeds.
|
||||
/// Transforms a possible error, like `map_err` in Rust.
|
||||
/// Similar to [`specialize_err`], but the error is arena allocated, and the
|
||||
/// mapping function receives a reference to the error.
|
||||
/// It has no effect if the inner parser succeeds.
|
||||
///
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// # #![forbid(unused_imports)]
|
||||
/// # use roc_parse::state::State;
|
||||
/// # use crate::roc_parse::parser::{Parser, Progress, word, specialize_ref};
|
||||
/// # use crate::roc_parse::parser::{Parser, Progress, word, specialize_err_ref};
|
||||
/// # use roc_region::all::Position;
|
||||
/// # use bumpalo::Bump;
|
||||
/// # #[derive(Debug, PartialEq)]
|
||||
|
@ -1885,7 +1889,7 @@ where
|
|||
/// # Other(Position),
|
||||
/// # }
|
||||
/// # let arena = Bump::new();
|
||||
/// let parser = specialize_ref(
|
||||
/// let parser = specialize_err_ref(
|
||||
/// |_prev_err, pos| Problem::Other(pos),
|
||||
/// word("bye", Problem::NotFound)
|
||||
/// );
|
||||
|
@ -1894,7 +1898,7 @@ where
|
|||
/// assert_eq!(progress, Progress::NoProgress);
|
||||
/// assert_eq!(err, Problem::Other(Position::new(0)));
|
||||
/// ```
|
||||
pub fn specialize_ref<'a, F, P, T, X, Y>(map_error: F, parser: P) -> impl Parser<'a, T, Y>
|
||||
pub fn specialize_err_ref<'a, F, P, T, X, Y>(map_error: F, parser: P) -> impl Parser<'a, T, Y>
|
||||
where
|
||||
F: Fn(&'a X, Position) -> Y,
|
||||
P: Parser<'a, T, X>,
|
||||
|
@ -1910,7 +1914,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Matches an entire `str` and moves the state's position forward if it succeeds
|
||||
/// Matches an entire `str` and moves the state's position forward if it succeeds.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
|
@ -1955,14 +1959,14 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
/// Matches a single `u8` and moves the state's position forward if it succeeds
|
||||
/// Matches a single `u8` and moves the state's position forward if it succeeds.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # #![forbid(unused_imports)]
|
||||
/// # use roc_parse::state::State;
|
||||
/// # use crate::roc_parse::parser::{Parser, Progress, word1};
|
||||
/// # use crate::roc_parse::parser::{Parser, Progress, byte};
|
||||
/// # use roc_region::all::Position;
|
||||
/// # use bumpalo::Bump;
|
||||
/// # #[derive(Debug, PartialEq)]
|
||||
|
@ -1970,7 +1974,7 @@ where
|
|||
/// # NotFound(Position),
|
||||
/// # }
|
||||
/// # let arena = Bump::new();
|
||||
/// let parser = word1(b'h', Problem::NotFound);
|
||||
/// let parser = byte(b'h', Problem::NotFound);
|
||||
///
|
||||
/// // Success case
|
||||
/// let (progress, output, state) = parser.parse(&arena, State::new("hello, world".as_bytes()), 0).unwrap();
|
||||
|
@ -1983,15 +1987,15 @@ where
|
|||
/// assert_eq!(progress, Progress::NoProgress);
|
||||
/// assert_eq!(problem, Problem::NotFound(Position::zero()));
|
||||
/// ```
|
||||
pub fn word1<'a, ToError, E>(word: u8, to_error: ToError) -> impl Parser<'a, (), E>
|
||||
pub fn byte<'a, ToError, E>(byte_to_match: u8, to_error: ToError) -> impl Parser<'a, (), E>
|
||||
where
|
||||
ToError: Fn(Position) -> E,
|
||||
E: 'a,
|
||||
{
|
||||
debug_assert_ne!(word, b'\n');
|
||||
debug_assert_ne!(byte_to_match, b'\n');
|
||||
|
||||
move |_arena: &'a Bump, state: State<'a>, _min_indent: u32| match state.bytes().first() {
|
||||
Some(x) if *x == word => {
|
||||
Some(x) if *x == byte_to_match => {
|
||||
let state = state.advance(1);
|
||||
Ok((MadeProgress, (), state))
|
||||
}
|
||||
|
@ -2007,7 +2011,7 @@ where
|
|||
/// ```
|
||||
/// # #![forbid(unused_imports)]
|
||||
/// # use roc_parse::state::State;
|
||||
/// # use crate::roc_parse::parser::{Parser, Progress, word1, word1_indent};
|
||||
/// # use crate::roc_parse::parser::{Parser, Progress, byte, byte_indent};
|
||||
/// # use roc_region::all::Position;
|
||||
/// # use bumpalo::Bump;
|
||||
/// # #[derive(Debug, PartialEq)]
|
||||
|
@ -2016,7 +2020,7 @@ where
|
|||
/// # WrongIndentLevel(Position),
|
||||
/// # }
|
||||
/// # let arena = Bump::new();
|
||||
/// let parser = word1_indent(b'h', Problem::WrongIndentLevel);
|
||||
/// let parser = byte_indent(b'h', Problem::WrongIndentLevel);
|
||||
///
|
||||
/// // Success case
|
||||
/// let (progress, output, state) = parser.parse(&arena, State::new("hello, world".as_bytes()), 0).unwrap();
|
||||
|
@ -2026,17 +2030,17 @@ where
|
|||
///
|
||||
/// // Error case
|
||||
/// let state = State::new(" hello, world".as_bytes());
|
||||
/// let _ = word1(b' ', Problem::NotFound).parse(&arena, state.clone(), 0).unwrap();
|
||||
/// let _ = byte(b' ', Problem::NotFound).parse(&arena, state.clone(), 0).unwrap();
|
||||
/// let (progress, problem) = parser.parse(&arena, state, 0).unwrap_err();
|
||||
/// assert_eq!(progress, Progress::NoProgress);
|
||||
/// assert_eq!(problem, Problem::WrongIndentLevel(Position::zero()));
|
||||
/// ```
|
||||
pub fn word1_indent<'a, ToError, E>(word: u8, to_error: ToError) -> impl Parser<'a, (), E>
|
||||
pub fn byte_indent<'a, ToError, E>(byte_to_match: u8, to_error: ToError) -> impl Parser<'a, (), E>
|
||||
where
|
||||
ToError: Fn(Position) -> E,
|
||||
E: 'a,
|
||||
{
|
||||
debug_assert_ne!(word, b'\n');
|
||||
debug_assert_ne!(byte_to_match, b'\n');
|
||||
|
||||
move |_arena: &'a Bump, state: State<'a>, min_indent: u32| {
|
||||
if min_indent > state.column() {
|
||||
|
@ -2044,7 +2048,7 @@ where
|
|||
}
|
||||
|
||||
match state.bytes().first() {
|
||||
Some(x) if *x == word => {
|
||||
Some(x) if *x == byte_to_match => {
|
||||
let state = state.advance(1);
|
||||
Ok((MadeProgress, (), state))
|
||||
}
|
||||
|
@ -2060,7 +2064,7 @@ where
|
|||
/// ```
|
||||
/// # #![forbid(unused_imports)]
|
||||
/// # use roc_parse::state::State;
|
||||
/// # use crate::roc_parse::parser::{Parser, Progress, word2};
|
||||
/// # use crate::roc_parse::parser::{Parser, Progress, two_bytes};
|
||||
/// # use roc_region::all::Position;
|
||||
/// # use bumpalo::Bump;
|
||||
/// # #[derive(Debug, PartialEq)]
|
||||
|
@ -2068,7 +2072,7 @@ where
|
|||
/// # NotFound(Position),
|
||||
/// # }
|
||||
/// # let arena = Bump::new();
|
||||
/// let parser = word2(b'h', b'e', Problem::NotFound);
|
||||
/// let parser = two_bytes(b'h', b'e', Problem::NotFound);
|
||||
///
|
||||
/// // Success case
|
||||
/// let (progress, output, state) = parser.parse(&arena, State::new("hello, world".as_bytes()), 0).unwrap();
|
||||
|
@ -2081,15 +2085,19 @@ where
|
|||
/// assert_eq!(progress, Progress::NoProgress);
|
||||
/// assert_eq!(problem, Problem::NotFound(Position::zero()));
|
||||
/// ```
|
||||
pub fn word2<'a, ToError, E>(word_1: u8, word_2: u8, to_error: ToError) -> impl Parser<'a, (), E>
|
||||
pub fn two_bytes<'a, ToError, E>(
|
||||
byte_1: u8,
|
||||
byte_2: u8,
|
||||
to_error: ToError,
|
||||
) -> impl Parser<'a, (), E>
|
||||
where
|
||||
ToError: Fn(Position) -> E,
|
||||
E: 'a,
|
||||
{
|
||||
debug_assert_ne!(word_1, b'\n');
|
||||
debug_assert_ne!(word_2, b'\n');
|
||||
debug_assert_ne!(byte_1, b'\n');
|
||||
debug_assert_ne!(byte_2, b'\n');
|
||||
|
||||
let needle = [word_1, word_2];
|
||||
let needle = [byte_1, byte_2];
|
||||
|
||||
move |_arena: &'a Bump, state: State<'a>, _min_indent: u32| {
|
||||
if state.bytes().starts_with(&needle) {
|
||||
|
@ -2108,7 +2116,7 @@ where
|
|||
/// ```
|
||||
/// # #![forbid(unused_imports)]
|
||||
/// # use roc_parse::state::State;
|
||||
/// # use crate::roc_parse::parser::{Parser, Progress, word3};
|
||||
/// # use crate::roc_parse::parser::{Parser, Progress, three_bytes};
|
||||
/// # use roc_region::all::Position;
|
||||
/// # use bumpalo::Bump;
|
||||
/// # #[derive(Debug, PartialEq)]
|
||||
|
@ -2116,7 +2124,7 @@ where
|
|||
/// # NotFound(Position),
|
||||
/// # }
|
||||
/// # let arena = Bump::new();
|
||||
/// let parser = word3(b'h', b'e', b'l', Problem::NotFound);
|
||||
/// let parser = three_bytes(b'h', b'e', b'l', Problem::NotFound);
|
||||
///
|
||||
/// // Success case
|
||||
/// let (progress, output, state) = parser.parse(&arena, State::new("hello, world".as_bytes()), 0).unwrap();
|
||||
|
@ -2129,21 +2137,21 @@ where
|
|||
/// assert_eq!(progress, Progress::NoProgress);
|
||||
/// assert_eq!(err, Problem::NotFound(Position::zero()));
|
||||
/// ```
|
||||
pub fn word3<'a, ToError, E>(
|
||||
word_1: u8,
|
||||
word_2: u8,
|
||||
word_3: u8,
|
||||
pub fn three_bytes<'a, ToError, E>(
|
||||
byte_1: u8,
|
||||
byte_2: u8,
|
||||
byte_3: u8,
|
||||
to_error: ToError,
|
||||
) -> impl Parser<'a, (), E>
|
||||
where
|
||||
ToError: Fn(Position) -> E,
|
||||
E: 'a,
|
||||
{
|
||||
debug_assert_ne!(word_1, b'\n');
|
||||
debug_assert_ne!(word_2, b'\n');
|
||||
debug_assert_ne!(word_3, b'\n');
|
||||
debug_assert_ne!(byte_1, b'\n');
|
||||
debug_assert_ne!(byte_2, b'\n');
|
||||
debug_assert_ne!(byte_3, b'\n');
|
||||
|
||||
let needle = [word_1, word_2, word_3];
|
||||
let needle = [byte_1, byte_2, byte_3];
|
||||
|
||||
move |_arena: &'a Bump, state: State<'a>, _min_indent: u32| {
|
||||
if state.bytes().starts_with(&needle) {
|
||||
|
@ -2156,16 +2164,16 @@ where
|
|||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! word1_check_indent {
|
||||
($word:expr, $word_problem:expr, $min_indent:expr, $indent_problem:expr) => {
|
||||
macro_rules! byte_check_indent {
|
||||
($byte_to_match:expr, $problem:expr, $min_indent:expr, $indent_problem:expr) => {
|
||||
and!(
|
||||
word1($word, $word_problem),
|
||||
byte($byte_to_match, $problem),
|
||||
$crate::parser::check_indent($min_indent, $indent_problem)
|
||||
)
|
||||
};
|
||||
}
|
||||
|
||||
/// Creates a new parser that maps the `Ok` result of parsing.
|
||||
/// transform the `Ok` result of a parser
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
|
@ -2209,7 +2217,7 @@ macro_rules! map {
|
|||
};
|
||||
}
|
||||
|
||||
/// Creates a new parser that maps the `Ok` result of parsing.
|
||||
/// Maps/transforms the `Ok` result of parsing using the given function.
|
||||
/// Similar to [`map!`], but the transform function also takes a bump allocator.
|
||||
///
|
||||
/// # Example
|
||||
|
@ -2257,7 +2265,7 @@ macro_rules! map_with_arena {
|
|||
}
|
||||
|
||||
/// Applies the parser as many times as possible.
|
||||
/// This parser will only fail if the inner parser makes partial progress.
|
||||
/// This parser will only fail if the given parser makes partial progress.
|
||||
#[macro_export]
|
||||
macro_rules! zero_or_more {
|
||||
($parser:expr) => {
|
||||
|
@ -2318,7 +2326,7 @@ macro_rules! zero_or_more {
|
|||
}
|
||||
|
||||
/// Creates a parser that matches one or more times.
|
||||
/// If the inner parser fails to match or partially matches, then this parser fails.
|
||||
/// Will fail if the given parser fails to match or matches partially.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
|
@ -2389,8 +2397,8 @@ macro_rules! one_or_more {
|
|||
}
|
||||
|
||||
/// Creates a parser that debug prints the result of parsing.
|
||||
/// It doesn't change the inner parser at all,
|
||||
/// so its quite useful for inspecting a parser during development.
|
||||
/// It doesn't change the given parser at all,
|
||||
/// useful for inspecting a parser during development.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
|
@ -2426,7 +2434,7 @@ macro_rules! debug {
|
|||
};
|
||||
}
|
||||
|
||||
/// Creates a new parser that matches either parser.
|
||||
/// Matches either of the two given parsers.
|
||||
/// If the first parser succeeds, its result is used,
|
||||
/// otherwise, the second parser's result is used.
|
||||
///
|
||||
|
@ -2491,14 +2499,16 @@ macro_rules! either {
|
|||
};
|
||||
}
|
||||
|
||||
/// Parse everything between two braces (e.g. parentheses), skipping both braces
|
||||
/// and keeping only whatever was parsed in between them.
|
||||
/// Given three parsers, parse them all but ignore the output of the first and last one.
|
||||
/// Useful for parsing things between two braces (e.g. parentheses).
|
||||
///
|
||||
/// If any of the three parsers error, this will error.
|
||||
///
|
||||
/// # Example
|
||||
/// ```
|
||||
/// # #![forbid(unused_imports)]
|
||||
/// # use roc_parse::state::State;
|
||||
/// # use crate::roc_parse::parser::{Parser, Progress, word, word1};
|
||||
/// # use crate::roc_parse::parser::{Parser, Progress, word, byte};
|
||||
/// # use roc_region::all::Position;
|
||||
/// # use roc_parse::{between, skip_first, skip_second};
|
||||
/// # use bumpalo::Bump;
|
||||
|
@ -2509,9 +2519,9 @@ macro_rules! either {
|
|||
/// # let arena = Bump::new();
|
||||
/// # fn foo<'a>(arena: &'a Bump) {
|
||||
/// let parser = between!(
|
||||
/// word1(b'(', Problem::NotFound),
|
||||
/// byte(b'(', Problem::NotFound),
|
||||
/// word("hello", Problem::NotFound),
|
||||
/// word1(b')', Problem::NotFound)
|
||||
/// byte(b')', Problem::NotFound)
|
||||
/// );
|
||||
/// let (progress, output, state) = parser.parse(&arena, State::new("(hello), world".as_bytes()), 0).unwrap();
|
||||
/// assert_eq!(progress, Progress::MadeProgress);
|
||||
|
@ -2527,12 +2537,11 @@ macro_rules! between {
|
|||
};
|
||||
}
|
||||
|
||||
/// Creates a new parser that returns the results of two parsers applied sequentially.
|
||||
/// It returns any partial progress made by the first parser.
|
||||
/// Runs two parsers in succession. If both parsers succeed, the output is a tuple of both outputs.
|
||||
/// Both parsers must have the same error type.
|
||||
///
|
||||
/// This is a function version of the [`and!`] macro.
|
||||
///
|
||||
/// For some reason, some usages won't compile unless they use this instead of the macro version
|
||||
/// For some reason, some usages won't compile unless they use this instead of the macro version.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
|
@ -2576,7 +2585,7 @@ where
|
|||
and!(p1, p2)
|
||||
}
|
||||
|
||||
/// The same as the [`loc!`] macro.
|
||||
/// Adds location info. This is a function version the [`loc!`] macro.
|
||||
///
|
||||
/// For some reason, some usages won't compile unless they use this instead of the macro version.
|
||||
/// This is likely because the lifetime `'a` is not defined at the call site.
|
||||
|
@ -2612,7 +2621,10 @@ where
|
|||
loc!(parser)
|
||||
}
|
||||
|
||||
/// The same as the [`map_with_arena!`] macro.
|
||||
/// Maps/transforms the `Ok` result of parsing using the given function.
|
||||
/// Similar to [`map!`], but the transform function also takes a bump allocator.
|
||||
///
|
||||
/// Function version of the [`map_with_arena!`] macro.
|
||||
///
|
||||
/// For some reason, some usages won't compile unless they use this instead of the macro version.
|
||||
/// This is likely because the lifetime `'a` is not defined at the call site.
|
||||
|
@ -2663,8 +2675,8 @@ where
|
|||
map_with_arena!(parser, transform)
|
||||
}
|
||||
|
||||
/// Creates a new parser that only has [`Progress`] of [`NoProgress`](Progress::NoProgress).
|
||||
/// The `State` is still modified, if the inner parser succeeds.
|
||||
/// Creates a new parser that does not progress but still forwards the output of
|
||||
/// the given parser if it succeeds.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
|
|
|
@ -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) => {
|
||||
|
@ -447,7 +451,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 {
|
||||
|
@ -458,17 +462,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
|
||||
|
@ -482,7 +486,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()
|
||||
))
|
||||
|
@ -494,14 +498,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)?;
|
||||
|
||||
|
@ -527,7 +531,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