Skip to content

Commit c213d7a

Browse files
committed
feat: Add more Zig grammar features
- Add for loop support (for iterating over slices) - Add logical operators (and, or) with proper precedence - Add string literal support with escape sequences - Fix unary operator handling with separate rule
1 parent bc66bca commit c213d7a

2 files changed

Lines changed: 56 additions & 7 deletions

File tree

crates/zyn_peg/grammars/zig.zyn

Lines changed: 54 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ primitive_type = { "i8" | "i16" | "i32" | "i64" | "u8" | "u16" | "u32" | "u64" |
151151

152152
// ===== Statements =====
153153

154-
statement = { if_stmt | while_stmt | return_stmt | local_const | local_var | assign_stmt | expr_stmt }
154+
statement = { if_stmt | while_stmt | for_stmt | return_stmt | local_const | local_var | assign_stmt | expr_stmt }
155155
-> TypedStatement {
156156
"get_child": { "index": 0 }
157157
}
@@ -192,6 +192,18 @@ while_stmt = { "while" ~ "(" ~ expr ~ ")" ~ block }
192192
]
193193
}
194194

195+
// For loop: for (slice) |item| { ... }
196+
for_stmt = { "for" ~ "(" ~ expr ~ ")" ~ "|" ~ identifier ~ "|" ~ block }
197+
-> TypedStatement {
198+
"commands": [
199+
{ "define": "for", "args": {
200+
"iterable": "$1",
201+
"binding": "$2",
202+
"body": "$3"
203+
}}
204+
]
205+
}
206+
195207
// Assignment statement: identifier = expr;
196208
assign_stmt = { identifier ~ "=" ~ expr ~ ";" }
197209
-> TypedStatement {
@@ -281,12 +293,24 @@ block = { "{" ~ statement* ~ "}" }
281293

282294
// ===== Expressions =====
283295

284-
expr = { comparison }
296+
expr = { logical_or }
285297
-> TypedExpression {
286298
"get_child": { "index": 0 }
287299
}
288300

289-
// Comparison operators (lowest precedence)
301+
// Logical OR (lowest precedence)
302+
logical_or = { logical_and ~ (or_op ~ logical_and)* }
303+
-> TypedExpression {
304+
"fold_binary": { "operand": "logical_and", "operator": "or_op" }
305+
}
306+
307+
// Logical AND
308+
logical_and = { comparison ~ (and_op ~ comparison)* }
309+
-> TypedExpression {
310+
"fold_binary": { "operand": "comparison", "operator": "and_op" }
311+
}
312+
313+
// Comparison operators
290314
comparison = { addition ~ ((eq_op | neq_op | lte_op | gte_op | lt_op | gt_op) ~ addition)* }
291315
-> TypedExpression {
292316
"fold_binary": { "operand": "addition", "operator": "eq_op|neq_op|lte_op|gte_op|lt_op|gt_op" }
@@ -302,12 +326,19 @@ multiplication = { unary ~ ((mul_op | div_op) ~ unary)* }
302326
"fold_binary": { "operand": "unary", "operator": "mul_op|div_op" }
303327
}
304328

305-
unary = { unary_op? ~ primary }
329+
unary = { unary_with_op | primary }
306330
-> TypedExpression {
307331
"get_child": { "index": 0 }
308332
}
309333

310-
primary = { bool_literal | integer_literal | call_expr | identifier_expr | paren_expr }
334+
unary_with_op = { unary_op ~ primary }
335+
-> TypedExpression {
336+
"commands": [
337+
{ "define": "unary", "args": { "op": "$1", "operand": "$2" } }
338+
]
339+
}
340+
341+
primary = { bool_literal | string_literal | integer_literal | call_expr | identifier_expr | paren_expr }
311342
-> TypedExpression {
312343
"get_child": { "index": 0 }
313344
}
@@ -354,6 +385,17 @@ integer_literal = @{ "-"? ~ ASCII_DIGIT+ }
354385
"args": { "value": "$result" }
355386
}
356387

388+
string_literal = @{ "\"" ~ string_inner* ~ "\"" }
389+
-> TypedExpression {
390+
"get_text": true,
391+
"define": "string_literal",
392+
"args": { "value": "$result" }
393+
}
394+
395+
string_inner = { (!("\"" | "\\") ~ ANY) | escape_seq }
396+
397+
escape_seq = { "\\" ~ ("n" | "r" | "t" | "\\" | "\"" | "0") }
398+
357399
// ===== Identifiers =====
358400

359401
identifier = @{ (ASCII_ALPHA | "_") ~ (ASCII_ALPHANUMERIC | "_")* }
@@ -363,6 +405,13 @@ identifier = @{ (ASCII_ALPHA | "_") ~ (ASCII_ALPHANUMERIC | "_")* }
363405

364406
// ===== Operators =====
365407

408+
// Logical operators
409+
and_op = { "and" }
410+
-> String { "get_text": true }
411+
412+
or_op = { "or" }
413+
-> String { "get_text": true }
414+
366415
// Comparison operators (must check longer operators first)
367416
eq_op = { "==" }
368417
-> String { "get_text": true }

crates/zyn_peg/src/runtime.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1794,7 +1794,7 @@ impl<'a, H: AstHostFunctions> CommandInterpreter<'a, H> {
17941794
Ok(RuntimeValue::Node(handle))
17951795
}
17961796

1797-
"unary_op" => {
1797+
"unary_op" | "unary" => {
17981798
let op = match args.get("op").or(args.get("operator")) {
17991799
Some(RuntimeValue::String(s)) => s.clone(),
18001800
_ => "-".to_string(),
@@ -2137,7 +2137,7 @@ impl<'a, H: AstHostFunctions> CommandInterpreter<'a, H> {
21372137
}
21382138

21392139
"for_stmt" | "for" => {
2140-
let variable = match args.get("variable").or(args.get("iterator")) {
2140+
let variable = match args.get("variable").or(args.get("iterator")).or(args.get("binding")) {
21412141
Some(RuntimeValue::String(s)) => s.clone(),
21422142
Some(RuntimeValue::Node(h)) => {
21432143
// If it's a node, try to extract the name

0 commit comments

Comments
 (0)