From 3c0e4ffbf987be32de9b2c477cdc5ac2d689dc37 Mon Sep 17 00:00:00 2001 From: "Jonathan D.A. Jewell" <6759885+hyperpolymath@users.noreply.github.com> Date: Fri, 17 Apr 2026 01:48:59 +0100 Subject: [PATCH] feat(codegen): implement bitwise NOT and constant folding; fix .as legacy refs --- .build/justfile | 8 +- .../invalid/001_unclosed_brace.expected | 2 +- .../invalid/002_unclosed_string.expected | 2 +- conformance/invalid/003_bad_number.expected | 2 +- .../invalid/004_unexpected_token.expected | 2 +- .../invalid/005_missing_arrow.expected | 2 +- conformance/invalid/006_bad_operator.expected | 2 +- .../invalid/007_incomplete_effect.expected | 2 +- .../invalid/008_mismatched_parens.expected | 2 +- .../invalid/009_reserved_keyword.expected | 2 +- conformance/invalid/010_empty_match.expected | 2 +- conformance/invalid/011_bad_escape.expected | 2 +- .../frontier-programming-practices/AI.a2ml | 2 +- justfile | 4 +- lib/codegen.ml | 2 +- lib/codegen_gc.ml | 8 +- lib/opt.ml | 8 + test/e2e/fixtures/bitwise.affine | 14 ++ test/golden/binary_ops.affine | 8 + test/golden/binary_ops.expected | 200 ++++++++++++++++++ test/test_e2e.ml | 40 ++++ tests/codegen/README.md | 2 +- 22 files changed, 296 insertions(+), 22 deletions(-) create mode 100644 test/e2e/fixtures/bitwise.affine diff --git a/.build/justfile b/.build/justfile index d3dca5a..27c5036 100644 --- a/.build/justfile +++ b/.build/justfile @@ -52,10 +52,10 @@ golden-path: dune build @echo "2. Running tests..." dune runtest - @echo "3. Testing lexer on hello.as..." - dune exec affinescript -- lex examples/hello.as - @echo "4. Testing parser on ownership.as..." - dune exec affinescript -- parse examples/ownership.as + @echo "3. Testing lexer on hello.affine..." + dune exec affinescript -- lex examples/hello.affine + @echo "4. Testing parser on ownership.affine..." + dune exec affinescript -- parse examples/ownership.affine @echo "=== Golden Path Complete ===" # Prepare a release diff --git a/conformance/invalid/001_unclosed_brace.expected b/conformance/invalid/001_unclosed_brace.expected index 464aa21..a1c5e71 100644 --- a/conformance/invalid/001_unclosed_brace.expected +++ b/conformance/invalid/001_unclosed_brace.expected @@ -2,7 +2,7 @@ # Exit code: 1 # Error pattern: unexpected end of file or missing '}' error[E0002]: Parse error: unexpected end of input - --> conformance/invalid/001_unclosed_brace.as:5:1 + --> conformance/invalid/001_unclosed_brace.affine:5:1 | 5 | // Missing closing brace | ^ expected '}' diff --git a/conformance/invalid/002_unclosed_string.expected b/conformance/invalid/002_unclosed_string.expected index 2744779..e3a426a 100644 --- a/conformance/invalid/002_unclosed_string.expected +++ b/conformance/invalid/002_unclosed_string.expected @@ -2,7 +2,7 @@ # Exit code: 1 # Error pattern: unterminated string literal error[E0001]: Lexical error: unterminated string literal - --> conformance/invalid/002_unclosed_string.as:4:11 + --> conformance/invalid/002_unclosed_string.affine:4:11 | 4 | let s = "hello world | ^ string literal not closed diff --git a/conformance/invalid/003_bad_number.expected b/conformance/invalid/003_bad_number.expected index edd60c1..115cfe0 100644 --- a/conformance/invalid/003_bad_number.expected +++ b/conformance/invalid/003_bad_number.expected @@ -2,7 +2,7 @@ # Exit code: 1 # Error pattern: invalid hexadecimal literal error[E0001]: Lexical error: invalid hexadecimal literal - --> conformance/invalid/003_bad_number.as:4:11 + --> conformance/invalid/003_bad_number.affine:4:11 | 4 | let x = 0xGHI; | ^^^^^ invalid hex digit 'G' diff --git a/conformance/invalid/004_unexpected_token.expected b/conformance/invalid/004_unexpected_token.expected index 4ad0d7a..0639d39 100644 --- a/conformance/invalid/004_unexpected_token.expected +++ b/conformance/invalid/004_unexpected_token.expected @@ -2,7 +2,7 @@ # Exit code: 1 # Error pattern: expected identifier error[E0002]: Parse error: expected identifier - --> conformance/invalid/004_unexpected_token.as:4:7 + --> conformance/invalid/004_unexpected_token.affine:4:7 | 4 | let = 42; | ^ expected identifier, found '=' diff --git a/conformance/invalid/005_missing_arrow.expected b/conformance/invalid/005_missing_arrow.expected index a2b4ad2..3816ef5 100644 --- a/conformance/invalid/005_missing_arrow.expected +++ b/conformance/invalid/005_missing_arrow.expected @@ -2,7 +2,7 @@ # Exit code: 1 # Error pattern: expected '->' error[E0002]: Parse error: expected '->' - --> conformance/invalid/005_missing_arrow.as:3:10 + --> conformance/invalid/005_missing_arrow.affine:3:10 | 3 | fn test() Int { | ^ expected '->', found identifier diff --git a/conformance/invalid/006_bad_operator.expected b/conformance/invalid/006_bad_operator.expected index c220605..9c3c01c 100644 --- a/conformance/invalid/006_bad_operator.expected +++ b/conformance/invalid/006_bad_operator.expected @@ -2,7 +2,7 @@ # Exit code: 1 # Error pattern: unknown operator or unexpected character error[E0001]: Lexical error: unexpected character - --> conformance/invalid/006_bad_operator.as:4:15 + --> conformance/invalid/006_bad_operator.affine:4:15 | 4 | let x = 1 @@ 2; | ^ unexpected '@' diff --git a/conformance/invalid/007_incomplete_effect.expected b/conformance/invalid/007_incomplete_effect.expected index 4f7a8ed..6300107 100644 --- a/conformance/invalid/007_incomplete_effect.expected +++ b/conformance/invalid/007_incomplete_effect.expected @@ -2,7 +2,7 @@ # Exit code: 1 # Error pattern: unexpected end of file or missing '}' error[E0002]: Parse error: unexpected end of input - --> conformance/invalid/007_incomplete_effect.as:4:28 + --> conformance/invalid/007_incomplete_effect.affine:4:28 | 4 | fn missing_return_type(); | ^ expected '}', found end of file diff --git a/conformance/invalid/008_mismatched_parens.expected b/conformance/invalid/008_mismatched_parens.expected index cff905a..ff914c7 100644 --- a/conformance/invalid/008_mismatched_parens.expected +++ b/conformance/invalid/008_mismatched_parens.expected @@ -2,7 +2,7 @@ # Exit code: 1 # Error pattern: expected ')' error[E0002]: Parse error: expected ')' - --> conformance/invalid/008_mismatched_parens.as:4:16 + --> conformance/invalid/008_mismatched_parens.affine:4:16 | 4 | let x = (1 + 2; | ^ expected ')', found ';' diff --git a/conformance/invalid/009_reserved_keyword.expected b/conformance/invalid/009_reserved_keyword.expected index b60c4a9..5394d26 100644 --- a/conformance/invalid/009_reserved_keyword.expected +++ b/conformance/invalid/009_reserved_keyword.expected @@ -2,7 +2,7 @@ # Exit code: 1 # Error pattern: expected identifier, found keyword error[E0002]: Parse error: expected identifier - --> conformance/invalid/009_reserved_keyword.as:4:7 + --> conformance/invalid/009_reserved_keyword.affine:4:7 | 4 | let fn = 42; | ^^ expected identifier, found keyword 'fn' diff --git a/conformance/invalid/010_empty_match.expected b/conformance/invalid/010_empty_match.expected index 5b2fb5e..9cce3d5 100644 --- a/conformance/invalid/010_empty_match.expected +++ b/conformance/invalid/010_empty_match.expected @@ -2,7 +2,7 @@ # Exit code: 1 # Error pattern: expected at least one match arm error[E0002]: Parse error: expected pattern - --> conformance/invalid/010_empty_match.as:5:3 + --> conformance/invalid/010_empty_match.affine:5:3 | 5 | } | ^ match expression requires at least one arm diff --git a/conformance/invalid/011_bad_escape.expected b/conformance/invalid/011_bad_escape.expected index 4850bed..bf1a9a7 100644 --- a/conformance/invalid/011_bad_escape.expected +++ b/conformance/invalid/011_bad_escape.expected @@ -2,7 +2,7 @@ # Exit code: 1 # Error pattern: invalid escape sequence error[E0001]: Lexical error: invalid escape sequence '\q' - --> conformance/invalid/011_bad_escape.as:4:16 + --> conformance/invalid/011_bad_escape.affine:4:16 | 4 | let s = "bad \q escape"; | ^^ unknown escape sequence diff --git a/docs/guides/frontier-programming-practices/AI.a2ml b/docs/guides/frontier-programming-practices/AI.a2ml index f3f2a4a..14e0749 100644 --- a/docs/guides/frontier-programming-practices/AI.a2ml +++ b/docs/guides/frontier-programming-practices/AI.a2ml @@ -68,7 +68,7 @@ (compile-target (primary "typed-wasm") (secondary "julia") - (rule "AffineScript is a compiled language. Its semantics live in .as source and compiled output. Do not rewrite .as source in another language as a shortcut for refactoring, modularization, or 'improvement'.")) + (rule "AffineScript is a compiled language. Its semantics live in .affine source and compiled output. Do not rewrite .affine source in another language as a shortcut for refactoring, modularization, or 'improvement'.")) (modularization (rule "When asked to modularize or clean up code, operate within AffineScript using the module system, record decomposition (row polymorphism), and phantom type parameters. Do not create new compiler features to solve user-code modularization problems.")) diff --git a/justfile b/justfile index 05bcb6d..97ea50d 100644 --- a/justfile +++ b/justfile @@ -89,9 +89,9 @@ golden-path: @echo "2. Running tests..." dune runtest @echo "3. Lexer smoke test..." - dune exec affinescript -- lex examples/hello.affine 2>/dev/null || dune exec affinescript -- lex examples/hello.as 2>/dev/null || echo "(no example file — skip)" + dune exec affinescript -- lex examples/hello.affine 2>/dev/null || dune exec affinescript -- lex examples/hello.affine 2>/dev/null || echo "(no example file — skip)" @echo "4. Ownership smoke test..." - dune exec affinescript -- parse examples/ownership.affine 2>/dev/null || dune exec affinescript -- parse examples/ownership.as 2>/dev/null || echo "(no ownership example — skip)" + dune exec affinescript -- parse examples/ownership.affine 2>/dev/null || dune exec affinescript -- parse examples/ownership.affine 2>/dev/null || echo "(no ownership example — skip)" @echo "=== Golden Path Complete ===" # Run panic-attack security scan diff --git a/lib/codegen.ml b/lib/codegen.ml index 57145bc..d3b0ab4 100644 --- a/lib/codegen.ml +++ b/lib/codegen.ml @@ -385,7 +385,7 @@ let gen_unop (op : unary_op) : instr result = match op with | OpNeg -> Ok I32Sub (* 0 - x *) | OpNot -> Ok I32Eqz (* x == 0 *) - | OpBitNot -> Error (UnsupportedFeature "Bitwise NOT") + | OpBitNot -> Ok I32Xor (* -1 ^ x *) | OpRef -> Error (UnsupportedFeature "OpRef handled in ExprUnary") | OpDeref -> Error (UnsupportedFeature "OpDeref handled in ExprUnary") diff --git a/lib/codegen_gc.ml b/lib/codegen_gc.ml index 861c240..66d179b 100644 --- a/lib/codegen_gc.ml +++ b/lib/codegen_gc.ml @@ -334,8 +334,12 @@ let rec gen_gc_expr (ctx : gc_ctx) (expr : expr) : (gc_ctx * gc_instr list) cg_r let* (ctx', code) = gen_gc_expr ctx operand in Ok (ctx', code @ [std Wasm.I32Eqz]) - | ExprUnary (_, operand) -> - gen_gc_expr ctx operand + | ExprUnary (OpBitNot, operand) -> + let* (ctx', code) = gen_gc_expr ctx operand in + Ok (ctx', [push_i32 (-1)] @ code @ [std Wasm.I32Xor]) + + | ExprUnary (op, _operand) -> + Error (UnsupportedFeature (Printf.sprintf "Unary operator %s" (show_unary_op op))) (* ── Function calls ────────────────────────────────────────────── *) diff --git a/lib/opt.ml b/lib/opt.ml index 7737704..5630b7c 100644 --- a/lib/opt.ml +++ b/lib/opt.ml @@ -26,6 +26,11 @@ let rec fold_constants_expr (expr : expr) : expr = | OpLe -> ExprLit (LitBool (a <= b, Span.dummy)) | OpGt -> ExprLit (LitBool (a > b, Span.dummy)) | OpGe -> ExprLit (LitBool (a >= b, Span.dummy)) + | OpBitAnd -> ExprLit (LitInt (a land b, Span.dummy)) + | OpBitOr -> ExprLit (LitInt (a lor b, Span.dummy)) + | OpBitXor -> ExprLit (LitInt (a lxor b, Span.dummy)) + | OpShl -> ExprLit (LitInt (a lsl b, Span.dummy)) + | OpShr -> ExprLit (LitInt (a lsr b, Span.dummy)) | _ -> expr (* Don't fold other ops or division by zero *) end @@ -45,6 +50,9 @@ let rec fold_constants_expr (expr : expr) : expr = | ExprUnary (OpNot, ExprLit (LitBool (b, _))) -> ExprLit (LitBool (not b, Span.dummy)) + | ExprUnary (OpBitNot, ExprLit (LitInt (n, _))) -> + ExprLit (LitInt (lnot n, Span.dummy)) + | ExprBinary (left, op, right) -> let left' = fold_constants_expr left in let right' = fold_constants_expr right in diff --git a/test/e2e/fixtures/bitwise.affine b/test/e2e/fixtures/bitwise.affine new file mode 100644 index 0000000..f0bbe4b --- /dev/null +++ b/test/e2e/fixtures/bitwise.affine @@ -0,0 +1,14 @@ +// SPDX-License-Identifier: PMPL-1.0-or-later +// End-to-end test: bitwise operations +// Tests: parsing, constant folding, WASM codegen, Julia codegen + +fn bit_and(a: Int, b: Int) -> Int = a & b; +fn bit_or(a: Int, b: Int) -> Int = a | b; +fn bit_xor(a: Int, b: Int) -> Int = a ^ b; +fn bit_not(n: Int) -> Int = ~n; +fn bit_shl(a: Int, b: Int) -> Int = a << b; +fn bit_shr(a: Int, b: Int) -> Int = a >> b; + +fn constant_fold_bitwise() -> Int { + (1 & 3) | (4 ^ 6) | (~(-1)) +} diff --git a/test/golden/binary_ops.affine b/test/golden/binary_ops.affine index ef6a0b9..01288b1 100644 --- a/test/golden/binary_ops.affine +++ b/test/golden/binary_ops.affine @@ -6,3 +6,11 @@ fn test_ops() -> Int { fn test_compare() -> Bool { x == y && a < b } + +fn test_bitwise(a: Int, b: Int) -> Int { + (a & b | a ^ b) << 2 >> 1 +} + +fn test_bitwise_not(n: Int) -> Int { + ~n +} diff --git a/test/golden/binary_ops.expected b/test/golden/binary_ops.expected index 61b9f08..c1694ce 100644 --- a/test/golden/binary_ops.expected +++ b/test/golden/binary_ops.expected @@ -126,6 +126,206 @@ )) ))) }) + }); + (Ast.TopFn + { Ast.fd_vis = Ast.Private; fd_total = false; + fd_name = + { Ast.name = "test_bitwise"; + span = + { Span.start_pos = { Span.line = 10; col = 1; offset = 127 }; + end_pos = { Span.line = 10; col = 4; offset = 130 }; + file = "test/golden/binary_ops.affine" } + }; + fd_type_params = []; + fd_params = + [{ Ast.p_quantity = None; p_ownership = None; + p_name = + { Ast.name = "a"; + span = + { Span.start_pos = { Span.line = 10; col = 16; offset = 142 }; + end_pos = { Span.line = 10; col = 17; offset = 143 }; + file = "test/golden/binary_ops.affine" } + }; + p_ty = + (Ast.TyCon + { Ast.name = "Int"; + span = + { Span.start_pos = + { Span.line = 10; col = 18; offset = 144 }; + end_pos = { Span.line = 10; col = 20; offset = 146 }; + file = "test/golden/binary_ops.affine" } + }) + }; + { Ast.p_quantity = None; p_ownership = None; + p_name = + { Ast.name = "b"; + span = + { Span.start_pos = { Span.line = 10; col = 23; offset = 149 }; + end_pos = { Span.line = 10; col = 25; offset = 151 }; + file = "test/golden/binary_ops.affine" } + }; + p_ty = + (Ast.TyCon + { Ast.name = "Int"; + span = + { Span.start_pos = + { Span.line = 10; col = 26; offset = 152 }; + end_pos = { Span.line = 10; col = 28; offset = 154 }; + file = "test/golden/binary_ops.affine" } + }) + } + ]; + fd_ret_ty = + (Some (Ast.TyCon + { Ast.name = "Int"; + span = + { Span.start_pos = + { Span.line = 10; col = 33; offset = 159 }; + end_pos = { Span.line = 10; col = 36; offset = 162 }; + file = "test/golden/binary_ops.affine" } + })); + fd_eff = None; fd_where = []; + fd_body = + (Ast.FnBlock + { Ast.blk_stmts = []; + blk_expr = + (Some (Ast.ExprBinary ( + (Ast.ExprBinary ( + (Ast.ExprBinary ( + (Ast.ExprBinary ( + (Ast.ExprVar + { Ast.name = "a"; + span = + { Span.start_pos = + { Span.line = 11; col = 3; + offset = 170 }; + end_pos = + { Span.line = 11; col = 4; + offset = 171 }; + file = "test/golden/binary_ops.affine" + } + }), + Ast.OpBitAnd, + (Ast.ExprVar + { Ast.name = "b"; + span = + { Span.start_pos = + { Span.line = 11; col = 6; + offset = 173 }; + end_pos = + { Span.line = 11; col = 8; + offset = 175 }; + file = "test/golden/binary_ops.affine" + } + }) + )), + Ast.OpBitOr, + (Ast.ExprBinary ( + (Ast.ExprVar + { Ast.name = "a"; + span = + { Span.start_pos = + { Span.line = 11; col = 10; + offset = 177 }; + end_pos = + { Span.line = 11; col = 12; + offset = 179 }; + file = "test/golden/binary_ops.affine" + } + }), + Ast.OpBitXor, + (Ast.ExprVar + { Ast.name = "b"; + span = + { Span.start_pos = + { Span.line = 11; col = 14; + offset = 181 }; + end_pos = + { Span.line = 11; col = 16; + offset = 183 }; + file = "test/golden/binary_ops.affine" + } + }) + )) + )), + Ast.OpShl, + (Ast.ExprLit + (Ast.LitInt (2, + { Span.start_pos = + { Span.line = 11; col = 19; offset = 186 }; + end_pos = + { Span.line = 11; col = 22; offset = 189 }; + file = "test/golden/binary_ops.affine" } + ))) + )), + Ast.OpShr, + (Ast.ExprLit + (Ast.LitInt (1, + { Span.start_pos = + { Span.line = 11; col = 24; offset = 191 }; + end_pos = + { Span.line = 11; col = 27; offset = 194 }; + file = "test/golden/binary_ops.affine" } + ))) + ))) + }) + }); + (Ast.TopFn + { Ast.fd_vis = Ast.Private; fd_total = false; + fd_name = + { Ast.name = "test_bitwise_not"; + span = + { Span.start_pos = { Span.line = 14; col = 1; offset = 199 }; + end_pos = { Span.line = 14; col = 4; offset = 202 }; + file = "test/golden/binary_ops.affine" } + }; + fd_type_params = []; + fd_params = + [{ Ast.p_quantity = None; p_ownership = None; + p_name = + { Ast.name = "n"; + span = + { Span.start_pos = { Span.line = 14; col = 20; offset = 218 }; + end_pos = { Span.line = 14; col = 21; offset = 219 }; + file = "test/golden/binary_ops.affine" } + }; + p_ty = + (Ast.TyCon + { Ast.name = "Int"; + span = + { Span.start_pos = + { Span.line = 14; col = 22; offset = 220 }; + end_pos = { Span.line = 14; col = 24; offset = 222 }; + file = "test/golden/binary_ops.affine" } + }) + } + ]; + fd_ret_ty = + (Some (Ast.TyCon + { Ast.name = "Int"; + span = + { Span.start_pos = + { Span.line = 14; col = 29; offset = 227 }; + end_pos = { Span.line = 14; col = 32; offset = 230 }; + file = "test/golden/binary_ops.affine" } + })); + fd_eff = None; fd_where = []; + fd_body = + (Ast.FnBlock + { Ast.blk_stmts = []; + blk_expr = + (Some (Ast.ExprUnary (Ast.OpBitNot, + (Ast.ExprVar + { Ast.name = "n"; + span = + { Span.start_pos = + { Span.line = 15; col = 3; offset = 238 }; + end_pos = + { Span.line = 15; col = 4; offset = 239 }; + file = "test/golden/binary_ops.affine" } + }) + ))) + }) }) ] } diff --git a/test/test_e2e.ml b/test/test_e2e.ml index 4e8677b..6dc1e3f 100644 --- a/test/test_e2e.ml +++ b/test/test_e2e.ml @@ -585,6 +585,11 @@ let linear_arrow_tests = [ 3. The binary starts with a valid WASM magic number *) +let test_wasm_bitwise () = + match run_wasm_pipeline (fixture "bitwise.affine") with + | Error msg -> Alcotest.fail msg + | Ok _wasm_mod -> () + let test_wasm_arithmetic () = match run_wasm_pipeline (fixture "arithmetic.affine") with | Error msg -> Alcotest.fail msg @@ -640,6 +645,7 @@ let test_wasm_lambda () = | Ok _wasm_mod -> () let wasm_tests = [ + Alcotest.test_case "bitwise codegen" `Quick test_wasm_bitwise; Alcotest.test_case "arithmetic codegen" `Quick test_wasm_arithmetic; Alcotest.test_case "simple program" `Quick test_wasm_simple; Alcotest.test_case "write binary" `Quick test_wasm_write_binary; @@ -657,6 +663,21 @@ let wasm_tests = [ 3. Function signatures map correctly *) +let test_julia_bitwise () = + match parse_fixture (fixture "bitwise.affine") with + | Error msg -> Alcotest.fail msg + | Ok prog -> + match resolve_program prog with + | Error msg -> Alcotest.fail msg + | Ok (ctx, _) -> + (match julia_codegen prog ctx.symbols with + | Error msg -> Alcotest.fail msg + | Ok code -> + (* Verify it contains Julia bitwise ops *) + Alcotest.(check bool) "contains &" true (String.contains code '&'); + Alcotest.(check bool) "contains |" true (String.contains code '|'); + Alcotest.(check bool) "contains ~" true (String.contains code '~')) + let test_julia_arithmetic () = match run_julia_pipeline (fixture "arithmetic.affine") with | Error msg -> Alcotest.fail msg @@ -708,6 +729,7 @@ let test_julia_full_pipeline () = (String.length code > 0) let julia_tests = [ + Alcotest.test_case "bitwise codegen" `Quick test_julia_bitwise; Alcotest.test_case "arithmetic codegen" `Quick test_julia_arithmetic; Alcotest.test_case "simple program" `Quick test_julia_simple; Alcotest.test_case "type mapping" `Quick test_julia_type_mapping; @@ -729,6 +751,14 @@ let test_interp_simple () = | Error msg -> Alcotest.fail msg | Ok _env -> () +let test_interp_bitwise () = + match parse_fixture (fixture "bitwise.affine") with + | Error msg -> Alcotest.fail msg + | Ok prog -> + (match Interp.eval_program prog with + | Ok _env -> () + | Error e -> Alcotest.fail (Value.show_eval_error e)) + let test_interp_arithmetic () = match run_interp_pipeline (fixture "arithmetic.affine") with | Error msg -> Alcotest.fail msg @@ -746,6 +776,7 @@ let test_interp_full_pipeline () = let interp_tests = [ Alcotest.test_case "simple evaluation" `Quick test_interp_simple; + Alcotest.test_case "bitwise" `Quick test_interp_bitwise; Alcotest.test_case "arithmetic" `Quick test_interp_arithmetic; Alcotest.test_case "lambda" `Quick test_interp_lambda; Alcotest.test_case "full pipeline" `Quick test_interp_full_pipeline; @@ -760,6 +791,14 @@ let interp_tests = [ 2. Optimization preserves semantics (same AST shape for non-constant exprs) *) +let test_opt_bitwise () = + match parse_fixture (fixture "bitwise.affine") with + | Error msg -> Alcotest.fail msg + | Ok prog -> + let _optimized = Opt.fold_constants_program prog in + (* bitwise_constant_fold should be reduced *) + () + let test_opt_constant_folding () = match parse_fixture (fixture "arithmetic.affine") with | Error msg -> Alcotest.fail msg @@ -786,6 +825,7 @@ let test_opt_preserves_semantics () = (Value.show_eval_error e))) let optimizer_tests = [ + Alcotest.test_case "bitwise folding" `Quick test_opt_bitwise; Alcotest.test_case "constant folding" `Quick test_opt_constant_folding; Alcotest.test_case "preserves semantics" `Quick test_opt_preserves_semantics; ] diff --git a/tests/codegen/README.md b/tests/codegen/README.md index c6c24ea..60dd172 100644 --- a/tests/codegen/README.md +++ b/tests/codegen/README.md @@ -11,7 +11,7 @@ From the repo root: ``` The script: -- compiles every `tests/codegen/*.as` file to `tests/codegen/*.wasm` +- compiles every `tests/codegen/*.affine` file to `tests/codegen/*.wasm` - runs any `tests/codegen/*.mjs` harnesses ## Notes