Root: Item*
Item: LetItem | TypeItem
LetItem: let Ident Arg* (: Type)? = Expr
Arg: Ident | ( Ident : Type )
TypeItem: type Ident TypeArg* = Type
TypeArg: Ident (TODO: add type bounds?)
Type: TypePath | Fn | Record | Enum | Tuple
TypePath: Ident (. Ident)* TypeArg*
Fn: Type -> Type
Record: { (Ident : Type ,)* })
Enum: EnumVar (| EnumVar)* (TODO: allow empty enums?)
EnumVar: Ident Type?
Tuple: ( (Type ,)* )
Expr: Call | Binop | Unary | TupleExpr | RecordExpr | Lambda | Index | IfElse | For | While | Block | Lit | Update | Paren
ExprPath: Ident (. Ident)*
ExprParened: ExprPath | Block | Lit | Paren
Call: ExprPath ExprParened*
Index: ExprParened [ Expr ]
Binop, Unary, use pratt parsing with corresponding operator precedence
Block: { ExprStmt* }
IfElse: if Expr then Expr (else Expr)?
For: for Ident in Expr Block
While: while Expr Block
Lambda: \ Ident* = Expr
TupleExpr: ( (Expr ,)* )
RecordExpr: { (Ident : Expr ,)* }
Update: ExprPath := Expr
Paren: ( Expr )
ExprStmt: Expr | Item
Lit: IntLit | FlaotLit | StringLit | true | false (define bool as an enum?)
Ident: refer to unicode-xid