Zum Inhalt

08 — Grammatik-Skizze: Types, Tags, TypeFns und Refinements

Status: Grammatikentwurf, Parser-Kombinator-kompatibel


1. Ziel

Diese Grammatik ist absichtlich knapp. Die normative Quelle sollte später die benannte Parser-Kombinator-Grammatik sein. Diese EBNF ist die lesbare Projektion. Zwei Wahrheiten wären schlecht. Eine Wahrheit plus Anzeigeformat ist akzeptabel. Sogar zivilisiert.


2. Top-Level Items

Item ::= TypeDecl
       | TagDecl
       | ProtocolDecl
       | ServiceDecl
       | TypeFnDecl
       | FunctionDecl
       | ProvideDecl
       | ExternDecl
       | ImportDecl

3. Type Declaration

TypeDecl ::= "type" MetaPrefix? TypeName TypeParams? ":" TypeBody Refinements?
           | "type" TypeName "=" TypeExpr

TypeBody ::= StructBody
           | EnumBody
           | UnionBody
           | AliasBody

StructBody ::= "struct" "{" FieldDecl* "}"
EnumBody   ::= "enum" "=" VariantDecl+
UnionBody  ::= "union" "=" TypeExpr ("|" TypeExpr)*

Beispiel:

type User : struct {
    id: UserId
    name: str
}

4. Tag Declaration

TagDecl ::= "tag" MetaPrefix? TagName TagKind? Refinements?

TagKind ::= ":" "enum" "=" TagVariant+
          | ":" TagDomainRef

TagVariant ::= "|" TagName Refinements?

Beispiele:

tag RequestArena
tag OwnPolicy : enum =
    | Unique
    | Shared
    | Weak
tag RequestArena : ArenaKind
tag TaskLocal
    :> Own(Unique)
    :> Share(Local)

5. Type Parameters

TypeParamList ::= "[" TypeParam ("," TypeParam)* "]"

TypeParam ::= TypeParamQualifier? Name Constraint?

TypeParamQualifier ::= "phantom" | "reified"

Constraint ::= ":" ConstraintExpr

Beispiele:

type ManagedUser[phantom State: UserState] : struct { ... }

def describe[reified T](value: T) -> str = ...

Ungültig:

type Bad[phantom reified T] : struct { ... }

6. TypeFn Declaration

TypeFnDecl ::= "typefn" TypeFnName TypeFnParams? "=" TypeLevelExpr

TypeFnParams ::= "(" TypeFnParam ("," TypeFnParam)* ")"
TypeFnParam  ::= Name ":" ConstraintExpr

Beispiel:

typefn Share(policy: SharePolicy) = <{ share: policy }>

TypeFns mit Type-Parametern:

typefn StackBuffer[T, Size] =
    struct {
        data: [T; Size]
        filled: usize
    } :> Memory(Value)

Ob TypeFnParams und TypeParamList syntaktisch getrennt bleiben, ist Parser-Design. Semantisch gilt:

Parameter von typefn sind compile-time Parameter.

7. Refinements

Refinements ::= Refinement+
Refinement  ::= ":>" TypeLevelExpr

MetaPrefix ::= "<{" MetaField* "}>"
MetaField  ::= Identifier ":" TypeLevelExpr

Beispiele:

type User : struct { ... } :> Share(Local)
tag <{
    own: Unique
    share: Local
}> TaskLocal

8. Type-Level Expressions

TypeLevelExpr ::= TagRef
                | TypeRef
                | TypeFnCall
                | MetaRecord
                | Literal
                | TypeLevelIf
                | TypeLevelMatch

MVP kann TypeLevelIf und TypeLevelMatch auf TypeFns beschränken.


9. Name Resolution

Die Grammatik erkennt Formen. Die Semantik prüft Symbolarten.

`Local` in Value-Expression:
    Fehler, wenn SymbolKind.tag.

`Local` als Argument für Share(policy: SharePolicy):
    ok, wenn Local ∈ SharePolicy.

`User` in Value-Type-Position:
    ok, wenn SymbolKind.type.

10. Parser-Kombinator-Hinweis

Die ausführbare Grammatik sollte in Parser-Kombinator-Syntax geschrieben und daraus als EBNF/Markdown projiziert werden.

Beispiel, konzeptionell:

auto tagDecl = rule("TagDecl",
    seq(
        tok("tag"),
        opt(metaPrefix),
        tagName,
        opt(tagKind),
        many(refinement)
    )
);

Die Spec sollte später die benannte Regel TagDecl referenzieren, nicht eine zweite handgepflegte BNF-Wahrheit aufbauen. Niemand braucht zwei auseinanderlaufende Grammatiken. Nicht einmal Menschen, und die sammeln sonst wirklich alles.