Skip to content

Commit e0f743f

Browse files
committed
feat: Add additional switch pattern types for Zig grammar
- Add struct pattern: Point{ .x, .y } or Point{ .x = px } - Add tagged union pattern: .some, .none, .value - Add error pattern: error.OutOfMemory, error.X - Add pointer pattern: *x for dereference patterns - Add slice pattern: prefix/middle/suffix patterns - Add corresponding host functions and define handlers in runtime - Update switch_primary_pattern to include all new pattern types Patterns are fully parsed and generate proper AST nodes. Code generation support varies by backend.
1 parent 0de04b9 commit e0f743f

2 files changed

Lines changed: 217 additions & 1 deletion

File tree

crates/zyn_peg/grammars/zig.zyn

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,7 @@ switch_or_pattern = { switch_primary_pattern ~ ("|" ~ switch_primary_pattern)* }
561561
}
562562

563563
// Primary patterns (non-or)
564-
switch_primary_pattern = { switch_range_pattern | switch_array_pattern | switch_literal_pattern | switch_wildcard_pattern | switch_identifier_pattern }
564+
switch_primary_pattern = { switch_struct_pattern | switch_tagged_union_pattern | switch_error_pattern | switch_pointer_pattern | switch_range_pattern | switch_array_pattern | switch_literal_pattern | switch_wildcard_pattern | switch_identifier_pattern }
565565
-> TypedExpression {
566566
"get_child": { "index": 0 }
567567
}
@@ -620,6 +620,67 @@ switch_identifier_pattern = { identifier }
620620
]
621621
}
622622

623+
// Struct pattern: Point{ .x, .y } or Point{ .x = px, .y = py }
624+
switch_struct_pattern = { identifier ~ "{" ~ switch_struct_field_patterns? ~ "}" }
625+
-> TypedExpression {
626+
"commands": [
627+
{ "define": "struct_pattern", "args": {
628+
"name": { "text": "$1" },
629+
"fields": "$2"
630+
}}
631+
]
632+
}
633+
634+
switch_struct_field_patterns = { switch_struct_field_pattern ~ ("," ~ switch_struct_field_pattern)* ~ ","? }
635+
-> List {
636+
"get_all_children": true
637+
}
638+
639+
// Struct field pattern: .x or .x = pattern
640+
switch_struct_field_pattern = { "." ~ identifier ~ ("=" ~ switch_pattern)? }
641+
-> TypedExpression {
642+
"commands": [
643+
{ "define": "field_pattern", "args": {
644+
"name": { "text": "$1" },
645+
"pattern": "$2"
646+
}}
647+
]
648+
}
649+
650+
// Tagged union pattern: .some, .none, .value
651+
// In Zig, tagged unions are matched with .variant or .variant => |capture|
652+
switch_tagged_union_pattern = { "." ~ identifier }
653+
-> TypedExpression {
654+
"commands": [
655+
{ "define": "enum_pattern", "args": {
656+
"name": "",
657+
"variant": { "text": "$1" },
658+
"fields": []
659+
}}
660+
]
661+
}
662+
663+
// Error pattern: error.OutOfMemory
664+
switch_error_pattern = { "error" ~ "." ~ identifier }
665+
-> TypedExpression {
666+
"commands": [
667+
{ "define": "error_pattern", "args": {
668+
"name": { "text": "$1" }
669+
}}
670+
]
671+
}
672+
673+
// Pointer pattern: *x (dereference pattern)
674+
switch_pointer_pattern = { "*" ~ switch_primary_pattern }
675+
-> TypedExpression {
676+
"commands": [
677+
{ "define": "pointer_pattern", "args": {
678+
"inner": "$1",
679+
"mutable": false
680+
}}
681+
]
682+
}
683+
623684
// Type as a value (for comptime type parameters)
624685
type_value = { type_expr_as_value }
625686
-> TypedExpression {

crates/zyn_peg/src/runtime.rs

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,15 @@ pub trait AstHostFunctions {
384384
/// Create an or pattern: x | y | z
385385
fn create_or_pattern(&mut self, patterns: Vec<NodeHandle>) -> NodeHandle;
386386

387+
/// Create a pointer/reference pattern: *x, &x
388+
fn create_pointer_pattern(&mut self, inner: NodeHandle, mutable: bool) -> NodeHandle;
389+
390+
/// Create a slice pattern: arr[0..5]
391+
fn create_slice_pattern(&mut self, prefix: Vec<NodeHandle>, middle: Option<NodeHandle>, suffix: Vec<NodeHandle>) -> NodeHandle;
392+
393+
/// Create an error pattern: error.X (Zig-style)
394+
fn create_error_pattern(&mut self, error_name: &str) -> NodeHandle;
395+
387396
// ========== Types ==========
388397

389398
/// Create a primitive type (i32, i64, f32, f64, bool, etc.)
@@ -2089,6 +2098,99 @@ impl AstHostFunctions for TypedAstBuilder {
20892098

20902099
self.store_pattern(pattern)
20912100
}
2101+
2102+
fn create_pointer_pattern(&mut self, inner: NodeHandle, mutable: bool) -> NodeHandle {
2103+
let span = self.default_span();
2104+
2105+
// Get the inner pattern
2106+
let inner_pattern = self.get_pattern(inner)
2107+
.unwrap_or_else(|| {
2108+
TypedNode {
2109+
node: TypedPattern::Wildcard,
2110+
ty: Type::Primitive(PrimitiveType::I32),
2111+
span,
2112+
}
2113+
});
2114+
2115+
let mutability = if mutable { Mutability::Mutable } else { Mutability::Immutable };
2116+
let inner_ty = inner_pattern.ty.clone();
2117+
2118+
// Create a Reference pattern (Zig uses * for pointers, Rust uses &)
2119+
let pattern = TypedNode {
2120+
node: TypedPattern::Reference {
2121+
pattern: Box::new(inner_pattern),
2122+
mutability,
2123+
},
2124+
ty: Type::Reference {
2125+
ty: Box::new(inner_ty),
2126+
mutability,
2127+
lifetime: None,
2128+
nullability: zyntax_typed_ast::type_registry::NullabilityKind::NonNull,
2129+
},
2130+
span,
2131+
};
2132+
2133+
self.store_pattern(pattern)
2134+
}
2135+
2136+
fn create_slice_pattern(&mut self, prefix: Vec<NodeHandle>, middle: Option<NodeHandle>, suffix: Vec<NodeHandle>) -> NodeHandle {
2137+
let span = self.default_span();
2138+
2139+
// Collect prefix patterns
2140+
let prefix_patterns: Vec<TypedNode<TypedPattern>> = prefix.iter()
2141+
.filter_map(|h| self.get_pattern(*h))
2142+
.collect();
2143+
2144+
// Get middle (rest) pattern if provided
2145+
let middle_pattern = middle.and_then(|h| self.get_pattern(h));
2146+
2147+
// Collect suffix patterns
2148+
let suffix_patterns: Vec<TypedNode<TypedPattern>> = suffix.iter()
2149+
.filter_map(|h| self.get_pattern(*h))
2150+
.collect();
2151+
2152+
// Determine element type from first available pattern
2153+
let elem_ty = prefix_patterns.first()
2154+
.or(middle_pattern.as_ref())
2155+
.or(suffix_patterns.first())
2156+
.map(|p| p.ty.clone())
2157+
.unwrap_or(Type::Primitive(PrimitiveType::I32));
2158+
2159+
let pattern = TypedNode {
2160+
node: TypedPattern::Slice {
2161+
prefix: prefix_patterns,
2162+
middle: middle_pattern.map(Box::new),
2163+
suffix: suffix_patterns,
2164+
},
2165+
// Use Array type for slices (similar to how Zig handles slices)
2166+
ty: Type::Array {
2167+
element_type: Box::new(elem_ty),
2168+
size: None, // dynamic size for slices
2169+
nullability: zyntax_typed_ast::type_registry::NullabilityKind::NonNull,
2170+
},
2171+
span,
2172+
};
2173+
2174+
self.store_pattern(pattern)
2175+
}
2176+
2177+
fn create_error_pattern(&mut self, error_name: &str) -> NodeHandle {
2178+
let span = self.default_span();
2179+
let name = InternedString::new_global(error_name);
2180+
2181+
// Error patterns in Zig are like enum variant patterns
2182+
// error.OutOfMemory is essentially an enum variant
2183+
let pattern = TypedNode {
2184+
node: TypedPattern::Path {
2185+
path: vec![InternedString::new_global("error"), name],
2186+
args: None,
2187+
},
2188+
ty: Type::Error,
2189+
span,
2190+
};
2191+
2192+
self.store_pattern(pattern)
2193+
}
20922194
}
20932195

20942196
// ============================================================================
@@ -3340,6 +3442,59 @@ impl<'a, H: AstHostFunctions> CommandInterpreter<'a, H> {
33403442
Ok(RuntimeValue::Node(handle))
33413443
}
33423444

3445+
"pointer_pattern" | "reference_pattern" => {
3446+
let inner = match args.get("inner").or(args.get("pattern")) {
3447+
Some(RuntimeValue::Node(h)) => *h,
3448+
_ => self.host.create_wildcard_pattern(),
3449+
};
3450+
let mutable = match args.get("mutable") {
3451+
Some(RuntimeValue::Bool(b)) => *b,
3452+
_ => false,
3453+
};
3454+
let handle = self.host.create_pointer_pattern(inner, mutable);
3455+
Ok(RuntimeValue::Node(handle))
3456+
}
3457+
3458+
"slice_pattern" => {
3459+
let prefix: Vec<NodeHandle> = match args.get("prefix") {
3460+
Some(RuntimeValue::List(list)) => {
3461+
list.iter()
3462+
.filter_map(|v| match v {
3463+
RuntimeValue::Node(h) => Some(*h),
3464+
_ => None,
3465+
})
3466+
.collect()
3467+
}
3468+
_ => vec![],
3469+
};
3470+
let middle = match args.get("middle").or(args.get("rest")) {
3471+
Some(RuntimeValue::Node(h)) => Some(*h),
3472+
_ => None,
3473+
};
3474+
let suffix: Vec<NodeHandle> = match args.get("suffix") {
3475+
Some(RuntimeValue::List(list)) => {
3476+
list.iter()
3477+
.filter_map(|v| match v {
3478+
RuntimeValue::Node(h) => Some(*h),
3479+
_ => None,
3480+
})
3481+
.collect()
3482+
}
3483+
_ => vec![],
3484+
};
3485+
let handle = self.host.create_slice_pattern(prefix, middle, suffix);
3486+
Ok(RuntimeValue::Node(handle))
3487+
}
3488+
3489+
"error_pattern" => {
3490+
let name = match args.get("name").or(args.get("error_name")) {
3491+
Some(RuntimeValue::String(s)) => s.clone(),
3492+
_ => "Error".to_string(),
3493+
};
3494+
let handle = self.host.create_error_pattern(&name);
3495+
Ok(RuntimeValue::Node(handle))
3496+
}
3497+
33433498
_ => {
33443499
Err(crate::error::ZynPegError::CodeGenError(format!("Unknown node type: {}", node_type)))
33453500
}

0 commit comments

Comments
 (0)