Plans + briefings for four new language loops, each with a delcc/JIT showcase that the runtime already supports natively: - common-lisp — conditions + restarts on delimited continuations - apl — rank-polymorphic primitives + 6 operators on the JIT - ruby — fibers as delcc, blocks/yield as escape continuations - tcl — uplevel/upvar via first-class env chain, the Dodekalogue Launcher scripts now spawn 12 windows (was 8).
122 lines
7.8 KiB
Markdown
122 lines
7.8 KiB
Markdown
# Common-Lisp-on-SX: conditions + restarts on delimited continuations
|
|
|
|
The headline showcase is the **condition system**. Restarts are *resumable* exceptions — every other Lisp implementation reinvents this on host-stack unwind tricks. On SX restarts are textbook delimited continuations: `signal` walks the handler chain; `invoke-restart` resumes the captured continuation at the restart point. Same delcc primitive that powers Erlang actors, expressed as a different surface.
|
|
|
|
End-state goal: ANSI Common Lisp subset with a working condition/restart system, CLOS multimethods (with `:before`/`:after`/`:around`), the LOOP macro, packages, and ~150 hand-written + classic programs.
|
|
|
|
## Scope decisions (defaults — override by editing before we spawn)
|
|
|
|
- **Syntax:** ANSI Common Lisp surface. Read tables, dispatch macros (`#'`, `#(`, `#\`, `#:`, `#x`, `#b`, `#o`, ratios `1/3`).
|
|
- **Conformance:** ANSI X3.226 *as a target*, not bug-for-bug SBCL/CCL. "Reads like CL, runs like CL."
|
|
- **Test corpus:** custom + a curated slice of `ansi-test`. Plus classic programs: condition-system demo, restart-driven debugger, multiple-dispatch geometry, LOOP corpus.
|
|
- **Out of scope:** compilation to native, FFI, sockets, threads, MOP class redefinition, full pathname/logical-pathname machinery, structures with `:include` deep customization.
|
|
- **Packages:** simple — `defpackage`/`in-package`/`export`/`use-package`/`:cl`/`:cl-user`. No nicknames, no shadowing-import edge cases.
|
|
|
|
## Ground rules
|
|
|
|
- **Scope:** only touch `lib/common-lisp/**` and `plans/common-lisp-on-sx.md`. Don't edit `spec/`, `hosts/`, `shared/`, or any other `lib/<lang>/**`. CL primitives go in `lib/common-lisp/runtime.sx`.
|
|
- **SX files:** use `sx-tree` MCP tools only.
|
|
- **Commits:** one feature per commit. Keep `## Progress log` updated and tick roadmap boxes.
|
|
|
|
## Architecture sketch
|
|
|
|
```
|
|
Common Lisp source
|
|
│
|
|
▼
|
|
lib/common-lisp/reader.sx — tokenizer + reader (read macros, dispatch chars)
|
|
│
|
|
▼
|
|
lib/common-lisp/parser.sx — AST: forms, declarations, lambda lists
|
|
│
|
|
▼
|
|
lib/common-lisp/transpile.sx — AST → SX AST (entry: cl-eval-ast)
|
|
│
|
|
▼
|
|
lib/common-lisp/runtime.sx — special forms, condition system, CLOS, packages, BIFs
|
|
```
|
|
|
|
Core mapping:
|
|
- **Symbol** = SX symbol with package prefix; package table is a flat dict.
|
|
- **Cons cell** = SX pair via `cons`/`car`/`cdr`; lists native.
|
|
- **Multiple values** = thread through `values`/`multiple-value-bind`; primary-value default for one-context callers.
|
|
- **Block / return-from** = captured continuation; `return-from name v` invokes the block-named `^k`.
|
|
- **Tagbody / go** = each tag is a continuation; `go tag` invokes it.
|
|
- **Unwind-protect** = scope frame with a cleanup thunk fired on any non-local exit.
|
|
- **Conditions / restarts** = layered handler chain on top of `handler-bind` + delcc. `signal` walks handlers; `invoke-restart` resumes a captured continuation.
|
|
- **CLOS** = generic functions are dispatch tables on argument-class lists; method combination computed lazily; `call-next-method` is a continuation.
|
|
- **Macros** = SX macros (sentinel-body) — defmacro lowers directly.
|
|
|
|
## Roadmap
|
|
|
|
### Phase 1 — reader + parser
|
|
- [ ] Tokenizer: symbols (with package qualification `pkg:sym` / `pkg::sym`), numbers (int, float, ratio `1/3`, `#xFF`, `#b1010`, `#o17`), strings `"…"` with `\` escapes, characters `#\Space` `#\Newline` `#\a`, comments `;`, block comments `#| … |#`
|
|
- [ ] Reader: list, dotted pair, quote `'`, function `#'`, quasiquote `` ` ``, unquote `,`, splice `,@`, vector `#(…)`, uninterned `#:foo`, nil/t literals
|
|
- [ ] Parser: lambda lists with `&optional` `&rest` `&key` `&aux` `&allow-other-keys`, defaults, supplied-p variables
|
|
- [ ] Unit tests in `lib/common-lisp/tests/read.sx`
|
|
|
|
### Phase 2 — sequential eval + special forms
|
|
- [ ] `cl-eval-ast`: `quote`, `if`, `progn`, `let`, `let*`, `flet`, `labels`, `setq`, `setf` (subset), `function`, `lambda`, `the`, `locally`, `eval-when`
|
|
- [ ] `block` + `return-from` via captured continuation
|
|
- [ ] `tagbody` + `go` via per-tag continuations
|
|
- [ ] `unwind-protect` cleanup frame
|
|
- [ ] `multiple-value-bind`, `multiple-value-call`, `multiple-value-prog1`, `values`, `nth-value`
|
|
- [ ] `defun`, `defparameter`, `defvar`, `defconstant`, `declaim`, `proclaim` (no-op)
|
|
- [ ] Dynamic variables — `defvar`/`defparameter` produce specials; `let` rebinds via parameterize-style scope
|
|
- [ ] 60+ tests in `lib/common-lisp/tests/eval.sx`
|
|
|
|
### Phase 3 — conditions + restarts (THE SHOWCASE)
|
|
- [ ] `define-condition` — class hierarchy rooted at `condition`/`error`/`warning`/`simple-error`/`simple-warning`/`type-error`/`arithmetic-error`/`division-by-zero`
|
|
- [ ] `signal`, `error`, `cerror`, `warn` — all walk the handler chain
|
|
- [ ] `handler-bind` — non-unwinding handlers, may decline by returning normally
|
|
- [ ] `handler-case` — unwinding handlers (delcc abort)
|
|
- [ ] `restart-case`, `with-simple-restart`, `restart-bind`
|
|
- [ ] `find-restart`, `invoke-restart`, `invoke-restart-interactively`, `compute-restarts`
|
|
- [ ] `with-condition-restarts` — associate restarts with a specific condition
|
|
- [ ] `*break-on-signals*`, `*debugger-hook*` (basic)
|
|
- [ ] Classic programs in `lib/common-lisp/tests/programs/`:
|
|
- [ ] `restart-demo.lisp` — division with `:use-zero` and `:retry` restarts
|
|
- [ ] `parse-recover.lisp` — parser with skipped-token restart
|
|
- [ ] `interactive-debugger.lisp` — ASCII REPL using `:debugger-hook`
|
|
- [ ] `lib/common-lisp/conformance.sh` + runner, `scoreboard.json` + `scoreboard.md`
|
|
|
|
### Phase 4 — CLOS
|
|
- [ ] `defclass` with `:initarg`/`:initform`/`:accessor`/`:reader`/`:writer`/`:allocation`
|
|
- [ ] `make-instance`, `slot-value`, `(setf slot-value)`, `with-slots`, `with-accessors`
|
|
- [ ] `defgeneric` with `:method-combination` (standard, plus `+`, `and`, `or`)
|
|
- [ ] `defmethod` with `:before` / `:after` / `:around` qualifiers
|
|
- [ ] `call-next-method` (continuation), `next-method-p`
|
|
- [ ] `class-of`, `find-class`, `slot-boundp`, `change-class` (basic)
|
|
- [ ] Multiple dispatch — method specificity by argument-class precedence list
|
|
- [ ] Built-in classes registered for tagged values (`integer`, `float`, `string`, `symbol`, `cons`, `null`, `t`)
|
|
- [ ] Classic programs:
|
|
- [ ] `geometry.lisp` — `intersect` generic dispatching on (point line), (line line), (line plane)…
|
|
- [ ] `mop-trace.lisp` — `:before` + `:after` printing call trace
|
|
|
|
### Phase 5 — macros + LOOP + reader macros
|
|
- [ ] `defmacro`, `macrolet`, `symbol-macrolet`, `macroexpand-1`, `macroexpand`
|
|
- [ ] `gensym`, `gentemp`
|
|
- [ ] `set-macro-character`, `set-dispatch-macro-character`, `get-macro-character`
|
|
- [ ] **The LOOP macro** — iteration drivers (`for … in/across/from/upto/downto/by`, `while`, `until`, `repeat`), accumulators (`collect`, `append`, `nconc`, `count`, `sum`, `maximize`, `minimize`), conditional clauses (`if`/`when`/`unless`/`else`), termination (`finally`/`thereis`/`always`/`never`), `named` blocks
|
|
- [ ] LOOP test corpus: 30+ tests covering all clause types
|
|
|
|
### Phase 6 — packages + stdlib drive
|
|
- [ ] `defpackage`, `in-package`, `export`, `use-package`, `import`, `find-package`
|
|
- [ ] Package qualification at the reader level — `cl:car`, `mypkg::internal`
|
|
- [ ] `:common-lisp` (`:cl`) and `:common-lisp-user` (`:cl-user`) packages
|
|
- [ ] Sequence functions — `mapcar`, `mapc`, `mapcan`, `reduce`, `find`, `find-if`, `position`, `count`, `every`, `some`, `notany`, `notevery`, `remove`, `remove-if`, `subst`
|
|
- [ ] List ops — `assoc`, `getf`, `nth`, `last`, `butlast`, `nthcdr`, `tailp`, `ldiff`
|
|
- [ ] String ops — `string=`, `string-upcase`, `string-downcase`, `subseq`, `concatenate`
|
|
- [ ] FORMAT — basic directives `~A`, `~S`, `~D`, `~F`, `~%`, `~&`, `~T`, `~{...~}` (iteration), `~[...~]` (conditional), `~^` (escape), `~P` (plural)
|
|
- [ ] Drive corpus to 200+ green
|
|
|
|
## Progress log
|
|
|
|
_Newest first._
|
|
|
|
- _(none yet)_
|
|
|
|
## Blockers
|
|
|
|
- _(none yet)_
|