From 25a837ab3fa276a898659c01868fd76852d28504 Mon Sep 17 00:00:00 2001 From: rvcas Date: Fri, 19 Jan 2024 14:32:21 -0500 Subject: [PATCH 1/5] feat: parser and check fixes - do not erase sequences if the sole expression is an assignment - emit parse error if an assignment is assigned to an assignment - do not allow assignments in logical op chains --- CHANGELOG.md | 4 ++ .../src/parser/definition/function.rs | 11 +++++ .../snapshots/function_assignment_only.snap | 44 +++++++++++++++++++ crates/aiken-lang/src/parser/error.rs | 20 +++++++++ .../aiken-lang/src/parser/expr/assignment.rs | 18 +++++--- crates/aiken-lang/src/parser/expr/block.rs | 12 ++++- crates/aiken-lang/src/tipo/expr.rs | 2 + 7 files changed, 105 insertions(+), 6 deletions(-) create mode 100644 crates/aiken-lang/src/parser/definition/snapshots/function_assignment_only.snap diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f91db35..0999f2f0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,10 @@ ### Fixed - **aiken-lang**: Fix flat encoding and decoding of large integer values. @KtorZ +- **aiken-lang**: Traces should not have following expressions formatted into a block. @rvcas +- **aiken-lang**: Sequences should not be erased if the sole expression is an assignment. @rvcas +- **aiken-lang**: Should not be able to assign an assignment to an assignment. @rvcas +- **aiken-lang**: Should not be able to have an assignment in a logical op chain. @rvcas - **aiken**: Ensures that test expected to fail that return `False` are considered to pass & improve error reporting when they fail. @KtorZ ### Removed diff --git a/crates/aiken-lang/src/parser/definition/function.rs b/crates/aiken-lang/src/parser/definition/function.rs index 639f187a..92d8af38 100644 --- a/crates/aiken-lang/src/parser/definition/function.rs +++ b/crates/aiken-lang/src/parser/definition/function.rs @@ -109,4 +109,15 @@ mod tests { "# ); } + + #[test] + fn function_assignment_only() { + assert_definition!( + r#" + fn run() { + let x = 1 + 1 + } + "# + ); + } } diff --git a/crates/aiken-lang/src/parser/definition/snapshots/function_assignment_only.snap b/crates/aiken-lang/src/parser/definition/snapshots/function_assignment_only.snap new file mode 100644 index 00000000..23f7613e --- /dev/null +++ b/crates/aiken-lang/src/parser/definition/snapshots/function_assignment_only.snap @@ -0,0 +1,44 @@ +--- +source: crates/aiken-lang/src/parser/definition/function.rs +description: "Code:\n\nfn run() {\n let x = 1 + 1\n}\n" +--- +Fn( + Function { + arguments: [], + body: Assignment { + location: 13..26, + value: BinOp { + location: 21..26, + name: AddInt, + left: UInt { + location: 21..22, + value: "1", + base: Decimal { + numeric_underscore: false, + }, + }, + right: UInt { + location: 25..26, + value: "1", + base: Decimal { + numeric_underscore: false, + }, + }, + }, + pattern: Var { + location: 17..18, + name: "x", + }, + kind: Let, + annotation: None, + }, + doc: None, + location: 0..8, + name: "run", + public: false, + return_annotation: None, + return_type: (), + end_position: 27, + can_error: true, + }, +) diff --git a/crates/aiken-lang/src/parser/error.rs b/crates/aiken-lang/src/parser/error.rs index 01be9ca2..d51217ff 100644 --- a/crates/aiken-lang/src/parser/error.rs +++ b/crates/aiken-lang/src/parser/error.rs @@ -28,6 +28,16 @@ impl ParseError { self } + pub fn invalid_assignment_right_hand_side(span: Span) -> Self { + Self { + kind: ErrorKind::InvalidAssignmentRightHandSide, + span, + while_parsing: None, + expected: HashSet::new(), + label: Some("invalid assignment right hand side"), + } + } + pub fn invalid_tuple_index(span: Span, index: String, suffix: Option) -> Self { let hint = suffix.map(|suffix| format!("Did you mean '{index}{suffix}'?")); Self { @@ -163,6 +173,16 @@ pub enum ErrorKind { hint: Option, }, + #[error("I discovered an invalid assignment.")] + #[diagnostic( + help( + "{} and {} bindings must be followed by a valid expression.", + "let".if_supports_color(Stdout, |s| s.yellow()), + "expect".if_supports_color(Stdout, |s| s.yellow()), + ), + )] + InvalidAssignmentRightHandSide, + #[error("I tripped over a {}", fmt_curve_type(.curve))] PointNotOnCurve { curve: CurveType }, diff --git a/crates/aiken-lang/src/parser/expr/assignment.rs b/crates/aiken-lang/src/parser/expr/assignment.rs index 7525c569..2ebc6887 100644 --- a/crates/aiken-lang/src/parser/expr/assignment.rs +++ b/crates/aiken-lang/src/parser/expr/assignment.rs @@ -14,15 +14,19 @@ pub fn let_( .then(just(Token::Colon).ignore_then(annotation()).or_not()) .then_ignore(just(Token::Equal)) .then(r.clone()) - .map_with_span( - move |((pattern, annotation), value), span| UntypedExpr::Assignment { + .validate(move |((pattern, annotation), value), span, emit| { + if matches!(value, UntypedExpr::Assignment { .. }) { + emit(ParseError::invalid_assignment_right_hand_side(span)) + } + + UntypedExpr::Assignment { location: span, value: Box::new(value), pattern, kind: ast::AssignmentKind::Let, annotation, - }, - ) + } + }) } pub fn expect( @@ -36,7 +40,7 @@ pub fn expect( .or_not(), ) .then(r.clone()) - .map_with_span(move |(opt_pattern, value), span| { + .validate(move |(opt_pattern, value), span, emit| { let (pattern, annotation) = opt_pattern.unwrap_or_else(|| { ( ast::UntypedPattern::Constructor { @@ -53,6 +57,10 @@ pub fn expect( ) }); + if matches!(value, UntypedExpr::Assignment { .. }) { + emit(ParseError::invalid_assignment_right_hand_side(span)) + } + UntypedExpr::Assignment { location: span, value: Box::new(value), diff --git a/crates/aiken-lang/src/parser/expr/block.rs b/crates/aiken-lang/src/parser/expr/block.rs index 1d4634a9..370536f8 100644 --- a/crates/aiken-lang/src/parser/expr/block.rs +++ b/crates/aiken-lang/src/parser/expr/block.rs @@ -11,7 +11,17 @@ pub fn parser( choice(( sequence .clone() - .delimited_by(just(Token::LeftBrace), just(Token::RightBrace)), + .delimited_by(just(Token::LeftBrace), just(Token::RightBrace)) + .map_with_span(|e, span| { + if matches!(e, UntypedExpr::Assignment { .. }) { + UntypedExpr::Sequence { + location: span, + expressions: vec![e], + } + } else { + e + } + }), sequence.clone().delimited_by( choice((just(Token::LeftParen), just(Token::NewLineLeftParen))), just(Token::RightParen), diff --git a/crates/aiken-lang/src/tipo/expr.rs b/crates/aiken-lang/src/tipo/expr.rs index 693b8257..a3dde5d1 100644 --- a/crates/aiken-lang/src/tipo/expr.rs +++ b/crates/aiken-lang/src/tipo/expr.rs @@ -1650,6 +1650,8 @@ impl<'a, 'b> ExprTyper<'a, 'b> { let mut typed_expressions = vec![]; for expression in expressions { + assert_no_assignment(&expression)?; + let typed_expression = self.infer(expression)?; self.unify( From cb6fd59dbd140a0c64393fd5a796ff2b24a9d4a8 Mon Sep 17 00:00:00 2001 From: Matthias Benkort <5680256+KtorZ@users.noreply.github.com> Date: Sat, 20 Jan 2024 09:58:36 +0100 Subject: [PATCH 2/5] Fix minor typo in error label --- crates/aiken-lang/src/parser/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/aiken-lang/src/parser/error.rs b/crates/aiken-lang/src/parser/error.rs index d51217ff..4c8ff215 100644 --- a/crates/aiken-lang/src/parser/error.rs +++ b/crates/aiken-lang/src/parser/error.rs @@ -34,7 +34,7 @@ impl ParseError { span, while_parsing: None, expected: HashSet::new(), - label: Some("invalid assignment right hand side"), + label: Some("invalid assignment right-hand side"), } } From bf96c3afd268c0fad8654755d3a1bb5d889e97d8 Mon Sep 17 00:00:00 2001 From: KtorZ Date: Sat, 20 Jan 2024 10:26:33 +0100 Subject: [PATCH 3/5] Add more tests & rename 'Invalid' -> 'Unfinished' --- crates/aiken-lang/src/parser/error.rs | 6 +-- .../aiken-lang/src/parser/expr/assignment.rs | 38 +++++++++++++++++ .../expr/snapshots/expect_expect_let.snap | 40 ++++++++++++++++++ .../expr/snapshots/expect_let_in_let.snap | 34 +++++++++++++++ .../snapshots/expect_let_in_let_parens.snap | 15 +++++++ .../snapshots/expect_let_in_let_return.snap | 38 +++++++++++++++++ .../expr/snapshots/expect_unfinished_let.snap | 15 +++++++ crates/aiken-lang/src/parser/utils.rs | 29 +++++++++---- examples/acceptance_tests/092/aiken.lock | 7 ++++ examples/acceptance_tests/092/aiken.toml | 2 + examples/acceptance_tests/092/lib/foo.ak | 41 +++++++++++++++++++ examples/acceptance_tests/092/plutus.json | 39 ++++++++++++++++++ 12 files changed, 293 insertions(+), 11 deletions(-) create mode 100644 crates/aiken-lang/src/parser/expr/snapshots/expect_expect_let.snap create mode 100644 crates/aiken-lang/src/parser/expr/snapshots/expect_let_in_let.snap create mode 100644 crates/aiken-lang/src/parser/expr/snapshots/expect_let_in_let_parens.snap create mode 100644 crates/aiken-lang/src/parser/expr/snapshots/expect_let_in_let_return.snap create mode 100644 crates/aiken-lang/src/parser/expr/snapshots/expect_unfinished_let.snap create mode 100644 examples/acceptance_tests/092/aiken.lock create mode 100644 examples/acceptance_tests/092/aiken.toml create mode 100644 examples/acceptance_tests/092/lib/foo.ak create mode 100644 examples/acceptance_tests/092/plutus.json diff --git a/crates/aiken-lang/src/parser/error.rs b/crates/aiken-lang/src/parser/error.rs index 4c8ff215..9308ca42 100644 --- a/crates/aiken-lang/src/parser/error.rs +++ b/crates/aiken-lang/src/parser/error.rs @@ -30,7 +30,7 @@ impl ParseError { pub fn invalid_assignment_right_hand_side(span: Span) -> Self { Self { - kind: ErrorKind::InvalidAssignmentRightHandSide, + kind: ErrorKind::UnfinishedAssignmentRightHandSide, span, while_parsing: None, expected: HashSet::new(), @@ -173,7 +173,7 @@ pub enum ErrorKind { hint: Option, }, - #[error("I discovered an invalid assignment.")] + #[error("I discovered an unfinished assignment.")] #[diagnostic( help( "{} and {} bindings must be followed by a valid expression.", @@ -181,7 +181,7 @@ pub enum ErrorKind { "expect".if_supports_color(Stdout, |s| s.yellow()), ), )] - InvalidAssignmentRightHandSide, + UnfinishedAssignmentRightHandSide, #[error("I tripped over a {}", fmt_curve_type(.curve))] PointNotOnCurve { curve: CurveType }, diff --git a/crates/aiken-lang/src/parser/expr/assignment.rs b/crates/aiken-lang/src/parser/expr/assignment.rs index 2ebc6887..30f8fbf5 100644 --- a/crates/aiken-lang/src/parser/expr/assignment.rs +++ b/crates/aiken-lang/src/parser/expr/assignment.rs @@ -94,4 +94,42 @@ mod tests { fn expect_trace_if_false() { assert_expr!("expect foo?"); } + + #[test] + fn expect_unfinished_let() { + assert_expr!( + " + let a = + // foo + let b = 42 + " + ); + } + + #[test] + fn expect_let_in_let() { + assert_expr!("let a = { let b = 42 }"); + } + + #[test] + fn expect_let_in_let_return() { + assert_expr!( + " + let a = { + let b = 42 + b + } + " + ); + } + + #[test] + fn expect_let_in_let_parens() { + assert_expr!("let a = ( let b = 42 )"); + } + + #[test] + fn expect_expect_let() { + assert_expr!("expect { let a = 42 } = foo"); + } } diff --git a/crates/aiken-lang/src/parser/expr/snapshots/expect_expect_let.snap b/crates/aiken-lang/src/parser/expr/snapshots/expect_expect_let.snap new file mode 100644 index 00000000..2f2b1431 --- /dev/null +++ b/crates/aiken-lang/src/parser/expr/snapshots/expect_expect_let.snap @@ -0,0 +1,40 @@ +--- +source: crates/aiken-lang/src/parser/expr/assignment.rs +description: "Code:\n\nexpect { let a = 42 } = foo" +--- +Assignment { + location: 0..21, + value: Sequence { + location: 7..21, + expressions: [ + Assignment { + location: 9..19, + value: UInt { + location: 17..19, + value: "42", + base: Decimal { + numeric_underscore: false, + }, + }, + pattern: Var { + location: 13..14, + name: "a", + }, + kind: Let, + annotation: None, + }, + ], + }, + pattern: Constructor { + is_record: false, + location: 0..21, + name: "True", + arguments: [], + module: None, + constructor: (), + with_spread: false, + tipo: (), + }, + kind: Expect, + annotation: None, +} diff --git a/crates/aiken-lang/src/parser/expr/snapshots/expect_let_in_let.snap b/crates/aiken-lang/src/parser/expr/snapshots/expect_let_in_let.snap new file mode 100644 index 00000000..feaa148b --- /dev/null +++ b/crates/aiken-lang/src/parser/expr/snapshots/expect_let_in_let.snap @@ -0,0 +1,34 @@ +--- +source: crates/aiken-lang/src/parser/expr/assignment.rs +description: "Code:\n\nlet a = { let b = 42 }" +--- +Assignment { + location: 0..22, + value: Sequence { + location: 8..22, + expressions: [ + Assignment { + location: 10..20, + value: UInt { + location: 18..20, + value: "42", + base: Decimal { + numeric_underscore: false, + }, + }, + pattern: Var { + location: 14..15, + name: "b", + }, + kind: Let, + annotation: None, + }, + ], + }, + pattern: Var { + location: 4..5, + name: "a", + }, + kind: Let, + annotation: None, +} diff --git a/crates/aiken-lang/src/parser/expr/snapshots/expect_let_in_let_parens.snap b/crates/aiken-lang/src/parser/expr/snapshots/expect_let_in_let_parens.snap new file mode 100644 index 00000000..250c033a --- /dev/null +++ b/crates/aiken-lang/src/parser/expr/snapshots/expect_let_in_let_parens.snap @@ -0,0 +1,15 @@ +--- +source: crates/aiken-lang/src/parser/expr/assignment.rs +description: "Invalid code (parse error):\n\nlet a = ( let b = 42 )" +--- +[ + ParseError { + kind: UnfinishedAssignmentRightHandSide, + span: 0..22, + while_parsing: None, + expected: {}, + label: Some( + "invalid assignment right-hand side", + ), + }, +] diff --git a/crates/aiken-lang/src/parser/expr/snapshots/expect_let_in_let_return.snap b/crates/aiken-lang/src/parser/expr/snapshots/expect_let_in_let_return.snap new file mode 100644 index 00000000..0d11cf5f --- /dev/null +++ b/crates/aiken-lang/src/parser/expr/snapshots/expect_let_in_let_return.snap @@ -0,0 +1,38 @@ +--- +source: crates/aiken-lang/src/parser/expr/assignment.rs +description: "Code:\n\nlet a = {\n let b = 42\n b\n}\n" +--- +Assignment { + location: 0..28, + value: Sequence { + location: 12..26, + expressions: [ + Assignment { + location: 12..22, + value: UInt { + location: 20..22, + value: "42", + base: Decimal { + numeric_underscore: false, + }, + }, + pattern: Var { + location: 16..17, + name: "b", + }, + kind: Let, + annotation: None, + }, + Var { + location: 25..26, + name: "b", + }, + ], + }, + pattern: Var { + location: 4..5, + name: "a", + }, + kind: Let, + annotation: None, +} diff --git a/crates/aiken-lang/src/parser/expr/snapshots/expect_unfinished_let.snap b/crates/aiken-lang/src/parser/expr/snapshots/expect_unfinished_let.snap new file mode 100644 index 00000000..2a9b3c48 --- /dev/null +++ b/crates/aiken-lang/src/parser/expr/snapshots/expect_unfinished_let.snap @@ -0,0 +1,15 @@ +--- +source: crates/aiken-lang/src/parser/expr/assignment.rs +description: "Invalid code (parse error):\n\nlet a =\n// foo\nlet b = 42\n" +--- +[ + ParseError { + kind: UnfinishedAssignmentRightHandSide, + span: 0..25, + while_parsing: None, + expected: {}, + label: Some( + "invalid assignment right-hand side", + ), + }, +] diff --git a/crates/aiken-lang/src/parser/utils.rs b/crates/aiken-lang/src/parser/utils.rs index 75d63e92..08853bd4 100644 --- a/crates/aiken-lang/src/parser/utils.rs +++ b/crates/aiken-lang/src/parser/utils.rs @@ -28,15 +28,28 @@ macro_rules! assert_expr { let stream = chumsky::Stream::from_iter($crate::ast::Span::create(tokens.len(), 1), tokens.into_iter()); - let result = $crate::parser::expr::sequence().parse(stream).unwrap(); + let result = $crate::parser::expr::sequence().parse(stream); - insta::with_settings!({ - description => concat!("Code:\n\n", indoc::indoc! { $code }), - prepend_module_to_snapshot => false, - omit_expression => true - }, { - insta::assert_debug_snapshot!(result); - }); + match result { + Ok(expr) => { + insta::with_settings!({ + description => concat!("Code:\n\n", indoc::indoc! { $code }), + prepend_module_to_snapshot => false, + omit_expression => true + }, { + insta::assert_debug_snapshot!(expr); + }) + }, + Err(err) => { + insta::with_settings!({ + description => concat!("Invalid code (parse error):\n\n", indoc::indoc! { $code }), + prepend_module_to_snapshot => false, + omit_expression => true + }, { + insta::assert_debug_snapshot!(err); + }) + } + } }; } diff --git a/examples/acceptance_tests/092/aiken.lock b/examples/acceptance_tests/092/aiken.lock new file mode 100644 index 00000000..6e350cda --- /dev/null +++ b/examples/acceptance_tests/092/aiken.lock @@ -0,0 +1,7 @@ +# This file was generated by Aiken +# You typically do not need to edit this file + +requirements = [] +packages = [] + +[etags] diff --git a/examples/acceptance_tests/092/aiken.toml b/examples/acceptance_tests/092/aiken.toml new file mode 100644 index 00000000..e1606480 --- /dev/null +++ b/examples/acceptance_tests/092/aiken.toml @@ -0,0 +1,2 @@ +name = "aiken-lang/acceptance_test_092" +version = "0.0.0" diff --git a/examples/acceptance_tests/092/lib/foo.ak b/examples/acceptance_tests/092/lib/foo.ak new file mode 100644 index 00000000..81ef9e41 --- /dev/null +++ b/examples/acceptance_tests/092/lib/foo.ak @@ -0,0 +1,41 @@ +test foo_1() { + let a = { + let b = 42 + b + } + + a == 42 +} + +test foo_2() { + expect Some(a) = { + let b = 42 + Some(b) + } + + a == 42 +} + +test foo_3() { + let c = Some(42) + + let a = { + expect Some(b) = c + b + } + + a == 42 +} + +test foo_4() { + let a = { + let b = 2 + let c = { + let d = 14 + d * b + } + c + 14 + } + + a == 42 +} diff --git a/examples/acceptance_tests/092/plutus.json b/examples/acceptance_tests/092/plutus.json new file mode 100644 index 00000000..a6a24507 --- /dev/null +++ b/examples/acceptance_tests/092/plutus.json @@ -0,0 +1,39 @@ +{ + "preamble": { + "title": "aiken-lang/acceptance_test_090", + "version": "0.0.0", + "plutusVersion": "v2", + "compiler": { + "name": "Aiken", + "version": "v1.0.21-alpha+9f263c4" + } + }, + "validators": [ + { + "title": "foo.spend", + "datum": { + "title": "datum", + "schema": { + "$ref": "#/definitions/Int" + } + }, + "redeemer": { + "title": "_redeemer", + "schema": { + "$ref": "#/definitions/Data" + } + }, + "compiledCode": "583f010000322223253330053370e00290487777c9cfdde5c8f27bf4c1637fc55b5eeef7d8c4d9e0d4454967ff7d6e7ee6e242eb60c6318a4c26cac6eb400d5cd1", + "hash": "d18aa035514acb988a34d33fc246420c5b0eca4f3f947ce95e294447" + } + ], + "definitions": { + "Data": { + "title": "Data", + "description": "Any Plutus data." + }, + "Int": { + "dataType": "integer" + } + } +} \ No newline at end of file From 54a1b501387ad81d26d6673aafb46ec7878734f8 Mon Sep 17 00:00:00 2001 From: KtorZ Date: Sat, 20 Jan 2024 10:36:07 +0100 Subject: [PATCH 4/5] Make behavior between curly- and paren-delimited blocks consistent. Note that the formatter rewrite parens-block sequences as curly-block sequences anyway. Albeit weird looking syntax, they are valid nonetheless. I also clarified a bit the hints and description of the 'illegal::return' error as it would mistakenly say 'function' instead of 'block'. --- crates/aiken-lang/src/parser/error.rs | 4 +- crates/aiken-lang/src/parser/expr/block.rs | 22 +++++----- .../snapshots/expect_let_in_let_parens.snap | 41 ++++++++++++++----- crates/aiken-lang/src/tipo/error.rs | 4 +- 4 files changed, 45 insertions(+), 26 deletions(-) diff --git a/crates/aiken-lang/src/parser/error.rs b/crates/aiken-lang/src/parser/error.rs index 9308ca42..0212e042 100644 --- a/crates/aiken-lang/src/parser/error.rs +++ b/crates/aiken-lang/src/parser/error.rs @@ -173,10 +173,10 @@ pub enum ErrorKind { hint: Option, }, - #[error("I discovered an unfinished assignment.")] + #[error("I spotted an unfinished assignment.")] #[diagnostic( help( - "{} and {} bindings must be followed by a valid expression.", + "{} and {} bindings must be followed by a valid, complete, expression.", "let".if_supports_color(Stdout, |s| s.yellow()), "expect".if_supports_color(Stdout, |s| s.yellow()), ), diff --git a/crates/aiken-lang/src/parser/expr/block.rs b/crates/aiken-lang/src/parser/expr/block.rs index 370536f8..ac1db7c8 100644 --- a/crates/aiken-lang/src/parser/expr/block.rs +++ b/crates/aiken-lang/src/parser/expr/block.rs @@ -11,22 +11,22 @@ pub fn parser( choice(( sequence .clone() - .delimited_by(just(Token::LeftBrace), just(Token::RightBrace)) - .map_with_span(|e, span| { - if matches!(e, UntypedExpr::Assignment { .. }) { - UntypedExpr::Sequence { - location: span, - expressions: vec![e], - } - } else { - e - } - }), + .delimited_by(just(Token::LeftBrace), just(Token::RightBrace)), sequence.clone().delimited_by( choice((just(Token::LeftParen), just(Token::NewLineLeftParen))), just(Token::RightParen), ), )) + .map_with_span(|e, span| { + if matches!(e, UntypedExpr::Assignment { .. }) { + UntypedExpr::Sequence { + location: span, + expressions: vec![e], + } + } else { + e + } + }) } #[cfg(test)] diff --git a/crates/aiken-lang/src/parser/expr/snapshots/expect_let_in_let_parens.snap b/crates/aiken-lang/src/parser/expr/snapshots/expect_let_in_let_parens.snap index 250c033a..7ca8ace8 100644 --- a/crates/aiken-lang/src/parser/expr/snapshots/expect_let_in_let_parens.snap +++ b/crates/aiken-lang/src/parser/expr/snapshots/expect_let_in_let_parens.snap @@ -1,15 +1,34 @@ --- source: crates/aiken-lang/src/parser/expr/assignment.rs -description: "Invalid code (parse error):\n\nlet a = ( let b = 42 )" +description: "Code:\n\nlet a = ( let b = 42 )" --- -[ - ParseError { - kind: UnfinishedAssignmentRightHandSide, - span: 0..22, - while_parsing: None, - expected: {}, - label: Some( - "invalid assignment right-hand side", - ), +Assignment { + location: 0..22, + value: Sequence { + location: 8..22, + expressions: [ + Assignment { + location: 10..20, + value: UInt { + location: 18..20, + value: "42", + base: Decimal { + numeric_underscore: false, + }, + }, + pattern: Var { + location: 14..15, + name: "b", + }, + kind: Let, + annotation: None, + }, + ], }, -] + pattern: Var { + location: 4..5, + name: "a", + }, + kind: Let, + annotation: None, +} diff --git a/crates/aiken-lang/src/tipo/error.rs b/crates/aiken-lang/src/tipo/error.rs index 8afd2a73..283efc5e 100644 --- a/crates/aiken-lang/src/tipo/error.rs +++ b/crates/aiken-lang/src/tipo/error.rs @@ -407,10 +407,10 @@ Perhaps, try the following: as, expect, check, const, else, fn, if, is, let, opaque, pub, test, todo, trace, type, use, when"#))] KeywordInModuleName { name: String, keyword: String }, - #[error("I discovered a function which is ending with an assignment.\n")] + #[error("I discovered a block which is ending with an assignment.\n")] #[diagnostic(url("https://aiken-lang.org/language-tour/functions#named-functions"))] #[diagnostic(code("illegal::return"))] - #[diagnostic(help(r#"In Aiken, functions must return an explicit result in the form of an expression. While assignments are technically speaking expressions, they aren't allowed to be the last expression of a function because they convey a different meaning and this could be error-prone. + #[diagnostic(help(r#"In Aiken, code blocks (such as function bodies) must return an explicit result in the form of an expression. While assignments are technically speaking expressions, they aren't allowed to be the last expression of a function because they convey a different meaning and this could be error-prone. If you really meant to return that last expression, try to replace it with the following: From 50ebfc609050710071de4ee566cfa90d7c25ece7 Mon Sep 17 00:00:00 2001 From: KtorZ Date: Sat, 20 Jan 2024 10:38:40 +0100 Subject: [PATCH 5/5] remove wrongly committed acceptance test blueprints Actually copy-pasted from 090 --- examples/acceptance_tests/091/plutus.json | 39 ----------------------- examples/acceptance_tests/092/plutus.json | 39 ----------------------- 2 files changed, 78 deletions(-) delete mode 100644 examples/acceptance_tests/091/plutus.json delete mode 100644 examples/acceptance_tests/092/plutus.json diff --git a/examples/acceptance_tests/091/plutus.json b/examples/acceptance_tests/091/plutus.json deleted file mode 100644 index a6a24507..00000000 --- a/examples/acceptance_tests/091/plutus.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "preamble": { - "title": "aiken-lang/acceptance_test_090", - "version": "0.0.0", - "plutusVersion": "v2", - "compiler": { - "name": "Aiken", - "version": "v1.0.21-alpha+9f263c4" - } - }, - "validators": [ - { - "title": "foo.spend", - "datum": { - "title": "datum", - "schema": { - "$ref": "#/definitions/Int" - } - }, - "redeemer": { - "title": "_redeemer", - "schema": { - "$ref": "#/definitions/Data" - } - }, - "compiledCode": "583f010000322223253330053370e00290487777c9cfdde5c8f27bf4c1637fc55b5eeef7d8c4d9e0d4454967ff7d6e7ee6e242eb60c6318a4c26cac6eb400d5cd1", - "hash": "d18aa035514acb988a34d33fc246420c5b0eca4f3f947ce95e294447" - } - ], - "definitions": { - "Data": { - "title": "Data", - "description": "Any Plutus data." - }, - "Int": { - "dataType": "integer" - } - } -} \ No newline at end of file diff --git a/examples/acceptance_tests/092/plutus.json b/examples/acceptance_tests/092/plutus.json deleted file mode 100644 index a6a24507..00000000 --- a/examples/acceptance_tests/092/plutus.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "preamble": { - "title": "aiken-lang/acceptance_test_090", - "version": "0.0.0", - "plutusVersion": "v2", - "compiler": { - "name": "Aiken", - "version": "v1.0.21-alpha+9f263c4" - } - }, - "validators": [ - { - "title": "foo.spend", - "datum": { - "title": "datum", - "schema": { - "$ref": "#/definitions/Int" - } - }, - "redeemer": { - "title": "_redeemer", - "schema": { - "$ref": "#/definitions/Data" - } - }, - "compiledCode": "583f010000322223253330053370e00290487777c9cfdde5c8f27bf4c1637fc55b5eeef7d8c4d9e0d4454967ff7d6e7ee6e242eb60c6318a4c26cac6eb400d5cd1", - "hash": "d18aa035514acb988a34d33fc246420c5b0eca4f3f947ce95e294447" - } - ], - "definitions": { - "Data": { - "title": "Data", - "description": "Any Plutus data." - }, - "Int": { - "dataType": "integer" - } - } -} \ No newline at end of file