拡張BNFで表したXtalの文法

yacc等のツールを使用していないため、BNFは頭の中にしか書かれていなかったのですが、この度書き出してみました。
これは正確なものではなく、あくまで大体こんな感じ、という位のモノです。
抜けもあるかもしれません。

binint ::= '0' 'b' [01_]+

hexint ::= '0' 'x' [0-9a-fA-F_]+

int ::= [0-9][0-9_]*
      | binint
      | hexint
      
float ::= [0-9][0-9_]* '.' [0-9][0-9_]* ([eE] ('+' | '-')? [0-9]+)?

ident_first ::= [a-zA-Z_]

ident_rest ::= ident_first | [0-9]

ident ::= ident_first ident_rest*

string ::= '"' [^"]* '"'

///////////////////////////////////////////

bin_expr ::= expr '+' expr
           | expr '-' expr
           | expr '*' expr
           | expr '/' expr
           | expr '%' expr
           | expr '|' expr
           | expr '&' expr
           | expr '^' expr
           | expr '<<' expr
           | expr '>>' expr
           | expr '>>>' expr
           | expr '==' expr
           | expr '!=' expr
           | expr '===' expr
           | expr '!==' expr
           | expr 'is' expr
           | expr '!is' expr
           | expr '<' expr
           | expr '>' expr
           | expr '<=' expr
           | expr '>=' expr
      
una_expr ::= '+' expr
           | '-' epxr
           | '^' expr
           | '!' expr
           | 'once' expr

expr ::= bin_expr
       | una_expr
       | int
       | float
       | array
       | map
       | class
       | fun
       | method
       | fiber
       | dofun
       | module
       | at
       | send
       | member
       | send_if_defined
       | call
       | 'true'
       | 'false'
       | 'null'
       | 'nop'
       | local
       | instance_var
       | arguments
       | string

block ::= '{' stmts '}'

class ::= 'class' ('extends' expr)? ('mixins' exprs)? class_block

module ::= 'module' ('mixins' exprs)? class_block

array ::= '[' exprs ']'

map ::= '[' (expr ':' expr)+ ']' | '[' ':' ']'

class_block ::= '{' (('@' ident (':' expr) ';') | (var_define ';'))* '}'

fun_block ::= ('(' params ')')? (block | expr)

fun ::= fun_block

method ::= fun_block

fiber ::= fun_block

dofun ::= fun_block

stmt_nosemi ::= 'return' exprs
              | 'yield' exprs
              | 'assert' exprs
              | assign
              | var_define
              | export
              | expr
              | member ':' expr

assign ::= '++' assign_target
         | '--' assign_target
         | assign_target '++'
         | assign_target '--'
         | assign_target '=' expr
         | assign_target '+=' expr
         | assign_target '-=' expr
         | assign_target '*=' expr
         | assign_target '/=' expr
         | assign_target '%=' expr
         | assign_target '|=' expr
         | assign_target '&=' expr
         | assign_target '^=' expr
         | assign_target '<<=' expr
         | assign_target '>>=' expr
         | assign_target '>>>=' expr
         
assign_target ::= local 
                | at 
                | send 
                | send_if_defined

at ::= expr '[' expr ']'

send ::= expr '.' ident ('(' args ')')? 

send_if_defined ::= expr '.?' ident ('(' args ')')? 

call ::= expr '(' args ')'

member ::= expr '::' ident

local ::= ident

instance_var ::= '@' ident

loop ::= for | while | foreach

loop_with_label ::= ident ':' loop

foreach ::= expr '{' block_param? stmts '}' ('else' stmt)?

for ::= 'for' '(' init_cond ';' expr ';' stmt_nosemi ')' stmt ('else' stmt)?

while ::= 'while' '(' init_cond ')' stmt ('else' stmt)?

brock_param ::= '|' (ident ',')* ident? '|'

arg ::= expr | ident ':' expr

args ::= (arg ',')* arg?

param ::= ident (':' expr)?

params ::= (param ',')* ('...' | param)?

arguments ::= '...'

exprs ::= (expr ',')* expr?

stmts ::= stmt*

stmt ::= if
       | loop
       | loop_with_label
       | stmt_nosemi ';'

if ::= 'if' '(' init_cond ')' stmt

init_cond ::= var_define | expr

var_define ::= ident ':' expr

export ::= 'export' var_define | expr