(* 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 ::= "' 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 ::= '[' mls proto_bindings? mls ']' ; 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 ;