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
|
|
|
/// The AST for DreamStack.
|
|
|
|
|
/// Homoiconic: every node is also representable as data (tagged vectors/maps).
|
|
|
|
|
|
|
|
|
|
/// A complete DreamStack program is a list of top-level declarations.
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
pub struct Program {
|
|
|
|
|
pub declarations: Vec<Declaration>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Top-level declarations.
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
pub enum Declaration {
|
|
|
|
|
/// `let name = expr`
|
|
|
|
|
Let(LetDecl),
|
|
|
|
|
/// `view name = expr` or `view name(params) = expr`
|
|
|
|
|
View(ViewDecl),
|
|
|
|
|
/// `effect name(params): ReturnType`
|
|
|
|
|
Effect(EffectDecl),
|
|
|
|
|
/// `on event_name -> body`
|
|
|
|
|
OnHandler(OnHandler),
|
2026-02-25 01:33:28 -08:00
|
|
|
/// `component Name(props) = body`
|
|
|
|
|
Component(ComponentDecl),
|
2026-02-25 07:54:00 -08:00
|
|
|
/// `route "/path" -> view_expr`
|
|
|
|
|
Route(RouteDecl),
|
2026-02-25 10:58:43 -08:00
|
|
|
/// `constrain element.prop = expr`
|
|
|
|
|
Constrain(ConstrainDecl),
|
feat(compiler): full bitstream integration across 7 pipeline stages
AST: StreamDecl, StreamMode, Expr::StreamFrom { source, mode }
Lexer: Pixel, Delta, Signals keywords
Parser: parse_stream_decl() with mode parsing, StreamFrom expression
Signal Graph: streamable flag on SignalNode, auto-detect stream decls
Type Checker: StreamFrom returns Type::Stream
Codegen: emit_stream_init phase, StreamFrom → DS.streamConnect(),
streaming runtime JS (WebSocket relay, binary protocol, signal frames,
remote input handler, auto-reconnect)
CLI: 'dreamstack stream' command — compile+serve with streaming enabled,
auto-inject stream declaration for the first view
All 77 workspace tests pass, 0 failures.
2026-02-25 13:13:21 -08:00
|
|
|
/// `stream main on "ws://..." { mode: signal }`
|
|
|
|
|
Stream(StreamDecl),
|
2026-02-25 19:20:20 -08:00
|
|
|
/// `every 500 -> expr`
|
|
|
|
|
Every(EveryDecl),
|
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
|
|
|
/// Top-level expression statement: `log("hello")`, `push(items, x)`
|
|
|
|
|
ExprStatement(Expr),
|
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
|
|
|
/// `import { Card, Button } from "./components"`
|
|
|
|
|
Import(ImportDecl),
|
|
|
|
|
/// `export let count = 0`, `export component Card(...) = ...`
|
|
|
|
|
Export(String, Box<Declaration>),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// `import { Card, Button } from "./components"`
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
pub struct ImportDecl {
|
|
|
|
|
pub names: Vec<String>,
|
|
|
|
|
pub source: String,
|
|
|
|
|
pub span: Span,
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// `let count = 0` or `let doubled = count * 2`
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
pub struct LetDecl {
|
|
|
|
|
pub name: String,
|
|
|
|
|
pub value: Expr,
|
|
|
|
|
pub span: Span,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// `view counter = column [ ... ]`
|
|
|
|
|
/// `view profile(id: UserId) = ...`
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
pub struct ViewDecl {
|
|
|
|
|
pub name: String,
|
|
|
|
|
pub params: Vec<Param>,
|
|
|
|
|
pub body: Expr,
|
|
|
|
|
pub span: Span,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// `effect fetchUser(id: UserId): Result<User, ApiError>`
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
pub struct EffectDecl {
|
|
|
|
|
pub name: String,
|
|
|
|
|
pub params: Vec<Param>,
|
|
|
|
|
pub return_type: TypeExpr,
|
|
|
|
|
pub span: Span,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// `on toggle_sidebar -> ...`
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
pub struct OnHandler {
|
|
|
|
|
pub event: String,
|
|
|
|
|
pub param: Option<String>,
|
|
|
|
|
pub body: Expr,
|
|
|
|
|
pub span: Span,
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-25 01:33:28 -08:00
|
|
|
/// `component Card(title: String, children: View) = ...`
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
pub struct ComponentDecl {
|
|
|
|
|
pub name: String,
|
|
|
|
|
pub props: Vec<Param>,
|
|
|
|
|
pub body: Expr,
|
|
|
|
|
pub span: Span,
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-25 07:54:00 -08:00
|
|
|
/// `route "/users/:id" -> column [ text "User {id}" ]`
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
pub struct RouteDecl {
|
|
|
|
|
pub path: String,
|
|
|
|
|
pub body: Expr,
|
|
|
|
|
pub span: Span,
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-25 10:58:43 -08:00
|
|
|
/// `constrain sidebar.width = clamp(200, parent.width * 0.2, 350)`
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
pub struct ConstrainDecl {
|
|
|
|
|
pub element: String,
|
|
|
|
|
pub prop: String,
|
|
|
|
|
pub expr: Expr,
|
|
|
|
|
pub span: Span,
|
|
|
|
|
}
|
|
|
|
|
|
feat(compiler): full bitstream integration across 7 pipeline stages
AST: StreamDecl, StreamMode, Expr::StreamFrom { source, mode }
Lexer: Pixel, Delta, Signals keywords
Parser: parse_stream_decl() with mode parsing, StreamFrom expression
Signal Graph: streamable flag on SignalNode, auto-detect stream decls
Type Checker: StreamFrom returns Type::Stream
Codegen: emit_stream_init phase, StreamFrom → DS.streamConnect(),
streaming runtime JS (WebSocket relay, binary protocol, signal frames,
remote input handler, auto-reconnect)
CLI: 'dreamstack stream' command — compile+serve with streaming enabled,
auto-inject stream declaration for the first view
All 77 workspace tests pass, 0 failures.
2026-02-25 13:13:21 -08:00
|
|
|
/// `stream main on "ws://localhost:9100" { mode: signal }`
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
pub struct StreamDecl {
|
|
|
|
|
pub view_name: String,
|
|
|
|
|
pub relay_url: Expr,
|
|
|
|
|
pub mode: StreamMode,
|
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
|
|
|
pub transport: StreamTransport,
|
2026-02-26 08:56:32 -08:00
|
|
|
/// Explicit signal output list. Empty = stream all signals (backwards-compat).
|
|
|
|
|
pub output: Vec<String>,
|
feat(compiler): full bitstream integration across 7 pipeline stages
AST: StreamDecl, StreamMode, Expr::StreamFrom { source, mode }
Lexer: Pixel, Delta, Signals keywords
Parser: parse_stream_decl() with mode parsing, StreamFrom expression
Signal Graph: streamable flag on SignalNode, auto-detect stream decls
Type Checker: StreamFrom returns Type::Stream
Codegen: emit_stream_init phase, StreamFrom → DS.streamConnect(),
streaming runtime JS (WebSocket relay, binary protocol, signal frames,
remote input handler, auto-reconnect)
CLI: 'dreamstack stream' command — compile+serve with streaming enabled,
auto-inject stream declaration for the first view
All 77 workspace tests pass, 0 failures.
2026-02-25 13:13:21 -08:00
|
|
|
pub span: Span,
|
|
|
|
|
}
|
|
|
|
|
|
2026-02-25 19:20:20 -08:00
|
|
|
/// `every 500 -> expr` — periodic timer
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
pub struct EveryDecl {
|
|
|
|
|
pub interval_ms: Expr,
|
|
|
|
|
pub body: Expr,
|
|
|
|
|
pub span: Span,
|
|
|
|
|
}
|
|
|
|
|
|
feat(compiler): full bitstream integration across 7 pipeline stages
AST: StreamDecl, StreamMode, Expr::StreamFrom { source, mode }
Lexer: Pixel, Delta, Signals keywords
Parser: parse_stream_decl() with mode parsing, StreamFrom expression
Signal Graph: streamable flag on SignalNode, auto-detect stream decls
Type Checker: StreamFrom returns Type::Stream
Codegen: emit_stream_init phase, StreamFrom → DS.streamConnect(),
streaming runtime JS (WebSocket relay, binary protocol, signal frames,
remote input handler, auto-reconnect)
CLI: 'dreamstack stream' command — compile+serve with streaming enabled,
auto-inject stream declaration for the first view
All 77 workspace tests pass, 0 failures.
2026-02-25 13:13:21 -08:00
|
|
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
|
|
|
|
pub enum StreamMode {
|
|
|
|
|
Pixel, // raw RGBA framebuffer every frame
|
|
|
|
|
Delta, // XOR + RLE — only changed pixels
|
|
|
|
|
Signal, // JSON signal diffs (DreamStack-native)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Default for StreamMode {
|
|
|
|
|
fn default() -> Self { StreamMode::Signal }
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
|
|
|
|
pub enum StreamTransport {
|
|
|
|
|
WebSocket, // default — frames over WebSocket via relay
|
|
|
|
|
WebRTC, // peer-to-peer data channels, relay for signaling only
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl Default for StreamTransport {
|
|
|
|
|
fn default() -> Self { StreamTransport::WebSocket }
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
/// Function/view parameter.
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
pub struct Param {
|
|
|
|
|
pub name: String,
|
|
|
|
|
pub type_annotation: Option<TypeExpr>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Type expressions (simplified for Phase 0).
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
pub enum TypeExpr {
|
|
|
|
|
Named(String),
|
|
|
|
|
Generic(String, Vec<TypeExpr>),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Expressions — the core of the language.
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
pub enum Expr {
|
|
|
|
|
/// Integer literal: `42`
|
|
|
|
|
IntLit(i64),
|
|
|
|
|
/// Float literal: `3.14`
|
|
|
|
|
FloatLit(f64),
|
|
|
|
|
/// String literal: `"hello"` (may contain `{interpolation}`)
|
|
|
|
|
StringLit(StringLit),
|
|
|
|
|
/// Boolean literal: `true` / `false`
|
|
|
|
|
BoolLit(bool),
|
|
|
|
|
/// Identifier: `count`, `sidebar.width`
|
|
|
|
|
Ident(String),
|
|
|
|
|
/// Dotted access: `user.name`
|
|
|
|
|
DotAccess(Box<Expr>, String),
|
|
|
|
|
/// Binary operation: `a + b`, `count > 10`
|
|
|
|
|
BinOp(Box<Expr>, BinOp, Box<Expr>),
|
|
|
|
|
/// Unary operation: `-x`, `!flag`
|
|
|
|
|
UnaryOp(UnaryOp, Box<Expr>),
|
|
|
|
|
/// Assignment: `count += 1`, `panel_x.target = 0`
|
|
|
|
|
Assign(Box<Expr>, AssignOp, Box<Expr>),
|
|
|
|
|
/// Function call: `clamp(200, 20vw, 350)`
|
|
|
|
|
Call(String, Vec<Expr>),
|
|
|
|
|
/// Block: multiple expressions, last is the value
|
|
|
|
|
Block(Vec<Expr>),
|
|
|
|
|
/// View element: `text "hello"`, `button "+" { click: ... }`
|
|
|
|
|
Element(Element),
|
|
|
|
|
/// Container: `column [ ... ]`, `row [ ... ]`
|
|
|
|
|
Container(Container),
|
|
|
|
|
/// When conditional: `when count > 10 -> ...`
|
|
|
|
|
When(Box<Expr>, Box<Expr>),
|
|
|
|
|
/// Match expression
|
|
|
|
|
Match(Box<Expr>, Vec<MatchArm>),
|
|
|
|
|
/// Pipe: `expr | operator`
|
|
|
|
|
Pipe(Box<Expr>, Box<Expr>),
|
|
|
|
|
/// `perform effectName(args)`
|
|
|
|
|
Perform(String, Vec<Expr>),
|
|
|
|
|
/// `stream from source`
|
feat(compiler): full bitstream integration across 7 pipeline stages
AST: StreamDecl, StreamMode, Expr::StreamFrom { source, mode }
Lexer: Pixel, Delta, Signals keywords
Parser: parse_stream_decl() with mode parsing, StreamFrom expression
Signal Graph: streamable flag on SignalNode, auto-detect stream decls
Type Checker: StreamFrom returns Type::Stream
Codegen: emit_stream_init phase, StreamFrom → DS.streamConnect(),
streaming runtime JS (WebSocket relay, binary protocol, signal frames,
remote input handler, auto-reconnect)
CLI: 'dreamstack stream' command — compile+serve with streaming enabled,
auto-inject stream declaration for the first view
All 77 workspace tests pass, 0 failures.
2026-02-25 13:13:21 -08:00
|
|
|
StreamFrom {
|
|
|
|
|
source: String,
|
|
|
|
|
mode: Option<StreamMode>,
|
2026-02-26 10:07:47 -08:00
|
|
|
/// Receiver-side field selector. Empty = receive all fields.
|
|
|
|
|
select: Vec<String>,
|
feat(compiler): full bitstream integration across 7 pipeline stages
AST: StreamDecl, StreamMode, Expr::StreamFrom { source, mode }
Lexer: Pixel, Delta, Signals keywords
Parser: parse_stream_decl() with mode parsing, StreamFrom expression
Signal Graph: streamable flag on SignalNode, auto-detect stream decls
Type Checker: StreamFrom returns Type::Stream
Codegen: emit_stream_init phase, StreamFrom → DS.streamConnect(),
streaming runtime JS (WebSocket relay, binary protocol, signal frames,
remote input handler, auto-reconnect)
CLI: 'dreamstack stream' command — compile+serve with streaming enabled,
auto-inject stream declaration for the first view
All 77 workspace tests pass, 0 failures.
2026-02-25 13:13:21 -08:00
|
|
|
},
|
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
|
|
|
/// Lambda: `(x -> x * 2)`
|
|
|
|
|
Lambda(Vec<String>, Box<Expr>),
|
|
|
|
|
/// Record literal: `{ key: value, ... }`
|
|
|
|
|
Record(Vec<(String, Expr)>),
|
|
|
|
|
/// List literal: `[a, b, c]`
|
|
|
|
|
List(Vec<Expr>),
|
|
|
|
|
/// `if cond then a else b`
|
|
|
|
|
If(Box<Expr>, Box<Expr>, Box<Expr>),
|
|
|
|
|
/// Spring: `spring(target: 0, stiffness: 300, damping: 30)`
|
|
|
|
|
Spring(Vec<(String, Expr)>),
|
2026-02-25 01:33:28 -08:00
|
|
|
/// `for item in items -> body` with optional index `for item, i in items -> body`
|
|
|
|
|
ForIn {
|
|
|
|
|
item: String,
|
|
|
|
|
index: Option<String>,
|
|
|
|
|
iter: Box<Expr>,
|
|
|
|
|
body: Box<Expr>,
|
|
|
|
|
},
|
|
|
|
|
/// Component instantiation: `<Card title="hello" />`
|
|
|
|
|
ComponentUse {
|
|
|
|
|
name: String,
|
|
|
|
|
props: Vec<(String, Expr)>,
|
|
|
|
|
children: Vec<Expr>,
|
|
|
|
|
},
|
2026-02-25 19:20:20 -08:00
|
|
|
/// Index access: `grid[i]`, `pads[8 + i]`
|
|
|
|
|
Index(Box<Expr>, Box<Expr>),
|
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
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// String literal with interpolation segments.
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
pub struct StringLit {
|
|
|
|
|
pub segments: Vec<StringSegment>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
pub enum StringSegment {
|
|
|
|
|
Literal(String),
|
|
|
|
|
Interpolation(Box<Expr>),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Binary operators.
|
|
|
|
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
|
|
|
|
pub enum BinOp {
|
|
|
|
|
Add,
|
|
|
|
|
Sub,
|
|
|
|
|
Mul,
|
|
|
|
|
Div,
|
|
|
|
|
Mod,
|
|
|
|
|
Eq,
|
|
|
|
|
Neq,
|
|
|
|
|
Lt,
|
|
|
|
|
Gt,
|
|
|
|
|
Lte,
|
|
|
|
|
Gte,
|
|
|
|
|
And,
|
|
|
|
|
Or,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Unary operators.
|
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
|
|
|
pub enum UnaryOp {
|
|
|
|
|
Neg,
|
|
|
|
|
Not,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Assignment operators.
|
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
|
|
|
pub enum AssignOp {
|
|
|
|
|
Set,
|
|
|
|
|
AddAssign,
|
|
|
|
|
SubAssign,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// A UI element: `text label`, `button "+" { click: handler }`
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
pub struct Element {
|
|
|
|
|
pub tag: String,
|
|
|
|
|
pub args: Vec<Expr>,
|
|
|
|
|
pub props: Vec<(String, Expr)>,
|
|
|
|
|
pub modifiers: Vec<Modifier>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// A container: `column [ child1, child2 ]`
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
pub struct Container {
|
|
|
|
|
pub kind: ContainerKind,
|
|
|
|
|
pub children: Vec<Expr>,
|
|
|
|
|
pub props: Vec<(String, Expr)>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
pub enum ContainerKind {
|
|
|
|
|
Column,
|
|
|
|
|
Row,
|
|
|
|
|
Stack,
|
|
|
|
|
List,
|
|
|
|
|
Panel,
|
|
|
|
|
Form,
|
2026-02-25 10:58:43 -08:00
|
|
|
Scene,
|
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
|
|
|
Custom(String),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Match arm: `Ok(u) -> column [ ... ]`
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
pub struct MatchArm {
|
|
|
|
|
pub pattern: Pattern,
|
|
|
|
|
pub body: Expr,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Pattern matching.
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
pub enum Pattern {
|
|
|
|
|
Wildcard,
|
|
|
|
|
Ident(String),
|
|
|
|
|
Constructor(String, Vec<Pattern>),
|
|
|
|
|
Literal(Expr),
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Modifiers: `| animate fade-in 200ms`
|
|
|
|
|
#[derive(Debug, Clone)]
|
|
|
|
|
pub struct Modifier {
|
|
|
|
|
pub name: String,
|
|
|
|
|
pub args: Vec<Expr>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Source location tracking.
|
|
|
|
|
#[derive(Debug, Clone, Copy, Default)]
|
|
|
|
|
pub struct Span {
|
|
|
|
|
pub start: usize,
|
|
|
|
|
pub end: usize,
|
|
|
|
|
pub line: usize,
|
|
|
|
|
}
|