Files
Odin/odin.ebnf
2026-05-17 13:18:48 +01:00

489 lines
15 KiB
EBNF

/* The Odin Programming Language Expressed as in EBNF */
/*
EBNF representation of itself:
Production = name "=" [ Expression ] "." ;
Expression = Alternative { "|" Alternative } ;
Alternative = Term { Term } ;
Term = name | token [ "…" token ] | Group | Option | Repetition ;
Group = "(" Expression ")" ;
Option = "[" Expression "]" ;
Repetition = "{" Expression "}" ;
*/
/* Tokens for Lexical Grammar */
IDENT = ( LETTER | "_" ) { LETTER | DIGIT | "_" } ;
LETTER = "a".."z" | "A".."Z" | "_" | UNICODE_LETTER ;
INT_LIT = DECIMAL_LIT | BINARY_LIT | OCTAL_LIT | DOZENAL_LIT | HEX_LIT ;
DECIMAL_LIT = DIGIT { [ "_" ] DIGIT } ;
BINARY_LIT = "0b" BIN_DIGIT { [ "_" ] BIN_DIGIT } ;
OCTAL_LIT = "0o" OCT_DIGIT { [ "_" ] OCT_DIGIT } ;
DOZENAL_LIT = "0z" DOZ_DIGIT { [ "_" ] DOZ_DIGIT } ;
HEX_LIT = "0x" HEX_DIGIT { [ "_" ] HEX_DIGIT } ;
FLOAT_LIT = DIGIT { DIGIT } "." DIGIT { DIGIT } [ EXPONENT ]
| DIGIT { DIGIT } EXPONENT
| "0h" HEX_DIGIT { [ "_" HEX_DIGIT ]} ;
EXPONENT = ( "e" | "E" ) [ "+" | "-" ] DIGIT { DIGIT } ;
IMAGINARY_LIT = ( INT_LIT | FLOAT_LIT ) ( "i" | "j" | "k" ) ;
RUNE_LIT = "'" ( CHAR | ESCAPE_SEQ ) "'" ;
STRING_LIT = '"' { CHAR | ESCAPE_SEQ } '"' ;
RAW_STRING_LIT = "`" { ANY_CHAR } "`" ;
ESCAPE_SEQ = "\" ( "a" | "b" | "e" | "f" | "n" | "r" | "t" | "v"
| "\\" | '"' | "'"
| OCT_DIGIT OCT_DIGIT OCT_DIGIT
| "x" HEX_DIGIT HEX_DIGIT
| "u" HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
| "U" HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT
HEX_DIGIT HEX_DIGIT HEX_DIGIT HEX_DIGIT ) ;
DIGIT = "0".."9" ;
BIN_DIGIT = "0" | "1" ;
OCT_DIGIT = "0".."7" ;
DOZ_DIGIT = "0".."9" | "a"| "b" | "A" | "B" ;
HEX_DIGIT = "0".."9" | "a".."f" | "A".."F" ;
COMMENT = "//" { ANY_CHAR } NEWLINE
| "/*" { ANY_CHAR | COMMENT } "*/" /* nestable */
| "#!" { ANY_CHAR } NEWLINE ;
/* Odin uses automatic semicolon insertion similar to Go/Python:
a newline acts as ";" after certain tokens such as IDENT,
literals, ")", "]", "}", "^", "---", "break", "continue",
"fallthrough", "return", "or_return", "or_break", "or_continue".
During parsing, ";" will be ignored with matching brackets in expressions similar to Python:
"(" ")"
"[" "]"
"{" "}"
*/
/* Syntax Grammar */
/* NOTE: Any directive such as "#partial" can also be written with any number of whitespace after the "#"
This grammar is simplified to represent minimize the need for "#" "partial"
*/
/* Source File Structure */
File = { FileTag } PackageDecl ";" { TopLevelStmt } ;
FileTag = "#+" IDENT [ TagValue ] NEWLINE ; /* #+build, #+private, #+feature, */
TagValue = { ANY_CHAR } ;
PackageDecl = "package" IDENT ;
TopLevelStmt = ImportDecl ";"
| ForeignImportDecl ";"
| ForeignBlock ";"
| WhenStmt
| Decl ";" ;
/* Import Declarations */
ImportDecl = { Attribute } "import" [ IDENT ] STRING_LIT ;
ForeignImportDecl = { Attribute } "foreign" "import" [ IDENT ] ( STRING_LIT | "{" ForeignImportPathList "}" ) ;
ForeignImportPathList = Expr { "," Expr } [ "," ] ;
/* Value Declarations */
Decl = { Attribute } ValueDecl ;
ValueDecl = IdentList ":" Type
| IdentList ":" [ Type ] "=" ExprList
| IdentList ":" [ Type ] ":" ExprList ;
IdentList = IDENT { "," IDENT } ;
ExprList = Expr { "," Expr } ;
/* Foreign Block Declaration */
ForeignBlock = { Attribute } "foreign" [ IDENT ] "{" { ForeignDecl ";" } "}" ;
ForeignDecl = { Attribute } ValueDecl ;
/* Statements */
Stmt = EmptyStmt
| Decl ";"
| ExprStmt ";"
| AssignStmt ";"
| BlockStmt
| IfStmt
| WhenStmt
| ForStmt
| SwitchStmt
| TypeSwitchStmt
| DeferStmt
| ReturnStmt ";"
| BranchStmt ";"
| UsingStmt ";"
| Attribute Stmt
| Label Stmt
| ForeignBlock
| DirectiveStmt ;
EmptyStmt = ";" ;
/* Directive Statements */
DirectiveStmt = "#assert" "(" Expr [ "," STRING_LIT ] ")"
| "#panic" "(" STRING_LIT ")"
| "#force_inline" CallBody
| "#force_no_inline" CallBody
| "#must_tail" CallBody ;
/* Block Statement */
BlockStmt = [ Label ] "{" StmtList "}" ;
StmtList = { Stmt } ;
Label = IDENT ":" ;
/* Assignment Statements */
ExprStmt = Expr ;
AssignStmt = ExprList AssignOp ExprList ;
AssignOp = "=" | "+=" | "-=" | "*=" | "/=" | "%=" | "%%="
| "|=" | "~=" | "&=" | "&~="
| "<<=" | ">>=" | "&&=" | "||=" ;
/* Control Flow */
IfStmt = "if" [ SimpleStmt ";" ] Expr StmtBody
{ "else" "if" [ SimpleStmt ";" ] Expr StmtBody }
[ "else" StmtBody ] ;
WhenStmt = "when" Expr StmtBody
{ "else" "when" Expr StmtBody }
[ "else" StmtBody ] ;
ForStmt = [ Label ] [ ForDirectivePrefix ]
"for" [ ForHead ] StmtBody ;
ForDirectivePrefix = "#reverse"
| "#unroll" [ CallBody ] ;
ForHead = RangeClause
| ForCondition
| ForCClause ;
ForCondition = Expr ;
ForCClause = [ SimpleStmt ] ";" [ Expr ] ";" [ SimpleStmt ] ;
RangeClause = [ [ SimpleStmt ] ";" ] [ [ "&" ] IDENT { "," [ "&" ] IDENT } "in" ] RangeExpr ;
RangeExpr = Expr
| Expr "..<" Expr
| Expr "..=" Expr ;
SwitchStmt = [ Label ] [ "#partial" ] "switch" [ SimpleStmt ";" ] [ Expr ]
"{" { CaseClause } "}" ;
CaseClause = "case" [ ExprList ] ":" StmtList ;
TypeSwitchStmt = [ Label ] [ "#partial" ] "switch" IDENT "in" Expr
"{" { TypeCaseClause } "}" ;
TypeCaseClause = "case" [ TypeList ] ":" StmtList ;
TypeList = Type { "," Type } ;
/* Branch & Defer */
BranchStmt = "break" [ IDENT ]
| "continue" [ IDENT ]
| "fallthrough" ;
DeferStmt = "defer" ( Stmt | ( "{" StmtList "}" ) ) ;
ReturnStmt = [ ReturnStmtDirectivePrefix ] "return" [ ExprList ] ;
ReturnStmtDirectivePrefix = "#force_inline" | "#force_no_inline" | "#must_tail" ;
/* Using Statement */
UsingStmt = "using" ( IdentList | Expr ) ;
/* Simple Statement (used in control flow init) */
SimpleStmt = ExprStmt | AssignStmt | ValueDecl ;
/* Body for Control Flow */
StmtBody = "{" StmtList "}"
| "do" Stmt ; /* must be on the same line as the initial token of the statement */
/* Expressions */
/* Binary Expressions
Operator Precedence (low -> high)
*/
Expr = OrElseExpr ;
OrElseExpr = TernaryExpr { "or_else" TernaryExpr } ;
TernaryExpr = RangeExprLvl
| RangeExprLvl "?" RangeExprLvl ":" TernaryExpr
| RangeExprLvl "if" RangeExprLvl "else" TernaryExpr
| RangeExprLvl "when" RangeExprLvl "else" TernaryExpr ;
RangeExprLvl = LogicalOrExpr [ "..<" | "..=" ] LogicalOrExpr ;
LogicalOrExpr = LogicalAndExpr { "||" LogicalAndExpr } ;
LogicalAndExpr = ComparisonExpr { "&&" ComparisonExpr } ;
ComparisonExpr = AddExpr { CompareOp AddExpr } ;
CompareOp = "==" | "!=" | "<" | "<=" | ">" | ">=" ;
AddExpr = MulExpr { AddOp MulExpr } ;
AddOp = "+" | "-" | "|" | "~" | "in" | "not_in" ;
MulExpr = UnaryExpr { MulOp UnaryExpr } ;
MulOp = "*" | "/" | "%" | "%%" | "&" | "&~" | "<<" | ">>" ;
/* Unary Expression */
UnaryExpr = PostfixExpr
| UnaryOp UnaryExpr
| "cast" "(" Type ")" UnaryExpr
| "transmute" "(" Type ")" UnaryExpr
| "auto_cast" UnaryExpr
| "." IDENT /* implicit selector */;
UnaryOp = "+" | "-" | "~" | "&" | "!" ;
/* Postfix / Operand Expressions */
PostfixExpr = Operand { PostfixOp } ;
PostfixOp = CallBody /* call */
| "->" IDENT CallBody /* selector call */
| "." IDENT /* field selector */
| "." "?" /* inferred type assertion */
| "." "(" Type ")" /* type assertion */
| "[" Expr "]" /* index */
| "[" [ Expr ] ":" [ Expr ] "]" /* slice */
| "[" Expr "," Expr "]" /* matrix index */
| "^" /* pointer deref */
| PostfixOrOp ;
CallBody = "(" [ ArgList ] ")" ;
PostfixOrOp = "or_return"
| "or_break" [ IDENT ]
| "or_continue" [ IDENT ] ;
ArgList = Arg { "," Arg } [ "," ] ;
Arg = [ IDENT "=" ] Expr
| ".." Expr ; /* spread */
Operand = IDENT
| "---" /* unintialized expression */
| "context"
| "typeid"
| Literal
| "(" Expr ")"
| ProcLiteral
| ProcGroup
| [ "#partial" ] CompoundLiteral
| DirectiveExpr
| Type ;
DirectiveExpr = "#" IDENT ; /* Used as the catch all */
/* Literals */
Literal = INT_LIT
| FLOAT_LIT
| IMAGINARY_LIT
| RUNE_LIT
| STRING_LIT
| RAW_STRING_LIT ;
CompoundLiteral = [ Type ] "{" [ ElementList ] "}" ;
ElementList = Element { "," Element } [ "," ] ;
Element = Expr [ "=" Expr ]
| ( Expr "..<" Expr | Expr "..=" Expr ) "=" Expr ;
/* Types */
Type = TypeName
| TypeLit
| "(" Type ")"
| "distinct" Type
| "typeid"
| "#type" Type ;
TypeName = IDENT
| QualifiedIdent
| PolyType ;
QualifiedIdent = IDENT "." IDENT ;
PolyType = "$" IDENT [ "/" Type ] ;
TypeLit = PointerType
| MultiPointerType
| ArrayType
| SliceType
| DynArrayType
| FixedCapDynArrayType
| MapType
| StructType
| UnionType
| EnumType
| BitSetType
| BitFieldType
| ProcType
| MatrixType
| SimdType
| SOAType ;
PointerType = "^" Type ;
MultiPointerType = "[^]" Type ;
ArrayType = "[" Expr "]" Type /* fixed-length or enumerated array */
| "[" "?" "]" Type /* infer-length array */
| "[" EnumType "]" Type ; /* enumerated array */
SliceType = "[" "]" Type ;
DynArrayType = "[" "dynamic" "]" Type ;
FixedCapDynArrayType = "[" "dynamic" ";" Expr "]" Type ; /* [dynamic; N]T */
MapType = "map" "[" Type "]" Type ;
StructType = "struct"
[ "(" PolyParamList ")" ]
[ StructDirectives ]
[ WhereClause ]
"{" [ FieldList ] "}" ;
StructDirectives = { "#packed"
| "#raw_union"
| "#align" "(" Expr ")"
| "#min_field_align" "(" Expr ")"
| "#max_field_align" "(" Expr ")"
| "#simple"
| "#all_or_none" } ;
FieldList = Field { "," Field } [ "," ] ;
Field = FieldNameList ":" Type [ FieldTag ] ;
FieldNameList = FieldName { "," FieldName } ;
FieldName = [ "using" | "#subtype" ] IDENT ;
FieldTag = STRING_LIT | RAW_STRING_LIT ;
UnionType = "union"
[ "(" PolyParamList ")" ]
[ UnionDirectives ]
[ WhereClause ]
"{" [ TypeList ] "}" ;
UnionDirectives = { "#no_nil"
| "#shared_nil"
| "#align" "(" Expr ")" } ;
EnumType = "enum" [ Type ] "{" [ EnumFieldList ] "}" ;
EnumFieldList = EnumField { "," EnumField } [ "," ] ;
EnumField = IDENT [ "=" Expr ] ;
BitSetType = "bit_set" "[" ( Type | RangeExpr ) [ ";" Type ] "]" ;
BitFieldType = "bit_field" Type "{" [ BitFieldList ] "}" ;
BitFieldList = BitFieldField { "," BitFieldField } [ "," ] ;
BitFieldField = IDENT ":" Type "|" Expr ;
ProcType = "proc" [ CallingConvention ] "(" [ ProcParamList ] ")"
[ "->" ProcResults ] ;
ProcLiteral = ProcType [ WhereClause ] ( ProcBody | "---" ) ; /* --- = no body / foreign */
ProcGroup = "proc" "{" ProcGroupList "}" ; /* procedure group */
ProcBody = "{" { Stmt } "}"
ProcGroupList = Expr { "," Expr } [ "," ] ;
CallingConvention = STRING_LIT ; /* "odin", "c", "std", "contextless", "fast", "none", etc. */
ProcParamList = ProcParam { "," ProcParam } [ "," ] ;
ProcParam = [ ParamPrefix ] PolyIdentList ":" [ ParamModifier ] ProcParamType [ "=" Expr ] ;
ProcParamType = Type
| "typeid" "/" ProcParamType ;
PolyIdent = [ "$" ] IDENT ;
PolyIdentList = PolyIdent { "," PolyIdent } ;
ParamPrefix = "using"
| "#no_alias"
| "#any_int"
| "#by_ptr"
| "#c_vararg"
| "#no_broadcast" ;
ParamModifier = ".." ; /* variadic */
ProcResults = Type
| "(" [ FieldList ] ")" ;
MatrixType = [ "#row_major" | "#column_major" ] "matrix" "[" Expr "," Expr "]" Type ;
SimdType = "#simd" "[" Expr "]" Type ;
SOAType = "#soa" ( ArrayType | SliceType | DynArrayType | FixedCapDynArrayType ) ;
PolyParamList = PolyParam { "," PolyParam } ;
PolyParam = PolyIdent ":" Type ;
WhereClause = "where" ConstraintExpr { "," ConstraintExpr } ;
ConstraintExpr = Expr ;
Attribute = "@" "(" AttrElemList ")"
| "@" IDENT ; /* shorthand: @private */
AttrElemList = AttrElem { "," AttrElem } [ "," ] ;
AttrElem = IDENT [ "=" Expr ] ;