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).
7.8 KiB
7.8 KiB
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, ratios1/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
:includedeep 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/**andplans/common-lisp-on-sx.md. Don't editspec/,hosts/,shared/, or any otherlib/<lang>/**. CL primitives go inlib/common-lisp/runtime.sx. - SX files: use
sx-treeMCP tools only. - Commits: one feature per commit. Keep
## Progress logupdated 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 vinvokes the block-named^k. - Tagbody / go = each tag is a continuation;
go taginvokes 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.signalwalks handlers;invoke-restartresumes a captured continuation. - CLOS = generic functions are dispatch tables on argument-class lists; method combination computed lazily;
call-next-methodis 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, ratio1/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-whenblock+return-fromvia captured continuationtagbody+govia per-tag continuationsunwind-protectcleanup framemultiple-value-bind,multiple-value-call,multiple-value-prog1,values,nth-valuedefun,defparameter,defvar,defconstant,declaim,proclaim(no-op)- Dynamic variables —
defvar/defparameterproduce specials;letrebinds via parameterize-style scope - 60+ tests in
lib/common-lisp/tests/eval.sx
Phase 3 — conditions + restarts (THE SHOWCASE)
define-condition— class hierarchy rooted atcondition/error/warning/simple-error/simple-warning/type-error/arithmetic-error/division-by-zerosignal,error,cerror,warn— all walk the handler chainhandler-bind— non-unwinding handlers, may decline by returning normallyhandler-case— unwinding handlers (delcc abort)restart-case,with-simple-restart,restart-bindfind-restart,invoke-restart,invoke-restart-interactively,compute-restartswith-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-zeroand:retryrestartsparse-recover.lisp— parser with skipped-token restartinteractive-debugger.lisp— ASCII REPL using:debugger-hook
lib/common-lisp/conformance.sh+ runner,scoreboard.json+scoreboard.md
Phase 4 — CLOS
defclasswith:initarg/:initform/:accessor/:reader/:writer/:allocationmake-instance,slot-value,(setf slot-value),with-slots,with-accessorsdefgenericwith:method-combination(standard, plus+,and,or)defmethodwith:before/:after/:aroundqualifierscall-next-method(continuation),next-method-pclass-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—intersectgeneric dispatching on (point line), (line line), (line plane)…mop-trace.lisp—:before+:afterprinting call trace
Phase 5 — macros + LOOP + reader macros
defmacro,macrolet,symbol-macrolet,macroexpand-1,macroexpandgensym,gentempset-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),namedblocks - 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)