Make parsing of conditionals consistent between stmts/exprs

This commit is contained in:
Joshua Warner 2024-12-02 17:52:18 -08:00
parent e47d7924d3
commit 7eb9909ac5
No known key found for this signature in database
GPG key ID: 89AD497003F93FDD
6 changed files with 100 additions and 38 deletions

View file

@ -182,26 +182,25 @@ fn record_field_access_chain<'a>() -> impl Parser<'a, Vec<'a, Suffix<'a>>, EExpr
/// pattern later
fn loc_term_or_underscore_or_conditional<'a>(
options: ExprParseOptions,
allow_conditional: bool,
) -> impl Parser<'a, Loc<Expr<'a>>, EExpr<'a>> {
move |arena: &'a Bump, state: State<'a>, min_indent: u32| {
if allow_conditional {
match loc_conditional(options).parse(arena, state.clone(), min_indent) {
Ok((_, expr, state)) => return Ok((MadeProgress, expr, state)),
Err((MadeProgress, e)) => return Err((MadeProgress, e)),
Err((NoProgress, _)) => {}
}
}
loc_term_or_underscore(options).parse(arena, state, min_indent)
}
}
fn loc_conditional<'a>(options: ExprParseOptions) -> impl Parser<'a, Loc<Expr<'a>>, EExpr<'a>> {
one_of!(
loc_expr_in_parens_etc_help(),
loc(specialize_err(EExpr::If, if_expr_help(options))),
loc(specialize_err(EExpr::When, when::when_expr_help(options))),
loc(specialize_err(EExpr::Str, string_like_literal_help())),
loc(specialize_err(
EExpr::Number,
positive_number_literal_help()
)),
loc(specialize_err(EExpr::Closure, closure_help(options))),
loc(crash_kw()),
loc(specialize_err(EExpr::Dbg, dbg_kw())),
loc(try_kw()),
loc(underscore_expression()),
loc(record_literal_help()),
loc(specialize_err(EExpr::List, list_literal_help())),
ident_seq(),
)
.trace("term_or_underscore_or_conditional")
}
/// In some contexts we want to parse the `_` as an expression, so it can then be turned into a
@ -217,6 +216,7 @@ fn loc_term_or_underscore<'a>(
positive_number_literal_help()
)),
loc(specialize_err(EExpr::Closure, closure_help(options))),
loc(crash_kw()),
loc(specialize_err(EExpr::Dbg, dbg_kw())),
loc(try_kw()),
loc(underscore_expression()),
@ -295,6 +295,7 @@ fn crash_kw<'a>() -> impl Parser<'a, Expr<'a>, EExpr<'a>> {
fn loc_possibly_negative_or_negated_term<'a>(
options: ExprParseOptions,
allow_negate: bool,
allow_conditional: bool,
) -> impl Parser<'a, Loc<Expr<'a>>, EExpr<'a>> {
let parse_unary_negate = move |arena, state: State<'a>, min_indent: u32| {
let initial = state.clone();
@ -305,7 +306,7 @@ fn loc_possibly_negative_or_negated_term<'a>(
let (_, (loc_op, loc_expr), state) = and(
loc(unary_negate()),
loc_possibly_negative_or_negated_term(options, true),
loc_possibly_negative_or_negated_term(options, true, allow_conditional),
)
.parse(arena, state, min_indent)?;
@ -322,7 +323,7 @@ fn loc_possibly_negative_or_negated_term<'a>(
and(
loc(unary_not()).trace("not"),
space0_before_e(
loc_possibly_negative_or_negated_term(options, true),
loc_possibly_negative_or_negated_term(options, true, allow_conditional),
EExpr::IndentStart
)
.trace("not_expr")
@ -332,7 +333,7 @@ fn loc_possibly_negative_or_negated_term<'a>(
}
))
.trace("not_expr"),
loc_term_or_underscore_or_conditional(options)
loc_term_or_underscore_or_conditional(options, allow_conditional)
]
.trace("loc_possibly_negative_or_negated_term")
}
@ -409,10 +410,11 @@ fn parse_expr_operator_chain<'a>(
) -> Result<(Progress, Expr<'a>, State<'a>), (Progress, EExpr<'a>)> {
let line_indent = state.line_indent();
let (_, expr, state) =
loc_possibly_negative_or_negated_term(options, true).parse(arena, state, min_indent)?;
let (_, expr, state) = loc_possibly_negative_or_negated_term(options, true, true)
.parse(arena, state, min_indent)?;
let mut initial_state = state.clone();
let end = state.pos();
let (spaces_before_op, state) =
match space0_e(EExpr::IndentEnd).parse(arena, state.clone(), min_indent) {
@ -420,6 +422,8 @@ fn parse_expr_operator_chain<'a>(
Ok((_, spaces_before_op, state)) => (spaces_before_op, state),
};
let allow_negate = state.pos() > end;
let mut expr_state = ExprState {
operators: Vec::new_in(arena),
arguments: Vec::new_in(arena),
@ -435,7 +439,7 @@ fn parse_expr_operator_chain<'a>(
loop {
let parser = skip_first(
crate::blankspace::check_indent(EExpr::IndentEnd),
loc_term_or_underscore(options),
loc_possibly_negative_or_negated_term(options, allow_negate, false),
)
.trace("term_or_underscore");
match parser.parse(arena, state.clone(), call_min_indent) {
@ -604,8 +608,8 @@ fn parse_stmt_operator_chain<'a>(
) -> Result<(Progress, Stmt<'a>, State<'a>), (Progress, EExpr<'a>)> {
let line_indent = state.line_indent();
let (_, expr, state) =
loc_possibly_negative_or_negated_term(options, true).parse(arena, state, min_indent)?;
let (_, expr, state) = loc_possibly_negative_or_negated_term(options, true, true)
.parse(arena, state, min_indent)?;
let mut initial_state = state.clone();
let end = state.pos();
@ -633,7 +637,7 @@ fn parse_stmt_operator_chain<'a>(
loop {
let parser = skip_first(
crate::blankspace::check_indent(EExpr::IndentEnd),
loc_possibly_negative_or_negated_term(options, allow_negate),
loc_possibly_negative_or_negated_term(options, allow_negate, false),
);
match parser.parse(arena, state.clone(), call_min_indent) {
Err((MadeProgress, f)) => return Err((MadeProgress, f)),
@ -1590,7 +1594,7 @@ fn parse_after_binop<'a>(
mut expr_state: ExprState<'a>,
loc_op: Loc<BinOp>,
) -> ParseResult<'a, Expr<'a>, EExpr<'a>> {
match loc_possibly_negative_or_negated_term(options, true).parse(
match loc_possibly_negative_or_negated_term(options, true, true).parse(
arena,
state.clone(),
min_indent,

View file

@ -0,0 +1,52 @@
Defs(
Defs {
tags: [
EitherIndex(2147483648),
],
regions: [
@0-11,
],
space_before: [
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
],
space_after: [
Slice<roc_parse::ast::CommentOrNewline> { start: 0, length: 0 },
],
spaces: [],
type_defs: [],
value_defs: [
Body(
@0-3 RecordDestructure(
Collection {
items: [],
final_comments: [
Newline,
],
},
),
@4-11 Apply(
@4-5 Var {
module_name: "",
ident: "d",
},
[
@6-11 Var {
module_name: "",
ident: "when!",
},
],
Space,
),
),
],
},
@13-14 SpaceBefore(
Var {
module_name: "",
ident: "s",
},
[
Newline,
],
),
)

View file

@ -20,21 +20,21 @@ Defs(
ident: "a",
},
@2-9 Apply(
@2-3 SpaceAfter(
Tag(
"A",
),
[
Newline,
],
@2-3 Tag(
"A",
),
[
@5-7 UnaryOp(
@6-7 Var {
module_name: "",
ident: "g",
},
@5-6 Negate,
@5-7 SpaceBefore(
UnaryOp(
@6-7 Var {
module_name: "",
ident: "g",
},
@5-6 Negate,
),
[
Newline,
],
),
@8-9 Var {
module_name: "",

View file

@ -382,6 +382,7 @@ mod test_snapshots {
pass/empty_record.expr,
pass/empty_record_assign_tag.expr,
pass/empty_record_assignment.expr,
pass/empty_record_assignment_d_when_bang.expr,
pass/empty_record_eq_dbg.expr,
pass/empty_record_eq_newlines_doubleeq.expr,
pass/empty_record_newline_assign.expr,