Real native machine code via mmap(PROT_EXEC). No exec(). No strings.
Raw x86_64 bytes: mov, add, sub, imul, cmp, je, jne, call, ret, jmp.
ack(3,4): 0.12ms JIT vs 1.5ms CPython vs 28ms interpreter
fib-rec(20): 0.16ms JIT vs 3.4ms CPython vs 40ms interpreter
Added cond support to JIT (cascaded comparisons → conditional jumps).
Fixed JIT cache: sentinel value prevents retry on unjittable functions.
System V AMD64 ABI: args in rdi/rsi/rdx, callee-saved r12-r15.
Tail calls use jmp (true TCO at machine code level).
691 lines of jit.c. 114 functional tests pass. All C tests pass.
JIT now matches CPython speed:
fib-rec(20): JIT 14ms vs VM 1245ms (87x faster)
ack(3,4): JIT 13ms vs VM 1053ms (82x faster)
Both at parity with hand-written CPython.
tests/functional.lsp — single .lsp file, runs identically in Python and C.
Covers: arithmetic, comparison, booleans, pairs, lists, strings, characters,
vectors, hash tables, control flow, let/lambda/closures, do loops, define,
recursion, TCO (100k depth), quasiquote, macros, type predicates, call/cc,
error handling, mergesort, higher-order programs.
Fixed C call/cc: proper escape continuations via setjmp/longjmp.
make test-all runs: Python unit (571) + C unit (58) + shared functional (114).
fib(35): C 0.1ms vs Python 0.6ms (6x)
fib-rec(20): C 44ms vs Python 283ms (6.4x)
ack(3,4): C 31ms vs Python 93ms (3x)
sum-to(50k): C 129ms vs Python 515ms (4x)
Both still ~20-30x slower than native CPython (interpreter overhead).
SBCL would be within 2-5x of C with native compilation.
Complete C port of the Scheme interpreter. Same .lsp files run in
both Python and C with identical output.
Architecture:
- NaN-boxed 64-bit values (zero-alloc numbers)
- Hash-map environments with parent chain + global shortcut
- Interned symbols
- TCO via explicit loop (eval) and TAIL_CALL/SELF_TAIL_CALL (VM)
- Bytecode compiler with all opcodes including superinstructions
- 58 unit + integration tests
Makefile targets:
make test-all run Python (571) + C (58) tests
make examples run examples in both, compare output
make friction benchmark same .lsp in Python vs C
make c-build build C interpreter
make c-test run C tests
make c-repl C REPL
Fused opcodes: LOOK_ADD1 (lookup + increment) and LOOK_SUB1
(lookup + decrement) emitted directly by compiler for (+ sym 1)
and (- sym 1) patterns. Eliminates one dispatch per loop iteration.
sum-to(50000) ratio improved from 59x to 45x vs Python.
ackermann(3,4) steady at 83x. 571 tests green.
Also defines LOOK_LOOK, CONST_EQ_JF, LOOK_CONST_CALL2
superinstruction opcodes (VM handlers ready, compiler emission
for remaining patterns deferred to next pass).
Formal proof (Lean, 1.5s) is 40x faster than brute-force search
(uncommonlisp, 59s) with mathematical certainty vs floating-point
tolerance. This is O(N²) search friction where O(1) algebraic
reasoning suffices — the sedimentary defect in proof methodology.
Proof assistants are the hash set to numerical analysis's nested loop.
Permacomputer whitepaper covering uncommonlisp architecture,
bytecode VM, continuations, portal, EML universality proof,
and benchmarks. AGPL-3.0-only. Builds via make whitepaper
using a local venv (no sudo).
Benchmark: Python 0.04s, uncommonlisp 59s, Lean 1.5s — for the same claim.
The formal proof is 40x faster than brute-force search with mathematical
certainty instead of floating-point tolerance.
This is MOAD-0001 at the proof layer: O(N²) search friction where
O(1) algebraic reasoning suffices. Proof assistants are the hash set
to numerical analysis's nested loop.
Lean's type checker verifies all 5 theorems:
1. exp(x) = eml(x, 1)
2. e = eml(1, 1)
3. ln(x) = eml(1, eml(eml(1,x), 1))
4. 0 = eml(1, eml(eml(1,1), 1))
5. a - b = eml(ln(a), exp(b))
Zero sorry. Machine-verified. This is a proof, not numerical analysis.
Portal saves the full machine state — env chain, compiled procedures,
continuations, frame stack — to a JSON file. Another interpreter
instance loads it and resumes execution from the exact instruction.
Demo: start a primality test on machine A, checkpoint mid-computation,
resume on machine B. 1000000007 prime check: machine B picks up from
i=30000 and finishes in 6% of the original time.
Implementation:
- PortalSerializer: graph-aware with identity tracking for shared env
references. Handles cycles (closures referencing their own env).
- portal-checkpoint!: triggers mid-execution save from within VM loop.
Hooks into TAIL_CALL (loop back-edge) for compiled code.
- --portal-resume CLI flag: load .portal file and resume continuation.
- portal-save / portal-resume Scheme builtins.
571 tests green (7 new portal tests: unit + integration + functional).
Source maps: tokenizer tracks line numbers, parser attaches to Pair nodes,
compiler records in CodeObj.source_map, errors display source line.
Multi-shot continuations: FullCont snapshots env at capture time via
deep copy. Each invocation gets a fresh env copy. Generators and
multi-shot patterns both work correctly.
Inline caching: VM caches global env lookups per instruction site.
Local shadow check (arg not in env.b) prevents stale cache hits.
Compiler tracks compile-time scopes to suppress specialization/folding
when builtins are locally shadowed.
Bytecode serialization: JSON-based .lspc format. save-compiled/load-compiled
builtins. --compile CLI flag precompiles .lsp files. Round-trip tested for
all operand types including nested closures and quoted data.
564 tests green (35 new: unit + integration + functional for each feature).
- Full call/cc: upward continuations via explicit VM frame stack + trampoline.
Generators now work: (make-gen (lambda (yield) (yield 1) (yield 2)))
- Explicit frame stack: compiled→compiled CALL no longer grows Python stack.
Non-tail calls use frames list instead of recursive vm_exec.
- Env global shortcut: lookup checks local then global before walking chain,
O(1) for builtins instead of O(depth).
- Constant folding: arithmetic on literals folded at compile time.
- Auto-compile covers inline lambdas (not just define).
- 522 tests green, 7-19x speedup over interpreter.
- auto-compile! parameter: compile defines on the fly for zero-effort speedup
- VM optimization: local aliases, inlined truthiness checks (~15% faster)
- disassemble builtin: human-readable bytecode listing
- call/cc compiled natively in VM (escape-only, no longer falls back to eval)
- Makefile: add lint, bench-verbose, clean targets
- 518 tests green
Stack-based VM with 17 opcodes, TCO via in-place frame reset,
compile-time macro expansion, and seamless interop between
compiled and interpreted code. 514 tests green.
Core additions:
- StringInputPort / StringOutputPort — open-input-string, open-output-string,
get-output-string, read/read-char/peek-char/read-line on ports
- R7RS ErrorObject class — error-object?, error-object-message,
error-object-irritants; guard and with-exception-handler now receive
ErrorObject instances instead of raw strings
- Exact rational arithmetic via Fraction — (/ 1 3) => 1/3, literal 1/3
syntax, numerator/denominator, exact/inexact conversions
- Module system — (module name (export ...) body...) and (import name) /
(import (name sym ...)) for selective import
- define-record-type now a Python special form supporting (inherit parent)
for single-inheritance with subtype predicates
- Pretty-printer — pp/pretty-print with configurable line width
Correctness:
- R7RS letrec* body semantics for internal defines — names pre-declared
before any initializer runs, enabling mutual recursion in let bodies
- string->number detects #x/#b/#o/#d and 0x/0b/0o prefixes
- show() guarantees decimal point in float output
- number->string rounds through show() for consistent float representation
Performance:
- _body_env fast path: skip scan when first body form is not define/begin
- Proc.has_defs flag: skip _body_env entirely for procs without internal defines
- Single-form body optimization: skip begin wrapper, set expr directly
Tests: 396 → 455 (+59 new tests covering all new features)