ROOT ::= INSTR* INSTR ::= | LEXPR semicolon | BEXPR EXPR ::= LEXPR | BEXPR LEXPR ::= | OR | ASSERT EXPR | VARDECL | CONSTDECL | FUNDECL | ASSIGN | break | continue | return EXPR? | FUN BEXPR ::= | BLOCK | IF | WHILE IF ::= | if EXPR BLOCK | if EXPR BLOCK else BLOCK | if EXPR BLOCK else IF WHILE ::= while EXPR BLOCK FUN ::= fun PARAMS (rarrow TYPE) BLOCK PARAMS ::= | opar ident colon TYPE (comma ident colon type)* cpar BLOCK ::= obrace INSTR* cbrace VARDECL ::= var ident colon TYPE? assign EXPR CONSTDECL ::= ident colon TYPE? assign EXPR FUNDECL ::= fun ident PARAMS (rarrow TYPE) BLOCK ASSIGN ::= ident assign EXPR OR ::= AND (or AND)* AND ::= EQNE (and EQNE)* EQNE ::= CMP ((eq|ne) CMP)? CMP ::= TERM ((lt|le|gt|ge) TERM)? TERM ::= FACTOR ((add|sub) FACTOR)* FACTOR ::= POW ((mul|div|mod) POW)* POW ::= NOT (pow NOT)? NOT ::= not* CALL CALL ::= LITERAL ARGS* ARGS ::= opar (EXPR (comma EXPR)*)? cpar LITERAL ::= | ident | BUILTIN | opar EXPR cpar CALL ::= LITERAL ARGS* ARGS ::= opar (EXPR (comma EXPR)*)? cpar BUILTIN ::= bool | int | float | string TYPE ::= | type | opar TYPE+ rarrow TYPE+ cpar