Skip to content

Commit 6c44950

Browse files
committed
feat: Add struct instantiation syntax to zig.zyn grammar
- Add struct_init rule for `Point{ .x = 10, .y = 20 }` syntax - Add struct_init_fields and struct_init_field rules - Add store_struct_field_init and get_struct_field_init to AstHostFunctions - Add struct_field_inits storage to TypedAstBuilder - Implement struct_init and struct_field_init handlers in define_node The parsing and TypedAST generation work correctly. Full type inference for struct variables requires lowering layer changes.
1 parent 5f9979d commit 6c44950

2 files changed

Lines changed: 81 additions & 1 deletion

File tree

crates/zyn_peg/grammars/zig.zyn

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -481,11 +481,31 @@ call_args = { expr ~ ("," ~ expr)* }
481481
}
482482

483483
// Atom: the base of postfix expressions
484-
atom = { try_expr | array_literal | bool_literal | string_literal | integer_literal | identifier_expr | paren_expr }
484+
atom = { try_expr | struct_init | array_literal | bool_literal | string_literal | integer_literal | identifier_expr | paren_expr }
485485
-> TypedExpression {
486486
"get_child": { "index": 0 }
487487
}
488488

489+
// Struct instantiation: Point{ .x = 10, .y = 20 }
490+
struct_init = { identifier ~ "{" ~ struct_init_fields? ~ "}" }
491+
-> TypedExpression {
492+
"commands": [
493+
{ "define": "struct_init", "args": { "type_name": "$1", "fields": "$2" } }
494+
]
495+
}
496+
497+
struct_init_fields = { struct_init_field ~ ("," ~ struct_init_field)* ~ ","? }
498+
-> List {
499+
"get_all_children": true
500+
}
501+
502+
struct_init_field = { "." ~ identifier ~ "=" ~ expr }
503+
-> TypedExpression {
504+
"commands": [
505+
{ "define": "struct_field_init", "args": { "name": "$1", "value": "$2" } }
506+
]
507+
}
508+
489509
// Try expression: try expr
490510
try_expr = { "try" ~ primary }
491511
-> TypedExpression {

crates/zyn_peg/src/runtime.rs

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,12 @@ pub trait AstHostFunctions {
279279
/// Create a struct literal expression
280280
fn create_struct_literal(&mut self, name: &str, fields: Vec<(String, NodeHandle)>) -> NodeHandle;
281281

282+
/// Store a struct field initialization (for later lookup by struct_init)
283+
fn store_struct_field_init(&mut self, name: &str, value: NodeHandle) -> NodeHandle;
284+
285+
/// Get a stored struct field initialization
286+
fn get_struct_field_init(&self, handle: NodeHandle) -> Option<(String, NodeHandle)>;
287+
282288
/// Create a cast expression
283289
fn create_cast(&mut self, expr: NodeHandle, target_type: NodeHandle) -> NodeHandle;
284290

@@ -840,6 +846,8 @@ pub struct TypedAstBuilder {
840846
fields: HashMap<NodeHandle, TypedField>,
841847
/// Stored variant nodes by handle
842848
variants: HashMap<NodeHandle, TypedVariant>,
849+
/// Stored struct field initializers (name, value) by handle
850+
struct_field_inits: HashMap<NodeHandle, (String, NodeHandle)>,
843851
/// Program declaration handles (in order)
844852
program_decls: Vec<NodeHandle>,
845853
}
@@ -861,6 +869,7 @@ impl TypedAstBuilder {
861869
declarations: HashMap::new(),
862870
fields: HashMap::new(),
863871
variants: HashMap::new(),
872+
struct_field_inits: HashMap::new(),
864873
program_decls: Vec::new(),
865874
}
866875
}
@@ -1536,6 +1545,16 @@ impl AstHostFunctions for TypedAstBuilder {
15361545
self.store_expr(expr)
15371546
}
15381547

1548+
fn store_struct_field_init(&mut self, name: &str, value: NodeHandle) -> NodeHandle {
1549+
let handle = self.alloc_handle();
1550+
self.struct_field_inits.insert(handle, (name.to_string(), value));
1551+
handle
1552+
}
1553+
1554+
fn get_struct_field_init(&self, handle: NodeHandle) -> Option<(String, NodeHandle)> {
1555+
self.struct_field_inits.get(&handle).cloned()
1556+
}
1557+
15391558
fn create_cast(&mut self, expr_handle: NodeHandle, _target_type: NodeHandle) -> NodeHandle {
15401559
let span = self.default_span();
15411560

@@ -2225,6 +2244,47 @@ impl<'a, H: AstHostFunctions> CommandInterpreter<'a, H> {
22252244
Ok(RuntimeValue::Node(handle))
22262245
}
22272246

2247+
// Struct instantiation: Point{ .x = 10, .y = 20 }
2248+
"struct_init" => {
2249+
let type_name = match args.get("type_name") {
2250+
Some(RuntimeValue::String(s)) => s.clone(),
2251+
_ => "AnonymousStruct".to_string(),
2252+
};
2253+
// Fields come as a list of struct_field_init results
2254+
// Each struct_field_init stores (name, value) in host's struct_init_fields map
2255+
let fields: Vec<(String, NodeHandle)> = match args.get("fields") {
2256+
Some(RuntimeValue::List(list)) => {
2257+
list.iter()
2258+
.filter_map(|v| match v {
2259+
RuntimeValue::Node(h) => {
2260+
// Look up the field init data from host
2261+
self.host.get_struct_field_init(*h)
2262+
}
2263+
_ => None,
2264+
})
2265+
.collect()
2266+
}
2267+
_ => vec![],
2268+
};
2269+
let handle = self.host.create_struct_literal(&type_name, fields);
2270+
Ok(RuntimeValue::Node(handle))
2271+
}
2272+
2273+
// Struct field initialization: .x = 10
2274+
"struct_field_init" => {
2275+
let name = match args.get("name") {
2276+
Some(RuntimeValue::String(s)) => s.clone(),
2277+
_ => "field".to_string(),
2278+
};
2279+
let value = match args.get("value") {
2280+
Some(RuntimeValue::Node(h)) => *h,
2281+
_ => return Err(crate::error::ZynPegError::CodeGenError("struct_field_init: missing value".into())),
2282+
};
2283+
// Store field init and return a handle for later lookup
2284+
let handle = self.host.store_struct_field_init(&name, value);
2285+
Ok(RuntimeValue::Node(handle))
2286+
}
2287+
22282288
"cast" => {
22292289
let expr = match args.get("expr") {
22302290
Some(RuntimeValue::Node(h)) => *h,

0 commit comments

Comments
 (0)