Three implementations of a simple Pascal-like language compiler built on LLVM.
The original implementation using OCaml 5.2 with LLVM OCaml bindings.
- Status: ✅ Complete and tested
- LLVM Bindings: ocaml-llvm 21.1
- Build System: Dune 3.20
- Parser Generator: Menhir
- Tests: 10 automated tests, all passing
Alternative implementation using Rust with Inkwell (safe LLVM bindings).
- Status: ✅ Complete and tested
- LLVM Bindings: Inkwell 0.6 (LLVM 18)
- Build System: Cargo
- Parser: Hand-written recursive descent
- Tests: 10 automated tests, all passing
JVM-based implementation using Scala 3 with fastparse and JavaCPP LLVM bindings.
- Status: ✅ Complete and tested
- LLVM Bindings: JavaCPP llvm-platform 20.1.7
- Build System: SBT 1.10.5
- Parser: fastparse 3.1.1 (parser combinators)
- Tests: 10 automated tests, all passing
All three implementations support the same Pascal-like language:
- Data Types: Integer, Real, Boolean, Char, String
- Composite Types: Arrays, Records (structs), Pointers
- Control Flow: if/then/else, while, for loops
- Functions: Functions and procedures with recursion
- Inline Declarations: Scala-style
var(mutable) andval(immutable) - I/O: Console input/output (writeln, write, readln)
- Pointers: Address-of (@), dereference (^), dynamic allocation (new)
cd ocaml-impl
direnv allow # If using nix
dune build
./compile.sh ../examples/fibonacci.pas fibonacci
./fibonacci # Output: 5cd rust-impl
cargo build --release
cargo run -- ../examples/fibonacci.pas -o fibonacci
./fibonacci # Output: 5cd scala-impl
nix develop # Or use direnv
sbt assembly
./compile.sh ../examples/fibonacci.pas fibonacci
./fibonacci # Output: 5program Fibonacci;
function fib(n: integer): integer;
begin
if n <= 1 then
return n
else
return fib(n-1) + fib(n-2)
end;
function main(): integer;
begin
val result: integer = fib(5);
writeln(result);
return 0
end;
.Both implementations support Scala-style inline declarations:
function demo(): integer;
begin
var counter: integer := 0; (* mutable *)
val max: integer = 100; (* immutable *)
counter := counter + 1; (* OK *)
(* max := 200; *) (* Error: cannot assign to val *)
return counter
end;cd ocaml-impl
./test.shcd rust-impl
cargo testcd scala-impl
./test.sh./test-all.sh # Runs tests for all three implementationsAll implementations use GitHub Actions with Nix for reproducible builds:
- OCaml: Full CI with Determinate Nix Installer (LLVM 21)
- Rust: Full CI with Determinate Nix Installer (LLVM 18)
- Scala: Full CI with Determinate Nix Installer (LLVM 20)
| Feature | OCaml | Rust | Scala |
|---|---|---|---|
| LLVM Bindings | ocaml-llvm 21 | Inkwell 0.6 (LLVM 18) | JavaCPP llvm-platform 20 |
| Parser | Menhir (LALR) | Hand-written | fastparse (combinators) |
| Type Safety | Strong | Strong | Strong |
| Memory Safety | GC | Ownership | GC (JVM) |
| Build Speed | Fast (Dune) | Fast (Cargo) | Medium (SBT) |
| Ecosystem | Nix/Opam | Cargo | JVM/Maven |
| Error Messages | Good | Excellent | Good |
| Status | ✅ Complete | ✅ Complete | ✅ Complete |
- OCaml Implementation README
- OCaml CI Setup
- Inline Declarations Guide
- Rust Implementation README
- Scala Implementation README
This project is licensed under the MIT License - see the LICENSE file for details.
Contributions welcome! Please see individual implementation directories for specific contribution guidelines.