
Oonta is a compiler front-end for the OCaml programming language: it generates LLVM intermediate representation (IR) from OCaml source code.
Oonta uses the JJIK parser generator and JLEK lexer generator to perform the parsing and lexing stages.
[!IMPORTANT] This project is still a work in progress, many OCaml features are not yet supported. For example, custom types, pattern matching, and modules are not yet supported. Additionally, the garbage collector runtime is not yet available. See the issues tab for the list of work items.
[!NOTE] This project is part of the "Compiler Toys" project, originally meant as a learning exercise on Compilers.
Quick Start
# 9
# 120
Dependencies
The oonta binary does not have any runtime dependencies other than the
standard library. However, for convenience, the oonta command provides the
--compile / -c and --exec / -e options to compile the generated IR to an
object code and executable, respectively. Internally, oonta will invoke the
following commands:
# with --compile
# with --exec
On Ubuntu, install the llvm package to make those commands available.
[!NOTE] I will be working on my own LLVM backend as part of my compiler learning journey! ✨
[!WARNING] The generated IR uses opaque pointers. If your LLVM version is older than version 15, the
--compile/--execoptions might not work.
User Guide
Feature Highlights
Debug compile phases
Use the --verbose / -v option to debug each compile phase.
=> Lexing & Parsing Start
=> Lexing & Parsing End (1 ms)
=> Build AST Start
factorial =
FunExpr
├─▸ parameters: [x]
├─▸ captures: []
├─▸ recursive: yes
└─▸ body:
CondExpr
├─▸ condition:
│ BinOpExpr
│ ├─▸ operator: <=
│ ├─▸ lhs:
│ │ VarExpr ("x")
│ └─▸ rhs:
│ LiteralExpr (1)
├─▸ then expr:
│ LiteralExpr (1)
└─▸ else expr:
BinOpExpr
├─▸ operator: *
├─▸ lhs:
│ VarExpr ("x")
└─▸ rhs:
ApplicationExpr
├─▸ function:
│ VarExpr ("factorial")
└─▸ binds:
└─▸ (0)
BinOpExpr
├─▸ operator: -
├─▸ lhs:
│ VarExpr ("x")
└─▸ rhs:
LiteralExpr (1)
() =
ApplicationExpr
├─▸ function:
│ VarExpr ("print_int")
└─▸ binds:
└─▸ (0)
ApplicationExpr
├─▸ function:
│ VarExpr ("factorial")
└─▸ binds:
└─▸ (0)
LiteralExpr (5)
=> Build AST End (0 ms)
=> Resolve types Start
Top level bindings:
factorial: (int -> int)
=> Resolve types End (0 ms)
=> Transform application expressions Start
=> Transform application expressions End (0 ms)
=> Build LLVM module Start
=> Build LLVM module End (0 ms)
=> Write LLVM module Start
=> Write LLVM module End (1 ms)
=> LLVM backend Start
=> LLVM backend End (117 ms)
Error reporting
Line 1|let x = foo 3
^--
Error: cannot infer expression type: Unbound value foo
Line 1|let rec f x = f
^
Error: cannot infer expression type: Cannot unify 'b with ('a -> 'b)
Line 1|let () = 1 + 2
^----
Error: cannot bind expression of type int to ()
Building from source
- Install
cargotool:
|
- Clone repository.
- Build
oontacrate.
[!NOTE]
oontaonly depends onjjik,jlek, and Rust's standard library for building.
Why is it called Oonta?
Oonta, is based on the Indonesian word unta, which translates to "camel".