mirror of
https://github.com/roc-lang/roc.git
synced 2024-09-22 00:09:33 +03:00
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:
commit
79789fd56f
@ -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 })
|
||||
}
|
||||
|
@ -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),
|
||||
));
|
||||
}
|
||||
};
|
||||
|
@ -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,
|
||||
|
@ -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),
|
||||
|
@ -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))),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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, ())),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 =
|
||||
|
@ -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)),
|
||||
}
|
||||
}
|
||||
|
@ -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>> {
|
||||
|
@ -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()))
|
||||
}
|
||||
|
@ -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,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
@ -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()))),
|
||||
}
|
||||
}
|
||||
|
@ -846,7 +846,7 @@ mod test_parse {
|
||||
Ok((_, _, _state)) => {
|
||||
// dbg!(_state);
|
||||
}
|
||||
Err((_, _fail, _state)) => {
|
||||
Err((_, _fail)) => {
|
||||
// dbg!(_fail, _state);
|
||||
panic!("Failed to parse!");
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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?",
|
||||
),
|
||||
|
@ -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
|
||||
^
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user