rename: uncommonlisp -> lumbda throughout the repo

Historical internal name "uncommonlisp" retired in favor of the
public name "lumbda" ahead of lumbda.com going live. Scope of
this commit:

Source files renamed:
  uncommonlisp.py                     -> lumbda.py
  asm/uncommonlisp.s                  -> asm/lumbda.s
  c/uncommonlisp.h                    -> c/lumbda.h
  whitepaper/uncommonlisp-whitepaper  -> whitepaper/lumbda-whitepaper (.rst + .pdf)

Binaries renamed (tracked ones; c/ was always gitignored):
  asm/uncommonlisp, asm/uncommonlisp-gc, asm/uncommonlisp.o,
  asm/uncommonlisp-gc.o                -> asm/lumbda(-gc)(.o)
  c/.gitignore                          -> ignores lumbda

Internal string updates (sed pass ordered longest-first):
  asm/uncommonlisp -> asm/lumbda
  c/uncommonlisp   -> c/lumbda
  uncommonlisp.py  -> lumbda.py
  UNCOMMONLISP_BIN -> LUMBDA_BIN (asm/test.sh env var)
  "uncommonlisp> " -> "lumbda> " (asm REPL prompt baked into binary)
  UNCOMMONLISP     -> LUMBDA (macros, comments)
  uncommonlisp     -> lumbda (prose)

Binary portal magic updated:
  "ULPORTAL" -> "LUMBDAB1"   # "Lumbda Binary v1"
Old portal files are not backward-compatible — this is a deliberate
break since it's the rename moment. S-expression portals already
carry their own ";; lumbda-portal v1" header and remain cleanly
versioned.

WHITEPAPER.pdf / WHITEPAPER.rst symlinks repointed to the renamed
files. Makefile's whitepaper target targets lumbda-whitepaper.pdf.

Not changed (intentional, separate phases):
  - Filesystem directory /home/fox/git/uncommonlisp itself
    (fox renames locally and the gitlab repo URL in a follow-up)
  - tests.py hardcoded cwd=/home/fox/git/uncommonlisp
    (matches the current on-disk location; will flip when the
    directory rename ships)
  - Git history (immutable; old commits still say uncommonlisp,
    which is correct — that's what they were)

Verified:
  137 asm no-GC + 137 asm GC + 571 Python + 83 C + 189 shared
  functional tests all pass under the new names.
  bench-gc-http (2000 req): all 4 cells behave as expected
  (cells 1/2 flat, 3 leaks, 4 bounded at 1 chunk).
  Python REPL, C REPL, asm REPL all start cleanly.
This commit is contained in:
russell@unturf.com 2026-04-19 10:20:11 -04:00
parent 9e54c7aaf1
commit f7352b51b0
77 changed files with 383 additions and 383 deletions

View file

@ -1,6 +1,6 @@
# Agent Blackops — Lumbda repo
This repo is operated by **agent blackops** — ml agent for fox/timehexon on the unsandbox/unturf/permacomputer platform. **Lumbda** is the language (home: lumbda.com); the repo directory and binaries still use the historical name `uncommonlisp` until the filesystem rename ships in a later phase.
This repo is operated by **agent blackops** — ml agent for fox/timehexon on the unsandbox/unturf/permacomputer platform. **Lumbda** is the language (home: lumbda.com); the repo directory and binaries still use the historical name `lumbda` until the filesystem rename ships in a later phase.
## Identity
@ -39,7 +39,7 @@ Then ask fox what the mission is.
| Impl | Path | Build | Test | REPL |
|------|------|-------|------|------|
| Python | `uncommonlisp.py` | — | `make test` | `make repl` |
| Python | `lumbda.py` | — | `make test` | `make repl` |
| C | `c/` | `make c-build` | `make c-test` | `make c-repl` |
| Assembly | `asm/` | `make asm-build` | `make asm-test` | `make asm-repl` |
| All | — | — | `make test-all` | — |
@ -75,22 +75,22 @@ crash is not just "my problem" — it takes their state down too.
The rules below are belt, suspenders, AND a parachute so that even
if two safeguards fail, the kernel itself backstops.
**MANDATORY pattern — every asm/uncommonlisp test in a shell block:**
**MANDATORY pattern — every asm/lumbda test in a shell block:**
```bash
set -e # (1) fail-fast
ulimit -v 524288 # (2) KERNEL CAP: 512 MB virt
# process gets SIGKILL at cap, no matter what
trap 'pkill -9 -u "$USER" -f "examples/http-server|asm/uncommonlisp" 2>/dev/null || true' \
trap 'pkill -9 -u "$USER" -f "examples/http-server|asm/lumbda" 2>/dev/null || true' \
EXIT INT TERM # (3) cleanup always fires
timeout 30 asm/uncommonlisp < server.lsp & # (4) wall-clock ceiling
timeout 30 asm/lumbda < server.lsp & # (4) wall-clock ceiling
SPID=$!
# ... do the work (curl requests, measurements, etc.) ...
kill -9 $SPID 2>/dev/null; wait $SPID 2>/dev/null # (5) explicit cleanup
# (6) VERIFY the block is clean before moving on
pgrep -u "$USER" -f 'asm/uncommonlisp|examples/http-server' \
pgrep -u "$USER" -f 'asm/lumbda|examples/http-server' \
&& { echo "STRAGGLER"; exit 1; } || true
```
@ -108,12 +108,12 @@ Additional rules:
in `examples/http-server.lsp`). Never raise for long-running tests.
- Use `pkill -u "$USER" -f <pattern>` not `pkill` alone — others may
have their own processes on this machine.
- Prefer FOREGROUND runs when possible: `timeout 10 asm/uncommonlisp
- Prefer FOREGROUND runs when possible: `timeout 10 asm/lumbda
< test.lsp` with the `.lsp` exiting on its own beats backgrounding.
- C has Boehm GC via `GC_MALLOC`. Python has Python's GC. Asm has
neither. Risk scales with how long the asm process lives.
- If `ulimit` is unavailable (some container setups), use
`systemd-run --user --scope -p MemoryMax=512M -- asm/uncommonlisp ...`
`systemd-run --user --scope -p MemoryMax=512M -- asm/lumbda ...`
as the equivalent cgroup-based cap.
## MOAD Scanner
@ -122,10 +122,10 @@ Additional rules:
```bash
cd ~/git/unmoadner && make all
./unmoad ~/git/uncommonlisp/ # scan entire repo
./unmoad ~/git/uncommonlisp/asm/ # scan assembly only
./unmoad ~/git/uncommonlisp/c/ # scan C only
./unmoad ~/git/uncommonlisp/*.py # scan Python only
./unmoad ~/git/lumbda/ # scan entire repo
./unmoad ~/git/lumbda/asm/ # scan assembly only
./unmoad ~/git/lumbda/c/ # scan C only
./unmoad ~/git/lumbda/*.py # scan Python only
```
**MANDATORY before committing new code:** run `unmoad` on changed files.

View file

@ -1,11 +1,11 @@
# ═══════════════════════════════════════════════════════════════════
# uncommonlisp — Python + C + Assembly implementations
# lumbda — Python + C + Assembly implementations
# ═══════════════════════════════════════════════════════════════════
#
# Implementations:
# Python uncommonlisp.py bytecode VM, full continuations, portal
# C c/uncommonlisp tree-walker + bytecode VM + x86_64 JIT
# Assembly asm/uncommonlisp pure x86_64, no libc, 13KB binary
# Python lumbda.py bytecode VM, full continuations, portal
# C c/lumbda tree-walker + bytecode VM + x86_64 JIT
# Assembly asm/lumbda pure x86_64, no libc, 13KB binary
#
# Test suites:
# make test Python unit/integration (571 tests)
@ -50,10 +50,10 @@ bench-verbose:
python3 bench.py -v
repl:
python3 uncommonlisp.py
python3 lumbda.py
lint:
python3 -m py_compile uncommonlisp.py
python3 -m py_compile lumbda.py
python3 -m py_compile tests.py
python3 -m py_compile bench.py
@ -65,13 +65,13 @@ c-build:
c-test: c-build
$(MAKE) -C c test
@echo "── C functional tests (shared .lsp suite) ──"
./c/uncommonlisp tests/functional.lsp
./c/lumbda tests/functional.lsp
c-bench: c-build
$(MAKE) -C c bench
c-repl: c-build
./c/uncommonlisp
./c/lumbda
c-clean:
$(MAKE) -C c clean
@ -85,7 +85,7 @@ asm-test: asm-build
$(MAKE) -C asm test
asm-repl: asm-build
./asm/uncommonlisp
./asm/lumbda
asm-clean:
$(MAKE) -C asm clean
@ -95,9 +95,9 @@ asm-clean:
functional-test: c-build
@echo "═══ Shared functional tests (114 tests) ═══"
@echo "── Python ──"
@python3 uncommonlisp.py --fast tests/functional.lsp | tail -3
@python3 lumbda.py --fast tests/functional.lsp | tail -3
@echo "── C ──"
@./c/uncommonlisp tests/functional.lsp | tail -3
@./c/lumbda tests/functional.lsp | tail -3
test-all: test c-test asm-test functional-test
@echo "════════════════════════════════════════════════════"
@ -147,16 +147,16 @@ bench-all: bench c-bench bench-3way bench-portal bench-portal-cross bench-web be
examples: c-build
@echo "═══ fibonacci.lsp ═══"
@echo "--- Python ---" && python3 uncommonlisp.py --fast examples/fibonacci.lsp
@echo "--- C ---" && ./c/uncommonlisp examples/fibonacci.lsp
@echo "--- Python ---" && python3 lumbda.py --fast examples/fibonacci.lsp
@echo "--- C ---" && ./c/lumbda examples/fibonacci.lsp
@echo
@echo "═══ mergesort.lsp ═══"
@echo "--- Python ---" && python3 uncommonlisp.py --fast examples/mergesort.lsp
@echo "--- C ---" && ./c/uncommonlisp examples/mergesort.lsp
@echo "--- Python ---" && python3 lumbda.py --fast examples/mergesort.lsp
@echo "--- C ---" && ./c/lumbda examples/mergesort.lsp
@echo
@echo "═══ objects.lsp ═══"
@echo "--- Python ---" && python3 uncommonlisp.py examples/objects.lsp
@echo "--- C ---" && ./c/uncommonlisp examples/objects.lsp
@echo "--- Python ---" && python3 lumbda.py examples/objects.lsp
@echo "--- C ---" && ./c/lumbda examples/objects.lsp
# ─── Friction benchmark ──────────────────────────────────────────
@ -176,8 +176,8 @@ docs/%.png: docs/%.dot
# ─── Whitepaper ───────────────────────────────────────────────────
VENV := whitepaper/.venv
RST := whitepaper/uncommonlisp-whitepaper.rst
PDF := whitepaper/uncommonlisp-whitepaper.pdf
RST := whitepaper/lumbda-whitepaper.rst
PDF := whitepaper/lumbda-whitepaper.pdf
STYLE := whitepaper/whitepaper.style
$(VENV)/bin/rst2pdf:
@ -191,9 +191,9 @@ $(PDF): $(RST) $(STYLE) $(VENV)/bin/rst2pdf
cd whitepaper && ../$(<D)/.venv/bin/rst2pdf \
-s whitepaper.style \
--fit-background-mode=scale \
uncommonlisp-whitepaper.rst \
-o uncommonlisp-whitepaper.pdf
@ln -sf uncommonlisp-whitepaper.pdf whitepaper/WHITEPAPER.pdf
lumbda-whitepaper.rst \
-o lumbda-whitepaper.pdf
@ln -sf lumbda-whitepaper.pdf whitepaper/WHITEPAPER.pdf
@echo "Built: $(PDF)"
# ─── Clean ────────────────────────────────────────────────────────

View file

@ -24,10 +24,10 @@ Home: [lumbda.com](https://lumbda.com)
## Usage
```bash
python3 uncommonlisp.py # interactive REPL
python3 uncommonlisp.py script.lsp # run a file
python3 uncommonlisp.py -e '(+ 1 2)' # eval an expression
python3 uncommonlisp.py --fast script.lsp # auto-compile (7-19x faster)
python3 lumbda.py # interactive REPL
python3 lumbda.py script.lsp # run a file
python3 lumbda.py -e '(+ 1 2)' # eval an expression
python3 lumbda.py --fast script.lsp # auto-compile (7-19x faster)
```
## Bytecode compiler
@ -35,7 +35,7 @@ python3 uncommonlisp.py --fast script.lsp # auto-compile (7-19x faster)
Lumbda includes a stack-based bytecode compiler and VM. Enable it with `--fast` or `(auto-compile! #t)`:
```bash
python3 uncommonlisp.py --fast examples/fibonacci.lsp
python3 lumbda.py --fast examples/fibonacci.lsp
```
```scheme
@ -108,10 +108,10 @@ Additional macros, string/list/numeric/tree utilities, alist/hash helpers, simpl
## Examples
```bash
python3 uncommonlisp.py --fast examples/fibonacci.lsp
python3 uncommonlisp.py --fast examples/generator.lsp
python3 uncommonlisp.py --fast examples/mergesort.lsp
python3 uncommonlisp.py examples/objects.lsp
python3 lumbda.py --fast examples/fibonacci.lsp
python3 lumbda.py --fast examples/generator.lsp
python3 lumbda.py --fast examples/mergesort.lsp
python3 lumbda.py examples/objects.lsp
```
```scheme
@ -150,11 +150,11 @@ Serialize a running VM mid-computation, transfer to another machine, resume:
```bash
# Machine A: start a long computation with checkpoints
python3 uncommonlisp.py --fast examples/portal-prime.lsp
python3 lumbda.py --fast examples/portal-prime.lsp
# saves prime-state.portal at checkpoint
# Machine B: resume from checkpoint
python3 uncommonlisp.py --portal-resume prime-state.portal
python3 lumbda.py --portal-resume prime-state.portal
# continues from exact instruction
```
@ -181,7 +181,7 @@ why this is MOAD-0001 (the sedimentary defect) at the proof methodology layer.
## File layout
```
uncommonlisp.py interpreter + bytecode compiler (one file, ~3200 lines)
lumbda.py interpreter + bytecode compiler (one file, ~3200 lines)
stdlib.lsp extended standard library
tests.py test suite (571 tests)
bench.py benchmarks vs CPython

View file

@ -1,20 +1,20 @@
all: uncommonlisp uncommonlisp-gc
all: lumbda lumbda-gc
uncommonlisp: uncommonlisp.s
as --64 -o uncommonlisp.o uncommonlisp.s
ld -o uncommonlisp uncommonlisp.o
lumbda: lumbda.s
as --64 -o lumbda.o lumbda.s
ld -o lumbda lumbda.o
uncommonlisp-gc: uncommonlisp.s
as --64 --defsym GC_NAIVE=1 -o uncommonlisp-gc.o uncommonlisp.s
ld -o uncommonlisp-gc uncommonlisp-gc.o
lumbda-gc: lumbda.s
as --64 --defsym GC_NAIVE=1 -o lumbda-gc.o lumbda.s
ld -o lumbda-gc lumbda-gc.o
test: uncommonlisp
test: lumbda
@bash test.sh
test-gc: uncommonlisp-gc
@UNCOMMONLISP_BIN=./uncommonlisp-gc bash test.sh
test-gc: lumbda-gc
@LUMBDA_BIN=./lumbda-gc bash test.sh
clean:
rm -f uncommonlisp.o uncommonlisp uncommonlisp-gc.o uncommonlisp-gc
rm -f lumbda.o lumbda lumbda-gc.o lumbda-gc
.PHONY: all test test-gc clean

BIN
asm/lumbda Executable file

Binary file not shown.

BIN
asm/lumbda-gc Executable file

Binary file not shown.

BIN
asm/lumbda.o Normal file

Binary file not shown.

View file

@ -1,4 +1,4 @@
# uncommonlisp.s — A Scheme interpreter in pure x86_64 assembly
# lumbda.s — A Scheme interpreter in pure x86_64 assembly
# No C. No libc. Just Linux syscalls and machine instructions.
#
# Value representation (tag in low 3 bits):
@ -207,7 +207,7 @@
.data
# ============================================================
prompt_str: .ascii "uncommonlisp> "
prompt_str: .ascii "lumbda> "
.equ prompt_len, . - prompt_str
newline_ch: .byte 10
@ -351,7 +351,7 @@ s_hashset: .ascii "#<hash-set>"
err_ht_miss: .ascii "Error: hash-table-ref: missing key\n"
.equ err_ht_miss_len, . - err_ht_miss
portal_magic: .ascii "ULPORTAL"
portal_magic: .ascii "LUMBDAB1"
.equ PORTAL_MAGIC_LEN, 8
.equ PORTAL_HDR_SIZE, 48 # magic(8) + heap_size(8) + heap_base(8) + r14(8) + r15(8) + reserved(8)

View file

@ -10,7 +10,7 @@ cd "$(dirname "$0")"
PASS=0
FAIL=0
UL="${UNCOMMONLISP_BIN:-./uncommonlisp}"
UL="${LUMBDA_BIN:-./lumbda}"
check() {
local name="$1" input="$2" expected="$3"
@ -28,7 +28,7 @@ check() {
}
echo "═══════════════════════════════════════════════════════"
echo "asm/uncommonlisp test suite"
echo "asm/lumbda test suite"
echo "═══════════════════════════════════════════════════════"
# ─── UNIT TESTS: individual primitives ────────────────────
@ -205,7 +205,7 @@ EOF
check "load-proc" "(load \"$LOAD_TMP/b.lsp\") (square 9)" "81"
echo "[unit] load — missing file returns #f"
check "load-missing" "(load \"/tmp/__nope_uncommonlisp_$$\")" "#f"
check "load-missing" "(load \"/tmp/__nope_lumbda_$$\")" "#f"
echo "[unit] load — empty file is void"
: > "$LOAD_TMP/empty.lsp"

Binary file not shown.

Binary file not shown.

Binary file not shown.

View file

@ -1,13 +1,13 @@
#!/usr/bin/env python3
"""
bench.py — benchmarks for uncommonlisp.
bench.py — benchmarks for lumbda.
Compares interpreter time against equivalent CPython.
Usage: python3 bench.py [-v]
"""
import sys, time, math
sys.setrecursionlimit(10000)
from uncommonlisp import make_global_env, read_all, leval, PRELUDE, show, bc_compile_proc, Proc
from lumbda import make_global_env, read_all, leval, PRELUDE, show, bc_compile_proc, Proc
VERBOSE = '-v' in sys.argv
@ -56,7 +56,7 @@ def bench(name, lisp_src, python_fn, iters=3):
return lisp_best, py_best
print('uncommonlisp benchmarks')
print('lumbda benchmarks')
print('=' * 75)
# ── 1. Fibonacci (iterative, named let) ──────────────────────────────────────
@ -388,7 +388,7 @@ print()
print('AUTO-COMPILE mode (auto-compile! #t)')
print('=' * 75)
from uncommonlisp import _auto_compile
from lumbda import _auto_compile
def bench_auto(name, lisp_src, python_fn, iters=3):
"""Time auto-compiled lisp vs python. Defines + runs in one pass."""

2
c/.gitignore vendored
View file

@ -1,5 +1,5 @@
*.o
uncommonlisp
lumbda
test_runner
test_runner_dbg
bench_runner

View file

@ -1,4 +1,4 @@
# Makefile for uncommonlisp C interpreter
# Makefile for lumbda C interpreter
# Targets: all, test, bench, clean
CC = gcc
@ -15,9 +15,9 @@ OBJS = $(SRCS:.c=.o)
.PHONY: all clean test bench
all: uncommonlisp
all: lumbda
uncommonlisp: main.o $(OBJS)
lumbda: main.o $(OBJS)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
test: test_runner
@ -26,14 +26,14 @@ test: test_runner
test_runner: test.c $(OBJS)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
bench: bench_runner uncommonlisp
bench: bench_runner lumbda
ulimit -s 65536 && ./bench_runner
bench_runner: bench.c $(OBJS)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
%.o: %.c uncommonlisp.h
%.o: %.c lumbda.h
$(CC) $(CFLAGS) -c -o $@ $<
clean:
rm -f *.o uncommonlisp test_runner bench_runner
rm -f *.o lumbda test_runner bench_runner

View file

@ -13,8 +13,8 @@
Expected output: `4`
Actual with `c/uncommonlisp --fast`: hangs or segfaults.
Tree-walker (`c/uncommonlisp` default) works correctly.
Actual with `c/lumbda --fast`: hangs or segfaults.
Tree-walker (`c/lumbda` default) works correctly.
Python `--fast` and asm tree-walker both work correctly.
## What's special

View file

@ -1,7 +1,7 @@
/*
* bench.c — Benchmarks: interpreted vs compiled vs JIT
*/
#include "uncommonlisp.h"
#include "lumbda.h"
#include "jit.h"
static double bench_time(void) {
@ -184,7 +184,7 @@ int main(void) {
return 1;
}
printf("uncommonlisp C benchmarks — interpreted vs compiled vs JIT\n");
printf("lumbda C benchmarks — interpreted vs compiled vs JIT\n");
printf("═════════════════════════════════════════════════════════════════\n");
const char *modes[] = { "interp", "compiled", "jit", NULL };

View file

@ -1,7 +1,7 @@
/*
* builtins.c — All built-in functions for the Scheme interpreter
*/
#include "uncommonlisp.h"
#include "lumbda.h"
/* ═══════════════════════════════════════════════════════════════════════════
* Helper macros
@ -1926,7 +1926,7 @@ Env *make_global_env(void) {
env_define(g, intern("else"), VAL_TRUE);
env_define(g, intern("..."), intern("..."));
env_define(g, intern("*version*"), make_string_from_cstr("1.0.0"));
env_define(g, intern("*name*"), make_string_from_cstr("uncommonlisp"));
env_define(g, intern("*name*"), make_string_from_cstr("lumbda"));
/* Portal builtins */
register_portal_builtins(g);

View file

@ -3,7 +3,7 @@
*
* Port of the Python leval() function with full special form support.
*/
#include "uncommonlisp.h"
#include "lumbda.h"
#include "jit.h"
/* ═══════════════════════════════════════════════════════════════════════════

View file

@ -1,5 +1,5 @@
/*
* jit.c — x86_64 native code JIT compiler for uncommonlisp
* jit.c — x86_64 native code JIT compiler for lumbda
*
* Emits real machine code bytes into mmap'd executable memory.
* Handles: integer arithmetic (+, -, *), comparisons (=, <, >, <=, >=),
@ -9,7 +9,7 @@
*
* Code outlasts authors.
*/
#include "uncommonlisp.h"
#include "lumbda.h"
#include "jit.h"
#include <sys/mman.h>

View file

@ -1,5 +1,5 @@
/*
* jit.h — x86_64 JIT compiler for uncommonlisp
* jit.h — x86_64 JIT compiler for lumbda
*
* Compiles Scheme procedures to native machine code.
* Uses mmap(PROT_READ|PROT_WRITE|PROT_EXEC) for executable memory.
@ -9,7 +9,7 @@
#ifndef JIT_H
#define JIT_H
#include "uncommonlisp.h"
#include "lumbda.h"
/* A JIT-compiled function takes NaN-boxed Value args and returns a Value.
* System V AMD64 ABI: args in rdi, rsi, rdx, rcx, r8, r9 */

View file

@ -1,11 +1,11 @@
/*
* uncommonlisp.h — A Scheme interpreter in C (NaN-boxed values, Boehm-style GC)
* lumbda.h — A Scheme interpreter in C (NaN-boxed values, Boehm-style GC)
*
* Complete port of uncommonlisp.py.
* Complete port of lumbda.py.
* Part of the permacomputer platform — code outlasts authors.
*/
#ifndef UNCOMMONLISP_H
#define UNCOMMONLISP_H
#ifndef LUMBDA_H
#define LUMBDA_H
#include <stdio.h>
#include <stdlib.h>
@ -763,4 +763,4 @@ typedef struct Module {
extern Module *g_modules;
#endif /* UNCOMMONLISP_H */
#endif /* LUMBDA_H */

View file

@ -1,7 +1,7 @@
/*
* main.c — REPL, script mode, -e mode
*/
#include "uncommonlisp.h"
#include "lumbda.h"
#include "jit.h"
/* ═══════════════════════════════════════════════════════════════════════════
@ -16,7 +16,7 @@ static char *find_stdlib(const char *argv0) {
ssize_t n = readlink("/proc/self/exe", path, sizeof(path) - 1);
if (n > 0) {
path[n] = '\0';
/* Go up one directory (from c/uncommonlisp to uncommonlisp/) */
/* Go up one directory (from c/lumbda to lumbda/) */
char *slash = strrchr(path, '/');
if (slash) {
*slash = '\0';
@ -51,7 +51,7 @@ static char *find_stdlib(const char *argv0) {
static void repl(Env *env) {
char *version_str = show(env_lookup(env, intern("*version*")), true);
printf("uncommonlisp %s (C) — (exit) to quit, (load \"file.lsp\") to load\n", version_str);
printf("lumbda %s (C) — (exit) to quit, (load \"file.lsp\") to load\n", version_str);
ul_free(version_str);
char buf[16384];
@ -161,10 +161,10 @@ int main(int argc, char **argv) {
}
if (help) {
printf("uncommonlisp — a Scheme interpreter in C\n\n"
"Usage: uncommonlisp [options] [script.lsp] [args...]\n"
" uncommonlisp -e '(+ 1 2)'\n"
" uncommonlisp (interactive REPL)\n\n"
printf("lumbda — a Scheme interpreter in C\n\n"
"Usage: lumbda [options] [script.lsp] [args...]\n"
" lumbda -e '(+ 1 2)'\n"
" lumbda (interactive REPL)\n\n"
"Options:\n"
" -e EXPR evaluate expression and print result\n"
" -f, --fast auto-compile all defines (bytecode VM;\n"
@ -178,7 +178,7 @@ int main(int argc, char **argv) {
}
if (version) {
printf("uncommonlisp 1.0.0 (C)\n");
printf("lumbda 1.0.0 (C)\n");
return 0;
}

View file

@ -4,7 +4,7 @@
* Port of the Python portal_save/portal_resume system.
* Serializes environment bindings and full continuations.
*/
#include "uncommonlisp.h"
#include "lumbda.h"
/* ═══════════════════════════════════════════════════════════════════════════
* Portal checkpoint — thread-local signal for mid-execution save
@ -188,7 +188,7 @@ void portal_save(Env *env, const char *path, FullCont *continuation) {
return;
}
fputs("{\"format\":\"uncommonlisp-portal-v1\",\n", fp);
fputs("{\"format\":\"lumbda-portal-v1\",\n", fp);
/* Environment bindings (user-defined only from global) */
fputs("\"env\":", fp);
@ -620,7 +620,7 @@ bool portal_resume(const char *path, Env *base_env, Env **out_env, FullCont **ou
/* Check format */
const char *fmt = json_str(json_obj_get(root, "format"));
if (!fmt || strcmp(fmt, "uncommonlisp-portal-v1") != 0) {
if (!fmt || strcmp(fmt, "lumbda-portal-v1") != 0) {
json_free(root);
return false;
}

View file

@ -1,7 +1,7 @@
/*
* printer.c — show/display/write for Scheme values
*/
#include "uncommonlisp.h"
#include "lumbda.h"
/* Dynamic string builder */
typedef struct {

View file

@ -1,7 +1,7 @@
/*
* reader.c — Tokenizer + parser for Scheme source
*/
#include "uncommonlisp.h"
#include "lumbda.h"
/* ═══════════════════════════════════════════════════════════════════════════
* Tokenizer

View file

@ -1,7 +1,7 @@
/*
* test.c — Unit + integration tests for the C Scheme interpreter
*/
#include "uncommonlisp.h"
#include "lumbda.h"
#include "jit.h"
static int tests_run = 0;
@ -876,7 +876,7 @@ TEST(portal_checkpoint_builtin) {
int main(void) {
init_symbols();
printf("Running uncommonlisp C tests...\n\n");
printf("Running lumbda C tests...\n\n");
printf("[types]\n");
run_test_nan_boxing_int();
run_test_nan_boxing_double();

View file

@ -1,7 +1,7 @@
/*
* types.c — Value types, NaN-boxing, symbol interning, Env, Pair, etc.
*/
#include "uncommonlisp.h"
#include "lumbda.h"
/* ═══════════════════════════════════════════════════════════════════════════
* Error context (thread-local)

4
c/vm.c
View file

@ -1,7 +1,7 @@
/*
* vm.c — Bytecode compiler + stack-based VM
*/
#include "uncommonlisp.h"
#include "lumbda.h"
/* ═══════════════════════════════════════════════════════════════════════════
* CodeObj
@ -625,7 +625,7 @@ void bc_compile(Value expr, CodeObj *code, Env *env, bool tail) {
ul_free(call_args);
}
/* syntax_transform_value is declared in uncommonlisp.h, implemented in eval.c */
/* syntax_transform_value is declared in lumbda.h, implemented in eval.c */
/* ═══════════════════════════════════════════════════════════════════════════
* Compile a Proc into a CompiledProc

View file

@ -1,10 +1,10 @@
# uncommonlisp Architecture Documentation
# 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 (uncommonlisp.py)
## Python Implementation (lumbda.py)
3,324 lines. Bytecode compiler + stack VM + full continuations + portal.
@ -118,5 +118,5 @@ make test-all
Total: 943 assertions
```
The language is **R7RS Scheme**. uncommonlisp is the project name — a play on
The language is **R7RS Scheme**. lumbda is the project name — a play on
Common Lisp, since this is decidedly uncommon.

View file

@ -21,7 +21,7 @@ digraph c_arch {
}
subgraph cluster_types {
label="Types (types.c, uncommonlisp.h)"
label="Types (types.c, lumbda.h)"
style=rounded
color="#666666"
nanbox [label="NaN-Boxing\n64-bit doubles\ntype tags in NaN payload\nzero-alloc numbers" fillcolor="#e2d5f1"]

View file

@ -3,7 +3,7 @@
;;; ASM-ONLY: exercises the native hash-set-* primitives introduced
;;; alongside the portable-lib equivalent. C and Python tiers do not
;;; carry hash-set builtins (they have hash-table), so this file is
;;; driven from tests/bench-hashset.sh against asm/uncommonlisp only.
;;; driven from tests/bench-hashset.sh against asm/lumbda only.
;;;
;;; Phases: insert-N, hit-lookup-N, miss-lookup-N.
;;; Output: ms per phase + speedup (portable/native).

View file

@ -1,5 +1,5 @@
;;; fibonacci.lsp — iterative and recursive Fibonacci
;;; Run: python3 uncommonlisp.py --fast examples/fibonacci.lsp
;;; Run: python3 lumbda.py --fast examples/fibonacci.lsp
(define (fib-iter n)
(let loop ((a 0) (b 1) (i 0))

View file

@ -1,5 +1,5 @@
;;; generator.lsp — coroutine-style generators using full continuations
;;; Run: python3 uncommonlisp.py --fast examples/generator.lsp
;;; Run: python3 lumbda.py --fast examples/generator.lsp
(define (make-generator thunk)
(let ((k #f) (done #f))

View file

@ -10,9 +10,9 @@
;;; server throughput shows up.
;;;
;;; Usage:
;;; python3 uncommonlisp.py --fast examples/http-client-bench.lsp
;;; ./c/uncommonlisp examples/http-client-bench.lsp
;;; ./asm/uncommonlisp < examples/http-client-bench.lsp
;;; python3 lumbda.py --fast examples/http-client-bench.lsp
;;; ./c/lumbda examples/http-client-bench.lsp
;;; ./asm/lumbda < examples/http-client-bench.lsp
;;;
;;; Override N or PORT by pre-setting *n-requests* / *port* before load.

View file

@ -56,7 +56,7 @@
(cond
((string=? path "/")
(http-response "200 OK" "text/html"
"<!doctype html><title>uncommonlisp</title><h1>feedback is all you need</h1>"))
"<!doctype html><title>lumbda</title><h1>feedback is all you need</h1>"))
((string=? path "/bench")
(http-response "200 OK" "text/plain" *bench-body*))
(else

View file

@ -3,9 +3,9 @@
;;; Runs identically in Python, C, and asm. The only primitives used are
;;; the six socket builtins + display/string-append/substring.
;;;
;;; python3 uncommonlisp.py --fast examples/http-server.lsp
;;; ./c/uncommonlisp examples/http-server.lsp
;;; ./asm/uncommonlisp < examples/http-server.lsp
;;; python3 lumbda.py --fast examples/http-server.lsp
;;; ./c/lumbda examples/http-server.lsp
;;; ./asm/lumbda < examples/http-server.lsp
;;;
;;; Default port 8080. First-line dispatch: GET / → greeting page.
;;; GET /bench → 1 KB body for throughput benchmarks.
@ -76,7 +76,7 @@
(cond
((string=? path "/")
(http-response "200 OK" "text/html"
"<!doctype html><title>uncommonlisp</title><h1>feedback is all you need</h1><p>portable HTTP in Scheme.</p>"))
"<!doctype html><title>lumbda</title><h1>feedback is all you need</h1><p>portable HTTP in Scheme.</p>"))
((string=? path "/bench")
(http-response "200 OK" "text/plain" *bench-body*))
((string=? path "/hello")
@ -110,7 +110,7 @@
(server-loop (+ n 1) snap))))
(define (serve)
(display "uncommonlisp http server on :") (display *port*)
(display "lumbda http server on :") (display *port*)
(display " (max ") (display *max-requests*) (display " requests)") (newline)
(server-loop 0 (heap-snapshot)))

View file

@ -1,5 +1,5 @@
;;; mergesort.lsp — functional merge sort
;;; Run: python3 uncommonlisp.py --fast examples/mergesort.lsp
;;; Run: python3 lumbda.py --fast examples/mergesort.lsp
(define (merge a b)
(cond ((null? a) b)

View file

@ -1,5 +1,5 @@
;;; objects.lsp — record types, closures as objects, hash tables
;;; Run: python3 uncommonlisp.py examples/objects.lsp
;;; Run: python3 lumbda.py examples/objects.lsp
;; Record types with inheritance
(define-record-type <point>
@ -42,7 +42,7 @@
;; Hash table
(define ht (make-hash-table))
(hash-table-set! ht 'name "uncommonlisp")
(hash-table-set! ht 'name "lumbda")
(hash-table-set! ht 'version "1.0.0")
(hash-table-set! ht 'features '(bytecode continuations macros))
(display "Name: ") (display (hash-table-ref ht 'name)) (newline)

View file

@ -7,9 +7,9 @@
;;; lines of string-munging plus (read-from-string) + (eval).
;;;
;;; Usage (server must be running first — see portal-http-server.lsp):
;;; python3 uncommonlisp.py --fast examples/portal-http-client.lsp
;;; ./c/uncommonlisp examples/portal-http-client.lsp
;;; ./asm/uncommonlisp < examples/portal-http-client.lsp
;;; python3 lumbda.py --fast examples/portal-http-client.lsp
;;; ./c/lumbda examples/portal-http-client.lsp
;;; ./asm/lumbda < examples/portal-http-client.lsp
(define *host* "127.0.0.1")
(define *port* 9085)

View file

@ -10,9 +10,9 @@
;;; sockets, using the language itself as the wire format.
;;;
;;; Runs byte-identically in Python, C, and asm:
;;; python3 uncommonlisp.py --fast examples/portal-http-server.lsp
;;; ./c/uncommonlisp examples/portal-http-server.lsp
;;; ./asm/uncommonlisp < examples/portal-http-server.lsp
;;; python3 lumbda.py --fast examples/portal-http-server.lsp
;;; ./c/lumbda examples/portal-http-server.lsp
;;; ./asm/lumbda < examples/portal-http-server.lsp
;;;
;;; Default port 9085.
@ -53,7 +53,7 @@
(define (portal-body)
;; Produce the S-expression portal as a single string.
(string-append
";; uncommonlisp portable portal\n"
";; lumbda portable portal\n"
"(define counter " (number->string counter) ")\n"
"(define my-int " (number->string my-int) ")\n"
"(define my-list '(" (list->string my-list) "))\n"
@ -91,7 +91,7 @@
(http-response "200 OK" "application/scheme" (portal-body)))
((string=? path "/")
(http-response "200 OK" "text/html"
"<!doctype html><title>portal-http</title><h1>uncommonlisp portal-http</h1><p>GET /portal returns the S-expression portal.</p>"))
"<!doctype html><title>portal-http</title><h1>lumbda portal-http</h1><p>GET /portal returns the S-expression portal.</p>"))
(else
(http-response "404 Not Found" "text/plain"
(string-append "not found: " path "\n"))))))

View file

@ -1,9 +1,9 @@
;;; portal-prime.lsp — portal a primality test between machines
;;;
;;; Machine A: python3 uncommonlisp.py --fast examples/portal-prime.lsp
;;; Machine A: python3 lumbda.py --fast examples/portal-prime.lsp
;;; (starts computing, saves checkpoint to prime-state.portal)
;;;
;;; Machine B: python3 uncommonlisp.py --portal-resume prime-state.portal
;;; Machine B: python3 lumbda.py --portal-resume prime-state.portal
;;; (resumes from checkpoint, finishes the computation)
(define (prime? n)

View file

@ -13,9 +13,9 @@
;;; until both hold the union of what either knew.
;;;
;;; Usage (start the server first):
;;; python3 uncommonlisp.py --fast examples/proof-netspace-client.lsp
;;; ./c/uncommonlisp examples/proof-netspace-client.lsp
;;; ./asm/uncommonlisp < examples/proof-netspace-client.lsp
;;; python3 lumbda.py --fast examples/proof-netspace-client.lsp
;;; ./c/lumbda examples/proof-netspace-client.lsp
;;; ./asm/lumbda < examples/proof-netspace-client.lsp
(define *host* "127.0.0.1")
(define *port* 9086)

View file

@ -12,9 +12,9 @@
;;;
;;; Portable across Python, C, and asm. Example:
;;;
;;; python3 uncommonlisp.py --fast examples/proof-netspace-server.lsp
;;; ./c/uncommonlisp --fast examples/proof-netspace-server.lsp
;;; ./asm/uncommonlisp < examples/proof-netspace-server.lsp
;;; python3 lumbda.py --fast examples/proof-netspace-server.lsp
;;; ./c/lumbda --fast examples/proof-netspace-server.lsp
;;; ./asm/lumbda < examples/proof-netspace-server.lsp
;;;
;;; For multi-node demos see proof-netspace-node-{a,b}.lsp.

View file

@ -11,9 +11,9 @@
;;; because both sides already have a reader and an evaluator.
;;;
;;; Usage:
;;; python3 uncommonlisp.py --fast examples/repl-server.lsp
;;; ./c/uncommonlisp examples/repl-server.lsp
;;; ./asm/uncommonlisp < examples/repl-server.lsp
;;; python3 lumbda.py --fast examples/repl-server.lsp
;;; ./c/lumbda examples/repl-server.lsp
;;; ./asm/lumbda < examples/repl-server.lsp
;;;
;;; Then from a client:
;;; (define x 42) ; server mutates its global env

View file

@ -5,9 +5,9 @@
;;; because they agree on S-expression framing.
;;;
;;; Usage:
;;; python3 uncommonlisp.py --fast examples/rpc-client.lsp
;;; ./c/uncommonlisp examples/rpc-client.lsp
;;; ./asm/uncommonlisp < examples/rpc-client.lsp
;;; python3 lumbda.py --fast examples/rpc-client.lsp
;;; ./c/lumbda examples/rpc-client.lsp
;;; ./asm/lumbda < examples/rpc-client.lsp
;;;
;;; Override *target-port* before loading to hit either rpc-server (9080)
;;; or repl-server (9081).

View file

@ -6,9 +6,9 @@
;;; asm backend, where the same .lsp runs at every hop and the wire
;;; format (Scheme source) needs no translation.
;;;
;;; python3 uncommonlisp.py --fast examples/rpc-relay.lsp
;;; ./c/uncommonlisp examples/rpc-relay.lsp
;;; ./asm/uncommonlisp < examples/rpc-relay.lsp
;;; python3 lumbda.py --fast examples/rpc-relay.lsp
;;; ./c/lumbda examples/rpc-relay.lsp
;;; ./asm/lumbda < examples/rpc-relay.lsp
;;;
;;; Override *listen-port* / *backend-port* by pre-defining before load
;;; (or edit here for a one-off demo).

View file

@ -5,9 +5,9 @@
;;; the parser on each side is already the right tool.
;;;
;;; Runs byte-identically in Python, C, and asm:
;;; python3 uncommonlisp.py --fast examples/rpc-server.lsp
;;; ./c/uncommonlisp examples/rpc-server.lsp
;;; ./asm/uncommonlisp < examples/rpc-server.lsp
;;; python3 lumbda.py --fast examples/rpc-server.lsp
;;; ./c/lumbda examples/rpc-server.lsp
;;; ./asm/lumbda < examples/rpc-server.lsp
;;;
;;; Request examples (send as plain text, one per connection):
;;; (ping) -> pong

View file

@ -12,7 +12,7 @@
;;; direction. N nodes in a mesh converge after N-1 spiral passes.
;;;
;;; Usage (start both nodes first):
;;; python3 uncommonlisp.py --fast examples/spiral-client.lsp
;;; python3 lumbda.py --fast examples/spiral-client.lsp
(define *host* "127.0.0.1")
(define *port-a* 9086)

View file

@ -19,9 +19,9 @@ trap 'pkill -9 -u "$USER" -f "proof-netspace-node|spiral-client" 2>/dev/null ||
IMPL="${1:-python}"
case "$IMPL" in
python) BIN="python3 uncommonlisp.py --fast" ;;
c) BIN="./c/uncommonlisp --fast" ;;
asm) BIN="asm/uncommonlisp" ;;
python) BIN="python3 lumbda.py --fast" ;;
c) BIN="./c/lumbda --fast" ;;
asm) BIN="asm/lumbda" ;;
*) echo "unknown impl: $IMPL (expected python|c|asm)"; exit 1 ;;
esac

View file

@ -1,5 +1,5 @@
#!/bin/bash
# friction.sh — Head-to-head benchmark: CPython vs uncommonlisp-Python vs uncommonlisp-C
# friction.sh — Head-to-head benchmark: CPython vs lumbda-Python vs lumbda-C
#
# Usage: bash friction.sh
@ -7,7 +7,7 @@ set -e
cd "$(dirname "$0")"
echo "═══════════════════════════════════════════════════════════════"
echo "Friction Benchmark: CPython vs uncommonlisp-Python vs uncommonlisp-C"
echo "Friction Benchmark: CPython vs lumbda-Python vs lumbda-C"
echo "═══════════════════════════════════════════════════════════════"
echo
@ -27,9 +27,9 @@ def fib(n):
t=time.perf_counter(); r=fib(35); print(f'{(time.perf_counter()-t)*1000:.3f}ms result={r}')
"
printf " uncommonlisp-Python: "
printf " lumbda-Python: "
python3 -c "
import time; from uncommonlisp import *
import time; from lumbda import *
g=make_global_env(); [leval(e,g) for e in read_all(PRELUDE)]
[leval(e,g) for e in read_all('(auto-compile! #t)')]
[leval(e,g) for e in read_all('(define (fib n) (let loop ((a 0) (b 1) (i 0)) (if (= i n) a (loop b (+ a b) (+ i 1)))))')]
@ -37,8 +37,8 @@ t=time.perf_counter(); r=[leval(e,g) for e in read_all('(fib 35)')][-1]
print(f'{(time.perf_counter()-t)*1000:.3f}ms result={r}')
"
printf " uncommonlisp-C: "
/usr/bin/time -f "%e s" ./c/uncommonlisp -e '(define (fib n) (let loop ((a 0) (b 1) (i 0)) (if (= i n) a (loop b (+ a b) (+ i 1))))) (display (fib 35)) (newline)' 2>&1
printf " lumbda-C: "
/usr/bin/time -f "%e s" ./c/lumbda -e '(define (fib n) (let loop ((a 0) (b 1) (i 0)) (if (= i n) a (loop b (+ a b) (+ i 1))))) (display (fib 35)) (newline)' 2>&1
echo
@ -54,9 +54,9 @@ def fib(n):
t=time.perf_counter(); r=fib(20); print(f'{(time.perf_counter()-t)*1000:.3f}ms result={r}')
"
printf " uncommonlisp-Python: "
printf " lumbda-Python: "
python3 -c "
import time,sys; sys.setrecursionlimit(50000); from uncommonlisp import *
import time,sys; sys.setrecursionlimit(50000); from lumbda import *
g=make_global_env(); [leval(e,g) for e in read_all(PRELUDE)]
[leval(e,g) for e in read_all('(auto-compile! #t)')]
[leval(e,g) for e in read_all('(define (fib n) (if (<= n 1) n (+ (fib (- n 1)) (fib (- n 2)))))')]
@ -64,8 +64,8 @@ t=time.perf_counter(); r=[leval(e,g) for e in read_all('(fib 20)')][-1]
print(f'{(time.perf_counter()-t)*1000:.3f}ms result={r}')
"
printf " uncommonlisp-C: "
/usr/bin/time -f "%e s" ./c/uncommonlisp -e '(define (fib n) (if (<= n 1) n (+ (fib (- n 1)) (fib (- n 2))))) (display (fib 20)) (newline)' 2>&1
printf " lumbda-C: "
/usr/bin/time -f "%e s" ./c/lumbda -e '(define (fib n) (if (<= n 1) n (+ (fib (- n 1)) (fib (- n 2))))) (display (fib 20)) (newline)' 2>&1
echo
@ -82,9 +82,9 @@ def ack(m,n):
t=time.perf_counter(); r=ack(3,4); print(f'{(time.perf_counter()-t)*1000:.3f}ms result={r}')
"
printf " uncommonlisp-Python: "
printf " lumbda-Python: "
python3 -c "
import time,sys; sys.setrecursionlimit(50000); from uncommonlisp import *
import time,sys; sys.setrecursionlimit(50000); from lumbda import *
g=make_global_env(); [leval(e,g) for e in read_all(PRELUDE)]
[leval(e,g) for e in read_all('(auto-compile! #t)')]
[leval(e,g) for e in read_all('(define (ack m n) (cond ((= m 0) (+ n 1)) ((= n 0) (ack (- m 1) 1)) (else (ack (- m 1) (ack m (- n 1))))))')]
@ -92,8 +92,8 @@ t=time.perf_counter(); r=[leval(e,g) for e in read_all('(ack 3 4)')][-1]
print(f'{(time.perf_counter()-t)*1000:.3f}ms result={r}')
"
printf " uncommonlisp-C: "
/usr/bin/time -f "%e s" ./c/uncommonlisp -e '(define (ack m n) (cond ((= m 0) (+ n 1)) ((= n 0) (ack (- m 1) 1)) (else (ack (- m 1) (ack m (- n 1)))))) (display (ack 3 4)) (newline)' 2>&1
printf " lumbda-C: "
/usr/bin/time -f "%e s" ./c/lumbda -e '(define (ack m n) (cond ((= m 0) (+ n 1)) ((= n 0) (ack (- m 1) 1)) (else (ack (- m 1) (ack m (- n 1)))))) (display (ack 3 4)) (newline)' 2>&1
echo
@ -110,9 +110,9 @@ def s(n):
t=time.perf_counter(); r=s(50000); print(f'{(time.perf_counter()-t)*1000:.3f}ms result={r}')
"
printf " uncommonlisp-Python: "
printf " lumbda-Python: "
python3 -c "
import time; from uncommonlisp import *
import time; from lumbda import *
g=make_global_env(); [leval(e,g) for e in read_all(PRELUDE)]
[leval(e,g) for e in read_all('(auto-compile! #t)')]
[leval(e,g) for e in read_all('(define (sum-to n) (let loop ((i n) (acc 0)) (if (= i 0) acc (loop (- i 1) (+ acc i)))))')]
@ -120,8 +120,8 @@ t=time.perf_counter(); r=[leval(e,g) for e in read_all('(sum-to 50000)')][-1]
print(f'{(time.perf_counter()-t)*1000:.3f}ms result={r}')
"
printf " uncommonlisp-C: "
/usr/bin/time -f "%e s" ./c/uncommonlisp -e '(define (sum-to n) (let loop ((i n) (acc 0)) (if (= i 0) acc (loop (- i 1) (+ acc i))))) (display (sum-to 50000)) (newline)' 2>&1
printf " lumbda-C: "
/usr/bin/time -f "%e s" ./c/lumbda -e '(define (sum-to n) (let loop ((i n) (acc 0)) (if (= i 0) acc (loop (- i 1) (+ acc i))))) (display (sum-to 50000)) (newline)' 2>&1
echo
echo "═══════════════════════════════════════════════════════════════"

View file

@ -1,9 +1,9 @@
#!/usr/bin/env python3
"""
uncommonlisp — a Lisp in one Python file.
Usage: python3 uncommonlisp.py [script.lsp] # run a file
python3 uncommonlisp.py # interactive REPL
python3 uncommonlisp.py -e '(+ 1 2)' # eval expression
lumbda — a Lisp in one Python file.
Usage: python3 lumbda.py [script.lsp] # run a file
python3 lumbda.py # interactive REPL
python3 lumbda.py -e '(+ 1 2)' # eval expression
"""
import sys, re, math, itertools, os as _os
from fractions import Fraction
@ -2217,7 +2217,7 @@ def portal_save(env, path, continuation=None):
"""Save machine state to a .portal file."""
ser = _PortalSerializer()
state = {
'format': 'uncommonlisp-portal-v1',
'format': 'lumbda-portal-v1',
'env': ser.serialize_env(env),
'continuation': ser.serialize_continuation(continuation) if continuation else None,
'auto_compile': _auto_compile[0],
@ -2231,7 +2231,7 @@ def portal_resume(path, base_env=None):
"""Resume machine state from a .portal file. Returns (env, continuation_or_None)."""
with open(path) as f:
state = _json.load(f)
if state.get('format') != 'uncommonlisp-portal-v1':
if state.get('format') != 'lumbda-portal-v1':
raise LispErr(f'portal: unsupported format: {state.get("format")}')
if base_env is None:
base_env = make_global_env()
@ -3488,7 +3488,7 @@ def make_global_env():
d(S('else'), True)
d(S('...'), S('...'))
d(S('*version*'), '1.0.0')
d(S('*name*'), 'uncommonlisp')
d(S('*name*'), 'lumbda')
return g
@ -3621,7 +3621,7 @@ PRELUDE = r"""
def repl(env, prompt='λ> ', quiet=False):
if not quiet:
print(f'uncommonlisp {env.lookup(S("*version*"))} '
print(f'lumbda {env.lookup(S("*version*"))} '
f'— (exit) to quit, (load "file.lsp") to load')
buf = ''
while True:
@ -3674,11 +3674,11 @@ def main():
# --help / -h
if '--help' in args or '-h' in args:
print('''uncommonlisp — a Scheme in one Python file
print('''lumbda — a Scheme in one Python file
Usage: uncommonlisp [options] [script.lsp] [args...]
uncommonlisp -e '(+ 1 2)'
uncommonlisp (interactive REPL)
Usage: lumbda [options] [script.lsp] [args...]
lumbda -e '(+ 1 2)'
lumbda (interactive REPL)
Options:
-e EXPR evaluate expression and print result
@ -3692,7 +3692,7 @@ Features: R7RS core, bytecode compiler, full continuations, macros,
# --version / -v
if '--version' in args or '-v' in args:
print(f'uncommonlisp 1.0.0'); return
print(f'lumbda 1.0.0'); return
# --fast / -f: enable auto-compile
if '--fast' in args or '-f' in args:
@ -3703,7 +3703,7 @@ Features: R7RS core, bytecode compiler, full continuations, macros,
if '--compile' in args:
args = [a for a in args if a != '--compile']
if not args:
print('usage: uncommonlisp --compile file.lsp', file=sys.stderr); sys.exit(1)
print('usage: lumbda --compile file.lsp', file=sys.stderr); sys.exit(1)
path = args[0]; out = path.rsplit('.', 1)[0] + '.lspc'
_auto_compile[0] = True
_load(path, g)
@ -3721,7 +3721,7 @@ Features: R7RS core, bytecode compiler, full continuations, macros,
if '--portal-resume' in args:
args = [a for a in args if a != '--portal-resume']
if not args:
print('usage: uncommonlisp --portal-resume state.portal', file=sys.stderr); sys.exit(1)
print('usage: lumbda --portal-resume state.portal', file=sys.stderr); sys.exit(1)
path = args[0]
env, cont = portal_resume(path, g)
if cont is not None:
@ -3739,7 +3739,7 @@ Features: R7RS core, bytecode compiler, full continuations, macros,
# -e 'expr' mode
if args and args[0] == '-e':
if len(args) < 2:
print('usage: uncommonlisp -e <expression>', file=sys.stderr)
print('usage: lumbda -e <expression>', file=sys.stderr)
sys.exit(1)
for expr in read_all(args[1]):
result = leval(expr, g)

View file

@ -1,10 +1,10 @@
#!/bin/bash
# benchmark.sh — Run EML proof in both Python and uncommonlisp, compare times
# benchmark.sh — Run EML proof in both Python and lumbda, compare times
#
# Usage: cd proof && bash benchmark.sh
echo "═══════════════════════════════════════════════════════════════"
echo "EML Universality Proof — Benchmark: Python vs uncommonlisp"
echo "EML Universality Proof — Benchmark: Python vs lumbda"
echo "═══════════════════════════════════════════════════════════════"
echo
@ -13,9 +13,9 @@ echo "---"
time python3 eml_proof.py
echo
echo ">>> uncommonlisp implementation (--fast = bytecode compiled)"
echo ">>> lumbda implementation (--fast = bytecode compiled)"
echo "---"
time python3 ../uncommonlisp.py --fast eml_proof.lsp
time python3 ../lumbda.py --fast eml_proof.lsp
echo
echo "═══════════════════════════════════════════════════════════════"

View file

@ -8,7 +8,7 @@ with constant 1 generates all elementary functions (arXiv:2603.21852v2).
| Approach | Time | Guarantee | Friction |
|----------|------|-----------|----------|
| Python (numerical) | 0.04s | 1e-10 tolerance | Low |
| uncommonlisp (numerical) | 59s | 1e-10 tolerance | High |
| lumbda (numerical) | 59s | 1e-10 tolerance | High |
| Lean 4 (formal proof) | 1.5s | kernel-verified | Medium |
## Analysis
@ -16,7 +16,7 @@ with constant 1 generates all elementary functions (arXiv:2603.21852v2).
**The formal proof is 40x faster than brute-force search and provides
mathematical certainty instead of floating-point tolerance.**
The numerical approaches (Python and uncommonlisp) perform O(N²) pairwise
The numerical approaches (Python and lumbda) perform O(N²) pairwise
enumeration of EML trees, evaluating at transcendental test points and
comparing against target functions. This is MOAD-0001 at the proof layer:
quadratic search friction where algebraic reasoning suffices.

View file

@ -1,9 +1,9 @@
;;; eml_proof.lsp — Verify EML universality in uncommonlisp
;;; eml_proof.lsp — Verify EML universality in lumbda
;;;
;;; eml(x, y) = exp(x) - ln(y) generates all elementary functions.
;;; Reference: "All elementary functions from a single operator" (arXiv:2603.21852v2)
;;;
;;; Run: python3 uncommonlisp.py --fast proof/eml_proof.lsp
;;; Run: python3 lumbda.py --fast proof/eml_proof.lsp
;;; ═══════════════════════════════════════════════════════════════════
;;; EML operator and test infrastructure
@ -35,7 +35,7 @@
(define gamma 0.5772156649015329)
(define apery 1.2020569031595943)
(display "EML Universality Proof — uncommonlisp") (newline)
(display "EML Universality Proof — lumbda") (newline)
(display "eml(x, y) = exp(x) - ln(y)") (newline)
(display "======================================================================") (newline)
@ -118,7 +118,7 @@
(display "----------------------------------------------------------------------") (newline)
(display " Key insight: ln(negative) = ln(|neg|) + iπ") (newline)
(display " From -1, ln(-1) = iπ, giving access to complex plane.") (newline)
(display " uncommonlisp uses real arithmetic; verifying the chain:") (newline)
(display " lumbda uses real arithmetic; verifying the chain:") (newline)
(newline)
;; Verify the real-arithmetic building blocks that WOULD give complex access:

View file

@ -12,9 +12,9 @@
;;; that checks it live in the same file.
;;;
;;; Runs byte-identically in Python, C, and asm:
;;; python3 uncommonlisp.py --fast proof/eml_proof_in_lumbda.lsp
;;; ./c/uncommonlisp proof/eml_proof_in_lumbda.lsp
;;; ./asm/uncommonlisp < proof/eml_proof_in_lumbda.lsp
;;; python3 lumbda.py --fast proof/eml_proof_in_lumbda.lsp
;;; ./c/lumbda proof/eml_proof_in_lumbda.lsp
;;; ./asm/lumbda < proof/eml_proof_in_lumbda.lsp
;;; ═══════════════════════════════════════════════════════════════
;;; Term-rewriting engine

View file

@ -1,6 +1,6 @@
;;; stdlib.lsp — standard library for uncommonlisp
;;; stdlib.lsp — standard library for lumbda
;;; Load with: (load "stdlib.lsp")
;;; Automatically loaded by the interpreter if found next to uncommonlisp.py.
;;; Automatically loaded by the interpreter if found next to lumbda.py.
;;;; ── Syntax-rules versions of core macros ────────────────────────────────

View file

@ -1,6 +1,6 @@
#!/usr/bin/env python3
"""
tests.py — unit, integration, and functional tests for uncommonlisp.
tests.py — unit, integration, and functional tests for lumbda.
Run: python3 tests.py [-v]
"""
@ -8,7 +8,7 @@ import sys, io, unittest, math, textwrap
sys.setrecursionlimit(200) # intentionally low — proves TCO works
# ── import the interpreter ────────────────────────────────────────────────────
from uncommonlisp import (
from lumbda import (
Symbol, S, NIL, Pair, Proc, Macro, VOID, EOF, LispErr,
show, _tokenize, _tokenize_lines, read_all, _L, _P, _truthy, _formals, _equal,
Env, _qq, leval, _call, make_global_env, PRELUDE,
@ -67,7 +67,7 @@ class TestSymbol(unittest.TestCase):
class TestNil(unittest.TestCase):
def test_singleton(self):
from uncommonlisp import _Nil
from lumbda import _Nil
assert _Nil() is NIL
def test_falsy(self):
@ -1509,7 +1509,7 @@ class TestCommandLine(unittest.TestCase):
def _run(self, *args, input_text=None):
import subprocess
result = subprocess.run(
[sys.executable, 'uncommonlisp.py'] + list(args),
[sys.executable, 'lumbda.py'] + list(args),
capture_output=True, text=True, input=input_text,
cwd='/home/fox/git/uncommonlisp'
)
@ -1670,7 +1670,7 @@ class TestStringPorts(unittest.TestCase):
def test_open_input_string_eof(self):
r = run('(let ((p (open-input-string ""))) (read p))', self.g)
from uncommonlisp import EOF
from lumbda import EOF
assert r is EOF
def test_open_input_string_read_char(self):
@ -1728,7 +1728,7 @@ class TestErrorObjects(unittest.TestCase):
def test_error_object_irritants_empty(self):
r = run('(guard (e (#t (error-object-irritants e))) (error "no-irritants"))', self.g)
from uncommonlisp import NIL
from lumbda import NIL
assert r is NIL
def test_with_exception_handler_gets_error_object(self):
@ -2717,7 +2717,7 @@ class TestSourceMaps(unittest.TestCase):
f.write('(define x 1)\n(define y 2)\n(+ x y)')
path = f.name
try:
from uncommonlisp import _load
from lumbda import _load
env = fresh()
_load(path, env)
assert env.lookup(S('x')) == 1
@ -3029,7 +3029,7 @@ class TestBytecodeSerialization(unittest.TestCase):
lspc = path.rsplit('.', 1)[0] + '.lspc'
try:
result = subprocess.run(
['python3', 'uncommonlisp.py', '--compile', path],
['python3', 'lumbda.py', '--compile', path],
capture_output=True, text=True, timeout=30)
assert result.returncode == 0
assert os.path.exists(lspc)
@ -3177,7 +3177,7 @@ class TestPortal(unittest.TestCase):
try:
portal_save(self.g, path)
result = subprocess.run(
['python3', 'uncommonlisp.py', '--portal-resume', path,
['python3', 'lumbda.py', '--portal-resume', path,
'-e', '(display answer)'],
capture_output=True, text=True, timeout=30)
# portal-resume loads state, then -e isn't processed (portal-resume returns)
@ -3195,7 +3195,7 @@ class TestPortal(unittest.TestCase):
portal_save(self.g, path)
with open(path) as f:
data = json.load(f)
assert data['format'] == 'uncommonlisp-portal-v1'
assert data['format'] == 'lumbda-portal-v1'
assert 'objects' in data
assert 'env' in data
finally:

View file

@ -60,15 +60,15 @@ best_of_two() {
}
echo "── Python (--fast) ──"
best_of_two "python3 uncommonlisp.py --fast /tmp/bench-3way.lsp"
best_of_two "python3 lumbda.py --fast /tmp/bench-3way.lsp"
echo
echo "── C (--fast) ──"
best_of_two "c/uncommonlisp --fast /tmp/bench-3way.lsp"
best_of_two "c/lumbda --fast /tmp/bench-3way.lsp"
echo
echo "── asm ──"
best_of_two "asm/uncommonlisp < /tmp/bench-3way.lsp"
best_of_two "asm/lumbda < /tmp/bench-3way.lsp"
echo
rm -f /tmp/bench-3way.lsp

View file

@ -6,7 +6,7 @@ set -e
cd "$(dirname "$0")/.."
ulimit -v 524288
trap 'pkill -9 -u "$USER" -f "asm/uncommonlisp" 2>/dev/null || true' EXIT
trap 'pkill -9 -u "$USER" -f "asm/lumbda" 2>/dev/null || true' EXIT
make -s -C asm all
@ -20,7 +20,7 @@ run_phase() {
echo "(define *workload* $workload)"
echo "(define *mode* $mode)"
cat examples/bench-gc-adaptive.lsp
} | timeout 60 ./asm/uncommonlisp-gc
} | timeout 60 ./asm/lumbda-gc
echo ""
}
@ -31,7 +31,7 @@ run_phase "hostile" 1 1 "adaptive"
run_phase "mixed" 2 0 "greedy"
run_phase "mixed" 2 1 "adaptive"
if pgrep -u "$USER" -f 'asm/uncommonlisp' > /dev/null; then
if pgrep -u "$USER" -f 'asm/lumbda' > /dev/null; then
echo "STRAGGLER" >&2
exit 1
fi

View file

@ -7,12 +7,12 @@ set -e
cd "$(dirname "$0")/.."
ulimit -v 524288
trap 'pkill -9 -u "$USER" -f "asm/uncommonlisp" 2>/dev/null || true' EXIT
trap 'pkill -9 -u "$USER" -f "asm/lumbda" 2>/dev/null || true' EXIT
make -s -C asm all
echo "== asm (naive GC, with arena as meta fast path) =="
./asm/uncommonlisp-gc < examples/bench-gc-arena.lsp &
./asm/lumbda-gc < examples/bench-gc-arena.lsp &
pid=$!
peak=0
while kill -0 "$pid" 2>/dev/null; do
@ -24,7 +24,7 @@ wait "$pid" || true
echo ""
echo "peak_rss_kb=$peak"
if pgrep -u "$USER" -f 'asm/uncommonlisp' > /dev/null; then
if pgrep -u "$USER" -f 'asm/lumbda' > /dev/null; then
echo "STRAGGLER" >&2
exit 1
fi

View file

@ -96,9 +96,9 @@ run_case() {
# to completion rather than OOM'd.
VCAP=${VCAP:-524288}
run_case "asm no-GC + snapshot loop" "./asm/uncommonlisp" "examples/http-server.lsp" "$VCAP" || true
run_case "asm GC + snapshot loop" "./asm/uncommonlisp-gc" "examples/http-server.lsp" "$VCAP" || true
run_case "asm no-GC + no snapshot" "./asm/uncommonlisp" "examples/http-server-noarena.lsp" "$VCAP" || true
run_case "asm GC + no snapshot" "./asm/uncommonlisp-gc" "examples/http-server-noarena.lsp" "$VCAP" || true
run_case "asm no-GC + snapshot loop" "./asm/lumbda" "examples/http-server.lsp" "$VCAP" || true
run_case "asm GC + snapshot loop" "./asm/lumbda-gc" "examples/http-server.lsp" "$VCAP" || true
run_case "asm no-GC + no snapshot" "./asm/lumbda" "examples/http-server-noarena.lsp" "$VCAP" || true
run_case "asm GC + no snapshot" "./asm/lumbda-gc" "examples/http-server-noarena.lsp" "$VCAP" || true
printf "\n"

View file

@ -7,7 +7,7 @@ set -e
cd "$(dirname "$0")/.."
ulimit -v 524288
trap 'pkill -9 -u "$USER" -f "asm/uncommonlisp" 2>/dev/null || true' EXIT
trap 'pkill -9 -u "$USER" -f "asm/lumbda" 2>/dev/null || true' EXIT
make -s -C asm all
@ -35,12 +35,12 @@ run_with_sampling() {
echo ""
}
run_with_sampling ./asm/uncommonlisp "asm (no GC, 64 MB chunks)"
run_with_sampling ./asm/uncommonlisp-gc "asm (naive GC, 1 MB chunks)"
run_with_sampling ./asm/lumbda "asm (no GC, 64 MB chunks)"
run_with_sampling ./asm/lumbda-gc "asm (naive GC, 1 MB chunks)"
rm -f /tmp/gc-bench.out
if pgrep -u "$USER" -f 'asm/uncommonlisp' > /dev/null; then
if pgrep -u "$USER" -f 'asm/lumbda' > /dev/null; then
echo "STRAGGLER detected" >&2
exit 1
fi

View file

@ -5,26 +5,26 @@ set +e
cd "$(dirname "$0")/.."
ulimit -v 524288
trap 'pkill -9 -u "$USER" -f "asm/uncommonlisp" 2>/dev/null || true' EXIT
trap 'pkill -9 -u "$USER" -f "asm/lumbda" 2>/dev/null || true' EXIT
# Build if needed
if [ ! -x asm/uncommonlisp ] || [ asm/uncommonlisp.s -nt asm/uncommonlisp ]; then
if [ ! -x asm/lumbda ] || [ asm/lumbda.s -nt asm/lumbda ]; then
make -s asm-build
fi
echo "── asm no-GC ──"
timeout 60 ./asm/uncommonlisp < examples/bench-hashset.lsp
timeout 60 ./asm/lumbda < examples/bench-hashset.lsp
echo ""
echo "── asm GC (GC_NAIVE build) ──"
# Under GC_NAIVE the heap is 1 MB per chunk; build-list(K=500) runs
# into the bump threshold and triggers implicit GC. That's the
# intended comparison — same primitives, different allocator.
timeout 60 ./asm/uncommonlisp-gc < examples/bench-hashset.lsp
timeout 60 ./asm/lumbda-gc < examples/bench-hashset.lsp
# Verify cleanup. pgrep with -x matches the exact command basename
# so it doesn't false-positive on the parent shell.
if pgrep -u "$USER" -x uncommonlisp > /dev/null || \
pgrep -u "$USER" -x uncommonlisp-gc > /dev/null; then
if pgrep -u "$USER" -x lumbda > /dev/null || \
pgrep -u "$USER" -x lumbda-gc > /dev/null; then
echo "STRAGGLER asm binary detected" >&2
exit 1
fi

View file

@ -52,17 +52,17 @@ echo "════════════════════════
printf " %-38s %s\n" "Lumbda tier" "cold cached"
printf " %-38s %s\n" "─────────────────────────────────────" "───────────────"
printf " %-38s %4s ms %4s ms\n" "Python --fast" \
"$(bestof_cold 'python3 uncommonlisp.py --fast proof/eml_proof_in_lumbda.lsp')" \
"$(bestof_cached 'python3 uncommonlisp.py --fast proof/eml_proof_in_lumbda.lsp')"
"$(bestof_cold 'python3 lumbda.py --fast proof/eml_proof_in_lumbda.lsp')" \
"$(bestof_cached 'python3 lumbda.py --fast proof/eml_proof_in_lumbda.lsp')"
printf " %-38s %4s ms %4s ms\n" "C (tree-walker)" \
"$(bestof_cold 'c/uncommonlisp proof/eml_proof_in_lumbda.lsp')" \
"$(bestof_cached 'c/uncommonlisp proof/eml_proof_in_lumbda.lsp')"
"$(bestof_cold 'c/lumbda proof/eml_proof_in_lumbda.lsp')" \
"$(bestof_cached 'c/lumbda proof/eml_proof_in_lumbda.lsp')"
printf " %-38s %4s ms %4s ms\n" "C --fast (bytecode VM)" \
"$(bestof_cold 'timeout 15 c/uncommonlisp --fast proof/eml_proof_in_lumbda.lsp')" \
"$(bestof_cached 'timeout 15 c/uncommonlisp --fast proof/eml_proof_in_lumbda.lsp')"
"$(bestof_cold 'timeout 15 c/lumbda --fast proof/eml_proof_in_lumbda.lsp')" \
"$(bestof_cached 'timeout 15 c/lumbda --fast proof/eml_proof_in_lumbda.lsp')"
printf " %-38s %4s ms %4s ms\n" "asm" \
"$(bestof_cold 'asm/uncommonlisp < proof/eml_proof_in_lumbda.lsp')" \
"$(bestof_cached 'asm/uncommonlisp < proof/eml_proof_in_lumbda.lsp')"
"$(bestof_cold 'asm/lumbda < proof/eml_proof_in_lumbda.lsp')" \
"$(bestof_cached 'asm/lumbda < proof/eml_proof_in_lumbda.lsp')"
echo ""
echo " Lean 4 comparison:"

View file

@ -1,8 +1,8 @@
;;; functional.lsp — Shared functional test suite
;;; Runs identically in both Python and C implementations.
;;;
;;; Python: python3 uncommonlisp.py --fast tests/functional.lsp
;;; C: ./c/uncommonlisp tests/functional.lsp
;;; Python: python3 lumbda.py --fast tests/functional.lsp
;;; C: ./c/lumbda tests/functional.lsp
;;;
;;; Output: lines of "PASS: name" or "FAIL: name got=X expected=Y"
;;; Exit: displays summary at end
@ -595,11 +595,11 @@
;;; File I/O: write-file / file->string round-trip
;;; ═══════════════════════════════════════════════════════════════
(define *tmp-path* "/tmp/uncommonlisp-functional-fio.txt")
(define *tmp-path* "/tmp/lumbda-functional-fio.txt")
(assert-true "write-file basic" (write-file *tmp-path* "hello\n"))
(assert-equal "file->string round-trip" (file->string *tmp-path*) "hello\n")
(assert-false "file->string missing" (file->string "/tmp/__nope_uncommonlisp_fio__"))
(assert-false "file->string missing" (file->string "/tmp/__nope_lumbda_fio__"))
(assert-true "write-file overwrite"
(begin (write-file *tmp-path* "second") (string=? (file->string *tmp-path*) "second")))
@ -608,7 +608,7 @@
;;; Cross-impl state exchange using only string primitives
;;; ═══════════════════════════════════════════════════════════════
(define *portal-path* "/tmp/uncommonlisp-functional-portal.sexp")
(define *portal-path* "/tmp/lumbda-functional-portal.sexp")
(write-file *portal-path*
"(define portal-x 111)\n(define portal-y 222)\n(define portal-z 333)\n")

View file

@ -11,9 +11,9 @@
set -u
cd "$(dirname "$0")/.."
PY="python3 uncommonlisp.py --fast"
C="./c/uncommonlisp"
ASM="./asm/uncommonlisp"
PY="python3 lumbda.py --fast"
C="./c/lumbda"
ASM="./asm/lumbda"
N=50
pad() { printf " %-42s " "$1"; }

View file

@ -13,9 +13,9 @@
set -e
cd "$(dirname "$0")/.."
PY="python3 uncommonlisp.py --fast"
C="./c/uncommonlisp"
ASM="./asm/uncommonlisp"
PY="python3 lumbda.py --fast"
C="./c/lumbda"
ASM="./asm/lumbda"
SEXP=/tmp/portal-xtest.sexp
PASS=0

View file

@ -16,7 +16,7 @@
;; Write all user-defined bindings as (define name value) forms
;; that any Scheme can evaluate to restore state
(let ((port (open-output-file filename)))
(display ";; uncommonlisp portable state" port)
(display ";; lumbda portable state" port)
(newline port)
(display ";; generated by portal-save-sexp" port)
(newline port)

View file

@ -4,9 +4,9 @@
;;; 2. JSON (Python + C)
;;; 3. Binary heap dump (assembly only, fastest)
;;;
;;; Run in Python: python3 uncommonlisp.py --fast tests/portal-formats.lsp
;;; Run in C: ./c/uncommonlisp tests/portal-formats.lsp
;;; Asm: asm/uncommonlisp < tests/portal-cross-load.lsp (no `load` builtin)
;;; Run in Python: python3 lumbda.py --fast tests/portal-formats.lsp
;;; Run in C: ./c/lumbda tests/portal-formats.lsp
;;; Asm: asm/lumbda < tests/portal-cross-load.lsp (no `load` builtin)
;;;
;;; ── Observed results (2026-04-16, same laptop) ─────────────────
;;;
@ -47,7 +47,7 @@
(define (write-sexp-portal filename)
(let ((port (open-output-file filename)))
;; Header
(display ";; uncommonlisp portable state (S-expression format)" port)
(display ";; lumbda portable state (S-expression format)" port)
(newline port)
(display ";; resume: (load \"" port)
(display filename port)

View file

@ -24,7 +24,7 @@ SPAWNED=()
cleanup() {
for pid in "${SPAWNED[@]}"; do kill -9 "$pid" 2>/dev/null; done
sleep 0.2
pkill -9 -u "$USER" -f 'uncommonlisp.*(rpc|repl)-(server|relay|chain-bench)\.lsp' 2>/dev/null || true
pkill -9 -u "$USER" -f 'lumbda.*(rpc|repl)-(server|relay|chain-bench)\.lsp' 2>/dev/null || true
}
trap cleanup EXIT INT TERM
@ -61,17 +61,17 @@ stop_bg() {
verify_clean() {
local strays
strays=$(pgrep -u "$USER" -f 'uncommonlisp.*(rpc|repl)-(server|relay|chain-bench)\.lsp' 2>/dev/null || true)
strays=$(pgrep -u "$USER" -f 'lumbda.*(rpc|repl)-(server|relay|chain-bench)\.lsp' 2>/dev/null || true)
if [ -n "$strays" ]; then
echo "!! STRAYS: $strays" >&2
pkill -9 -u "$USER" -f 'uncommonlisp.*(rpc|repl)-(server|relay|chain-bench)\.lsp' 2>/dev/null || true
pkill -9 -u "$USER" -f 'lumbda.*(rpc|repl)-(server|relay|chain-bench)\.lsp' 2>/dev/null || true
return 1
fi
}
PY="python3 uncommonlisp.py --fast"
C="./c/uncommonlisp"
ASM="./asm/uncommonlisp"
PY="python3 lumbda.py --fast"
C="./c/lumbda"
ASM="./asm/lumbda"
# Always use Python client to drive (identical across benches).
# We sed the hardcoded port in-place because asm's top-level

View file

@ -1,5 +1,5 @@
#!/bin/bash
# web-benchmark.sh — race the three uncommonlisp HTTP servers
# web-benchmark.sh — race the three lumbda HTTP servers
# against Python http.server and busybox httpd.
#
# No wrk/ab/nginx dependency — we use xargs+curl for concurrency.
@ -12,10 +12,10 @@ cd "$(dirname "$0")/.."
REQUESTS=${REQUESTS:-500}
CONCURRENCY=${CONCURRENCY:-10}
PY="python3 uncommonlisp.py --fast"
C="./c/uncommonlisp"
ASM="./asm/uncommonlisp"
ASM_GC="./asm/uncommonlisp-gc"
PY="python3 lumbda.py --fast"
C="./c/lumbda"
ASM="./asm/lumbda"
ASM_GC="./asm/lumbda-gc"
# Track every server PID we spawn; the EXIT trap kills them all.
# Asm has no GC — a leaked server leaks 64 MB per heap growth
@ -34,7 +34,7 @@ cleanup() {
rm -rf "${STATIC_DIR:-/nonexistent/xyz}"
# Final sanity: any stray servers from examples/http-server?
# Narrow to processes actually serving the HTTP example, not the
# shell running this script or tmux sessions with "uncommonlisp"
# shell running this script or tmux sessions with "lumbda"
# in their name.
local strays
strays=$(pgrep -u "$USER" -f 'examples/http-server\.lsp|http\.server 8080' | wc -l)
@ -106,25 +106,25 @@ stop_server() {
sleep 0.2
}
# ── uncommonlisp Python ──
# ── lumbda Python ──
PID=$(start_server "$PY examples/http-server.lsp" 8080)
bench_one "uncommonlisp Python (/bench, 1 KB)" 8080 /bench
bench_one "lumbda Python (/bench, 1 KB)" 8080 /bench
stop_server "$PID"
# ── uncommonlisp C ──
# ── lumbda C ──
PID=$(start_server "$C examples/http-server.lsp" 8080)
bench_one "uncommonlisp C (/bench, 1 KB)" 8080 /bench
bench_one "lumbda C (/bench, 1 KB)" 8080 /bench
stop_server "$PID"
# ── uncommonlisp asm (bump-only) ──
# ── lumbda asm (bump-only) ──
PID=$(start_server "$ASM < examples/http-server.lsp" 8080)
bench_one "uncommonlisp asm (/bench, 1 KB)" 8080 /bench
bench_one "lumbda asm (/bench, 1 KB)" 8080 /bench
stop_server "$PID"
# ── uncommonlisp asm-gc (naive mark-sweep + meta-GC build) ──
# ── lumbda asm-gc (naive mark-sweep + meta-GC build) ──
if [ -x "$ASM_GC" ]; then
PID=$(start_server "$ASM_GC < examples/http-server.lsp" 8080)
bench_one "uncommonlisp asm-gc (/bench, 1 KB)" 8080 /bench
bench_one "lumbda asm-gc (/bench, 1 KB)" 8080 /bench
stop_server "$PID"
fi
@ -148,9 +148,9 @@ echo
echo "═══════════════════════════════════════════════════════════════"
echo "Binary sizes"
echo "═══════════════════════════════════════════════════════════════"
printf " uncommonlisp asm: %s\n" "$(du -b asm/uncommonlisp | cut -f1) bytes"
[ -x asm/uncommonlisp-gc ] && \
printf " uncommonlisp asm-gc: %s\n" "$(du -b asm/uncommonlisp-gc | cut -f1) bytes (GC_NAIVE build)"
printf " uncommonlisp C: %s\n" "$(du -b c/uncommonlisp | cut -f1) bytes"
printf " lumbda asm: %s\n" "$(du -b asm/lumbda | cut -f1) bytes"
[ -x asm/lumbda-gc ] && \
printf " lumbda asm-gc: %s\n" "$(du -b asm/lumbda-gc | cut -f1) bytes (GC_NAIVE build)"
printf " lumbda C: %s\n" "$(du -b c/lumbda | cut -f1) bytes"
printf " busybox httpd: %s\n" "$(du -b /usr/bin/busybox | cut -f1) bytes (multi-call)"
printf " python3: %s bytes (interpreter binary)\n" "$(du -bL $(which python3) | cut -f1)"

View file

@ -1 +1 @@
uncommonlisp-whitepaper.pdf
lumbda-whitepaper.pdf

View file

@ -1 +1 @@
uncommonlisp-whitepaper.rst
lumbda-whitepaper.rst

View file

@ -584,7 +584,7 @@ endobj
endobj
69 0 obj
<<
/Author () /CreationDate (D:20260419094254-04'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260419094254-04'00') /Producer (ReportLab PDF Library - \(opensource\))
/Author () /CreationDate (D:20260419101758-04'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260419101758-04'00') /Producer (ReportLab PDF Library - \(opensource\))
/Subject (\(unspecified\)) /Title () /Trapped /False
>>
endobj
@ -875,7 +875,7 @@ endobj
endobj
125 0 obj
<<
/Dest [ 57 0 R /XYZ 57.02362 265.0236 0 ] /Next 126 0 R /Parent 123 0 R /Prev 124 0 R /Title (12.2 MOAD-0002: The Intertangle in Our Own Design)
/Dest [ 57 0 R /XYZ 57.02362 277.0236 0 ] /Next 126 0 R /Parent 123 0 R /Prev 124 0 R /Title (12.2 MOAD-0002: The Intertangle in Our Own Design)
>>
endobj
126 0 obj
@ -4473,7 +4473,7 @@ endstream
endobj
143 0 obj
<<
/Length 8523
/Length 8511
>>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
@ -4492,7 +4492,7 @@ n -6 -6 480.0283 31.2 re B*
Q
q
0 0 0 rg
BT 1 0 0 1 0 11.2 Tm /F5 8 Tf 9.6 TL (as --64 --defsym GC_NAIVE=1 uncommonlisp.s # collecting build) Tj T* (as --64 uncommonlisp.s # default, bump-only) Tj T* ET
BT 1 0 0 1 0 11.2 Tm /F5 8 Tf 9.6 TL (as --64 --defsym GC_NAIVE=1 lumbda.s # collecting build) Tj T* (as --64 lumbda.s # default, bump-only) Tj T* ET
Q
Q
Q
@ -6477,7 +6477,7 @@ endstream
endobj
148 0 obj
<<
/Length 10633
/Length 10627
>>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
@ -6920,7 +6920,7 @@ n -6 -6 480.0283 21.6 re B*
Q
q
0 0 0 rg
BT 1 0 0 1 0 1.6 Tm /F5 8 Tf 9.6 TL (python3 uncommonlisp.py --portal-resume state.portal) Tj T* ET
BT 1 0 0 1 0 1.6 Tm /F5 8 Tf 9.6 TL (python3 lumbda.py --portal-resume state.portal) Tj T* ET
Q
Q
Q
@ -7905,7 +7905,7 @@ endstream
endobj
152 0 obj
<<
/Length 10223
/Length 10217
>>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
@ -8206,7 +8206,7 @@ Q
q
1 0 0 1 23 -3 cm
q
BT 1 0 0 1 0 26 Tm .886835 Tw 12 TL /F3 10 Tf 0 0 0 rg (Self-hosted verification) Tj /F1 10 Tf ( \() Tj /F5 10 Tf (proof/eml_proof.lsp) Tj /F1 10 Tf (\): The same proof runs in Lumbda's bytecode VM) Tj T* 0 Tw 2.063543 Tw (\() Tj /F5 10 Tf (python3) Tj ( ) Tj (uncommonlisp.py) Tj ( ) Tj (--fast) Tj ( ) Tj (proof/eml_proof.lsp) Tj /F1 10 Tf (\). The language verifies its own) Tj T* 0 Tw (mathematical foundations.) Tj T* ET
BT 1 0 0 1 0 26 Tm .886835 Tw 12 TL /F3 10 Tf 0 0 0 rg (Self-hosted verification) Tj /F1 10 Tf ( \() Tj /F5 10 Tf (proof/eml_proof.lsp) Tj /F1 10 Tf (\): The same proof runs in Lumbda's bytecode VM) Tj T* 0 Tw 6.563543 Tw (\() Tj /F5 10 Tf (python3) Tj ( ) Tj (lumbda.py) Tj ( ) Tj (--fast) Tj ( ) Tj (proof/eml_proof.lsp) Tj /F1 10 Tf (\). The language verifies its own) Tj T* 0 Tw (mathematical foundations.) Tj T* ET
Q
Q
q
@ -9374,7 +9374,7 @@ endstream
endobj
157 0 obj
<<
/Length 16605
/Length 16587
>>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
@ -10123,7 +10123,7 @@ q
n -6 -6 480.0283 40.8 re B*
Q
q
BT 1 0 0 1 0 20.8 Tm 9.6 TL /F5 8 Tf 0 0 0 rg (python3 uncommonlisp.py --fast examples/http-server.lsp) Tj T* (./c/uncommonlisp examples/http-server.lsp) Tj T* (./asm/uncommonlisp ) Tj (<) Tj ( examples/http-server.lsp) Tj T* ET
BT 1 0 0 1 0 20.8 Tm 9.6 TL /F5 8 Tf 0 0 0 rg (python3 lumbda.py --fast examples/http-server.lsp) Tj T* (./c/lumbda examples/http-server.lsp) Tj T* (./asm/lumbda ) Tj (<) Tj ( examples/http-server.lsp) Tj T* ET
Q
Q
Q
@ -10975,7 +10975,7 @@ endstream
endobj
161 0 obj
<<
/Length 8009
/Length 7971
>>
stream
1 0 0 1 0 0 cm BT /F1 12 Tf 14.4 TL ET
@ -11091,7 +11091,7 @@ Q
q
1 0 0 1 23 -3 cm
q
BT 1 0 0 1 0 26 Tm .908543 Tw 12 TL /F5 10 Tf 0 0 0 rg (uncommonlisp.py) Tj /F1 10 Tf ('s ) Tj /F5 10 Tf (_tokenize_lines) Tj /F1 10 Tf ( called ) Tj /F5 10 Tf (src.count\('\\n',) Tj ( ) Tj (0,) Tj ( ) Tj (m.start\(\)\)) Tj /F1 10 Tf ( per token to) Tj T* 0 Tw 1.140596 Tw (compute line numbers. O\(N\267M\). Replaced with a single pass that builds a ) Tj /F5 10 Tf (line_starts) Tj /F1 10 Tf ( array, then) Tj T* 0 Tw (bisects per token. O\(M + N log M\).) Tj T* ET
BT 1 0 0 1 0 26 Tm .237594 Tw 12 TL /F5 10 Tf 0 0 0 rg (lumbda.py) Tj /F1 10 Tf ('s ) Tj /F5 10 Tf (_tokenize_lines) Tj /F1 10 Tf ( called ) Tj /F5 10 Tf (src.count\('\\n',) Tj ( ) Tj (0,) Tj ( ) Tj (m.start\(\)\)) Tj /F1 10 Tf ( per token to compute) Tj T* 0 Tw .39789 Tw (line numbers. O\(N\267M\). Replaced with a single pass that builds a ) Tj /F5 10 Tf (line_starts) Tj /F1 10 Tf ( array, then bisects per) Tj T* 0 Tw (token. O\(M + N log M\).) Tj T* ET
Q
Q
q
@ -11102,39 +11102,39 @@ q
1 0 0 1 57.02362 387.0236 cm
Q
q
1 0 0 1 57.02362 297.0236 cm
1 0 0 1 57.02362 309.0236 cm
q
BT 1 0 0 1 0 74 Tm 4.926213 Tw 12 TL /F1 10 Tf 0 0 0 rg (A third correctness fix landed after the portal-over-HTTP demo exposed it: ) Tj /F5 10 Tf (uncommonlisp.py) Tj /F1 10 Tf ('s) Tj T* 0 Tw .515223 Tw /F5 10 Tf (Env.lookup) Tj /F1 10 Tf ( used to short-cut from the local frame directly to the global frame before walking intermediate) Tj T* 0 Tw 1.47713 Tw (parents. That was fast but wrong \227 a let-loop parameter named the same as a global builtin \() Tj /F5 10 Tf (count) Tj /F1 10 Tf (, a) Tj T* 0 Tw .409897 Tw (SRFI-1 procedure\) got shadowed in reverse, the shortcut returned the global builtin instead of walking up to) Tj T* 0 Tw .07402 Tw (the loop's parameter frame. Fix: walk ) Tj /F5 10 Tf (self) Tj ( ) Tj /F6 10 Tf 12 TL (\256) Tj /F5 10 Tf 12 TL ( ) Tj (self.p) Tj ( ) Tj /F6 10 Tf 12 TL (\256) Tj /F5 10 Tf 12 TL ( ) Tj (...) Tj ( ) Tj /F6 10 Tf 12 TL (\256) Tj /F5 10 Tf 12 TL ( ) Tj (global) Tj /F1 10 Tf ( in order, without any shortcut.) Tj T* 0 Tw 1.17189 Tw (The inline cache at ) Tj /F5 10 Tf (OP_LOOKUP) Tj /F1 10 Tf ( was correspondingly tightened to validate the full chain before firing. 980) Tj T* 0 Tw (tests remained green.) Tj T* ET
BT 1 0 0 1 0 62 Tm .226796 Tw 12 TL /F1 10 Tf 0 0 0 rg (A third correctness fix landed after the portal-over-HTTP demo exposed it: ) Tj /F5 10 Tf (lumbda.py) Tj /F1 10 Tf ('s ) Tj /F5 10 Tf (Env.lookup) Tj /F1 10 Tf ( used) Tj T* 0 Tw .794272 Tw (to short-cut from the local frame directly to the global frame before walking intermediate parents. That was) Tj T* 0 Tw .366019 Tw (fast but wrong \227 a let-loop parameter named the same as a global builtin \() Tj /F5 10 Tf (count) Tj /F1 10 Tf (, a SRFI-1 procedure\) got) Tj T* 0 Tw .949897 Tw (shadowed in reverse, the shortcut returned the global builtin instead of walking up to the loop's parameter) Tj T* 0 Tw .453797 Tw (frame. Fix: walk ) Tj /F5 10 Tf (self) Tj ( ) Tj /F6 10 Tf 12 TL (\256) Tj /F5 10 Tf 12 TL ( ) Tj (self.p) Tj ( ) Tj /F6 10 Tf 12 TL (\256) Tj /F5 10 Tf 12 TL ( ) Tj (...) Tj ( ) Tj /F6 10 Tf 12 TL (\256) Tj /F5 10 Tf 12 TL ( ) Tj (global) Tj /F1 10 Tf ( in order, without any shortcut. The inline cache at) Tj T* 0 Tw /F5 10 Tf (OP_LOOKUP) Tj /F1 10 Tf ( was correspondingly tightened to validate the full chain before firing. 980 tests remained green.) Tj T* ET
Q
Q
q
1 0 0 1 57.02362 279.0236 cm
1 0 0 1 57.02362 291.0236 cm
q
0 0 0 rg
BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (Every release audit surfaces more. Writing new code is writing new sediment, unless the audit runs.) Tj T* ET
Q
Q
q
1 0 0 1 57.02362 253.0236 cm
1 0 0 1 57.02362 265.0236 cm
q
BT 1 0 0 1 0 2 Tm 12 TL /F2 10 Tf .133333 .133333 .133333 rg (12.2 MOAD-0002: The Intertangle in Our Own Design) Tj T* ET
Q
Q
q
1 0 0 1 57.02362 235.0236 cm
1 0 0 1 57.02362 247.0236 cm
q
0 0 0 rg
BT 1 0 0 1 0 2 Tm /F1 10 Tf 12 TL (All three implementations share mutable global state between subsystems:) Tj T* ET
Q
Q
q
1 0 0 1 57.02362 229.0236 cm
1 0 0 1 57.02362 241.0236 cm
Q
q
1 0 0 1 57.02362 229.0236 cm
1 0 0 1 57.02362 241.0236 cm
Q
q
1 0 0 1 57.02362 181.0236 cm
1 0 0 1 57.02362 193.0236 cm
q
0 0 0 rg
BT /F1 10 Tf 12 TL ET
@ -11156,10 +11156,10 @@ Q
Q
Q
q
1 0 0 1 57.02362 175.0236 cm
1 0 0 1 57.02362 187.0236 cm
Q
q
1 0 0 1 57.02362 139.0236 cm
1 0 0 1 57.02362 151.0236 cm
q
0 0 0 rg
BT /F1 10 Tf 12 TL ET
@ -11181,10 +11181,10 @@ Q
Q
Q
q
1 0 0 1 57.02362 133.0236 cm
1 0 0 1 57.02362 145.0236 cm
Q
q
1 0 0 1 57.02362 97.02362 cm
1 0 0 1 57.02362 109.0236 cm
q
0 0 0 rg
BT /F1 10 Tf 12 TL ET
@ -11206,7 +11206,7 @@ Q
Q
Q
q
1 0 0 1 57.02362 79.02362 cm
1 0 0 1 57.02362 91.02362 cm
Q
endstream
@ -12146,66 +12146,66 @@ xref
0002447433 00000 n
0002457549 00000 n
0002466915 00000 n
0002475491 00000 n
0002486442 00000 n
0002498945 00000 n
0002509558 00000 n
0002518581 00000 n
0002529268 00000 n
0002536885 00000 n
0002546473 00000 n
0002554309 00000 n
0002564586 00000 n
0002574527 00000 n
0002581044 00000 n
0002582879 00000 n
0002596335 00000 n
0002612994 00000 n
0002623502 00000 n
0002630961 00000 n
0002637635 00000 n
0002645697 00000 n
0002653633 00000 n
0002660101 00000 n
0002662257 00000 n
0002663335 00000 n
0002663739 00000 n
0002663774 00000 n
0002663809 00000 n
0002663844 00000 n
0002663879 00000 n
0002663914 00000 n
0002663949 00000 n
0002663984 00000 n
0002664019 00000 n
0002664054 00000 n
0002664090 00000 n
0002664126 00000 n
0002664162 00000 n
0002664198 00000 n
0002664234 00000 n
0002664270 00000 n
0002664306 00000 n
0002664342 00000 n
0002664378 00000 n
0002664414 00000 n
0002664450 00000 n
0002664486 00000 n
0002664522 00000 n
0002664558 00000 n
0002664594 00000 n
0002664630 00000 n
0002664666 00000 n
0002664702 00000 n
0002664738 00000 n
0002664774 00000 n
0002664810 00000 n
0002664846 00000 n
0002664882 00000 n
0002475479 00000 n
0002486430 00000 n
0002498933 00000 n
0002509546 00000 n
0002518569 00000 n
0002529250 00000 n
0002536867 00000 n
0002546455 00000 n
0002554291 00000 n
0002564562 00000 n
0002574503 00000 n
0002581020 00000 n
0002582855 00000 n
0002596311 00000 n
0002612952 00000 n
0002623460 00000 n
0002630919 00000 n
0002637593 00000 n
0002645617 00000 n
0002653553 00000 n
0002660021 00000 n
0002662177 00000 n
0002663255 00000 n
0002663659 00000 n
0002663694 00000 n
0002663729 00000 n
0002663764 00000 n
0002663799 00000 n
0002663834 00000 n
0002663869 00000 n
0002663904 00000 n
0002663939 00000 n
0002663974 00000 n
0002664010 00000 n
0002664046 00000 n
0002664082 00000 n
0002664118 00000 n
0002664154 00000 n
0002664190 00000 n
0002664226 00000 n
0002664262 00000 n
0002664298 00000 n
0002664334 00000 n
0002664370 00000 n
0002664406 00000 n
0002664442 00000 n
0002664478 00000 n
0002664514 00000 n
0002664550 00000 n
0002664586 00000 n
0002664622 00000 n
0002664658 00000 n
0002664694 00000 n
0002664730 00000 n
0002664766 00000 n
0002664802 00000 n
trailer
<<
/ID
[<1d446ae1004a02d6f40b0a19c1f8b013><1d446ae1004a02d6f40b0a19c1f8b013>]
[<256838ea1d698f91db2ad0c26a223907><256838ea1d698f91db2ad0c26a223907>]
% ReportLab generated PDF document -- digest (opensource)
/Info 69 0 R
@ -12213,5 +12213,5 @@ trailer
/Size 200
>>
startxref
2664918
2664838
%%EOF

View file

@ -482,8 +482,8 @@ To measure what a collector would actually cost, we built a second asm binary be
.. code-block::
as --64 --defsym GC_NAIVE=1 uncommonlisp.s # collecting build
as --64 uncommonlisp.s # default, bump-only
as --64 --defsym GC_NAIVE=1 lumbda.s # collecting build
as --64 lumbda.s # default, bump-only
Same source, same tests (137/137 pass on both). The GC build adds an 8-byte ``(size << 1 | mark)`` header on every heap block, a stop-the-world mark-sweep triggered by bump overflow, and a free-list allocator that first-fits reclaimed space.
@ -746,7 +746,7 @@ During VM execution, ``portal-checkpoint!`` triggers at ``OP_JUMP`` & ``OP_TAIL_
::
python3 uncommonlisp.py --portal-resume state.portal
python3 lumbda.py --portal-resume state.portal
The computation does not need to restart from the beginning.
@ -954,7 +954,7 @@ The proof has been verified at six distinct levels. Times are best-of-3 on the i
1. **Numerical verification** (``proof/eml_proof.py``): Python script using ``cmath`` at high precision. Verifies every derivation step with tolerance ``1e-10``. Includes brute-force tree search at depth ≤ 4 confirming that eml compositions reach the expected targets.
2. **Self-hosted verification** (``proof/eml_proof.lsp``): The same proof runs in Lumbda's bytecode VM (``python3 uncommonlisp.py --fast proof/eml_proof.lsp``). The language verifies its own mathematical foundations.
2. **Self-hosted verification** (``proof/eml_proof.lsp``): The same proof runs in Lumbda's bytecode VM (``python3 lumbda.py --fast proof/eml_proof.lsp``). The language verifies its own mathematical foundations.
3. **Formal proof** (``proof/lean/EmlProof/Basic.lean``): Lean 4 proof with zero ``sorry``. Five theorems:
@ -1143,9 +1143,9 @@ Sockets share the same port representation as files — in asm the fd is packed
::
python3 uncommonlisp.py --fast examples/http-server.lsp
./c/uncommonlisp examples/http-server.lsp
./asm/uncommonlisp < examples/http-server.lsp
python3 lumbda.py --fast examples/http-server.lsp
./c/lumbda examples/http-server.lsp
./asm/lumbda < examples/http-server.lsp
The companion ``examples/http-client-bench.lsp`` is a 45-line load generator using only the six ``tcp-*`` primitives plus ``current-time-ms``. In-process client eliminates the ~2 ms/request fork overhead that curl-based benchmarks suffer, so real server throughput shows through. **Reproduce:** ``make bench-web`` (source: ``tests/web-benchmark.sh``).
@ -1314,9 +1314,9 @@ The Python implementation had a similar defect: ``_define_record_type`` used ``l
**Two more MOAD-0001 defects surfaced during the HTTP server work and were fixed in the same pass:**
- ``c/builtins.c``'s ``bi_string_replace`` scanned the source byte-by-byte, calling ``strncmp(src, from, from_len)`` at every position. O(N·k). Replaced with ``strstr`` (libc-tuned, typically Boyer-Moore-Horspool) called in a loop that skips to the next match. O(N + matches·k).
- ``uncommonlisp.py``'s ``_tokenize_lines`` called ``src.count('\\n', 0, m.start())`` per token to compute line numbers. O(N·M). Replaced with a single pass that builds a ``line_starts`` array, then bisects per token. O(M + N log M).
- ``lumbda.py``'s ``_tokenize_lines`` called ``src.count('\\n', 0, m.start())`` per token to compute line numbers. O(N·M). Replaced with a single pass that builds a ``line_starts`` array, then bisects per token. O(M + N log M).
A third correctness fix landed after the portal-over-HTTP demo exposed it: ``uncommonlisp.py``'s ``Env.lookup`` used to short-cut from the local frame directly to the global frame before walking intermediate parents. That was fast but wrong — a let-loop parameter named the same as a global builtin (``count``, a SRFI-1 procedure) got shadowed in reverse, the shortcut returned the global builtin instead of walking up to the loop's parameter frame. Fix: walk ``self → self.p → ... → global`` in order, without any shortcut. The inline cache at ``OP_LOOKUP`` was correspondingly tightened to validate the full chain before firing. 980 tests remained green.
A third correctness fix landed after the portal-over-HTTP demo exposed it: ``lumbda.py``'s ``Env.lookup`` used to short-cut from the local frame directly to the global frame before walking intermediate parents. That was fast but wrong — a let-loop parameter named the same as a global builtin (``count``, a SRFI-1 procedure) got shadowed in reverse, the shortcut returned the global builtin instead of walking up to the loop's parameter frame. Fix: walk ``self → self.p → ... → global`` in order, without any shortcut. The inline cache at ``OP_LOOKUP`` was correspondingly tightened to validate the full chain before firing. 980 tests remained green.
Every release audit surfaces more. Writing new code is writing new sediment, unless the audit runs.