§6. Core grammar sketch (EBNF)
Generated from
docs/LANGUAGE.md§6. This is the normative specification; for a guided tour see the Language and Neurosymbolic sections.
Illustrative excerpt of the reference PEG, restricted to the constructs above (full grammar is
a toolchain artifact; the tree-sitter grammar and the constrained-decoding GBNF are
co-maintained with a CI drift check against it — single-sourcing is not a commitment,
TOOLCHAIN.md D8 — 12 §8). Soft keywords marked ?.
file = { statement } ;statement = import_stmt | ported_import | native_import | def | ported_def | agent_decl | circuit_decl | operator_decl | bridge_decl | template_decl | context_decl | args_decl | config_decl | container_decl | component_decl | provide_decl | collector_decl | worker_decl | struct | enum_decl | trait_decl | impl_decl | model_decl | policy_decl | policy_attach | service_decl | monitor_decl | protocol_decl | supervise | event_decl | subscriber_decl | sem_decl | assure_decl | test_decl | equation_decl | equation_stmt | theorem_decl | solve_stmt | if_stmt | while_stmt | loop_until_stmt | for_stmt | match_stmt | with_stmt | expect_stmt | scope_block | simple_stmt ;
import_stmt = [ "pub"? ] ( "import" qualified_name [ "as" IDENT ] | "from" qualified_name "import" IDENT [ "as" IDENT ] { "," IDENT [ "as" IDENT ] } ) NEWLINE ;
struct = [ "pub"? ] "struct" IDENT [ type_params ] [ "(" trait_list ")" ] ":" NEWLINE INDENT { field_decl | contract_clause | sem_decl | def | const_bind } DEDENT ;enum_decl = [ "pub"? ] "enum" IDENT [ type_params ] [ "(" trait_list ")" ] ":" NEWLINE INDENT { variant_decl | sem_decl | def } DEDENT | "enum" IDENT ":" IDENT { "|" IDENT } ; (* inline sugar *)type_params = "[" type_param { "," type_param } "]" ; (* generics, erased §5.29 *)type_param = IDENT [ ":" IDENT { "+" IDENT } ] ; (* optional trait bounds §3.9 *)variant_decl = IDENT [ "(" params ")" ] NEWLINE ;trait_decl = [ "pub"? ] "trait" IDENT [ "(" trait_list ")" ] ":" NEWLINE INDENT { def_sig | def | law_clause | sem_decl | "sem"? STRING NEWLINE } DEDENT ; (* "(" trait_list ")" = supertraits; `def_sig` = required method, `def` (with a block) = default (provided) method, §3.9 *)law_clause = "law" IDENT ":" expr NEWLINE ;impl_decl = "impl" IDENT "for" type ":" NEWLINE INDENT { def } DEDENT ;trait_list = IDENT { "," IDENT } ;const_bind = IDENT "=" expr NEWLINE ;field_decl = IDENT ":" type [ "=" expr ] [ "sem" STRING ] [ "where" expr ] [ "coerce" "by" qualified_name ] [ "named" STRING ] NEWLINE ; (* Clause ORDER is fixed — each clause is accepted only in this position, so `x: int sem "d" = 3` is a parse error while `x: int = 3 sem "d" where value > 0 coerce by f named "q"` parses. *)
def = { decorator } [ "pub"? ] [ "simulate" ] [ "stream"? ] [ "mut"? ] "def" IDENT [ type_params ] "(" [ params ] ")" [ "->" type ] [ "!" effect_row ] [ "by" expr ] ":" block ;agent_decl = { decorator } [ "pub"? ] "agent" IDENT [ type_params ] "(" [ params ] ")" [ "->" type ] [ "!" effect_row ] [ "by" expr ] ":" block ;circuit_decl = { decorator } [ "pub"? ] "circuit" IDENT [ type_params ] "(" [ params ] ")" [ "->" type ] [ "!" effect_row ] ":" block ;params = param { "," param } ;param = [ "*" | "**" ] IDENT [ ":" type ] [ "=" expr ] ; (* *args / **kwargs §5.29 *)(* `pub` is REJECTED on `operator` and on `theorem`: neither binds an importable name, so a visibility marker would mean nothing (§5.18 Granularity). Every other declaration kind below accepts it. *)operator_decl = { decorator } [ "simulate" ] "operator" operator_head "(" [ params ] ")" [ "->" type ] [ "!" effect_row ] [ "by" expr ] ":" block ;operator_head = operator_token | "infix" STRING "precedence" precedence_class ;operator_token = "+" | "-" | "*" | "/" | "//" | "%" | "&" | "|" | "^" | "<<" | ">>" | "==" | "~=" ;precedence_class= "additive" | "multiplicative" | "comparison" | "logical" ; (* Parsed as a bare IDENT and DISCARDED: any word is accepted and none of them changes precedence yet. *)block = simple_line { ";" simple_line } NEWLINE (* inline suite *) | NEWLINE INDENT { contract_clause | statement } DEDENT ;contract_clause = ( "require" | "ensure" | "invariant" ) expr NEWLINE | "check" expr NEWLINE | "sem"? STRING NEWLINE | "budget" kwargs NEWLINE | "repair" kwargs NEWLINE (* simulate def bodies only, §5.22 *) | "use" ( "template" call_expr | "context" call_expr | "protocol" qualified_name | "tools" "[" [ expr { "," expr } ] "]" ) NEWLINE ;
if_stmt = "if" expr ":" block { "elif" expr ":" block } [ "else" ":" block ] ;while_stmt = "while" expr ":" block ;loop_until_stmt = "loop" "until" expr [ "max_iters" expr ] ":" block ;for_stmt = "for" pattern "in" expr ":" block ;simple_stmt = simple_line NEWLINE ;simple_line = assign_stmt | return_stmt | yield_stmt | emit_stmt | breakpoint_stmt | "pass" | "break" | "continue" | expr ;assign_stmt = "mut" IDENT [ ":" type ] "=" expr | assign_target [ ":" type ] "=" expr ;assign_target = IDENT | tuple_pattern | struct_pattern | enum_pattern | mutation_target ;mutation_target = atom { call_suffix | "." IDENT | subscript_suffix } ( "." IDENT | subscript_suffix ) ;return_stmt = "return" [ expr ] ;
effect_row = "{" [ effect { "," effect } ] "}" ; (* "*" is the all-effects wildcard (top); §3.6. An OMITTED row is inferred/fail-closed, not a wildcard, and is required explicitly at `assure silver`+. *)effect = "*" | ("model" | "fs" | "net" | "proc" | "code" | "memory" | "db" | "env" | "config" | "observe" | "event" | "policy" | "package" | "ui" | "human" | "agent") "." IDENT [ "(" [ args ] ")" ] | "clock" | "random" | "ffi.call" ;
match_stmt = "match" expr ":" NEWLINE INDENT { case_clause } DEDENT ;case_clause = "case" pattern [ "if" expr ] ":" block ;pattern = or_pattern ;or_pattern = base_pattern { "|" base_pattern } ;base_pattern = "_" | literal_pattern | regex_pattern | struct_pattern | enum_pattern | tuple_pattern | bind_pattern ;literal_pattern = literal ;struct_pattern = qualified_name "(" [ IDENT "=" pattern { "," IDENT "=" pattern } ] ")" ;enum_pattern = qualified_name [ "(" [ pattern { "," pattern } ] ")" ] ;tuple_pattern = "(" pattern { "," pattern } [ "," ] ")" ;bind_pattern = IDENT ;regex_pattern = "re" STRING ;template_expr = ( "f" | "rf" | "fr" | "sql" ) STRING ; (* rf/fr = raw template, D126 *)validate_expr = "validate" expr ":" block ;with_stmt = "with" ( "policy" "(" expr ")" | qualified_name "=" expr | expr [ "as" IDENT ] ) ":" block ;expect_stmt = "expect" ( semantics_pred | IDENT "=" expr | expr ) ":" block { "except" IDENT [ "as" IDENT ] ":" block } ;comprehension = "[" expr "for" pattern "in" expr [ "if" expr ] "]" | "{" expr ":" expr "for" pattern "in" expr [ "if" expr ] "}" | "{" expr "for" pattern "in" expr [ "if" expr ] "}" ;list_comp = "[" expr "for" pattern "in" expr [ "if" expr ] "]" ;
template_decl = [ "pub"? ] "template" IDENT "(" [ params ] ")" "->" prompt_type ":" template_block ;template_block = NEWLINE INDENT { template_item | contract_clause | statement } DEDENT ;template_item = "role" role_name ":" template_block | "text" text_expr NEWLINE | "use" "template" call_expr NEWLINE ;text_expr = STRING | "f" STRING ;role_name = "system" | "developer" | "user" | "assistant" | "tool" | "data" | IDENT ;prompt_type = "Prompt" "[" type "]" ;
context_decl = [ "pub"? ] "context" IDENT ":" NEWLINE INDENT { context_item } DEDENT ;context_item = "model" expr NEWLINE | "state" IDENT { "|" IDENT } NEWLINE | "slot" IDENT "role" role_name [ "retention" expr ] [ "budget" kwargs ] "=" expr NEWLINE | "transition" IDENT "->" IDENT "on" call_sig ":" context_block ;context_block = NEWLINE INDENT { context_action | contract_clause | statement } DEDENT ;context_action = ( "replace" | "append" | "drop" ) "slot" IDENT [ "role" role_name ] [ "=" expr ] NEWLINE ;
sem_decl = "sem"? qualified_name "=" STRING NEWLINE ;model_decl = [ "pub"? ] "model"? IDENT "=" "model" "(" args ")" NEWLINE ;
args_decl = [ "pub"? ] "args" IDENT ":" NEWLINE INDENT { arg_item } DEDENT ;arg_item = IDENT ":" type "=" ( "option" | "flag" ) "(" args ")" NEWLINE ;
config_decl = [ "pub"? ] "config" IDENT ":" NEWLINE INDENT { config_item } DEDENT ;config_item = "source" config_source NEWLINE | config_field | contract_clause ;config_field = IDENT ":" ( config_leaf | config_block ) ;config_leaf = type [ "=" expr ] [ "sem" STRING ] [ "where" expr ] NEWLINE ;config_block = NEWLINE INDENT { config_item } DEDENT ;config_source = ( ( "yaml" | "json" | "toml" ) expr [ "optional" ] | "env" "prefix" STRING | "cli" expr ) [ "as" IDENT ] ;
container_decl = [ "pub"? ] "container" IDENT ":" NEWLINE INDENT { container_item } DEDENT ;container_item = "args" IDENT NEWLINE | "config" IDENT NEWLINE | "bind" type [ "named" STRING ] [ "=" expr ] [ "lifetime" lifetime ] NEWLINE | "expose" IDENT NEWLINE ;component_decl = [ "pub"? ] "component" IDENT ":" NEWLINE INDENT { component_item } DEDENT ;component_item = "lifetime" lifetime NEWLINE | "inject" ":" NEWLINE INDENT { inject_field } DEDENT | sem_decl | def ;inject_field = IDENT ":" type [ "named" STRING ] [ "=" expr ] NEWLINE ;provide_decl = [ "pub"? ] "provide" IDENT "(" [ params ] ")" "->" type [ "lifetime" lifetime ] ":" block ;lifetime = "transient" | "singleton" | "scoped" "(" IDENT ")" ; (* Parsed and DISCARDED wherever it appears as a trailing clause: any word parses, none is enforced yet. *)inject_expr = "inject" type [ "named" STRING ] ;
collector_decl = [ "pub"? ] "collector" IDENT ":" NEWLINE INDENT { collector_item } DEDENT ;collector_item = IDENT ":" type [ "mode" collector_mode ] [ "retention" expr ] NEWLINE | "export" qualified_name kwargs NEWLINE | "strict" NEWLINE ;collector_mode = "series" | "histogram" | "stack" | "set" | "counts" | "bag" | "last" ; (* Parsed and DISCARDED: `collector_item` swallows the whole trailing `mode`/`retention` tail, so any word parses. *)tap_expr = expr "|>" collector_sink ;collector_sink = qualified_name [ "(" [ args ] ")" ] ;
worker_decl = [ "pub"? ] "worker" IDENT ":" NEWLINE INDENT { worker_item } DEDENT ;worker_item = "lane" IDENT NEWLINE | "workers" ( "auto" | expr ) NEWLINE | "batch" kwargs NEWLINE | queue_clause | "merge" parallel_merge NEWLINE | "on_error" parallel_error NEWLINE | "budget" kwargs NEWLINE ;parallel_expr = "parallel" [ "stream" ] postfix_expr parallel_op lambda_expr [ parallel_opts ] | "parallel" postfix_expr "reduce" postfix_expr "with" lambda_expr [ parallel_opts ] | "parallel" list_comp ;parallel_op = "map" | "filter" | "find" | "any" | "all" ;parallel_opts = [ "by" expr ] [ parallel_merge ] [ "limit" expr ] [ "chunk" expr ] [ "on_error" parallel_error ] ;parallel_merge = "ordered" | "unordered" | "stable" ;parallel_error = "fail_fast" | "collect" | "skip" ;
expr = lambda_expr ;lambda_expr = conditional_expr | IDENT "=>" lambda_expr | "(" [ params ] ")" "=>" lambda_expr | "lambda" [ IDENT { "," IDENT } ] ":" lambda_expr ;conditional_expr= tap_chain [ "if" tap_chain "else" conditional_expr ] ;tap_chain = iff_expr { "|>" postfix_expr } ;iff_expr = implication_expr { "⇔" implication_expr } ;implication_expr= or_expr [ "⇒" implication_expr ] ;or_expr = and_expr { ( "or" | "xor" | "∨" | "⊕" | "~" "or" | "~" "xor" ) and_expr } ;and_expr = not_expr { ( "and" | "∧" | "~" "and" ) not_expr } ;not_expr = [ "not" | "¬" | "~" "not" | "bitnot" ] not_expr | comparison_expr ;comparison_expr = set_expr { comparison_tail } ;comparison_tail = ( "==" | "!=" | "<" | "<=" | ">" | ">=" | "in" | "not" "in" | "∈" | "∉" | "⊆" | "⊂" | "⊇" | "~<" | "~>" | "~<=" | "~>=" | "~!=" | "~" "in" ) set_expr | "~=" set_expr [ "with" kwargs ] | "is" [ "not" ] qualified_name ;set_expr = bit_or_expr { ( "∪" | "∩" | "∖" | "△" ) bit_or_expr } ;bit_or_expr = bit_xor_expr { "|" bit_xor_expr } ;bit_xor_expr = bit_and_expr { "^" bit_and_expr } ;bit_and_expr = shift_expr { "&" shift_expr } ;shift_expr = additive_expr { ( "<<" | ">>" ) additive_expr } ;additive_expr = multiplicative_expr { ( "+" | "-" | "~+" | "~-" ) multiplicative_expr } ;multiplicative_expr = power_expr { ( "*" | "/" | "//" | "%" ) power_expr } ;power_expr = unary_expr [ "**" power_expr ] ;unary_expr = [ "+" | "-" ] unary_expr | postfix_expr ;postfix_expr = atom { call_suffix | "." IDENT | subscript_suffix | semantic_index_suffix | "?" } ;call_expr = postfix_expr ;call_suffix = "(" [ args ] ")" ;subscript_suffix= "[" ( expr | [ expr ] ":" [ expr ] [ ":" [ expr ] ] ) "]" ;semantic_index_suffix = "~" "[" expr "]" ;atom = literal | qualified_name | template_expr | list_expr | dict_or_set_expr | tuple_or_group | comprehension | parallel_expr | spawn_expr | validate_expr | semantics_pred | inject_expr ;list_expr = "[" [ list_elem { "," list_elem } [ "," ] ] "]" ;list_elem = "..." expr | expr ;dict_or_set_expr= "{" [ ( expr ":" expr { "," expr ":" expr } | list_elem { "," list_elem } ) [ "," ] ] "}" ;tuple_or_group = "(" [ expr { "," expr } [ "," ] ] ")" ;semantics_pred = "semantics" "(" STRING { "," expr } [ "," kwargs ] ")" ;(* `~` is the semantic sigil: `xs ~[q]`, `a ~< b`, `a ~+ b`, `a ~in b`, `a ~and b`, `~not a`, etc. all derive `model.invoke`. Bitwise NOT is `bitnot` (since `~` is reserved for semantics); strict boolean xor is `xor`. Semantic primitives are the `semantic.<verb>(subject, query, ...)` namespace (filter/rank/map/extract/summarize/translate/choose/query/combine/correct/ unique/similar/select). A type controls its semantic representation via the coercion protocol — methods `sem_text(self) -> str` and/or `embed(self) -> Embedding` (§5.30); pipelines attach via `with pipeline(pre=[..], post=[..])`. *)
policy_decl = [ "pub"? ] "policy" IDENT ":" NEWLINE INDENT { policy_rule } DEDENT ;policy_attach = "policy" "attach" IDENT NEWLINE ; (* module-level attachment, §5.8 *)policy_rule = policy_single | policy_group | example_single | example_group | "budget" IDENT comparator expr NEWLINE | "justification" STRING NEWLINE ;policy_single = "allow" effect_list [ "except" except_list ] [ "where" expr ] NEWLINE | "forbid" [ "cap" ] effect_list [ "except" except_list ] [ "where" expr ] NEWLINE ;policy_group = "allow" ":" NEWLINE INDENT { effect_list [ "except" except_list ] [ "where" expr ] NEWLINE } DEDENT | "forbid" [ "cap" ] ":" NEWLINE INDENT { effect_list [ "except" except_list ] [ "where" expr ] NEWLINE } DEDENT ;effect_list = effect { "," effect } ;except_list = ( effect | STRING ) { "," ( effect | STRING ) } ;comparator = "<=" | "<" | "==" ;example_single = "example" ( "allow" | "deny" ) ":" expr NEWLINE ;example_group = "examples" ":" NEWLINE INDENT { example_case } DEDENT ;example_case = ( "allow" | "deny" ) ":" NEWLINE INDENT { expr NEWLINE } DEDENT ;
monitor_decl = [ "pub"? ] "monitor"? IDENT "on" qualified_name ":" NEWLINE INDENT "capture" expr_list NEWLINE "baseline" ( "from" IDENT | STRING ) NEWLINE "test" expr NEWLINE { "on" IDENT ":" block } DEDENT ;
supervise = [ "pub"? ] "supervise"? IDENT ":" NEWLINE INDENT [ "restart" kwargs NEWLINE ] [ "fallback" expr NEWLINE ] [ "heal" kwargs ":" heal_block ] { statement } DEDENT ;heal_block = NEWLINE INDENT { "require" expr NEWLINE } [ "rollout" IDENT { "->" IDENT } NEWLINE ] DEDENT ;
event_decl = [ "pub"? ] "event"? IDENT ":" NEWLINE INDENT { field_decl | sem_decl | contract_clause | "key" qualified_name NEWLINE } DEDENT ;emit_stmt = "emit" qualified_name "(" [ args ] ")" ;subscriber_decl = [ "pub"? ] "subscriber"? IDENT "on" qualified_name ":" NEWLINE INDENT [ "sem"? STRING NEWLINE ] [ "where" expr NEWLINE ] [ queue_clause ] "handle" IDENT [ "!" effect_row ] ":" block DEDENT ;queue_clause = "queue" expr [ "," "on_full" "=" IDENT ] NEWLINE ;
ported_def = "ported"? "def" IDENT "(" [ params ] ")" [ "->" type ] "from" STRING ":" ported_block ;ported_block = NEWLINE INDENT { contract_clause | "differential" "against" IDENT NEWLINE } DEDENT ;ported_import = "ported"? "import" STRING "as" IDENT NEWLINE ;native_import = "native"? "import" ( qualified_name | STRING ) [ "as" IDENT ] NEWLINE ;bridge_decl = [ "pub"? ] "bridge" bridge_mode IDENT [ "from" STRING ] ":" NEWLINE INDENT { bridge_expose | foreign_block | bridge_meta } DEDENT ;bridge_mode = "python.inline" | "python.isolated" | "js.component" | "js.host" | "node.host" | "c.abi" | "cpp.abi" ;bridge_expose = "expose" def | "expose" ":" NEWLINE INDENT { def } DEDENT ;foreign_block = "begin" IDENT NEWLINE FOREIGN_TEXT "end" IDENT NEWLINE ;bridge_meta = ( "deps" STRING { [ "," ] STRING } | "link" STRING kwargs | "checksum" STRING | "symbol" STRING | "timeout_ms" ( NUMBER | STRING ) ) NEWLINE ; (* One `deps` line may pin several requirements and the separating commas are optional. `timeout_ms` is the per-request ceiling: at most one per bridge, one base-10 integer or a quoted string holding one. *)
scope_block = "scope" ":" block ;spawn_expr = "spawn" call_expr ;protocol_decl = [ "pub"? ] "protocol"? IDENT ":" NEWLINE INDENT { proto_transition } DEDENT ;proto_transition= IDENT ":" type "->" IDENT { "|" IDENT } NEWLINE ;
assure_decl = "assure"? ( "bronze" | "silver" | "gold" ) NEWLINE ;test_decl = "test"? STRING ":" block ; (* verification entry point, §5.7 *)service_decl = [ "pub"? ] "service"? IDENT "at" expr ":" NEWLINE INDENT { def_sig | sem_decl | "sem"? STRING NEWLINE | "budget" kwargs NEWLINE | "use" "protocol" qualified_name NEWLINE } DEDENT ;yield_stmt = "yield" expr ; (* stream def bodies only, §5.25 *)breakpoint_stmt = "breakpoint" [ "when" ( semantics_pred | expr ) ] ; (* §5.26 *)equation_decl = [ "pub"? ] "equation" IDENT "(" [ params ] ")" [ "->" type ] ":" eq_block ;equation_stmt = "equation" ":" eq_block ; (* bindings flow outward, §5.28 *)theorem_decl = "theorem" IDENT "(" [ params ] ")" ":" eq_block ; (* §5.28/D109. No "->" type: a theorem states a proposition rather than computing a value. Declaration position only — there is no inline `theorem:` form. *)eq_block = NEWLINE INDENT { eq_item } DEDENT ;eq_item = IDENT [ "(" [ params ] ")" ] ":=" math_expr NEWLINE | "return" math_expr NEWLINE | math_expr NEWLINE ;(* math_expr is the §5.28 notation: quantifiers ∀/∃/∃! with `x ∈ D :` binders, big operators Σ Π ⋃ ⋂ ∫ with _{binder} and ^{bound}, ∇/∂/d-dx/∇²/Δ, min/max/argmin/argmax/sup/inf with binder subscripts and `s.t.` constraint lists, ‖·‖_p, ⟨·,·⟩, |·|, set builder { x ∈ D : P }, ∪ ∩ ∖ △ ∈ ∉ ⊆ ⊂ ⊇, ¬ ∧ ∨ ⊕ ⇒ ⇔, `^` as power, postfix `!` and `^T`, `:=` definitions, ranges a..b. ASCII spellings (forall, exists, sum, prod, integral, grad, norm, inner, ...) are token-equivalent. Machine-readable sub-grammar: grammar/math.ebnf. *)
(* Neurosymbolic finite-domain constraint search (§5.51). `solve`, `var` and `constraint` are ordinary statement directives, so the domain and the constraint are plain Sema expressions; the block is legal anywhere a statement is. *)solve_stmt = "solve" [ "all" ] ":" NEWLINE INDENT { solve_item } DEDENT ;solve_item = "var" IDENT "in" expr NEWLINE | "constraint" expr NEWLINE ;
(* String literals (§5.13, D126). Prefixes bind lowercase and immediately adjacent to the quote; either quote character works everywhere: STRING = [ prefix ] ( quoted | triple ) ; prefix = "f" | "rf" | "fr" | "r" | "sql" | "re" ; quoted = '"' { escape | CHAR } '"' | "'" { escape | CHAR } "'" ; triple = '"""' RAW '"""' | "'''" RAW "'''" ; (* raw, multi-line *) escape = "\" ( "n" | "t" | "r" | "\" | '"' | "'" | "0" | "a" | "b" | "f" | "v" | "{" | "}" | "x" HEX HEX | "u" HEX HEX HEX HEX | "U" HEX HEX HEX HEX HEX HEX HEX HEX | NEWLINE ) ; (* non-raw bodies only *) Raw bodies (r/rf/fr/re) keep every backslash; `\<quote>` keeps both characters and does not terminate. Unknown escapes are lex errors. f/rf/fr/sql bodies carry `{expr[:format]}` interpolation holes with `{{`/`}}` literal braces (non-raw f also accepts `\{`/`\}`). *)
(* Shared syntactic and lexical productions. *)decorator = "@" qualified_name [ "(" [ args ] ")" ] NEWLINE ;def_sig = { decorator } [ "pub" ] [ "stream" ] [ "mut" ] "def" IDENT [ type_params ] "(" [ params ] ")" [ "->" type ] [ "!" effect_row ] NEWLINE ;args = argument { "," argument } [ "," ] ;argument = "..." expr | IDENT "=" expr | expr ;kwargs = IDENT "=" expr { "," IDENT "=" expr } [ "," ] ;expr_list = expr { "," expr } [ "," ] ;call_sig = qualified_name "(" [ params ] ")" ;
type = union_type ;union_type = primary_type { "|" primary_type } ;primary_type = qualified_name [ "[" type { "," type } "]" ] | "(" [ type { "," type } [ "," ] ] ")" | "(" [ type { "," type } ] ")" "->" type [ "!" effect_row ] | "None" ;qualified_name = IDENT { "." IDENT } ;literal = NUMBER | STRING | "true" | "false" | "None" ;
(* Interpolated token bodies are lexer-delimited; the parser recursively parses each expression and preserves the optional format suffix verbatim. *)interpolation = "{" expr [ ":" format_spec ] "}" ;format_spec = { FORMAT_CHAR } ;
(* INDENT/DEDENT are emitted from leading spaces after NEWLINE. Blank and comment-only lines do not affect indentation. IDENT, NUMBER, STRING, FORMAT_CHAR, CHAR, RAW, and HEX are lexer tokens; `#` starts a line comment. *)The normative grammar is a PEG; the published machine-readable CFG/GBNF export overapproximates it, so grammar-constrained decoding raises the syntactic-validity rate of generated Sema but the reference parser’s post-check remains the decider — masks alone are not the guarantee (THEORY.md T2; 05 §1.3; grammar prompting, NeurIPS 2023).