Complete C port of the Scheme interpreter. Same .lsp files run in both Python and C with identical output. Architecture: - NaN-boxed 64-bit values (zero-alloc numbers) - Hash-map environments with parent chain + global shortcut - Interned symbols - TCO via explicit loop (eval) and TAIL_CALL/SELF_TAIL_CALL (VM) - Bytecode compiler with all opcodes including superinstructions - 58 unit + integration tests Makefile targets: make test-all run Python (571) + C (58) tests make examples run examples in both, compare output make friction benchmark same .lsp in Python vs C make c-build build C interpreter make c-test run C tests make c-repl C REPL
138 lines
5.5 KiB
Makefile
138 lines
5.5 KiB
Makefile
# ═══════════════════════════════════════════════════════════════════
|
|
# uncommonlisp — Python + C implementations
|
|
# ═══════════════════════════════════════════════════════════════════
|
|
|
|
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 uncommonlisp.py
|
|
|
|
lint:
|
|
python3 -m py_compile uncommonlisp.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
|
|
|
|
c-bench: c-build
|
|
$(MAKE) -C c bench
|
|
|
|
c-repl: c-build
|
|
./c/uncommonlisp
|
|
|
|
c-clean:
|
|
$(MAKE) -C c clean
|
|
|
|
# ─── Both implementations ────────────────────────────────────────
|
|
|
|
test-all: test c-test
|
|
@echo "════════════════════════════════════"
|
|
@echo "All tests passed (Python + C)"
|
|
|
|
bench-all: bench c-bench
|
|
|
|
# ─── Examples (run in both, compare output) ──────────────────────
|
|
|
|
examples: c-build
|
|
@echo "═══ fibonacci.lsp ═══"
|
|
@echo "--- Python ---"
|
|
@python3 uncommonlisp.py --fast examples/fibonacci.lsp
|
|
@echo "--- C ---"
|
|
@./c/uncommonlisp examples/fibonacci.lsp
|
|
@echo
|
|
@echo "═══ mergesort.lsp ═══"
|
|
@echo "--- Python ---"
|
|
@python3 uncommonlisp.py --fast examples/mergesort.lsp
|
|
@echo "--- C ---"
|
|
@./c/uncommonlisp examples/mergesort.lsp
|
|
@echo
|
|
@echo "═══ objects.lsp ═══"
|
|
@echo "--- Python ---"
|
|
@python3 uncommonlisp.py examples/objects.lsp
|
|
@echo "--- C ---"
|
|
@./c/uncommonlisp examples/objects.lsp
|
|
|
|
# ─── Friction benchmark (same .lsp, both runtimes) ──────────────
|
|
|
|
friction: c-build
|
|
@echo "═══════════════════════════════════════════════════════"
|
|
@echo "Friction benchmark: Python vs C on identical .lsp files"
|
|
@echo "═══════════════════════════════════════════════════════"
|
|
@echo
|
|
@echo ">>> fib(35) iterative"
|
|
@printf " Python: " && python3 -c "\
|
|
import time; from uncommonlisp 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)))))')]; \
|
|
t=time.perf_counter(); r=[leval(e,g) for e in read_all('(fib 35)')][-1]; \
|
|
print(f'{(time.perf_counter()-t)*1000:.2f}ms result={r}')"
|
|
@printf " 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))))) (fib 35)' 2>&1
|
|
@echo
|
|
@echo ">>> ackermann(3,4)"
|
|
@printf " Python: " && python3 -c "\
|
|
import time; from uncommonlisp 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))))))')];\
|
|
t=time.perf_counter(); r=[leval(e,g) for e in read_all('(ack 3 4)')][-1]; \
|
|
print(f'{(time.perf_counter()-t)*1000:.2f}ms result={r}')"
|
|
@printf " 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)))))) (ack 3 4)' 2>&1
|
|
|
|
# ═══════════════════════════════════════════════════════════════════
|
|
# Whitepaper
|
|
# ═══════════════════════════════════════════════════════════════════
|
|
|
|
VENV := whitepaper/.venv
|
|
RST := whitepaper/uncommonlisp-whitepaper.rst
|
|
PDF := whitepaper/uncommonlisp-whitepaper.pdf
|
|
STYLE := whitepaper/whitepaper.style
|
|
|
|
$(VENV)/bin/rst2pdf:
|
|
python3 -m venv $(VENV)
|
|
$(VENV)/bin/pip install --upgrade pip
|
|
$(VENV)/bin/pip install rst2pdf
|
|
|
|
whitepaper: $(PDF)
|
|
|
|
$(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
|
|
@echo "Built: $(PDF)"
|
|
|
|
clean:
|
|
rm -rf __pycache__ *.pyc
|
|
|
|
clean-whitepaper:
|
|
rm -rf $(VENV) $(PDF) whitepaper/WHITEPAPER.pdf
|
|
|
|
clean-all: clean clean-whitepaper c-clean
|
|
|
|
.PHONY: all test test-verbose bench bench-verbose repl lint \
|
|
c-build c-test c-bench c-repl c-clean \
|
|
test-all bench-all examples friction \
|
|
whitepaper clean clean-whitepaper clean-all
|