Merge pull request #4543 from joshuawarner32/more-parser-refactoring

Refactor parser methods to not return State as part of ParseError
This commit is contained in:
Richard Feldman 2022-11-19 02:37:50 -05:00 committed by GitHub
commit 79789fd56f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 374 additions and 456 deletions

View File

@ -157,9 +157,7 @@ fn parse_all<'a>(arena: &'a Bump, src: &'a str) -> Result<Ast<'a>, SyntaxError<'
let (module, state) = module::parse_header(arena, State::new(src.as_bytes()))
.map_err(|e| SyntaxError::Header(e.problem))?;
let (_, defs, _) = module_defs()
.parse(arena, state, 0)
.map_err(|(_, e, _)| e)?;
let (_, defs, _) = module_defs().parse(arena, state, 0).map_err(|(_, e)| e)?;
Ok(Ast { module, defs })
}

View File

@ -4860,11 +4860,11 @@ fn parse<'a>(arena: &'a Bump, header: ModuleHeader<'a>) -> Result<Msg<'a>, Loadi
let parse_start = Instant::now();
let source = header.parse_state.original_bytes();
let parse_state = header.parse_state;
let parsed_defs = match module_defs().parse(arena, parse_state, 0) {
let parsed_defs = match module_defs().parse(arena, parse_state.clone(), 0) {
Ok((_, success, _state)) => success,
Err((_, fail, state)) => {
Err((_, fail)) => {
return Err(LoadingProblem::ParsingFailed(
fail.into_file_error(header.module_path, &state),
fail.into_file_error(header.module_path, &parse_state),
));
}
};

View File

@ -159,7 +159,7 @@ where
if state.column() >= min_indent {
Ok((NoProgress, (), state))
} else {
Err((NoProgress, indent_problem(state.pos()), state))
Err((NoProgress, indent_problem(state.pos())))
}
}
}
@ -184,7 +184,6 @@ where
FastSpaceState::HasTab(position) => Err((
MadeProgress,
E::space_problem(BadInputError::HasTab, position),
state,
)),
FastSpaceState::Good {
newlines,
@ -194,7 +193,7 @@ where
if consumed == 0 {
Ok((NoProgress, &[] as &[_], state))
} else if column < min_indent {
Err((MadeProgress, indent_problem(state.pos()), state))
Err((MadeProgress, indent_problem(state.pos())))
} else {
let comments_and_newlines = Vec::with_capacity_in(newlines, arena);
let spaces = eat_spaces(state, comments_and_newlines);
@ -218,7 +217,6 @@ where
FastSpaceState::HasTab(position) => Err((
MadeProgress,
E::space_problem(BadInputError::HasTab, position),
state,
)),
FastSpaceState::Good {
newlines,

View File

@ -14,7 +14,7 @@ use crate::parser::{
word1_indent, word2, EClosure, EExpect, EExpr, EIf, EInParens, EList, ENumber, EPattern,
ERecord, EString, ETuple, EType, EWhen, Either, ParseResult, Parser,
};
use crate::pattern::{loc_closure_param, loc_has_parser};
use crate::pattern::{closure_param, loc_has_parser};
use crate::state::State;
use crate::type_annotation;
use bumpalo::collections::Vec;
@ -30,7 +30,7 @@ fn expr_end<'a>() -> impl Parser<'a, (), EExpr<'a>> {
if state.has_reached_end() {
Ok((NoProgress, (), state))
} else {
Err((NoProgress, EExpr::BadExprEnd(state.pos()), state))
Err((NoProgress, EExpr::BadExprEnd(state.pos())))
}
}
}
@ -44,7 +44,7 @@ pub fn test_parse_expr<'a>(
match parser.parse(arena, state, min_indent) {
Ok((_, expression, _)) => Ok(expression),
Err((_, fail, _)) => Err(fail),
Err((_, fail)) => Err(fail),
}
}
@ -102,7 +102,7 @@ fn loc_expr_in_parens_help<'a>() -> impl Parser<'a, Loc<Expr<'a>>, EInParens<'a>
state,
))
} else if elements.is_empty() {
Err((NoProgress, EInParens::Empty(state.pos()), state))
Err((NoProgress, EInParens::Empty(state.pos())))
} else {
// TODO: don't discard comments before/after
// (stored in the Collection)
@ -157,7 +157,11 @@ 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, &'a str>, EExpr<'a>> {
|arena, state, min_indent| match record_field_access().parse(arena, state, min_indent) {
|arena, state: State<'a>, min_indent| match record_field_access().parse(
arena,
state.clone(),
min_indent,
) {
Ok((_, initial, state)) => {
let mut accesses = Vec::with_capacity_in(1, arena);
@ -165,18 +169,18 @@ fn record_field_access_chain<'a>() -> impl Parser<'a, Vec<'a, &'a str>, EExpr<'a
let mut loop_state = state;
loop {
match record_field_access().parse(arena, loop_state, min_indent) {
match record_field_access().parse(arena, loop_state.clone(), min_indent) {
Ok((_, next, state)) => {
accesses.push(next);
loop_state = state;
}
Err((MadeProgress, fail, state)) => return Err((MadeProgress, fail, state)),
Err((NoProgress, _, state)) => return Ok((MadeProgress, accesses, state)),
Err((MadeProgress, fail)) => return Err((MadeProgress, fail)),
Err((NoProgress, _)) => return Ok((MadeProgress, accesses, loop_state)),
}
}
}
Err((MadeProgress, fail, state)) => Err((MadeProgress, fail, state)),
Err((NoProgress, _, state)) => Err((NoProgress, EExpr::Access(state.pos()), state)),
Err((MadeProgress, fail)) => Err((MadeProgress, fail)),
Err((NoProgress, _)) => Err((NoProgress, EExpr::Access(state.pos()))),
}
}
@ -292,7 +296,7 @@ fn loc_possibly_negative_or_negated_term<'a>(
}
fn fail_expr_start_e<'a, T: 'a>() -> impl Parser<'a, T, EExpr<'a>> {
|_arena, state: State<'a>, _min_indent: u32| Err((NoProgress, EExpr::Start(state.pos()), state))
|_arena, state: State<'a>, _min_indent: u32| Err((NoProgress, EExpr::Start(state.pos())))
}
fn unary_negate<'a>() -> impl Parser<'a, (), EExpr<'a>> {
@ -313,7 +317,7 @@ fn unary_negate<'a>() -> impl Parser<'a, (), EExpr<'a>> {
Ok((MadeProgress, (), state))
} else {
// this is not a negated expression
Err((NoProgress, EExpr::UnaryNot(state.pos()), state))
Err((NoProgress, EExpr::UnaryNot(state.pos())))
}
}
}
@ -338,8 +342,8 @@ fn expr_operator_chain<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a
let initial_state = state.clone();
let end = state.pos();
match space0_e(EExpr::IndentEnd).parse(arena, state, min_indent) {
Err((_, _, state)) => Ok((MadeProgress, expr.value, state)),
match space0_e(EExpr::IndentEnd).parse(arena, state.clone(), min_indent) {
Err((_, _)) => Ok((MadeProgress, expr.value, state)),
Ok((_, spaces_before_op, state)) => {
let expr_state = ExprState {
operators: Vec::new_in(arena),
@ -570,14 +574,14 @@ pub fn parse_single_def<'a>(
let spaces_before_current_start = state.pos();
let state = match space0_e(EExpr::IndentStart).parse(arena, state, min_indent) {
Err((MadeProgress, _, s)) => {
return Err((MadeProgress, EExpr::DefMissingFinalExpr(s.pos()), s));
Err((MadeProgress, _)) => {
return Err((MadeProgress, EExpr::DefMissingFinalExpr(initial.pos())));
}
Ok((_, spaces, state)) => {
spaces_before_current = spaces;
state
}
Err((NoProgress, _, state)) => state,
Err((NoProgress, _)) => initial.clone(),
};
let start = state.pos();
@ -591,9 +595,9 @@ pub fn parse_single_def<'a>(
state.clone(),
min_indent,
) {
Err((NoProgress, _, _)) => {
Err((NoProgress, _)) => {
match parse_expect.parse(arena, state, min_indent) {
Err((_, _, _)) => {
Err((_, _)) => {
// a hacky way to get expression-based error messages. TODO fix this
Ok((NoProgress, None, initial))
}
@ -645,7 +649,7 @@ pub fn parse_single_def<'a>(
}
}
}
Err((MadeProgress, _, _)) => {
Err((MadeProgress, _)) => {
// a hacky way to get expression-based error messages. TODO fix this
Ok((NoProgress, None, initial))
}
@ -1014,7 +1018,7 @@ fn parse_defs_end<'a>(
next_state
}
Ok((progress, None, s)) => return Ok((progress, defs, s)),
Err((progress, err, s)) => return Err((progress, err, s)),
Err((progress, err)) => return Err((progress, err)),
};
}
}
@ -1038,12 +1042,11 @@ fn parse_defs_expr<'a>(
// this is no def, because there is no `=` or `:`; parse as an expr
let parse_final_expr = space0_before_e(loc_expr(), EExpr::IndentEnd);
match parse_final_expr.parse(arena, state, min_indent) {
Err((_, fail, state)) => {
match parse_final_expr.parse(arena, state.clone(), min_indent) {
Err((_, fail)) => {
return Err((
MadeProgress,
EExpr::DefMissingFinalExpr2(arena.alloc(fail), state.pos()),
state,
));
}
Ok((_, loc_ret, state)) => {
@ -1104,7 +1107,7 @@ fn finish_parsing_alias_or_opaque<'a>(
let (expr, arguments) = expr_state
.validate_is_type_def(arena, loc_op, kind)
.map_err(|fail| (MadeProgress, fail, state.clone()))?;
.map_err(|fail| (MadeProgress, fail))?;
let mut defs = Defs::default();
@ -1180,8 +1183,8 @@ fn finish_parsing_alias_or_opaque<'a>(
),
);
match parser.parse(arena, state, min_indent) {
Err((_, fail, state)) => return Err((MadeProgress, fail, state)),
match parser.parse(arena, state.clone(), min_indent) {
Err((_, fail)) => return Err((MadeProgress, fail)),
Ok((_, mut ann_type, state)) => {
// put the spaces from after the operator in front of the call
if !spaces_after_operator.is_empty() {
@ -1209,7 +1212,7 @@ fn finish_parsing_alias_or_opaque<'a>(
};
let fail = EExpr::BadOperator(op, loc_op.region.start());
return Err((MadeProgress, fail, state));
return Err((MadeProgress, fail));
}
}
}
@ -1261,12 +1264,10 @@ mod ability {
indent: IndentLevel,
) -> impl Parser<'a, (u32, AbilityMember<'a>), EAbility<'a>> {
move |arena, state: State<'a>, min_indent: u32| {
let initial = state.clone();
// Put no restrictions on the indent after the spaces; we'll check it manually.
match space0_e(EAbility::DemandName).parse(arena, state, 0) {
Err((MadeProgress, fail, _)) => Err((NoProgress, fail, initial)),
Err((NoProgress, fail, _)) => Err((NoProgress, fail, initial)),
Err((MadeProgress, fail)) => Err((NoProgress, fail)),
Err((NoProgress, fail)) => Err((NoProgress, fail)),
Ok((_progress, spaces, state)) => {
match indent {
@ -1275,7 +1276,6 @@ mod ability {
Err((
MadeProgress,
EAbility::DemandAlignment(indent_difference, state.pos()),
initial,
))
}
IndentLevel::Exact(wanted) if state.column() < wanted => {
@ -1286,7 +1286,6 @@ mod ability {
// expression
NoProgress,
EAbility::DemandAlignment(indent_difference, state.pos()),
initial,
))
}
IndentLevel::Exact(wanted) if state.column() > wanted => {
@ -1304,7 +1303,6 @@ mod ability {
Err((
progress,
EAbility::DemandAlignment(indent_difference, state.pos()),
initial,
))
}
_ => {
@ -1312,14 +1310,12 @@ mod ability {
let parser = parse_demand_help();
match parser.parse(arena, state, min_indent) {
Err((MadeProgress, fail, state)) => {
Err((MadeProgress, fail, state))
}
Err((NoProgress, fail, _)) => {
match parser.parse(arena, state.clone(), min_indent) {
Err((MadeProgress, fail)) => Err((MadeProgress, fail)),
Err((NoProgress, fail)) => {
// We made progress relative to the entire ability definition,
// so this is an error.
Err((MadeProgress, fail, initial))
Err((MadeProgress, fail))
}
Ok((_, mut demand, state)) => {
@ -1355,12 +1351,11 @@ fn finish_parsing_ability_def_help<'a>(
// Parse the first demand. This will determine the indentation level all the
// other demands must observe.
let start = state.pos();
let (_, (demand_indent_level, first_demand), mut state) =
ability::parse_demand(ability::IndentLevel::PendingMin(min_indent_for_demand))
.parse(arena, state, min_indent_for_demand)
.map_err(|(progress, err, state)| {
(progress, EExpr::Ability(err, state.pos()), state)
})?;
.map_err(|(progress, err)| (progress, EExpr::Ability(err, start)))?;
demands.push(first_demand);
let demand_indent = ability::IndentLevel::Exact(demand_indent_level);
@ -1372,15 +1367,10 @@ fn finish_parsing_ability_def_help<'a>(
state = next_state;
demands.push(demand);
}
Err((MadeProgress, problem, old_state)) => {
return Err((
MadeProgress,
EExpr::Ability(problem, old_state.pos()),
old_state,
));
Err((MadeProgress, problem)) => {
return Err((MadeProgress, EExpr::Ability(problem, state.pos())));
}
Err((NoProgress, _, old_state)) => {
state = old_state;
Err((NoProgress, _)) => {
break;
}
}
@ -1431,10 +1421,11 @@ fn parse_expr_operator<'a>(
let initial_state = state.clone();
let (spaces, state) = match space0_e(EExpr::IndentEnd).parse(arena, state, min_indent) {
Err((_, _, state)) => (&[] as &[_], state),
Ok((_, spaces, state)) => (spaces, state),
};
let (spaces, state) =
match space0_e(EExpr::IndentEnd).parse(arena, state.clone(), min_indent) {
Err((_, _)) => (&[] as &[_], state),
Ok((_, spaces, state)) => (spaces, state),
};
expr_state.arguments.push(arena.alloc(arg));
expr_state.spaces_after = spaces;
@ -1448,7 +1439,7 @@ fn parse_expr_operator<'a>(
let call = expr_state
.validate_assignment_or_backpassing(arena, loc_op, EExpr::ElmStyleFunction)
.map_err(|fail| (MadeProgress, fail, state.clone()))?;
.map_err(|fail| (MadeProgress, fail))?;
let (value_def, def_region, state) = {
match expr_to_pattern_help(arena, &call.value) {
@ -1475,7 +1466,7 @@ fn parse_expr_operator<'a>(
// this `=` likely occurred inline; treat it as an invalid operator
let fail = EExpr::BadOperator(arena.alloc("="), loc_op.region.start());
return Err((MadeProgress, fail, state));
return Err((MadeProgress, fail));
}
}
};
@ -1493,7 +1484,7 @@ fn parse_expr_operator<'a>(
.validate_assignment_or_backpassing(arena, loc_op, |_, pos| {
EExpr::BadOperator("<-", pos)
})
.map_err(|fail| (MadeProgress, fail, state.clone()))?;
.map_err(|fail| (MadeProgress, fail))?;
let (loc_pattern, loc_body, state) = {
match expr_to_pattern_help(arena, &call.value) {
@ -1514,7 +1505,7 @@ fn parse_expr_operator<'a>(
// this `=` likely occurred inline; treat it as an invalid operator
let fail = EExpr::BadOperator("=", loc_op.region.start());
return Err((MadeProgress, fail, state));
return Err((MadeProgress, fail));
}
}
};
@ -1545,8 +1536,12 @@ fn parse_expr_operator<'a>(
_ => unreachable!(),
},
),
_ => match loc_possibly_negative_or_negated_term(options).parse(arena, state, min_indent) {
Err((MadeProgress, f, s)) => Err((MadeProgress, f, s)),
_ => match loc_possibly_negative_or_negated_term(options).parse(
arena,
state.clone(),
min_indent,
) {
Err((MadeProgress, f)) => Err((MadeProgress, f)),
Ok((_, mut new_expr, state)) => {
let new_end = state.pos();
@ -1559,8 +1554,8 @@ fn parse_expr_operator<'a>(
.with_spaces_before(spaces_after_operator, new_expr.region);
}
match space0_e(EExpr::IndentEnd).parse(arena, state, min_indent) {
Err((_, _, state)) => {
match space0_e(EExpr::IndentEnd).parse(arena, state.clone(), min_indent) {
Err((_, _)) => {
let args = std::mem::replace(&mut expr_state.arguments, Vec::new_in(arena));
let call = to_call(arena, args, expr_state.expr);
@ -1588,8 +1583,8 @@ fn parse_expr_operator<'a>(
}
}
}
Err((NoProgress, expr, e)) => {
todo!("{:?} {:?}", expr, e)
Err((NoProgress, expr)) => {
todo!("{:?} {:?}", expr, state)
}
},
}
@ -1609,7 +1604,7 @@ fn parse_expr_end<'a>(
);
match parser.parse(arena, state.clone(), min_indent) {
Err((MadeProgress, f, s)) => Err((MadeProgress, f, s)),
Err((MadeProgress, f)) => Err((MadeProgress, f)),
Ok((
_,
has @ Loc {
@ -1638,11 +1633,7 @@ fn parse_expr_end<'a>(
Err(_) => {
let start = argument.region.start();
let err = &*arena.alloc(EPattern::Start(start));
return Err((
MadeProgress,
EExpr::Pattern(err, argument.region.start()),
state,
));
return Err((MadeProgress, EExpr::Pattern(err, argument.region.start())));
}
}
}
@ -1679,8 +1670,8 @@ fn parse_expr_end<'a>(
}
let initial_state = state.clone();
match space0_e(EExpr::IndentEnd).parse(arena, state, min_indent) {
Err((_, _, state)) => {
match space0_e(EExpr::IndentEnd).parse(arena, state.clone(), min_indent) {
Err((_, _)) => {
expr_state.arguments.push(arena.alloc(arg));
expr_state.end = new_end;
expr_state.spaces_after = &[];
@ -1697,11 +1688,11 @@ fn parse_expr_end<'a>(
}
}
}
Err((NoProgress, _, _)) => {
Err((NoProgress, _)) => {
let before_op = state.clone();
// try an operator
match loc!(operator()).parse(arena, state, min_indent) {
Err((MadeProgress, f, s)) => Err((MadeProgress, f, s)),
match loc!(operator()).parse(arena, state.clone(), min_indent) {
Err((MadeProgress, f)) => Err((MadeProgress, f)),
Ok((_, loc_op, state)) => {
expr_state.consume_spaces(arena);
let initial_state = before_op;
@ -1715,7 +1706,8 @@ fn parse_expr_end<'a>(
initial_state,
)
}
Err((NoProgress, _, mut state)) => {
Err((NoProgress, _)) => {
let mut state = state;
// try multi-backpassing
if options.accept_multi_backpassing && state.bytes().starts_with(b",") {
state = state.advance(1);
@ -1743,10 +1735,12 @@ fn parse_expr_end<'a>(
patterns.insert(0, loc_pattern);
match word2(b'<', b'-', EExpr::BackpassArrow)
.parse(arena, state, min_indent)
{
Err((_, fail, state)) => Err((MadeProgress, fail, state)),
match word2(b'<', b'-', EExpr::BackpassArrow).parse(
arena,
state.clone(),
min_indent,
) {
Err((_, fail)) => Err((MadeProgress, fail)),
Ok((_, _, state)) => {
let parse_body = space0_before_e(
increment_min_indent(loc_expr()),
@ -1771,7 +1765,7 @@ fn parse_expr_end<'a>(
}
}
} else if options.check_for_arrow && state.bytes().starts_with(b"->") {
Err((MadeProgress, EExpr::BadOperator("->", state.pos()), state))
Err((MadeProgress, EExpr::BadOperator("->", state.pos())))
} else {
let expr = parse_expr_final(expr_state, arena);
@ -1998,7 +1992,7 @@ fn closure_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EClo
sep_by1_e(
word1(b',', EClosure::Comma),
space0_around_ee(
specialize(EClosure::Pattern, loc_closure_param()),
specialize(EClosure::Pattern, closure_param()),
EClosure::IndentArg,
EClosure::IndentArrow,
),
@ -2090,11 +2084,7 @@ mod when {
Ok((MadeProgress, (loc_patterns, loc_guard), state))
} else {
let indent = pattern_indent_level - indent_column;
Err((
MadeProgress,
EWhen::PatternAlignment(indent, state.pos()),
state,
))
Err((MadeProgress, EWhen::PatternAlignment(indent, state.pos())))
}
},
),
@ -2111,18 +2101,16 @@ mod when {
);
while !state.bytes().is_empty() {
match branch_parser.parse(arena, state, min_indent) {
match branch_parser.parse(arena, state.clone(), min_indent) {
Ok((_, next_output, next_state)) => {
state = next_state;
branches.push(arena.alloc(next_output));
}
Err((MadeProgress, problem, old_state)) => {
return Err((MadeProgress, problem, old_state));
Err((MadeProgress, problem)) => {
return Err((MadeProgress, problem));
}
Err((NoProgress, _, old_state)) => {
state = old_state;
Err((NoProgress, _)) => {
break;
}
}
@ -2193,25 +2181,19 @@ mod when {
pattern_indent_level: Option<u32>,
) -> impl Parser<'a, (u32, Vec<'a, Loc<Pattern<'a>>>), EWhen<'a>> {
move |arena, state: State<'a>, min_indent: u32| {
let initial = state.clone();
// put no restrictions on the indent after the spaces; we'll check it manually
match space0_e(EWhen::IndentPattern).parse(arena, state, 0) {
Err((MadeProgress, fail, _)) => Err((NoProgress, fail, initial)),
Err((NoProgress, fail, _)) => Err((NoProgress, fail, initial)),
Err((MadeProgress, fail)) => Err((NoProgress, fail)),
Err((NoProgress, fail)) => Err((NoProgress, fail)),
Ok((_progress, spaces, state)) => {
match pattern_indent_level {
Some(wanted) if state.column() > wanted => {
// this branch is indented too much
Err((NoProgress, EWhen::IndentPattern(state.pos()), initial))
Err((NoProgress, EWhen::IndentPattern(state.pos())))
}
Some(wanted) if state.column() < wanted => {
let indent = wanted - state.column();
Err((
NoProgress,
EWhen::PatternAlignment(indent, state.pos()),
initial,
))
Err((NoProgress, EWhen::PatternAlignment(indent, state.pos())))
}
_ => {
let pattern_indent =
@ -2223,13 +2205,11 @@ mod when {
let parser =
sep_by1(word1(b'|', EWhen::Bar), branch_single_alternative());
match parser.parse(arena, state, pattern_indent) {
Err((MadeProgress, fail, state)) => {
Err((MadeProgress, fail, state))
}
Err((NoProgress, fail, _)) => {
match parser.parse(arena, state.clone(), pattern_indent) {
Err((MadeProgress, fail)) => Err((MadeProgress, fail)),
Err((NoProgress, fail)) => {
// roll back space parsing if the pattern made no progress
Err((NoProgress, fail, initial))
Err((NoProgress, fail))
}
Ok((_, mut loc_patterns, state)) => {
@ -2303,7 +2283,7 @@ fn expect_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EExpe
EExpect::IndentCondition,
)
.parse(arena, state, start_column + 1)
.map_err(|(_, f, s)| (MadeProgress, f, s))?;
.map_err(|(_, f)| (MadeProgress, f))?;
let parse_cont = specialize_ref(
EExpect::Continuation,
@ -2340,8 +2320,8 @@ fn if_expr_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EIf<
parser::keyword_e(keyword::IF, EIf::If)
);
match optional_if.parse(arena, state, min_indent) {
Err((_, _, state)) => break state,
match optional_if.parse(arena, state.clone(), min_indent) {
Err((_, _)) => break state,
Ok((_, _, state)) => {
loop_state = state;
continue;
@ -2354,7 +2334,7 @@ fn if_expr_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EIf<
EIf::IndentElseBranch,
)
.parse(arena, state_final_else, min_indent)
.map_err(|(_, f, s)| (MadeProgress, f, s))?;
.map_err(|(_, f)| (MadeProgress, f))?;
let expr = Expr::If(branches.into_bump_slice(), arena.alloc(else_branch));
@ -2711,12 +2691,12 @@ where
macro_rules! bad_made_progress {
($op:expr) => {{
Err((MadeProgress, to_error($op, state.pos()), state))
Err((MadeProgress, to_error($op, state.pos())))
}};
}
match chomped {
"" => Err((NoProgress, to_expectation(state.pos()), state)),
"" => Err((NoProgress, to_expectation(state.pos()))),
"+" => good!(BinOp::Plus, 1),
"-" => good!(BinOp::Minus, 1),
"*" => good!(BinOp::Star, 1),
@ -2727,7 +2707,7 @@ where
"<" => good!(BinOp::LessThan, 1),
"." => {
// a `.` makes no progress, so it does not interfere with `.foo` access(or)
Err((NoProgress, to_error(".", state.pos()), state))
Err((NoProgress, to_error(".", state.pos())))
}
"=" => good!(BinOp::Assignment, 1),
":=" => good!(BinOp::IsOpaqueType, 2),
@ -2742,7 +2722,7 @@ where
"//" => good!(BinOp::DoubleSlash, 2),
"->" => {
// makes no progress, so it does not interfere with `_ if isGood -> ...`
Err((NoProgress, to_error("->", state.pos()), state))
Err((NoProgress, to_error("->", state.pos())))
}
"<-" => good!(BinOp::Backpassing, 2),
_ => bad_made_progress!(chomped),

View File

@ -312,8 +312,8 @@ pub fn package_name<'a>() -> impl Parser<'a, PackageName<'a>, EPackageName<'a>>
.parse(arena, state, min_indent)
.and_then(|(progress, text, next_state)| match text {
StrLiteral::PlainLine(text) => Ok((progress, PackageName(text), next_state)),
StrLiteral::Line(_) => Err((progress, EPackageName::Escapes(pos), next_state)),
StrLiteral::Block(_) => Err((progress, EPackageName::Multiline(pos), next_state)),
StrLiteral::Line(_) => Err((progress, EPackageName::Escapes(pos))),
StrLiteral::Block(_) => Err((progress, EPackageName::Multiline(pos))),
})
}
}

View File

@ -88,10 +88,10 @@ impl<'a> Ident<'a> {
/// * A named pattern match, e.g. "foo" in `foo =` or `foo ->` or `\foo ->`
pub fn lowercase_ident<'a>() -> impl Parser<'a, &'a str, ()> {
move |_, state: State<'a>, _min_indent: u32| match chomp_lowercase_part(state.bytes()) {
Err(progress) => Err((progress, (), state)),
Err(progress) => Err((progress, ())),
Ok(ident) => {
if crate::keyword::KEYWORDS.iter().any(|kw| &ident == kw) {
Err((NoProgress, (), state))
Err((NoProgress, ()))
} else {
let width = ident.len();
Ok((MadeProgress, ident, state.advance(width)))
@ -113,7 +113,7 @@ pub fn tag_name<'a>() -> impl Parser<'a, &'a str, ()> {
/// * A tag
pub fn uppercase<'a>() -> impl Parser<'a, UppercaseIdent<'a>, ()> {
move |_, state: State<'a>, _min_indent: u32| match chomp_uppercase_part(state.bytes()) {
Err(progress) => Err((progress, (), state)),
Err(progress) => Err((progress, ())),
Ok(ident) => {
let width = ident.len();
Ok((MadeProgress, ident.into(), state.advance(width)))
@ -128,7 +128,7 @@ pub fn uppercase<'a>() -> impl Parser<'a, UppercaseIdent<'a>, ()> {
/// * A tag
pub fn uppercase_ident<'a>() -> impl Parser<'a, &'a str, ()> {
move |_, state: State<'a>, _min_indent: u32| match chomp_uppercase_part(state.bytes()) {
Err(progress) => Err((progress, (), state)),
Err(progress) => Err((progress, ())),
Ok(ident) => {
let width = ident.len();
Ok((MadeProgress, ident, state.advance(width)))
@ -138,10 +138,10 @@ pub fn uppercase_ident<'a>() -> impl Parser<'a, &'a str, ()> {
pub fn unqualified_ident<'a>() -> impl Parser<'a, &'a str, ()> {
move |_, state: State<'a>, _min_indent: u32| match chomp_anycase_part(state.bytes()) {
Err(progress) => Err((progress, (), state)),
Err(progress) => Err((progress, ())),
Ok(ident) => {
if crate::keyword::KEYWORDS.iter().any(|kw| &ident == kw) {
Err((MadeProgress, (), state))
Err((MadeProgress, ()))
} else {
let width = ident.len();
Ok((MadeProgress, ident, state.advance(width)))
@ -163,27 +163,32 @@ pub fn parse_ident<'a>(
) -> ParseResult<'a, Ident<'a>, EExpr<'a>> {
let initial = state.clone();
match parse_ident_help(arena, state) {
Ok((progress, ident, state)) => {
match chomp_identifier_chain(arena, state.bytes(), state.pos()) {
Ok((width, ident)) => {
let state = advance_state!(state, width as usize)?;
if let Ident::Access { module_name, parts } = ident {
if module_name.is_empty() {
if let Some(first) = parts.first() {
for keyword in crate::keyword::KEYWORDS.iter() {
if first == keyword {
return Err((NoProgress, EExpr::Start(initial.pos()), initial));
return Err((NoProgress, EExpr::Start(initial.pos())));
}
}
}
}
}
Ok((progress, ident, state))
Ok((MadeProgress, ident, state))
}
Err((NoProgress, _, state)) => Err((NoProgress, EExpr::Start(state.pos()), state)),
Err((MadeProgress, fail, state)) => match fail {
BadIdent::Start(pos) => Err((NoProgress, EExpr::Start(pos), state)),
BadIdent::Space(e, pos) => Err((NoProgress, EExpr::Space(e, pos), state)),
_ => malformed_identifier(initial.bytes(), fail, state),
Err((0, _)) => Err((NoProgress, EExpr::Start(state.pos()))),
Err((width, fail)) => match fail {
BadIdent::Start(pos) => Err((NoProgress, EExpr::Start(pos))),
BadIdent::Space(e, pos) => Err((NoProgress, EExpr::Space(e, pos))),
_ => malformed_identifier(
initial.bytes(),
fail,
advance_state!(state, width as usize)?,
),
},
}
}
@ -504,7 +509,7 @@ fn chomp_module_chain(buffer: &[u8]) -> Result<u32, Progress> {
pub fn concrete_type<'a>() -> impl Parser<'a, (&'a str, &'a str), ()> {
move |_, state: State<'a>, _min_indent: u32| match chomp_concrete_type(state.bytes()) {
Err(progress) => Err((progress, (), state)),
Err(progress) => Err((progress, ())),
Ok((module_name, type_name, width)) => {
Ok((MadeProgress, (module_name, type_name), state.advance(width)))
}
@ -574,20 +579,3 @@ fn chomp_access_chain<'a>(buffer: &'a [u8], parts: &mut Vec<'a, &'a str>) -> Res
Ok(chomped as u32)
}
}
fn parse_ident_help<'a>(
arena: &'a Bump,
mut state: State<'a>,
) -> ParseResult<'a, Ident<'a>, BadIdent> {
match chomp_identifier_chain(arena, state.bytes(), state.pos()) {
Ok((width, ident)) => {
state = advance_state!(state, width as usize)?;
Ok((MadeProgress, ident, state))
}
Err((0, fail)) => Err((NoProgress, fail, state)),
Err((width, fail)) => {
state = advance_state!(state, width as usize)?;
Err((MadeProgress, fail, state))
}
}
}

View File

@ -7,9 +7,9 @@ use crate::header::{
use crate::ident::{self, lowercase_ident, unqualified_ident, uppercase, UppercaseIdent};
use crate::parser::Progress::{self, *};
use crate::parser::{
backtrackable, increment_min_indent, optional, reset_min_indent, specialize, specialize_region,
word1, EExposes, EGenerates, EGeneratesWith, EHeader, EImports, EPackages, EProvides,
ERequires, ETypedIdent, Parser, SourceError, SpaceProblem, SyntaxError,
backtrackable, increment_min_indent, optional, reset_min_indent, specialize, word1, EExposes,
EGenerates, EGeneratesWith, EHeader, EImports, EPackages, EProvides, ERequires, ETypedIdent,
Parser, SourceError, SpaceProblem, SyntaxError,
};
use crate::state::State;
use crate::string_literal;
@ -21,7 +21,7 @@ fn end_of_file<'a>() -> impl Parser<'a, (), SyntaxError<'a>> {
if state.has_reached_end() {
Ok((NoProgress, (), state))
} else {
Err((NoProgress, SyntaxError::NotEndOfFile(state.pos()), state))
Err((NoProgress, SyntaxError::NotEndOfFile(state.pos())))
}
}
}
@ -29,10 +29,7 @@ fn end_of_file<'a>() -> impl Parser<'a, (), SyntaxError<'a>> {
#[inline(always)]
pub fn module_defs<'a>() -> impl Parser<'a, Defs<'a>, SyntaxError<'a>> {
skip_second!(
specialize_region(
|e, r| SyntaxError::Expr(e, r.start()),
crate::expr::toplevel_defs(),
),
specialize(SyntaxError::Expr, crate::expr::toplevel_defs(),),
end_of_file()
)
}
@ -42,9 +39,9 @@ pub fn parse_header<'a>(
state: State<'a>,
) -> Result<(Module<'a>, State<'a>), SourceError<'a, EHeader<'a>>> {
let min_indent = 0;
match header().parse(arena, state, min_indent) {
match header().parse(arena, state.clone(), min_indent) {
Ok((_, module, state)) => Ok((module, state)),
Err((_, fail, state)) => Err(SourceError::new(fail, &state)),
Err((_, fail)) => Err(SourceError::new(fail, &state)),
}
}
@ -234,7 +231,7 @@ fn module_name<'a>() -> impl Parser<'a, ModuleName<'a>, ()> {
Ok((MadeProgress, ModuleName::new(name), state))
}
Err(progress) => Err((progress, (), state)),
Err(progress) => Err((progress, ())),
}
}

View File

@ -20,7 +20,7 @@ pub fn positive_number_literal<'a>() -> impl Parser<'a, NumLiteral<'a>, ENumber>
}
_ => {
// this is not a number at all
Err((Progress::NoProgress, ENumber::End, state))
Err((Progress::NoProgress, ENumber::End))
}
}
}
@ -38,7 +38,7 @@ pub fn number_literal<'a>() -> impl Parser<'a, NumLiteral<'a>, ENumber> {
}
_ => {
// this is not a number at all
Err((Progress::NoProgress, ENumber::End, state))
Err((Progress::NoProgress, ENumber::End))
}
}
}
@ -89,12 +89,12 @@ fn chomp_number_dec<'a>(
if is_negative && chomped == 0 {
// we're probably actually looking at unary negation here
return Err((Progress::NoProgress, ENumber::End, state));
return Err((Progress::NoProgress, ENumber::End));
}
if !bytes.first().copied().unwrap_or_default().is_ascii_digit() {
// we're probably actually looking at unary negation here
return Err((Progress::NoProgress, ENumber::End, state));
return Err((Progress::NoProgress, ENumber::End));
}
let string =

View File

@ -10,8 +10,7 @@ pub enum Either<First, Second> {
Second(Second),
}
pub type ParseResult<'a, Output, Error> =
Result<(Progress, Output, State<'a>), (Progress, Error, State<'a>)>;
pub type ParseResult<'a, Output, Error> = Result<(Progress, Output, State<'a>), (Progress, Error)>;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Progress {
@ -851,7 +850,7 @@ where
let (progress, value, state) = match &res {
Ok((progress, result, state)) => (progress, Ok(result), state),
Err((progress, error, state)) => (progress, Err(error), state),
Err((progress, error)) => (progress, Err(error), state),
};
println!(
@ -924,7 +923,7 @@ where
let width = keyword.len();
if !state.bytes().starts_with(keyword.as_bytes()) {
return Err((NoProgress, if_error(state.pos()), state));
return Err((NoProgress, if_error(state.pos())));
}
// the next character should not be an identifier character
@ -938,7 +937,7 @@ where
state = state.advance(width);
Ok((MadeProgress, (), state))
}
Some(_) => Err((NoProgress, if_error(state.pos()), state)),
Some(_) => Err((NoProgress, if_error(state.pos()))),
}
}
}
@ -955,6 +954,8 @@ where
Error: 'a,
{
move |arena, state: State<'a>, min_indent: u32| {
let original_state = state.clone();
let start_bytes_len = state.bytes().len();
match parser.parse(arena, state, min_indent) {
@ -968,10 +969,10 @@ where
buf.push(first_output);
loop {
match delimiter.parse(arena, state, min_indent) {
match delimiter.parse(arena, state.clone(), min_indent) {
Ok((_, (), next_state)) => {
// If the delimiter passed, check the element parser.
match parser.parse(arena, next_state, min_indent) {
match parser.parse(arena, next_state.clone(), min_indent) {
Ok((element_progress, next_output, next_state)) => {
// in practice, we want elements to make progress
debug_assert_eq!(element_progress, MadeProgress);
@ -979,28 +980,28 @@ where
state = next_state;
buf.push(next_output);
}
Err((_, fail, state)) => {
Err((_, fail)) => {
// If the delimiter parsed, but the following
// element did not, that's a fatal error.
let progress = Progress::from_lengths(
start_bytes_len,
state.bytes().len(),
next_state.bytes().len(),
);
return Err((progress, fail, state));
return Err((progress, fail));
}
}
}
Err((delim_progress, fail, old_state)) => match delim_progress {
MadeProgress => return Err((MadeProgress, fail, old_state)),
NoProgress => return Ok((NoProgress, buf, old_state)),
Err((delim_progress, fail)) => match delim_progress {
MadeProgress => return Err((MadeProgress, fail)),
NoProgress => return Ok((NoProgress, buf, state)),
},
}
}
}
Err((element_progress, fail, new_state)) => match element_progress {
MadeProgress => Err((MadeProgress, fail, new_state)),
NoProgress => Ok((NoProgress, Vec::new_in(arena), new_state)),
Err((element_progress, fail)) => match element_progress {
MadeProgress => Err((MadeProgress, fail)),
NoProgress => Ok((NoProgress, Vec::new_in(arena), original_state)),
},
}
}
@ -1018,6 +1019,7 @@ where
Error: 'a,
{
move |arena, state: State<'a>, min_indent: u32| {
let original_state = state.clone();
let start_bytes_len = state.bytes().len();
match parser.parse(arena, state, min_indent) {
@ -1030,10 +1032,10 @@ where
buf.push(first_output);
loop {
match delimiter.parse(arena, state, min_indent) {
match delimiter.parse(arena, state.clone(), min_indent) {
Ok((_, (), next_state)) => {
// If the delimiter passed, check the element parser.
match parser.parse(arena, next_state, min_indent) {
match parser.parse(arena, next_state.clone(), min_indent) {
Ok((element_progress, next_output, next_state)) => {
// in practice, we want elements to make progress
debug_assert_eq!(element_progress, MadeProgress);
@ -1041,27 +1043,27 @@ where
state = next_state;
buf.push(next_output);
}
Err((_, _fail, old_state)) => {
Err((_, _fail)) => {
// If the delimiter parsed, but the following
// element did not, that means we saw a trailing comma
let progress = Progress::from_lengths(
start_bytes_len,
old_state.bytes().len(),
next_state.bytes().len(),
);
return Ok((progress, buf, old_state));
return Ok((progress, buf, next_state));
}
}
}
Err((delim_progress, fail, old_state)) => match delim_progress {
MadeProgress => return Err((MadeProgress, fail, old_state)),
NoProgress => return Ok((NoProgress, buf, old_state)),
Err((delim_progress, fail)) => match delim_progress {
MadeProgress => return Err((MadeProgress, fail)),
NoProgress => return Ok((NoProgress, buf, state)),
},
}
}
}
Err((element_progress, fail, new_state)) => match element_progress {
MadeProgress => Err((MadeProgress, fail, new_state)),
NoProgress => Ok((NoProgress, Vec::new_in(arena), new_state)),
Err((element_progress, fail)) => match element_progress {
MadeProgress => Err((MadeProgress, fail)),
NoProgress => Ok((NoProgress, Vec::new_in(arena), original_state)),
},
}
}
@ -1090,6 +1092,7 @@ where
buf.push(first_output);
loop {
let old_state = state.clone();
match delimiter.parse(arena, state, min_indent) {
Ok((_, (), next_state)) => {
// If the delimiter passed, check the element parser.
@ -1098,16 +1101,16 @@ where
state = next_state;
buf.push(next_output);
}
Err((_, fail, state)) => {
return Err((MadeProgress, fail, state));
Err((_, fail)) => {
return Err((MadeProgress, fail));
}
}
}
Err((delim_progress, fail, old_state)) => {
Err((delim_progress, fail)) => {
match delim_progress {
MadeProgress => {
// fail if the delimiter made progress
return Err((MadeProgress, fail, old_state));
return Err((MadeProgress, fail));
}
NoProgress => {
let progress = Progress::from_lengths(
@ -1121,7 +1124,7 @@ where
}
}
}
Err((fail_progress, fail, new_state)) => Err((fail_progress, fail, new_state)),
Err((fail_progress, fail)) => Err((fail_progress, fail)),
}
}
}
@ -1140,6 +1143,7 @@ where
Error: 'a,
{
move |arena, state: State<'a>, min_indent: u32| {
let original_state = state.clone();
let start_bytes_len = state.bytes().len();
match parser.parse(arena, state, min_indent) {
@ -1151,27 +1155,28 @@ where
buf.push(first_output);
loop {
let old_state = state.clone();
match delimiter.parse(arena, state, min_indent) {
Ok((_, (), next_state)) => {
// If the delimiter passed, check the element parser.
match parser.parse(arena, next_state, min_indent) {
match parser.parse(arena, next_state.clone(), min_indent) {
Ok((_, next_output, next_state)) => {
state = next_state;
buf.push(next_output);
}
Err((MadeProgress, fail, state)) => {
return Err((MadeProgress, fail, state));
Err((MadeProgress, fail)) => {
return Err((MadeProgress, fail));
}
Err((NoProgress, _fail, state)) => {
return Err((NoProgress, to_element_error(state.pos()), state));
Err((NoProgress, _fail)) => {
return Err((NoProgress, to_element_error(next_state.pos())));
}
}
}
Err((delim_progress, fail, old_state)) => {
Err((delim_progress, fail)) => {
match delim_progress {
MadeProgress => {
// fail if the delimiter made progress
return Err((MadeProgress, fail, old_state));
return Err((MadeProgress, fail));
}
NoProgress => {
let progress = Progress::from_lengths(
@ -1186,10 +1191,8 @@ where
}
}
Err((MadeProgress, fail, state)) => Err((MadeProgress, fail, state)),
Err((NoProgress, _fail, state)) => {
Err((NoProgress, to_element_error(state.pos()), state))
}
Err((MadeProgress, fail)) => Err((MadeProgress, fail)),
Err((NoProgress, _fail)) => Err((NoProgress, to_element_error(original_state.pos()))),
}
}
}
@ -1201,7 +1204,7 @@ pub fn fail_when_progress<T, E>(
state: State<'_>,
) -> ParseResult<'_, T, E> {
match progress {
MadeProgress => Err((MadeProgress, fail, state)),
MadeProgress => Err((MadeProgress, fail)),
NoProgress => Ok((NoProgress, value, state)),
}
}
@ -1218,7 +1221,7 @@ where
match parser.parse(arena, state, min_indent) {
Ok((progress, out1, state)) => Ok((progress, Some(out1), state)),
Err((_, _, _)) => {
Err((_, _)) => {
// NOTE this will backtrack
// TODO can we get rid of some of the potential backtracking?
Ok((NoProgress, None, original_state))
@ -1257,16 +1260,14 @@ macro_rules! loc {
#[macro_export]
macro_rules! skip_first {
($p1:expr, $p2:expr) => {
move |arena, state: $crate::state::State<'a>, min_indent: u32| {
let original_state = state.clone();
match $p1.parse(arena, state, min_indent) {
Ok((p1, _, state)) => match $p2.parse(arena, state, min_indent) {
Ok((p2, out2, state)) => Ok((p1.or(p2), out2, state)),
Err((p2, fail, _)) => Err((p1.or(p2), fail, original_state)),
},
Err((progress, fail, _)) => Err((progress, fail, original_state)),
}
move |arena, state: $crate::state::State<'a>, min_indent: u32| match $p1
.parse(arena, state, min_indent)
{
Ok((p1, _, state)) => match $p2.parse(arena, state, min_indent) {
Ok((p2, out2, state)) => Ok((p1.or(p2), out2, state)),
Err((p2, fail)) => Err((p1.or(p2), fail)),
},
Err((progress, fail)) => Err((progress, fail)),
}
};
}
@ -1276,16 +1277,14 @@ macro_rules! skip_first {
#[macro_export]
macro_rules! skip_second {
($p1:expr, $p2:expr) => {
move |arena, state: $crate::state::State<'a>, min_indent: u32| {
let original_state = state.clone();
match $p1.parse(arena, state, min_indent) {
Ok((p1, out1, state)) => match $p2.parse(arena, state, min_indent) {
Ok((p2, _, state)) => Ok((p1.or(p2), out1, state)),
Err((p2, fail, _)) => Err((p1.or(p2), fail, original_state)),
},
Err((progress, fail, _)) => Err((progress, fail, original_state)),
}
move |arena, state: $crate::state::State<'a>, min_indent: u32| match $p1
.parse(arena, state, min_indent)
{
Ok((p1, out1, state)) => match $p2.parse(arena, state, min_indent) {
Ok((p2, _, state)) => Ok((p1.or(p2), out1, state)),
Err((p2, fail)) => Err((p1.or(p2), fail)),
},
Err((progress, fail)) => Err((progress, fail)),
}
};
}
@ -1381,6 +1380,23 @@ macro_rules! succeed {
};
}
pub fn fail_when<'a, T, T2, E, F, P>(f: F, p: P) -> impl Parser<'a, T, E>
where
T: 'a,
T2: 'a,
E: 'a,
F: Fn(Position) -> E,
P: Parser<'a, T2, E>,
{
move |arena: &'a bumpalo::Bump, state: State<'a>, min_indent: u32| {
let original_state = state.clone();
match p.parse(arena, state, min_indent) {
Ok((_, _, _)) => Err((MadeProgress, f(original_state.pos()))),
Err((progress, err)) => Err((progress, err)),
}
}
}
pub fn fail<'a, T, E, F>(f: F) -> impl Parser<'a, T, E>
where
T: 'a,
@ -1388,25 +1404,21 @@ where
F: Fn(Position) -> E,
{
move |_arena: &'a bumpalo::Bump, state: State<'a>, _min_indent: u32| {
Err((NoProgress, f(state.pos()), state))
Err((NoProgress, f(state.pos())))
}
}
#[macro_export]
macro_rules! and {
($p1:expr, $p2:expr) => {
move |arena: &'a bumpalo::Bump, state: $crate::state::State<'a>, min_indent: u32| {
// We have to clone this because if the first parser passes and then
// the second one fails, we need to revert back to the original state.
let original_state = state.clone();
match $p1.parse(arena, state, min_indent) {
Ok((p1, out1, state)) => match $p2.parse(arena, state, min_indent) {
Ok((p2, out2, state)) => Ok((p1.or(p2), (out1, out2), state)),
Err((p2, fail, _)) => Err((p1.or(p2), fail, original_state)),
},
Err((progress, fail, state)) => Err((progress, fail, state)),
}
move |arena: &'a bumpalo::Bump, state: $crate::state::State<'a>, min_indent: u32| match $p1
.parse(arena, state, min_indent)
{
Ok((p1, out1, state)) => match $p2.parse(arena, state, min_indent) {
Ok((p2, out2, state)) => Ok((p1.or(p2), (out1, out2), state)),
Err((p2, fail)) => Err((p1.or(p2), fail)),
},
Err((progress, fail)) => Err((progress, fail)),
}
};
}
@ -1428,16 +1440,12 @@ macro_rules! indented_seq {
let p1_indent = start_indent;
let p2_indent = p1_indent + 1;
// We have to clone this because if the first parser passes and then
// the second one fails, we need to revert back to the original state.
let original_state = state.clone();
match $p1.parse(arena, state, p1_indent) {
Ok((p1, (), state)) => match $p2.parse(arena, state, p2_indent) {
Ok((p2, out2, state)) => Ok((p1.or(p2), out2, state)),
Err((p2, fail, _)) => Err((p1.or(p2), fail, original_state)),
Err((p2, fail)) => Err((p1.or(p2), fail)),
},
Err((progress, fail, state)) => Err((progress, fail, state)),
Err((progress, fail)) => Err((progress, fail)),
}
}
};
@ -1454,16 +1462,12 @@ macro_rules! absolute_indented_seq {
let p1_indent = start_indent;
let p2_indent = p1_indent + 1;
// We have to clone this because if the first parser passes and then
// the second one fails, we need to revert back to the original state.
let original_state = state.clone();
match $p1.parse(arena, state, p1_indent) {
Ok((p1, out1, state)) => match $p2.parse(arena, state, p2_indent) {
Ok((p2, out2, state)) => Ok((p1.or(p2), (out1, out2), state)),
Err((p2, fail, _)) => Err((p1.or(p2), fail, original_state)),
Err((p2, fail)) => Err((p1.or(p2), fail)),
},
Err((progress, fail, state)) => Err((progress, fail, state)),
Err((progress, fail)) => Err((progress, fail)),
}
}
};
@ -1477,8 +1481,8 @@ macro_rules! one_of {
match $p1.parse(arena, state, min_indent) {
valid @ Ok(_) => valid,
Err((MadeProgress, fail, state)) => Err((MadeProgress, fail, state)),
Err((NoProgress, _, _)) => $p2.parse(arena, original_state, min_indent),
Err((MadeProgress, fail)) => Err((MadeProgress, fail)),
Err((NoProgress, _)) => $p2.parse(arena, original_state, min_indent),
}
}
};
@ -1494,12 +1498,14 @@ macro_rules! one_of {
#[macro_export]
macro_rules! maybe {
($p1:expr) => {
move |arena: &'a bumpalo::Bump, state: $crate::state::State<'a>, min_indent: u32| match $p1
.parse(arena, state, min_indent)
{
Ok((progress, value, state)) => Ok((progress, Some(value), state)),
Err((MadeProgress, fail, state)) => Err((MadeProgress, fail, state)),
Err((NoProgress, _, state)) => Ok((NoProgress, None, state)),
move |arena: &'a bumpalo::Bump, state: $crate::state::State<'a>, min_indent: u32| {
let original_state = state.clone();
match $p1.parse(arena, state, min_indent) {
Ok((progress, value, state)) => Ok((progress, Some(value), state)),
Err((MadeProgress, fail)) => Err((MadeProgress, fail)),
Err((NoProgress, _)) => Ok((NoProgress, None, original_state)),
}
}
};
}
@ -1508,11 +1514,12 @@ macro_rules! maybe {
macro_rules! one_of_with_error {
($toerror:expr; $p1:expr) => {
move |arena: &'a bumpalo::Bump, state: $crate::state::State<'a>, min_indent: u32| {
let original_state = state.clone();
match $p1.parse(arena, state, min_indent) {
valid @ Ok(_) => valid,
Err((MadeProgress, fail, state)) => Err((MadeProgress, fail, state )),
Err((NoProgress, _, state)) => Err((MadeProgress, $toerror(state.pos()), state)),
Err((MadeProgress, fail)) => Err((MadeProgress, fail)),
Err((NoProgress, _)) => Err((MadeProgress, $toerror(original_state.pos()))),
}
}
};
@ -1569,24 +1576,11 @@ where
P: Parser<'a, T, X>,
Y: 'a,
{
move |a, s, min_indent| match parser.parse(a, s, min_indent) {
Ok(t) => Ok(t),
Err((p, error, s)) => Err((p, map_error(error, s.pos()), s)),
}
}
/// Like `specialize`, except the error function receives a Region representing the begin/end of the error
pub fn specialize_region<'a, F, P, T, X, Y>(map_error: F, parser: P) -> impl Parser<'a, T, Y>
where
F: Fn(X, Region) -> Y,
P: Parser<'a, T, X>,
Y: 'a,
{
move |a, s: State<'a>, min_indent: u32| {
let start = s.pos();
match parser.parse(a, s, min_indent) {
move |a, state: State<'a>, min_indent| {
let original_state = state.clone();
match parser.parse(a, state, min_indent) {
Ok(t) => Ok(t),
Err((p, error, s)) => Err((p, map_error(error, Region::new(start, s.pos())), s)),
Err((p, error)) => Err((p, map_error(error, original_state.pos()))),
}
}
}
@ -1598,9 +1592,12 @@ where
Y: 'a,
X: 'a,
{
move |a, s, min_indent| match parser.parse(a, s, min_indent) {
Ok(t) => Ok(t),
Err((p, error, s)) => Err((p, map_error(a.alloc(error), s.pos()), s)),
move |a, state: State<'a>, min_indent| {
let original_state = state.clone();
match parser.parse(a, state, min_indent) {
Ok(t) => Ok(t),
Err((p, error)) => Err((p, map_error(a.alloc(error), original_state.pos()))),
}
}
}
@ -1616,7 +1613,7 @@ where
let state = state.advance(1);
Ok((MadeProgress, (), state))
}
_ => Err((NoProgress, to_error(state.pos()), state)),
_ => Err((NoProgress, to_error(state.pos()))),
}
}
@ -1629,7 +1626,7 @@ where
move |_arena: &'a Bump, state: State<'a>, min_indent: u32| {
if min_indent > state.column() {
return Err((NoProgress, to_error(state.pos()), state));
return Err((NoProgress, to_error(state.pos())));
}
match state.bytes().first() {
@ -1637,7 +1634,7 @@ where
let state = state.advance(1);
Ok((MadeProgress, (), state))
}
_ => Err((NoProgress, to_error(state.pos()), state)),
_ => Err((NoProgress, to_error(state.pos()))),
}
}
}
@ -1657,7 +1654,7 @@ where
let state = state.advance(2);
Ok((MadeProgress, (), state))
} else {
Err((NoProgress, to_error(state.pos()), state))
Err((NoProgress, to_error(state.pos())))
}
}
}
@ -1683,7 +1680,7 @@ where
let state = state.advance(3);
Ok((MadeProgress, (), state))
} else {
Err((NoProgress, to_error(state.pos()), state))
Err((NoProgress, to_error(state.pos())))
}
}
}
@ -1728,6 +1725,8 @@ macro_rules! zero_or_more {
move |arena, state: State<'a>, min_indent: u32| {
use bumpalo::collections::Vec;
let original_state = state.clone();
let start_bytes_len = state.bytes().len();
match $parser.parse(arena, state, min_indent) {
@ -1738,16 +1737,17 @@ macro_rules! zero_or_more {
buf.push(first_output);
loop {
let old_state = state.clone();
match $parser.parse(arena, state, min_indent) {
Ok((_, next_output, next_state)) => {
state = next_state;
buf.push(next_output);
}
Err((fail_progress, fail, old_state)) => {
Err((fail_progress, fail)) => {
match fail_progress {
MadeProgress => {
// made progress on an element and then failed; that's an error
return Err((MadeProgress, fail, old_state));
return Err((MadeProgress, fail));
}
NoProgress => {
// the next element failed with no progress
@ -1760,16 +1760,16 @@ macro_rules! zero_or_more {
}
}
}
Err((fail_progress, fail, new_state)) => {
Err((fail_progress, fail)) => {
match fail_progress {
MadeProgress => {
// made progress on an element and then failed; that's an error
Err((MadeProgress, fail, new_state))
Err((MadeProgress, fail))
}
NoProgress => {
// the first element failed (with no progress), but that's OK
// because we only need to parse 0 elements
Ok((NoProgress, Vec::new_in(arena), new_state))
Ok((NoProgress, Vec::new_in(arena), original_state))
}
}
}
@ -1792,15 +1792,16 @@ macro_rules! one_or_more {
buf.push(first_output);
loop {
let old_state = state.clone();
match $parser.parse(arena, state, min_indent) {
Ok((_, next_output, next_state)) => {
state = next_state;
buf.push(next_output);
}
Err((NoProgress, _, old_state)) => {
Err((NoProgress, _)) => {
return Ok((MadeProgress, buf, old_state));
}
Err((MadeProgress, fail, old_state)) => {
Err((MadeProgress, fail)) => {
return Err((MadeProgress, fail, old_state));
}
}
@ -1826,19 +1827,22 @@ macro_rules! debug {
#[macro_export]
macro_rules! either {
($p1:expr, $p2:expr) => {
move |arena: &'a bumpalo::Bump, state: $crate::state::State<'a>, min_indent: u32| match $p1
.parse(arena, state, min_indent)
{
Ok((progress, output, state)) => {
Ok((progress, $crate::parser::Either::First(output), state))
}
Err((NoProgress, _, state)) => match $p2.parse(arena, state, min_indent) {
move |arena: &'a bumpalo::Bump, state: $crate::state::State<'a>, min_indent: u32| {
let original_state = state.clone();
match $p1.parse(arena, state, min_indent) {
Ok((progress, output, state)) => {
Ok((progress, $crate::parser::Either::Second(output), state))
Ok((progress, $crate::parser::Either::First(output), state))
}
Err((progress, fail, state)) => Err((progress, fail, state)),
},
Err((MadeProgress, fail, state)) => Err((MadeProgress, fail, state)),
Err((NoProgress, _)) => {
match $p2.parse(arena, original_state.clone(), min_indent) {
Ok((progress, output, state)) => {
Ok((progress, $crate::parser::Either::Second(output), state))
}
Err((progress, fail)) => Err((progress, fail)),
}
}
Err((MadeProgress, fail)) => Err((MadeProgress, fail)),
}
}
};
}
@ -1900,12 +1904,10 @@ where
P: Parser<'a, Val, Error>,
Error: 'a,
{
move |arena: &'a Bump, state: State<'a>, min_indent: u32| {
let old_state = state.clone();
match parser.parse(arena, state, min_indent) {
Ok((_, a, s1)) => Ok((NoProgress, a, s1)),
Err((_, f, _)) => Err((NoProgress, f, old_state)),
}
move |arena: &'a Bump, state: State<'a>, min_indent: u32| match parser
.parse(arena, state, min_indent)
{
Ok((_, a, s1)) => Ok((NoProgress, a, s1)),
Err((_, f)) => Err((NoProgress, f)),
}
}

View File

@ -3,8 +3,8 @@ use crate::blankspace::{space0_before_e, space0_e};
use crate::ident::{lowercase_ident, parse_ident, Ident};
use crate::parser::Progress::{self, *};
use crate::parser::{
backtrackable, optional, specialize, specialize_ref, then, word1, word2, word3, EPattern,
PInParens, PList, PRecord, ParseResult, Parser,
backtrackable, fail_when, optional, specialize, specialize_ref, then, word1, word2, word3,
EPattern, PInParens, PList, PRecord, Parser,
};
use crate::state::State;
use bumpalo::collections::string::String;
@ -24,15 +24,7 @@ pub enum PatternType {
WhenBranch,
}
pub fn loc_closure_param<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, EPattern<'a>> {
parse_closure_param
}
fn parse_closure_param<'a>(
arena: &'a Bump,
state: State<'a>,
min_indent: u32,
) -> ParseResult<'a, Loc<Pattern<'a>>, EPattern<'a>> {
pub fn closure_param<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, EPattern<'a>> {
one_of!(
// An ident is the most common param, e.g. \foo -> ...
loc_ident_pattern_help(true),
@ -47,7 +39,6 @@ fn parse_closure_param<'a>(
// e.g. \User.UserId userId -> ...
specialize(EPattern::PInParens, loc_pattern_in_parens_help())
)
.parse(arena, state, min_indent)
}
pub fn loc_pattern_help<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, EPattern<'a>> {
@ -88,16 +79,12 @@ fn loc_tag_pattern_arg<'a>(
min_indent,
)?;
let (_, loc_pat, state) = loc_parse_tag_pattern_arg(min_indent, arena, state)?;
let (_, loc_pat, state) = loc_parse_tag_pattern_arg().parse(arena, state, min_indent)?;
let Loc { region, value } = loc_pat;
if stop_on_has_kw && matches!(value, Pattern::Identifier("has")) {
Err((
NoProgress,
EPattern::End(original_state.pos()),
original_state,
))
Err((NoProgress, EPattern::End(original_state.pos())))
} else {
Ok((
MadeProgress,
@ -119,17 +106,13 @@ pub fn loc_has_parser<'a>() -> impl Parser<'a, Loc<Has<'a>>, EPattern<'a>> {
if matches!(pattern.value, Pattern::Identifier("has")) {
Ok((progress, Loc::at(pattern.region, Has::Has), state))
} else {
Err((progress, EPattern::End(state.pos()), state))
Err((progress, EPattern::End(state.pos())))
}
},
)
}
fn loc_parse_tag_pattern_arg<'a>(
min_indent: u32,
arena: &'a Bump,
state: State<'a>,
) -> ParseResult<'a, Loc<Pattern<'a>>, EPattern<'a>> {
fn loc_parse_tag_pattern_arg<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, EPattern<'a>> {
one_of!(
specialize(EPattern::PInParens, loc_pattern_in_parens_help()),
loc!(underscore_pattern_help()),
@ -143,7 +126,6 @@ fn loc_parse_tag_pattern_arg<'a>(
loc!(single_quote_pattern_help()),
loc!(number_pattern_help())
)
.parse(arena, state, min_indent)
}
fn loc_pattern_in_parens_help<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, PInParens<'a>> {
@ -168,7 +150,7 @@ fn loc_pattern_in_parens_help<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, PInPare
state,
))
} else if elements.is_empty() {
Err((NoProgress, PInParens::Empty(state.pos()), state))
Err((NoProgress, PInParens::Empty(state.pos())))
} else {
// TODO: don't discard comments before/after
// (stored in the Collection)
@ -221,8 +203,8 @@ fn single_quote_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, EPattern<'a>>
}
fn list_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, PList<'a>> {
move |arena, state, min_indent| {
let (_, pats, state) = collection_trailing_sep_e!(
map!(
collection_trailing_sep_e!(
word1(b'[', PList::Open),
list_element_pattern(),
word1(b',', PList::End),
@ -230,13 +212,9 @@ fn list_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, PList<'a>> {
PList::Open,
PList::IndentEnd,
Pattern::SpaceBefore
)
.parse(arena, state, min_indent)?;
let result = Pattern::List(pats);
Ok((MadeProgress, result, state))
}
),
Pattern::List
)
}
fn list_element_pattern<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, PList<'a>> {
@ -248,12 +226,7 @@ fn list_element_pattern<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, PList<'a>> {
}
fn three_list_rest_pattern_error<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, PList<'a>> {
then(
loc!(word3(b'.', b'.', b'.', PList::Rest)),
|_arena, state, _progress, word| {
Err((MadeProgress, PList::Rest(word.region.start()), state))
},
)
fail_when(PList::Rest, loc!(word3(b'.', b'.', b'.', PList::Rest)))
}
fn list_rest_pattern<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, PList<'a>> {
@ -330,11 +303,7 @@ fn loc_ident_pattern_help<'a>(
// Plain identifiers (e.g. `foo`) are allowed in patterns, but
// more complex ones (e.g. `Foo.bar` or `foo.bar.baz`) are not.
if crate::keyword::KEYWORDS.contains(&parts[0]) {
Err((
NoProgress,
EPattern::End(original_state.pos()),
original_state,
))
Err((NoProgress, EPattern::End(original_state.pos())))
} else if module_name.is_empty() && parts.len() == 1 {
Ok((
MadeProgress,
@ -387,34 +356,26 @@ fn loc_ident_pattern_help<'a>(
}
fn underscore_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, EPattern<'a>> {
move |arena: &'a Bump, state: State<'a>, min_indent: u32| {
let (_, _, next_state) =
word1(b'_', EPattern::Underscore).parse(arena, state, min_indent)?;
let (_, output, final_state) =
optional(lowercase_ident_pattern).parse(arena, next_state, min_indent)?;
match output {
Some(name) => Ok((MadeProgress, Pattern::Underscore(name), final_state)),
None => Ok((MadeProgress, Pattern::Underscore(""), final_state)),
map!(
skip_first!(
word1(b'_', EPattern::Underscore),
optional(lowercase_ident_pattern())
),
|output| match output {
Some(name) => Pattern::Underscore(name),
None => Pattern::Underscore(""),
}
}
)
}
fn lowercase_ident_pattern<'a>(
arena: &'a Bump,
state: State<'a>,
min_indent: u32,
) -> ParseResult<'a, &'a str, EPattern<'a>> {
let pos = state.pos();
specialize(move |_, _| EPattern::End(pos), lowercase_ident()).parse(arena, state, min_indent)
fn lowercase_ident_pattern<'a>() -> impl Parser<'a, &'a str, EPattern<'a>> {
specialize(move |_, pos| EPattern::End(pos), lowercase_ident())
}
#[inline(always)]
fn record_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, PRecord<'a>> {
move |arena, state, min_indent| {
let (_, fields, state) = collection_trailing_sep_e!(
map!(
collection_trailing_sep_e!(
word1(b'{', PRecord::Open),
record_pattern_field(),
word1(b',', PRecord::End),
@ -422,13 +383,9 @@ fn record_pattern_help<'a>() -> impl Parser<'a, Pattern<'a>, PRecord<'a>> {
PRecord::Open,
PRecord::IndentEnd,
Pattern::SpaceBefore
)
.parse(arena, state, min_indent)?;
let result = Pattern::RecordDestructure(fields);
Ok((MadeProgress, result, state))
}
),
Pattern::RecordDestructure
)
}
fn record_pattern_field<'a>() -> impl Parser<'a, Loc<Pattern<'a>>, PRecord<'a>> {

View File

@ -58,9 +58,9 @@ impl<'a> State<'a> {
&self,
indent: u32,
e: impl Fn(Position) -> E,
) -> Result<u32, (Progress, E, State<'a>)> {
) -> Result<u32, (Progress, E)> {
if self.column() < indent {
Err((Progress::NoProgress, e(self.pos()), self.clone()))
Err((Progress::NoProgress, e(self.pos())))
} else {
Ok(std::cmp::max(indent, self.line_indent()))
}

View File

@ -19,7 +19,7 @@ fn ascii_hex_digits<'a>() -> impl Parser<'a, &'a str, EString<'a>> {
buf.push(byte as char);
} else if buf.is_empty() {
// We didn't find any hex digits!
return Err((NoProgress, EString::CodePtEnd(state.pos()), state));
return Err((NoProgress, EString::CodePtEnd(state.pos())));
} else {
state.advance_mut(buf.len());
@ -27,7 +27,7 @@ fn ascii_hex_digits<'a>() -> impl Parser<'a, &'a str, EString<'a>> {
}
}
Err((NoProgress, EString::CodePtEnd(state.pos()), state))
Err((NoProgress, EString::CodePtEnd(state.pos())))
}
}
@ -36,7 +36,7 @@ pub fn parse_single_quote<'a>() -> impl Parser<'a, &'a str, EString<'a>> {
if state.consume_mut("\'") {
// we will be parsing a single-quote-string
} else {
return Err((NoProgress, EString::Open(state.pos()), state));
return Err((NoProgress, EString::Open(state.pos())));
}
// Handle back slaches in byte literal
@ -64,18 +64,18 @@ pub fn parse_single_quote<'a>() -> impl Parser<'a, &'a str, EString<'a>> {
return Ok((MadeProgress, &*arena.alloc_str(&test.to_string()), state));
}
// invalid error, backslah escaping something we do not recognize
return Err((NoProgress, EString::CodePtEnd(state.pos()), state));
return Err((NoProgress, EString::CodePtEnd(state.pos())));
}
None => {
// no close quote found
return Err((NoProgress, EString::CodePtEnd(state.pos()), state));
return Err((NoProgress, EString::CodePtEnd(state.pos())));
}
}
}
Some(_) => {
// do nothing for other characters, handled below
}
None => return Err((NoProgress, EString::CodePtEnd(state.pos()), state)),
None => return Err((NoProgress, EString::CodePtEnd(state.pos()))),
}
let mut bytes = state.bytes().iter();
@ -90,7 +90,7 @@ pub fn parse_single_quote<'a>() -> impl Parser<'a, &'a str, EString<'a>> {
}
Some(_) => end_index += 1,
None => {
return Err((NoProgress, EString::Open(state.pos()), state));
return Err((NoProgress, EString::Open(state.pos())));
}
}
}
@ -99,12 +99,12 @@ pub fn parse_single_quote<'a>() -> impl Parser<'a, &'a str, EString<'a>> {
// no progress was made
// this case is a double single quote, ex: ''
// not supporting empty single quotes
return Err((NoProgress, EString::Open(state.pos()), state));
return Err((NoProgress, EString::Open(state.pos())));
}
if end_index > (std::mem::size_of::<u32>() + 1) {
// bad case: too big to fit into u32
return Err((NoProgress, EString::Open(state.pos()), state));
return Err((NoProgress, EString::Open(state.pos())));
}
// happy case -> we have some bytes that will fit into a u32
@ -116,13 +116,13 @@ pub fn parse_single_quote<'a>() -> impl Parser<'a, &'a str, EString<'a>> {
Ok(string) => Ok((MadeProgress, string, state)),
Err(_) => {
// invalid UTF-8
return Err((NoProgress, EString::CodePtEnd(state.pos()), state));
return Err((NoProgress, EString::CodePtEnd(state.pos())));
}
}
}
}
fn consume_indent(mut state: State, mut indent: u32) -> Result<State, (Progress, EString, State)> {
fn consume_indent(mut state: State, mut indent: u32) -> Result<State, (Progress, EString)> {
while indent > 0 {
match state.bytes().first() {
Some(b' ') => {
@ -136,7 +136,6 @@ fn consume_indent(mut state: State, mut indent: u32) -> Result<State, (Progress,
return Err((
MadeProgress,
EString::MultilineInsufficientIndent(state.pos()),
state,
));
}
}
@ -145,10 +144,7 @@ fn consume_indent(mut state: State, mut indent: u32) -> Result<State, (Progress,
Ok(state)
}
fn utf8<'a>(
state: State<'a>,
string_bytes: &'a [u8],
) -> Result<&'a str, (Progress, EString<'a>, State<'a>)> {
fn utf8<'a>(state: State<'a>, string_bytes: &'a [u8]) -> Result<&'a str, (Progress, EString<'a>)> {
std::str::from_utf8(string_bytes).map_err(|_| {
// Note Based on where this `utf8` function is used, the fact that we know the whole string
// in the parser is valid utf8, and barring bugs in the parser itself
@ -156,7 +152,6 @@ fn utf8<'a>(
(
MadeProgress,
EString::Space(BadInputError::BadUtf8, state.pos()),
state,
)
})
}
@ -186,7 +181,7 @@ pub fn parse<'a>() -> impl Parser<'a, StrLiteral<'a>, EString<'a>> {
// we will be parsing a single-line string
is_multiline = false;
} else {
return Err((NoProgress, EString::Open(state.pos()), state));
return Err((NoProgress, EString::Open(state.pos())));
}
let mut bytes = state.bytes().iter();
@ -227,7 +222,6 @@ pub fn parse<'a>() -> impl Parser<'a, StrLiteral<'a>, EString<'a>> {
return Err((
MadeProgress,
EString::Space(BadInputError::BadUtf8, state.pos()),
state,
));
}
}
@ -336,11 +330,7 @@ pub fn parse<'a>() -> impl Parser<'a, StrLiteral<'a>, EString<'a>> {
// all remaining chars. This will mask all other errors, but
// it should make it easiest to debug; the file will be a giant
// error starting from where the open quote appeared.
return Err((
MadeProgress,
EString::EndlessSingle(start_state.pos()),
start_state,
));
return Err((MadeProgress, EString::EndlessSingle(start_state.pos())));
}
}
b'\\' => {
@ -432,7 +422,7 @@ pub fn parse<'a>() -> impl Parser<'a, StrLiteral<'a>, EString<'a>> {
// Invalid escape! A backslash must be followed
// by either an open paren or else one of the
// escapable characters (\n, \t, \", \\, etc)
return Err((MadeProgress, EString::UnknownEscape(state.pos()), state));
return Err((MadeProgress, EString::UnknownEscape(state.pos())));
}
}
}
@ -450,7 +440,6 @@ pub fn parse<'a>() -> impl Parser<'a, StrLiteral<'a>, EString<'a>> {
} else {
EString::EndlessSingle(start_state.pos())
},
start_state,
))
}
}

View File

@ -104,7 +104,7 @@ fn parse_type_alias_after_as<'a>() -> impl Parser<'a, TypeHeader<'a>, EType<'a>>
match res {
Ok(header) => Ok((progress, header, state)),
Err(err) => Err((progress, EType::TInlineAlias(err, state.pos()), state)),
Err(err) => Err((progress, EType::TInlineAlias(err, state.pos()))),
}
},
)
@ -242,11 +242,13 @@ where
F: Fn(Position) -> E,
E: 'a,
{
move |arena, state: State<'a>, min_indent: u32| match crate::ident::tag_name()
.parse(arena, state, min_indent)
{
move |arena, state: State<'a>, min_indent: u32| match crate::ident::tag_name().parse(
arena,
state.clone(),
min_indent,
) {
Ok(good) => Ok(good),
Err((progress, _, state)) => Err((progress, to_problem(state.pos()), state)),
Err((progress, _)) => Err((progress, to_problem(state.pos()))),
}
}
@ -645,14 +647,15 @@ fn concrete_type<'a>() -> impl Parser<'a, TypeAnnotation<'a>, ETypeApply> {
move |arena: &'a Bump, state: State<'a>, min_indent: u32| {
let initial_bytes = state.bytes();
match crate::ident::concrete_type().parse(arena, state, min_indent) {
match crate::ident::concrete_type().parse(arena, state.clone(), min_indent) {
Ok((_, (module_name, type_name), state)) => {
let answer = TypeAnnotation::Apply(module_name, type_name, &[]);
Ok((MadeProgress, answer, state))
}
Err((NoProgress, _, state)) => Err((NoProgress, ETypeApply::End(state.pos()), state)),
Err((MadeProgress, _, mut state)) => {
Err((NoProgress, _)) => Err((NoProgress, ETypeApply::End(state.pos()))),
Err((MadeProgress, _)) => {
let mut state = state.clone();
// we made some progress, but ultimately failed.
// that means a malformed type name
let chomped = crate::ident::chomp_malformed(state.bytes());
@ -671,18 +674,20 @@ fn concrete_type<'a>() -> impl Parser<'a, TypeAnnotation<'a>, ETypeApply> {
fn parse_type_variable<'a>(
stop_at_surface_has: bool,
) -> impl Parser<'a, TypeAnnotation<'a>, EType<'a>> {
move |arena, state: State<'a>, min_indent: u32| match crate::ident::lowercase_ident()
.parse(arena, state, min_indent)
{
move |arena, state: State<'a>, min_indent: u32| match crate::ident::lowercase_ident().parse(
arena,
state.clone(),
min_indent,
) {
Ok((_, name, state)) => {
if name == "has" && stop_at_surface_has {
Err((NoProgress, EType::TEnd(state.pos()), state))
Err((NoProgress, EType::TEnd(state.pos())))
} else {
let answer = TypeAnnotation::BoundVariable(name);
Ok((MadeProgress, answer, state))
}
}
Err((progress, _, state)) => Err((progress, EType::TBadTypeVariable(state.pos()), state)),
Err((progress, _)) => Err((progress, EType::TBadTypeVariable(state.pos()))),
}
}

View File

@ -846,7 +846,7 @@ mod test_parse {
Ok((_, _, _state)) => {
// dbg!(_state);
}
Err((_, _fail, _state)) => {
Err((_, _fail)) => {
// dbg!(_fail, _state);
panic!("Failed to parse!");
}

View File

@ -321,12 +321,12 @@ fn parse_src<'a>(arena: &'a Bump, line: &'a str) -> ParseOutcome<'a> {
match roc_parse::expr::loc_expr().parse(arena, State::new(src_bytes), 0) {
Ok((_, loc_expr, _)) => ParseOutcome::Expr(loc_expr.value),
// Special case some syntax errors to allow for multi-line inputs
Err((_, EExpr::Closure(EClosure::Body(_, _), _), _))
| Err((_, EExpr::When(EWhen::Pattern(EPattern::Start(_), _), _), _))
| Err((_, EExpr::Start(_), _))
| Err((_, EExpr::IndentStart(_), _)) => ParseOutcome::Incomplete,
Err((_, EExpr::DefMissingFinalExpr(_), _))
| Err((_, EExpr::DefMissingFinalExpr2(_, _), _)) => {
Err((_, EExpr::Closure(EClosure::Body(_, _), _)))
| Err((_, EExpr::When(EWhen::Pattern(EPattern::Start(_), _), _)))
| Err((_, EExpr::Start(_)))
| Err((_, EExpr::IndentStart(_))) => ParseOutcome::Incomplete,
Err((_, EExpr::DefMissingFinalExpr(_)))
| Err((_, EExpr::DefMissingFinalExpr2(_, _))) => {
// This indicates that we had an attempted def; re-parse it as a single-line def.
match parse_single_def(
ExprParseOptions {

View File

@ -1547,7 +1547,7 @@ fn to_unexpected_arrow_report<'a>(
),
alloc.concat([
alloc.reflow(r"It makes sense to see arrows around here, "),
alloc.reflow(r"so I suspect it is something earlier."),
alloc.reflow(r"so I suspect it is something earlier. "),
alloc.reflow(
r"Maybe this pattern is indented a bit farther from the previous patterns?",
),

View File

@ -5011,12 +5011,13 @@ mod test_reporting {
I am parsing a `when` expression right now, but this arrow is confusing
me:
5 5 -> 2
6 _ -> 2
^^
It makes sense to see arrows around here, so I suspect it is something
earlier.Maybe this pattern is indented a bit farther from the previous
patterns?
earlier. Maybe this pattern is indented a bit farther from the
previous patterns?
Note: Here is an example of a valid `when` expression for reference.
@ -5047,12 +5048,13 @@ mod test_reporting {
I am parsing a `when` expression right now, but this arrow is confusing
me:
5 5 -> Num.neg
6 2 -> 2
^^
It makes sense to see arrows around here, so I suspect it is something
earlier.Maybe this pattern is indented a bit farther from the previous
patterns?
earlier. Maybe this pattern is indented a bit farther from the
previous patterns?
Note: Here is an example of a valid `when` expression for reference.
@ -5295,6 +5297,7 @@ mod test_reporting {
This multiline string is not sufficiently indented:
4 """
5 testing
^
@ -8069,6 +8072,7 @@ All branches in an `if` must have the same type!
I was partway through parsing an ability definition, but I got stuck
here:
4 MEq has
5 eq b c : a, a -> U64 | a has MEq
^