OCamli is a proof-of-concept step-by-step interpreter for OCaml programs intended for teaching purposes and, eventually, as a debugger. It works by reading an OCaml program into an abstract syntax tree, then interpreting the AST one reduction at a time, optionally displaying each reduction and underlining the reducible expression. For example:
With just -show
instead:
Running the classic factorial program, using a set of options to elide parts of the output (there are too many options, and the interface will be improved):
Mutable code
Some of ocamli
's output is a little low-level for now, but it's important to emulate what OCaml itself does by making the actual calls to primitives like %setfield0
:
Input/Output
Sometimes the approach of printing everything gets far too much. We will need methods for hiding this internal detail by default:
Standard Library Functions
You should be able to use some or most of the Standard Library functions. Presently Printf
and Scanf
are not loaded due to bugs.
Searching
"I want to see the last few steps before factorial (4 - 1)
":
The directory examples contains a number of little programs written for development.
The directory OCaml from the Very Beginning contains all the examples and exercises from the beginner's OCaml textbook.
The eventual use of ocamli
as a debugger is sketched in the position paper "Visualizing the Evaluation of Functional Programs for Debugging", given at SLATE'17 in June.
eval <filename | -e program> [-- arg1 arg2 ...]
Loading and runnning programs:
Multiple files and -e
options may be given, and will be treated as zero or more modules followed by one main program.
Searching:
Interaction:
Elision:
Configuration:
The ocamli
interpreter requires no patches to the OCaml compiler; it is implemented entirely using compiler-libs
.
The OCaml program is lexed and parsed by compiler-libs
, typechecked, then the parse tree is converted to a simpler, more direct datatype, called Tinyocaml
.
The Tinyocaml
representation is then interpreted step-by-step, optionally printing each stage out. We use a custom prettyprinter, but hope to eventually contribute back to the standard one.
Keeping ocamli
in sync with OCaml will involve updating it to reflect any changes in the compiler-libs
API and adding any new features added to the OCaml languages. So, we will have ocamli
4.05 for OCaml 4.05 and so on.
The ocamli
facilities for conversing with C code (such as OCaml %external
declarations) are based on reading and writing OCaml heap values. The interpreter and the interpreted program and the compiled parts live in the same process with the same OCaml runtime.
The interpreter can be used at runtime, and the resulting value bought back into the caller:
# let x : int list * int list =
Tinyocaml.to_ocaml_value
(Runeval.eval_string "List.split [(1, 2); (3, 4)]");;
val x : int list * int list = ([1; 3], [2; 4])
Support for this is very rudimentary at the moment.
Writing
let compiler_command = [%compiletimestr "Sys.argv.(0)"])
in a normal compiled OCaml program with PPX_eval
generates
let compiler_command = "ocamlopt"
The ocamli
interpreter is a proof-of-concept. Do not expect it to run your larger programs!
It supports just enough of the language to load (and run the module initialisation of) most of the OCaml Standard Library. This is quite a large number of constructs, though, including functors, first class modules and so on.
The ocamli
interpreter can run almost all the programs in the OCaml from the Very Beginning textbook. The examples are included in the download.
The ocamli
interpreter currently makes no guarantee of computational complexity, even when the steps of evaluation are not shown. The extent to which such a guarantee can be given is an open research question.
In short, make it more than a proof-of-concept:
Make sure to download from tag "OCaml17". Should work on all platforms with OCaml 4.05. To build, run the build
script. You will need ocamlfind
and ppx_tools
installed, both of which are available on OPAM.