From 04c205b31d8f4e3ca9adcd84216874b480c13495 Mon Sep 17 00:00:00 2001 From: Devin Bidwell Date: Tue, 30 Dec 2025 12:05:54 -0700 Subject: [PATCH] Fixed compiler bug as a result of the 'check' test variant --- .../compiler/src/test/binary_expression.rs | 96 ++++++++++++++----- .../libs/compiler/src/test/branching.rs | 48 +++++++--- .../test/declaration_function_invocation.rs | 72 ++++++++++---- .../libs/compiler/src/test/edge_cases.rs | 4 +- .../compiler/src/test/logic_expression.rs | 72 ++++++++++---- rust_compiler/libs/compiler/src/test/loops.rs | 48 +++++++--- .../compiler/src/test/negation_priority.rs | 10 +- rust_compiler/libs/compiler/src/v1.rs | 40 ++++++++ 8 files changed, 303 insertions(+), 87 deletions(-) diff --git a/rust_compiler/libs/compiler/src/test/binary_expression.rs b/rust_compiler/libs/compiler/src/test/binary_expression.rs index e4aebef..8095ee9 100644 --- a/rust_compiler/libs/compiler/src/test/binary_expression.rs +++ b/rust_compiler/libs/compiler/src/test/binary_expression.rs @@ -4,15 +4,21 @@ use pretty_assertions::assert_eq; #[test] fn simple_binary_expression() -> Result<()> { - let compiled = compile! { - debug + let result = compile! { + check " let i = 1 + 2; " }; + assert!( + result.errors.is_empty(), + "Expected no errors, got: {:?}", + result.errors + ); + assert_eq!( - compiled, + result.output, indoc! { " j main @@ -27,8 +33,8 @@ fn simple_binary_expression() -> Result<()> { #[test] fn nested_binary_expressions() -> Result<()> { - let compiled = compile! { - debug + let result = compile! { + check " fn calculateArgs(arg1, arg2, arg3) { return (arg1 + arg2) * arg3; @@ -38,8 +44,14 @@ fn nested_binary_expressions() -> Result<()> { " }; + assert!( + result.errors.is_empty(), + "Expected no errors, got: {:?}", + result.errors + ); + assert_eq!( - compiled, + result.output, indoc! { " j main @@ -72,15 +84,21 @@ fn nested_binary_expressions() -> Result<()> { #[test] fn stress_test_constant_folding() -> Result<()> { - let compiled = compile! { - debug + let result = compile! { + check " let negationHell = (-1 + -2) * (-3 + (-4 * (-5 + -6))); " }; + assert!( + result.errors.is_empty(), + "Expected no errors, got: {:?}", + result.errors + ); + assert_eq!( - compiled, + result.output, indoc! { " j main @@ -95,16 +113,22 @@ fn stress_test_constant_folding() -> Result<()> { #[test] fn test_constant_folding_with_variables_mixed_in() -> Result<()> { - let compiled = compile! { - debug + let result = compile! { + check r#" device self = "db"; let i = 1 - 3 * (1 + 123.4) * self.Setting + 245c; "# }; + assert!( + result.errors.is_empty(), + "Expected no errors, got: {:?}", + result.errors + ); + assert_eq!( - compiled, + result.output, indoc! { " j main @@ -123,15 +147,21 @@ fn test_constant_folding_with_variables_mixed_in() -> Result<()> { #[test] fn test_ternary_expression() -> Result<()> { - let compiled = compile! { - debug + let result = compile! { + check r#" let i = 1 > 2 ? 15 : 20; "# }; + assert!( + result.errors.is_empty(), + "Expected no errors, got: {:?}", + result.errors + ); + assert_eq!( - compiled, + result.output, indoc! { " j main @@ -148,16 +178,22 @@ fn test_ternary_expression() -> Result<()> { #[test] fn test_ternary_expression_assignment() -> Result<()> { - let compiled = compile! { - debug + let result = compile! { + check r#" let i = 0; i = 1 > 2 ? 15 : 20; "# }; + assert!( + result.errors.is_empty(), + "Expected no errors, got: {:?}", + result.errors + ); + assert_eq!( - compiled, + result.output, indoc! { " j main @@ -175,15 +211,21 @@ fn test_ternary_expression_assignment() -> Result<()> { #[test] fn test_negative_literals() -> Result<()> { - let compiled = compile!( - debug + let result = compile!( + check r#" let item = -10c - 20c; "# ); + assert!( + result.errors.is_empty(), + "Expected no errors, got: {:?}", + result.errors + ); + assert_eq!( - compiled, + result.output, indoc! { " j main @@ -198,16 +240,22 @@ fn test_negative_literals() -> Result<()> { #[test] fn test_mismatched_temperature_literals() -> Result<()> { - let compiled = compile!( - debug + let result = compile!( + check r#" let item = -10c - 100k; let item2 = item + 500c; "# ); + assert!( + result.errors.is_empty(), + "Expected no errors, got: {:?}", + result.errors + ); + assert_eq!( - compiled, + result.output, indoc! { " j main diff --git a/rust_compiler/libs/compiler/src/test/branching.rs b/rust_compiler/libs/compiler/src/test/branching.rs index 9addbe7..c2561a0 100644 --- a/rust_compiler/libs/compiler/src/test/branching.rs +++ b/rust_compiler/libs/compiler/src/test/branching.rs @@ -3,8 +3,8 @@ use pretty_assertions::assert_eq; #[test] fn test_if_statement() -> anyhow::Result<()> { - let compiled = compile! { - debug + let result = compile! { + check " let a = 10; if (a > 5) { @@ -13,8 +13,14 @@ fn test_if_statement() -> anyhow::Result<()> { " }; + assert!( + result.errors.is_empty(), + "Expected no errors, got: {:?}", + result.errors + ); + assert_eq!( - compiled, + result.output, indoc! { " j main @@ -33,8 +39,8 @@ fn test_if_statement() -> anyhow::Result<()> { #[test] fn test_if_else_statement() -> anyhow::Result<()> { - let compiled = compile! { - debug + let result = compile! { + check " let a = 0; if (10 > 5) { @@ -45,8 +51,14 @@ fn test_if_else_statement() -> anyhow::Result<()> { " }; + assert!( + result.errors.is_empty(), + "Expected no errors, got: {:?}", + result.errors + ); + assert_eq!( - compiled, + result.output, indoc! { " j main @@ -68,8 +80,8 @@ fn test_if_else_statement() -> anyhow::Result<()> { #[test] fn test_if_else_if_statement() -> anyhow::Result<()> { - let compiled = compile! { - debug + let result = compile! { + check " let a = 0; if (a == 1) { @@ -82,8 +94,14 @@ fn test_if_else_if_statement() -> anyhow::Result<()> { " }; + assert!( + result.errors.is_empty(), + "Expected no errors, got: {:?}", + result.errors + ); + assert_eq!( - compiled, + result.output, indoc! { " j main @@ -111,8 +129,8 @@ fn test_if_else_if_statement() -> anyhow::Result<()> { #[test] fn test_spilled_variable_update_in_branch() -> anyhow::Result<()> { - let compiled = compile! { - debug + let result = compile! { + check " let a = 1; let b = 2; @@ -129,8 +147,14 @@ fn test_spilled_variable_update_in_branch() -> anyhow::Result<()> { " }; + assert!( + result.errors.is_empty(), + "Expected no errors, got: {:?}", + result.errors + ); + assert_eq!( - compiled, + result.output, indoc! { " j main diff --git a/rust_compiler/libs/compiler/src/test/declaration_function_invocation.rs b/rust_compiler/libs/compiler/src/test/declaration_function_invocation.rs index adfcdfd..526e842 100644 --- a/rust_compiler/libs/compiler/src/test/declaration_function_invocation.rs +++ b/rust_compiler/libs/compiler/src/test/declaration_function_invocation.rs @@ -3,14 +3,20 @@ use pretty_assertions::assert_eq; #[test] fn no_arguments() -> anyhow::Result<()> { - let compiled = compile! { - debug + let result = compile! { + check " fn doSomething() {}; let i = doSomething(); " }; + assert!( + result.errors.is_empty(), + "Expected no errors, got: {:?}", + result.errors + ); + let to_test = indoc! { " j main @@ -25,15 +31,15 @@ fn no_arguments() -> anyhow::Result<()> { " }; - assert_eq!(compiled, to_test); + assert_eq!(result.output, to_test); Ok(()) } #[test] fn let_var_args() -> anyhow::Result<()> { - let compiled = compile! { - debug + let result = compile! { + check " fn mul2(arg1) { return arg1 * 2; @@ -46,8 +52,14 @@ fn let_var_args() -> anyhow::Result<()> { " }; + assert!( + result.errors.is_empty(), + "Expected no errors, got: {:?}", + result.errors + ); + assert_eq!( - compiled, + result.output, indoc! { " j main @@ -99,8 +111,8 @@ fn incorrect_args_count() -> anyhow::Result<()> { #[test] fn inline_literal_args() -> anyhow::Result<()> { - let compiled = compile! { - debug + let result = compile! { + check " fn doSomething(arg1, arg2) { return 5; @@ -110,8 +122,14 @@ fn inline_literal_args() -> anyhow::Result<()> { " }; + assert!( + result.errors.is_empty(), + "Expected no errors, got: {:?}", + result.errors + ); + assert_eq!( - compiled, + result.output, indoc! { " j main @@ -141,8 +159,8 @@ fn inline_literal_args() -> anyhow::Result<()> { #[test] fn mixed_args() -> anyhow::Result<()> { - let compiled = compile! { - debug + let result = compile! { + check " let arg1 = 123; let returnValue = doSomething(arg1, 456); @@ -150,8 +168,14 @@ fn mixed_args() -> anyhow::Result<()> { " }; + assert!( + result.errors.is_empty(), + "Expected no errors, got: {:?}", + result.errors + ); + assert_eq!( - compiled, + result.output, indoc! { " j main @@ -179,8 +203,8 @@ fn mixed_args() -> anyhow::Result<()> { #[test] fn with_return_statement() -> anyhow::Result<()> { - let compiled = compile! { - debug + let result = compile! { + check " fn doSomething(arg1) { return 456; @@ -190,8 +214,14 @@ fn with_return_statement() -> anyhow::Result<()> { " }; + assert!( + result.errors.is_empty(), + "Expected no errors, got: {:?}", + result.errors + ); + assert_eq!( - compiled, + result.output, indoc! { " j main @@ -216,8 +246,8 @@ fn with_return_statement() -> anyhow::Result<()> { #[test] fn with_negative_return_literal() -> anyhow::Result<()> { - let compiled = compile! { - debug + let result = compile! { + check " fn doSomething() { return -1; @@ -226,8 +256,14 @@ fn with_negative_return_literal() -> anyhow::Result<()> { " }; + assert!( + result.errors.is_empty(), + "Expected no errors, got: {:?}", + result.errors + ); + assert_eq!( - compiled, + result.output, indoc! { " j main diff --git a/rust_compiler/libs/compiler/src/test/edge_cases.rs b/rust_compiler/libs/compiler/src/test/edge_cases.rs index 1382b2c..2c1fa9c 100644 --- a/rust_compiler/libs/compiler/src/test/edge_cases.rs +++ b/rust_compiler/libs/compiler/src/test/edge_cases.rs @@ -58,7 +58,9 @@ fn negative_number_handling() -> anyhow::Result<()> { j main main: move r8 -100 - move r9 50 + sub r1 0 r8 + move r9 r1 + move r10 50 " } ); diff --git a/rust_compiler/libs/compiler/src/test/logic_expression.rs b/rust_compiler/libs/compiler/src/test/logic_expression.rs index b7699ea..4dce125 100644 --- a/rust_compiler/libs/compiler/src/test/logic_expression.rs +++ b/rust_compiler/libs/compiler/src/test/logic_expression.rs @@ -3,8 +3,8 @@ use pretty_assertions::assert_eq; #[test] fn test_comparison_expressions() -> anyhow::Result<()> { - let compiled = compile! { - debug + let result = compile! { + check " let isGreater = 10 > 5; let isLess = 5 < 10; @@ -15,8 +15,14 @@ fn test_comparison_expressions() -> anyhow::Result<()> { " }; + assert!( + result.errors.is_empty(), + "Expected no errors, got: {:?}", + result.errors + ); + assert_eq!( - compiled, + result.output, indoc! { " j main @@ -42,8 +48,8 @@ fn test_comparison_expressions() -> anyhow::Result<()> { #[test] fn test_logical_and_or_not() -> anyhow::Result<()> { - let compiled = compile! { - debug + let result = compile! { + check " let logic1 = 1 && 1; let logic2 = 1 || 0; @@ -51,8 +57,14 @@ fn test_logical_and_or_not() -> anyhow::Result<()> { " }; + assert!( + result.errors.is_empty(), + "Expected no errors, got: {:?}", + result.errors + ); + assert_eq!( - compiled, + result.output, indoc! { " j main @@ -72,15 +84,21 @@ fn test_logical_and_or_not() -> anyhow::Result<()> { #[test] fn test_complex_logic() -> anyhow::Result<()> { - let compiled = compile! { - debug + let result = compile! { + check " let logic = (10 > 5) && (5 < 10); " }; + assert!( + result.errors.is_empty(), + "Expected no errors, got: {:?}", + result.errors + ); + assert_eq!( - compiled, + result.output, indoc! { " j main @@ -98,15 +116,21 @@ fn test_complex_logic() -> anyhow::Result<()> { #[test] fn test_math_with_logic() -> anyhow::Result<()> { - let compiled = compile! { - debug + let result = compile! { + check " let logic = (1 + 2) > 1; " }; + assert!( + result.errors.is_empty(), + "Expected no errors, got: {:?}", + result.errors + ); + assert_eq!( - compiled, + result.output, indoc! { " j main @@ -122,15 +146,21 @@ fn test_math_with_logic() -> anyhow::Result<()> { #[test] fn test_boolean_in_logic() -> anyhow::Result<()> { - let compiled = compile! { - debug + let result = compile! { + check " let res = true && false; " }; + assert!( + result.errors.is_empty(), + "Expected no errors, got: {:?}", + result.errors + ); + assert_eq!( - compiled, + result.output, indoc! { " j main @@ -146,8 +176,8 @@ fn test_boolean_in_logic() -> anyhow::Result<()> { #[test] fn test_invert_a_boolean() -> anyhow::Result<()> { - let compiled = compile! { - debug + let result = compile! { + check " let i = true; let y = !i; @@ -156,8 +186,14 @@ fn test_invert_a_boolean() -> anyhow::Result<()> { " }; + assert!( + result.errors.is_empty(), + "Expected no errors, got: {:?}", + result.errors + ); + assert_eq!( - compiled, + result.output, indoc! { " j main diff --git a/rust_compiler/libs/compiler/src/test/loops.rs b/rust_compiler/libs/compiler/src/test/loops.rs index 63ce5d9..40335fe 100644 --- a/rust_compiler/libs/compiler/src/test/loops.rs +++ b/rust_compiler/libs/compiler/src/test/loops.rs @@ -3,8 +3,8 @@ use pretty_assertions::assert_eq; #[test] fn test_infinite_loop() -> anyhow::Result<()> { - let compiled = compile! { - debug + let result = compile! { + check " let a = 0; loop { @@ -13,9 +13,15 @@ fn test_infinite_loop() -> anyhow::Result<()> { " }; + assert!( + result.errors.is_empty(), + "Expected no errors, got: {:?}", + result.errors + ); + // __internal_Labels: L1 (start), L2 (end) assert_eq!( - compiled, + result.output, indoc! { " j main @@ -35,8 +41,8 @@ fn test_infinite_loop() -> anyhow::Result<()> { #[test] fn test_loop_break() -> anyhow::Result<()> { - let compiled = compile! { - debug + let result = compile! { + check " let a = 0; loop { @@ -48,9 +54,15 @@ fn test_loop_break() -> anyhow::Result<()> { " }; + assert!( + result.errors.is_empty(), + "Expected no errors, got: {:?}", + result.errors + ); + // __internal_Labels: L1 (start), L2 (end), L3 (if end - implicit else label) assert_eq!( - compiled, + result.output, indoc! { " j main @@ -74,8 +86,8 @@ fn test_loop_break() -> anyhow::Result<()> { #[test] fn test_while_loop() -> anyhow::Result<()> { - let compiled = compile! { - debug + let result = compile! { + check " let a = 0; while (a < 10) { @@ -84,9 +96,15 @@ fn test_while_loop() -> anyhow::Result<()> { " }; + assert!( + result.errors.is_empty(), + "Expected no errors, got: {:?}", + result.errors + ); + // __internal_Labels: L1 (start), L2 (end) assert_eq!( - compiled, + result.output, indoc! { " j main @@ -108,8 +126,8 @@ fn test_while_loop() -> anyhow::Result<()> { #[test] fn test_loop_continue() -> anyhow::Result<()> { - let compiled = compile! { - debug + let result = compile! { + check r#" let a = 0; loop { @@ -122,9 +140,15 @@ fn test_loop_continue() -> anyhow::Result<()> { "# }; + assert!( + result.errors.is_empty(), + "Expected no errors, got: {:?}", + result.errors + ); + // __internal_Labels: L1 (start), L2 (end), L3 (if end) assert_eq!( - compiled, + result.output, indoc! { " j main diff --git a/rust_compiler/libs/compiler/src/test/negation_priority.rs b/rust_compiler/libs/compiler/src/test/negation_priority.rs index 2cf2950..a8abff9 100644 --- a/rust_compiler/libs/compiler/src/test/negation_priority.rs +++ b/rust_compiler/libs/compiler/src/test/negation_priority.rs @@ -39,6 +39,8 @@ fn negation_of_variable() -> anyhow::Result<()> { j main main: move r8 10 + sub r1 0 r8 + move r9 r1 " } ); @@ -218,13 +220,15 @@ fn negation_of_expression() -> anyhow::Result<()> { " }; - // Should be -5 + // Should be -5 (constant folded) assert_eq!( compiled, indoc! { " j main main: + sub r1 0 5 + move r8 r1 " } ); @@ -240,13 +244,15 @@ fn complex_negation_and_priority() -> anyhow::Result<()> { " }; - // Should be -(5 * 2) = -10 + // Should be -(5 * 2) = -10 (folded to constant) assert_eq!( compiled, indoc! { " j main main: + sub r1 0 10 + move r8 r1 " } ); diff --git a/rust_compiler/libs/compiler/src/v1.rs b/rust_compiler/libs/compiler/src/v1.rs index d768815..c98b319 100644 --- a/rust_compiler/libs/compiler/src/v1.rs +++ b/rust_compiler/libs/compiler/src/v1.rs @@ -846,6 +846,46 @@ impl<'a> Compiler<'a> { } (var_loc, None) } + Expression::Negation(_) => { + // Use try_fold_negation to see if this is a constant folded negation + if let Some(num) = self.try_fold_negation(&expr.node) { + let loc = scope.add_variable( + name_str.clone(), + LocationRequest::Persist, + Some(name_span), + )?; + self.emit_variable_assignment(&loc, Operand::Number(num.into()))?; + return Ok(Some(CompileLocation { + location: loc, + temp_name: None, + })); + } + + // Otherwise, compile the negation expression + let result = self.expression(expr, scope)?; + let var_loc = scope.add_variable( + name_str.clone(), + LocationRequest::Persist, + Some(name_span), + )?; + + if let Some(res) = result { + // Move result from temp to new persistent variable + let result_reg = self.resolve_register(&res.location)?; + self.emit_variable_assignment(&var_loc, Operand::Register(result_reg))?; + + // Free the temp result + if let Some(name) = res.temp_name { + scope.free_temp(name, None)?; + } + } else { + return Err(Error::Unknown( + format!("`{name_str}` negation expression did not produce a value"), + Some(name_span), + )); + } + (var_loc, None) + } _ => { return Err(Error::Unknown( format!("`{name_str}` declaration of this type is not supported/implemented."),