This commit is contained in:
Folkert 2021-02-23 15:21:19 +01:00
parent 9d9316d170
commit 9189e3a461
3 changed files with 84 additions and 56 deletions

View file

@ -1257,33 +1257,59 @@ pub fn if_expr_help<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, If<'a>> {
let mut branches = Vec::with_capacity_in(1, arena); let mut branches = Vec::with_capacity_in(1, arena);
let (_, cond, state) = space0_around_e( let mut loop_state = state;
specialize_ref(
If::Syntax,
loc!(move |arena, state| parse_expr(min_indent, arena, state)),
),
min_indent,
If::Space,
If::IndentCondition,
)
.parse(arena, state)?;
let (_, _, state) = parser::keyword_e(keyword::THEN, If::Then).parse(arena, state)?; let state_final_else = loop {
let state = loop_state;
let (_, cond, state) = space0_around_e(
specialize_ref(
If::Syntax,
loc!(move |arena, state| parse_expr(min_indent, arena, state)),
),
min_indent,
If::Space,
If::IndentCondition,
)
.parse(arena, state)
.map_err(|(_, f, s)| (MadeProgress, f, s))?;
let (_, then_branch, state) = space0_around_e( let (_, _, state) = parser::keyword_e(keyword::THEN, If::Then)
specialize_ref( .parse(arena, state)
If::Syntax, .map_err(|(_, f, s)| (MadeProgress, f, s))?;
loc!(move |arena, state| parse_expr(min_indent, arena, state)),
),
min_indent,
If::Space,
If::IndentThen,
)
.parse(arena, state)?;
let (_, _, state) = parser::keyword_e(keyword::ELSE, If::Else).parse(arena, state)?; let (_, then_branch, state) = space0_around_e(
specialize_ref(
If::Syntax,
loc!(move |arena, state| parse_expr(min_indent, arena, state)),
),
min_indent,
If::Space,
If::IndentThen,
)
.parse(arena, state)
.map_err(|(_, f, s)| (MadeProgress, f, s))?;
branches.push((cond, then_branch)); let (_, _, state) = parser::keyword_e(keyword::ELSE, If::Else)
.parse(arena, state)
.map_err(|(_, f, s)| (MadeProgress, f, s))?;
branches.push((cond, then_branch));
// try to parse another `if`
// NOTE this drops spaces between the `else` and the `if`
let optional_if = and!(
backtrackable(space0_e(min_indent, If::Space, If::IndentIf)),
parser::keyword_e(keyword::IF, If::If)
);
match optional_if.parse(arena, state) {
Err((_, _, state)) => break state,
Ok((_, _, state)) => {
loop_state = state;
continue;
}
}
};
let (_, else_branch, state) = space0_before_e( let (_, else_branch, state) = space0_before_e(
specialize_ref( specialize_ref(
@ -1294,9 +1320,9 @@ pub fn if_expr_help<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, If<'a>> {
If::Space, If::Space,
If::IndentElse, If::IndentElse,
) )
.parse(arena, state)?; .parse(arena, state_final_else)
.map_err(|(_, f, s)| (MadeProgress, f, s))?;
// parse the final else
let expr = Expr::If(branches.into_bump_slice(), arena.alloc(else_branch)); let expr = Expr::If(branches.into_bump_slice(), arena.alloc(else_branch));
Ok((MadeProgress, expr, state)) Ok((MadeProgress, expr, state))
@ -1304,10 +1330,10 @@ pub fn if_expr_help<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, If<'a>> {
} }
pub fn if_expr<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, SyntaxError<'a>> { pub fn if_expr<'a>(min_indent: u16) -> impl Parser<'a, Expr<'a>, SyntaxError<'a>> {
specialize( debug!(specialize(
|e, r, c| SyntaxError::Expr(EExpr::If(e, r, c)), |e, r, c| SyntaxError::Expr(EExpr::If(e, r, c)),
if_expr_help(min_indent), if_expr_help(min_indent),
) ))
} }
/// This is a helper function for parsing function args. /// This is a helper function for parsing function args.

View file

@ -440,6 +440,7 @@ pub enum If<'a> {
Syntax(&'a SyntaxError<'a>, Row, Col), Syntax(&'a SyntaxError<'a>, Row, Col),
IndentCondition(Row, Col), IndentCondition(Row, Col),
IndentIf(Row, Col),
IndentThen(Row, Col), IndentThen(Row, Col),
IndentElse(Row, Col), IndentElse(Row, Col),

View file

@ -801,35 +801,36 @@ mod test_reporting {
) )
} }
// #[test] #[test]
// fn if_3_branch_mismatch() { fn if_3_branch_mismatch() {
// report_problem_as( report_problem_as(
// indoc!( indoc!(
// r#" r#"
// if True then 2 else if False then 2 else "foo" if True then 2 else if False then 2 else "foo"
// "# "#
// ), ),
// indoc!( indoc!(
// r#" r#"
// ── TYPE MISMATCH ─────────────────────────────────────────────────────────────── TYPE MISMATCH
// The 2nd branch of this `if` does not match all the previous branches: The 3rd branch of this `if` does not match all the previous branches:
// 1│ if True then 2 else "foo" 1 if True then 2 else if False then 2 else "foo"
// ^^^^^ ^^^^^
// The 2nd branch is a string of type The 3rd branch is a string of type:
// Str Str
// But all the previous branches have the type But all the previous branches have type:
// Num a Num a
// "# I need all branches in an `if` to have the same type!
// ), "#
// ) ),
// } )
}
#[test] #[test]
fn when_branch_mismatch() { fn when_branch_mismatch() {