mirror of
https://github.com/odin-lang/Odin.git
synced 2026-05-25 05:09:53 +00:00
Add EBNF for Odin
This commit is contained in:
466
odin.ebnf
Normal file
466
odin.ebnf
Normal file
@@ -0,0 +1,466 @@
|
||||
/* 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"
|
||||
*/
|
||||
|
||||
|
||||
File = { FileTag } PackageDecl ";" { TopLevelStmt } ;
|
||||
FileTag = "#+" IDENT [ TagValue ] NEWLINE ; /* #+build, #+private, #+feature, … */
|
||||
TagValue = { ANY_CHAR } ;
|
||||
PackageDecl = "package" IDENT ;
|
||||
|
||||
TopLevelStmt = ImportDecl ";"
|
||||
| ForeignImportDecl ";"
|
||||
| ForeignBlock ";"
|
||||
| WhenStmt
|
||||
| Decl ";" ;
|
||||
|
||||
|
||||
ImportDecl = { Attribute } "import" [ IDENT ] STRING_LIT ;
|
||||
|
||||
ForeignImportDecl = { Attribute } "foreign" "import" [ IDENT ] ( STRING_LIT | "{" ForeignImportPathList "}" ) ;
|
||||
|
||||
ForeignImportPathList = Expr { "," Expr } [ "," ] ;
|
||||
|
||||
|
||||
Decl = { Attribute } ValueDecl ;
|
||||
|
||||
ValueDecl = IdentList ":" Type
|
||||
| IdentList ":" [ Type ] "=" ExprList
|
||||
| IdentList ":" [ Type ] ":" ExprList ;
|
||||
|
||||
IdentList = IDENT { "," IDENT } ;
|
||||
ExprList = Expr { "," Expr } ;
|
||||
|
||||
Stmt = EmptyStmt
|
||||
| Decl ";"
|
||||
| ExprStmt ";"
|
||||
| AssignStmt ";"
|
||||
| BlockStmt
|
||||
| IfStmt
|
||||
| WhenStmt
|
||||
| ForStmt
|
||||
| SwitchStmt
|
||||
| TypeSwitchStmt
|
||||
| DeferStmt
|
||||
| ReturnStmt ";"
|
||||
| BranchStmt ";"
|
||||
| UsingStmt ";"
|
||||
| Attribute Stmt
|
||||
| Label Stmt
|
||||
| ForeignBlock
|
||||
| DirectiveStmt ;
|
||||
|
||||
|
||||
EmptyStmt = ";" ;
|
||||
|
||||
|
||||
BlockStmt = [ Label ] "{" StmtList "}" ;
|
||||
StmtList = { Stmt } ;
|
||||
Label = IDENT ":" ;
|
||||
|
||||
|
||||
|
||||
ExprStmt = Expr ;
|
||||
|
||||
AssignStmt = ExprList AssignOp ExprList ;
|
||||
|
||||
AssignOp = "=" | "+=" | "-=" | "*=" | "/=" | "%=" | "%%="
|
||||
| "|=" | "~=" | "&=" | "&~="
|
||||
| "<<=" | ">>=" | "&&=" | "||=" ;
|
||||
|
||||
|
||||
|
||||
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 } ;
|
||||
|
||||
|
||||
|
||||
BranchStmt = "break" [ IDENT ]
|
||||
| "continue" [ IDENT ]
|
||||
| "fallthrough" ;
|
||||
|
||||
DeferStmt = "defer" ( Stmt | ( "{" StmtList "}" ) ) ;
|
||||
|
||||
ReturnStmt = [ ReturnStmtDirectivePrefix ] "return" [ ExprList ] ;
|
||||
ReturnStmtDirectivePrefix = "#force_inline" | "#force_no_inline" | "#must_tail" ;
|
||||
|
||||
|
||||
UsingStmt = "using" ( IdentList | Expr ) ;
|
||||
|
||||
|
||||
SimpleStmt = ExprStmt | AssignStmt | ValueDecl ;
|
||||
|
||||
|
||||
StmtBody = "{" StmtList "}"
|
||||
| "do" Stmt ; /* must be on the same line as the initial token of the statement */
|
||||
|
||||
|
||||
/* Binary Expressions */
|
||||
|
||||
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 = "+" | "-" | "~" | "&" | "!" ;
|
||||
|
||||
|
||||
|
||||
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 */
|
||||
|
||||
|
||||
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 ;
|
||||
|
||||
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 ] ;
|
||||
|
||||
ForeignBlock = { Attribute } "foreign" [ IDENT ] "{" { ForeignDecl ";" } "}" ;
|
||||
|
||||
ForeignDecl = { Attribute } ValueDecl ;
|
||||
|
||||
|
||||
DirectiveStmt = "#assert" "(" Expr [ "," STRING_LIT ] ")"
|
||||
| "#panic" "(" STRING_LIT ")"
|
||||
| "#force_inline" CallBody
|
||||
| "#force_no_inline" CallBody
|
||||
| "#must_tail" CallBody ;
|
||||
Reference in New Issue
Block a user