mirror of
https://github.com/roc-lang/roc.git
synced 2025-11-02 22:01:20 +00:00
Merge pull request #7038 from mulias/expr-dbg
Support `dbg` in expressions
This commit is contained in:
commit
02cf61f985
33 changed files with 1308 additions and 249 deletions
File diff suppressed because it is too large
Load diff
|
|
@ -1209,7 +1209,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) => {
|
||||
|
|
@ -2488,21 +2488,28 @@ pub fn is_valid_interpolation(expr: &ast::Expr<'_>) -> bool {
|
|||
| ast::Expr::AccessorFunction(_)
|
||||
| ast::Expr::RecordUpdater(_)
|
||||
| ast::Expr::Crash
|
||||
| ast::Expr::Dbg
|
||||
| ast::Expr::Underscore(_)
|
||||
| ast::Expr::MalformedIdent(_, _)
|
||||
| ast::Expr::Tag(_)
|
||||
| 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(_, _)
|
||||
| ast::Expr::When(_, _)
|
||||
| ast::Expr::Backpassing(_, _, _)
|
||||
| ast::Expr::SpaceBefore(_, _)
|
||||
| ast::Expr::Str(StrLiteral::Block(_))
|
||||
| ast::Expr::SpaceAfter(_, _) => false,
|
||||
// Desugared dbg expression
|
||||
ast::Expr::Defs(_, loc_ret) => match loc_ret.value {
|
||||
ast::Expr::LowLevelDbg(_, _, continuation) => {
|
||||
is_valid_interpolation(&continuation.value)
|
||||
}
|
||||
_ => false,
|
||||
},
|
||||
// These can contain subexpressions, so we need to recursively check those
|
||||
ast::Expr::Str(StrLiteral::Line(segments)) => {
|
||||
segments.iter().all(|segment| match segment {
|
||||
|
|
|
|||
|
|
@ -268,6 +268,7 @@ pub fn canonicalize_module_defs<'a>(
|
|||
|
||||
crate::desugar::desugar_defs_node_values(
|
||||
arena,
|
||||
var_store,
|
||||
loc_defs,
|
||||
src,
|
||||
&mut None,
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ pub fn can_expr_with(arena: &Bump, home: ModuleId, expr_str: &str) -> CanExprOut
|
|||
// rules multiple times unnecessarily.
|
||||
let loc_expr = desugar::desugar_expr(
|
||||
arena,
|
||||
&mut var_store,
|
||||
&loc_expr,
|
||||
expr_str,
|
||||
&mut None,
|
||||
|
|
|
|||
|
|
@ -0,0 +1,145 @@
|
|||
---
|
||||
source: crates/compiler/can/tests/test_suffixed.rs
|
||||
assertion_line: 449
|
||||
expression: snapshot
|
||||
---
|
||||
Defs {
|
||||
tags: [
|
||||
Index(2147483648),
|
||||
],
|
||||
regions: [
|
||||
@0-26,
|
||||
],
|
||||
space_before: [
|
||||
Slice(start = 0, length = 0),
|
||||
],
|
||||
space_after: [
|
||||
Slice(start = 0, length = 1),
|
||||
],
|
||||
spaces: [
|
||||
Newline,
|
||||
],
|
||||
type_defs: [],
|
||||
value_defs: [
|
||||
Body(
|
||||
@0-4 Identifier {
|
||||
ident: "main",
|
||||
},
|
||||
@11-26 Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
Index(2147483648),
|
||||
],
|
||||
regions: [
|
||||
@15-26,
|
||||
],
|
||||
space_before: [
|
||||
Slice(start = 0, length = 0),
|
||||
],
|
||||
space_after: [
|
||||
Slice(start = 0, length = 0),
|
||||
],
|
||||
spaces: [],
|
||||
type_defs: [],
|
||||
value_defs: [
|
||||
Body(
|
||||
@15-26 Identifier {
|
||||
ident: "64",
|
||||
},
|
||||
@15-26 ParensAround(
|
||||
Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
Index(2147483648),
|
||||
],
|
||||
regions: [
|
||||
@20-25,
|
||||
],
|
||||
space_before: [
|
||||
Slice(start = 0, length = 0),
|
||||
],
|
||||
space_after: [
|
||||
Slice(start = 0, length = 0),
|
||||
],
|
||||
spaces: [],
|
||||
type_defs: [],
|
||||
value_defs: [
|
||||
Body(
|
||||
@20-25 Identifier {
|
||||
ident: "63",
|
||||
},
|
||||
@20-25 Apply(
|
||||
@22-23 Var {
|
||||
module_name: "Num",
|
||||
ident: "add",
|
||||
},
|
||||
[
|
||||
@20-21 Num(
|
||||
"1",
|
||||
),
|
||||
@24-25 Num(
|
||||
"1",
|
||||
),
|
||||
],
|
||||
BinOp(
|
||||
Plus,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
},
|
||||
@15-26 LowLevelDbg(
|
||||
(
|
||||
"test.roc:3",
|
||||
" ",
|
||||
),
|
||||
@20-25 Apply(
|
||||
@20-25 Var {
|
||||
module_name: "Inspect",
|
||||
ident: "toStr",
|
||||
},
|
||||
[
|
||||
@20-25 Var {
|
||||
module_name: "",
|
||||
ident: "63",
|
||||
},
|
||||
],
|
||||
Space,
|
||||
),
|
||||
@20-25 Var {
|
||||
module_name: "",
|
||||
ident: "63",
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
},
|
||||
@11-26 LowLevelDbg(
|
||||
(
|
||||
"test.roc:2",
|
||||
"in =\n ",
|
||||
),
|
||||
@15-26 Apply(
|
||||
@15-26 Var {
|
||||
module_name: "Inspect",
|
||||
ident: "toStr",
|
||||
},
|
||||
[
|
||||
@15-26 Var {
|
||||
module_name: "",
|
||||
ident: "64",
|
||||
},
|
||||
],
|
||||
Space,
|
||||
),
|
||||
@15-26 Var {
|
||||
module_name: "",
|
||||
ident: "64",
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
---
|
||||
source: crates/compiler/can/tests/test_suffixed.rs
|
||||
assertion_line: 459
|
||||
expression: snapshot
|
||||
---
|
||||
Defs {
|
||||
tags: [
|
||||
Index(2147483648),
|
||||
],
|
||||
regions: [
|
||||
@0-19,
|
||||
],
|
||||
space_before: [
|
||||
Slice(start = 0, length = 0),
|
||||
],
|
||||
space_after: [
|
||||
Slice(start = 0, length = 1),
|
||||
],
|
||||
spaces: [
|
||||
Newline,
|
||||
],
|
||||
type_defs: [],
|
||||
value_defs: [
|
||||
Body(
|
||||
@0-4 Identifier {
|
||||
ident: "main",
|
||||
},
|
||||
@11-19 Defs(
|
||||
Defs {
|
||||
tags: [
|
||||
Index(2147483648),
|
||||
],
|
||||
regions: [
|
||||
@11-12,
|
||||
],
|
||||
space_before: [
|
||||
Slice(start = 0, length = 0),
|
||||
],
|
||||
space_after: [
|
||||
Slice(start = 0, length = 0),
|
||||
],
|
||||
spaces: [],
|
||||
type_defs: [],
|
||||
value_defs: [
|
||||
Body(
|
||||
@11-12 Identifier {
|
||||
ident: "63",
|
||||
},
|
||||
@11-12 Num(
|
||||
"1",
|
||||
),
|
||||
),
|
||||
],
|
||||
},
|
||||
@11-19 LowLevelDbg(
|
||||
(
|
||||
"test.roc:2",
|
||||
" ",
|
||||
),
|
||||
@11-12 Apply(
|
||||
@11-12 Var {
|
||||
module_name: "Inspect",
|
||||
ident: "toStr",
|
||||
},
|
||||
[
|
||||
@11-12 Var {
|
||||
module_name: "",
|
||||
ident: "63",
|
||||
},
|
||||
],
|
||||
Space,
|
||||
),
|
||||
@11-12 Var {
|
||||
module_name: "",
|
||||
ident: "63",
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
}
|
||||
|
|
@ -7,13 +7,16 @@ mod suffixed_tests {
|
|||
use insta::assert_snapshot;
|
||||
use roc_can::desugar::desugar_defs_node_values;
|
||||
use roc_parse::test_helpers::parse_defs_with;
|
||||
use roc_types::subs::VarStore;
|
||||
|
||||
macro_rules! run_test {
|
||||
($src:expr) => {{
|
||||
let arena = &Bump::new();
|
||||
let mut var_store = VarStore::default();
|
||||
let mut defs = parse_defs_with(arena, indoc!($src)).unwrap();
|
||||
desugar_defs_node_values(
|
||||
arena,
|
||||
&mut var_store,
|
||||
&mut defs,
|
||||
$src,
|
||||
&mut None,
|
||||
|
|
@ -441,6 +444,16 @@ mod suffixed_tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dbg_expr() {
|
||||
run_test!(
|
||||
r#"
|
||||
main =
|
||||
dbg (dbg 1 + 1)
|
||||
"#
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn apply_argument_single() {
|
||||
run_test!(
|
||||
|
|
|
|||
|
|
@ -46,7 +46,8 @@ impl<'a> Formattable for Expr<'a> {
|
|||
| MalformedClosure
|
||||
| Tag(_)
|
||||
| OpaqueRef(_)
|
||||
| Crash => false,
|
||||
| Crash
|
||||
| Dbg => false,
|
||||
|
||||
RecordAccess(inner, _) | TupleAccess(inner, _) | TrySuffix { expr: inner, .. } => {
|
||||
inner.is_multiline()
|
||||
|
|
@ -65,7 +66,7 @@ impl<'a> Formattable for Expr<'a> {
|
|||
Expect(condition, continuation) => {
|
||||
condition.is_multiline() || continuation.is_multiline()
|
||||
}
|
||||
Dbg(condition, _) => condition.is_multiline(),
|
||||
DbgStmt(condition, _) => condition.is_multiline(),
|
||||
LowLevelDbg(_, _, _) => unreachable!(
|
||||
"LowLevelDbg should only exist after desugaring, not during formatting"
|
||||
),
|
||||
|
|
@ -453,8 +454,12 @@ impl<'a> Formattable for Expr<'a> {
|
|||
Expect(condition, continuation) => {
|
||||
fmt_expect(buf, condition, continuation, self.is_multiline(), indent);
|
||||
}
|
||||
Dbg(condition, continuation) => {
|
||||
fmt_dbg(buf, condition, continuation, self.is_multiline(), indent);
|
||||
Dbg => {
|
||||
buf.indent(indent);
|
||||
buf.push_str("dbg");
|
||||
}
|
||||
DbgStmt(condition, continuation) => {
|
||||
fmt_dbg_stmt(buf, condition, continuation, self.is_multiline(), indent);
|
||||
}
|
||||
LowLevelDbg(_, _, _) => unreachable!(
|
||||
"LowLevelDbg should only exist after desugaring, not during formatting"
|
||||
|
|
@ -1018,7 +1023,7 @@ fn fmt_when<'a>(
|
|||
}
|
||||
}
|
||||
|
||||
fn fmt_dbg<'a>(
|
||||
fn fmt_dbg_stmt<'a>(
|
||||
buf: &mut Buf,
|
||||
condition: &'a Loc<Expr<'a>>,
|
||||
continuation: &'a Loc<Expr<'a>>,
|
||||
|
|
|
|||
|
|
@ -170,6 +170,7 @@ pub fn can_expr_with<'a>(
|
|||
// rules multiple times unnecessarily.
|
||||
let loc_expr = desugar::desugar_expr(
|
||||
arena,
|
||||
&mut var_store,
|
||||
&loc_expr,
|
||||
expr_str,
|
||||
&mut None,
|
||||
|
|
|
|||
|
|
@ -5760,28 +5760,6 @@ mod test_reporting {
|
|||
"#
|
||||
);
|
||||
|
||||
test_report!(
|
||||
dbg_without_final_expression,
|
||||
indoc!(
|
||||
r"
|
||||
dbg 42
|
||||
"
|
||||
),
|
||||
@r#"
|
||||
── INDENT ENDS AFTER EXPRESSION in tmp/dbg_without_final_expression/Test.roc ───
|
||||
|
||||
I am partway through parsing a dbg statement, but I got stuck here:
|
||||
|
||||
4│ dbg 42
|
||||
^
|
||||
|
||||
I was expecting a final expression, like so
|
||||
|
||||
dbg 42
|
||||
"done"
|
||||
"#
|
||||
);
|
||||
|
||||
test_report!(
|
||||
expect_without_final_expression,
|
||||
indoc!(
|
||||
|
|
@ -14517,6 +14495,76 @@ All branches in an `if` must have the same type!
|
|||
"
|
||||
);
|
||||
|
||||
test_report!(
|
||||
dbg_unapplied,
|
||||
indoc!(
|
||||
r"
|
||||
1 + dbg + 2
|
||||
"
|
||||
),
|
||||
@r"
|
||||
── UNAPPLIED DBG in /code/proj/Main.roc ────────────────────────────────────────
|
||||
|
||||
This `dbg` doesn't have a value given to it:
|
||||
|
||||
4│ 1 + dbg + 2
|
||||
^^^
|
||||
|
||||
`dbg` must be passed a value to print at the exact place it's used. `dbg`
|
||||
can't be used as a value that's passed around, like functions can be -
|
||||
it must be applied immediately!
|
||||
|
||||
── TYPE MISMATCH in /code/proj/Main.roc ────────────────────────────────────────
|
||||
|
||||
This 2nd argument to + has an unexpected type:
|
||||
|
||||
4│ 1 + dbg + 2
|
||||
^^^
|
||||
|
||||
This `63` value is a:
|
||||
|
||||
{}
|
||||
|
||||
But + needs its 2nd argument to be:
|
||||
|
||||
Num *
|
||||
"
|
||||
);
|
||||
|
||||
test_report!(
|
||||
dbg_overapplied,
|
||||
indoc!(
|
||||
r#"
|
||||
1 + dbg "" "" + 2
|
||||
"#
|
||||
),
|
||||
@r#"
|
||||
── OVERAPPLIED DBG in /code/proj/Main.roc ──────────────────────────────────────
|
||||
|
||||
This `dbg` has too many values given to it:
|
||||
|
||||
4│ 1 + dbg "" "" + 2
|
||||
^^^^^
|
||||
|
||||
`dbg` must be given exactly one value to print.
|
||||
|
||||
── TYPE MISMATCH in /code/proj/Main.roc ────────────────────────────────────────
|
||||
|
||||
This 2nd argument to + has an unexpected type:
|
||||
|
||||
4│ 1 + dbg "" "" + 2
|
||||
^^^^^^^^^
|
||||
|
||||
This `63` value is a:
|
||||
|
||||
{}
|
||||
|
||||
But + needs its 2nd argument to be:
|
||||
|
||||
Num *
|
||||
"#
|
||||
);
|
||||
|
||||
// TODO: add the following tests after built-in Tasks are added
|
||||
// https://github.com/roc-lang/roc/pull/6836
|
||||
|
||||
|
|
|
|||
|
|
@ -497,7 +497,10 @@ pub enum Expr<'a> {
|
|||
|
||||
Backpassing(&'a [Loc<Pattern<'a>>], &'a Loc<Expr<'a>>, &'a Loc<Expr<'a>>),
|
||||
Expect(&'a Loc<Expr<'a>>, &'a Loc<Expr<'a>>),
|
||||
Dbg(&'a Loc<Expr<'a>>, &'a Loc<Expr<'a>>),
|
||||
|
||||
Dbg,
|
||||
DbgStmt(&'a Loc<Expr<'a>>, &'a Loc<Expr<'a>>),
|
||||
|
||||
// This form of debug is a desugared call to roc_dbg
|
||||
LowLevelDbg(&'a (&'a str, &'a str), &'a Loc<Expr<'a>>, &'a Loc<Expr<'a>>),
|
||||
|
||||
|
|
@ -663,9 +666,9 @@ pub fn is_expr_suffixed(expr: &Expr) -> bool {
|
|||
Expr::Tag(_) => false,
|
||||
Expr::OpaqueRef(_) => false,
|
||||
Expr::Backpassing(_, _, _) => false, // TODO: we might want to check this?
|
||||
Expr::Expect(a, b) | Expr::Dbg(a, b) => {
|
||||
is_expr_suffixed(&a.value) || is_expr_suffixed(&b.value)
|
||||
}
|
||||
Expr::Expect(a, b) => is_expr_suffixed(&a.value) || is_expr_suffixed(&b.value),
|
||||
Expr::Dbg => false,
|
||||
Expr::DbgStmt(a, b) => is_expr_suffixed(&a.value) || is_expr_suffixed(&b.value),
|
||||
Expr::LowLevelDbg(_, a, b) => is_expr_suffixed(&a.value) || is_expr_suffixed(&b.value),
|
||||
Expr::UnaryOp(a, _) => is_expr_suffixed(&a.value),
|
||||
Expr::When(cond, branches) => {
|
||||
|
|
@ -958,9 +961,17 @@ impl<'a, 'b> RecursiveValueDefIter<'a, 'b> {
|
|||
expr_stack.push(&a.value);
|
||||
expr_stack.push(&b.value);
|
||||
}
|
||||
Expect(condition, cont)
|
||||
| Dbg(condition, cont)
|
||||
| LowLevelDbg(_, condition, cont) => {
|
||||
Expect(condition, cont) => {
|
||||
expr_stack.reserve(2);
|
||||
expr_stack.push(&condition.value);
|
||||
expr_stack.push(&cont.value);
|
||||
}
|
||||
DbgStmt(condition, cont) => {
|
||||
expr_stack.reserve(2);
|
||||
expr_stack.push(&condition.value);
|
||||
expr_stack.push(&cont.value);
|
||||
}
|
||||
LowLevelDbg(_, condition, cont) => {
|
||||
expr_stack.reserve(2);
|
||||
expr_stack.push(&condition.value);
|
||||
expr_stack.push(&cont.value);
|
||||
|
|
@ -1032,6 +1043,7 @@ impl<'a, 'b> RecursiveValueDefIter<'a, 'b> {
|
|||
| Var { .. }
|
||||
| Underscore(_)
|
||||
| Crash
|
||||
| Dbg
|
||||
| Tag(_)
|
||||
| OpaqueRef(_)
|
||||
| MalformedIdent(_, _)
|
||||
|
|
@ -2518,8 +2530,9 @@ impl<'a> Malformed for Expr<'a> {
|
|||
Closure(args, body) => args.iter().any(|arg| arg.is_malformed()) || body.is_malformed(),
|
||||
Defs(defs, body) => defs.is_malformed() || body.is_malformed(),
|
||||
Backpassing(args, call, body) => args.iter().any(|arg| arg.is_malformed()) || call.is_malformed() || body.is_malformed(),
|
||||
Expect(condition, continuation) |
|
||||
Dbg(condition, continuation) => condition.is_malformed() || continuation.is_malformed(),
|
||||
Expect(condition, continuation) => condition.is_malformed() || continuation.is_malformed(),
|
||||
Dbg => false,
|
||||
DbgStmt(condition, continuation) => condition.is_malformed() || continuation.is_malformed(),
|
||||
LowLevelDbg(_, condition, continuation) => condition.is_malformed() || continuation.is_malformed(),
|
||||
Apply(func, args, _) => func.is_malformed() || args.iter().any(|arg| arg.is_malformed()),
|
||||
BinOps(firsts, last) => firsts.iter().any(|(expr, _)| expr.is_malformed()) || last.is_malformed(),
|
||||
|
|
|
|||
|
|
@ -194,6 +194,7 @@ fn loc_term_or_underscore_or_conditional<'a>(
|
|||
)),
|
||||
loc(specialize_err(EExpr::Closure, closure_help(options))),
|
||||
loc(crash_kw()),
|
||||
loc(specialize_err(EExpr::Dbg, dbg_kw())),
|
||||
loc(underscore_expression()),
|
||||
loc(record_literal_help()),
|
||||
loc(specialize_err(EExpr::List, list_literal_help())),
|
||||
|
|
@ -215,6 +216,7 @@ fn loc_term_or_underscore<'a>(
|
|||
positive_number_literal_help()
|
||||
)),
|
||||
loc(specialize_err(EExpr::Closure, closure_help(options))),
|
||||
loc(specialize_err(EExpr::Dbg, dbg_kw())),
|
||||
loc(underscore_expression()),
|
||||
loc(record_literal_help()),
|
||||
loc(specialize_err(EExpr::List, list_literal_help())),
|
||||
|
|
@ -232,6 +234,7 @@ fn loc_term<'a>(options: ExprParseOptions) -> impl Parser<'a, Loc<Expr<'a>>, EEx
|
|||
positive_number_literal_help()
|
||||
)),
|
||||
loc(specialize_err(EExpr::Closure, closure_help(options))),
|
||||
loc(specialize_err(EExpr::Dbg, dbg_kw())),
|
||||
loc(record_literal_help()),
|
||||
loc(specialize_err(EExpr::List, list_literal_help())),
|
||||
ident_seq(),
|
||||
|
|
@ -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(
|
||||
|
|
@ -2170,7 +2173,8 @@ fn expr_to_pattern_help<'a>(arena: &'a Bump, expr: &Expr<'a>) -> Result<Pattern<
|
|||
| Expr::If(_, _)
|
||||
| Expr::When(_, _)
|
||||
| Expr::Expect(_, _)
|
||||
| Expr::Dbg(_, _)
|
||||
| Expr::Dbg
|
||||
| Expr::DbgStmt(_, _)
|
||||
| Expr::LowLevelDbg(_, _, _)
|
||||
| Expr::MalformedClosure
|
||||
| Expr::MalformedSuffixed(..)
|
||||
|
|
@ -2647,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>> {
|
||||
|
|
@ -2672,7 +2676,17 @@ fn dbg_help<'a>(
|
|||
|
||||
Ok((MadeProgress, stmt, state))
|
||||
})
|
||||
.trace("dbg_help")
|
||||
.trace("dbg_stmt_help")
|
||||
}
|
||||
|
||||
fn dbg_kw<'a>() -> impl Parser<'a, Expr<'a>, EExpect<'a>> {
|
||||
(move |arena: &'a Bump, state: State<'a>, min_indent: u32| {
|
||||
let (_, _, next_state) =
|
||||
parser::keyword(keyword::DBG, EExpect::Dbg).parse(arena, state, min_indent)?;
|
||||
|
||||
Ok((MadeProgress, Expr::Dbg, next_state))
|
||||
})
|
||||
.trace("dbg_kw")
|
||||
}
|
||||
|
||||
fn import<'a>() -> impl Parser<'a, ValueDef<'a>, EImport<'a>> {
|
||||
|
|
@ -2986,14 +3000,17 @@ 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::Apply(
|
||||
arena.alloc(Loc {
|
||||
value: Expr::Dbg,
|
||||
region: loc_stmt.region,
|
||||
}),
|
||||
arena.alloc([condition]),
|
||||
CalledVia::Space,
|
||||
)
|
||||
}
|
||||
Stmt::ValueDef(ValueDef::Expect { .. }) => {
|
||||
return Err(EExpr::Expect(
|
||||
|
|
@ -3145,13 +3162,19 @@ 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::Dbg(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::Apply(
|
||||
arena.alloc(Loc {
|
||||
value: Expr::Dbg,
|
||||
region: sp_stmt.item.region,
|
||||
}),
|
||||
arena.alloc([condition]),
|
||||
CalledVia::Space,
|
||||
)
|
||||
};
|
||||
|
||||
let e = if sp_stmt.before.is_empty() {
|
||||
e
|
||||
|
|
|
|||
|
|
@ -779,7 +779,8 @@ impl<'a> Normalize<'a> for Expr<'a> {
|
|||
arena.alloc(a.normalize(arena)),
|
||||
arena.alloc(b.normalize(arena)),
|
||||
),
|
||||
Expr::Dbg(a, b) => Expr::Dbg(
|
||||
Expr::Dbg => Expr::Dbg,
|
||||
Expr::DbgStmt(a, b) => Expr::DbgStmt(
|
||||
arena.alloc(a.normalize(arena)),
|
||||
arena.alloc(b.normalize(arena)),
|
||||
),
|
||||
|
|
|
|||
|
|
@ -828,8 +828,7 @@ where
|
|||
}
|
||||
|
||||
// This should be enough for anyone. Right? RIGHT?
|
||||
let indent_text =
|
||||
"| ; : ! | ; : ! | ; : ! | ; : ! | ; : ! | ; : ! | ; : ! | ; : ! | ; : ! ";
|
||||
let indent_text = "| ; : ! ".repeat(20);
|
||||
|
||||
let cur_indent = INDENT.with(|i| *i.borrow());
|
||||
|
||||
|
|
|
|||
|
|
@ -220,6 +220,12 @@ pub enum Problem {
|
|||
OverAppliedCrash {
|
||||
region: Region,
|
||||
},
|
||||
UnappliedDbg {
|
||||
region: Region,
|
||||
},
|
||||
OverAppliedDbg {
|
||||
region: Region,
|
||||
},
|
||||
FileProblem {
|
||||
filename: PathBuf,
|
||||
error: io::ErrorKind,
|
||||
|
|
@ -313,6 +319,8 @@ impl Problem {
|
|||
// injecting a crash message
|
||||
Problem::UnappliedCrash { .. } => RuntimeError,
|
||||
Problem::OverAppliedCrash { .. } => RuntimeError,
|
||||
Problem::UnappliedDbg { .. } => RuntimeError,
|
||||
Problem::OverAppliedDbg { .. } => RuntimeError,
|
||||
Problem::DefsOnlyUsedInRecursion(_, _) => Warning,
|
||||
Problem::FileProblem { .. } => Fatal,
|
||||
}
|
||||
|
|
@ -477,6 +485,8 @@ impl Problem {
|
|||
| Problem::UnnecessaryOutputWildcard { region }
|
||||
| Problem::OverAppliedCrash { region }
|
||||
| Problem::UnappliedCrash { region }
|
||||
| Problem::OverAppliedDbg { region }
|
||||
| Problem::UnappliedDbg { region }
|
||||
| Problem::DefsOnlyUsedInRecursion(_, region) => Some(*region),
|
||||
Problem::RuntimeError(RuntimeError::CircularDef(cycle_entries))
|
||||
| Problem::BadRecursion(cycle_entries) => {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
use roc_error_macros::internal_error;
|
||||
use roc_types::subs::{Rank, Variable};
|
||||
|
||||
const DEFAULT_POOLS: usize = 8;
|
||||
|
|
@ -27,14 +28,14 @@ impl Pools {
|
|||
pub fn get_mut(&mut self, rank: Rank) -> &mut Vec<Variable> {
|
||||
match self.0.get_mut(rank.into_usize()) {
|
||||
Some(reference) => reference,
|
||||
None => panic!("Compiler bug: could not find pool at rank {rank}"),
|
||||
None => internal_error!("Compiler bug: could not find pool at rank {rank}"),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(&self, rank: Rank) -> &Vec<Variable> {
|
||||
match self.0.get(rank.into_usize()) {
|
||||
Some(reference) => reference,
|
||||
None => panic!("Compiler bug: could not find pool at rank {rank}"),
|
||||
None => internal_error!("Compiler bug: could not find pool at rank {rank}"),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -46,7 +47,7 @@ impl Pools {
|
|||
let last = self
|
||||
.0
|
||||
.pop()
|
||||
.unwrap_or_else(|| panic!("Attempted to split_last() on non-empty Pools"));
|
||||
.unwrap_or_else(|| internal_error!("Attempted to split_last() on non-empty Pools"));
|
||||
|
||||
(last, self.0)
|
||||
}
|
||||
|
|
|
|||
56
crates/compiler/test_mono/generated/dbg_expr.txt
generated
Normal file
56
crates/compiler/test_mono/generated/dbg_expr.txt
generated
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
procedure Inspect.278 (Inspect.279, Inspect.277):
|
||||
let Inspect.318 : Str = CallByName Num.96 Inspect.277;
|
||||
let Inspect.317 : Str = CallByName Inspect.63 Inspect.279 Inspect.318;
|
||||
dec Inspect.318;
|
||||
ret Inspect.317;
|
||||
|
||||
procedure Inspect.30 (Inspect.147):
|
||||
ret Inspect.147;
|
||||
|
||||
procedure Inspect.33 (Inspect.152):
|
||||
let Inspect.305 : Str = CallByName Inspect.5 Inspect.152;
|
||||
let Inspect.304 : Str = CallByName Inspect.64 Inspect.305;
|
||||
ret Inspect.304;
|
||||
|
||||
procedure Inspect.39 (Inspect.301):
|
||||
let Inspect.311 : Str = "";
|
||||
ret Inspect.311;
|
||||
|
||||
procedure Inspect.5 (Inspect.150):
|
||||
let Inspect.312 : I64 = CallByName Inspect.57 Inspect.150;
|
||||
let Inspect.309 : {} = Struct {};
|
||||
let Inspect.308 : Str = CallByName Inspect.39 Inspect.309;
|
||||
let Inspect.307 : Str = CallByName Inspect.278 Inspect.308 Inspect.312;
|
||||
ret Inspect.307;
|
||||
|
||||
procedure Inspect.57 (Inspect.277):
|
||||
let Inspect.313 : I64 = CallByName Inspect.30 Inspect.277;
|
||||
ret Inspect.313;
|
||||
|
||||
procedure Inspect.63 (Inspect.300, Inspect.296):
|
||||
let Inspect.320 : Str = CallByName Str.3 Inspect.300 Inspect.296;
|
||||
ret Inspect.320;
|
||||
|
||||
procedure Inspect.64 (Inspect.302):
|
||||
ret Inspect.302;
|
||||
|
||||
procedure Num.19 (#Attr.2, #Attr.3):
|
||||
let Num.281 : I64 = lowlevel NumAdd #Attr.2 #Attr.3;
|
||||
ret Num.281;
|
||||
|
||||
procedure Num.96 (#Attr.2):
|
||||
let Num.282 : Str = lowlevel NumToStr #Attr.2;
|
||||
ret Num.282;
|
||||
|
||||
procedure Str.3 (#Attr.2, #Attr.3):
|
||||
let Str.236 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.236;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.4 : I64 = 1i64;
|
||||
let Test.1 : I64 = 2i64;
|
||||
let Test.2 : Str = CallByName Inspect.33 Test.1;
|
||||
dbg Test.2;
|
||||
dec Test.2;
|
||||
let Test.3 : I64 = CallByName Num.19 Test.4 Test.1;
|
||||
ret Test.3;
|
||||
58
crates/compiler/test_mono/generated/dbg_inside_string.txt
generated
Normal file
58
crates/compiler/test_mono/generated/dbg_inside_string.txt
generated
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
procedure Inspect.250 (Inspect.251, Inspect.249):
|
||||
let Inspect.323 : Str = "\"";
|
||||
let Inspect.322 : Str = CallByName Inspect.63 Inspect.251 Inspect.323;
|
||||
dec Inspect.323;
|
||||
let Inspect.318 : Str = CallByName Inspect.63 Inspect.322 Inspect.249;
|
||||
let Inspect.319 : Str = "\"";
|
||||
let Inspect.317 : Str = CallByName Inspect.63 Inspect.318 Inspect.319;
|
||||
dec Inspect.319;
|
||||
ret Inspect.317;
|
||||
|
||||
procedure Inspect.30 (Inspect.147):
|
||||
ret Inspect.147;
|
||||
|
||||
procedure Inspect.33 (Inspect.152):
|
||||
let Inspect.305 : Str = CallByName Inspect.5 Inspect.152;
|
||||
let Inspect.304 : Str = CallByName Inspect.64 Inspect.305;
|
||||
ret Inspect.304;
|
||||
|
||||
procedure Inspect.39 (Inspect.301):
|
||||
let Inspect.311 : Str = "";
|
||||
ret Inspect.311;
|
||||
|
||||
procedure Inspect.47 (Inspect.249):
|
||||
let Inspect.313 : Str = CallByName Inspect.30 Inspect.249;
|
||||
ret Inspect.313;
|
||||
|
||||
procedure Inspect.5 (Inspect.150):
|
||||
let Inspect.312 : Str = CallByName Inspect.47 Inspect.150;
|
||||
let Inspect.309 : {} = Struct {};
|
||||
let Inspect.308 : Str = CallByName Inspect.39 Inspect.309;
|
||||
let Inspect.307 : Str = CallByName Inspect.250 Inspect.308 Inspect.312;
|
||||
dec Inspect.312;
|
||||
ret Inspect.307;
|
||||
|
||||
procedure Inspect.63 (Inspect.300, Inspect.296):
|
||||
let Inspect.321 : Str = CallByName Str.3 Inspect.300 Inspect.296;
|
||||
ret Inspect.321;
|
||||
|
||||
procedure Inspect.64 (Inspect.302):
|
||||
ret Inspect.302;
|
||||
|
||||
procedure Str.3 (#Attr.2, #Attr.3):
|
||||
let Str.238 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.238;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.4 : Str = "Hello ";
|
||||
let Test.1 : Str = "world";
|
||||
inc Test.1;
|
||||
let Test.2 : Str = CallByName Inspect.33 Test.1;
|
||||
dbg Test.2;
|
||||
dec Test.2;
|
||||
let Test.7 : Str = "!";
|
||||
let Test.5 : Str = CallByName Str.3 Test.1 Test.7;
|
||||
dec Test.7;
|
||||
let Test.3 : Str = CallByName Str.3 Test.4 Test.5;
|
||||
dec Test.5;
|
||||
ret Test.3;
|
||||
56
crates/compiler/test_mono/generated/dbg_nested_expr.txt
generated
Normal file
56
crates/compiler/test_mono/generated/dbg_nested_expr.txt
generated
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
procedure Inspect.278 (Inspect.279, Inspect.277):
|
||||
let Inspect.318 : Str = CallByName Num.96 Inspect.277;
|
||||
let Inspect.317 : Str = CallByName Inspect.63 Inspect.279 Inspect.318;
|
||||
dec Inspect.318;
|
||||
ret Inspect.317;
|
||||
|
||||
procedure Inspect.30 (Inspect.147):
|
||||
ret Inspect.147;
|
||||
|
||||
procedure Inspect.33 (Inspect.152):
|
||||
let Inspect.324 : Str = CallByName Inspect.5 Inspect.152;
|
||||
let Inspect.323 : Str = CallByName Inspect.64 Inspect.324;
|
||||
ret Inspect.323;
|
||||
|
||||
procedure Inspect.39 (Inspect.301):
|
||||
let Inspect.311 : Str = "";
|
||||
ret Inspect.311;
|
||||
|
||||
procedure Inspect.5 (Inspect.150):
|
||||
let Inspect.312 : I64 = CallByName Inspect.57 Inspect.150;
|
||||
let Inspect.309 : {} = Struct {};
|
||||
let Inspect.308 : Str = CallByName Inspect.39 Inspect.309;
|
||||
let Inspect.307 : Str = CallByName Inspect.278 Inspect.308 Inspect.312;
|
||||
ret Inspect.307;
|
||||
|
||||
procedure Inspect.57 (Inspect.277):
|
||||
let Inspect.313 : I64 = CallByName Inspect.30 Inspect.277;
|
||||
ret Inspect.313;
|
||||
|
||||
procedure Inspect.63 (Inspect.300, Inspect.296):
|
||||
let Inspect.320 : Str = CallByName Str.3 Inspect.300 Inspect.296;
|
||||
ret Inspect.320;
|
||||
|
||||
procedure Inspect.64 (Inspect.302):
|
||||
ret Inspect.302;
|
||||
|
||||
procedure Num.96 (#Attr.2):
|
||||
let Num.281 : Str = lowlevel NumToStr #Attr.2;
|
||||
ret Num.281;
|
||||
|
||||
procedure Str.3 (#Attr.2, #Attr.3):
|
||||
let Str.236 : Str = lowlevel StrConcat #Attr.2 #Attr.3;
|
||||
ret Str.236;
|
||||
|
||||
procedure Test.0 ():
|
||||
let Test.3 : I64 = 1i64;
|
||||
let Test.4 : Str = CallByName Inspect.33 Test.3;
|
||||
dbg Test.4;
|
||||
dec Test.4;
|
||||
let Test.5 : Str = CallByName Inspect.33 Test.3;
|
||||
dbg Test.5;
|
||||
dec Test.5;
|
||||
let Test.6 : Str = CallByName Inspect.33 Test.3;
|
||||
dbg Test.6;
|
||||
dec Test.6;
|
||||
ret Test.3;
|
||||
|
|
@ -3243,6 +3243,33 @@ fn dbg_str_followed_by_number() {
|
|||
)
|
||||
}
|
||||
|
||||
#[mono_test]
|
||||
fn dbg_expr() {
|
||||
indoc!(
|
||||
r#"
|
||||
1 + (dbg 2)
|
||||
"#
|
||||
)
|
||||
}
|
||||
|
||||
#[mono_test]
|
||||
fn dbg_nested_expr() {
|
||||
indoc!(
|
||||
r#"
|
||||
dbg (dbg (dbg 1))
|
||||
"#
|
||||
)
|
||||
}
|
||||
|
||||
#[mono_test]
|
||||
fn dbg_inside_string() {
|
||||
indoc!(
|
||||
r#"
|
||||
"Hello $(dbg "world")!"
|
||||
"#
|
||||
)
|
||||
}
|
||||
|
||||
#[mono_test]
|
||||
fn linked_list_reverse() {
|
||||
indoc!(
|
||||
|
|
|
|||
|
|
@ -1,3 +1 @@
|
|||
dbg 1 == 1
|
||||
|
||||
4
|
||||
dbg 1
|
||||
|
|
@ -1,32 +1,12 @@
|
|||
SpaceBefore(
|
||||
SpaceAfter(
|
||||
Dbg(
|
||||
@5-11 BinOps(
|
||||
[
|
||||
(
|
||||
@5-6 Num(
|
||||
"1",
|
||||
),
|
||||
@7-9 Equals,
|
||||
),
|
||||
],
|
||||
@10-11 Num(
|
||||
"1",
|
||||
),
|
||||
),
|
||||
@13-14 SpaceBefore(
|
||||
Num(
|
||||
"4",
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
Newline,
|
||||
],
|
||||
),
|
||||
),
|
||||
SpaceAfter(
|
||||
Apply(
|
||||
@0-5 Dbg,
|
||||
[
|
||||
Newline,
|
||||
@4-5 Num(
|
||||
"1",
|
||||
),
|
||||
],
|
||||
Space,
|
||||
),
|
||||
[
|
||||
Newline,
|
||||
|
|
|
|||
|
|
@ -1,4 +1 @@
|
|||
|
||||
dbg 1 == 1
|
||||
|
||||
4
|
||||
dbg 1
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
dbg 1 == 1
|
||||
|
||||
4
|
||||
|
|
@ -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,
|
||||
],
|
||||
)
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
|
||||
dbg 1 == 1
|
||||
|
||||
4
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
SpaceAfter(
|
||||
Dbg(
|
||||
DbgStmt(
|
||||
@4-16 Tuple(
|
||||
[
|
||||
@5-6 Num(
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue