~mna/snow

ref: 51726a5ef2959dd97add58914fe45d829880e258 snow/pkg/grammar/grammar.ebnf -rw-r--r-- 3.6 KiB
51726a5eMartin Angers Merge branch 'wip-static-func-return' 1 year, 11 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
// NOTE: comment production omitted for brevity.

SourceFile = { TopLevelStmt } .

// => Types 
Type = TypeName | TypeLiteral | "(" Type ")" .
TypeName = ( ident [ GenericArgClause ] | GenericTypeName ) | ident "." TypeName .
GenericTypeName = "$" ident .
TypeLiteral = FuncType | TupleType .

FuncType = "(" [ TypeList [ "," ] ] ")" "->" Type .
TupleType = "(" Type "," TypeList [ "," ] ")" . // at least 2 types
TypeList = Type { "," Type } .

// => Generic clauses
GenericParamClause = "[" GenericTypeList [ "," ] "]" .
GenericTypeList = GenericTypeName { "," GenericTypeName } .
GenericArgClause = "[" TypeList [ "," ] "]" .

// => Statements
TopLevelStmt = Declaration .
Stmt = Declaration | SimpleStmt | Block | ReturnStmt | BranchStmt .
Declaration = VarDecl | FuncDecl | StructDecl | InterfaceDecl .
SimpleStmt = ExprStmt | AssignStmt | EmptyStmt .

// => Variable declaration statement
VarDecl = ( "let" | "var" ) VarList . // there is no semicolon inserted after a comma, so cannot have a trailing comma
VarList = Var { "," Var } .
Var = ident ( TypedVarDecl | InitializedVarDecl ) .
TypedVarDecl = ":" Type [ InitializedVarDecl ] .
InitializedVarDecl = "=" Expr .

// => Function declaration statement 
FuncDecl = FuncHead ident [ GenericParamClause ] "(" [ ParamsList [ "," ] ] ")" [ FuncTrailer ] [ Block ] .
FuncHead = { FuncAttr } [ "ref" ] "fn" .

FuncAttr = "@" ident "(" [ FieldValueList [ "," ] ] ")" . 
FieldValueList = FieldValue { "," FieldValue } .
FieldValue = ident ":" Literal .  // only literals are supported as field values for attrs

ParamsList = ParamDef { "," ParamDef } .
ParamDef = ident ":" Type .
FuncTrailer = "->" Type .

// => Struct type declaration statement
StructDecl = "struct" ident [ GenericParamClause ] "{" StructDeclBody "}" .
StructDeclBody = { Declaration } .

// => Interface type declaration statement
InterfaceDecl = "interface" ident [ GenericParamClause ] "{" InterfaceBody "}" .
InterfaceBody = { FuncDecl } . // the parser will make sure there is no attribute, generic clause and body

// => Assignment statement 
AssignStmt = Expr "=" Expr .

// => Block statement
Block = "{" { Stmt } "}" .

// => Return statement
ReturnStmt = "return" [ Expr ] .

// => Branch statement 
BranchStmt = IfStmt | GuardStmt .
IfStmt = "if" CondList Block [ ElseClause ] .
ElseClause = "else" ( Block | IfStmt ) .
GuardStmt = "guard" CondList "else" Block .
CondList = ExprList .

// => Expression statement 
ExprStmt = Expr .
// => Empty statement
EmptyStmt = .

// => Expressions with operator precedence
Expr = OrTest .
OrTest = AndTest { "||" AndTest } .
AndTest = Comparison { "&&" Comparison } .
Comparison = Arithmetic  { ( "==" | "!=" | "<" | "<=" | ">" | ">=" ) Arithmetic } .
Arithmetic = Term { ( "+" | "-" ) Term } .
Term = Factor { ( "*" | "/" | "%" ) Factor } .
Factor = ( "+" | "-" | "!" ) Factor | Compound .
Compound = Atom { Trailer } .
Atom = "(" Expr ")" | TupleExpr | Literal | ident [ GenericArgClause ] .
TupleExpr = "(" Expr "," ExprList [ "," ] ")" . // at least 2 expressions
Literal = number | string .

// => Trailers
Trailer = Arguments | Selector .
Arguments = "(" [ ( ExprList | LabeledExprList ) [ "," ] ] ")" . // either all args are labeled, or none
ExprList = Expr { "," Expr } .
LabeledExprList = LabeledExpr { "," LabeledExpr } .
LabeledExpr = Label ":" Expr .
Selector = "." ( ident [ GenericArgClause ] | number ) .
Label = ident .

// => Terminals

// NOTE: not actual definitions, tokenizer is the source of truth.
ident = "a"  "z" { ( "a"  "z" | "0"  "9" | "A"  "Z" | "_" ) } [ "!" | "?" ] .
number = "0"  "9" { "0"  "9" } .
string = "\"" { " " … "~" } "\"" .