Commit graph

38 commits

Author SHA1 Message Date
enzotar
cbd6dfc7a6 feat: dynamic lists (push/remove/pop) + TodoMVC demo
- MethodCall AST node: obj.method(args) parsing
- Array push: items.push(x) → immutable spread+append
- Array remove: items.remove(idx) → filter by index
- Array pop: items.pop() → slice(0, -1)
- Fix: loop vars (todo, _idx) emitted without .value via is_local_var()
- Fix: _idx added to each loop scope for index-based event handlers
- New: examples/todomvc.ds — add, remove, clear all, fully reactive
2026-02-26 16:46:06 -08:00
enzotar
a7af39e900 fix: when/else parentNode null guard for slot context + match parser boundaries + showcase demo
- When/else inside slots: anchor parentNode is null during initial effect
  Fixed with named effect function + requestAnimationFrame retry
- Match parser now terminates on ] } else tokens (works inside containers)
- Updated Progress/Badge components
- Added examples/showcase.ds: 5-section demo exercising all features
2026-02-26 16:34:45 -08:00
enzotar
76bb1bb3a2 feat: slot/children composition for components
- AST: added Expr::Slot variant
- Parser: 'slot' keyword renders children, [...] bracket children after ComponentUse
- Codegen: DS_{name}(props, __children) factory pattern
- Type checker: Slot => Type::View
- Updated Card component with slot for children
- Added examples/slot-demo.ds
2026-02-26 16:14:35 -08:00
enzotar
bb65e10f5c feat: when/else conditional branching
- AST: When(cond, body) -> When(cond, body, Option<else_body>)
- Parser: optional 'else -> expr' after when body
- Codegen: reactive DOM swap with anchor comments
- Signal graph + type checker updated for 3-arg When
- Component prop signal wrapping: .value compatible accessors
- Added examples/when-else-demo.ds
2026-02-26 16:03:29 -08:00
enzotar
55dc24eecc fix: component prop signal wrapping + import demo
- emit_component_decl now wraps props in signal-like accessors
- Props use { get value() { return props.X; } } pattern
- Missing props default to empty string instead of null
- Added examples/import-demo.ds demonstrating 3-component import
- Zero console errors when rendering imported Card, Badge, Button
2026-02-26 15:46:55 -08:00
enzotar
8a318e380e fix: integer division + streaming restart
Codegen: BinOp::Div now emits Math.trunc(l / r)
- Clock displays 0:1:30 instead of 0.016:1.5:30
- Affects both emit_expr and predicate_to_js

Lexer: removed duplicate 'in' keyword mapping
- InKw at line 312 is canonical, removed old In at line 338

Examples: added project-tracker.ds (each loops + cards)
2026-02-26 15:22:54 -08:00
enzotar
008f164ae7 feat: each loop, dreamstack init, expanded registry
Language:
- each item in list -> template (reactive list rendering)
- each/in tokens in lexer, Expr::Each in AST
- Reactive forEach codegen with scope push/pop
- Container trailing props: column [...] { variant: card }

CLI:
- dreamstack init [name] - scaffold new project
- Generates app.ds, components/, dreamstack.json
- 4 starter components (button, card, badge, input)

Registry expanded to 11 components:
- NEW: progress, alert, separator, toggle, avatar
- All embedded via include_str!

CSS: progress bar, avatar, separator, alert variants,
toggle switch, stat values (230+ lines design system)

Examples:
- each-demo.ds: list rendering demo
- dashboard.ds: glassmorphism cards with container variant
2026-02-26 14:42:00 -08:00
enzotar
a290bc1891 feat: container variant props, 11-component registry, rich dashboard
Parser:
- column/row/stack now parse trailing { props } after ]
- Enables: column [...] { variant: "card" }

Codegen:
- Container props dispatch: variant, class, click, style, layout
- variant_to_css() maps (tag, variant) → CSS class
- variant_map_js() for dynamic variants via inline JS map
- 230+ lines design system CSS (button/badge/card/dialog/toast/
  progress/alert/separator/toggle/avatar/stat)

Registry (11 components):
- button, input, card, badge, dialog, toast
- NEW: progress, alert, separator, toggle, avatar
- All embedded via include_str! for offline use

Examples:
- showcase.ds: component gallery with variant prop
- dashboard.ds: admin dashboard with glassmorphism cards
2026-02-26 13:58:33 -08:00
enzotar
7805b94704 feat: component registry with styled variants, dreamstack add/convert CLI, and showcase
- Phase 1: Component parser + codegen (emit_component_decl, emit_component_use, emit_match)
- Phase 2: 6 registry components (button, input, card, badge, dialog, toast)
- Phase 3: dreamstack add CLI with dependency resolution and --list/--all
- Phase 4: dreamstack convert TSX→DS transpiler with --shadcn GitHub fetch
- Phase 5: 120+ lines variant CSS (buttons, badges, cards, dialog, toast, input)
- New example: showcase.ds demonstrating all component styles
2026-02-26 13:27:49 -08:00
enzotar
9ef28bb53a feat: dependent types — refinement types, type aliases, type annotations
- Lexer: added 'type' and 'where' keywords
- AST: TypeExpr::Refined, Declaration::TypeAlias, LetDecl.type_annotation
- Parser: parse_type_alias_decl, parse_type_expr (Named, Generic, where)
- Type system: Type::Refined, Predicate/PredicateExpr with evaluate_static()
- Errors: RefinementViolation, TypeAliasCycle (Elm-style messages)
- Checker: type alias registry, resolve_type_expr, ast_to_predicate,
  static refinement checking for literal values
- Codegen: Phase 1b runtime guards, predicate_to_js helper

Syntax: type PositiveInt = Int where value > 0
        let count: PositiveInt = 5  -- static check passes
        let count: PositiveInt = -1 -- compile error

118 tests pass (16 in ds-types, 5 new for refinements)
2026-02-26 11:09:33 -08:00
enzotar
a8235c48b3 feat: stream composition API — select, schema, relay filtering
1. Receiver-side `select` clause:
   - `stream from "url" { select: field1, field2 }`
   - Parser, AST, codegen all updated
   - Emits: `_connectStream(url, ["field1","field2"])`
   - Client-side _csFilter strips unwanted fields

2. Schema announcement (0x32):
   - Sources send output schema on connect
   - Lists registered signal names and mode

3. Relay schema cache:
   - ChannelState stores schema from 0x32
   - Forwarded to late-joining receivers

4. Relay-side subscribe filter (0x33):
   - Receivers send wanted fields after connecting
   - Relay strips unwanted JSON keys from 0x30/0x31
     frames before forwarding — saves bandwidth

Protocol: SchemaAnnounce=0x32, SubscribeFilter=0x33
54 tests pass, all crates build clean.
2026-02-26 10:07:47 -08:00
enzotar
b5d813b9af feat: chained signal composition — 3→1→final + mood mixing
Add compose-metrics.ds (Layer 1): receives counter+clock+stats,
derives uptime/events/status, re-streams on /peer/metrics. This app
is BOTH a receiver and a source.

Add compose-master.ds (Layer 2): receives chained metrics from
Layer 1 + mood direct from Layer 0. Demonstrates multi-layer
signal composition with independent stream mixing.

Verified: Uptime: 51s, Total Events: 9 flowing through the full
three-layer chain to the master dashboard.
2026-02-26 09:51:36 -08:00
enzotar
442a2db65e fix: use explicit /peer/counter channel for streaming-counter
The 'default' relay channel accumulated stale Source connections from
previous sessions, causing frame delivery issues to Receivers on
/stream/default. Moving counter to an explicit /peer/counter channel
(matching clock, stats, mood pattern) fixes the composition dashboard.

All 4 streams now show live data: Count: 3, Doubled: 6.
2026-02-26 09:45:07 -08:00
enzotar
8775860fdd feat: 4-app signal composition demo with explicit outputs
Add 3 new streaming apps with explicit output declarations:
- streaming-clock.ds: output hours, minutes, seconds (tick private)
- streaming-stats.ds: output total, average, max (sum private)
- streaming-mood.ds: output mood, energy, color (clicks private)

Add compose-dashboard.ds that receives all 4 streams via unique
relay channels (/stream/default, /stream/clock, /stream/stats,
/stream/mood) into a single dashboard view.

Each app demonstrates selective signal registration — only declared
outputs are streamed, internal state remains private.
2026-02-26 09:04:22 -08:00
enzotar
627ee44275 feat: explicit signal output API for stream declarations
Add 'output: field1, field2' syntax to stream declarations to control
which signals are exposed over the relay. Only listed signals are
registered in _signalRegistry (and thus streamed). Omitting output
streams all signals (backwards-compatible).

Also strips internal sync metadata (_pid, _v) from receiver state
so composition consumers only see clean signal values.

Parser: parse comma-separated idents after 'output:' key
AST: Vec<String> output field on StreamDecl
Codegen: conditional _registerSignal, delete _pid/_v on receive

Example: stream counter on 'ws://...' { mode: signal, output: count, doubled }
2026-02-26 08:56:32 -08:00
enzotar
b0e7de3b2e fix: signal composition — stream derived signals, fix identity check, correct relay routing
- Register derived signals in _signalRegistry so _streamSync includes them
- Auto-sync all signals (source + derived) after flush() recomputes effects
- Fix Object.assign identity check: create new object so signal setter detects changes
- Change _connectStream receiver path from /signal/main to /stream/default
- Initialize stream state with {} instead of null to prevent crashes
- Emit StreamFrom bindings directly without double-wrapping in signal()

Verified: static build shows Count: 9, Doubled: 18 on composition page.
HMR interference with WebSocket connections is a separate issue.
2026-02-25 23:55:05 -08:00
enzotar
a943d2e2e9 feat: peer mode relay + self-echo filtering for true bidirectional sync
- Added /peer/{name} route to relay: all clients are equal peers
- handle_peer: binary broadcast to all other peers, catchup for late joiners
- Simplified runtime: single /peer/ WS replaces dual source+receiver
- _peerId: random 8-char ID prevents self-echo from broadcast
- _pid in each diff JSON, filtered in _applyRemoteDiff
2026-02-25 21:37:17 -08:00
enzotar
69c7ff1e22 feat: bidirectional signal streaming sync
- _signalRegistry: maps signal names → signal objects
- _registerSignal: called after each DS.signal() declaration
- _applyRemoteDiff: JSON diff → update local signals + flush
- _initStreamReceiver: parallel receiver WS for incoming diffs
- Echo loop guard: _applyingRemoteDiff prevents re-broadcasting
- 0x31 handler in _handleRemoteInput for signal diff frames

Changes sync both directions: laptop → phone, phone → laptop.
2026-02-25 21:00:57 -08:00
enzotar
0369bf831f feat: todo app demo — streamable, showcases v2 builtins
Push, len, for-in with index, array access, if/then/else in elements,
string interpolation, input binding, streaming enabled.
40 lines of .ds code. Run: dreamstack stream examples/todo.ds
2026-02-25 20:51:01 -08:00
enzotar
6368b798cf feat: v2 module system — import/export with multi-file compilation
Syntax:
  import { Counter, shared_count } from "./shared"
  export let shared_count = 0
  export component Counter = ...

Implementation:
- Lexer: Import, Export keywords
- AST: ImportDecl(names, source), Export(name, inner_decl)
- Parser: parse_import_decl, parse_export_decl
- CLI: resolve_imports() — recursive file resolution, dedup, inline

Resolves relative paths, adds .ds extension, handles transitive imports.
110 tests, 0 failures.
2026-02-25 20:36:18 -08:00
enzotar
26d6c4f17a feat: v2 built-in functions — 90+ native functions
Array: len, push, pop, filter, map, concat, contains, reverse, slice,
  indexOf, find, some, every, flat, sort (mutating ops re-trigger signal)
Math: abs, min, max, floor, ceil, round, random, sqrt, pow, sin, cos,
  tan, atan2, clamp, lerp
String: split, join, trim, upper, lower, replace, starts_with, ends_with,
  char_at, substring
Conversion: int, float, string, bool
Console: log, debug, warn
Timer: delay

Also adds ExprStatement support for top-level expressions (log, push, etc).
110 tests, 0 failures.
2026-02-25 20:30:08 -08:00
enzotar
2aa2c7ad8e feat: step sequencer demo — reactive pads, playhead, BPM
Step sequencer: 4 instruments × 8 steps, timer-driven playhead,
toggleable pads, BPM controls with streaming. 75 lines of .ds code.

Parser fixes:
- UI elements checked before LParen (button (if ...) is element, not call)
- Element args support parenthesized expressions: button (if cond ...)
- StringInterp recognized as valid string start in parse_primary/parse_element

Codegen fixes:
- emit_expr checks local_vars: loop var i emits 'i' not 'i.value'
- Array index mutations re-trigger signal: pads.value = [...pads.value]

110 tests, 0 failures.
2026-02-25 19:33:12 -08:00
enzotar
392e478351 feat: WebRTC transport — peer-to-peer data channels with auto-fallback
Relay:
- /signal/{channel} path for SDP/ICE exchange via WebSocket
- handle_signaling broadcasts text messages between signaling peers
- signaling_tx broadcast channel in ChannelState
- 46 ds-stream tests (+2 signaling path tests)

JS Runtime:
- _initWebRTC(signalingUrl, streamUrl, mode) with RTCPeerConnection
- Unordered DataChannel (ordered:false, maxRetransmits:0) for low latency
- Auto-fallback: WebSocket starts immediately, WebRTC upgrades in ≤5s
- Data channel override of _streamSend for transparent binary protocol

Parser/AST:
- StreamTransport enum (WebSocket, WebRTC)
- transport field in StreamDecl
- Parses: stream x on url { mode: signal, transport: webrtc }

Codegen:
- WebRTC: emits DS._initWebRTC(sigUrl, streamUrl, mode)
- WebSocket: emits DS._initStream(url, mode) (unchanged)

97 tests, 0 failures
2026-02-25 15:02:31 -08:00
enzotar
e2570b5df4 feat(examples): add streaming-physics.ds, mark all roadmap items complete
- streaming-physics.ds: physics scene streaming via named /source/physics channel
- Updated BITSTREAM_INTEGRATION.md: Phase B/C items marked 
- 95 tests, 0 failures across workspace
2026-02-25 14:53:12 -08:00
enzotar
be811662bf feat(examples): add streaming .ds examples — compiler-native streaming
- streaming-counter.ds: reactive counter with 'stream counter on ws://...'
- streaming-receiver.ds: remote receiver with 'stream from ws://...'
- E2E verified: compiles to streaming JS, connects to relay, sends signal diffs
2026-02-25 14:34:41 -08:00
enzotar
439a775dec feat(compiler): complete bitstream integration — all 9 changes
- AST: StreamDecl, StreamMode, Declaration::Stream, StreamFrom struct variant
- Lexer: Pixel, Delta, Signals keywords
- Parser: parse_stream_decl with mode block, fixed TokenKind::On match
- Signal graph: streamable flag, SignalManifest, Declaration::Stream detection
- Checker: StreamFrom { source, .. } pattern
- Codegen: DS._initStream(), DS._connectStream(), DS._streamDiff() hooks
- Runtime JS: full streaming layer with binary protocol encoding
- Layout: to_bytes/from_bytes on LayoutRect

82 tests pass (5 new: 3 parser stream + 2 analyzer streamable)
2026-02-25 13:26:59 -08:00
enzotar
968d62d0bb feat(demos): sync protocol with Rust codec, add touch/gamepad support
- RLE format: 2-byte LE count (matches Rust rle_encode/rle_decode)
- Delta frames: FLAG_COMPRESSED flag set correctly
- Signal sync: FLAG_KEYFRAME flag + periodic sync every ~5s for late-join
- Source: handle touch, gamepad axis/button, resize inputs from receiver
- Receiver: touch event capture for mobile, ping frame handling
- Protocol constants: added FRAME_PING, INPUT_TOUCH, INPUT_GAMEPAD_*
2026-02-25 11:06:42 -08:00
enzotar
ea64617569 feat: physics language integration — scene container with Rapier2D WASM
- Add scene container to AST, lexer, parser, analyzer, and codegen
- Add circle/rect/line as UI elements for physics body declaration
- Compile scene {} to canvas + async WASM init + Rapier2D PhysicsWorld
- Reactive gravity via DS.effect() — bodies wake on gravity change
- Mouse drag interaction with impulse-based body movement
- Compile-time hex color parsing for body colors
- Fix is_signal_ref matching numeric literals (700.value bug)
- Fix body variable uniqueness (next_node_id per body)
- Fix gravity signal detection (check AST Ident before emit_expr)
- Add physics.ds example with 5 bodies + 4 gravity control buttons
- Update DREAMSTACK.md and IMPLEMENTATION_PLAN.md with Phase 10-11
- 39 tests pass across all crates, 22KB output
2026-02-25 10:58:43 -08:00
enzotar
d7961cdc98 feat: universal bitstream streaming — any input → any output
New crate: engine/ds-stream/
- Binary protocol: 16-byte header, typed frame/input enums
  - Frame types: Pixels, Delta, Audio, Signal, Neural (0x01-0x43)
  - Input types: Pointer, Key, Scroll, Gamepad, MIDI, BCI (0x01-0x90)
- WebSocket relay server (tokio + tungstenite)
  - Source → receivers: frame broadcast
  - Receivers → source: input routing
- Codec: encode/decode, XOR delta compression, RLE, convenience builders
- 17 unit tests, all passing

Streaming modes (stream-source.html):
1. Pixel mode: raw RGBA framebuffer (~28 MB/s)
2. Delta mode: XOR + RLE compression (~1-9 MB/s, 70-95% savings)
3. Signal mode: compact JSON signal diffs (~2 KB/s, 12000x reduction)
4. Neural mode: procedural SDF pixel generator (concept demo)
5. Audio channel: spring velocity→frequency synthesis
6. Multi-receiver: broadcast to all connected clients

Thin receiver client (stream-receiver.html, ~300 lines):
- Zero framework, zero build step
- Renders any incoming bitstream mode
- Local signal-diff renderer for signal mode
- AudioContext playback for audio frames
- Full input capture: click/drag, keyboard, scroll
- Per-channel bitstream bus visualization

DREAMSTACK.md: Phase 7 section with protocol spec
2026-02-25 10:29:44 -08:00
enzotar
a35d44bd59 feat: two-way binding, form props, and async resources
Phase 8 features:
- bind prop: two-way signal <-> input sync
- placeholder, value, style, disabled props
- DS.resource() for reactive async data fetching
- DS.fetchJSON() convenience wrapper
- Props-only element parsing: input { bind: x }
- examples/form.ds: contact form with validation

Fixed: double .value.value bug in bind codegen.
2026-02-25 08:08:37 -08:00
enzotar
adff40d47f feat: hash-based router + keyed list reconciliation
Phase 7 features:
- route "/path" -> body declarations with hash-based routing
- navigate "/path" built-in function
- DS.route signal tracks current hash path
- DS.matchRoute() with :param pattern matching
- DS.keyedList() for keyed DOM reconciliation
- Route-aware mounting: views + routes compose
- examples/router.ds: 3-page app (home/about/counter)
- State persists across route changes (10818 bytes)
2026-02-25 07:54:00 -08:00
enzotar
ca45c688df feat: for-in list rendering + component system
Phase 6 features:
- ForIn reactive list rendering: for item in items -> body
- Optional index binding: for item, idx in items -> body
- Component declarations: component Name(props) = body
- Component instantiation: ComponentUse { name, props }

Added across 5 crates:
- ds-parser: For/In/Component tokens, ForIn/ComponentDecl AST nodes
- ds-codegen: reactive list effect, component function emission
- ds-types: ForIn/ComponentUse type inference
- local_vars tracking for non-reactive for-in loop vars

Includes examples/list.ds showcasing for-in + when + signals.
2026-02-25 01:33:28 -08:00
enzotar
e3da3b2d8b feat: signal propagation benchmarks + dev server HMR fix
Benchmarks (examples/benchmarks.html):
- Wide Fan-Out: 1→1000 derived signals (46K ops/s)
- Deep Chain: 100-layer propagation (399K ops/s)
- Diamond Dependency: 500 glitch-free diamonds (16K ops/s)
- Batch Updates: 50 sources in single batch (89K ops/s)
- Effect Throughput: 500 effects (135K ops/s)
- Mixed Graph: realistic 10→30→10 topology (247K ops/s)

Dev server fix: replaced EventSource SSE (flickering) with
fetch-based polling every 500ms for stable HMR.
2026-02-25 01:06:07 -08:00
enzotar
bbdeb6b82b feat: showcase — What DreamStack Does That Nothing Else Can
Interactive page comparing 5 unique DreamStack capabilities vs React/Svelte/Solid/Vue:
1. Reactivity as a type (Signal<T> in the type system)
2. Algebraic effects (swappable side-effect handlers)
3. Springs are signals (physics auto-propagates through reactive graph)
4. Compile-time dependency graph (static analysis, dead signal elimination)
5. Constraint-based layout (Cassowary solver, not CSS hacks)

Includes live spring physics demo, interactive constraint layout toggle,
side-by-side code comparisons, Elm-style error previews, and comparison table.
2026-02-25 00:34:46 -08:00
enzotar
20ea2cb82e feat: Phase 5 — Live Playground with editor, preview, signal graph, console
- playground.html: full web IDE for DreamStack DSL
- Code editor with auto-compile (500ms debounce) + Ctrl+Enter
- Live preview: renders interactive UI from DreamStack code
- Signal graph: visualizes source signals, derived values, handlers, views
- Console: compile metrics, type inference (Signal<Int>, Derived<Bool>, etc.)
- 4 examples: counter, todo, effects, springs
- Dark theme with purple accent, premium glassmorphism design
2026-02-25 00:27:42 -08:00
enzotar
fcf2639d9b feat: Phase 2+3 — effects, streams, springs, search + dashboard
Phase 2 — Effect System & Streams:
- Algebraic effects (perform/handle/handleAsync) for composable,
  testable side-effects with swappable handlers
- Stream engine with map, filter, debounce, throttle, distinct,
  scan, flatMap, merge, fromEvent, fromSignal, fromPromise
- Search-with-autocomplete example: debounce + flatMap + effects

Phase 3 — Spring Physics:
- RK4 integrator with fixed substep and sleep-when-idle scheduler
- Springs are signals — anything that reads spring.value auto-updates
- Dashboard example: spring-animated sidebar, staggered card entrance,
  draggable spring ball with configurable stiffness/damping/mass

Runtime evolution: v0.1 (signals) → v0.2 (+ effects + streams) → v0.3 (+ springs)
2026-02-25 00:13:09 -08:00
enzotar
51cf09336b feat: TodoMVC example with full reactivity
Full todo app using DreamStack's signal runtime:
- Add/toggle/remove individual todos
- Filter by all/active/completed
- Clear completed batch action
- Derived reactive stats (total, active, done counts)
- Premium dark theme with glassmorphism, slide-in animations
- No VDOM, no re-renders — pure signal propagation
2026-02-25 00:06:20 -08:00
enzotar
a634152318 feat: DreamStack compiler foundation — Phase 0/1
Complete compiler pipeline from .ds source to reactive browser apps:

- ds-parser: lexer (string interpolation, operators, keywords) + recursive
  descent parser with operator precedence + full AST types
- ds-analyzer: signal graph extraction (source/derived classification),
  topological sort for glitch-free propagation, DOM binding analysis
- ds-codegen: JavaScript emitter with embedded reactive runtime (~3KB
  signal/derived/effect system) and dark-theme CSS design system
- ds-cli: build (compile to HTML+JS), dev (live server), check (analyze)

Verified working: source signals, derived signals, event handlers,
conditional rendering (when), 12 unit tests passing, 6.8KB output.
2026-02-25 00:03:06 -08:00