(rontolisp) docs

File Interpretation

Pass a path to a .lisp file and rontolisp interprets it directly, without producing any compiled artifact. The file's top-level forms are read and evaluated in order on the tree-walking interpreter, sharing one environment, so a function or variable defined near the top is available to everything below it.

rontolisp program.lisp

Unlike the REPL, a script does not echo the value of each form -- output is whatever the program writes explicitly with print, format, and the like. The process exits with status 0 when the file runs to completion, or non-zero if a form signals an error.

Example (program.lisp):

25
144

This is the same source you would later hand to the JVM or WASM compiler; running it through the interpreter first is the fastest way to check a program's behavior before compiling it.

Interpretation Speed

The interpreter is built for turnaround, not throughput: it starts immediately and runs the exact semantics the compilers are pinned against, but a tight loop pays interpretation on every iteration, and nothing warms up over time. On loop-heavy code that costs 20x-200x over the same file compiled: summing the first ten million integers takes several seconds interpreted and a fraction of a second as a compiled class or WASM module.

For a script that reads a file, calls an HTTP API, or serves requests, the factor is invisible -- the time goes to I/O -- and interpretation is the right default. When a program is CPU-bound (numeric loops, parsing, crypto), compile it and run the artifact instead:

rontolisp program.lisp -o program.jar
java -jar program.jar

The compiled output is the fast path, on the JVM and on WASM alike; see Compile to JVM Bytecode and Compile to WASM.

Recursion Depth

The interpreter recurses on the host's stack: every Lisp call that still has work to do after the callee returns holds interpreter frames, so a deeply recursive program can exhaust it. A call in tail position -- the last thing a function does, including a call through a function value, apply, a function calling another that calls it back, or the value of a return-from/return that leaves the function, from a loop body too -- holds none, so a loop written as tail recursion runs at any depth. rontolisp runs the program on a thread of its own with a 16 MiB stack, so the depth a program reaches is the same number on every platform and every launcher -- a java -jar's -Xss sizes a thread the program no longer runs on. Ask for more with --stack, in MiB:

rontolisp --stack 64 deep.lisp

A program deeper than its stack stops with error: stack overflow (--stack <MiB> raises the limit) and exit status 1; the cure is this flag or an iterative formulation of the recursion. At the REPL the same overflow is reported and the session goes on with everything defined so far.

Programs Given on the Command Line

-e (long form --eval) takes the program from the argument itself instead of a file. It runs exactly like a file -- no value is echoed, only what the program prints:

rontolisp -e "(print (+ 1 2))"
3

The option is repeatable, and the occurrences make up one program evaluated in order, as if the forms were written on successive lines of a single file:

rontolisp -e "(defun square (x) (* x x))" -e "(print (square 5))"
25

It combines with everything a file accepts, including the compilers (rontolisp -e "(print (+ 1 2))" -o Prog.class), but not with an input file -- give the program one way or the other. There being no source file, a relative (load "...") resolves against the working directory.