Files
rose-ash/plans/elm-on-sx.md
giles 985671cd76 hs: query targets, prolog hook, loop scripts, new plans, WASM regen
Hyperscript compiler/runtime:
- query target support in set/fire/put commands
- hs-set-prolog-hook! / hs-prolog-hook / hs-prolog in runtime
- runtime log-capture cleanup

Scripts: sx-loops-up/down, sx-hs-e-up/down, sx-primitives-down
Plans: datalog, elixir, elm, go, koka, minikanren, ocaml, hs-bucket-f,
       designs (breakpoint, null-safety, step-limit, tell, cookies, eval,
       plugin-system)
lib/prolog/hs-bridge.sx: initial hook-based bridge draft
lib/common-lisp/tests/runtime.sx: CL runtime tests

WASM: regenerate sx_browser.bc.js from updated hs sources

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-06 09:19:56 +00:00

132 lines
6.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Elm-on-SX: Elm 0.19 on the CEK/VM
Compile Elm source to SX AST; the existing CEK evaluator runs it. The unique angle: SX's
reactive island system (`defisland`, signals, `provide`/`context`) is a natural host for
The Elm Architecture — Model/Update/View maps almost directly onto SX's reactive runtime.
This is the only language in the set that targets SX's browser-side reactivity rather than
the server-side evaluator.
End-state goal: **core Elm programs running in the browser via SX islands**, with The Elm
Architecture wired to SX signals. Not a full Elm compiler — no exhaustiveness checking, no
module system, no type inference — but a faithful runtime that can run Elm programs written
in idiomatic style.
## Ground rules
- **Scope:** only touch `lib/elm/**` and `plans/elm-on-sx.md`. Do **not** edit `spec/`,
`hosts/`, `shared/`, or other `lib/<lang>/`.
- **Shared-file issues** go under "Blockers" below with a minimal repro; do not fix here.
- **SX files:** use `sx-tree` MCP tools only.
- **Architecture:** Elm source → Elm AST → SX AST. No standalone Elm evaluator.
- **Type system:** defer. Focus on runtime semantics. Type errors surface at eval time.
- **Commits:** one feature per commit. Keep `## Progress log` updated and tick boxes.
## Architecture sketch
```
Elm source text
lib/elm/tokenizer.sx — numbers, strings, idents, operators, indentation-sensitive lexer
lib/elm/parser.sx — Elm AST: module, import, type alias, type, let, case, lambda,
│ if, list/tuple/record literals, pipe operator |>
lib/elm/transpile.sx — Elm AST → SX AST
lib/elm/runtime.sx — TEA runtime: Program, sandbox, element; Cmd/Sub wrappers;
│ Html.* shims; Browser.* shims
SX island / reactive runtime (browser)
```
Key semantic mappings:
- `Model` → SX signal (`make-signal`)
- `update : Msg -> Model -> Model` → SX signal updater (called on each message)
- `view : Model -> Html Msg` → SX component (re-renders on model signal change)
- `Cmd` → SX `perform` IO request
- `Sub` → SX event listener registered via `dom-listen`
- `Maybe a``nil` (Nothing) or value (Just a) — uses ADTs from Phase 6 of primitives
- `Result a b` → ADT `(Ok val)` / `(Err err)`
## Roadmap
### Phase 1 — tokenizer + parser
- [ ] Tokenizer: keywords (`module`, `import`, `type`, `alias`, `let`, `in`, `if`, `then`,
`else`, `case`, `of`, `port`), indentation tokens (indent/dedent/newline), string
literals, number literals, operators (`|>`, `>>`, `<<`, `<|`, `++`, `::`), type vars
- [ ] Parser: module declaration, imports, type aliases, union types, function definitions
with pattern matching, `let`/`in`, `case`/`of`, `if`/`then`/`else`, lambda `\x -> e`,
list literals `[1,2,3]`, tuple literals `(a,b)`, record literals `{x=1, y=2}`,
record update `{ r | x = 1 }`, pipe operator `|>`
- [ ] Skip for phase 1: ports, subscriptions, effects manager, type annotations
- [ ] Tests in `lib/elm/tests/parse.sx`
### Phase 2 — transpile: expressions + pattern matching
- [ ] `elm-eval-ast` entry
- [ ] Arithmetic, string `++`, comparison, boolean ops
- [ ] Lambda → SX `fn`; function application
- [ ] `let`/`in` → SX `let`
- [ ] `if`/`then`/`else` → SX `if`
- [ ] `case`/`of` with constructor, literal, tuple, list, wildcard patterns → SX `cond`
using ADT match (Phase 6 primitives)
- [ ] List ops: `List.map`, `List.filter`, `List.foldl`, `List.foldr`
- [ ] `Maybe` and `Result` as ADTs
- [ ] 30+ eval tests in `lib/elm/tests/eval.sx`
### Phase 3 — The Elm Architecture runtime
- [ ] `Browser.sandbox` — pure TEA loop (no Cmds, no Subs)
`{ init : model, update : msg -> model -> model, view : model -> Html msg }`
Wires to: SX signal for model, SX component for view, message dispatch on user events
- [ ] `Html.*` shims: `div`, `p`, `button`, `input`, `text`, `h1``h6`, `ul`, `li`, `a`,
`span`, `img` — emit SX component calls
- [ ] `Html.Attributes.*`: `class`, `id`, `href`, `src`, `type_`, `placeholder`, `value`
- [ ] `Html.Events.*`: `onClick`, `onInput`, `onSubmit`, `onBlur`, `onFocus`
- [ ] `Browser.element` — adds `init` returning `(model, Cmd msg)`, `subscriptions`
- [ ] Demo: counter app (`init=0`, `update Increment m = m+1`, `view` shows count + button)
### Phase 4 — Cmds and Subs
- [ ] `Cmd` — mapped to SX `perform` IO requests. `Cmd.none`, `Cmd.batch`
- [ ] `Http.get`/`Http.post` → SX fetch IO
- [ ] `Sub` — mapped to SX `dom-listen`. `Sub.none`, `Sub.batch`
- [ ] `Browser.Events.onClick`, `onKeyPress`, `onAnimationFrame`
- [ ] `Time.every` — periodic subscription via SX timer IO
- [ ] `Task.perform`/`Task.attempt` — single-shot async operations
### Phase 5 — standard library
- [ ] `String.*``length`, `append`, `concat`, `split`, `join`, `trim`, `toUpper`, `toLower`,
`contains`, `startsWith`, `endsWith`, `replace`, `toInt`, `toFloat`, `fromInt`, `fromFloat`
- [ ] `List.*``map`, `filter`, `foldl`, `foldr`, `head`, `tail`, `isEmpty`, `length`,
`reverse`, `append`, `concat`, `member`, `sort`, `sortBy`, `indexedMap`, `range`
- [ ] `Dict.*` — SX immutable dict; `fromList`, `toList`, `get`, `insert`, `remove`, `update`,
`member`, `keys`, `values`, `map`, `filter`, `foldl`
- [ ] `Set.*` — SX set primitive (Phase 18); `fromList`, `toList`, `member`, `insert`,
`remove`, `union`, `intersect`, `diff`
- [ ] `Maybe.*``withDefault`, `map`, `andThen`, `map2`
- [ ] `Result.*``withDefault`, `map`, `andThen`, `mapError`, `toMaybe`
- [ ] `Tuple.*``first`, `second`, `pair`, `mapFirst`, `mapSecond`
- [ ] `Basics.*``identity`, `always`, `not`, `xor`, `modBy`, `remainderBy`, `clamp`,
`min`, `max`, `abs`, `sqrt`, `logBase`, `e`, `pi`, `floor`, `ceiling`, `round`,
`truncate`, `toFloat`, `isNaN`, `isInfinite`, `compare`
- [ ] `Random.*` — seed-based PRNG via SX IO perform
### Phase 6 — full browser integration
- [ ] `Browser.application` — URL routing, `onUrlChange`, `onUrlRequest`
- [ ] `Browser.Navigation.*``pushUrl`, `replaceUrl`, `back`, `forward`
- [ ] `Url.Parser.*` — path segment parsing
- [ ] `Json.Decode.*` — JSON decoder combinators
- [ ] `Json.Encode.*` — JSON encoder
- [ ] `Ports``port` keyword; JS interop via SX `host-call`
## Blockers
_(none yet)_
## Progress log
_Newest first._
_(awaiting phase 1)_