Grammar notes

Meta: not a full BNF — the source of truth is pkg/dang/dang.peg. This page captures the user-visible regularities so people don't have to read PEG.

Source of truth

Top-level structure

The start rule is Dang, not Module. Import and Reassignment are siblings of Decl/Form, not members of Decl.

Dang         := (Expr Sep)* Expr?         # Sep = newline or comma
Expr         := Import | Decl | Reassignment | Form
Import       := 'import' Symbol
Reassignment := Term AssignOp Form
Decl         := DocString? ( InterfaceDecl | UnionDecl | EnumDecl | ScalarDecl
                           | ObjectDecl | NewConstructorDecl | FieldDecl | DirectiveDecl )
Form         := Return | TryCatch | Raise | Conditional | ForLoop
              | Case | Break | Continue | DefaultExpr | TypeHint | Term
Term         := UnaryExpr | IndexOrCall | SelectOrCall | Literal | List
              | ObjectLiteral | Block | ParenForm | SymbolOrCall

Separators

Expression form (precedence)

Meta: keep this in sync with Operators precedence table — duplicating it isn't ideal but it's the kind of thing readers expect on a grammar page.

Type syntax

Type dispatches to one of these; non-null is a suffix ! wrapping any inner type. See Types and nullability.

Type         := NonNull | NamedType | ListType | ObjectType | TypeVariable
NonNull      := Type '!'
NamedType    := (NamedType '.')? UpperIdent     # qualifier is itself a NamedType
ListType     := '[' Type ']'
ObjectType   := '{{' (ObjectTypeField Sep)* ObjectTypeField? '}}'
TypeVariable := [a-z]                           # single lowercase letter

Lexical

Reserved words

Notable productions