lumbda/Makefile
russell@unturf.com 1b7de2c9c6
wasm/playground: cancel button, asm state-leak fix, restyle to match homepage
User-visible changes
  - Cancel button — terminates the running worker. Pyodide's slow mandelbrot
    no longer freezes the UI; click cancel and the elapsed counter freezes
    at "(cancelled @ NNNN ms)".
  - Live ms counter ticks per animation frame while a tier is busy, so the
    Pyodide tier's ~5-15 s wait is visible instead of looking hung.
  - Restyled to match lumbda.com: chunkfive wordmark, --green: #227842
    (light) / #5ec07a (dark), lumbda-logo-green.png, lowercase "lumbda"
    everywhere. Pulls fonts/chunkfive locally so the playground stays
    self-contained.

Architecture
  - All tier evaluations now run inside a Web Worker (wasm/app/worker.mjs)
    so the main thread stays responsive. Cancel = worker.terminate(); next
    eval respawns a fresh worker.
  - Loaders use new URL("./...", import.meta.url) so paths resolve against
    the loader file's own location — works identically in window and
    worker contexts, no baseURL argument needed.
  - C tier Emscripten build flipped to EXPORT_ES6=1; loader uses dynamic
    `import()` of the factory module. Integration test updated accordingly.
  - Python loader uses `import("pyodide.mjs")` (ES module) instead of
    document.createElement, which doesn't exist in workers.

Bug fixes
  - Asm tier state leak: running the same demo twice on a cached WASM
    instance produced corrupted output (every other cell on row 2+ rendered
    as " " instead of the expected shade char). Root cause: top-level eval
    passed `global_env` as the env, so closures captured stale globals;
    fixed by passing NIL — env_lookup falls back to the CURRENT global_env
    via its existing two-pass walk. Multi-run regression added to the
    functional test suite.
  - fib-ack demo: (ack 3 4) was too heavy for Pyodide (minutes). Cut to
    (ack 3 3) + (fib 20) max so every tier finishes in seconds.

Test discipline
  - Root `make test-all` now includes `wasm-test`. Adding a language
    feature without exercising it on all six implementations is no longer
    possible by accident.
  - Functional suite: 11 assertions (was 10) — adds asm multi-run stability.
  - Integration + unit: still 20 + 8.
2026-06-14 12:13:20 -04:00

371 lines
14 KiB
Makefile
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# ═══════════════════════════════════════════════════════════════════
# lumbda — Python + C + Assembly implementations
# ═══════════════════════════════════════════════════════════════════
#
# Implementations:
# 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)
# make c-test C unit/integration + JIT (76 tests) + functional (114)
# make asm-test Assembly unit/integration/functional (75 tests)
# make functional-test Shared .lsp suite in Python + C (114 each)
# make test-all Everything (836 total)
#
# Benchmarks (each generates reproducible numbers referenced in the
# whitepaper; hardware-independent commands, safety envelope built in):
# make bench Python bench.py (tree-walker vs bytecode VM)
# make c-bench C unit-level microbenchmarks
# make bench-3way §6.4: Python vs C vs asm on sum-to/ack
# make bench-portal §7.5: S-exp/JSON/binary portal save+load timings
# make bench-portal-cross §7.2: 3x3 cross-impl portal save×load matrix
# make bench-web §11.3: HTTP benchmark vs busybox + python http.server
# make bench-rpc-chain §11.4: Py → C relay → asm backend chain timing
# make bench-proof §8.6: EML proof — Lean 4 vs Lumbda tiers
# make bench-all run every bench above back to back
# make friction head-to-head timing: Python vs C vs CPython
#
# Other:
# make examples Run examples in Python + C, compare output
# make docs Generate architecture diagrams
# make whitepaper Build PDF whitepaper
# make clean-all Clean everything
all: test
# ─── Python implementation ────────────────────────────────────────
test:
python3 tests.py
test-verbose:
python3 tests.py -v
bench:
python3 bench.py
bench-verbose:
python3 bench.py -v
repl:
python3 lumbda.py
lint:
python3 -m py_compile lumbda.py
python3 -m py_compile tests.py
python3 -m py_compile bench.py
# ─── C implementation ─────────────────────────────────────────────
c-build:
$(MAKE) -C c all
c-test: c-build
$(MAKE) -C c test
@echo "── C functional tests (shared .lsp suite) ──"
./c/lumbda tests/functional.lsp
c-bench: c-build
$(MAKE) -C c bench
c-repl: c-build
./c/lumbda
c-clean:
$(MAKE) -C c clean
# ─── Assembly implementation ──────────────────────────────────────
asm-build:
$(MAKE) -C asm all
asm-test: asm-build
$(MAKE) -C asm test
asm-repl: asm-build
./asm/lumbda
asm-clean:
$(MAKE) -C asm clean
# ─── All implementations ─────────────────────────────────────────
functional-test: c-build
@echo "═══ Shared functional tests (114 tests) ═══"
@echo "── Python ──"
@python3 lumbda.py --fast tests/functional.lsp | tail -3
@echo "── C ──"
@./c/lumbda tests/functional.lsp | tail -3
portal-rng-cross-test: c-build asm-build
@bash tests/portal-rng-cross-test.sh
zoe-favorites-test: c-build
@bash tests/zoe-favorites-test.sh
regression-named-let-leak: c-build
@bash tests/regression-named-let-leak.sh
# Fetches Zoë's source live from wedgewack.org, verifies the edits in
# examples/ursa.lisp.txt reduce to the documented six annotations, runs
# the suite across tiers, and spot-checks her exact source on asm-full
# with a 10-line stubs prelude. See tests/prove-ursa-runs.sh for the
# full chain. Needs a network connection; `make zoe-favorites-test`
# covers the offline case.
prove-ursa-runs: c-build
@bash tests/prove-ursa-runs.sh
test-all: test c-test asm-test functional-test portal-rng-cross-test zoe-favorites-test regression-named-let-leak wasm-test
@echo "════════════════════════════════════════════════════"
@echo "All tests passed (Python + C + Assembly + functional + portal-rng-cross + zoe-favorites + wasm)"
# ─── Benchmarks (reproducible; referenced in whitepaper §6§11) ───
bench-3way: c-build asm-build
@bash tests/bench-3way.sh
bench-portal: c-build asm-build
@bash tests/portal-benchmark.sh
bench-portal-cross: c-build asm-build
@bash tests/portal-cross-test.sh
bench-web: c-build asm-build
@bash tests/web-benchmark.sh
bench-rpc-chain: c-build asm-build
@bash tests/rpc-chain-bench.sh
bench-proof: c-build asm-build
@bash tests/bench-proof.sh
bench-hashset: asm-build
@bash tests/bench-hashset.sh
bench-gc: asm-build
@bash tests/bench-gc-memory.sh
bench-gc-arena: asm-build
@bash tests/bench-gc-arena.sh
bench-gc-adaptive: asm-build
@bash tests/bench-gc-adaptive.sh
bench-gc-http: asm-build
@bash tests/bench-gc-http.sh
bench-lumbda-www: asm-build
@bash tests/bench-lumbda-www.sh
bench-www-race: asm-build
@bash tests/bench-www-race.sh
bench-all: bench c-bench bench-3way bench-portal bench-portal-cross bench-web bench-rpc-chain bench-proof
@echo "═══════════════════════════════════════════════════════════"
@echo "All benchmarks complete. Numbers in the whitepaper §6.4,"
@echo "§7.2, §7.5, §11.3, §11.4 are reproducible from these targets."
# ─── Examples ─────────────────────────────────────────────────────
examples: c-build
@echo "═══ 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 lumbda.py --fast examples/mergesort.lsp
@echo "--- C ---" && ./c/lumbda examples/mergesort.lsp
@echo
@echo "═══ objects.lsp ═══"
@echo "--- Python ---" && python3 lumbda.py examples/objects.lsp
@echo "--- C ---" && ./c/lumbda examples/objects.lsp
# ─── Friction benchmark ──────────────────────────────────────────
friction: c-build asm-build
bash friction.sh
# ─── GPU worker (bend primitive) ─────────────────────────────────
#
# Builds the cuda-fanout leaf binary & launches gpu-worker.lsp on
# port 8320 (override via PORT=NNNN). Client tier choice via
# LUMBDA=python|c|asm (default python). Once running, any tier can
# (bend …) to it from the same host or another LAN host.
#
# Port mnemonic — 8320 = BEND:
# 8 ~= B (implied infinity B flattened; bake a cake; baby & me)
# 3 ~= E (backward)
# 2 ~= N (pivoted 90 degrees)
# 0 ~= D (flattened)
GPU_WORKER_DIR := examples/cuda-fanout
PORT ?= 8320
LUMBDA ?= c
gpu-worker-bin:
$(MAKE) -C $(GPU_WORKER_DIR) shake256-fanout
gpu-worker: gpu-worker-bin
@echo "→ launching gpu-worker.lsp on port $(PORT) ($(LUMBDA) tier)"
@printf '(load "wire.lsp")\n(load "gpu-worker.lsp")\n(main)\n' > $(GPU_WORKER_DIR)/launch.lsp
ifeq ($(LUMBDA),c)
$(MAKE) c-build
cd $(GPU_WORKER_DIR) && ../../c/lumbda launch.lsp --port $(PORT)
else ifeq ($(LUMBDA),python)
cd $(GPU_WORKER_DIR) && python3 -u ../../lumbda.py launch.lsp --port $(PORT)
else ifeq ($(LUMBDA),asm)
$(MAKE) asm-build
cd $(GPU_WORKER_DIR) && ../../asm/lumbda-gc launch.lsp --port $(PORT)
else
@echo "LUMBDA=$(LUMBDA) — expected c | python | asm"; exit 2
endif
gpu-worker-test: gpu-worker-bin
$(MAKE) -C $(GPU_WORKER_DIR) test
# ─── Factory — bend at scale ──────────────────────────────────────
#
# Bounded-parallel emit + dispatch + autoscaling for lumbda research
# loops driving GPU bend backends. See factory/README.md & factory/CONTRACT.md.
# Originally built at foxhop for secp256k1 attack-surface research; shared
# upstream under AGPLv3.
#
# make factory-lint bash -n syntax check on factory/*.sh
# make test-integration integration tests (autoscaler V2 reducer + DLQ classifier)
# make sweep-doctrine TCRAUDT reducer gate (serial)
# make sweep-doctrine-parallel same, xargs -P fan-out (JOBS=N)
#
# Consumer wrapper pattern: domain repos export LUMBDA_* env then exec
# factory/bend-supervisor.sh. See factory/CONTRACT.md.
FACTORY_DIR := factory
TESTS_INTEGRATION_DIR := tests/integration
TESTS_SWEEP_DOCTRINE_DIR := tests/sweep-doctrine
factory-lint:
@bash $(TESTS_INTEGRATION_DIR)/test-bash-script-syntax.sh
test-integration:
@for t in $(TESTS_INTEGRATION_DIR)/test-*.sh; do \
echo "── $$t ──"; \
bash "$$t" || { rc=$$?; [ $$rc -eq 77 ] && echo "SKIP (factory script absent)" || exit $$rc; }; \
done
sweep-doctrine:
@bash $(TESTS_SWEEP_DOCTRINE_DIR)/run.sh
sweep-doctrine-parallel:
@bash $(TESTS_SWEEP_DOCTRINE_DIR)/run-parallel.sh
# ─── WebAssembly tiers (Python + C + asm to browser) ──────────────
#
# Three-tier Lumbda stack compiled to WASM for any modern browser.
# Python → Pyodide (CPython-in-WASM) loading lumbda.py
# C → Emscripten build of c/ (tree-walker + bytecode VM, no JIT)
# Asm → hand-written WebAssembly Text format (wasm/asm/lumbda.wat)
#
# Plus a single-page app at wasm/app/ (CodeMirror editor on left, output
# on right, tier radio: Python | C | Asm | All Three, demo radio:
# Mandelbrot | Fib+Ack | Sieve | Self-interp).
#
# make wasm-build all three tiers + SPA bundle in wasm/dist/
# make wasm-test unit + integration (node)
# make wasm-test-fn functional (headless browser via playwright)
# make wasm-serve local dev server at :8080
# make wasm-deploy copy bundle into www/playground/
# make wasm-clean
wasm-build:
$(MAKE) -C wasm build
wasm-test:
$(MAKE) -C wasm test
wasm-test-fn:
$(MAKE) -C wasm test-fn
wasm-serve:
$(MAKE) -C wasm serve
wasm-deploy:
$(MAKE) -C wasm deploy
wasm-clean:
$(MAKE) -C wasm clean
# ─── Documentation ────────────────────────────────────────────────
DOT_FILES := $(wildcard docs/*.dot)
DOT_PNGS := $(DOT_FILES:.dot=.png)
docs: $(DOT_PNGS)
docs/%.png: docs/%.dot
dot -Tpng $< -o $@
# ─── Whitepaper ───────────────────────────────────────────────────
VENV := whitepaper/.venv
RST := whitepaper/lumbda-whitepaper.rst
PDF := whitepaper/lumbda-whitepaper.pdf
HTML := whitepaper/lumbda-whitepaper.html
STYLE := whitepaper/whitepaper.style
$(VENV)/bin/rst2pdf:
python3 -m venv $(VENV)
$(VENV)/bin/pip install --upgrade pip
$(VENV)/bin/pip install rst2pdf docutils
whitepaper: $(PDF) $(HTML)
whitepaper-pdf: $(PDF)
whitepaper-html: $(HTML)
$(PDF): $(RST) $(STYLE) $(VENV)/bin/rst2pdf
cd whitepaper && ../$(<D)/.venv/bin/rst2pdf \
-s whitepaper.style \
--fit-background-mode=scale \
lumbda-whitepaper.rst \
-o lumbda-whitepaper.pdf
@ln -sf lumbda-whitepaper.pdf whitepaper/WHITEPAPER.pdf
@echo "Built: $(PDF)"
# HTML whitepaper: single self-contained file with embedded stylesheet
# plus an uncloseai.js module script (matches lumbda.com front door).
$(HTML): $(RST) $(VENV)/bin/rst2pdf
@DOCUTILS_CSS="$$(cd whitepaper/.venv/lib/python*/site-packages/docutils/writers/html5_polyglot && pwd)"; \
cd whitepaper && ../$(<D)/.venv/bin/rst2html5 \
--embed-stylesheet \
--stylesheet="$$DOCUTILS_CSS/minimal.css,$$DOCUTILS_CSS/responsive.css" \
lumbda-whitepaper.rst \
lumbda-whitepaper.html
@sed -i 's|</head>|<script src="https://uncloseai.com/uncloseai.js" type="module"></script>\n</head>|' $(HTML)
@sed -i 's|<title>lumbda-whitepaper.rst</title>|<title>Lumbda whitepaper — feedback as a primitive</title>|' $(HTML)
@python3 whitepaper/embed-images.py $(HTML)
@python3 whitepaper/inject-whitepaper-css.py $(HTML) \
www/fonts/chunkfive/chunkfive-regular-webfont.woff2
@echo "Built: $(HTML)"
# ─── Clean ────────────────────────────────────────────────────────
clean:
rm -rf __pycache__ *.pyc
clean-whitepaper:
rm -rf $(VENV) $(PDF) whitepaper/WHITEPAPER.pdf
clean-docs:
rm -f docs/*.png
clean-all: clean clean-whitepaper clean-docs c-clean asm-clean
.PHONY: all test test-verbose bench bench-verbose repl lint \
c-build c-test c-bench c-repl c-clean \
asm-build asm-test asm-repl asm-clean \
test-all bench-all examples friction functional-test portal-rng-cross-test \
bench-3way bench-portal bench-portal-cross bench-web bench-rpc-chain bench-proof \
gpu-worker gpu-worker-bin gpu-worker-test \
factory-lint test-integration sweep-doctrine sweep-doctrine-parallel \
wasm-build wasm-test wasm-test-fn wasm-serve wasm-deploy wasm-clean \
docs whitepaper clean clean-whitepaper clean-docs clean-all