Demo program that lives entirely on lib/* and libwwrt.a — no @symbol
FFI of its own. The interpreter sits in lispcore.ww (exports for the
test driver); lisp.ww is a 3-line entry that calls lispcore.repl().
Language surface: integers, floats, symbols, strings, lists, lambdas
with closures, define / set! / if / quote / let / begin, recursion
(fact / fib / ackermann / gcd), map / filter / reduce as user code.
REPL is line-buffered: each read tries to parse one top-level form,
asks for more on "unterminated list", evaluates and prints, then
shifts consumed bytes off the front of the buffer. Lookahead-aware —
the parser primes one extra token so we shift to L.curstart, not
L.pos, otherwise the first byte of the next form gets eaten.
lisp_test.ww exec'd as a regular binary (ww test drops -I in single-
file mode); 66 probes cover arithmetic, lists, closures, recursion,
errors. test_*.lisp drive the live REPL through `make demo`.
The wwstage cgen still mis-lowers a handful of patterns at this
shape of program — top-level array indexing, global-ptr deref,
two-level field stores, f64 routing through *T, alloc(structlit{})
for f64/str fields, (slice | E) returns, xs[i].kind chains, f64
compound assigns. Each workaround is annotated at its use site;
the full taxonomy is in examples/lisp/CLAUDE.md.
49 lines
1.7 KiB
Makefile
49 lines
1.7 KiB
Makefile
# examples/lisp — tiny Lisp interpreter, built with the ww toolchain.
|
|
# No FFI: the program lives entirely on lib/* and libwwrt.a.
|
|
#
|
|
# Layout
|
|
# lisp.ww entry point. `use lispcore;` + `main()` = repl().
|
|
# lispcore.ww interpreter module. Types/functions are `export`-ed
|
|
# so both lisp.ww and lisp_test.ww consume them via
|
|
# the same `use lispcore;`.
|
|
# lisp_test.ww in-process test driver, executed by `make test`
|
|
# (which invokes `ww test`).
|
|
#
|
|
# `ww`'s module resolver uses the *directory's basename* as the module
|
|
# name when finding `lispcore.ww` through `-I <dir>`. Passing the
|
|
# absolute path of the current directory keeps that name stable
|
|
# (otherwise `-I.` collapses to ".", and the cgen mangles symbols as
|
|
# `..helper`, which then breaks the assembler).
|
|
|
|
WW := $(shell cd ../..; pwd)/out/bin/ww
|
|
HERE := $(shell pwd)
|
|
|
|
lisp: lisp.ww lispcore.ww
|
|
$(WW) build lisp.ww -I $(HERE)
|
|
|
|
# `ww test <file.ww>` in single-file mode discards extra args, so we
|
|
# can't pass `-I` through it. Build the test as a normal binary and
|
|
# exec it directly — exit 0 means all probes passed.
|
|
test: lisp_test lisp
|
|
./lisp_test
|
|
|
|
lisp_test: lisp_test.ww lispcore.ww
|
|
$(WW) build lisp_test.ww -I $(HERE)
|
|
|
|
# Demo programs in tree. `make demo` runs every test_*.lisp through
|
|
# the REPL; each prints its results to stdout (errors go to stderr
|
|
# and don't break the run). Useful as a smoke check after edits.
|
|
DEMOS := test_arith.lisp test_list.lisp test_lambda.lisp test_error.lisp
|
|
|
|
demo: lisp
|
|
@for f in $(DEMOS); do \
|
|
echo "==> $$f"; \
|
|
./lisp < $$f; \
|
|
done
|
|
|
|
clean:
|
|
rm -f lisp lisp.o lisp.s lisp.combined.ww \
|
|
lisp_test lisp_test.o lisp_test.s lisp_test.combined.ww
|
|
|
|
.PHONY: clean test demo
|