Parse dbg in expression position

Add dbg parsing logic everywhere we parse normal expressions. Add
special case to statement parsing to handle a series of statements
ending in a `dbg` in expression position.

Rename existing `dbg_help` function to `dbg_stmt_help`, similarly rename
syntax snapshot test files to specify which ones are for dbg statements.
This commit is contained in:
Elias Mulhall 2024-08-26 14:42:06 -04:00
parent 43d932df3b
commit 335265e15c
12 changed files with 90 additions and 56 deletions

View file

@ -1207,7 +1207,7 @@ pub fn canonicalize_expr<'a>(
output,
)
}
ast::Expr::Dbg(_, _) => {
ast::Expr::Dbg(_) | ast::Expr::DbgStmt(_, _) => {
internal_error!("Dbg should have been desugared by now")
}
ast::Expr::LowLevelDbg((source_location, source), message, continuation) => {
@ -2476,7 +2476,7 @@ pub fn is_valid_interpolation(expr: &ast::Expr<'_>) -> bool {
| ast::Expr::OpaqueRef(_)
| ast::Expr::MalformedClosure => true,
// Newlines are disallowed inside interpolation, and these all require newlines
ast::Expr::Dbg(_, _)
ast::Expr::DbgStmt(_, _)
| ast::Expr::LowLevelDbg(_, _, _)
| ast::Expr::Defs(_, _)
| ast::Expr::Expect(_, _)
@ -2486,6 +2486,7 @@ pub fn is_valid_interpolation(expr: &ast::Expr<'_>) -> bool {
| ast::Expr::Str(StrLiteral::Block(_))
| ast::Expr::SpaceAfter(_, _) => false,
// These can contain subexpressions, so we need to recursively check those
ast::Expr::Dbg(expr) => is_valid_interpolation(&expr.value),
ast::Expr::Str(StrLiteral::Line(segments)) => {
segments.iter().all(|segment| match segment {
ast::StrSegment::EscapedChar(_)

View file

@ -187,6 +187,7 @@ fn loc_term_or_underscore_or_conditional<'a>(
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::Dbg, dbg_expr_help(options))),
loc(specialize_err(EExpr::Str, string_like_literal_help())),
loc(specialize_err(
EExpr::Number,
@ -214,6 +215,7 @@ fn loc_term_or_underscore<'a>(
EExpr::Number,
positive_number_literal_help()
)),
loc(specialize_err(EExpr::Dbg, dbg_expr_help(options))),
loc(specialize_err(EExpr::Closure, closure_help(options))),
loc(underscore_expression()),
loc(record_literal_help()),
@ -231,6 +233,7 @@ fn loc_term<'a>(options: ExprParseOptions) -> impl Parser<'a, Loc<Expr<'a>>, EEx
EExpr::Number,
positive_number_literal_help()
)),
loc(specialize_err(EExpr::Dbg, dbg_expr_help(options))),
loc(specialize_err(EExpr::Closure, closure_help(options))),
loc(record_literal_help()),
loc(specialize_err(EExpr::List, list_literal_help())),
@ -541,7 +544,7 @@ fn stmt_start<'a>(
)),
loc(specialize_err(
EExpr::Dbg,
dbg_help(options, preceding_comment)
dbg_stmt_help(options, preceding_comment)
)),
loc(specialize_err(EExpr::Import, map(import(), Stmt::ValueDef))),
map(
@ -2648,7 +2651,7 @@ fn expect_help<'a>(
}
}
fn dbg_help<'a>(
fn dbg_stmt_help<'a>(
options: ExprParseOptions,
preceding_comment: Region,
) -> impl Parser<'a, Stmt<'a>, EExpect<'a>> {
@ -2673,7 +2676,29 @@ fn dbg_help<'a>(
Ok((MadeProgress, stmt, state))
})
.trace("dbg_help")
.trace("dbg_stmt_help")
}
fn dbg_expr_help<'a>(options: ExprParseOptions) -> impl Parser<'a, Expr<'a>, EExpect<'a>> {
(move |arena: &'a Bump, state: State<'a>, min_indent| {
let (_, _, state) =
parser::keyword(keyword::DBG, EExpect::Dbg).parse(arena, state, min_indent)?;
let (_, condition, state) = parse_block(
options,
arena,
state,
true,
EExpect::IndentCondition,
EExpect::Condition,
)
.map_err(|(_, f)| (MadeProgress, f))?;
let expr = Expr::Dbg(arena.alloc(condition));
Ok((MadeProgress, expr, state))
})
.trace("dbg_expr_help")
}
fn import<'a>() -> impl Parser<'a, ValueDef<'a>, EImport<'a>> {
@ -2987,14 +3012,10 @@ fn stmts_to_expr<'a>(
arena.alloc(e).before(space)
}
}
Stmt::ValueDef(ValueDef::Dbg { .. }) => {
return Err(EExpr::Dbg(
EExpect::Continuation(
arena.alloc(EExpr::IndentEnd(loc_stmt.region.end())),
loc_stmt.region.end(),
),
loc_stmt.region.start(),
));
Stmt::ValueDef(ValueDef::Dbg { condition, .. }) => {
// If we parse a `dbg` as the last thing in a series of statements then it's
// actually an expression.
Expr::Dbg(arena.alloc(condition))
}
Stmt::ValueDef(ValueDef::Expect { .. }) => {
return Err(EExpr::Expect(
@ -3146,13 +3167,12 @@ fn stmts_to_defs<'a>(
} = vd
{
if exprify_dbg {
if i + 1 >= stmts.len() {
return Err(EExpr::DbgContinue(sp_stmt.item.region.end()));
}
let rest = stmts_to_expr(&stmts[i + 1..], arena)?;
let e = Expr::DbgStmt(arena.alloc(condition), arena.alloc(rest));
let e = if i + 1 < stmts.len() {
let rest = stmts_to_expr(&stmts[i + 1..], arena)?;
Expr::DbgStmt(arena.alloc(condition), arena.alloc(rest))
} else {
Expr::Dbg(arena.alloc(condition))
};
let e = if sp_stmt.before.is_empty() {
e

View file

@ -1,32 +1,8 @@
SpaceBefore(
SpaceAfter(
DbgStmt(
@5-11 BinOps(
[
(
@5-6 Num(
"1",
),
@7-9 Equals,
),
],
@10-11 Num(
"1",
),
),
@13-14 SpaceBefore(
Num(
"4",
),
[
Newline,
Newline,
],
),
SpaceAfter(
Dbg(
@4-5 Num(
"1",
),
[
Newline,
],
),
[
Newline,

View file

@ -1,4 +1 @@
dbg 1 == 1
4
dbg 1

View file

@ -0,0 +1,3 @@
dbg 1 == 1
4

View file

@ -0,0 +1,34 @@
SpaceBefore(
SpaceAfter(
DbgStmt(
@5-11 BinOps(
[
(
@5-6 Num(
"1",
),
@7-9 Equals,
),
],
@10-11 Num(
"1",
),
),
@13-14 SpaceBefore(
Num(
"4",
),
[
Newline,
Newline,
],
),
),
[
Newline,
],
),
[
Newline,
],
)

View file

@ -0,0 +1,4 @@
dbg 1 == 1
4

View file

@ -301,8 +301,9 @@ mod test_snapshots {
pass/comment_with_non_ascii.expr,
pass/control_characters_in_scalar.expr,
pass/crash.expr,
pass/dbg_stmt.expr,
pass/dbg_stmt_multiline.expr,
pass/dbg.expr,
pass/dbg_multiline.expr,
pass/defs_suffixed_middle_extra_indents.moduledefs,
pass/deprecated_interpolated_string.expr,
pass/destructure_tag_assignment.expr,