# ═══════════════════════════════════════════════════════════════════
# 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
