Gramática formal
A gramática, token a token, sincronizada com o documento de design.
Notação.
::=define uma regra;?opcional;*zero-ou-mais;+um-ou-mais;|alternativa;( )agrupa;"…"é um terminal literal. Como a linguagem usa{ } [ ] ( )como tokens reais, eles aparecem sempre entre aspas ("{","[") pra não colidir com o metassintaxe.Newlineé uma quebra de linha significativa (ver ASI, §1).Separadores (regra central, do design doc). O separador segue o tipo do conteúdo, não o bracket. Um grupo-de-valor (lista posicional e homogênea de valores) separa por
,: argumentos de função, elementos de tupla, elementos de literal de array/slice/coleção, e os membros group-ish de set (error{A, B},Event{Send, Recv}, type argsMap[K, V]). Um corpo de membros distintos (cada um um campo nomeado, um caso, ou um statement) separa por;ouNewline(combináveis para legibilidade): campos de struct (numa declaração e num struct literal), variantes de enum, braços dematch, statements de bloco. Então um struct literal é campos distintos,Point{1; 2}, enquanto um array literal é grupo-de-valor,[]int{1, 2, 3}, mesmo os dois sendo delimitados por{ }: o conteúdo decide, não a chave.Fidelidade. As regras espelham o design doc seção por seção, sincronizadas com ele.
[decisão]marca os poucos pontos onde a gramática precisou escolher por silêncio do doc (ex.: a desambiguação do{}em §6).
1. Léxico (tokens)
Seção intitulada “1. Léxico (tokens)”Program ::= ModuleDecl? Item* (* ModuleDecl, se houver, é a 1ª coisa do arquivo *)
Ident ::= (Letter | "_") (Letter | Digit | "_")*Letter ::= "a"…"z" | "A"…"Z"Digit ::= "0"…"9"HexDigit ::= Digit | "a"…"f" | "A"…"F"OctDigit ::= "0"…"7"BinDigit ::= "0" | "1"
(* Keywords reservadas, nunca um Ident. As 32 do §27: *)Keyword ::= "fn" | "let" | "var" | "mut" | "const" | "decl" | "alias" | "union" | "module" | "use" | "if" | "else" | "match" | "loop" | "in" | "break" | "continue" | "return" | "defer" | "catch" | "yield" | "spawn" | "timeout" | "comptime" | "unsafe" | "assert" | "assume" | "pub" | "priv" | "as" | "true" | "false"
(* --- literais --- *)Literal ::= IntLit | FloatLit | DurationLit | SizeLit | StringLit | CharLit | BoolLitIntLit ::= DecInt | HexInt | OctInt | BinInt (* 4 bases + separador '_' *)DecInt ::= Digit (Digit | "_")*HexInt ::= "0x" HexDigit (HexDigit | "_")*OctInt ::= "0o" OctDigit (OctDigit | "_")*BinInt ::= "0b" BinDigit (BinDigit | "_")*FloatLit ::= DecInt "." DecInt (("e" | "E") ("+" | "-")? DecInt)?DurationLit ::= DecInt DurationUnit (* lexer converte → Duration, sem import *)DurationUnit ::= "ns" | "ms" | "s" | "m" | "h" | "d" (* §14, ver nota *)SizeLit ::= DecInt SizeUnit (* lexer converte → usize em BYTES, sem import (§14) *)SizeUnit ::= "b" | "kb" | "kib" | "mb" | "mib" | "gb" | "gib" | "tb" | "tib" (* b=byte; 'i'=base-2, só com prefixo *)StringLit ::= '"' (StringChar | Interpolation)* '"'Interpolation ::= "{{" Expr "}}" (* §16, interpolação via Display *)CharLit ::= "'" Grapheme "'" (* um grapheme cluster; resolve p/ codepoint/byte/grapheme por contexto *)BoolLit ::= "true" | "false"
BuiltinValue ::= "none" | … (* 'none' = Optional vazio E estratégia de @mm; é VALOR builtin, não keyword (§5) *)
Comment ::= "//" (até Newline)
(* --- operadores (tokens) --- *)ArithOp ::= "+" | "-" | "*" | "/" | "%" | "+%" | "-%" | "*%" (* soma/sub/mul com wrap: +/-/* trapam em overflow, as formas com %-sufixo dão wrap (§4) *)BitwiseOp ::= "&" | "|" | "^" | "~" | "<<" | ">>" (* ~ é unário (complemento); resto binário *)CompareOp ::= "==" | "!=" | "<" | ">" | "<=" | ">="LogicalOp ::= "&&" | "||" | "!"CompoundAssign ::= "+=" | "-=" | "*=" | "/=" | "%=" (* aritméticos com '=' *) | "&=" | "|=" | "^=" | "<<=" | ">>=" (* bitwise com '=' *)ChannelArrow ::= "<-" | "->" | "<->" (* tipo de channel E operadores send/receive (§4) *)Unidades de duração. São 6 (ns ms s m h d), como o §14 do design doc (5s, 300ms, 10ns, 6m, 7h, 18d).
ASI (só Newline). O separador de statement é a quebra de linha (estilo Go); o lexer fecha o statement no fim da linha. O ; explícito existe para os casos de uma-linha (cláusulas do loop C-style; braços/statements inline como unsafe { a; b }), mas a inserção automática é disparada apenas por Newline.
2. Itens de topo e declarações
Seção intitulada “2. Itens de topo e declarações”Item ::= Decorator* ItemBodyItemBody ::= FnDecl | MethodDecl | TypeDecl | AliasDecl | UnionDecl | Binding | UseDecl
(* --- função --- *)FnDecl ::= Visibility? "comptime"? "unsafe"? "fn" Ident GenericParams? "(" ParamList? ")" ("->" ReturnType)? BlockVisibility ::= "pub" | "priv"ParamList ::= Param ("," Param)* (* grupo em '()' → vírgula *)Param ::= Decorator* Ident ":" ParamType ("=" Expr)? (* "= Expr" = valor default *)ParamType ::= "mut"? Type (* 'mut' = passagem write-back (§6) *) | "..." Type (* variádico, '...' é PREFIXO (§7/§13) *)ReturnType ::= Type "==" Expr (* pós-condição tersa: -> u8 == cond (§5) *) | "(" NamedReturn ("," NamedReturn)+ ")" (* tupla nomeada: -> (lo: u8, hi: u8): SÓ retorno; rótulos p/ @ensures (§5/§14) *) | Type (* inclui tupla (a,b), Result[…], error{…} *)NamedReturn ::= Ident ":" Type
MethodDecl ::= "fn" "(" (Ident ":")? Type ")" Ident "(" ParamList? ")" ("->" ReturnType)? Block (* binding presente = método; ausente = função associada (§2) *)
(* --- decl: struct | enum | interface (o corpo desambigua; §2) --- *)TypeDecl ::= "decl" Ident GenericParams? ("->" Kind)? "{" DeclBody "}" (* '-> Kind' opcional, default '-> type'; '-> prop' = família de proposição (§21, D2) *)DeclBody ::= FieldList (* campos 'nome: tipo' → struct *) | VariantList (* variantes 'Nome'/'Nome(…)' → enum *) | SigList (* assinaturas 'fn …' → interface *)FieldList ::= Field (MemberSep Field)* MemberSep?Field ::= Decorator* Visibility? Ident ":" Type Decorator* (* @embeds após o tipo (§2) *)VariantList ::= Variant (MemberSep Variant)* MemberSep?Variant ::= Ident ("(" TypeList ")")? (* Nome OU Nome(payload) *) | Ident ":" ResultVariant (* variante que refina índice, SÓ sob um head dependente (§21, D3) *)ResultVariant ::= Type (* resultado do construtor nulário: Nil: Vec[T, 0] *) | "fn" GenericParams? "(" ParamList? ")" "->" Type (* Cons: fn[m: usize](head: T, tail: Vec[T, m]) -> Vec[T, m + 1] *)SigList ::= MethodSig (MemberSep MethodSig)* MemberSep?MethodSig ::= "fn" Ident "(" ParamList? ")" ("->" ReturnType)?Kind ::= "type" | "prop" (* o universo que um decl produz: 'type' (default, o kind da §10) | 'prop' (uma proposição, §21) *)
(* --- alias / union --- *)AliasDecl ::= "alias" Ident GenericParams? "=" RefinedType (* sinônimo transparente; parametrizado com GenericParams (§10, ex. alias StringTrie[V] = Trie[byte, V]); RefinedType permite um refinamento @where no fim (§21); leva '=' (§2) *)RefinedType ::= Type Decorator* (* referência-por-tipo: i64 @where(i64 >= 0) — o valor é nomeado pelo tipo, como @ensures(u8 > 0) (§21) *) | "(" Ident ":" Type ")" Decorator* (* slot nomeado: (xs: List[T]) @where(xs.len > 0) — liga o nome do valor, como um retorno nomeado -> (lo: u8) (§21) *)UnionDecl ::= "unsafe"? "union" Ident "{" FieldList "}" (* union é sempre unsafe (§2/§5) *)
MemberSep ::= ";" | Newline (* corpo em '{}' → ';' ou Newline; NUNCA ',' *)decl State { Idle; Running; Done } · decl Point { x: int; y: int } · decl Shape { Circle(int); Square }: membros separados por ; (ou Newline em multilinha). Contraste com fn f(a: int, b: int), em que os argumentos em () separam por ,.
3. Bindings (declaração de valor)
Seção intitulada “3. Bindings (declaração de valor)”Binding ::= BindKw? BindTarget BindRhsBindKw ::= "let" | "var" | "const" (* ausente = atalho imutável (':=') *)BindTarget ::= BindNames (* a, b (sem parênteses) *) | "(" BindNames ")" (* (a, b) (com parênteses) *)BindNames ::= BindName ("," BindName)* (* nomes = grupo-ish → vírgula *)BindName ::= Ident | "_" (* '_' descarta (§14) *)BindRhs ::= ":=" ExprList (* inferido: x := v | a, b := 0, 1 *) | ":" Type "=" Expr (* tipado (estilo Odin): x: T = v (§6/§14) *)ExprList ::= Expr ("," Expr)*Semântica (anotada): := (ou : T =) declara; = pelado só atribui a um var. _ := Expr é a única forma de descartar. const x := v ≡ comptime let. a, b := f() ≡ (a, b) := f() (casam por posição).
4. Tipos
Seção intitulada “4. Tipos”Type ::= PointerType | ManyPtrType | SliceType | ArrayType | TupleType | FunctionType | ChannelType | ErrorSetType | VariantSetType | GenericType | QualifiedType | NamedType
PointerType ::= "*" Type (* um só ponteiro; sem *const/*mut (§6) *)ManyPtrType ::= "[" "*" "]" Type (* [*]T, ponteiro-de-muitos: N contíguos, sem comprimento; indexar é unsafe (§6) *)SliceType ::= "[" "]" Type (* []T = [*]T + comprimento (§6) *)ArrayType ::= "[" (Expr | "_") "]" Type (* [N]T (N comptime) | [_]T (tamanho inferido do literal, §6) *)TupleType ::= "(" Type ("," Type)+ ")" (* (a, b): grupo em '()' → vírgula (§7) *)FunctionType ::= "fn" "(" TypeList? ")" ("->" Type)? (* fn(A) -> B (§9/§10) *)ChannelType ::= "Channel" "[" ChannelDir ("," ChannelDir)* "]"ChannelDir ::= "<-" Type | "->" Type | Type (* <-T envio, ->T recebo (§4) *)
ErrorSetType ::= "error" ("{" SetMembers "}")? (* 'error' = ABERTO; 'error{…}' = FECHADO (§7) *)VariantSetType ::= NamedType "{" SetMembers "}" (* Event{Send, Receive}, em POSIÇÃO DE TIPO (§7) *)SetMembers ::= (SetMember ("," SetMember)*)? (* grupo-ish → vírgula; VAZIO = conjunto fechado vazio = desabitado: error{} = "não erra" (§7) *)SetMember ::= Ident (* uma variante / tag *) | Ident "..." (* spread, '…' é POSTFIX: 'nome...' (§7) *)
GenericType ::= (QualifiedType | NamedType) "[" TypeArg ("," TypeArg)* "]" (* List[int], Result[(int,int), E], box.Box[int] — base qualificada por módulo também (§15) *)TypeArg ::= Type | Expr (* tipo OU valor comptime (ex.: [N]) *)QualifiedType ::= Ident ("." Ident)+ (* c.gcc.int, modulo.Tipo; instancie uma genérica qualificada como QualifiedType "[" … "]" *)NamedType ::= Ident | PrimitiveTypeTypeList ::= Type ("," Type)*
PrimitiveType ::= IntType | FloatType | "bool" | "string" | "byte" | "bit" | "codepoint" | "grapheme" | "char" (* byte=u8, bit=u1, char=grapheme: apelidos builtin (§14/§16) *) | "int" | "uint" | "isize" | "usize" | "type" (* o kind, valor de compilação (§10) *) | "noreturn" (* tipo bottom, divergência; encaixa em qualquer contexto (§14) *)IntType ::= ("i" | "u") DecInt (* iN/uN, N ∈ 1..65535 (§14) *)FloatType ::= "f16" | "bf16" | "f32" | "f64" | "f128" | "f256" | "float"Desambiguação Nome{…} (§7). Em posição de tipo, Nome{…} é VariantSetType (Event{Send}). Em posição de valor, é StructLit (Vec2{1; 2}). A posição separa; o kind reforça. error{…} é sempre ErrorSetType (error é keyword contextual: nomeia o domínio de erro builtin em posição de tipo e na construção error.Tag, mas não é reservada fora disso). Note que as formas de set são group-ish de posição-de-tipo e separam membros por vírgula (error{A, B}, Event{Send, Recv}), como um array literal []int{1, 2, 3} (grupo-de-valor), e diferente de um struct literal Vec2{1; 2} (campos distintos, ;): o conteúdo decide o separador, não a chave (§1).
Builtin que não são keywords (moram aqui, §27): Result[T,E], Optional[T], Ptr, RawPtr, Generator[T], Duration.
5. Statements
Seção intitulada “5. Statements”Block ::= "{" (Stmt MemberSep)* Stmt? "}"Stmt ::= Binding | ComptimeStmt | Assignment | LoopStmt | IfStmt | MatchStmt | ReturnStmt | BreakStmt | ContinueStmt | YieldStmt | DeferStmt | SpawnStmt | UnsafeStmt | StandaloneDecorator | FnDecl (* função ANINHADA: só escopo, sem captura (§14) *) | ExprStmt
ComptimeStmt ::= "comptime" (Binding | Block | IfStmt | LoopStmt | MatchStmt) (* comptime ortogonal sobre binding/bloco/if/loop/match; comptime fn está no FnDecl (§10) *)
(* --- atribuição (≠ binding: '=' pelado, só p/ var) --- *)Assignment ::= LValue AssignOp Expr | LValueList "=" ExprList (* a, b = b, a: swap/paralelo (§14) *)AssignOp ::= "=" | CompoundAssign (* = | += -= *= /= %= &= |= ^= <<= >>= *)LValue ::= Ident | LValue "." Ident | LValue "[" Expr "]" | "*" LValueLValueList ::= LValue ("," LValue)*
ReturnStmt ::= "return" Expr? | "return" MatchExpr (* 'return' distribuído (§14); `if` é statement-only, use o ternário para valor *)BreakStmt ::= "break" Ident? (* LABEL de LOOP opcional, nunca valor (§14); um loop entrega via return *)ContinueStmt ::= "continue" Ident? (* label de loop opcional *)YieldStmt ::= "yield" Expr (* generators (§11) *)DeferStmt ::= "defer" Expr (* cleanup LIFO (§14) *)
(* --- loop unificado (§14) --- *)LoopStmt ::= (Ident ":")? "loop" LoopHeader? Block (* label Go-style opcional; também usável em posição de valor (Primary), entregando via return *)LoopHeader ::= Expr (* condição booleana → while *) | Ident "in" Expr (* IDENT in iterável/range → for-each *) | Binding ";" Expr ";" SimpleStmt (* C-style; ';' explícito delimita as 3 partes *)SimpleStmt ::= Assignment | ExprStmtRangeExpr ::= Expr ".." Expr | Expr "..=" Expr (* '..' exclusivo, '..=' inclusivo *)
IfStmt ::= IfExprIfExpr ::= "if" Expr Block ("else" (IfExpr | Block))?
SpawnStmt ::= "spawn" (CallExpr | Block) ErrorTrailer? (* spawn f(x) catch|e|{} | spawn { … } *)UnsafeStmt ::= "unsafe" Block (AssertTrailer | AssumeTrailer)? (* 'unsafe expr' aparece como Unary em Expr *)StandaloneDecorator ::= Decorator (Binding | Block)? (* @mm(arena), @state x := v, @effect { … } *)ExprStmt ::= ExprMatchStmt ::= MatchExpr6. Expressões e precedência
Seção intitulada “6. Expressões e precedência”Precedência do mais alto (liga mais forte) ao mais baixo. Adotada a do Go, a mais comum entre Zig/Go/Odin/Erlang/Gleam (Odin e Erlang concordam no agrupamento bitwise; só o Zig separa). Propriedade universal nas 5: comparação fica abaixo de bitwise.
Nível Operadores1 postfix/acesso x.y x.f() x() x[i] x as T x@decorator2 unário (prefixo) -x !x ~x *x(deref) &x(addr)3 multiplicativo * / % << >> &4 aditivo + - | ^5 comparação == != < > <= >=6 E lógico &&7 OU lógico ||8 ternário (mais baixo) ? : (atribuição é statement, fora da escada de expressão)Expr ::= TernaryTernary ::= LogicalOr ("?" Expr ":" Expr)? (* cond ? a : b (§14) *)LogicalOr ::= LogicalAnd ("||" LogicalAnd)*LogicalAnd ::= Comparison ("&&" Comparison)*Comparison ::= Additive (CompareOp Additive)* (* string usa estes byte-a-byte; semântica Unicode por método (§16) *)Additive ::= Multiplicative (("+" | "-" | "|" | "^") Multiplicative)* (* '+' concatena string *)Multiplicative ::= Unary (("*" | "/" | "%" | "<<" | ">>" | "&") Unary)*Unary ::= UnaryPrefix* PostfixUnaryPrefix ::= "-" | "!" | "~" | "*" | "&" (* *deref; &addr *)Postfix ::= Primary PostfixOp*PostfixOp ::= "." Ident (* campo / método sem args *) | "." Ident "(" ArgList? ")" (* método via UFCS: x.f(y) ≡ f(x, y) (§14) *) | "(" ArgList? ")" (* chamada *) | "[" Expr "]" (* indexação *) | "[" Expr? (".." | "..=") Expr? "]" (* slice VIEW, aliasa o backing; bounds opcionais (§6) *) | "[" Expr? ":" Expr? "]" (* slice COPY, independente O(n); bounds opcionais (§6) *) | "[" TypeArg ("," TypeArg)* "]" (* args comptime: collect[List]() (§10) *) | "as" Type (* conversão (§2/§16) *) | ValueDecorator (* result @transfer (§5) *) | ErrorTrailer (* catch|e| / match|e| / assert / assume (§5/§7) *) | ChannelTrailer (* <- / <-> com timeout (§4) *)
Primary ::= Literal | BuiltinValue | Ident | EnumShorthandLit (* .Variante: enum inferido do tipo esperado (§7, §16) *) | "(" Expr ")" (* agrupamento *) | TupleLit | StructLit | ArrayLit | MatchExpr | LoopStmt | RangeExpr (* match e loop são formas-valor (entregam via return); `if` NÃO está aqui: é statement-só, sua forma-valor é o ternário `c ? a : b` (§14). `Lambda` também NÃO está aqui: só é alcançável por `Arg`, e é isso que faz "só como argumento direto" (§6/§14) ser um fato da GRAMÁTICA, não uma regra do checker *) | ReceiveExpr
EnumShorthandLit ::= "." Ident (* literal de enum ponto-líder: `.Red`, `.semantic`; enum inferido do contexto (estilo Zig). Só no início de expr; `x.campo` é um PostfixOp. Não-inferível = erro. *)
TupleLit ::= "(" Expr ("," Expr)+ ")" (* (a, b): grupo em '()' → vírgula *)StructLit ::= StructHead "{" (FieldInits | FieldVals)? "}" (* Vec2{x: 1; y: 2} | Vec2{1; 2}: campos distintos → MemberSep (§1) *)StructHead ::= (QualifiedType | NamedType) ("[" TypeArg ("," TypeArg)* "]")? (* Vec2 | Box[int] | box.Point | box.Box[int]: local ou qualificada por módulo, simples ou genérica (§15) *)FieldInits ::= FieldInit (MemberSep FieldInit)*FieldVals ::= Expr (MemberSep Expr)* (* struct literal posicional: campos distintos, não grupo de valores *)FieldInit ::= Ident ":" ExprArrayLit ::= (SliceType | ArrayType) "{" (Expr ("," Expr)*)? "}" (* []int{1, 2, 3} | [3]int{1, 2, 3} | [_]int{1, 2, 3}: elementos são GRUPO-DE-VALOR → vírgula (§1) *)ArgList ::= Arg ("," Arg)*Arg ::= "mut"? Expr | Lambda (* 'mut' no call site (§6); lambda como arg *)
Lambda ::= "fn" "(" ParamList? ")" ("=>" Expr | Block) (* SÓ como argumento direto (§14) *)
(* --- channels (§4) --- *)ReceiveExpr ::= "->" Expr (* receive: data := -> chan (prefixo, posição de valor) *)ChannelTrailer ::= "<-" Expr (* send: chan <- data *) | "<->" Expr "timeout" "(" Expr ")" (* sync req-reply; timeout OBRIGATÓRIO *)ValueDecorator ::= "@" ("transfer" | "pin" | "unpin") | "@" "promote" "(" DecoratorArgs ")" (* node @promote(gc, deep) *)[decisão: resolvida] Separador por conteúdo, não por bracket. Um struct literal é um corpo de campos distintos, então separa por ; ou Newline (Vec2{1; 2} ou a forma multi-linha). Um array/slice literal é um grupo-de-valor de elementos homogêneos, então separa por , ([]int{1, 2, 3}), igual aos outros grupos-de-valor (argumentos, tuplas, membros de set). Os dois são delimitados por { }, mas o conteúdo decide o separador, não a chave: membros distintos (campos, variantes, braços, statements) levam ;/Newline; um grupo-de-valor posicional leva ,. (Isso refina um fraseado anterior “todo corpo { } usa ;”, que era grosso demais: elementos de array não são campos distintos.)
7. Match e padrões
Seção intitulada “7. Match e padrões”MatchExpr ::= "match" Expr "{" MatchArms "}" (* COM sujeito → switch/pattern (§14) *) | "match" "{" SelectArms "}" TimeoutTrailer? (* SEM sujeito → select (§4) *)
ErrorTrailer ::= "match" "|" Ident "|" "{" MatchArms "}" (* op match |e| { }, ramifica (§7) *) | "catch" "|" Ident "|" Block (* op catch |e| { }, erro como unidade (§7) *) | AssertTrailer | AssumeTrailerAssertTrailer ::= "assert" "(" Expr ")" (* checa: runtime verifica, panic se falsa (§5) *)AssumeTrailer ::= "assume" StringLit (* confia: afirma sem check e sem licença p/ UB (§5) *)
MatchArms ::= MatchArm (MemberSep MatchArm)* MemberSep?MatchArm ::= Pattern "=>" ArmBodyArmBody ::= Block | ReturnStmt | BreakStmt | ContinueStmt | ExprStmtSelectArms ::= SelectArm (MemberSep SelectArm)* MemberSep?SelectArm ::= (BindName ":=")? ReceiveExpr "=>" ArmBody (* data := -> chan_a => handle(data) *)TimeoutTrailer ::= "timeout" "(" Expr ")" Block (* } timeout(5s) { … }; ausente=infinito; timeout(0)=poll *)
Pattern ::= SubPattern ("|" SubPattern)* (* or-pattern 'A | B' (§14) *)SubPattern ::= "_" (* wildcard, SÓ domínio aberto (§7/§14) *) | Literal | "Ok" "(" Pattern ")" | "Err" "(" Pattern ")" | VariantPattern | Ident (* binding, ou variante sem payload *)VariantPattern ::= QualName ("(" PatternList ")")? (* error.NotFound | Send(m) | Click(x, y) *)QualName ::= Ident ("." Ident)*PatternList ::= Pattern ("," Pattern)*Os braços de match/select usam MemberSep (; ou Newline), a mesma regra de {} das declarações. Nunca vírgula. Exaustividade: domínio fechado (enum, error{…}, conjunto de variantes, whitelist) exige todas as variantes que o tipo admite e proíbe _; domínio aberto (int, string, error pelado) exige _.
8. Decoradores (sigil @)
Seção intitulada “8. Decoradores (sigil @)”Decorator ::= "@" Ident ("(" DecoratorArgs ")")? (* com args → '()'; tag pura → sem (§14) *)DecoratorArgs ::= DecoratorArg ("," DecoratorArg)* (* args = grupo em '()' → vírgula *)DecoratorArg ::= Ident ":" Expr (* nomeado: strategy: rest_for_one *) | Expr (* posicional: arena, gc, none, 16mb, x86 *)Posições (do §5/§14/§20). Prefixo de declaração (@repr(c) decl …, @component fn …, @test fn …, @supervisor(cfg) spawn …); postfix de valor (result @transfer, node @promote(gc, deep)); statement solto / binding reativo (@mm(arena), @state x := v, @effect { … }); em parâmetro/campo (value: *Record @mm(c), motor: Motor @embeds(methods)).
@generator é decorador comum. Pode vir acima da função (linha própria) ou inline antes do fn, como qualquer outro decorador, capturado por Decorator* em Item. Não há slot fixo no header de FnDecl (a ordem pub? comptime? @generator? unsafe? fn do doc é só convenção de escrita).
9. Módulos (§14/§15)
Seção intitulada “9. Módulos (§14/§15)”ModuleDecl ::= "module" ModulePath (* no TOPO do arquivo, estilo 'package' do Go/Odin *)UseDecl ::= "use" ModulePath (* use json → json.parse(…) *) | "use" ModulePath "." "{" Ident ("," Ident)* "}" (* use json.{parse, decode} *) | "use" ModulePath "as" Ident (* use json as j *) | "use" ModulePath "." Ident "(" ArgList? ")" (* inline: use json.parse(data) *)ModulePath ::= Ident ("." Ident)*
GenericParams ::= "[" GenericParam ("," GenericParam)* "]"GenericParam ::= TypeParam | ValueParam (* um parâmetro de tipo OU um parâmetro de valor comptime *)TypeParam ::= Ident HKTParams? ConstraintSpec? (* T | T: {…} | T + I | C[_] | C[_: {…}]: {…} + I *)ValueParam ::= Ident ":" Type (* um valor comptime de QUALQUER tipo: [n: usize], [flag: bool], [p: Point] (§10). O Type pode nomear um type-param ANTERIOR → value-param dependente, ex. [A, x: A] (§21, D1). Desambiguação: ':' seguido de '{' é whitelist num TypeParam; ':' seguido de um Type é um ValueParam. *)HKTParams ::= "[" "_" ConstraintSpec? "]" (* C[_] não-aplicado; ConstraintSpec aqui = constraint do ELEMENTO (§10) *)ConstraintSpec ::= Whitelist ("+" Interface)* (* régua estrita §10: ':' SÓ whitelist (pertencimento), *) | ("+" Interface)+ (* '+' SÓ interface (implementação): nome não diz qual, daí 2 símbolos *)Whitelist ::= ":" "{" TypeList "}" (* ': {List, Set}': pertence ao conjunto *)Interface ::= NamedType (* '+ Writeable', implementa a interface *)module path declara, no topo do arquivo, a que módulo o arquivo pertence (igual package do Go). O sistema de resolução (árvore, paths, visibilidade) está no §15 do design doc.
10. Notas e decisões
Seção intitulada “10. Notas e decisões”Resolvidas nesta rodada (todas confirmadas por você):
- Literais numéricos: 4 bases (
0b/0o/0x/decimal) + separador_. - Separadores (por conteúdo, não por bracket): grupos-de-valor
,(args, tuplas, membros de set, literais de array/slice[]int{1, 2, 3}); corpos de membros distintos;/Newline (corpos dedecl, variantes de enum, braços dematch, blocos, literais de structVec2{1; 2}). Os dois literais usam{ }; o conteúdo decide (§1). - Operadores booleanos:
&&||!(grafia de símbolo). - Precedência: a do Go (a mais comum).
- Bitwise + compostos:
& | ^ ~ << >>; compostos+= -= *= /= %= &= |= ^= <<= >>=. none: valor builtin (Optional vazio + estratégia de@mm), não keyword.@generator: decorador comum (acima ou inline), sem slot fixo.module: declaração no topo do arquivo (estilopackagedo Go).- ASI: disparada só por Newline;
;explícito para uma-linha. ->receive vs->tipo de retorno: mesmo glifo, desambiguado por posição (expressão de channel vs assinatura).
Resolvidas também nesta rodada:
++/--: removidos. Incremento/decremento não entram na linguagem (usa+= 1/-= 1), alinhado com as 5 referências e com a explicitude do doc.- Separadores no design doc: sincronizados. Os corpos de
decl(e ounion) passaram a;, e a nota do §14 foi ajustada; gramática e doc batem de novo. @generatorno doc: nota de decorador adicionada (acima ou inline, sem slot fixo).- Unidades de duração: confirmadas as 6 (
ns ms s m h d).
Resolvidas nesta rodada (revisão pós-feedback):
- Régua estrita de constraint:
:introduz só whitelist{…}(pertencimento);+introduz só interface (implementação).T: DisplayvirouT + Display. HKT: constraint do elemento dentro de[_ …], constraint do container depois de]; todas as formas derivam deGenericParam ::= Ident HKTParams? ConstraintSpec?. Motivo: um nome não distingue “é o tipo Foo” de “implementa Foo”, então dois símbolos. assume(nova keyword, 32 no total):assertagora é só a forma checávelassert (cond)(checa, panic se falsa); a forma fraca (afirmar sem checar, sem licença para UB) virouassume "razão". Dois trailers distintos (AssertTrailer/AssumeTrailer).- Operadores em string: liberados byte-a-byte:
==/!=(igualdade de bytes),</>/<=/>=(ordem lexicográfica). Sós[i]continua banido (unidade ambígua); semântica Unicode (normalização, collation) por método. - Tupla nomeada no retorno:
-> (lo: u8, hi: u8)vale só em posição de retorno (rótulos de slot para@ensures), não como tipo-tupla nomeado geral. - Sintaxe de extensão fica fora desta gramática: esta gramática descreve só o core (
.mko). Uma extensão de compilador (seção 20 do design doc) pode trazer sua própria gramática para os tipos de arquivo que registra (ex.: o markup do.mkoui) e definir decoradores próprios; nada disso entra aqui. O core é fechado; o que cada extensão adiciona é especificado por ela.
11. Camada de verificação (§21 do design)
Seção intitulada “11. Camada de verificação (§21 do design)”As construções de verificação do core. A maior parte da camada é decorador comum, capturado por Decorator* sem produção nova: @must_consume/@consume_once (posse nível-de-tipo num decl), @pure/@total (cercas), @proof (a cerca de soundness sobre uma família dependente ou função). O que adiciona gramática é triplo, e tudo reusa formas existentes: refinamentos (RefinedType, §2), os deltas de tipos dependentes (ValueParam em GenericParam, o Kind no cabeçalho do decl, e a Variant/ResultVariant que refina índice, todos §2), e protocolos de sessão (abaixo).
(* --- protocolos de sessão: o decorador @protocol seleciona um corpo-de-passos para o decl (§21) --- *)ProtocolDecl ::= "@protocol" "decl" Ident GenericParams? "{" ProtoBody "}" (* @protocol faz o '{}' ser um ProtoBody, não um DeclBody *)ProtoBody ::= ProtoStep (MemberSep ProtoStep)* MemberSep?ProtoStep ::= Type ("@sends" | "@receives") (* postfix: Credentials @sends, Token @receives (prefixo '@sends Type' também aceito) *) | ("@sends" | "@receives") "match" "{" ProtoArms "}" (* @sends match = eu escolho (escolha interna); @receives match = o peer escolhe (externa) *) | "loop" "{" ProtoBody "}" (* recursão *) | "continue" (* volta ao loop envolvente *) | "_" (* fim do protocolo *)ProtoArms ::= ProtoArm (MemberSep ProtoArm)* MemberSep?ProtoArm ::= Ident "=>" (("{" ProtoBody "}") | ProtoStep | "_")
(* --- dual: o endpoint espelhado; um operador-de-tipo comptime, junta-se às formas de Type --- *)DualType ::= "dual" Type (* Channel[dual Auth]: troca todo @sends ↔ @receives, inclusive @sends match ↔ @receives match (§21) *)DualType é uma alternativa adicional de Type (um operador-de-tipo prefixo, como um builtin sobre tipos), então dual Auth é válido onde quer que um tipo seja esperado — mais utilmente Channel[dual Auth], onde o contrato-no-spawn (§4 do design) checa que os dois endpoints são complementos.
Nenhuma keyword cresce. A camada toda reusa match, loop, continue, _ e fn, mais o namespace do @ para seus decoradores; o conjunto de 32 keywords (§7 acima) não muda. type ganha o universo-irmão prop no Kind (ambos builtins minúsculos, como int/bool), não uma keyword nova.
@by é um delta de core diferido, ainda não gramaticalizado aqui. O bloco de tática @by { … } (§21) é um bloco com goal-threading portado por decorador — semântica de bloco nova, logo um delta de core, mas realizado só na era self-hosting (quando use compiler expõe o AST como tipo de library). É nomeado aqui para não ser esquecido; sua produção é adicionada quando ele chegar.
Model checking é uma extensão, então sua gramática fica fora. @spec e a library temporal spec.* (§21) pertencem à extensão de model-checking, e pela nota de fechamento do §10 acima, a gramática de uma extensão não faz parte do core e não aparece neste documento.
Resolvido nesta rodada (a camada de verificação, §21 do design):
- Posse
@must_consume/@consume_once: decoradores nível-de-tipo nodecl, sem produção nova. - Refinamento
@where:RefinedTypeno RHS de umalias(e via oDecorator*no fim/início de um campo/param) — referência-por-tipo ou um slot nomeado(x: T), reusando o device de retorno-nomeado do §14. Sem binder mágico. - Value-params, generalizados (D1):
GenericParam ::= TypeParam | ValueParam; umValueParamé um valor comptime de qualquer tipo, cujo tipo pode nomear um type-param anterior (dependente). Isso também fecha uma lacuna anterior — value-params eram usados no design doc mas não estavam na produção. - Kind no cabeçalho do decl (D2):
("->" Kind)?noTypeDecl;Kind ::= "type" | "prop".->reusa “produz”;:continua significando binding de campo/param só. - Variante que refina índice (D3):
VariantganhaIdent ":" ResultVariant(tipo-resultado nulário, ou um construtorfn[…](…) -> …), válido só sob um head dependente. - Sessões:
@protocol declcom umProtoBodyde passos@sends/@receives,matchpara escolha (direção = quem escolhe),loop/continue/_;dualcomo operador-de-tipo. Só umChanneltipado por um protocolo é percorrido como sessão. - Definitional equality (D4) e Σ/Π (D5) são poderes de checker/tipagem, não gramática de superfície; não adicionam produções.