Add signal test suite (17/17) and Island type to evaluator

test-signals.sx: 17 tests covering signal basics (create, deref, reset!,
swap!), computed (derive, update, chain), effects (run, re-run, dispose,
cleanup), batch (deferred deduped notifications), and defisland (create,
call, children).

types.py: Island dataclass mirroring Component but for reactive boundaries.
evaluator.py: sf_defisland special form, Island in call dispatch.
run.py: Signal platform primitives (make-signal, tracking context, etc)
  and native effect/computed/batch implementations that bridge Lambda
  calls across the Python↔SX boundary.
signals.sx: Updated batch to deduplicate subscribers across signals.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-08 09:44:18 +00:00
parent a97f4c0e39
commit 26320abd64
5 changed files with 580 additions and 15 deletions

View File

@@ -189,6 +189,31 @@ class Component:
return f"<Component ~{self.name}({', '.join(self.params)})>"
# ---------------------------------------------------------------------------
# Island
# ---------------------------------------------------------------------------
@dataclass
class Island:
"""A reactive UI component defined via ``(defisland ~name (&key ...) body)``.
Islands are like components but create a reactive boundary. Inside an
island, signals are tracked — deref subscribes DOM nodes to signals.
On the server, islands render as static HTML with hydration attributes.
"""
name: str
params: list[str]
has_children: bool
body: Any
closure: dict[str, Any] = field(default_factory=dict)
css_classes: set[str] = field(default_factory=set)
deps: set[str] = field(default_factory=set)
io_refs: set[str] = field(default_factory=set)
def __repr__(self):
return f"<Island ~{self.name}({', '.join(self.params)})>"
# ---------------------------------------------------------------------------
# HandlerDef
# ---------------------------------------------------------------------------
@@ -355,4 +380,4 @@ class _ShiftSignal(BaseException):
# ---------------------------------------------------------------------------
# An s-expression value after evaluation
SExp = int | float | str | bool | Symbol | Keyword | Lambda | Macro | Component | Continuation | HandlerDef | RelationDef | PageDef | QueryDef | ActionDef | list | dict | _Nil | None
SExp = int | float | str | bool | Symbol | Keyword | Lambda | Macro | Component | Island | Continuation | HandlerDef | RelationDef | PageDef | QueryDef | ActionDef | list | dict | _Nil | None