z-lisp-core
Installation
SKILL.md
Lisp core
Design the interpreter/compiler and its host boundary together — an embedded Lisp VM lives or dies on how cleanly values, errors, and control cross that boundary.
Core semantics — non-negotiable
- lexical scoping and closures: a closure captures its defining environment, not the dynamic call stack. This is Scheme's defining trait — get it right before anything else
- proper tail calls are a requirement, not an optimization flag. A self-tail-call written as
(loop ...)must run in constant stack space, or callers will fall back towhile/gotoand lose the language's expressiveness - macros hygienic by default (rename introduced bindings so they can't capture caller identifiers). If the VM only supports unhygienic macros, document the capture hazard at every macro definition site — don't leave it implicit
- full
call/ccis expensive to implement correctly (stack copying or a CPS transform) — support it only when the host genuinely needs resumable control flow (generators, backtracking, coroutines-via-continuations). A one-shot escape continuation covers most real uses at a fraction of the cost
VM/host boundary
- values cross as tagged types (a discriminated union/enum on the host side) — never as untyped host-native values guessed at runtime
- host functions register explicitly through a table the embedder builds, not via reflection over the host language — reflection breaks static typing and hides the real API surface
- errors map both directions without losing stack context: a Lisp error surfacing to the host carries the Lisp call stack; a host error raised into Lisp carries enough structure for a
condition/guardhandler to act on, not just a string