Merge pull request #4464 from joshuawarner32/fix-one_of

Fix one_of bug, properly return MadeProgress from "when" parsing
This commit is contained in:
Richard Feldman 2022-11-03 19:25:36 -07:00 committed by GitHub
commit 2110540a53
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 45 additions and 12 deletions

View File

@ -346,6 +346,7 @@ fn parse_expr_start<'a>(
loc!(move |a, s, m| parse_expr_operator_chain(m, options, a, s)), loc!(move |a, s, m| parse_expr_operator_chain(m, options, a, s)),
fail_expr_start_e() fail_expr_start_e()
] ]
.trace("expr_start")
.parse(arena, state, min_indent) .parse(arena, state, min_indent)
} }
@ -2076,10 +2077,10 @@ mod when {
parser::keyword_e(keyword::IS, EWhen::Is) parser::keyword_e(keyword::IS, EWhen::Is)
) )
), ),
move |arena, state, progress, (case_indent, loc_condition), min_indent| { move |arena, state, _progress, (case_indent, loc_condition), min_indent| {
if case_indent < min_indent { if case_indent < min_indent {
return Err(( return Err((
progress, MadeProgress,
// TODO maybe pass case_indent here? // TODO maybe pass case_indent here?
EWhen::PatternAlignment(5, state.pos()), EWhen::PatternAlignment(5, state.pos()),
state, state,
@ -2089,15 +2090,18 @@ mod when {
// Everything in the branches must be indented at least as much as the case itself. // Everything in the branches must be indented at least as much as the case itself.
let min_indent = case_indent; let min_indent = case_indent;
let (p1, branches, state) = branches(options).parse(arena, state, min_indent)?; let (_p1, branches, state) = branches(options)
.parse(arena, state, min_indent)
.map_err(|(_p, e, s)| (MadeProgress, e, s))?;
Ok(( Ok((
progress.or(p1), MadeProgress,
Expr::When(arena.alloc(loc_condition), branches.into_bump_slice()), Expr::When(arena.alloc(loc_condition), branches.into_bump_slice()),
state, state,
)) ))
}, },
) )
.trace("when")
} }
/// Parsing when with indentation. /// Parsing when with indentation.

View File

@ -737,6 +737,7 @@ pub trait Parser<'a, Output, Error> {
) -> ParseResult<'a, Output, Error>; ) -> ParseResult<'a, Output, Error>;
#[cfg(not(feature = "parse_debug_trace"))] #[cfg(not(feature = "parse_debug_trace"))]
#[inline(always)]
fn trace(self, _message: &'static str) -> Self fn trace(self, _message: &'static str) -> Self
where where
Self: Sized, Self: Sized,
@ -789,7 +790,7 @@ impl<'a, O: std::fmt::Debug, E: std::fmt::Debug, P: Parser<'a, O, E>> Parser<'a,
where where
E: 'a, E: 'a,
{ {
fn parse(&self, arena: &'a Bump, state: State<'a>) -> ParseResult<'a, O, E> { fn parse(&self, arena: &'a Bump, state: State<'a>, min_indent: u32) -> ParseResult<'a, O, E> {
use std::cell::RefCell; use std::cell::RefCell;
thread_local! { thread_local! {
@ -803,7 +804,7 @@ where
let cur_indent = INDENT.with(|i| *i.borrow()); let cur_indent = INDENT.with(|i| *i.borrow());
println!( println!(
"{:>5?}: {}{:<50}", "{:<5?}: {}{:<50}",
state.pos(), state.pos(),
&indent_text[..cur_indent * 2], &indent_text[..cur_indent * 2],
self.message self.message
@ -1379,11 +1380,12 @@ macro_rules! and {
macro_rules! one_of { macro_rules! one_of {
($p1:expr, $p2:expr) => { ($p1:expr, $p2:expr) => {
move |arena: &'a bumpalo::Bump, state: $crate::state::State<'a>, min_indent: u32| { 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) { match $p1.parse(arena, state, min_indent) {
valid @ Ok(_) => valid, valid @ Ok(_) => valid,
Err((MadeProgress, fail, state)) => Err((MadeProgress, fail, state)), Err((MadeProgress, fail, state)) => Err((MadeProgress, fail, state)),
Err((NoProgress, _, state)) => $p2.parse(arena, state, min_indent), Err((NoProgress, _, _)) => $p2.parse(arena, original_state, min_indent),
} }
} }
}; };

View File

@ -0,0 +1 @@
Expr(When(Condition(Start(@30), @29), @24), @0)

View File

@ -0,0 +1,6 @@
when Just 4 is
Just when ->
4
_ ->
2

View File

@ -0,0 +1 @@
Expr(When(Arrow(@26), @20), @0)

View File

@ -0,0 +1,3 @@
when 5 is
1 -> 2
_

View File

@ -124,6 +124,8 @@ mod test_parse {
fail/lambda_missing_indent.expr, fail/lambda_missing_indent.expr,
fail/type_argument_no_arrow.expr, fail/type_argument_no_arrow.expr,
fail/type_double_comma.expr, fail/type_double_comma.expr,
fail/when_missing_arrow.expr,
fail/pattern_binds_keyword.expr,
pass/ability_demand_signature_is_multiline.expr, pass/ability_demand_signature_is_multiline.expr,
pass/ability_multi_line.expr, pass/ability_multi_line.expr,
pass/ability_single_line.expr, pass/ability_single_line.expr,

View File

@ -133,7 +133,8 @@ impl Position {
impl Debug for Position { impl Debug for Position {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "@{}", self.offset) write!(f, "@")?;
self.offset.fmt(f)
} }
} }

View File

@ -4847,14 +4847,27 @@ mod test_reporting {
"# "#
), ),
@r###" @r###"
MISSING EXPRESSION tmp/pattern_binds_keyword/Test.roc MISSING ARROW tmp/pattern_binds_keyword/Test.roc
I am partway through parsing a `when` expression, but I got stuck here: I am partway through parsing a `when` expression, but got stuck here:
5 Just when -> 5 Just when ->
^ ^
I was expecting to see an expression like 42 or "hello". I was expecting to see an arrow next.
Note: Sometimes I get confused by indentation, so try to make your `when`
look something like this:
when List.first plants is
Ok n ->
n
Err _ ->
200
Notice the indentation. All patterns are aligned, and each branch is
indented a bit more than the corresponding pattern. That is important!
"### "###
); );