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)
This commit is contained in:
enzotar 2026-02-26 15:22:54 -08:00
parent 008f164ae7
commit 8a318e380e
3 changed files with 114 additions and 33 deletions

View file

@ -953,22 +953,27 @@ impl JsEmitter {
Expr::BinOp(left, op, right) => {
let l = self.emit_expr(left);
let r = self.emit_expr(right);
let op_str = match op {
BinOp::Add => "+",
BinOp::Sub => "-",
BinOp::Mul => "*",
BinOp::Div => "/",
BinOp::Mod => "%",
BinOp::Eq => "===",
BinOp::Neq => "!==",
BinOp::Lt => "<",
BinOp::Gt => ">",
BinOp::Lte => "<=",
BinOp::Gte => ">=",
BinOp::And => "&&",
BinOp::Or => "||",
};
format!("({l} {op_str} {r})")
match op {
BinOp::Div => format!("Math.trunc({l} / {r})"),
_ => {
let op_str = match op {
BinOp::Add => "+",
BinOp::Sub => "-",
BinOp::Mul => "*",
BinOp::Div => unreachable!(),
BinOp::Mod => "%",
BinOp::Eq => "===",
BinOp::Neq => "!==",
BinOp::Lt => "<",
BinOp::Gt => ">",
BinOp::Lte => "<=",
BinOp::Gte => ">=",
BinOp::And => "&&",
BinOp::Or => "||",
};
format!("({l} {op_str} {r})")
}
}
}
Expr::UnaryOp(op, inner) => {
let inner_js = self.emit_expr(inner);
@ -1290,22 +1295,27 @@ impl JsEmitter {
Expr::BinOp(left, op, right) => {
let l = Self::predicate_to_js(left, signal_name);
let r = Self::predicate_to_js(right, signal_name);
let op_str = match op {
BinOp::Gt => ">",
BinOp::Gte => ">=",
BinOp::Lt => "<",
BinOp::Lte => "<=",
BinOp::Eq => "===",
BinOp::Neq => "!==",
BinOp::And => "&&",
BinOp::Or => "||",
BinOp::Add => "+",
BinOp::Sub => "-",
BinOp::Mul => "*",
BinOp::Div => "/",
BinOp::Mod => "%",
};
format!("({} {} {})", l, op_str, r)
match op {
BinOp::Div => format!("Math.trunc({} / {})", l, r),
_ => {
let op_str = match op {
BinOp::Gt => ">",
BinOp::Gte => ">=",
BinOp::Lt => "<",
BinOp::Lte => "<=",
BinOp::Eq => "===",
BinOp::Neq => "!==",
BinOp::And => "&&",
BinOp::Or => "||",
BinOp::Add => "+",
BinOp::Sub => "-",
BinOp::Mul => "*",
BinOp::Div => unreachable!(),
BinOp::Mod => "%",
};
format!("({} {} {})", l, op_str, r)
}
}
}
Expr::UnaryOp(UnaryOp::Not, inner) => {
format!("!({})", Self::predicate_to_js(inner, signal_name))

View file

@ -335,7 +335,6 @@ impl Lexer {
"true" => TokenKind::True,
"false" => TokenKind::False,
"for" => TokenKind::For,
"in" => TokenKind::In,
"component" => TokenKind::Component,
"route" => TokenKind::Route,
"navigate" => TokenKind::Navigate,

View file

@ -0,0 +1,72 @@
-- DreamStack Full App Demo
-- Combines: each loops, variant props, container variants, reactive state
let tasks = ["Design landing page", "Build API endpoints", "Write unit tests", "Deploy to staging", "Code review PR #42"]
let done = ["Set up CI/CD", "Create database schema", "Auth integration"]
let total = 8
let completed = 3
let search = ""
let tab = "active"
view main = column [
-- Header
row [
text "🏗️ Project Tracker" { variant: "title" }
input { bind: search, placeholder: "Search tasks..." }
]
text "Track your sprint progress" { variant: "subtitle" }
-- Progress stats
row [
column [
text "Active" { variant: "subtitle" }
text "5" { variant: "title" }
text "In progress" { variant: "warning" }
] { variant: "card" }
column [
text "Completed" { variant: "subtitle" }
text "3" { variant: "title" }
text "✓ Done" { variant: "success" }
] { variant: "card" }
column [
text "Total" { variant: "subtitle" }
text "8" { variant: "title" }
text "37.5% complete" { variant: "info" }
] { variant: "card" }
]
-- Active tasks
column [
text "📋 Active Tasks" { variant: "title" }
each task in tasks ->
row [
text "○"
text task
text "TODO" { variant: "warning" }
]
] { variant: "card" }
-- Completed tasks
column [
text "✅ Completed" { variant: "title" }
each item in done ->
row [
text "✓"
text item
text "DONE" { variant: "success" }
]
] { variant: "card" }
-- Actions
row [
button "Add Task" { variant: "primary" }
button "Export" { variant: "secondary" }
button "Archive" { variant: "ghost" }
button "Delete All" { variant: "destructive" }
]
]