Add reactive islands spec: signals.sx + defisland across all adapters

New spec file signals.sx defines the signal runtime: signal, computed,
effect, deref, reset!, swap!, batch, dispose, and island scope tracking.

eval.sx: defisland special form + island? type predicate in eval-call.
boundary.sx: signal primitive declarations (Tier 3).
render.sx: defisland in definition-form?.
adapter-dom.sx: render-dom-island with reactive context, reactive-text,
  reactive-attr, reactive-fragment, reactive-list helpers.
adapter-html.sx: render-html-island for SSR with data-sx-island/state.
adapter-sx.sx: island? handling in wire format serialization.
special-forms.sx: defisland declaration with docs and example.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-08 09:34:47 +00:00
parent b2aaa3786d
commit a97f4c0e39
8 changed files with 646 additions and 9 deletions

View File

@@ -182,6 +182,23 @@
(when subtitle (p subtitle))
children))")
(define-special-form "defisland"
:syntax (defisland ~name (&key param1 param2 &rest children) body)
:doc "Define a reactive island. Islands have the same calling convention
as components (defcomp) but create a reactive boundary. Inside an
island, signals are tracked — deref subscribes DOM nodes to signals,
and signal changes update only the affected nodes.
On the server, islands render as static HTML wrapped in a
data-sx-island container with serialized initial state. On the
client, islands hydrate into reactive contexts."
:tail-position "body"
:example "(defisland ~counter (&key initial)
(let ((count (signal (or initial 0))))
(div :class \"counter\"
(span (deref count))
(button :on-click (fn (e) (swap! count inc)) \"+\"))))")
(define-special-form "defmacro"
:syntax (defmacro name (params ...) body)
:doc "Define a macro. Macros receive their arguments unevaluated (as raw