# lumbda Architecture Documentation

> "A diagram is worth 10,000 words." — russell@unturf.com

Three implementations of the same Scheme language, sharing the same .lsp test files.

## Python Implementation (lumbda.py)

3,324 lines. Bytecode compiler + stack VM + full continuations + portal.

![Python Architecture](python-architecture.png)

**Execution tiers:**
- Tree-walker (`leval`): default, handles all forms including macros
- Bytecode VM (`--fast`): 40 opcodes + superinstructions, 7-19x faster
- Python JIT prototype: exec()-based transpilation (labeled as prototype)

**Key features:**
- Full multi-shot continuations via explicit frame stack
- Portal: serialize VM state to JSON, resume on another machine
- Inline cache, constant folding, peephole optimizer
- Source maps for error reporting with line numbers
- Bytecode serialization (.lspc files)

**Tests:** 571 unit + integration tests (tests.py)

---

## C Implementation (c/)

8,120 lines. Tree-walker + bytecode VM + x86_64 JIT.

![C Architecture](c-architecture.png)

**Execution tiers:**
- Tree-walker: default, full special form support
- Bytecode VM (`--fast`): matching Python's opcodes
- x86_64 JIT (`--jit`): **10-24x faster than CPython**

**Key features:**
- NaN-boxed 64-bit values (zero-alloc numbers)
- Hash-map environments with parent chain + global shortcut
- Interned symbols
- Real JIT: mmap(PROT_EXEC) + raw x86_64 bytes

**Tests:** 76 unit + integration + JIT tests (test.c)

---

## Assembly Implementation (asm/)

2,592 lines of GNU assembler. 13KB binary. Zero dependencies.

![Assembly Architecture](asm-architecture.png)

**Design:**
- No C. No libc. Only Linux syscalls (read, write, mmap, exit)
- Tag-in-low-3-bits value representation
- Bump allocator on 64MB mmap'd page
- TCO via `jmp .eval_top` (never grows the stack)
- 34 builtins, all special forms

**Tests:** 75 unit + integration + functional tests (test.sh)

---

## JIT Pipeline (c/jit.c)

1,309 lines. Compiles Scheme AST directly to x86_64 machine code.

![JIT Pipeline](jit-pipeline.png)

**What gets JIT'd:**
- if, cond, and, or (conditional jumps)
- +, -, *, =, <, >, <=, >= (native integer ops)
- let, let* (stack-allocated locals)
- Named-let loops (native jmp, zero call overhead)
- car, cdr, cons, null?, pair? (NaN-box pointer ops)
- Self-recursive calls (call/ret) and tail calls (jmp)

**What falls back to interpreter:**
- call/cc, macros, syntax-rules, quasiquote, modules
- String/vector/hash-table operations
- Any form the AST analyzer can't verify as integer-safe

---

## Performance Summary

All benchmarks measured in-process (no startup overhead) on the same machine.

| Implementation | ack(3,4) | fib(35) | sum-to(50k) | Binary |
|---------------|----------|---------|-------------|--------|
| **C + x86_64 JIT** | **0.19ms** | **0.09ms** | **0.55ms** | 171KB |
| CPython (native) | 1.3ms | 0.006ms | 5.5ms | ~5MB |
| C interpreter | 20ms | 0.06ms | 109ms | 171KB |
| Python bytecode VM | 149ms | 0.75ms | 437ms | 3,324 lines |
| Assembly (13KB) | ~8ms* | ~0.6ms* | ~43ms* | **13KB** |

*Assembly times include process startup + tokenizer + parser.

**The JIT runs Scheme faster than CPython runs Python** on recursive workloads:
ack(3,4) is 7x faster, sum-to(50k) is 10x faster. The JIT compiles Scheme AST
directly to x86_64 machine code via mmap(PROT_EXEC).

---

## Test Coverage

943 verified assertions across all implementations:

```
make test-all
  Python unit/integration:   571 tests
  C unit/integration/JIT:     83 tests
  Assembly unit/int/func:    108 tests
  Shared functional:         181 tests (Python + C)
  Total:                     943 assertions
```

The language is **R7RS Scheme**. lumbda is the project name — a play on
Common Lisp, since this is decidedly uncommon.
