mirror of
https://github.com/roc-lang/roc.git
synced 2025-09-26 13:29:12 +00:00
Merge pull request #6548 from roboteng/parser-docs
Parser docs examples
This commit is contained in:
commit
30b5943b54
9 changed files with 1221 additions and 326 deletions
2
.github/workflows/ci_manager.yml
vendored
2
.github/workflows/ci_manager.yml
vendored
|
@ -34,7 +34,7 @@ jobs:
|
||||||
if git diff --name-only origin/${{ github.base_ref }} HEAD | grep -qvE '(\.md$|\.css$|\.html$|^AUTHORS$|\.rs|\.roc)'; then
|
if git diff --name-only origin/${{ github.base_ref }} HEAD | grep -qvE '(\.md$|\.css$|\.html$|^AUTHORS$|\.rs|\.roc)'; then
|
||||||
echo "should_run_tests=y" >> $GITHUB_OUTPUT
|
echo "should_run_tests=y" >> $GITHUB_OUTPUT
|
||||||
else
|
else
|
||||||
if git diff --unified=0 origin/${{ github.base_ref }} HEAD '*.rs' | grep -E --color=never '^[+-]' | grep -qvE '^(\+\+\+|\-\-\-|[+-]\s*($|\/\/|\/\*.*\*\/\s*$))'; then
|
if git diff --unified=0 origin/${{ github.base_ref }} HEAD '*.rs' | grep -E --color=never '^[+-]' | grep -qvE '^(\+\+\+|\-\-\-|[+-]\s*($|\/\/[^\/]|\/\*.*\*\/\s*$))'; then
|
||||||
echo "should_run_tests=y" >> $GITHUB_OUTPUT
|
echo "should_run_tests=y" >> $GITHUB_OUTPUT
|
||||||
else
|
else
|
||||||
echo "should_run_tests=n" >> $GITHUB_OUTPUT
|
echo "should_run_tests=n" >> $GITHUB_OUTPUT
|
||||||
|
|
3
.github/workflows/ubuntu_x86_64.yml
vendored
3
.github/workflows/ubuntu_x86_64.yml
vendored
|
@ -38,6 +38,9 @@ jobs:
|
||||||
# see #5904 for skipped test
|
# see #5904 for skipped test
|
||||||
run: cargo test --locked --release -- --skip cli_run::expects_dev_and_test && sccache --show-stats
|
run: cargo test --locked --release -- --skip cli_run::expects_dev_and_test && sccache --show-stats
|
||||||
|
|
||||||
|
- name: tests examples in docs
|
||||||
|
run: cargo test --doc --release
|
||||||
|
|
||||||
- name: check that the platform`s produced dylib is loadable
|
- name: check that the platform`s produced dylib is loadable
|
||||||
run: cd examples/platform-switching/rust-platform && LD_LIBRARY_PATH=. cargo test --release --locked
|
run: cd examples/platform-switching/rust-platform && LD_LIBRARY_PATH=. cargo test --release --locked
|
||||||
|
|
||||||
|
|
|
@ -10,10 +10,10 @@ use crate::blankspace::{
|
||||||
use crate::ident::{integer_ident, lowercase_ident, parse_ident, Accessor, Ident};
|
use crate::ident::{integer_ident, lowercase_ident, parse_ident, Accessor, Ident};
|
||||||
use crate::keyword;
|
use crate::keyword;
|
||||||
use crate::parser::{
|
use crate::parser::{
|
||||||
self, backtrackable, increment_min_indent, line_min_indent, optional, reset_min_indent,
|
self, backtrackable, byte, byte_indent, increment_min_indent, line_min_indent, optional,
|
||||||
sep_by1, sep_by1_e, set_min_indent, specialize, specialize_ref, then, word1, word1_indent,
|
reset_min_indent, sep_by1, sep_by1_e, set_min_indent, specialize_err, specialize_err_ref, then,
|
||||||
word2, EClosure, EExpect, EExpr, EIf, EInParens, EList, ENumber, EPattern, ERecord, EString,
|
two_bytes, EClosure, EExpect, EExpr, EIf, EInParens, EList, ENumber, EPattern, ERecord,
|
||||||
EType, EWhen, Either, ParseResult, Parser,
|
EString, EType, EWhen, Either, ParseResult, Parser,
|
||||||
};
|
};
|
||||||
use crate::pattern::{closure_param, loc_implements_parser};
|
use crate::pattern::{closure_param, loc_implements_parser};
|
||||||
use crate::state::State;
|
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>> {
|
fn loc_expr_in_parens_help<'a>() -> impl Parser<'a, Loc<Expr<'a>>, EInParens<'a>> {
|
||||||
then(
|
then(
|
||||||
loc!(collection_trailing_sep_e!(
|
loc!(collection_trailing_sep_e!(
|
||||||
word1(b'(', EInParens::Open),
|
byte(b'(', EInParens::Open),
|
||||||
specialize_ref(EInParens::Expr, loc_expr(false)),
|
specialize_err_ref(EInParens::Expr, loc_expr(false)),
|
||||||
word1(b',', EInParens::End),
|
byte(b',', EInParens::End),
|
||||||
word1(b')', EInParens::End),
|
byte(b')', EInParens::End),
|
||||||
Expr::SpaceBefore
|
Expr::SpaceBefore
|
||||||
)),
|
)),
|
||||||
move |arena, state, _, loc_elements| {
|
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>> {
|
fn loc_expr_in_parens_etc_help<'a>() -> impl Parser<'a, Loc<Expr<'a>>, EExpr<'a>> {
|
||||||
map_with_arena!(
|
map_with_arena!(
|
||||||
loc!(and!(
|
loc!(and!(
|
||||||
specialize(EExpr::InParens, loc_expr_in_parens_help()),
|
specialize_err(EExpr::InParens, loc_expr_in_parens_help()),
|
||||||
record_field_access_chain()
|
record_field_access_chain()
|
||||||
)),
|
)),
|
||||||
move |arena: &'a Bump, value: Loc<(Loc<Expr<'a>>, Vec<'a, Accessor<'a>>)>| {
|
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>> {
|
fn record_field_access_chain<'a>() -> impl Parser<'a, Vec<'a, Accessor<'a>>, EExpr<'a>> {
|
||||||
zero_or_more!(skip_first!(
|
zero_or_more!(skip_first!(
|
||||||
word1(b'.', EExpr::Access),
|
byte(b'.', EExpr::Access),
|
||||||
specialize(
|
specialize_err(
|
||||||
|_, pos| EExpr::Access(pos),
|
|_, pos| EExpr::Access(pos),
|
||||||
one_of!(
|
one_of!(
|
||||||
map!(lowercase_ident(), Accessor::RecordField),
|
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>> {
|
) -> impl Parser<'a, Loc<Expr<'a>>, EExpr<'a>> {
|
||||||
one_of!(
|
one_of!(
|
||||||
loc_expr_in_parens_etc_help(),
|
loc_expr_in_parens_etc_help(),
|
||||||
loc!(specialize(EExpr::If, if_expr_help(options))),
|
loc!(specialize_err(EExpr::If, if_expr_help(options))),
|
||||||
loc!(specialize(EExpr::When, when::expr_help(options))),
|
loc!(specialize_err(EExpr::When, when::expr_help(options))),
|
||||||
loc!(specialize(EExpr::Str, string_like_literal_help())),
|
loc!(specialize_err(EExpr::Str, string_like_literal_help())),
|
||||||
loc!(specialize(EExpr::Number, positive_number_literal_help())),
|
loc!(specialize_err(
|
||||||
loc!(specialize(EExpr::Closure, closure_help(options))),
|
EExpr::Number,
|
||||||
|
positive_number_literal_help()
|
||||||
|
)),
|
||||||
|
loc!(specialize_err(EExpr::Closure, closure_help(options))),
|
||||||
loc!(crash_kw()),
|
loc!(crash_kw()),
|
||||||
loc!(underscore_expression()),
|
loc!(underscore_expression()),
|
||||||
loc!(record_literal_help()),
|
loc!(record_literal_help()),
|
||||||
loc!(specialize(EExpr::List, list_literal_help())),
|
loc!(specialize_err(EExpr::List, list_literal_help())),
|
||||||
loc!(map_with_arena!(
|
loc!(map_with_arena!(
|
||||||
assign_or_destructure_identifier(),
|
assign_or_destructure_identifier(),
|
||||||
ident_to_expr
|
ident_to_expr
|
||||||
|
@ -185,12 +188,15 @@ fn loc_term_or_underscore<'a>(
|
||||||
) -> impl Parser<'a, Loc<Expr<'a>>, EExpr<'a>> {
|
) -> impl Parser<'a, Loc<Expr<'a>>, EExpr<'a>> {
|
||||||
one_of!(
|
one_of!(
|
||||||
loc_expr_in_parens_etc_help(),
|
loc_expr_in_parens_etc_help(),
|
||||||
loc!(specialize(EExpr::Str, string_like_literal_help())),
|
loc!(specialize_err(EExpr::Str, string_like_literal_help())),
|
||||||
loc!(specialize(EExpr::Number, positive_number_literal_help())),
|
loc!(specialize_err(
|
||||||
loc!(specialize(EExpr::Closure, closure_help(options))),
|
EExpr::Number,
|
||||||
|
positive_number_literal_help()
|
||||||
|
)),
|
||||||
|
loc!(specialize_err(EExpr::Closure, closure_help(options))),
|
||||||
loc!(underscore_expression()),
|
loc!(underscore_expression()),
|
||||||
loc!(record_literal_help()),
|
loc!(record_literal_help()),
|
||||||
loc!(specialize(EExpr::List, list_literal_help())),
|
loc!(specialize_err(EExpr::List, list_literal_help())),
|
||||||
loc!(map_with_arena!(
|
loc!(map_with_arena!(
|
||||||
assign_or_destructure_identifier(),
|
assign_or_destructure_identifier(),
|
||||||
ident_to_expr
|
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>> {
|
fn loc_term<'a>(options: ExprParseOptions) -> impl Parser<'a, Loc<Expr<'a>>, EExpr<'a>> {
|
||||||
one_of!(
|
one_of!(
|
||||||
loc_expr_in_parens_etc_help(),
|
loc_expr_in_parens_etc_help(),
|
||||||
loc!(specialize(EExpr::Str, string_like_literal_help())),
|
loc!(specialize_err(EExpr::Str, string_like_literal_help())),
|
||||||
loc!(specialize(EExpr::Number, positive_number_literal_help())),
|
loc!(specialize_err(
|
||||||
loc!(specialize(EExpr::Closure, closure_help(options))),
|
EExpr::Number,
|
||||||
|
positive_number_literal_help()
|
||||||
|
)),
|
||||||
|
loc!(specialize_err(EExpr::Closure, closure_help(options))),
|
||||||
loc!(record_literal_help()),
|
loc!(record_literal_help()),
|
||||||
loc!(specialize(EExpr::List, list_literal_help())),
|
loc!(specialize_err(EExpr::List, list_literal_help())),
|
||||||
loc!(map_with_arena!(
|
loc!(map_with_arena!(
|
||||||
assign_or_destructure_identifier(),
|
assign_or_destructure_identifier(),
|
||||||
ident_to_expr
|
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| {
|
move |arena: &'a Bump, state: State<'a>, min_indent: u32| {
|
||||||
let start = state.pos();
|
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) =
|
let (_, output, final_state) =
|
||||||
optional(lowercase_ident_expr).parse(arena, next_state, min_indent)?;
|
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>> {
|
fn crash_kw<'a>() -> impl Parser<'a, Expr<'a>, EExpr<'a>> {
|
||||||
move |arena: &'a Bump, state: State<'a>, min_indent: u32| {
|
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)?;
|
.parse(arena, state, min_indent)?;
|
||||||
|
|
||||||
Ok((MadeProgress, Expr::Crash, next_state))
|
Ok((MadeProgress, Expr::Crash, next_state))
|
||||||
|
@ -255,10 +265,10 @@ fn loc_possibly_negative_or_negated_term<'a>(
|
||||||
Ok((MadeProgress, loc_expr, state))
|
Ok((MadeProgress, loc_expr, state))
|
||||||
},
|
},
|
||||||
// this will parse negative numbers, which the unary negate thing up top doesn't (for now)
|
// 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!(
|
loc!(map_with_arena!(
|
||||||
and!(
|
and!(
|
||||||
loc!(word1(b'!', EExpr::Start)),
|
loc!(byte(b'!', EExpr::Start)),
|
||||||
space0_before_e(loc_term(options), EExpr::IndentStart)
|
space0_before_e(loc_term(options), EExpr::IndentStart)
|
||||||
),
|
),
|
||||||
|arena: &'a Bump, (loc_op, loc_expr): (Loc<_>, _)| {
|
|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>> {
|
fn expr_start<'a>(options: ExprParseOptions) -> impl Parser<'a, Loc<Expr<'a>>, EExpr<'a>> {
|
||||||
one_of![
|
one_of![
|
||||||
loc!(specialize(EExpr::If, if_expr_help(options))),
|
loc!(specialize_err(EExpr::If, if_expr_help(options))),
|
||||||
loc!(specialize(EExpr::When, when::expr_help(options))),
|
loc!(specialize_err(EExpr::When, when::expr_help(options))),
|
||||||
loc!(specialize(EExpr::Expect, expect_help(options))),
|
loc!(specialize_err(EExpr::Expect, expect_help(options))),
|
||||||
loc!(specialize(EExpr::Dbg, dbg_help(options))),
|
loc!(specialize_err(EExpr::Dbg, dbg_help(options))),
|
||||||
loc!(specialize(EExpr::Closure, closure_help(options))),
|
loc!(specialize_err(EExpr::Closure, closure_help(options))),
|
||||||
loc!(expr_operator_chain(options)),
|
loc!(expr_operator_chain(options)),
|
||||||
fail_expr_start_e()
|
fail_expr_start_e()
|
||||||
]
|
]
|
||||||
|
@ -576,8 +586,8 @@ pub fn parse_single_def<'a>(
|
||||||
|
|
||||||
let start = state.pos();
|
let start = state.pos();
|
||||||
|
|
||||||
let parse_expect_vanilla = crate::parser::keyword_e(crate::keyword::EXPECT, EExpect::Expect);
|
let parse_expect_vanilla = crate::parser::keyword(crate::keyword::EXPECT, EExpect::Expect);
|
||||||
let parse_expect_fx = crate::parser::keyword_e(crate::keyword::EXPECT_FX, EExpect::Expect);
|
let parse_expect_fx = crate::parser::keyword(crate::keyword::EXPECT_FX, EExpect::Expect);
|
||||||
let parse_expect = either!(parse_expect_fx, parse_expect_vanilla);
|
let parse_expect = either!(parse_expect_fx, parse_expect_vanilla);
|
||||||
|
|
||||||
match space0_after_e(crate::pattern::loc_pattern_help(), EPattern::IndentEnd).parse(
|
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>> {
|
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,
|
EExpr::Type,
|
||||||
space0_before_e(type_annotation::located(false), EType::TIndentStart),
|
space0_before_e(type_annotation::located(false), EType::TIndentStart),
|
||||||
))
|
))
|
||||||
|
@ -1088,14 +1098,14 @@ fn opaque_signature_with_space_before<'a>() -> impl Parser<
|
||||||
EExpr<'a>,
|
EExpr<'a>,
|
||||||
> {
|
> {
|
||||||
and!(
|
and!(
|
||||||
specialize(
|
specialize_err(
|
||||||
EExpr::Type,
|
EExpr::Type,
|
||||||
space0_before_e(
|
space0_before_e(
|
||||||
type_annotation::located_opaque_signature(true),
|
type_annotation::located_opaque_signature(true),
|
||||||
EType::TIndentStart,
|
EType::TIndentStart,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
optional(backtrackable(specialize(
|
optional(backtrackable(specialize_err(
|
||||||
EExpr::Type,
|
EExpr::Type,
|
||||||
space0_before_e(type_annotation::implements_abilities(), EType::TIndentStart,),
|
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) {
|
match expr_to_pattern_help(arena, &call.value) {
|
||||||
Ok(good) => {
|
Ok(good) => {
|
||||||
let parser = specialize(
|
let parser = specialize_err(
|
||||||
EExpr::Type,
|
EExpr::Type,
|
||||||
space0_before_e(
|
space0_before_e(
|
||||||
set_min_indent(indented_more, type_annotation::located(false)),
|
set_min_indent(indented_more, type_annotation::located(false)),
|
||||||
|
@ -1277,14 +1287,14 @@ mod ability {
|
||||||
map!(
|
map!(
|
||||||
// Require the type to be more indented than the name
|
// Require the type to be more indented than the name
|
||||||
absolute_indented_seq!(
|
absolute_indented_seq!(
|
||||||
specialize(|_, pos| EAbility::DemandName(pos), loc!(lowercase_ident())),
|
specialize_err(|_, pos| EAbility::DemandName(pos), loc!(lowercase_ident())),
|
||||||
skip_first!(
|
skip_first!(
|
||||||
and!(
|
and!(
|
||||||
// TODO: do we get anything from picking up spaces here?
|
// TODO: do we get anything from picking up spaces here?
|
||||||
space0_e(EAbility::DemandName),
|
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>>)| {
|
|(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",") {
|
if options.accept_multi_backpassing && state.bytes().starts_with(b",") {
|
||||||
state = state.advance(1);
|
state = state.advance(1);
|
||||||
|
|
||||||
let (_, mut patterns, state) = specialize_ref(
|
let (_, mut patterns, state) = specialize_err_ref(
|
||||||
EExpr::Pattern,
|
EExpr::Pattern,
|
||||||
crate::parser::sep_by0(
|
crate::parser::sep_by0(
|
||||||
word1(b',', EPattern::Start),
|
byte(b',', EPattern::Start),
|
||||||
space0_around_ee(
|
space0_around_ee(
|
||||||
crate::pattern::loc_pattern_help(),
|
crate::pattern::loc_pattern_help(),
|
||||||
EPattern::Start,
|
EPattern::Start,
|
||||||
|
@ -1787,7 +1797,7 @@ fn parse_expr_end<'a>(
|
||||||
|
|
||||||
patterns.insert(0, loc_pattern);
|
patterns.insert(0, loc_pattern);
|
||||||
|
|
||||||
match word2(b'<', b'-', EExpr::BackpassArrow).parse(
|
match two_bytes(b'<', b'-', EExpr::BackpassArrow).parse(
|
||||||
arena,
|
arena,
|
||||||
state.clone(),
|
state.clone(),
|
||||||
min_indent,
|
min_indent,
|
||||||
|
@ -2064,16 +2074,16 @@ fn closure_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EClo
|
||||||
// After the first token, all other tokens must be indented past the start of the line
|
// After the first token, all other tokens must be indented past the start of the line
|
||||||
indented_seq!(
|
indented_seq!(
|
||||||
// All closures start with a '\' - e.g. (\x -> x + 1)
|
// 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.
|
// 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.
|
// It may turn out to be malformed, but it is definitely a closure.
|
||||||
and!(
|
and!(
|
||||||
// Parse the params
|
// Parse the params
|
||||||
// Params are comma-separated
|
// Params are comma-separated
|
||||||
sep_by1_e(
|
sep_by1_e(
|
||||||
word1(b',', EClosure::Comma),
|
byte(b',', EClosure::Comma),
|
||||||
space0_around_ee(
|
space0_around_ee(
|
||||||
specialize(EClosure::Pattern, closure_param()),
|
specialize_err(EClosure::Pattern, closure_param()),
|
||||||
EClosure::IndentArg,
|
EClosure::IndentArg,
|
||||||
EClosure::IndentArrow,
|
EClosure::IndentArrow,
|
||||||
),
|
),
|
||||||
|
@ -2081,10 +2091,10 @@ fn closure_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EClo
|
||||||
),
|
),
|
||||||
skip_first!(
|
skip_first!(
|
||||||
// Parse the -> which separates params from body
|
// Parse the -> which separates params from body
|
||||||
word2(b'-', b'>', EClosure::Arrow),
|
two_bytes(b'-', b'>', EClosure::Arrow),
|
||||||
// Parse the body
|
// Parse the body
|
||||||
space0_before_e(
|
space0_before_e(
|
||||||
specialize_ref(EClosure::Body, expr_start(options)),
|
specialize_err_ref(EClosure::Body, expr_start(options)),
|
||||||
EClosure::IndentBody
|
EClosure::IndentBody
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -2107,9 +2117,9 @@ mod when {
|
||||||
map_with_arena!(
|
map_with_arena!(
|
||||||
and!(
|
and!(
|
||||||
indented_seq!(
|
indented_seq!(
|
||||||
parser::keyword_e(keyword::WHEN, EWhen::When),
|
parser::keyword(keyword::WHEN, EWhen::When),
|
||||||
space0_around_e_no_after_indent_check(
|
space0_around_e_no_after_indent_check(
|
||||||
specialize_ref(EWhen::Condition, expr_start(options)),
|
specialize_err_ref(EWhen::Condition, expr_start(options)),
|
||||||
EWhen::IndentCondition,
|
EWhen::IndentCondition,
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
@ -2118,7 +2128,7 @@ mod when {
|
||||||
//
|
//
|
||||||
// We require that branches are indented relative to the line containing the `is`.
|
// We require that branches are indented relative to the line containing the `is`.
|
||||||
indented_seq!(
|
indented_seq!(
|
||||||
parser::keyword_e(keyword::IS, EWhen::Is),
|
parser::keyword(keyword::IS, EWhen::Is),
|
||||||
branches(options)
|
branches(options)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
@ -2215,10 +2225,10 @@ mod when {
|
||||||
one_of![
|
one_of![
|
||||||
map!(
|
map!(
|
||||||
skip_first!(
|
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
|
// TODO we should require space before the expression but not after
|
||||||
space0_around_ee(
|
space0_around_ee(
|
||||||
specialize_ref(
|
specialize_err_ref(
|
||||||
EWhen::IfGuard,
|
EWhen::IfGuard,
|
||||||
increment_min_indent(expr_start(options))
|
increment_min_indent(expr_start(options))
|
||||||
),
|
),
|
||||||
|
@ -2239,7 +2249,7 @@ mod when {
|
||||||
backtrackable(space0_e(EWhen::IndentPattern)).parse(arena, state, min_indent)?;
|
backtrackable(space0_e(EWhen::IndentPattern)).parse(arena, state, min_indent)?;
|
||||||
|
|
||||||
let (_, loc_pattern, state) = space0_after_e(
|
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,
|
EWhen::IndentPattern,
|
||||||
)
|
)
|
||||||
.parse(arena, state, min_indent)?;
|
.parse(arena, state, min_indent)?;
|
||||||
|
@ -2284,7 +2294,7 @@ mod when {
|
||||||
let pattern_indent_column = state.column();
|
let pattern_indent_column = state.column();
|
||||||
|
|
||||||
let parser =
|
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) {
|
match parser.parse(arena, state.clone(), pattern_indent) {
|
||||||
Err((MadeProgress, fail)) => Err((MadeProgress, fail)),
|
Err((MadeProgress, fail)) => Err((MadeProgress, fail)),
|
||||||
|
@ -2317,9 +2327,9 @@ mod when {
|
||||||
fn branch_result<'a>(indent: u32) -> impl Parser<'a, Loc<Expr<'a>>, EWhen<'a>> {
|
fn branch_result<'a>(indent: u32) -> impl Parser<'a, Loc<Expr<'a>>, EWhen<'a>> {
|
||||||
move |arena, state, _min_indent| {
|
move |arena, state, _min_indent| {
|
||||||
skip_first!(
|
skip_first!(
|
||||||
word2(b'-', b'>', EWhen::Arrow),
|
two_bytes(b'-', b'>', EWhen::Arrow),
|
||||||
space0_before_e(
|
space0_before_e(
|
||||||
specialize_ref(EWhen::Branch, loc_expr(true)),
|
specialize_err_ref(EWhen::Branch, loc_expr(true)),
|
||||||
EWhen::IndentBranch,
|
EWhen::IndentBranch,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -2333,19 +2343,19 @@ fn if_branch<'a>() -> impl Parser<'a, (Loc<Expr<'a>>, Loc<Expr<'a>>), EIf<'a>> {
|
||||||
and!(
|
and!(
|
||||||
skip_second!(
|
skip_second!(
|
||||||
space0_around_ee(
|
space0_around_ee(
|
||||||
specialize_ref(EIf::Condition, loc_expr(true)),
|
specialize_err_ref(EIf::Condition, loc_expr(true)),
|
||||||
EIf::IndentCondition,
|
EIf::IndentCondition,
|
||||||
EIf::IndentThenToken,
|
EIf::IndentThenToken,
|
||||||
),
|
),
|
||||||
parser::keyword_e(keyword::THEN, EIf::Then)
|
parser::keyword(keyword::THEN, EIf::Then)
|
||||||
),
|
),
|
||||||
space0_around_ee(
|
space0_around_ee(
|
||||||
specialize_ref(EIf::ThenBranch, loc_expr(true)),
|
specialize_err_ref(EIf::ThenBranch, loc_expr(true)),
|
||||||
EIf::IndentThenBranch,
|
EIf::IndentThenBranch,
|
||||||
EIf::IndentElseToken,
|
EIf::IndentElseToken,
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
parser::keyword_e(keyword::ELSE, EIf::Else)
|
parser::keyword(keyword::ELSE, EIf::Else)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2354,10 +2364,10 @@ fn expect_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EExpe
|
||||||
let start_column = state.column();
|
let start_column = state.column();
|
||||||
|
|
||||||
let (_, _, state) =
|
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(
|
let (_, condition, state) = space0_before_e(
|
||||||
specialize_ref(
|
specialize_err_ref(
|
||||||
EExpect::Condition,
|
EExpect::Condition,
|
||||||
set_min_indent(start_column + 1, expr_start(options)),
|
set_min_indent(start_column + 1, expr_start(options)),
|
||||||
),
|
),
|
||||||
|
@ -2366,7 +2376,7 @@ fn expect_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EExpe
|
||||||
.parse(arena, state, start_column + 1)
|
.parse(arena, state, start_column + 1)
|
||||||
.map_err(|(_, f)| (MadeProgress, f))?;
|
.map_err(|(_, f)| (MadeProgress, f))?;
|
||||||
|
|
||||||
let parse_cont = specialize_ref(
|
let parse_cont = specialize_err_ref(
|
||||||
EExpect::Continuation,
|
EExpect::Continuation,
|
||||||
space0_before_e(expr_start(options), EExpr::IndentEnd),
|
space0_before_e(expr_start(options), EExpr::IndentEnd),
|
||||||
);
|
);
|
||||||
|
@ -2384,10 +2394,10 @@ fn dbg_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EExpect<
|
||||||
let start_column = state.column();
|
let start_column = state.column();
|
||||||
|
|
||||||
let (_, _, state) =
|
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(
|
let (_, condition, state) = space0_before_e(
|
||||||
specialize_ref(
|
specialize_err_ref(
|
||||||
EExpect::Condition,
|
EExpect::Condition,
|
||||||
set_min_indent(start_column + 1, expr_start(options)),
|
set_min_indent(start_column + 1, expr_start(options)),
|
||||||
),
|
),
|
||||||
|
@ -2396,7 +2406,7 @@ fn dbg_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EExpect<
|
||||||
.parse(arena, state, start_column + 1)
|
.parse(arena, state, start_column + 1)
|
||||||
.map_err(|(_, f)| (MadeProgress, f))?;
|
.map_err(|(_, f)| (MadeProgress, f))?;
|
||||||
|
|
||||||
let parse_cont = specialize_ref(
|
let parse_cont = specialize_err_ref(
|
||||||
EExpect::Continuation,
|
EExpect::Continuation,
|
||||||
space0_before_e(expr_start(options), EExpr::IndentEnd),
|
space0_before_e(expr_start(options), EExpr::IndentEnd),
|
||||||
);
|
);
|
||||||
|
@ -2412,7 +2422,7 @@ fn dbg_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EExpect<
|
||||||
fn if_expr_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EIf<'a>> {
|
fn if_expr_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EIf<'a>> {
|
||||||
move |arena: &'a Bump, state, min_indent| {
|
move |arena: &'a Bump, state, min_indent| {
|
||||||
let (_, _, state) =
|
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);
|
let mut branches = Vec::with_capacity_in(1, arena);
|
||||||
|
|
||||||
|
@ -2428,7 +2438,7 @@ fn if_expr_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EIf<
|
||||||
// NOTE this drops spaces between the `else` and the `if`
|
// NOTE this drops spaces between the `else` and the `if`
|
||||||
let optional_if = and!(
|
let optional_if = and!(
|
||||||
backtrackable(space0_e(EIf::IndentIf)),
|
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) {
|
match optional_if.parse(arena, state.clone(), min_indent) {
|
||||||
|
@ -2441,7 +2451,7 @@ fn if_expr_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EIf<
|
||||||
};
|
};
|
||||||
|
|
||||||
let (_, else_branch, state) = space0_before_e(
|
let (_, else_branch, state) = space0_before_e(
|
||||||
specialize_ref(EIf::ElseBranch, expr_start(options)),
|
specialize_err_ref(EIf::ElseBranch, expr_start(options)),
|
||||||
EIf::IndentElseBranch,
|
EIf::IndentElseBranch,
|
||||||
)
|
)
|
||||||
.parse(arena, state_final_else, min_indent)
|
.parse(arena, state_final_else, min_indent)
|
||||||
|
@ -2549,10 +2559,10 @@ fn ident_to_expr<'a>(arena: &'a Bump, src: Ident<'a>) -> Expr<'a> {
|
||||||
fn list_literal_help<'a>() -> impl Parser<'a, Expr<'a>, EList<'a>> {
|
fn list_literal_help<'a>() -> impl Parser<'a, Expr<'a>, EList<'a>> {
|
||||||
map_with_arena!(
|
map_with_arena!(
|
||||||
collection_trailing_sep_e!(
|
collection_trailing_sep_e!(
|
||||||
word1(b'[', EList::Open),
|
byte(b'[', EList::Open),
|
||||||
specialize_ref(EList::Expr, loc_expr(false)),
|
specialize_err_ref(EList::Expr, loc_expr(false)),
|
||||||
word1(b',', EList::End),
|
byte(b',', EList::End),
|
||||||
word1(b']', EList::End),
|
byte(b']', EList::End),
|
||||||
Expr::SpaceBefore
|
Expr::SpaceBefore
|
||||||
),
|
),
|
||||||
|arena, elements: Collection<'a, _>| {
|
|arena, elements: Collection<'a, _>| {
|
||||||
|
@ -2680,14 +2690,14 @@ pub fn record_field<'a>() -> impl Parser<'a, RecordField<'a>, ERecord<'a>> {
|
||||||
|
|
||||||
map_with_arena!(
|
map_with_arena!(
|
||||||
and!(
|
and!(
|
||||||
specialize(|_, pos| ERecord::Field(pos), loc!(lowercase_ident())),
|
specialize_err(|_, pos| ERecord::Field(pos), loc!(lowercase_ident())),
|
||||||
and!(
|
and!(
|
||||||
spaces(),
|
spaces(),
|
||||||
optional(either!(
|
optional(either!(
|
||||||
and!(word1(b':', ERecord::Colon), record_field_expr()),
|
and!(byte(b':', ERecord::Colon), record_field_expr()),
|
||||||
and!(
|
and!(
|
||||||
word1(b'?', ERecord::QuestionMark),
|
byte(b'?', ERecord::QuestionMark),
|
||||||
spaces_before(specialize_ref(ERecord::Expr, loc_expr(false)))
|
spaces_before(specialize_err_ref(ERecord::Expr, loc_expr(false)))
|
||||||
)
|
)
|
||||||
))
|
))
|
||||||
)
|
)
|
||||||
|
@ -2731,10 +2741,10 @@ fn record_field_expr<'a>() -> impl Parser<'a, RecordFieldExpr<'a>, ERecord<'a>>
|
||||||
spaces(),
|
spaces(),
|
||||||
either!(
|
either!(
|
||||||
and!(
|
and!(
|
||||||
word2(b'<', b'-', ERecord::Arrow),
|
two_bytes(b'<', b'-', ERecord::Arrow),
|
||||||
spaces_before(specialize_ref(ERecord::Expr, loc_expr(false)))
|
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)| {
|
|arena: &'a bumpalo::Bump, (spaces, either)| {
|
||||||
|
@ -2755,7 +2765,7 @@ fn record_field_expr<'a>() -> impl Parser<'a, RecordFieldExpr<'a>, ERecord<'a>>
|
||||||
}
|
}
|
||||||
|
|
||||||
fn record_updateable_identifier<'a>() -> impl Parser<'a, Expr<'a>, ERecord<'a>> {
|
fn record_updateable_identifier<'a>() -> impl Parser<'a, Expr<'a>, ERecord<'a>> {
|
||||||
specialize(
|
specialize_err(
|
||||||
|_, pos| ERecord::Updateable(pos),
|
|_, pos| ERecord::Updateable(pos),
|
||||||
map_with_arena!(parse_ident, ident_to_expr),
|
map_with_arena!(parse_ident, ident_to_expr),
|
||||||
)
|
)
|
||||||
|
@ -2768,7 +2778,7 @@ struct RecordHelp<'a> {
|
||||||
|
|
||||||
fn record_help<'a>() -> impl Parser<'a, RecordHelp<'a>, ERecord<'a>> {
|
fn record_help<'a>() -> impl Parser<'a, RecordHelp<'a>, ERecord<'a>> {
|
||||||
between!(
|
between!(
|
||||||
word1(b'{', ERecord::Open),
|
byte(b'{', ERecord::Open),
|
||||||
reset_min_indent(record!(RecordHelp {
|
reset_min_indent(record!(RecordHelp {
|
||||||
// You can optionally have an identifier followed by an '&' to
|
// You can optionally have an identifier followed by an '&' to
|
||||||
// make this a record update, e.g. { Foo.user & username: "blah" }.
|
// make this a record update, e.g. { Foo.user & username: "blah" }.
|
||||||
|
@ -2780,22 +2790,22 @@ fn record_help<'a>() -> impl Parser<'a, RecordHelp<'a>, ERecord<'a>> {
|
||||||
// (and not e.g. an `Expr::Access`) and extract its string.
|
// (and not e.g. an `Expr::Access`) and extract its string.
|
||||||
loc!(record_updateable_identifier()),
|
loc!(record_updateable_identifier()),
|
||||||
),
|
),
|
||||||
word1(b'&', ERecord::Ampersand)
|
byte(b'&', ERecord::Ampersand)
|
||||||
))),
|
))),
|
||||||
fields: collection_inner!(
|
fields: collection_inner!(
|
||||||
loc!(record_field()),
|
loc!(record_field()),
|
||||||
word1(b',', ERecord::End),
|
byte(b',', ERecord::End),
|
||||||
RecordField::SpaceBefore
|
RecordField::SpaceBefore
|
||||||
),
|
),
|
||||||
})),
|
})),
|
||||||
word1(b'}', ERecord::End)
|
byte(b'}', ERecord::End)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn record_literal_help<'a>() -> impl Parser<'a, Expr<'a>, EExpr<'a>> {
|
fn record_literal_help<'a>() -> impl Parser<'a, Expr<'a>, EExpr<'a>> {
|
||||||
then(
|
then(
|
||||||
and!(
|
and!(
|
||||||
specialize(EExpr::Record, record_help()),
|
specialize_err(EExpr::Record, record_help()),
|
||||||
// there can be field access, e.g. `{ x : 4 }.x`
|
// there can be field access, e.g. `{ x : 4 }.x`
|
||||||
record_field_access_chain()
|
record_field_access_chain()
|
||||||
),
|
),
|
||||||
|
|
|
@ -4,8 +4,8 @@ use crate::ast::{
|
||||||
use crate::blankspace::space0_e;
|
use crate::blankspace::space0_e;
|
||||||
use crate::expr::merge_spaces;
|
use crate::expr::merge_spaces;
|
||||||
use crate::ident::{lowercase_ident, UppercaseIdent};
|
use crate::ident::{lowercase_ident, UppercaseIdent};
|
||||||
|
use crate::parser::{byte, specialize_err, EPackageEntry, EPackageName, Parser};
|
||||||
use crate::parser::{optional, then};
|
use crate::parser::{optional, then};
|
||||||
use crate::parser::{specialize, word1, EPackageEntry, EPackageName, Parser};
|
|
||||||
use crate::string_literal;
|
use crate::string_literal;
|
||||||
use roc_module::symbol::{ModuleId, Symbol};
|
use roc_module::symbol::{ModuleId, Symbol};
|
||||||
use roc_region::all::Loc;
|
use roc_region::all::Loc;
|
||||||
|
@ -346,14 +346,14 @@ pub fn package_entry<'a>() -> impl Parser<'a, Spaced<'a, PackageEntry<'a>>, EPac
|
||||||
optional(and!(
|
optional(and!(
|
||||||
skip_second!(
|
skip_second!(
|
||||||
and!(
|
and!(
|
||||||
specialize(|_, pos| EPackageEntry::Shorthand(pos), lowercase_ident()),
|
specialize_err(|_, pos| EPackageEntry::Shorthand(pos), lowercase_ident()),
|
||||||
space0_e(EPackageEntry::IndentPackage)
|
space0_e(EPackageEntry::IndentPackage)
|
||||||
),
|
),
|
||||||
word1(b':', EPackageEntry::Colon)
|
byte(b':', EPackageEntry::Colon)
|
||||||
),
|
),
|
||||||
space0_e(EPackageEntry::IndentPackage)
|
space0_e(EPackageEntry::IndentPackage)
|
||||||
)),
|
)),
|
||||||
loc!(specialize(EPackageEntry::BadPackage, package_name()))
|
loc!(specialize_err(EPackageEntry::BadPackage, package_name()))
|
||||||
),
|
),
|
||||||
move |arena, (opt_shorthand, package_or_path)| {
|
move |arena, (opt_shorthand, package_or_path)| {
|
||||||
let entry = match opt_shorthand {
|
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>> {
|
pub fn package_name<'a>() -> impl Parser<'a, PackageName<'a>, EPackageName<'a>> {
|
||||||
then(
|
then(
|
||||||
loc!(specialize(
|
loc!(specialize_err(
|
||||||
EPackageName::BadPath,
|
EPackageName::BadPath,
|
||||||
string_literal::parse_str_literal()
|
string_literal::parse_str_literal()
|
||||||
)),
|
)),
|
||||||
|
|
|
@ -9,9 +9,9 @@ use crate::header::{
|
||||||
use crate::ident::{self, lowercase_ident, unqualified_ident, uppercase, UppercaseIdent};
|
use crate::ident::{self, lowercase_ident, unqualified_ident, uppercase, UppercaseIdent};
|
||||||
use crate::parser::Progress::{self, *};
|
use crate::parser::Progress::{self, *};
|
||||||
use crate::parser::{
|
use crate::parser::{
|
||||||
backtrackable, increment_min_indent, optional, reset_min_indent, specialize, word1, word2,
|
backtrackable, byte, increment_min_indent, optional, reset_min_indent, specialize_err,
|
||||||
EExposes, EGenerates, EGeneratesWith, EHeader, EImports, EPackages, EProvides, ERequires,
|
two_bytes, EExposes, EGenerates, EGeneratesWith, EHeader, EImports, EPackages, EProvides,
|
||||||
ETypedIdent, Parser, SourceError, SpaceProblem, SyntaxError,
|
ERequires, ETypedIdent, Parser, SourceError, SpaceProblem, SyntaxError,
|
||||||
};
|
};
|
||||||
use crate::state::State;
|
use crate::state::State;
|
||||||
use crate::string_literal::{self, parse_str_literal};
|
use crate::string_literal::{self, parse_str_literal};
|
||||||
|
@ -31,7 +31,7 @@ fn end_of_file<'a>() -> impl Parser<'a, (), SyntaxError<'a>> {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn module_defs<'a>() -> impl Parser<'a, Defs<'a>, SyntaxError<'a>> {
|
pub fn module_defs<'a>() -> impl Parser<'a, Defs<'a>, SyntaxError<'a>> {
|
||||||
skip_second!(
|
skip_second!(
|
||||||
specialize(SyntaxError::Expr, crate::expr::toplevel_defs(),),
|
specialize_err(SyntaxError::Expr, crate::expr::toplevel_defs(),),
|
||||||
end_of_file()
|
end_of_file()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -48,42 +48,42 @@ pub fn parse_header<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn header<'a>() -> impl Parser<'a, Module<'a>, EHeader<'a>> {
|
pub fn header<'a>() -> impl Parser<'a, Module<'a>, EHeader<'a>> {
|
||||||
use crate::parser::keyword_e;
|
use crate::parser::keyword;
|
||||||
|
|
||||||
record!(Module {
|
record!(Module {
|
||||||
comments: space0_e(EHeader::IndentStart),
|
comments: space0_e(EHeader::IndentStart),
|
||||||
header: one_of![
|
header: one_of![
|
||||||
map!(
|
map!(
|
||||||
skip_first!(
|
skip_first!(
|
||||||
keyword_e("interface", EHeader::Start),
|
keyword("interface", EHeader::Start),
|
||||||
increment_min_indent(interface_header())
|
increment_min_indent(interface_header())
|
||||||
),
|
),
|
||||||
Header::Interface
|
Header::Interface
|
||||||
),
|
),
|
||||||
map!(
|
map!(
|
||||||
skip_first!(
|
skip_first!(
|
||||||
keyword_e("app", EHeader::Start),
|
keyword("app", EHeader::Start),
|
||||||
increment_min_indent(app_header())
|
increment_min_indent(app_header())
|
||||||
),
|
),
|
||||||
Header::App
|
Header::App
|
||||||
),
|
),
|
||||||
map!(
|
map!(
|
||||||
skip_first!(
|
skip_first!(
|
||||||
keyword_e("package", EHeader::Start),
|
keyword("package", EHeader::Start),
|
||||||
increment_min_indent(package_header())
|
increment_min_indent(package_header())
|
||||||
),
|
),
|
||||||
Header::Package
|
Header::Package
|
||||||
),
|
),
|
||||||
map!(
|
map!(
|
||||||
skip_first!(
|
skip_first!(
|
||||||
keyword_e("platform", EHeader::Start),
|
keyword("platform", EHeader::Start),
|
||||||
increment_min_indent(platform_header())
|
increment_min_indent(platform_header())
|
||||||
),
|
),
|
||||||
Header::Platform
|
Header::Platform
|
||||||
),
|
),
|
||||||
map!(
|
map!(
|
||||||
skip_first!(
|
skip_first!(
|
||||||
keyword_e("hosted", EHeader::Start),
|
keyword("hosted", EHeader::Start),
|
||||||
increment_min_indent(hosted_header())
|
increment_min_indent(hosted_header())
|
||||||
),
|
),
|
||||||
Header::Hosted
|
Header::Hosted
|
||||||
|
@ -97,8 +97,8 @@ fn interface_header<'a>() -> impl Parser<'a, InterfaceHeader<'a>, EHeader<'a>> {
|
||||||
record!(InterfaceHeader {
|
record!(InterfaceHeader {
|
||||||
before_name: space0_e(EHeader::IndentStart),
|
before_name: space0_e(EHeader::IndentStart),
|
||||||
name: loc!(module_name_help(EHeader::ModuleName)),
|
name: loc!(module_name_help(EHeader::ModuleName)),
|
||||||
exposes: specialize(EHeader::Exposes, exposes_values()),
|
exposes: specialize_err(EHeader::Exposes, exposes_values()),
|
||||||
imports: specialize(EHeader::Imports, imports()),
|
imports: specialize_err(EHeader::Imports, imports()),
|
||||||
})
|
})
|
||||||
.trace("interface_header")
|
.trace("interface_header")
|
||||||
}
|
}
|
||||||
|
@ -108,10 +108,10 @@ fn hosted_header<'a>() -> impl Parser<'a, HostedHeader<'a>, EHeader<'a>> {
|
||||||
record!(HostedHeader {
|
record!(HostedHeader {
|
||||||
before_name: space0_e(EHeader::IndentStart),
|
before_name: space0_e(EHeader::IndentStart),
|
||||||
name: loc!(module_name_help(EHeader::ModuleName)),
|
name: loc!(module_name_help(EHeader::ModuleName)),
|
||||||
exposes: specialize(EHeader::Exposes, exposes_values()),
|
exposes: specialize_err(EHeader::Exposes, exposes_values()),
|
||||||
imports: specialize(EHeader::Imports, imports()),
|
imports: specialize_err(EHeader::Imports, imports()),
|
||||||
generates: specialize(EHeader::Generates, generates()),
|
generates: specialize_err(EHeader::Generates, generates()),
|
||||||
generates_with: specialize(EHeader::GeneratesWith, generates_with()),
|
generates_with: specialize_err(EHeader::GeneratesWith, generates_with()),
|
||||||
})
|
})
|
||||||
.trace("hosted_header")
|
.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>> {
|
fn app_header<'a>() -> impl Parser<'a, AppHeader<'a>, EHeader<'a>> {
|
||||||
record!(AppHeader {
|
record!(AppHeader {
|
||||||
before_name: space0_e(EHeader::IndentStart),
|
before_name: space0_e(EHeader::IndentStart),
|
||||||
name: loc!(crate::parser::specialize(
|
name: loc!(crate::parser::specialize_err(
|
||||||
EHeader::AppName,
|
EHeader::AppName,
|
||||||
string_literal::parse_str_literal()
|
string_literal::parse_str_literal()
|
||||||
)),
|
)),
|
||||||
packages: optional(specialize(EHeader::Packages, packages())),
|
packages: optional(specialize_err(EHeader::Packages, packages())),
|
||||||
imports: optional(specialize(EHeader::Imports, imports())),
|
imports: optional(specialize_err(EHeader::Imports, imports())),
|
||||||
provides: specialize(EHeader::Provides, provides_to()),
|
provides: specialize_err(EHeader::Provides, provides_to()),
|
||||||
})
|
})
|
||||||
.trace("app_header")
|
.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>> {
|
fn package_header<'a>() -> impl Parser<'a, PackageHeader<'a>, EHeader<'a>> {
|
||||||
record!(PackageHeader {
|
record!(PackageHeader {
|
||||||
before_name: space0_e(EHeader::IndentStart),
|
before_name: space0_e(EHeader::IndentStart),
|
||||||
name: loc!(specialize(EHeader::PackageName, package_name())),
|
name: loc!(specialize_err(EHeader::PackageName, package_name())),
|
||||||
exposes: specialize(EHeader::Exposes, exposes_modules()),
|
exposes: specialize_err(EHeader::Exposes, exposes_modules()),
|
||||||
packages: specialize(EHeader::Packages, packages()),
|
packages: specialize_err(EHeader::Packages, packages()),
|
||||||
})
|
})
|
||||||
.trace("package_header")
|
.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>> {
|
fn platform_header<'a>() -> impl Parser<'a, PlatformHeader<'a>, EHeader<'a>> {
|
||||||
record!(PlatformHeader {
|
record!(PlatformHeader {
|
||||||
before_name: space0_e(EHeader::IndentStart),
|
before_name: space0_e(EHeader::IndentStart),
|
||||||
name: loc!(specialize(EHeader::PlatformName, package_name())),
|
name: loc!(specialize_err(EHeader::PlatformName, package_name())),
|
||||||
requires: specialize(EHeader::Requires, requires()),
|
requires: specialize_err(EHeader::Requires, requires()),
|
||||||
exposes: specialize(EHeader::Exposes, exposes_modules()),
|
exposes: specialize_err(EHeader::Exposes, exposes_modules()),
|
||||||
packages: specialize(EHeader::Packages, packages()),
|
packages: specialize_err(EHeader::Packages, packages()),
|
||||||
imports: specialize(EHeader::Imports, imports()),
|
imports: specialize_err(EHeader::Imports, imports()),
|
||||||
provides: specialize(EHeader::Provides, provides_exposed()),
|
provides: specialize_err(EHeader::Provides, provides_exposed()),
|
||||||
})
|
})
|
||||||
.trace("platform_header")
|
.trace("platform_header")
|
||||||
}
|
}
|
||||||
|
|
||||||
fn provides_to_package<'a>() -> impl Parser<'a, To<'a>, EProvides<'a>> {
|
fn provides_to_package<'a>() -> impl Parser<'a, To<'a>, EProvides<'a>> {
|
||||||
one_of![
|
one_of![
|
||||||
specialize(
|
specialize_err(
|
||||||
|_, pos| EProvides::Identifier(pos),
|
|_, pos| EProvides::Identifier(pos),
|
||||||
map!(lowercase_ident(), To::ExistingPackage)
|
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
|
EProvides::IndentListStart
|
||||||
),
|
),
|
||||||
entries: collection_trailing_sep_e!(
|
entries: collection_trailing_sep_e!(
|
||||||
word1(b'[', EProvides::ListStart),
|
byte(b'[', EProvides::ListStart),
|
||||||
exposes_entry(EProvides::Identifier),
|
exposes_entry(EProvides::Identifier),
|
||||||
word1(b',', EProvides::ListEnd),
|
byte(b',', EProvides::ListEnd),
|
||||||
word1(b']', EProvides::ListEnd),
|
byte(b']', EProvides::ListEnd),
|
||||||
Spaced::SpaceBefore
|
Spaced::SpaceBefore
|
||||||
),
|
),
|
||||||
types: optional(backtrackable(provides_types())),
|
types: optional(backtrackable(provides_types())),
|
||||||
|
@ -266,10 +266,10 @@ fn provides_exposed<'a>() -> impl Parser<
|
||||||
EProvides::IndentListStart
|
EProvides::IndentListStart
|
||||||
),
|
),
|
||||||
item: collection_trailing_sep_e!(
|
item: collection_trailing_sep_e!(
|
||||||
word1(b'[', EProvides::ListStart),
|
byte(b'[', EProvides::ListStart),
|
||||||
exposes_entry(EProvides::Identifier),
|
exposes_entry(EProvides::Identifier),
|
||||||
word1(b',', EProvides::ListEnd),
|
byte(b',', EProvides::ListEnd),
|
||||||
word1(b']', EProvides::ListEnd),
|
byte(b']', EProvides::ListEnd),
|
||||||
Spaced::SpaceBefore
|
Spaced::SpaceBefore
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
@ -283,7 +283,7 @@ fn provides_types<'a>(
|
||||||
// to be the design forever. Someday it will hopefully work like Elm,
|
// to be the design forever. Someday it will hopefully work like Elm,
|
||||||
// where platform authors can provide functions like Browser.sandbox which
|
// where platform authors can provide functions like Browser.sandbox which
|
||||||
// present an API based on ordinary-looking type variables.
|
// present an API based on ordinary-looking type variables.
|
||||||
zero_or_more!(word1(
|
zero_or_more!(byte(
|
||||||
b' ',
|
b' ',
|
||||||
// HACK: If this errors, EProvides::Provides is not an accurate reflection
|
// HACK: If this errors, EProvides::Provides is not an accurate reflection
|
||||||
// of what went wrong. However, this is both skipped and zero_or_more,
|
// of what went wrong. However, this is both skipped and zero_or_more,
|
||||||
|
@ -291,10 +291,10 @@ fn provides_types<'a>(
|
||||||
EProvides::Provides
|
EProvides::Provides
|
||||||
)),
|
)),
|
||||||
collection_trailing_sep_e!(
|
collection_trailing_sep_e!(
|
||||||
word1(b'{', EProvides::ListStart),
|
byte(b'{', EProvides::ListStart),
|
||||||
provides_type_entry(EProvides::Identifier),
|
provides_type_entry(EProvides::Identifier),
|
||||||
word1(b',', EProvides::ListEnd),
|
byte(b',', EProvides::ListEnd),
|
||||||
word1(b'}', EProvides::ListEnd),
|
byte(b'}', EProvides::ListEnd),
|
||||||
Spaced::SpaceBefore
|
Spaced::SpaceBefore
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -309,7 +309,7 @@ where
|
||||||
E: 'a,
|
E: 'a,
|
||||||
{
|
{
|
||||||
loc!(map!(
|
loc!(map!(
|
||||||
specialize(|_, pos| to_expectation(pos), ident::uppercase()),
|
specialize_err(|_, pos| to_expectation(pos), ident::uppercase()),
|
||||||
Spaced::Item
|
Spaced::Item
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -323,7 +323,7 @@ where
|
||||||
E: 'a,
|
E: 'a,
|
||||||
{
|
{
|
||||||
loc!(map!(
|
loc!(map!(
|
||||||
specialize(|_, pos| to_expectation(pos), unqualified_ident()),
|
specialize_err(|_, pos| to_expectation(pos), unqualified_ident()),
|
||||||
|n| Spaced::Item(ExposedName::new(n))
|
|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>(
|
fn requires_rigids<'a>(
|
||||||
) -> impl Parser<'a, Collection<'a, Loc<Spaced<'a, UppercaseIdent<'a>>>>, ERequires<'a>> {
|
) -> impl Parser<'a, Collection<'a, Loc<Spaced<'a, UppercaseIdent<'a>>>>, ERequires<'a>> {
|
||||||
collection_trailing_sep_e!(
|
collection_trailing_sep_e!(
|
||||||
word1(b'{', ERequires::ListStart),
|
byte(b'{', ERequires::ListStart),
|
||||||
specialize(
|
specialize_err(
|
||||||
|_, pos| ERequires::Rigid(pos),
|
|_, pos| ERequires::Rigid(pos),
|
||||||
loc!(map!(ident::uppercase(), Spaced::Item))
|
loc!(map!(ident::uppercase(), Spaced::Item))
|
||||||
),
|
),
|
||||||
word1(b',', ERequires::ListEnd),
|
byte(b',', ERequires::ListEnd),
|
||||||
word1(b'}', ERequires::ListEnd),
|
byte(b'}', ERequires::ListEnd),
|
||||||
Spaced::SpaceBefore
|
Spaced::SpaceBefore
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -368,14 +368,14 @@ fn requires_rigids<'a>(
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn requires_typed_ident<'a>() -> impl Parser<'a, Loc<Spaced<'a, TypedIdent<'a>>>, ERequires<'a>> {
|
fn requires_typed_ident<'a>() -> impl Parser<'a, Loc<Spaced<'a, TypedIdent<'a>>>, ERequires<'a>> {
|
||||||
skip_first!(
|
skip_first!(
|
||||||
word1(b'{', ERequires::ListStart),
|
byte(b'{', ERequires::ListStart),
|
||||||
skip_second!(
|
skip_second!(
|
||||||
reset_min_indent(space0_around_ee(
|
reset_min_indent(space0_around_ee(
|
||||||
specialize(ERequires::TypedIdent, loc!(typed_ident()),),
|
specialize_err(ERequires::TypedIdent, loc!(typed_ident()),),
|
||||||
ERequires::ListStart,
|
ERequires::ListStart,
|
||||||
ERequires::ListEnd
|
ERequires::ListEnd
|
||||||
)),
|
)),
|
||||||
word1(b'}', ERequires::ListStart)
|
byte(b'}', ERequires::ListStart)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -394,10 +394,10 @@ fn exposes_values<'a>() -> impl Parser<
|
||||||
EExposes::IndentListStart
|
EExposes::IndentListStart
|
||||||
),
|
),
|
||||||
item: collection_trailing_sep_e!(
|
item: collection_trailing_sep_e!(
|
||||||
word1(b'[', EExposes::ListStart),
|
byte(b'[', EExposes::ListStart),
|
||||||
exposes_entry(EExposes::Identifier),
|
exposes_entry(EExposes::Identifier),
|
||||||
word1(b',', EExposes::ListEnd),
|
byte(b',', EExposes::ListEnd),
|
||||||
word1(b']', EExposes::ListEnd),
|
byte(b']', EExposes::ListEnd),
|
||||||
Spaced::SpaceBefore
|
Spaced::SpaceBefore
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -416,7 +416,7 @@ where
|
||||||
and!(
|
and!(
|
||||||
skip_second!(
|
skip_second!(
|
||||||
backtrackable(space0_e(indent_problem1)),
|
backtrackable(space0_e(indent_problem1)),
|
||||||
crate::parser::keyword_e(K::KEYWORD, expectation)
|
crate::parser::keyword(K::KEYWORD, expectation)
|
||||||
),
|
),
|
||||||
space0_e(indent_problem2)
|
space0_e(indent_problem2)
|
||||||
),
|
),
|
||||||
|
@ -444,10 +444,10 @@ fn exposes_modules<'a>() -> impl Parser<
|
||||||
EExposes::IndentListStart
|
EExposes::IndentListStart
|
||||||
),
|
),
|
||||||
item: collection_trailing_sep_e!(
|
item: collection_trailing_sep_e!(
|
||||||
word1(b'[', EExposes::ListStart),
|
byte(b'[', EExposes::ListStart),
|
||||||
exposes_module(EExposes::Identifier),
|
exposes_module(EExposes::Identifier),
|
||||||
word1(b',', EExposes::ListEnd),
|
byte(b',', EExposes::ListEnd),
|
||||||
word1(b']', EExposes::ListEnd),
|
byte(b']', EExposes::ListEnd),
|
||||||
Spaced::SpaceBefore
|
Spaced::SpaceBefore
|
||||||
),
|
),
|
||||||
})
|
})
|
||||||
|
@ -462,7 +462,7 @@ where
|
||||||
E: 'a,
|
E: 'a,
|
||||||
{
|
{
|
||||||
loc!(map!(
|
loc!(map!(
|
||||||
specialize(|_, pos| to_expectation(pos), module_name()),
|
specialize_err(|_, pos| to_expectation(pos), module_name()),
|
||||||
Spaced::Item
|
Spaced::Item
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -481,10 +481,10 @@ fn packages<'a>() -> impl Parser<
|
||||||
EPackages::IndentListStart
|
EPackages::IndentListStart
|
||||||
),
|
),
|
||||||
item: collection_trailing_sep_e!(
|
item: collection_trailing_sep_e!(
|
||||||
word1(b'{', EPackages::ListStart),
|
byte(b'{', EPackages::ListStart),
|
||||||
specialize(EPackages::PackageEntry, loc!(package_entry())),
|
specialize_err(EPackages::PackageEntry, loc!(package_entry())),
|
||||||
word1(b',', EPackages::ListEnd),
|
byte(b',', EPackages::ListEnd),
|
||||||
word1(b'}', EPackages::ListEnd),
|
byte(b'}', EPackages::ListEnd),
|
||||||
Spaced::SpaceBefore
|
Spaced::SpaceBefore
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -500,7 +500,7 @@ fn generates<'a>(
|
||||||
EGenerates::IndentGenerates,
|
EGenerates::IndentGenerates,
|
||||||
EGenerates::IndentTypeStart
|
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
|
EGeneratesWith::IndentListStart
|
||||||
),
|
),
|
||||||
item: collection_trailing_sep_e!(
|
item: collection_trailing_sep_e!(
|
||||||
word1(b'[', EGeneratesWith::ListStart),
|
byte(b'[', EGeneratesWith::ListStart),
|
||||||
exposes_entry(EGeneratesWith::Identifier),
|
exposes_entry(EGeneratesWith::Identifier),
|
||||||
word1(b',', EGeneratesWith::ListEnd),
|
byte(b',', EGeneratesWith::ListEnd),
|
||||||
word1(b']', EGeneratesWith::ListEnd),
|
byte(b']', EGeneratesWith::ListEnd),
|
||||||
Spaced::SpaceBefore
|
Spaced::SpaceBefore
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -541,10 +541,10 @@ fn imports<'a>() -> impl Parser<
|
||||||
EImports::IndentListStart
|
EImports::IndentListStart
|
||||||
),
|
),
|
||||||
item: collection_trailing_sep_e!(
|
item: collection_trailing_sep_e!(
|
||||||
word1(b'[', EImports::ListStart),
|
byte(b'[', EImports::ListStart),
|
||||||
loc!(imports_entry()),
|
loc!(imports_entry()),
|
||||||
word1(b',', EImports::ListEnd),
|
byte(b',', EImports::ListEnd),
|
||||||
word1(b']', EImports::ListEnd),
|
byte(b']', EImports::ListEnd),
|
||||||
Spaced::SpaceBefore
|
Spaced::SpaceBefore
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -559,16 +559,16 @@ fn typed_ident<'a>() -> impl Parser<'a, Spaced<'a, TypedIdent<'a>>, ETypedIdent<
|
||||||
map!(
|
map!(
|
||||||
and!(
|
and!(
|
||||||
and!(
|
and!(
|
||||||
loc!(specialize(
|
loc!(specialize_err(
|
||||||
|_, pos| ETypedIdent::Identifier(pos),
|
|_, pos| ETypedIdent::Identifier(pos),
|
||||||
lowercase_ident()
|
lowercase_ident()
|
||||||
)),
|
)),
|
||||||
space0_e(ETypedIdent::IndentHasType)
|
space0_e(ETypedIdent::IndentHasType)
|
||||||
),
|
),
|
||||||
skip_first!(
|
skip_first!(
|
||||||
word1(b':', ETypedIdent::HasType),
|
byte(b':', ETypedIdent::HasType),
|
||||||
space0_before_e(
|
space0_before_e(
|
||||||
specialize(
|
specialize_err(
|
||||||
ETypedIdent::Type,
|
ETypedIdent::Type,
|
||||||
reset_min_indent(type_annotation::located(true))
|
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> {
|
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>
|
fn module_name_help<'a, F, E>(to_expectation: F) -> impl Parser<'a, ModuleName<'a>, E>
|
||||||
|
@ -596,7 +596,7 @@ where
|
||||||
E: 'a,
|
E: 'a,
|
||||||
F: 'a,
|
F: 'a,
|
||||||
{
|
{
|
||||||
specialize(move |_, pos| to_expectation(pos), module_name())
|
specialize_err(move |_, pos| to_expectation(pos), module_name())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -613,19 +613,19 @@ fn imports_entry<'a>() -> impl Parser<'a, Spaced<'a, ImportsEntry<'a>>, EImports
|
||||||
// e.g. `pf.`
|
// e.g. `pf.`
|
||||||
optional(backtrackable(skip_second!(
|
optional(backtrackable(skip_second!(
|
||||||
shortname(),
|
shortname(),
|
||||||
word1(b'.', EImports::ShorthandDot)
|
byte(b'.', EImports::ShorthandDot)
|
||||||
))),
|
))),
|
||||||
// e.g. `Task`
|
// e.g. `Task`
|
||||||
module_name_help(EImports::ModuleName)
|
module_name_help(EImports::ModuleName)
|
||||||
),
|
),
|
||||||
// e.g. `.{ Task, after}`
|
// e.g. `.{ Task, after}`
|
||||||
optional(skip_first!(
|
optional(skip_first!(
|
||||||
word1(b'.', EImports::ExposingDot),
|
byte(b'.', EImports::ExposingDot),
|
||||||
collection_trailing_sep_e!(
|
collection_trailing_sep_e!(
|
||||||
word1(b'{', EImports::SetStart),
|
byte(b'{', EImports::SetStart),
|
||||||
exposes_entry(EImports::Identifier),
|
exposes_entry(EImports::Identifier),
|
||||||
word1(b',', EImports::SetEnd),
|
byte(b',', EImports::SetEnd),
|
||||||
word1(b'}', EImports::SetEnd),
|
byte(b'}', EImports::SetEnd),
|
||||||
Spaced::SpaceBefore
|
Spaced::SpaceBefore
|
||||||
)
|
)
|
||||||
))
|
))
|
||||||
|
@ -650,18 +650,18 @@ fn imports_entry<'a>() -> impl Parser<'a, Spaced<'a, ImportsEntry<'a>>, EImports
|
||||||
and!(
|
and!(
|
||||||
// e.g. "filename"
|
// e.g. "filename"
|
||||||
// TODO: str literal allows for multiline strings. We probably don't want that for file names.
|
// 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
|
// e.g. as
|
||||||
and!(
|
and!(
|
||||||
and!(
|
and!(
|
||||||
space0_e(EImports::AsKeyword),
|
space0_e(EImports::AsKeyword),
|
||||||
word2(b'a', b's', EImports::AsKeyword)
|
two_bytes(b'a', b's', EImports::AsKeyword)
|
||||||
),
|
),
|
||||||
space0_e(EImports::AsKeyword)
|
space0_e(EImports::AsKeyword)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
// e.g. file : Str
|
// e.g. file : Str
|
||||||
specialize(|_, pos| EImports::TypedIdent(pos), typed_ident())
|
specialize_err(|_, pos| EImports::TypedIdent(pos), typed_ident())
|
||||||
),
|
),
|
||||||
|((file_name, _), typed_ident)| {
|
|((file_name, _), typed_ident)| {
|
||||||
// TODO: look at blacking block strings during parsing.
|
// TODO: look at blacking block strings during parsing.
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -4,8 +4,8 @@ use crate::ident::{lowercase_ident, parse_ident, Accessor, Ident};
|
||||||
use crate::keyword;
|
use crate::keyword;
|
||||||
use crate::parser::Progress::{self, *};
|
use crate::parser::Progress::{self, *};
|
||||||
use crate::parser::{
|
use crate::parser::{
|
||||||
self, backtrackable, fail_when, optional, specialize, specialize_ref, then, word1, word2,
|
self, backtrackable, byte, fail_when, optional, specialize_err, specialize_err_ref, then,
|
||||||
word3, EPattern, PInParens, PList, PRecord, Parser,
|
three_bytes, two_bytes, EPattern, PInParens, PList, PRecord, Parser,
|
||||||
};
|
};
|
||||||
use crate::state::State;
|
use crate::state::State;
|
||||||
use crate::string_literal::StrLikeLiteral;
|
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. \_ -> ...
|
// Underscore is also common, e.g. \_ -> ...
|
||||||
loc!(underscore_pattern_help()),
|
loc!(underscore_pattern_help()),
|
||||||
// You can destructure records in params, e.g. \{ x, y } -> ...
|
// You can destructure records in params, e.g. \{ x, y } -> ...
|
||||||
loc!(specialize(
|
loc!(specialize_err(
|
||||||
EPattern::Record,
|
EPattern::Record,
|
||||||
crate::pattern::record_pattern_help()
|
crate::pattern::record_pattern_help()
|
||||||
)),
|
)),
|
||||||
// If you wrap it in parens, you can match any arbitrary pattern at all.
|
// If you wrap it in parens, you can match any arbitrary pattern at all.
|
||||||
// e.g. \User.UserId userId -> ...
|
// 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>> {
|
fn loc_pattern_help_help<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, EPattern<'a>> {
|
||||||
one_of!(
|
one_of!(
|
||||||
specialize(EPattern::PInParens, loc_pattern_in_parens_help()),
|
specialize_err(EPattern::PInParens, loc_pattern_in_parens_help()),
|
||||||
loc!(underscore_pattern_help()),
|
loc!(underscore_pattern_help()),
|
||||||
loc_ident_pattern_help(true),
|
loc_ident_pattern_help(true),
|
||||||
loc!(specialize(
|
loc!(specialize_err(
|
||||||
EPattern::Record,
|
EPattern::Record,
|
||||||
crate::pattern::record_pattern_help()
|
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!(number_pattern_help()),
|
||||||
loc!(string_like_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>> {
|
fn pattern_as<'a>() -> impl Parser<'a, PatternAs<'a>, EPattern<'a>> {
|
||||||
move |arena, state: State<'a>, min_indent| {
|
move |arena, state: State<'a>, min_indent| {
|
||||||
let (_, _, state) =
|
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) =
|
let (_, spaces, state) =
|
||||||
space0_e(EPattern::AsIdentifier).parse(arena, state, min_indent)?;
|
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>> {
|
fn loc_parse_tag_pattern_arg<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, EPattern<'a>> {
|
||||||
one_of!(
|
one_of!(
|
||||||
specialize(EPattern::PInParens, loc_pattern_in_parens_help()),
|
specialize_err(EPattern::PInParens, loc_pattern_in_parens_help()),
|
||||||
loc!(underscore_pattern_help()),
|
loc!(underscore_pattern_help()),
|
||||||
// Make sure `Foo Bar 1` is parsed as `Foo (Bar) 1`, and not `Foo (Bar 1)`
|
// Make sure `Foo Bar 1` is parsed as `Foo (Bar) 1`, and not `Foo (Bar 1)`
|
||||||
loc_ident_pattern_help(false),
|
loc_ident_pattern_help(false),
|
||||||
loc!(specialize(
|
loc!(specialize_err(
|
||||||
EPattern::Record,
|
EPattern::Record,
|
||||||
crate::pattern::record_pattern_help()
|
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>> {
|
fn loc_pattern_in_parens_help<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, PInParens<'a>> {
|
||||||
then(
|
then(
|
||||||
loc!(collection_trailing_sep_e!(
|
loc!(collection_trailing_sep_e!(
|
||||||
word1(b'(', PInParens::Open),
|
byte(b'(', PInParens::Open),
|
||||||
specialize_ref(PInParens::Pattern, loc_pattern_help()),
|
specialize_err_ref(PInParens::Pattern, loc_pattern_help()),
|
||||||
word1(b',', PInParens::End),
|
byte(b',', PInParens::End),
|
||||||
word1(b')', PInParens::End),
|
byte(b')', PInParens::End),
|
||||||
Pattern::SpaceBefore
|
Pattern::SpaceBefore
|
||||||
)),
|
)),
|
||||||
move |_arena, state, _, loc_elements| {
|
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>> {
|
fn number_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, EPattern<'a>> {
|
||||||
specialize(
|
specialize_err(
|
||||||
EPattern::NumLiteral,
|
EPattern::NumLiteral,
|
||||||
map!(crate::number_literal::number_literal(), |literal| {
|
map!(crate::number_literal::number_literal(), |literal| {
|
||||||
use crate::number_literal::NumLiteral::*;
|
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>> {
|
fn string_like_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, EPattern<'a>> {
|
||||||
specialize(
|
specialize_err(
|
||||||
|_, pos| EPattern::Start(pos),
|
|_, pos| EPattern::Start(pos),
|
||||||
map_with_arena!(
|
map_with_arena!(
|
||||||
crate::string_literal::parse_str_like_literal(),
|
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>> {
|
fn list_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, PList<'a>> {
|
||||||
map!(
|
map!(
|
||||||
collection_trailing_sep_e!(
|
collection_trailing_sep_e!(
|
||||||
word1(b'[', PList::Open),
|
byte(b'[', PList::Open),
|
||||||
list_element_pattern(),
|
list_element_pattern(),
|
||||||
word1(b',', PList::End),
|
byte(b',', PList::End),
|
||||||
word1(b']', PList::End),
|
byte(b']', PList::End),
|
||||||
Pattern::SpaceBefore
|
Pattern::SpaceBefore
|
||||||
),
|
),
|
||||||
Pattern::List
|
Pattern::List
|
||||||
|
@ -277,18 +277,21 @@ fn list_element_pattern<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, PList<'a>> {
|
||||||
one_of!(
|
one_of!(
|
||||||
three_list_rest_pattern_error(),
|
three_list_rest_pattern_error(),
|
||||||
list_rest_pattern(),
|
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>> {
|
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>> {
|
fn list_rest_pattern<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, PList<'a>> {
|
||||||
move |arena: &'a Bump, state: State<'a>, min_indent: u32| {
|
move |arena: &'a Bump, state: State<'a>, min_indent: u32| {
|
||||||
let (_, loc_word, state) =
|
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));
|
let no_as = Loc::at(loc_word.region, Pattern::ListRest(None));
|
||||||
|
|
||||||
|
@ -323,7 +326,8 @@ fn loc_ident_pattern_help<'a>(
|
||||||
move |arena: &'a Bump, state: State<'a>, min_indent: u32| {
|
move |arena: &'a Bump, state: State<'a>, min_indent: u32| {
|
||||||
let original_state = state.clone();
|
let original_state = state.clone();
|
||||||
|
|
||||||
let (_, loc_ident, state) = specialize(|_, pos| EPattern::Start(pos), loc!(parse_ident))
|
let (_, loc_ident, state) =
|
||||||
|
specialize_err(|_, pos| EPattern::Start(pos), loc!(parse_ident))
|
||||||
.parse(arena, state, min_indent)?;
|
.parse(arena, state, min_indent)?;
|
||||||
|
|
||||||
match loc_ident.value {
|
match loc_ident.value {
|
||||||
|
@ -449,7 +453,7 @@ fn loc_ident_pattern_help<'a>(
|
||||||
fn underscore_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, EPattern<'a>> {
|
fn underscore_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, EPattern<'a>> {
|
||||||
map!(
|
map!(
|
||||||
skip_first!(
|
skip_first!(
|
||||||
word1(b'_', EPattern::Underscore),
|
byte(b'_', EPattern::Underscore),
|
||||||
optional(lowercase_ident_pattern())
|
optional(lowercase_ident_pattern())
|
||||||
),
|
),
|
||||||
|output| match output {
|
|output| match output {
|
||||||
|
@ -460,17 +464,17 @@ fn underscore_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, EPattern<'a>> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lowercase_ident_pattern<'a>() -> impl Parser<'a, &'a str, EPattern<'a>> {
|
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)]
|
#[inline(always)]
|
||||||
fn record_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, PRecord<'a>> {
|
fn record_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, PRecord<'a>> {
|
||||||
map!(
|
map!(
|
||||||
collection_trailing_sep_e!(
|
collection_trailing_sep_e!(
|
||||||
word1(b'{', PRecord::Open),
|
byte(b'{', PRecord::Open),
|
||||||
record_pattern_field(),
|
record_pattern_field(),
|
||||||
word1(b',', PRecord::End),
|
byte(b',', PRecord::End),
|
||||||
word1(b'}', PRecord::End),
|
byte(b'}', PRecord::End),
|
||||||
Pattern::SpaceBefore
|
Pattern::SpaceBefore
|
||||||
),
|
),
|
||||||
Pattern::RecordDestructure
|
Pattern::RecordDestructure
|
||||||
|
@ -484,7 +488,7 @@ fn record_pattern_field<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, PRecord<'a>>
|
||||||
// You must have a field name, e.g. "email"
|
// You must have a field name, e.g. "email"
|
||||||
// using the initial pos is important for error reporting
|
// using the initial pos is important for error reporting
|
||||||
let pos = state.pos();
|
let pos = state.pos();
|
||||||
let (progress, loc_label, state) = loc!(specialize(
|
let (progress, loc_label, state) = loc!(specialize_err(
|
||||||
move |_, _| PRecord::Field(pos),
|
move |_, _| PRecord::Field(pos),
|
||||||
lowercase_ident()
|
lowercase_ident()
|
||||||
))
|
))
|
||||||
|
@ -496,14 +500,14 @@ fn record_pattern_field<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, PRecord<'a>>
|
||||||
// Having a value is optional; both `{ email }` and `{ email: blah }` work.
|
// Having a value is optional; both `{ email }` and `{ email: blah }` work.
|
||||||
// (This is true in both literals and types.)
|
// (This is true in both literals and types.)
|
||||||
let (_, opt_loc_val, state) = optional(either!(
|
let (_, opt_loc_val, state) = optional(either!(
|
||||||
word1(b':', PRecord::Colon),
|
byte(b':', PRecord::Colon),
|
||||||
word1(b'?', PRecord::Optional)
|
byte(b'?', PRecord::Optional)
|
||||||
))
|
))
|
||||||
.parse(arena, state, min_indent)?;
|
.parse(arena, state, min_indent)?;
|
||||||
|
|
||||||
match opt_loc_val {
|
match opt_loc_val {
|
||||||
Some(First(_)) => {
|
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) =
|
let (_, loc_val, state) =
|
||||||
spaces_before(val_parser).parse(arena, state, min_indent)?;
|
spaces_before(val_parser).parse(arena, state, min_indent)?;
|
||||||
|
|
||||||
|
@ -529,7 +533,7 @@ fn record_pattern_field<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, PRecord<'a>>
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
Some(Second(_)) => {
|
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) =
|
let (_, loc_val, state) =
|
||||||
spaces_before(val_parser).parse(arena, state, min_indent)?;
|
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::expr;
|
||||||
use crate::parser::Progress::{self, *};
|
use crate::parser::Progress::{self, *};
|
||||||
use crate::parser::{
|
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,
|
EString, Parser,
|
||||||
};
|
};
|
||||||
use crate::state::State;
|
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;
|
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.
|
// This is for the byte we just grabbed from the iterator.
|
||||||
segment_parsed_bytes += 1;
|
segment_parsed_bytes += 1;
|
||||||
|
|
||||||
match byte {
|
match one_byte {
|
||||||
b'"' if !is_single_quote => {
|
b'"' if !is_single_quote => {
|
||||||
if segment_parsed_bytes == 1 && segments.is_empty() {
|
if segment_parsed_bytes == 1 && segments.is_empty() {
|
||||||
// special case of the empty string
|
// 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
|
// canonicalization error if that expression variant
|
||||||
// is not allowed inside a string interpolation.
|
// is not allowed inside a string interpolation.
|
||||||
let (_progress, loc_expr, new_state) = skip_second!(
|
let (_progress, loc_expr, new_state) = skip_second!(
|
||||||
specialize_ref(
|
specialize_err_ref(
|
||||||
EString::Format,
|
EString::Format,
|
||||||
loc(allocated(reset_min_indent(expr::expr_help())))
|
loc(allocated(reset_min_indent(expr::expr_help())))
|
||||||
),
|
),
|
||||||
word1(b')', EString::FormatEnd)
|
byte(b')', EString::FormatEnd)
|
||||||
)
|
)
|
||||||
.parse(arena, state, min_indent)?;
|
.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
|
// give a canonicalization error if the digits form
|
||||||
// an invalid unicode code point.
|
// an invalid unicode code point.
|
||||||
let (_progress, loc_digits, new_state) = between!(
|
let (_progress, loc_digits, new_state) = between!(
|
||||||
word1(b'(', EString::CodePtOpen),
|
byte(b'(', EString::CodePtOpen),
|
||||||
loc(ascii_hex_digits()),
|
loc(ascii_hex_digits()),
|
||||||
word1(b')', EString::CodePtEnd)
|
byte(b')', EString::CodePtEnd)
|
||||||
)
|
)
|
||||||
.parse(arena, state, min_indent)?;
|
.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 ')'
|
// Parse an arbitrary expression, followed by ')'
|
||||||
let (_progress, loc_expr, new_state) = skip_second!(
|
let (_progress, loc_expr, new_state) = skip_second!(
|
||||||
specialize_ref(
|
specialize_err_ref(
|
||||||
EString::Format,
|
EString::Format,
|
||||||
loc(allocated(reset_min_indent(expr::expr_help())))
|
loc(allocated(reset_min_indent(expr::expr_help())))
|
||||||
),
|
),
|
||||||
word1(b')', EString::FormatEnd)
|
byte(b')', EString::FormatEnd)
|
||||||
)
|
)
|
||||||
.parse(arena, state, min_indent)?;
|
.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.
|
// iff the '$' is followed by '(', this is string interpolation.
|
||||||
// We'll check for the '(' on the next iteration of the loop.
|
// 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
|
// 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,
|
absolute_column_min_indent, increment_min_indent, then, ERecord, ETypeAbilityImpl,
|
||||||
};
|
};
|
||||||
use crate::parser::{
|
use crate::parser::{
|
||||||
allocated, backtrackable, fail, optional, specialize, specialize_ref, word, word1, word2,
|
allocated, backtrackable, byte, fail, optional, specialize_err, specialize_err_ref, two_bytes,
|
||||||
EType, ETypeApply, ETypeInParens, ETypeInlineAlias, ETypeRecord, ETypeTagUnion, Parser,
|
word, EType, ETypeApply, ETypeInParens, ETypeInlineAlias, ETypeRecord, ETypeTagUnion, Parser,
|
||||||
Progress::{self, *},
|
Progress::{self, *},
|
||||||
};
|
};
|
||||||
use crate::state::State;
|
use crate::state::State;
|
||||||
|
@ -39,16 +39,16 @@ fn tag_union_type<'a>(
|
||||||
) -> impl Parser<'a, TypeAnnotation<'a>, ETypeTagUnion<'a>> {
|
) -> impl Parser<'a, TypeAnnotation<'a>, ETypeTagUnion<'a>> {
|
||||||
move |arena, state, min_indent| {
|
move |arena, state, min_indent| {
|
||||||
let (_, tags, state) = collection_trailing_sep_e!(
|
let (_, tags, state) = collection_trailing_sep_e!(
|
||||||
word1(b'[', ETypeTagUnion::Open),
|
byte(b'[', ETypeTagUnion::Open),
|
||||||
loc!(tag_type(false)),
|
loc!(tag_type(false)),
|
||||||
word1(b',', ETypeTagUnion::End),
|
byte(b',', ETypeTagUnion::End),
|
||||||
word1(b']', ETypeTagUnion::End),
|
byte(b']', ETypeTagUnion::End),
|
||||||
Tag::SpaceBefore
|
Tag::SpaceBefore
|
||||||
)
|
)
|
||||||
.parse(arena, state, min_indent)?;
|
.parse(arena, state, min_indent)?;
|
||||||
|
|
||||||
// This could be an open tag union, e.g. `[Foo, Bar]a`
|
// 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,
|
ETypeTagUnion::Type,
|
||||||
term(stop_at_surface_has),
|
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!(
|
one_of!(
|
||||||
loc_wildcard(),
|
loc_wildcard(),
|
||||||
loc_inferred(),
|
loc_inferred(),
|
||||||
specialize(EType::TInParens, loc_type_in_parens(stop_at_surface_has)),
|
specialize_err(EType::TInParens, loc_type_in_parens(stop_at_surface_has)),
|
||||||
loc!(specialize(EType::TRecord, record_type(stop_at_surface_has))),
|
loc!(specialize_err(
|
||||||
loc!(specialize(
|
EType::TRecord,
|
||||||
|
record_type(stop_at_surface_has)
|
||||||
|
)),
|
||||||
|
loc!(specialize_err(
|
||||||
EType::TTagUnion,
|
EType::TTagUnion,
|
||||||
tag_union_type(stop_at_surface_has)
|
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!(
|
and!(
|
||||||
skip_second!(
|
skip_second!(
|
||||||
backtrackable(space0_e(EType::TIndentEnd)),
|
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()
|
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,
|
/// The `*` type variable, e.g. in (List *) Wildcard,
|
||||||
fn loc_wildcard<'a>() -> impl Parser<'a, Loc<TypeAnnotation<'a>>, EType<'a>> {
|
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)
|
loc_val.map(|_| TypeAnnotation::Wildcard)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -204,13 +207,16 @@ fn loc_applied_arg<'a>(
|
||||||
one_of!(
|
one_of!(
|
||||||
loc_wildcard(),
|
loc_wildcard(),
|
||||||
loc_inferred(),
|
loc_inferred(),
|
||||||
specialize(EType::TInParens, loc_type_in_parens(stop_at_surface_has)),
|
specialize_err(EType::TInParens, loc_type_in_parens(stop_at_surface_has)),
|
||||||
loc!(specialize(EType::TRecord, record_type(stop_at_surface_has))),
|
loc!(specialize_err(
|
||||||
loc!(specialize(
|
EType::TRecord,
|
||||||
|
record_type(stop_at_surface_has)
|
||||||
|
)),
|
||||||
|
loc!(specialize_err(
|
||||||
EType::TTagUnion,
|
EType::TTagUnion,
|
||||||
tag_union_type(stop_at_surface_has)
|
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))
|
loc!(parse_type_variable(stop_at_surface_has))
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
@ -231,13 +237,13 @@ fn loc_type_in_parens<'a>(
|
||||||
then(
|
then(
|
||||||
loc!(and!(
|
loc!(and!(
|
||||||
collection_trailing_sep_e!(
|
collection_trailing_sep_e!(
|
||||||
word1(b'(', ETypeInParens::Open),
|
byte(b'(', ETypeInParens::Open),
|
||||||
specialize_ref(ETypeInParens::Type, expression(true, false)),
|
specialize_err_ref(ETypeInParens::Type, expression(true, false)),
|
||||||
word1(b',', ETypeInParens::End),
|
byte(b',', ETypeInParens::End),
|
||||||
word1(b')', ETypeInParens::End),
|
byte(b')', ETypeInParens::End),
|
||||||
TypeAnnotation::SpaceBefore
|
TypeAnnotation::SpaceBefore
|
||||||
),
|
),
|
||||||
optional(allocated(specialize_ref(
|
optional(allocated(specialize_err_ref(
|
||||||
ETypeInParens::Type,
|
ETypeInParens::Type,
|
||||||
term(stop_at_surface_has)
|
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)?;
|
loc!(parse_tag_name(ETypeTagUnion::End)).parse(arena, state, min_indent)?;
|
||||||
|
|
||||||
let (_, args, state) =
|
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)?;
|
.parse(arena, state, min_indent)?;
|
||||||
|
|
||||||
let result = Tag::Apply {
|
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"
|
// You must have a field name, e.g. "email"
|
||||||
// using the initial pos is important for error reporting
|
// using the initial pos is important for error reporting
|
||||||
let pos = state.pos();
|
let pos = state.pos();
|
||||||
let (progress, loc_label, state) = loc!(specialize(
|
let (progress, loc_label, state) = loc!(specialize_err(
|
||||||
move |_, _| ETypeRecord::Field(pos),
|
move |_, _| ETypeRecord::Field(pos),
|
||||||
lowercase_ident_keyword_e()
|
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.
|
// Having a value is optional; both `{ email }` and `{ email: blah }` work.
|
||||||
// (This is true in both literals and types.)
|
// (This is true in both literals and types.)
|
||||||
let (_, opt_loc_val, state) = optional(either!(
|
let (_, opt_loc_val, state) = optional(either!(
|
||||||
word1(b':', ETypeRecord::Colon),
|
byte(b':', ETypeRecord::Colon),
|
||||||
word1(b'?', ETypeRecord::Optional)
|
byte(b'?', ETypeRecord::Optional)
|
||||||
))
|
))
|
||||||
.parse(arena, state, min_indent)?;
|
.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 {
|
match opt_loc_val {
|
||||||
Some(First(_)) => {
|
Some(First(_)) => {
|
||||||
|
@ -370,13 +376,13 @@ fn record_type<'a>(
|
||||||
) -> impl Parser<'a, TypeAnnotation<'a>, ETypeRecord<'a>> {
|
) -> impl Parser<'a, TypeAnnotation<'a>, ETypeRecord<'a>> {
|
||||||
record!(TypeAnnotation::Record {
|
record!(TypeAnnotation::Record {
|
||||||
fields: collection_trailing_sep_e!(
|
fields: collection_trailing_sep_e!(
|
||||||
word1(b'{', ETypeRecord::Open),
|
byte(b'{', ETypeRecord::Open),
|
||||||
loc!(record_type_field()),
|
loc!(record_type_field()),
|
||||||
word1(b',', ETypeRecord::End),
|
byte(b',', ETypeRecord::End),
|
||||||
word1(b'}', ETypeRecord::End),
|
byte(b'}', ETypeRecord::End),
|
||||||
AssignedField::SpaceBefore
|
AssignedField::SpaceBefore
|
||||||
),
|
),
|
||||||
ext: optional(allocated(specialize_ref(
|
ext: optional(allocated(specialize_err_ref(
|
||||||
ETypeRecord::Type,
|
ETypeRecord::Type,
|
||||||
term(stop_at_surface_has)
|
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>> {
|
fn applied_type<'a>(stop_at_surface_has: bool) -> impl Parser<'a, TypeAnnotation<'a>, EType<'a>> {
|
||||||
map!(
|
map!(
|
||||||
and!(
|
and!(
|
||||||
specialize(EType::TApply, concrete_type()),
|
specialize_err(EType::TApply, concrete_type()),
|
||||||
// Optionally parse space-separated arguments for the constructor,
|
// Optionally parse space-separated arguments for the constructor,
|
||||||
// e.g. `Str Float` in `Map Str Float`
|
// e.g. `Str Float` in `Map Str Float`
|
||||||
loc_applied_args_e(stop_at_surface_has)
|
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!(
|
map!(
|
||||||
and!(
|
and!(
|
||||||
space0_before_optional_after(
|
space0_before_optional_after(
|
||||||
specialize(EType::TApply, loc!(concrete_type())),
|
specialize_err(EType::TApply, loc!(concrete_type())),
|
||||||
EType::TIndentStart,
|
EType::TIndentStart,
|
||||||
EType::TIndentEnd,
|
EType::TIndentEnd,
|
||||||
),
|
),
|
||||||
zero_or_more!(skip_first!(
|
zero_or_more!(skip_first!(
|
||||||
word1(b'&', EType::TImplementsClause),
|
byte(b'&', EType::TImplementsClause),
|
||||||
space0_before_optional_after(
|
space0_before_optional_after(
|
||||||
specialize(EType::TApply, loc!(concrete_type())),
|
specialize_err(EType::TApply, loc!(concrete_type())),
|
||||||
EType::TIndentStart,
|
EType::TIndentStart,
|
||||||
EType::TIndentEnd,
|
EType::TIndentEnd,
|
||||||
)
|
)
|
||||||
|
@ -450,7 +456,7 @@ fn implements_clause<'a>() -> impl Parser<'a, Loc<ImplementsClause<'a>>, EType<'
|
||||||
and!(
|
and!(
|
||||||
space0_around_ee(
|
space0_around_ee(
|
||||||
// Parse "a", with appropriate spaces
|
// Parse "a", with appropriate spaces
|
||||||
specialize(
|
specialize_err(
|
||||||
|_, pos| EType::TBadTypeVariable(pos),
|
|_, pos| EType::TBadTypeVariable(pos),
|
||||||
loc!(map!(lowercase_ident(), Spaced::Item)),
|
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 (_, first_clause, state) = implements_clause().parse(arena, state, min_indent)?;
|
||||||
|
|
||||||
let (_, mut clauses, state) = zero_or_more!(skip_first!(
|
let (_, mut clauses, state) = zero_or_more!(skip_first!(
|
||||||
word1(b',', EType::TImplementsClause),
|
byte(b',', EType::TImplementsClause),
|
||||||
implements_clause()
|
implements_clause()
|
||||||
))
|
))
|
||||||
.parse(arena, state, min_indent)?;
|
.parse(arena, state, min_indent)?;
|
||||||
|
@ -519,10 +525,10 @@ pub fn implements_abilities<'a>() -> impl Parser<'a, Loc<ImplementsAbilities<'a>
|
||||||
space0_before_e(
|
space0_before_e(
|
||||||
loc!(map!(
|
loc!(map!(
|
||||||
collection_trailing_sep_e!(
|
collection_trailing_sep_e!(
|
||||||
word1(b'[', EType::TStart),
|
byte(b'[', EType::TStart),
|
||||||
loc!(parse_implements_ability()),
|
loc!(parse_implements_ability()),
|
||||||
word1(b',', EType::TEnd),
|
byte(b',', EType::TEnd),
|
||||||
word1(b']', EType::TEnd),
|
byte(b']', EType::TEnd),
|
||||||
ImplementsAbility::SpaceBefore
|
ImplementsAbility::SpaceBefore
|
||||||
),
|
),
|
||||||
ImplementsAbilities::Implements
|
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>> {
|
fn parse_implements_ability<'a>() -> impl Parser<'a, ImplementsAbility<'a>, EType<'a>> {
|
||||||
increment_min_indent(record!(ImplementsAbility::ImplementsAbility {
|
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(
|
impls: optional(backtrackable(space0_before_e(
|
||||||
loc!(map!(
|
loc!(map!(
|
||||||
specialize(
|
specialize_err(
|
||||||
EType::TAbilityImpl,
|
EType::TAbilityImpl,
|
||||||
collection_trailing_sep_e!(
|
collection_trailing_sep_e!(
|
||||||
word1(b'{', ETypeAbilityImpl::Open),
|
byte(b'{', ETypeAbilityImpl::Open),
|
||||||
specialize(|e: ERecord<'_>, _| e.into(), loc!(ability_impl_field())),
|
specialize_err(|e: ERecord<'_>, _| e.into(), loc!(ability_impl_field())),
|
||||||
word1(b',', ETypeAbilityImpl::End),
|
byte(b',', ETypeAbilityImpl::End),
|
||||||
word1(b'}', ETypeAbilityImpl::End),
|
byte(b'}', ETypeAbilityImpl::End),
|
||||||
AssignedField::SpaceBefore
|
AssignedField::SpaceBefore
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
@ -573,7 +579,7 @@ fn expression<'a>(
|
||||||
|
|
||||||
let result = and![
|
let result = and![
|
||||||
zero_or_more!(skip_first!(
|
zero_or_more!(skip_first!(
|
||||||
word1(b',', EType::TFunctionArgument),
|
byte(b',', EType::TFunctionArgument),
|
||||||
one_of![
|
one_of![
|
||||||
space0_around_ee(
|
space0_around_ee(
|
||||||
term(stop_at_surface_has),
|
term(stop_at_surface_has),
|
||||||
|
@ -586,7 +592,7 @@ fn expression<'a>(
|
||||||
.trace("type_annotation:expression:rest_args"),
|
.trace("type_annotation:expression:rest_args"),
|
||||||
skip_second!(
|
skip_second!(
|
||||||
space0_e(EType::TIndentStart),
|
space0_e(EType::TIndentStart),
|
||||||
word2(b'-', b'>', EType::TStart)
|
two_bytes(b'-', b'>', EType::TStart)
|
||||||
)
|
)
|
||||||
.trace("type_annotation:expression:arrow")
|
.trace("type_annotation:expression:arrow")
|
||||||
]
|
]
|
||||||
|
@ -625,7 +631,7 @@ fn expression<'a>(
|
||||||
if !is_trailing_comma_valid {
|
if !is_trailing_comma_valid {
|
||||||
let (_, comma, _) = optional(backtrackable(skip_first!(
|
let (_, comma, _) = optional(backtrackable(skip_first!(
|
||||||
space0_e(EType::TIndentStart),
|
space0_e(EType::TIndentStart),
|
||||||
word1(b',', EType::TStart)
|
byte(b',', EType::TStart)
|
||||||
)))
|
)))
|
||||||
.trace("check trailing comma")
|
.trace("check trailing comma")
|
||||||
.parse(arena, state.clone(), min_indent)?;
|
.parse(arena, state.clone(), min_indent)?;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue