From 9b8137c056553b55b1b50490f9a9494c44d9c9d3 Mon Sep 17 00:00:00 2001 From: KtorZ Date: Sat, 1 Mar 2025 16:59:22 +0100 Subject: [PATCH] Better trace parsing + default behaviour. Somehow, we allow traces with no continuation after and currently default to a Todo. That todo is completely invisible from a user standpoint and return a generic `a`. So it is pretty easy for someone to think their program is okay, compiles, and have no issues, while simply crashing at runtime because of an invisible todo. Hence, I've changed that to default to `Void` instead, which is more sensible as a default for an empty trace. Also, I've made the parser fail with one puts a colon for label, but doesn't add any value to display. Fixes #1113. Signed-off-by: KtorZ --- .../src/parser/expr/fail_todo_trace.rs | 21 +++++- .../expr/snapshots/trace_dangling_colons.snap | 72 +++++++++++++++++++ .../expr/snapshots/trace_expr_todo.snap | 12 +--- .../parser/expr/snapshots/trace_labelled.snap | 12 +--- .../parser/expr/snapshots/trace_variadic.snap | 12 +--- crates/aiken-lang/src/tests/check.rs | 16 +++++ 6 files changed, 112 insertions(+), 33 deletions(-) create mode 100644 crates/aiken-lang/src/parser/expr/snapshots/trace_dangling_colons.snap diff --git a/crates/aiken-lang/src/parser/expr/fail_todo_trace.rs b/crates/aiken-lang/src/parser/expr/fail_todo_trace.rs index aed2d6f3..2a1180a6 100644 --- a/crates/aiken-lang/src/parser/expr/fail_todo_trace.rs +++ b/crates/aiken-lang/src/parser/expr/fail_todo_trace.rs @@ -1,5 +1,5 @@ use crate::{ - ast::TraceKind, + ast::{well_known, TraceKind}, expr::UntypedExpr, parser::{ error::{ParseError, Pattern}, @@ -32,7 +32,8 @@ pub fn parser<'a>( choice((just(Token::Colon), just(Token::Comma))) .then( choice((string::hybrid(), expression.clone())) - .separated_by(just(Token::Comma)), + .separated_by(just(Token::Comma)) + .at_least(1), ) .validate(|(token, arguments), span, emit| { if token != Token::Colon { @@ -53,7 +54,10 @@ pub fn parser<'a>( |((label, arguments), continuation), span| UntypedExpr::Trace { kind: TraceKind::Trace, location: span, - then: Box::new(continuation.unwrap_or_else(|| UntypedExpr::todo(None, span))), + then: Box::new(continuation.unwrap_or_else(|| UntypedExpr::Var { + location: span, + name: well_known::VOID.to_string(), + })), label: Box::new(label), arguments, }, @@ -193,4 +197,15 @@ mod tests { "# ); } + + #[test] + fn trace_dangling_colons() { + assert_expr!( + r#" + let debug = fn() { + trace "foo": + } + "# + ); + } } diff --git a/crates/aiken-lang/src/parser/expr/snapshots/trace_dangling_colons.snap b/crates/aiken-lang/src/parser/expr/snapshots/trace_dangling_colons.snap new file mode 100644 index 00000000..87a82c3e --- /dev/null +++ b/crates/aiken-lang/src/parser/expr/snapshots/trace_dangling_colons.snap @@ -0,0 +1,72 @@ +--- +source: crates/aiken-lang/src/parser/expr/fail_todo_trace.rs +description: "Invalid code (parse error):\n\nlet debug = fn() {\n trace \"foo\":\n}\n" +--- +[ + ParseError { + kind: Unexpected( + Token( + RightBrace, + ), + ), + span: 34..35, + while_parsing: None, + expected: { + Token( + If, + ), + Token( + Expect, + ), + Token( + Minus, + ), + Token( + When, + ), + Token( + And, + ), + Token( + Or, + ), + Token( + LeftParen, + ), + Token( + Todo, + ), + Token( + LeftSquare, + ), + Token( + NewLineMinus, + ), + Token( + Bang, + ), + Token( + Fail, + ), + Token( + NewLineLeftParen, + ), + Token( + LeftBrace, + ), + Token( + Trace, + ), + Token( + Let, + ), + Token( + Hash, + ), + Token( + Fn, + ), + }, + label: None, + }, +] diff --git a/crates/aiken-lang/src/parser/expr/snapshots/trace_expr_todo.snap b/crates/aiken-lang/src/parser/expr/snapshots/trace_expr_todo.snap index ae65d4df..32b3ea26 100644 --- a/crates/aiken-lang/src/parser/expr/snapshots/trace_expr_todo.snap +++ b/crates/aiken-lang/src/parser/expr/snapshots/trace_expr_todo.snap @@ -5,17 +5,9 @@ description: "Code:\n\ntrace some_var\n" Trace { kind: Trace, location: 0..14, - then: Trace { - kind: Todo, + then: Var { location: 0..14, - then: ErrorTerm { - location: 0..14, - }, - label: String { - location: 0..14, - value: "aiken::todo", - }, - arguments: [], + name: "Void", }, label: Var { location: 6..14, diff --git a/crates/aiken-lang/src/parser/expr/snapshots/trace_labelled.snap b/crates/aiken-lang/src/parser/expr/snapshots/trace_labelled.snap index 3af8fa07..2deadaf9 100644 --- a/crates/aiken-lang/src/parser/expr/snapshots/trace_labelled.snap +++ b/crates/aiken-lang/src/parser/expr/snapshots/trace_labelled.snap @@ -5,17 +5,9 @@ description: "Code:\n\ntrace foo: \"bar\"\n" Trace { kind: Trace, location: 0..16, - then: Trace { - kind: Todo, + then: Var { location: 0..16, - then: ErrorTerm { - location: 0..16, - }, - label: String { - location: 0..16, - value: "aiken::todo", - }, - arguments: [], + name: "Void", }, label: Var { location: 6..9, diff --git a/crates/aiken-lang/src/parser/expr/snapshots/trace_variadic.snap b/crates/aiken-lang/src/parser/expr/snapshots/trace_variadic.snap index 71ee7150..721f7493 100644 --- a/crates/aiken-lang/src/parser/expr/snapshots/trace_variadic.snap +++ b/crates/aiken-lang/src/parser/expr/snapshots/trace_variadic.snap @@ -5,17 +5,9 @@ description: "Code:\n\ntrace \"foo\": @\"bar\", baz\n" Trace { kind: Trace, location: 0..24, - then: Trace { - kind: Todo, + then: Var { location: 0..24, - then: ErrorTerm { - location: 0..24, - }, - label: String { - location: 0..24, - value: "aiken::todo", - }, - arguments: [], + name: "Void", }, label: String { location: 6..11, diff --git a/crates/aiken-lang/src/tests/check.rs b/crates/aiken-lang/src/tests/check.rs index 8655bb8d..9410b801 100644 --- a/crates/aiken-lang/src/tests/check.rs +++ b/crates/aiken-lang/src/tests/check.rs @@ -3332,6 +3332,22 @@ fn dangling_let_in_block() { ) } +#[test] +fn default_trace_return() { + let source_code = r#" + fn debug() { + trace @"patate": Void + } + + test foo() { + debug() + True + } + "#; + + assert!(matches!(check_validator(parse(source_code)), Ok(..))) +} + #[test] fn dangling_trace_let_standalone() { let source_code = r#"