(*
-- Grammar for Roost v2 --
Author: RubixDev
*)
Program = Statements ;
(* The end of <Statements> is indicated by a following `Eof` or `RBrace` token *)
Statements = [ Statement , { EOL , Statement } , [ EOL ] ] ;
Block = BlockExpr | Statement ;
(**************************)
(******* STATEMENTS *******)
(**************************)
Statement = VarStmt
| FunctionDecl
| ClassDecl
| BreakStmt
| ContinueStmt
| ReturnStmt
| Expression ;
VarStmt = 'var' , identifier , [ '=' , Expression ] ;
FunctionDecl = 'fun' , identifier , Params , Block ;
ClassDecl = 'class' , identifier , MemberBlock ;
BreakStmt = 'break' , [ Expression ] ;
ContinueStmt = 'continue' ;
ReturnStmt = 'return' , [ Expression ] ;
(*****************************)
(******* CLASS MEMBERS *******)
(*****************************)
Member = [ 'static' ] , ( FunctionDecl | VarStmt ) ;
MemberBlock = '{' , { Member , EOL } , '}' ;
(***************************)
(******* EXPRESSIONS *******)
(***************************)
Expression = RangeExpr ;
RangeExpr = OrExpr
| OrExpr , ( '..' | '..=' ) , OrExpr
| OrExpr , '..'
| ( '..' | '..=' ) , OrExpr
| '..' ;
OrExpr = AndExpr , { '||' , AndExpr } ;
AndExpr = BitOrExpr , { '&&' , BitOrExpr } ;
BitOrExpr = BitXorExpr , { '|' , BitXorExpr } ;
BitXorExpr = BitAndExpr , { '^' , BitAndExpr } ;
BitAndExpr = EqExpr , { '&' , EqExpr } ;
EqExpr = RelExpr , [ ( '==' | '!=' ) , RelExpr ] ;
RelExpr = ShiftExpr , [ ( '<' | '>' | '<=' | '>=' ) , ShiftExpr ] ;
ShiftExpr = AddExpr , { ( '<<' | '>>' ) , AddExpr } ;
AddExpr = MulExpr , { ( '+' | '-' ) , MulExpr } ;
MulExpr = UnaryExpr , { ( '*' | '/' | '%' | '\' ) , UnaryExpr } ;
UnaryExpr = ( '+' | '-' | '!' ) , UnaryExpr
| ExpExpr ;
ExpExpr = AssignExpr , [ '**' , UnaryExpr ] ;
AssignExpr = CallExpr , [ ASSIGN_OPERATOR , Expression ] ;
ASSING_OPERATOR = '=' | '*=' | '/=' | '\=' | '%=' | '+=' | '-='
| '<<=' | '>>=' | '&=' | '^=' | '|=' | '**=' ;
CallExpr = MemberExpr , [ Args , { CallPart } ] ;
MemberExpr = Atom , { MemberPart } ;
Atom = number
| bool
| string
| 'null'
| identifier
| '(' , Expression , ')'
| ListLiteral
| IfExpr
| ForExpr
| WhileExpr
| LoopExpr
| FunExpr
| ClassExpr
| TryExpr
| BlockExpr ;
ListLiteral = '[' , [ Expression , { ',' , Expression } , [ ',' ] ] , ']' ;
IfExpr = 'if' , '(' , Expression , ')' , Block , [ 'else' , Block ] ;
ForExpr = 'for' , '(' , identifier , 'in' , Expression , ')' , Block ;
WhileExpr = 'while' , '(' , Expression , ')' , Block ;
LoopExpr = 'loop' , Block ;
FunExpr = 'fun' , Params , Block ;
ClassExpr = 'class' , MemberBlock ;
TryExpr = 'try' , Block , 'catch' , '(' , identifier , ')' , Block ;
BlockExpr = '{' , Statements , '}' ;
(*********************)
(******* OTHER *******)
(*********************)
MemberPart = '.' , identifier
| '[' , Expression , ']' ;
CallPart = MemberPart | Args ;
Args = '(' , [ Expression , { ',' , Expression } , [ ',' ] ] , ')' ;
Params = '(' , [ identifier , { ',' , identifier } , [ ',' ] ] , ')' ;
(**********************************)
(******* NONTERMINAL TOKENS *******)
(**********************************)
number = DIGIT , { DIGIT | '_' } , [ '.' , DIGIT , { DIGIT | '_' } ]
| '.' , DIGIT , { DIGIT , | '_' } ;
string = '"' , { CHAR - ( '"' | '\' ) | escape_seq } , '"'
| "'" , { CHAR - ( "'" | '\' ) | escape_seq } , "'" ;
escape_seq = '\' , ( ESCAPE_CHAR
| 3 * OCTAL
| 'x' , 2 * HEX
| 'u' , 4 * HEX
| 'U' , 8 * HEX ) ;
bool = 'true' | 'false' ;
identifier = ( LETTER , { LETTER | DIGIT } ) - ( bool | 'null' | ? any keyword ? ) ;
(************************************)
(******* TERMINAL SYMBOL SETS *******)
(************************************)
LETTER = 'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J'
| 'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T'
| 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z'
| 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j'
| 'k' | 'l' | 'm' | 'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't'
| 'u' | 'v' | 'w' | 'x' | 'y' | 'z'
| '_' ;
OCTAL = '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' ;
DIGIT = OCTAL | '8' | '9' ;
HEX = DIGIT
| 'A' | 'B' | 'C' | 'D' | 'E' | 'F'
| 'a' | 'b' | 'c' | 'd' | 'e' | 'f' ;
CHAR = ? any character included in the Unicode character set ? ;
ESCAPE_CHAR = '\' | "'" | '"' | 'a' | 'b' | 'f' | 'n' | 'r' | 't' | 'v' ;
(*
<EOL>: End Of Line
Note: Line break characters (LF) are treated like spaces throughout the
parsing process but, unlike the other space characters (' ', '\t', and '\r'),
are accepted in place of semicolons.
*)
EOL = ';' | ? line feed ? ;