Skip to content

Commit 0658528

Browse files
committed
feat: extend GrammarInterpreter with additional TypedAST constructs
Add support for more statement and expression types in the runtime interpreter to enable migration of complex grammars like ml.zyn: Statements: - If (with optional else) - While - For (iterator-based) - Break (with optional value) - Continue Expressions: - Unary operations (-, !, +, ~) - Array literals - Index expressions - Field/member access - Range expressions - Struct literals - Bool literals - Ternary/if expressions Also added helper methods: - get_field_as_block for required block fields - get_field_as_field_init_list for struct field initialization - string_to_unary_op for operator conversion - ParsedValue::FieldInit variant for struct field init values This prepares the runtime for Phase 5 migration of ml.zyn from legacy JSON actions to the new named bindings syntax.
1 parent 2668084 commit 0658528

2 files changed

Lines changed: 193 additions & 0 deletions

File tree

crates/zyn_peg/src/runtime2/interpreter.rs

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ use std::collections::HashMap;
1515
use zyntax_typed_ast::{
1616
TypedNode, TypedStatement, TypedExpression, TypedLiteral, TypedBlock,
1717
TypedDeclaration, TypedFunction, TypedLet, TypedCall, TypedProgram,
18+
TypedIf, TypedWhile, TypedFor, TypedUnary, TypedFieldAccess, TypedIndex,
19+
TypedRange, TypedStructLiteral, TypedFieldInit, TypedPattern,
20+
UnaryOp,
1821
typed_node, Span,
1922
type_registry::{Type, PrimitiveType, Mutability, Visibility, CallingConvention},
2023
};
@@ -296,6 +299,53 @@ impl<'g> GrammarInterpreter<'g> {
296299
let value = self.get_field_optional_expr("value", fields, state)?;
297300
TypedStatement::Return(value.map(Box::new))
298301
}
302+
"If" => {
303+
let condition = self.get_field_as_expr("condition", fields, state)?;
304+
let then_block = self.get_field_as_block("then_branch", fields, state)?;
305+
let else_block = self.get_field_optional_block("else_branch", fields, state)?;
306+
307+
TypedStatement::If(TypedIf {
308+
condition: Box::new(condition),
309+
then_block,
310+
else_block,
311+
span,
312+
})
313+
}
314+
"While" => {
315+
let condition = self.get_field_as_expr("condition", fields, state)?;
316+
let body = self.get_field_as_block("body", fields, state)?;
317+
318+
TypedStatement::While(TypedWhile {
319+
condition: Box::new(condition),
320+
body,
321+
span,
322+
})
323+
}
324+
"For" => {
325+
let variable = self.get_field_as_interned("variable", fields, state)?;
326+
let iterable = self.get_field_as_expr("iterable", fields, state)?;
327+
let body = self.get_field_as_block("body", fields, state)?;
328+
329+
// Create a binding pattern for the variable
330+
let pattern = typed_node(
331+
TypedPattern::Identifier { name: variable, mutability: Mutability::Immutable },
332+
Type::Any,
333+
span,
334+
);
335+
336+
TypedStatement::For(TypedFor {
337+
pattern: Box::new(pattern),
338+
iterator: Box::new(iterable),
339+
body,
340+
})
341+
}
342+
"Break" => {
343+
let value = self.get_field_optional_expr("value", fields, state)?;
344+
TypedStatement::Break(value.map(Box::new))
345+
}
346+
"Continue" => {
347+
TypedStatement::Continue
348+
}
299349
_ => return Err(format!("unknown TypedStatement variant: {}", variant)),
300350
};
301351

@@ -357,6 +407,74 @@ impl<'g> GrammarInterpreter<'g> {
357407
right: Box::new(right),
358408
})
359409
}
410+
"Unary" => {
411+
let operand = self.get_field_as_expr("operand", fields, state)?;
412+
let op = self.get_field_as_string("op", fields, state)?;
413+
414+
let unary_op = self.string_to_unary_op(&op)?;
415+
TypedExpression::Unary(TypedUnary {
416+
op: unary_op,
417+
operand: Box::new(operand),
418+
})
419+
}
420+
"Array" => {
421+
let elements = self.get_field_as_expr_list("elements", fields, state)?;
422+
TypedExpression::Array(elements)
423+
}
424+
"Index" => {
425+
let object = self.get_field_as_expr("object", fields, state)?;
426+
let index = self.get_field_as_expr("index", fields, state)?;
427+
428+
TypedExpression::Index(TypedIndex {
429+
object: Box::new(object),
430+
index: Box::new(index),
431+
})
432+
}
433+
"Field" | "FieldAccess" => {
434+
let object = self.get_field_as_expr("object", fields, state)?;
435+
let field = self.get_field_as_interned("field", fields, state)?;
436+
437+
TypedExpression::Field(TypedFieldAccess {
438+
object: Box::new(object),
439+
field,
440+
})
441+
}
442+
"Range" => {
443+
let start = self.get_field_optional_expr("start", fields, state)?;
444+
let end = self.get_field_optional_expr("end", fields, state)?;
445+
let inclusive = self.get_field_as_bool("inclusive", fields, state).unwrap_or(false);
446+
447+
TypedExpression::Range(TypedRange {
448+
start: start.map(Box::new),
449+
end: end.map(Box::new),
450+
inclusive,
451+
})
452+
}
453+
"Struct" | "StructLiteral" => {
454+
let type_name = self.get_field_as_interned("type_name", fields, state)?;
455+
let field_inits = self.get_field_as_field_init_list("fields", fields, state)?;
456+
457+
TypedExpression::Struct(TypedStructLiteral {
458+
name: type_name,
459+
fields: field_inits,
460+
})
461+
}
462+
"BoolLiteral" => {
463+
let value = self.get_field_as_bool("value", fields, state)?;
464+
TypedExpression::Literal(TypedLiteral::Bool(value))
465+
}
466+
"Ternary" | "If" => {
467+
// Ternary expression: condition ? then_expr : else_expr
468+
let condition = self.get_field_as_expr("condition", fields, state)?;
469+
let then_expr = self.get_field_as_expr("then_expr", fields, state)?;
470+
let else_expr = self.get_field_as_expr("else_expr", fields, state)?;
471+
472+
TypedExpression::If(zyntax_typed_ast::TypedIfExpr {
473+
condition: Box::new(condition),
474+
then_branch: Box::new(then_expr),
475+
else_branch: Box::new(else_expr),
476+
})
477+
}
360478
_ => return Err(format!("unknown TypedExpression variant: {}", variant)),
361479
};
362480

@@ -900,6 +1018,65 @@ impl<'g> GrammarInterpreter<'g> {
9001018
}
9011019
}
9021020

1021+
fn get_field_as_block<'a>(
1022+
&self,
1023+
name: &str,
1024+
fields: &[(String, ExprIR)],
1025+
state: &mut ParserState<'a>,
1026+
) -> Result<TypedBlock, String> {
1027+
let expr = self.get_field(name, fields)
1028+
.ok_or_else(|| format!("missing field: {}", name))?;
1029+
let val = self.eval_expr(expr, state)?;
1030+
self.parsed_value_to_block(val, state)
1031+
}
1032+
1033+
fn get_field_as_field_init_list<'a>(
1034+
&self,
1035+
name: &str,
1036+
fields: &[(String, ExprIR)],
1037+
state: &mut ParserState<'a>,
1038+
) -> Result<Vec<TypedFieldInit>, String> {
1039+
match self.get_field(name, fields) {
1040+
Some(expr) => {
1041+
let val = self.eval_expr(expr, state)?;
1042+
match val {
1043+
ParsedValue::List(items) => {
1044+
let mut result = Vec::new();
1045+
for item in items {
1046+
let field_init = self.parsed_value_to_field_init(item, state)?;
1047+
result.push(field_init);
1048+
}
1049+
Ok(result)
1050+
}
1051+
ParsedValue::None => Ok(vec![]),
1052+
other => {
1053+
// Single item - try to convert
1054+
let field_init = self.parsed_value_to_field_init(other, state)?;
1055+
Ok(vec![field_init])
1056+
}
1057+
}
1058+
}
1059+
None => Ok(vec![]),
1060+
}
1061+
}
1062+
1063+
fn parsed_value_to_field_init<'a>(
1064+
&self,
1065+
val: ParsedValue,
1066+
state: &mut ParserState<'a>,
1067+
) -> Result<TypedFieldInit, String> {
1068+
match val {
1069+
ParsedValue::FieldInit { name, value } => {
1070+
let expr = self.parsed_value_to_expr(*value, state)?;
1071+
Ok(TypedFieldInit {
1072+
name,
1073+
value: Box::new(expr),
1074+
})
1075+
}
1076+
_ => Err("cannot convert value to field init".to_string()),
1077+
}
1078+
}
1079+
9031080
fn get_field_as_decl_list<'a>(
9041081
&self,
9051082
name: &str,
@@ -1036,6 +1213,17 @@ impl<'g> GrammarInterpreter<'g> {
10361213
}
10371214
}
10381215

1216+
/// Convert string to UnaryOp
1217+
fn string_to_unary_op(&self, op: &str) -> Result<UnaryOp, String> {
1218+
match op {
1219+
"-" | "Minus" | "Neg" => Ok(UnaryOp::Minus),
1220+
"!" | "Not" => Ok(UnaryOp::Not),
1221+
"+" | "Plus" => Ok(UnaryOp::Plus),
1222+
"~" | "BitNot" => Ok(UnaryOp::BitNot),
1223+
_ => Err(format!("unknown unary operator: {}", op)),
1224+
}
1225+
}
1226+
10391227
/// Execute a pattern
10401228
fn execute_pattern<'a>(
10411229
&self,

crates/zyn_peg/src/runtime2/state.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,11 @@ pub enum ParsedValue {
135135
Program(Box<zyntax_typed_ast::TypedProgram>),
136136
/// A TypedBlock AST node
137137
Block(zyntax_typed_ast::TypedBlock),
138+
/// A field initialization (name -> value)
139+
FieldInit {
140+
name: InternedString,
141+
value: Box<ParsedValue>,
142+
},
138143
}
139144

140145
/// Handle to an AST node (opaque, managed by builder)

0 commit comments

Comments
 (0)