(* Dodo grammar *)
line_terminator ::= "\r\n" | "\n";
input_character ::= ~line_terminator sigma;
spacing ::= space*;
space ::= white_space | comment;
mls ::= multiline_space*;
multiline_space ::= space | line_terminator | end_of_line_comment;
white_space ::= [ \t\012]+ ;
comment ::= xml_comment;
xml_comment ::= "" sigma)* "-->";
end_of_line_comment ::= '#' (~ line_terminator sigma)* line_terminator;
separator ::= line_terminator | ';' | end_of_line_comment;
is_caps ::= [A-Z];
is_nocaps ::= [a-z];
is_alpha ::= [a-zA-Z];
is_alpha_num ::= [a-zA-Z0-9];
dodo_caps_letter ::= is_caps;
dodo_nocaps_letter ::= is_nocaps;
dodo_letter_or_digit ::= is_alpha_num | '_';
word_strict ::= cword_strict | nword_strict ;
cword_strict ::= dodo_caps_letter dodo_letter_or_digit* ;
nword_strict ::= dodo_nocaps_letter dodo_letter_or_digit* ;
word ::= '$'? word_strict "'"* | "$_" ;
cword ::= '$'? cword_strict "'"* | "$_" ;
nword ::= '$'? nword_strict "'"* | "$_" ;
xml_docspec ::= "";
xmltag ::= '<' name:word_strict xmltag_attr* mls '>';
xmltag_attr ::= mls name:word_strict spacing '=' spacing string_literal ;
xmltag_close ::= "" name:word_strict ( ~'>' sigma)* '>' ;
xmltag_no_body ::= '<' name:word_strict xmltag_attr* mls "/>";
xmltag_wrap ::= '<' name:"wrap" xmltag_attr* mls '>';
(* keyword ::= keywords &word;*)
keywords ::=
"test"
| "loop"
| "def"
| "default"
| "dispatch"
| "else"
| "filter"
| "fold"
| "for"
| "fun"
| "if"
| "is"
| "map"
| "match"
| "new"
| "parent"
| "return"
| "resume"
| "seed"
| "self"
| "throw"
| "try"
| "yield"
| "AND"
| "NOT"
| "OR"
| "UNDO"
| "XOR"
;
symchars ::=
"->"
| "==>"
| "+="
| "-="
| "*="
| "%="
| "++"
| "--"
| "&&"
| "||"
| "<="
| ">="
| "!=" (*::=*)
| ";"
| ":"
| ","
| "."
| "{"
| "}"
| "("
| ")"
| "["
| "]"
| "]0"
| "!"
| "~"
| "+"
| "-"
| "*"
| "|"
| "%"
| "<"
| ">"
| "="
| "?"
;
assign_op ::=
'='
| "+="
| "-="
| "*="
| "%="
;
operator ::=
"++"
| "--"
| "&&"
| "||"
| "<="
| ">="
| "!="
| "!"
| "~"
| "+"
| "-"
| "*"
| "/"
| "%"
| "<"
| ">"
| "="
;
integer_literal ::= numeral spacing ;
numeral ::= hex_numeral
| octal_numeral
| decimal_numeral
;
hex_numeral ::= code:hex_code value:hex_digit+;
hex_code ::= '0' [xX] ;
hex_digit ::= [0-9a-fA-F];
octal_numeral ::= code:'0' value:octal_digit+;
octal_digit ::= [0-7];
decimal_numeral ::= value:[0-9]+;
floating_point_literal ::=
m:digit+ '.' (f:fraction_part)? (exponent_part)? (t:float_type_suffix)? spacing
| '.' f:fraction_part (exponent_part)? (t:float_type_suffix)? spacing
| m:digit+ exponent_part (t:float_type_suffix)? spacing
| m:digit+ (exponent_part)? t:float_type_suffix spacing
;
fraction_part ::= digit+;
exponent_part ::= [eE]e:([+\-]? digit+);
float_type_suffix ::= [fF];
digit ::= [0-9];
boolean_literal ::= "true" | "false";
character_literal ::=
"'" value:single_character "'" spacing
| value:escape_sequence spacing
;
single_character ::= ~"'" input_character;
string_literal ::= '"' value:string_character* '"' spacing ;
string_character ::= ~'"' ~'\\' sigma | escape_sequence;
escape_sequence ::= octal_escape | unicode_escape | '\\' [0bfnrtv\\"']; (* " *)
unicode_escape ::= '\\' 'u' [0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F];
octal_escape ::= '\\' [0-3]?[0-7]?[0-7];
null_literal ::= "null";
spacy_literal ::= floating_point_literal | integer_literal | character_literal | string_literal ;
regexp ::= '/' ( '\\' sigma | ~'/' sigma ) '/' | regexp_list | regexp_vartype | spacy_literal ;
regexp_list ::= '[' regexps? ']'
;
regexps ::= regexp ( ',' mls regexp )* ;
regexp_vartype ::= regexp_var ( '/' regexp_type )? ;
regexp_qualifier ::= '?' | '*' | '+' ;
prefix ::=
( op:"map" | op:"fold" | op:"seed" | op:"filter" | op:"match" | op:"return" | op:"throw" | op:"yield" ) white_space
|
;
prefix_new ::= "new" white_space ;
prefix_for ::= "for" white_space ;
prefix_in ::= "in" multiline_space ;
prefix_is ::= "is" multiline_space ;
prefix_resume ::= "resume" white_space ;
prefix_test ::= "test" white_space ;
prefix_loop ::= "loop" white_space ;
prefix_undo ::= "UNDO" white_space ;
identifier ::= name:word;
compound_ident ::= ( compound_ident_path '.' ~multiline_space )* identifier;
compound_ident_path ::= identifier ( list_index | call_arguments )? ;
class_ident ::= name:cword;
compound_class_ident ::= ( compound_ident_path '.' ~multiline_space )* class_ident;
var_ident ::= name:nword;
compound_var_ident ::= ( compound_ident_path '.' ~multiline_space )* var_ident ;
compound_operator ::= ( compound_ident_path '.' ~multiline_space )+ name:operator ;
reference ::= '.' ~multiline_space compound_var_ident ;
signal_ident ::= name:nword '!' ( compound_ident_path '.' ~multiline_space )+ class_ident ;
label ::= ;
outfixing spacing do
appending spacing do
regexp_var ::= name:compound_var_ident ( '(' ( regexp_bindings | regexps )? ')' )? regexp_qualifier? ;
regexp_binding ::= identifier regexp ;
regexp_bindings ::= regexp_binding ( ',' regexp_binding )* ;
regexp_type ::= name:compound_ident ( '(' regexp_bindings? ')' )? ;
type_spec ::= type_fun | type_yield | type_dispatch | compound_ident ( type_suffix )* | "def" | '?' ;
type_suffix ::= type_map_suffix | type_list_suffix;
type_map_suffix ::= '[' prefix_for type_spec mls ']';
type_list_suffix ::= '[' ( mls type_list_sizes mls )? ']' ;
type_list_sizes ::= type_list_size ( ',' mls type_list_size )* ;
type_list_size ::= integer_literal ;
type_fun ::= name:"fun" '(' mls type_list? mls "->" mls type_continuations mls ')' ;
type_yield ::= name:"yield" '(' mls type_list? mls ')' ;
type_dispatch ::= name:"dispatch" compound_ident ;
type_continuations ::= type_continuation ( ',' mls type_continuation )* ;
type_continuation ::= type_spec | '(' mls type_list? mls ')' ;
type_list ::= type_spec ( ',' mls type_spec )* ;
type_name ::= compound_ident ;
class_name ::= compound_class_ident ;
ident_name ::= compound_ident ;
var_name ::= compound_var_ident | compound_operator | reference ;
simple_class_name ::= class_ident ;
simple_var_name ::= var_ident ;
literal ::=
boolean_literal
| null_literal
| spacy_literal (* ~[a-zA-Z0-9_'] '*)
| list_literal
| map_literal
;
list_literal ::= '[' mls expression_list? mls ']'
;
map_literal ::= ;
proto_based ::= prefix_new type_name ( mls proto_attributes )? class_qualifiers? class_body? ;
proto_attribute ::= compound_ident expression ;
proto_attributes ::= '(' mls proto_bindings mls ')' ;
proto_bindings ::= proto_attribute ( ',' mls proto_attribute )* ;
class_qualifiers ::= prefix_is mls class_name ( ',' mls class_name )* ;
class_body ::=
mls '{' mls declarations mls '}' | ':' mls declarations mls '.' ;
class_decl ::=
var_name class_name
( (* prototype-based *) var_init | class_qualifiers? class_body )?
;
declaration ::=
class_decl
| conversion_decl
| constructor_spec | constructor_decl
| type_spec ( fun_specification | fun_declaration | var_declarations )
;
declaration_xml ::=
xmltag_no_body mls
| xmltag_wrap mls ( test_match mls )* xmltag_close mls
| xmltag mls declarations mls xmltag_close mls
;
declarations ::= declaration_xml* declaration? ( separator mls declaration_xml* declaration? )* ;
var_declaration ::= compound_var_ident var_init? ;
var_init ::= '=' mls expression ;
var_declarations ::= var_declaration ( ',' var_declaration )* ;
fun_declaration ::=
compound_var_ident
parameters
( var_init | fun_body )?
;
fun_specification ::= compound_var_ident '(' mls param_specs mls ')' ;
constructor_decl ::=
class_ident
parameters
fun_body?
;
constructor_spec ::= class_ident '(' mls param_specs mls ')' ;
conversion_decl ::= "->" '(' mls type_list ')' ( var_init | fun_body )? ;
fun_body ::= ':' mls instructions mls '.' | mls '{' mls instructions mls '}' ;
instruction ::= undo_instr ( mls "==>" instruction )? ;
undo_instr ::= prefix_undo single_instr | single_instr ;
single_instr ::=
test_instr
| loop_instr
| "try" fun_body
| "transaction" fun_body
| prefix_resume label expression?
| declaration
| assign_instr
| expressions
| label
;
instruction_xml ::=
xmltag_no_body mls
| xmltag mls instructions mls xmltag_close mls
;
instructions ::= instruction_xml* instruction? ( separator mls instruction_xml* instruction? )* ;
assign_instr ::= reference op:assign_op expression ;
loop_instr ::= "loop" fun_body | prefix_loop loop_header fun_body ;
loop_header ::=
"while" mls expression
| "until" mls expression
| "foreach" mls foreach_in | "foreach" mls '(' mls foreach_ins mls ')'
| "for" '(' mls ( for_init separator | ';' ) mls ( for_cond ';'? | ( for_cond separator | ';' ) mls for_step ) mls ')'
;
test_instr ::= "test" test_body | prefix_test expression fun_body | prefix_test match_header match_body ;
test_body ::= ':' mls ( test_select mls )* '.' | mls '{' mls ( test_select mls )* '}' ;
test_select ::= expression_list fun_body ;
match_header ::= expression | '(' mls expression_list mls ')' ;
match_body ::= ':' mls ( test_match mls )* '.' | mls '{' mls ( test_match mls )* '}' ;
test_match ::= regexp ( ',' mls regexp )* fun_body ;
for_cond ::= unfold_cond ;
for_init ::= expressions ;
for_step ::= expressions ;
foreach_in ::= simple_var_name prefix_in mls expression ;
foreach_ins ::= foreach_in ( ',' mls foreach_in )* ;
param_specs ::= param_spec ( ',' param_spec )* ;
param_spec ::= type_spec regexp_qualifier? ;
parameters ::= '(' mls param_list? mls ')' ;
param_list ::=
type_spec var_declarations
( separator mls type_spec var_declarations )*
;
continuations ::= mls "->" continuation_body ( mls '|' continuation_body )* ;
continuation_body ::=
( label? idents_continuation mls expressions )?
;
idents_continuation ::= simple_var_name separator | '(' mls bindings? mls ')' ;
bindings ::= binding ( ',' mls binding )* ;
binding ::= simple_var_name | literal ;
expression ::= exp_comp continuations | exp_comp ;
exp_comp ::=
prefix exp_comp
| prefix_resume label
| exp_base
;
exp_base ::= proto_based | exp_atom exp_bool+ | exp_atom exp_compar exp_bool* | exp_atom ;
exp_bool ::=
op:"&&" mls exp_atom exp_compar?
| op:"||" mls exp_atom exp_compar?
| exp_term
;
(* support for chained comparisons eg. a = b = c or a < b <= c *)
exp_compar_eq ::= op:'=' mls ( exp_compar_with exp_compar_eq | exp_compar_with ) ;
exp_compar_lt ::=
op:'<' mls ( exp_compar_with exp_compar_lt | exp_compar_with )
| op:"<=" mls ( exp_compar_with exp_compar_lt | exp_compar_with )
;
exp_compar_gt ::=
op:'>' mls ( exp_compar_with exp_compar_gt | exp_compar_with )
| op:">=" mls ( exp_compar_with exp_compar_gt | exp_compar_with )
;
exp_compar ::=
exp_compar_eq
| exp_compar_lt
| exp_compar_gt
| op:"!=" mls exp_compar_with
| op:'~' mls regexp
;
exp_compar_with ::= exp_atom exp_term+ | exp_atom;
exp_term ::=
op:'+' mls exp_atom exp_factor*
| op:'-' mls exp_atom exp_factor*
| exp_factor
;
exp_factor ::=
op:'*' mls exp_atom
| op:'/' mls exp_atom
;
exp_atom ::=
literal
| if_else
| lambda
| unfold
| exp_unary
| label exp_atom
| exp_var_atom
;
exp_unary ::=
op:"++" exp_var_atom
| op:"--" exp_var_atom
| op:'-' exp_var_atom
|
op:"!" exp_var_atom
;
exp_var_atom ::=
'(' mls expressions mls ')'
| signal_ident call_arguments
| class_name call_arguments
| var_name ( list_index | call_arguments )?
;
list_index ::= '[' mls ( integer_literal '+' | expression_list ) mls ']' ;
call_arguments ::= '(' mls expression_list? mls ')' ;
expressions ::= expression ( ',' mls expressions ) | expression ;
expression_list ::= expression ( ',' mls expression )* ;
if_else ::=
"if" mls '(' mls expression mls ')' mls
expressions mls
"else" mls expressions
;
lambda ::=
"fun" ':' mls lambda_param separator mls expressions mls '.'
| "fun" mls '{' mls lambda_param separator mls expressions mls '}'
;
lambda_param ::= param_list? mls "->" mls lambda_cont ( ',' mls lambda_cont )* ;
lambda_cont ::= simple_var_name type_continuation ( '=' simple_var_name )? ;
unfold ::=
"unfold" ':' mls unfold_parts mls '.'
| "unfold" mls '{' mls unfold_parts mls '}'
;
unfold_parts ::= ( unfold_inits separator | ';' ) mls ( unfold_cond separator | ';' ) mls unfold_steps? ;
unfold_inits ::= unfold_init ( ',' mls unfold_init )* ;
unfold_init ::= var_ident '=' mls expression ;
unfold_cond ::= expressions ;
unfold_steps ::= unfold_step ( ',' mls unfold_step )* ;
unfold_step ::= expressions ( prefix_in mls expression )? ;
done;
done;
start ::= ( xml_docspec )? mls declarations mls EOF ;