feat: multi-statement event handlers with semicolons
- Added Semicolon token to lexer - Enables: click: items.push(x); input = "" - Push-and-clear, increment-and-reset, clear-all patterns - Browser-verified: both actions fire in one click - All existing examples pass regression
This commit is contained in:
parent
6c9d109ebd
commit
10b2717281
3 changed files with 48 additions and 1 deletions
|
|
@ -82,6 +82,7 @@ pub enum TokenKind {
|
||||||
PlusEq, // +=
|
PlusEq, // +=
|
||||||
MinusEq, // -=
|
MinusEq, // -=
|
||||||
Arrow, // ->
|
Arrow, // ->
|
||||||
|
Semicolon, // ;
|
||||||
Pipe, // |
|
Pipe, // |
|
||||||
Dot, // .
|
Dot, // .
|
||||||
|
|
||||||
|
|
@ -223,6 +224,7 @@ impl Lexer {
|
||||||
'>' => { self.advance(); Token { kind: TokenKind::Gt, lexeme: ">".into(), line, col } }
|
'>' => { self.advance(); Token { kind: TokenKind::Gt, lexeme: ">".into(), line, col } }
|
||||||
'!' => { self.advance(); Token { kind: TokenKind::Not, lexeme: "!".into(), line, col } }
|
'!' => { self.advance(); Token { kind: TokenKind::Not, lexeme: "!".into(), line, col } }
|
||||||
'|' => { self.advance(); Token { kind: TokenKind::Pipe, lexeme: "|".into(), line, col } }
|
'|' => { self.advance(); Token { kind: TokenKind::Pipe, lexeme: "|".into(), line, col } }
|
||||||
|
';' => { self.advance(); Token { kind: TokenKind::Semicolon, lexeme: ";".into(), line, col } }
|
||||||
'.' => { self.advance(); Token { kind: TokenKind::Dot, lexeme: ".".into(), line, col } }
|
'.' => { self.advance(); Token { kind: TokenKind::Dot, lexeme: ".".into(), line, col } }
|
||||||
'(' => { self.advance(); Token { kind: TokenKind::LParen, lexeme: "(".into(), line, col } }
|
'(' => { self.advance(); Token { kind: TokenKind::LParen, lexeme: "(".into(), line, col } }
|
||||||
')' => { self.advance(); Token { kind: TokenKind::RParen, lexeme: ")".into(), line, col } }
|
')' => { self.advance(); Token { kind: TokenKind::RParen, lexeme: ")".into(), line, col } }
|
||||||
|
|
|
||||||
|
|
@ -1355,7 +1355,24 @@ impl Parser {
|
||||||
let key = self.expect_ident()?;
|
let key = self.expect_ident()?;
|
||||||
self.expect(&TokenKind::Colon)?;
|
self.expect(&TokenKind::Colon)?;
|
||||||
self.skip_newlines();
|
self.skip_newlines();
|
||||||
let val = self.parse_expr()?;
|
let first = self.parse_expr()?;
|
||||||
|
// Multi-action: `click: action1; action2; action3`
|
||||||
|
// Collects semicolon-separated expressions into a Block
|
||||||
|
let val = if self.check(&TokenKind::Semicolon) {
|
||||||
|
let mut exprs = vec![first];
|
||||||
|
while self.check(&TokenKind::Semicolon) {
|
||||||
|
self.advance(); // consume ';'
|
||||||
|
self.skip_newlines();
|
||||||
|
// Stop if we hit } (end of props) or , (next prop)
|
||||||
|
if self.check(&TokenKind::RBrace) || self.check(&TokenKind::Comma) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
exprs.push(self.parse_expr()?);
|
||||||
|
}
|
||||||
|
Expr::Block(exprs)
|
||||||
|
} else {
|
||||||
|
first
|
||||||
|
};
|
||||||
props.push((key, val));
|
props.push((key, val));
|
||||||
self.skip_newlines();
|
self.skip_newlines();
|
||||||
if self.check(&TokenKind::Comma) {
|
if self.check(&TokenKind::Comma) {
|
||||||
|
|
|
||||||
28
examples/multi-action.ds
Normal file
28
examples/multi-action.ds
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
-- Multi-Action Click Handler Test
|
||||||
|
-- Tests semicolon-separated actions in click handlers
|
||||||
|
|
||||||
|
let items = ["Buy milk", "Walk dog"]
|
||||||
|
let input = ""
|
||||||
|
let count = 0
|
||||||
|
|
||||||
|
view main = column [
|
||||||
|
text "Multi-Action Demo" { variant: "title" }
|
||||||
|
text "Add items AND clear input in one click" { variant: "subtitle" }
|
||||||
|
|
||||||
|
row [
|
||||||
|
input { bind: input, placeholder: "New item..." }
|
||||||
|
button "Add & Clear" { click: items.push(input); input = "", variant: "primary" }
|
||||||
|
]
|
||||||
|
|
||||||
|
each item in items ->
|
||||||
|
row [
|
||||||
|
text "• {item}"
|
||||||
|
button "×" { click: items.remove(_idx), variant: "ghost" }
|
||||||
|
]
|
||||||
|
|
||||||
|
text "Count: {count}"
|
||||||
|
row [
|
||||||
|
button "+5 & Reset Name" { click: count += 5; input = "reset!", variant: "secondary" }
|
||||||
|
button "Reset All" { click: count = 0; items = [], variant: "ghost" }
|
||||||
|
]
|
||||||
|
]
|
||||||
Loading…
Add table
Reference in a new issue