Skip to content

Commit 536db8f

Browse files
committed
docs: Use actual zig.zyn pattern for custom types example
Show the real "define": "primitive_type" pattern from zig.zyn. Be honest that grammar only parses type names - type semantics must be handled in the compiler/runtime, not in grammar actions.
1 parent 724aeca commit 536db8f

1 file changed

Lines changed: 17 additions & 38 deletions

File tree

book/15-building-dsls.md

Lines changed: 17 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -544,57 +544,36 @@ The key insight: `zrtl_plugin!` **defines** what symbols a plugin exports. The r
544544

545545
## Advanced Patterns
546546

547-
### Domain-Specific Type Systems
547+
### Domain-Specific Types
548548

549-
Your DSL can parse custom type names and map them to TypedAST primitive types. The grammar handles parsing while semantic actions build the AST:
549+
Your DSL can define custom type names. Like the Zig grammar, use `"define": "primitive_type"` to create type nodes:
550550

551551
```zyn
552-
// Parse type annotations - dispatch to the matched child
553-
type_annotation = { ":" ~ type_expr }
554-
-> Type {
555-
"get_child": { "index": 0 }
556-
}
557-
558-
// Type expression - each alternative produces a type
559-
type_expr = { primitive_type | custom_type }
560-
-> Type {
561-
"get_child": { "index": 0 }
562-
}
563-
564-
// Standard primitive types
552+
// Standard primitive types (same pattern as zig.zyn)
565553
primitive_type = { "i32" | "i64" | "f32" | "f64" | "bool" | "void" }
566554
-> Type {
567-
"get_text": true
555+
"get_text": true,
556+
"define": "primitive_type",
557+
"args": { "name": "$result" }
568558
}
569559
570-
// DSL-specific type names that compile to primitives
571-
// Currency/Percentage → f64, Date/Duration → i64
572-
custom_type = { "Currency" | "Percentage" | "Date" | "Duration" }
560+
// DSL-specific type aliases - parsed the same way
561+
// The compiler treats these as their underlying types
562+
dsl_type = { "Currency" | "Percentage" | "Date" | "Duration" }
573563
-> Type {
574-
"get_text": true
564+
"get_text": true,
565+
"define": "primitive_type",
566+
"args": { "name": "$result" }
575567
}
576568
577-
// Variable declaration using type annotation
578-
var_decl = { "let" ~ identifier ~ type_annotation ~ "=" ~ expr }
579-
-> TypedStatement {
580-
"commands": [
581-
{ "define": "var_decl", "args": {
582-
"name": "$1",
583-
"type": "$2",
584-
"value": "$3"
585-
}}
586-
]
569+
// Combined type expression
570+
type_expr = { primitive_type | dsl_type | identifier }
571+
-> Type {
572+
"get_child": { "index": 0 }
587573
}
588574
```
589575

590-
The type mapping (Currency → f64, Date → i64) happens during compilation. Your DSL plugin can validate and transform types as needed. This allows DSL code like:
591-
592-
```text
593-
let price: Currency = 99.99
594-
let discount: Percentage = 15
595-
let created: Date = now()
596-
let timeout: Duration = 5000
597-
```
576+
Note: The grammar only parses type names as strings. Type semantics (e.g., treating `Currency` as `f64`) must be handled in your compiler or runtime, not in the grammar.
598577

599578
### Compile-Time Validation
600579

0 commit comments

Comments
 (0)