Skip to content

Commit bc66bca

Browse files
committed
feat: Extend zig.zyn grammar with control flow and operators
- Add if statements (if_only, if_else variants) - Add while loop support - Add comparison operators (==, !=, <=, >=, <, >) - Add assignment statements with BinaryOp::Assign - Add function call expressions - Add bool_literal handling - Fix TypedAstBuilder to store blocks separately - Fix if/while/for to use get_block() for proper block retrieval
1 parent 4d2f12e commit bc66bca

2 files changed

Lines changed: 155 additions & 31 deletions

File tree

crates/zyn_peg/grammars/zig.zyn

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

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

154-
statement = { return_stmt | local_const | local_var | expr_stmt }
154+
statement = { if_stmt | while_stmt | return_stmt | local_const | local_var | assign_stmt | expr_stmt }
155155
-> TypedStatement {
156156
"get_child": { "index": 0 }
157157
}
158158

159+
// If statement variants
160+
if_stmt = { if_else | if_only }
161+
-> TypedStatement { "get_child": { "index": 0 } }
162+
163+
if_only = { "if" ~ "(" ~ expr ~ ")" ~ block }
164+
-> TypedStatement {
165+
"commands": [
166+
{ "define": "if", "args": {
167+
"condition": "$1",
168+
"then_branch": "$2"
169+
}}
170+
]
171+
}
172+
173+
if_else = { "if" ~ "(" ~ expr ~ ")" ~ block ~ "else" ~ block }
174+
-> TypedStatement {
175+
"commands": [
176+
{ "define": "if", "args": {
177+
"condition": "$1",
178+
"then_branch": "$2",
179+
"else_branch": "$3"
180+
}}
181+
]
182+
}
183+
184+
// While loop
185+
while_stmt = { "while" ~ "(" ~ expr ~ ")" ~ block }
186+
-> TypedStatement {
187+
"commands": [
188+
{ "define": "while", "args": {
189+
"condition": "$1",
190+
"body": "$2"
191+
}}
192+
]
193+
}
194+
195+
// Assignment statement: identifier = expr;
196+
assign_stmt = { identifier ~ "=" ~ expr ~ ";" }
197+
-> TypedStatement {
198+
"commands": [
199+
{ "define": "assignment", "args": {
200+
"target": "$1",
201+
"value": "$2"
202+
}}
203+
]
204+
}
205+
159206
// Children (non-silent): expr?
160207
return_stmt = { "return" ~ expr? ~ ";" }
161208
-> TypedStatement {
@@ -234,11 +281,17 @@ block = { "{" ~ statement* ~ "}" }
234281

235282
// ===== Expressions =====
236283

237-
expr = { addition }
284+
expr = { comparison }
238285
-> TypedExpression {
239286
"get_child": { "index": 0 }
240287
}
241288

289+
// Comparison operators (lowest precedence)
290+
comparison = { addition ~ ((eq_op | neq_op | lte_op | gte_op | lt_op | gt_op) ~ addition)* }
291+
-> TypedExpression {
292+
"fold_binary": { "operand": "addition", "operator": "eq_op|neq_op|lte_op|gte_op|lt_op|gt_op" }
293+
}
294+
242295
addition = { multiplication ~ ((add_op | sub_op) ~ multiplication)* }
243296
-> TypedExpression {
244297
"fold_binary": { "operand": "multiplication", "operator": "add_op|sub_op" }
@@ -254,13 +307,29 @@ unary = { unary_op? ~ primary }
254307
"get_child": { "index": 0 }
255308
}
256309

257-
primary = { integer_literal | identifier_expr | paren_expr }
310+
primary = { bool_literal | integer_literal | call_expr | identifier_expr | paren_expr }
258311
-> TypedExpression {
259312
"get_child": { "index": 0 }
260313
}
261314

262315
paren_expr = _{ "(" ~ expr ~ ")" }
263316

317+
// Function call expression: identifier(args...)
318+
call_expr = { identifier ~ "(" ~ call_args? ~ ")" }
319+
-> TypedExpression {
320+
"commands": [
321+
{ "define": "call", "args": {
322+
"callee": "$1",
323+
"args": "$2"
324+
}}
325+
]
326+
}
327+
328+
call_args = { expr ~ ("," ~ expr)* }
329+
-> List {
330+
"get_all_children": true
331+
}
332+
264333
identifier_expr = { identifier }
265334
-> TypedExpression {
266335
"get_text": true,
@@ -270,6 +339,13 @@ identifier_expr = { identifier }
270339

271340
// ===== Literals =====
272341

342+
bool_literal = { "true" | "false" }
343+
-> TypedExpression {
344+
"get_text": true,
345+
"define": "bool_literal",
346+
"args": { "value": "$result" }
347+
}
348+
273349
integer_literal = @{ "-"? ~ ASCII_DIGIT+ }
274350
-> TypedExpression {
275351
"get_text": true,
@@ -287,6 +363,26 @@ identifier = @{ (ASCII_ALPHA | "_") ~ (ASCII_ALPHANUMERIC | "_")* }
287363

288364
// ===== Operators =====
289365

366+
// Comparison operators (must check longer operators first)
367+
eq_op = { "==" }
368+
-> String { "get_text": true }
369+
370+
neq_op = { "!=" }
371+
-> String { "get_text": true }
372+
373+
lte_op = { "<=" }
374+
-> String { "get_text": true }
375+
376+
gte_op = { ">=" }
377+
-> String { "get_text": true }
378+
379+
lt_op = { "<" }
380+
-> String { "get_text": true }
381+
382+
gt_op = { ">" }
383+
-> String { "get_text": true }
384+
385+
// Arithmetic operators
290386
add_op = { "+" }
291387
-> String { "get_text": true }
292388

crates/zyn_peg/src/runtime.rs

Lines changed: 56 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1136,16 +1136,23 @@ impl AstHostFunctions for TypedAstBuilder {
11361136
fn create_assignment(&mut self, target: NodeHandle, value: NodeHandle) -> NodeHandle {
11371137
let span = self.default_span();
11381138

1139-
// Assignment is represented as an expression statement with binary op
1140-
// For simplicity, we'll create an expression statement
1139+
// Get target and value expressions
11411140
let target_expr = self.get_expr(target)
11421141
.unwrap_or_else(|| self.inner.variable("target", Type::Primitive(PrimitiveType::I32), span));
11431142
let value_expr = self.get_expr(value)
11441143
.unwrap_or_else(|| self.inner.int_literal(0, span));
11451144

1146-
// For now, wrap as expression (proper assignment would need TypedAssignment)
1147-
let _ = target_expr; // TODO: proper assignment
1148-
let stmt = self.inner.expression_statement(value_expr, span);
1145+
// Create assignment as a binary expression: target = value
1146+
let assign_expr = self.inner.binary(
1147+
BinaryOp::Assign,
1148+
target_expr,
1149+
value_expr,
1150+
Type::Primitive(PrimitiveType::Unit),
1151+
span,
1152+
);
1153+
1154+
// Wrap in expression statement
1155+
let stmt = self.inner.expression_statement(assign_expr, span);
11491156
self.store_stmt(stmt)
11501157
}
11511158

@@ -1174,24 +1181,28 @@ impl AstHostFunctions for TypedAstBuilder {
11741181
let cond_expr = self.get_expr(condition)
11751182
.unwrap_or_else(|| self.inner.bool_literal(true, span));
11761183

1177-
let then_stmts = if let Some(stmt) = self.get_stmt(then_branch) {
1178-
vec![stmt]
1184+
// Get the then block - check for block first, then statement, then expression
1185+
let then_block = if let Some(block) = self.get_block(then_branch) {
1186+
block
1187+
} else if let Some(stmt) = self.get_stmt(then_branch) {
1188+
TypedBlock { statements: vec![stmt], span }
11791189
} else if let Some(expr) = self.get_expr(then_branch) {
1180-
vec![self.inner.expression_statement(expr, span)]
1190+
TypedBlock { statements: vec![self.inner.expression_statement(expr, span)], span }
11811191
} else {
1182-
vec![]
1192+
TypedBlock { statements: vec![], span }
11831193
};
1184-
let then_block = self.inner.block(then_stmts, span);
11851194

1195+
// Get the else block if present
11861196
let else_block = else_branch.map(|h| {
1187-
let else_stmts = if let Some(stmt) = self.get_stmt(h) {
1188-
vec![stmt]
1197+
if let Some(block) = self.get_block(h) {
1198+
block
1199+
} else if let Some(stmt) = self.get_stmt(h) {
1200+
TypedBlock { statements: vec![stmt], span }
11891201
} else if let Some(expr) = self.get_expr(h) {
1190-
vec![self.inner.expression_statement(expr, span)]
1202+
TypedBlock { statements: vec![self.inner.expression_statement(expr, span)], span }
11911203
} else {
1192-
vec![]
1193-
};
1194-
self.inner.block(else_stmts, span)
1204+
TypedBlock { statements: vec![], span }
1205+
}
11951206
});
11961207

11971208
let stmt = self.inner.if_statement(cond_expr, then_block, else_block, span);
@@ -1204,14 +1215,16 @@ impl AstHostFunctions for TypedAstBuilder {
12041215
let cond_expr = self.get_expr(condition)
12051216
.unwrap_or_else(|| self.inner.bool_literal(true, span));
12061217

1207-
let body_stmts = if let Some(stmt) = self.get_stmt(body) {
1208-
vec![stmt]
1218+
// Get body block - check for block first, then statement, then expression
1219+
let body_block = if let Some(block) = self.get_block(body) {
1220+
block
1221+
} else if let Some(stmt) = self.get_stmt(body) {
1222+
TypedBlock { statements: vec![stmt], span }
12091223
} else if let Some(expr) = self.get_expr(body) {
1210-
vec![self.inner.expression_statement(expr, span)]
1224+
TypedBlock { statements: vec![self.inner.expression_statement(expr, span)], span }
12111225
} else {
1212-
vec![]
1226+
TypedBlock { statements: vec![], span }
12131227
};
1214-
let body_block = self.inner.block(body_stmts, span);
12151228

12161229
let stmt = self.inner.while_loop(cond_expr, body_block, span);
12171230
self.store_stmt(stmt)
@@ -1223,14 +1236,16 @@ impl AstHostFunctions for TypedAstBuilder {
12231236
let iter_expr = self.get_expr(iterable)
12241237
.unwrap_or_else(|| self.inner.variable("iter", Type::Primitive(PrimitiveType::I32), span));
12251238

1226-
let body_stmts = if let Some(stmt) = self.get_stmt(body) {
1227-
vec![stmt]
1239+
// Get body block - check for block first, then statement, then expression
1240+
let body_block = if let Some(block) = self.get_block(body) {
1241+
block
1242+
} else if let Some(stmt) = self.get_stmt(body) {
1243+
TypedBlock { statements: vec![stmt], span }
12281244
} else if let Some(expr) = self.get_expr(body) {
1229-
vec![self.inner.expression_statement(expr, span)]
1245+
TypedBlock { statements: vec![self.inner.expression_statement(expr, span)], span }
12301246
} else {
1231-
vec![]
1247+
TypedBlock { statements: vec![], span }
12321248
};
1233-
let body_block = self.inner.block(body_stmts, span);
12341249

12351250
let stmt = self.inner.for_loop(iterator, iter_expr, body_block, span);
12361251
self.store_stmt(stmt)
@@ -1746,6 +1761,7 @@ impl<'a, H: AstHostFunctions> CommandInterpreter<'a, H> {
17461761
"bool_literal" => {
17471762
let value = match args.get("value") {
17481763
Some(RuntimeValue::Bool(b)) => *b,
1764+
Some(RuntimeValue::String(s)) => s == "true",
17491765
_ => false,
17501766
};
17511767
let handle = self.host.create_bool_literal(value);
@@ -1904,8 +1920,13 @@ impl<'a, H: AstHostFunctions> CommandInterpreter<'a, H> {
19041920
}
19051921

19061922
"call_expr" | "call" => {
1923+
// Callee can be either a Node (expression) or String (identifier)
19071924
let callee = match args.get("callee") {
19081925
Some(RuntimeValue::Node(h)) => *h,
1926+
Some(RuntimeValue::String(name)) => {
1927+
// Create a variable reference for the callee
1928+
self.host.create_variable(name)
1929+
}
19091930
_ => return Err(crate::error::ZynPegError::CodeGenError("call: missing callee".into())),
19101931
};
19111932
let call_args: Vec<NodeHandle> = match args.get("args") {
@@ -1917,6 +1938,8 @@ impl<'a, H: AstHostFunctions> CommandInterpreter<'a, H> {
19171938
})
19181939
.collect()
19191940
}
1941+
Some(RuntimeValue::Null) => vec![],
1942+
None => vec![],
19201943
_ => vec![],
19211944
};
19221945
let handle = self.host.create_call(callee, call_args);
@@ -2066,8 +2089,13 @@ impl<'a, H: AstHostFunctions> CommandInterpreter<'a, H> {
20662089
}
20672090

20682091
"assignment" | "assign" => {
2092+
// Target can be either a Node (expression) or String (identifier)
20692093
let target = match args.get("target") {
20702094
Some(RuntimeValue::Node(h)) => *h,
2095+
Some(RuntimeValue::String(name)) => {
2096+
// Create a variable reference for the target
2097+
self.host.create_variable(name)
2098+
}
20712099
_ => return Err(crate::error::ZynPegError::CodeGenError("assignment: missing target".into())),
20722100
};
20732101
let value = match args.get("value") {
@@ -2083,11 +2111,11 @@ impl<'a, H: AstHostFunctions> CommandInterpreter<'a, H> {
20832111
Some(RuntimeValue::Node(h)) => *h,
20842112
_ => return Err(crate::error::ZynPegError::CodeGenError("if: missing condition".into())),
20852113
};
2086-
let then_block = match args.get("then").or(args.get("then_block")) {
2114+
let then_block = match args.get("then").or(args.get("then_block")).or(args.get("then_branch")) {
20872115
Some(RuntimeValue::Node(h)) => *h,
20882116
_ => return Err(crate::error::ZynPegError::CodeGenError("if: missing then block".into())),
20892117
};
2090-
let else_block = match args.get("else").or(args.get("else_block")) {
2118+
let else_block = match args.get("else").or(args.get("else_block")).or(args.get("else_branch")) {
20912119
Some(RuntimeValue::Node(h)) => Some(*h),
20922120
_ => None,
20932121
};

0 commit comments

Comments
 (0)