diff --git a/PLAN.md b/PLAN.md index e4bccf0..63ce27e 100644 --- a/PLAN.md +++ b/PLAN.md @@ -3,7 +3,7 @@ A Rust-flavored, C-targeting language - built pipeline-first. **Implementation language:** Rust -**Code generation target:** x86-64 (AT&T / Intel syntax `.s` → assembled via GAS or NASM) +**Code generation target:** Native object files (`.o`) via Cranelift JIT/AOT ## Phase 1 - Lexer @@ -25,23 +25,25 @@ A Rust-flavored, C-targeting language - built pipeline-first. ## Phase 3 - Semantic Analysis -- [ ] Implement scope-aware symbol table -- [ ] Name resolution pass - resolve all `Ident` nodes to their declarations -- [ ] Type inference / checking for `int` and `bool` -- [ ] Validate function return types match declared signature -- [ ] Error on use-before-declaration and undeclared symbols -- [ ] Unit-test: ill-typed programs produce correct diagnostics +- [x] Implement scope-aware symbol table (environment) +- [x] Name resolution pass - resolve all `Ident` nodes to their declarations +- [x] Hindley-Milner type inference (unification, type variables, occurs check) +- [x] Integer literal sizing and unary minus type promotion logic +- [x] Translate untyped AST directly into a fully-typed AST (Typed AST) +- [x] Validate function return types match declared signature +- [x] Error on use-before-declaration, undeclared symbols, and type mismatches +- [x] Unit-test: HM unification, type mappings, and ill-typed program diagnostics -## Phase 4 - x86-64 Code Generation +## Phase 4 - Code Generation via Cranelift -- [ ] Design a simple intermediate representation (linear IR, or use AST directly) -- [ ] Implement stack-frame layout for local variables -- [ ] Emit System V AMD64 ABI-compliant function prologues / epilogues -- [ ] Codegen for arithmetic & comparison expressions -- [ ] Codegen for function calls (argument passing via registers) -- [ ] Codegen for `return` statements -- [ ] Output `.s` file, assemble with NASM / GAS -- [ ] End-to-end test: compile a simple `fn` → run → correct exit code +- [x] Integrate `cranelift-codegen`, `cranelift-frontend`, and `cranelift-object` +- [x] Implement CLI with `clap` (`--emit-ir` flag, input/output files) +- [x] Map Typed AST types (`Ty`) to Cranelift IR types +- [x] Lower functions, parameters, and variable definitions to Cranelift IR +- [x] Codegen for arithmetic, unary operations, and `return` statements +- [x] Run built-in optimization passes (constant folding, e-graphs, DCE) +- [x] Output System V AMD64 ABI-compliant `.o` machine code files +- [x] End-to-end test: compile a simple `fn` → link via `gcc` → run → correct exit code ## Planned Features (Backlog) diff --git a/e2e.sh b/e2e.sh new file mode 100755 index 0000000..301d57a --- /dev/null +++ b/e2e.sh @@ -0,0 +1,56 @@ +#!/bin/bash + +# Exit immediately if a command exits with a non-zero status. +set -e + +# --- Helper Function --- +run_test() { + local src_file="$1" + local expected_code="$2" + local base_name + base_name=$(basename "$src_file" .src) + local obj_file="tests/$base_name.o" + local exec_file="tests/$base_name" + + echo "--- Running test: $src_file ---" + + # 1. Compile the source file using our compiler + echo " [1/4] Compiling..." + cargo run --release -- "$src_file" -o "$obj_file" > /dev/null 2>&1 + + # 2. Link the object file with the system linker (gcc) + echo " [2/4] Linking with gcc..." + gcc "$obj_file" -o "$exec_file" + + # 3. Run the executable + echo " [3/4] Running..." + set +e + ./"$exec_file" + local actual_code=$? + set -e + + # 4. Check the exit code + echo " [4/4] Verifying exit code..." + if [ "$actual_code" -eq "$expected_code" ]; then + echo "SUCCESS: Exit code is $actual_code as expected." + else + echo "FAILURE: Expected exit code $expected_code, but got $actual_code." + exit 1 + fi + + # Clean up generated files + rm "$obj_file" "$exec_file" + echo "------------------------------------" + echo +} + +# --- Test Cases --- + +# Test a simple positive return value. +run_test "tests/return_42.src" 42 + +# Test a negative return value. Shell exit codes are unsigned 8-bit integers, +# so -69 (i8) wraps around to 187. +run_test "tests/return_neg_69.src" 187 + +echo "All end-to-end tests passed!" \ No newline at end of file diff --git a/tests/return_42.src b/tests/return_42.src new file mode 100644 index 0000000..f356e2d --- /dev/null +++ b/tests/return_42.src @@ -0,0 +1,3 @@ +fn main() -> i32 { + return 42; +} \ No newline at end of file diff --git a/tests/return_neg_69.src b/tests/return_neg_69.src new file mode 100644 index 0000000..2eaeebc --- /dev/null +++ b/tests/return_neg_69.src @@ -0,0 +1,3 @@ +fn main() -> i8 { + return -69; +} \ No newline at end of file