grammar Delorean rule line f:formula sp? ('#' .*)? end rule formula sp4 i:identifier sp? '=?' sp? e:expression / sp4 i:identifier sp? '=?' / sp4 i:identifier sp? '=' sp? e:expression / n:class_name ':' sp? mod:(m:class_name_import_nested) # FIXME: requires to be above SubNode statement, otherwise doesn't work / n:class_name ':' sp? mod:(m:class_name '::')? p:class_name / n:class_name ':' / 'import' sp n:class_name_import end rule class_name [A-Z] [a-zA-Z0-9_]* end rule class_name_import [A-Z] [a-zA-Z0-9_]* ('::' [A-Z] [a-zA-Z0-9_]*)* end # FIXME: Hacky way to skip Module::Node cases, so only Module::NestedModule::Node will pass rule class_name_import_nested [A-Z] [a-zA-Z0-9_]* (('::' [A-Z] [a-zA-Z0-9_]*) 2..) end rule elsif 'elsif' sp? v:expression sp? 'then' sp? e1:expression sp? end rule expression 'ERR(' sp? args:fn_args? sp? ')' / op:unary_op sp? e:expression / 'if' sp? v:expression sp? 'then' sp? e1:expression sp? 'else' sp? e2:expression / 'if' sp? v:expression sp? 'then' sp? e1:expression sp? sp? elsifs:elsif+ sp? 'else' sp? e2:expression / v:getattr_exp sp? op:binary_op sp? e:expression / getattr_exp end rule block_args sp4 sp4 sp? i:identifier sp? '=?' sp1? e:expression / sp4 sp4 sp? i:identifier sp? '=?' end rule block_formulas sp4 sp4 sp? i:identifier sp? '=' sp? e:expression end rule getattr_exp v:value dotted:dotted / value end rule dotted d:dot_exp d_rest:dotted? end rule dot_exp '[' sp? args:fn_args sp? ']' / '(' sp? al:kw_args? sp? ')' / '.' sp? i:identifier '(' sp? al:fn_args? sp? ')' b_args:block_args* expressions:block_formulas+ / '.' sp? i:identifier '(' sp? al:fn_args? sp? ')' / '&.' sp? i:identifier '(' sp? al:fn_args? sp? ')' / '.' sp? i:identifier b_args:block_args* expressions:block_formulas+ / '.' sp? i:(identifier / integer) / '&.' sp? i:(identifier / integer) end rule unpack_args arg0:identifier args_rest:(sp? ',' sp? args:unpack_args?)? end rule list_expr '[]' / '[' sp? e2:expression sp 'for' sp args:unpack_args sp 'in' sp e1:expression sp? ifexp:('if' sp e3:expression sp?)? ']' / '[' sp? args:fn_args sp? ']' end rule set_expr '{-}' / '{' sp? e2:expression sp 'for' sp args:unpack_args sp 'in' sp e1:expression sp? ifexp:('if' sp e3:expression sp?)? '}' / '{' sp? args:fn_args sp? '}' end rule hash_expr '{}' / '{' sp? el:expression sp? ':' sp? er:expression sp 'for' sp args:unpack_args sp 'in' sp e1:expression sp? ifexp:('if' sp ei:expression sp?)? '}' / '{' sp? args:hash_args sp? '}' end # NOTE: some operations such as << have side-effects (e.g. on # Arrays). So, be cautious about which opertaions are added. rule binary_op '==' / '!=' / '>=' / '<=' / '&&' / '||' / '**' / '>' / '<' / '+' / '-' / '*' / '/' / '%' / '&' / '^' / '|' / 'in' sp end rule unary_op '!' / '-' end rule value decimal / integer / string / boolean / nil_val / sup / identifier / self / list_expr / set_expr / hash_expr / c:class_name_import / # FIXME: requires to be above NodeAsValue statement, otherwise doesn't work mod:(m:class_name '::')? c:class_name / '(' sp? e:expression sp? ')' end rule fn_args arg0:expression args_rest:(sp? ',' sp? args:fn_args?)? end rule hash_args splat:('**') e0:expression sp? ifexp:('if' sp e3:expression sp?)? args_rest:(sp? ',' sp? al:hash_args?)? / e0:expression sp? ':' sp? e1:expression sp? ifexp:('if' sp e3:expression sp?)? args_rest:(sp? ',' sp? al:hash_args?)? end rule kw_args splat:('**') arg0:expression sp? ifexp:('if' sp e3:expression sp?)? args_rest:(sp? ',' sp? al:kw_args?)? / k:(i:identifier sp? '=' sp?)? arg0:expression sp? ifexp:('if' sp e3:expression sp?)? args_rest:(sp? ',' sp? al:kw_args?)? end # rule block_args # '|' sp? args:unpack_args sp? '|' # end rule decimal i:integer '.' [0-9]+ end rule integer '0' / [1-9] [0-9]* end rule identifier [a-z] [a-zA-Z0-9_]* '?'? / [_] [a-zA-Z0-9_]+ '?'? end rule boolean 'true' / 'false' end rule sup '_sup' end rule self '_' end rule nil_val 'nil' end # and you thought python was anal about spaces? rule sp4 ' ' end rule sp1 ' ' end rule sp [\s]+ end rule string '"' ('\"' / !'"' .)* '"' / "'" [^']* "'" end end