lumbda/Makefile
russell@unturf.com 346b873247
wasm: three-tier Lumbda to WebAssembly + browser playground
Adds a parallel build of all three Lumbda implementations to WASM, a
single-page playground at www/playground/, and a verified test suite.

Tiers
  - Python: Pyodide (CPython-in-WASM) hosting lumbda.py
  - C:      Emscripten build of c/ (tree-walker + bytecode VM; jit.c
            stubbed, gc.c uses its existing no-Boehm fallback)
  - Asm:    hand-written asm/lumbda.wat — parallel impl to asm/lumbda.s.
            Reader, eval (lambda/define/if/cond/let/and/or/quote/set!),
            recursion across mutated top-level env, bump allocator with
            memory.grow, 24 primitives. ~1200 lines of raw WAT.

SPA (wasm/app/, deployed to www/playground/)
  - CodeMirror 6 editor (Scheme highlighting) on left, output on right
  - Radios: 4 demos (Mandelbrot, Fib+Ack, Sieve, self-interp meta-eval)
            x 4 tiers (Python | C | Asm | All three)
  - All-three mode renders the three tier outputs side by side with
    per-tier elapsed timing

Tests (38 verified assertions)
  - 20 unit (Node): per-tier module loads, eval smoke
  - 8 integration (Node): each demo on c+asm WASM byte-matches the
                          canonical native Python run
  - 10 functional (Playwright headless Chromium): page mounts, every
                          demo runs on every tier, all-three renders

Makefile
  - Root targets: wasm-build, wasm-test, wasm-test-fn, wasm-serve,
                  wasm-deploy, wasm-clean
  - wasm/Makefile orchestrates the three tier builds; deploy copies
    dist/ into www/playground/

Asm tier notes
  - WAT linear symbol intern + linear env lookup is MOAD-0001 at scale;
    documented in the asm/lumbda.wat header and in the SPA footer. The
    demos hit ~30 globals so the linear walks are cheap enough.
  - Bump allocator never frees (matches asm/lumbda.s heap discipline);
    memory.grow expands by 1 MB chunks. Browser tab tears down at unload.

Toolchain (developer prerequisites)
  - Emscripten 6.0.0 via emsdk at ~/git/emsdk
  - wabt 1.0.36 at ~/git/wabt
  - Playwright for functional tests (symlinked from ~/git/agnt)
2026-06-14 11:40:34 -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
@echo "════════════════════════════════════════════════════"
@echo "All tests passed (Python + C + Assembly + functional + portal-rng-cross + zoe-favorites)"
# ─── 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