rattler 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +3 -175
- data/features/README.markdown +27 -0
- data/features/Tutorial.md +224 -0
- data/features/command_line/output_option.feature +2 -1
- data/features/command_line/{parser_generator.feature → rtlr.feature} +43 -15
- data/features/error_reporting/automatic_error_messages.feature +40 -0
- data/features/error_reporting/custom_error_messages.feature +28 -0
- data/features/examples/json_parser.markdown +88 -0
- data/features/{grammar → extended_matching_syntax}/back_reference.feature +5 -3
- data/features/{grammar → extended_matching_syntax}/e_symbol.feature +2 -2
- data/features/{grammar → extended_matching_syntax}/eof.feature +4 -3
- data/features/{grammar → extended_matching_syntax}/fail.feature +8 -6
- data/features/extended_matching_syntax/fragments.feature +29 -0
- data/features/extended_matching_syntax/include.feature +42 -0
- data/features/{grammar → extended_matching_syntax}/list_matching.feature +7 -6
- data/features/extended_matching_syntax/posix_class.feature +127 -0
- data/features/{grammar → extended_matching_syntax}/repeat.feature +29 -3
- data/features/{grammar → extended_matching_syntax}/skip_operator.feature +2 -1
- data/features/extended_matching_syntax/super.feature +24 -0
- data/features/{grammar → extended_matching_syntax}/token.feature +6 -5
- data/features/{grammar → extended_matching_syntax}/whitespace.feature +7 -6
- data/features/{grammar → extended_matching_syntax}/word_literal.feature +10 -6
- data/features/grammar_heading/explicit_start_rule.feature +20 -0
- data/features/grammar_heading/grammar_declaration.feature +60 -0
- data/features/grammar_heading/include.feature +19 -0
- data/features/grammar_heading/require.feature +27 -0
- data/features/{grammar → peg_syntax}/any_character.feature +1 -1
- data/features/peg_syntax/character_class.feature +25 -0
- data/features/{grammar → peg_syntax}/comments.feature +1 -1
- data/features/{grammar → peg_syntax}/literal.feature +5 -3
- data/features/{grammar → peg_syntax}/negative_lookahead.feature +5 -3
- data/features/peg_syntax/nonterminal.feature +46 -0
- data/features/peg_syntax/one_or_more.feature +59 -0
- data/features/{grammar → peg_syntax}/optional.feature +2 -2
- data/features/peg_syntax/ordered_choice.feature +24 -0
- data/features/{grammar → peg_syntax}/positive_lookahead.feature +6 -4
- data/features/peg_syntax/sequence.feature +23 -0
- data/features/{grammar → peg_syntax}/start_rule.feature +1 -1
- data/features/peg_syntax/zero_or_more.feature +59 -0
- data/features/{grammar → semantics}/labels.feature +0 -0
- data/features/{grammar → semantics}/negative_semantic_predicate.feature +30 -9
- data/features/{grammar → semantics}/node_action.feature +0 -0
- data/features/{grammar → semantics}/positive_semantic_predicate.feature +29 -8
- data/features/{grammar/symantic_action.feature → semantics/semantic_action.feature} +2 -2
- data/features/semantics/semantic_result.feature +86 -0
- data/features/{grammar → semantics}/side_effect.feature +33 -21
- data/features/step_definitions/cli_steps.rb +1 -1
- data/features/step_definitions/grammar_steps.rb +19 -5
- data/features/support/env.rb +5 -0
- data/lib/rattler.rb +21 -44
- data/lib/rattler/compiler.rb +69 -0
- data/lib/rattler/{grammar → compiler}/grammar_parser.rb +58 -24
- data/lib/rattler/compiler/metagrammar.rb +1570 -0
- data/lib/rattler/compiler/optimizer.rb +77 -0
- data/lib/rattler/{back_end → compiler}/optimizer/composite_reducing.rb +2 -2
- data/lib/rattler/{back_end → compiler}/optimizer/flatten_choice.rb +3 -12
- data/lib/rattler/{back_end → compiler}/optimizer/flatten_sequence.rb +4 -16
- data/lib/rattler/{back_end → compiler}/optimizer/flattening.rb +2 -2
- data/lib/rattler/compiler/optimizer/inline_regular_rules.rb +24 -0
- data/lib/rattler/{back_end → compiler}/optimizer/join_match_capturing_sequence.rb +16 -14
- data/lib/rattler/{back_end → compiler}/optimizer/join_match_choice.rb +4 -13
- data/lib/rattler/{back_end → compiler}/optimizer/join_match_matching_sequence.rb +4 -13
- data/lib/rattler/compiler/optimizer/join_match_sequence.rb +7 -0
- data/lib/rattler/{back_end → compiler}/optimizer/join_predicate_bare_match.rb +3 -12
- data/lib/rattler/compiler/optimizer/join_predicate_match.rb +7 -0
- data/lib/rattler/{back_end → compiler}/optimizer/join_predicate_nested_match.rb +4 -13
- data/lib/rattler/{back_end → compiler}/optimizer/join_predicate_or_bare_match.rb +3 -12
- data/lib/rattler/compiler/optimizer/join_predicate_or_match.rb +7 -0
- data/lib/rattler/{back_end → compiler}/optimizer/join_predicate_or_nested_match.rb +4 -13
- data/lib/rattler/{back_end → compiler}/optimizer/match_joining.rb +2 -2
- data/lib/rattler/{back_end → compiler}/optimizer/optimization.rb +12 -34
- data/lib/rattler/compiler/optimizer/optimization_context.rb +83 -0
- data/lib/rattler/{back_end → compiler}/optimizer/optimization_sequence.rb +3 -11
- data/lib/rattler/compiler/optimizer/optimizations.rb +27 -0
- data/lib/rattler/{back_end → compiler}/optimizer/optimize_children.rb +6 -14
- data/lib/rattler/{back_end → compiler}/optimizer/reduce_repeat_match.rb +4 -13
- data/lib/rattler/compiler/optimizer/remove_meaningless_wrapper.rb +22 -0
- data/lib/rattler/{back_end → compiler}/optimizer/simplify_redundant_repeat.rb +4 -13
- data/lib/rattler/{back_end → compiler}/optimizer/simplify_token_match.rb +4 -13
- data/lib/rattler/compiler/parser_generator.rb +108 -0
- data/lib/rattler/{back_end → compiler}/parser_generator/apply_generator.rb +7 -21
- data/lib/rattler/{back_end → compiler}/parser_generator/assert_generator.rb +11 -19
- data/lib/rattler/compiler/parser_generator/attributed_sequence_generator.rb +37 -0
- data/lib/rattler/{back_end → compiler}/parser_generator/back_reference_generator.rb +10 -10
- data/lib/rattler/{back_end → compiler}/parser_generator/choice_generator.rb +10 -22
- data/lib/rattler/{back_end → compiler}/parser_generator/delegating_generator.rb +2 -2
- data/lib/rattler/{back_end → compiler}/parser_generator/disallow_generator.rb +11 -19
- data/lib/rattler/{back_end → compiler}/parser_generator/e_symbol_generator.rb +2 -10
- data/lib/rattler/{back_end → compiler}/parser_generator/eof_generator.rb +2 -10
- data/lib/rattler/{back_end → compiler}/parser_generator/expr_generator.rb +9 -35
- data/lib/rattler/{back_end → compiler}/parser_generator/fail_generator.rb +7 -3
- data/lib/rattler/{back_end → compiler}/parser_generator/gen_method_names.rb +3 -5
- data/lib/rattler/{back_end → compiler}/parser_generator/general_list_generator.rb +6 -18
- data/lib/rattler/{back_end → compiler}/parser_generator/general_repeat_generator.rb +16 -22
- data/lib/rattler/{back_end/parser_generator/rule_set_generator.rb → compiler/parser_generator/grammar_generator.rb} +24 -33
- data/lib/rattler/compiler/parser_generator/group_match.rb +33 -0
- data/lib/rattler/{back_end → compiler}/parser_generator/group_match_generator.rb +4 -17
- data/lib/rattler/compiler/parser_generator/label_generator.rb +37 -0
- data/lib/rattler/{back_end → compiler}/parser_generator/list0_generating.rb +5 -5
- data/lib/rattler/{back_end → compiler}/parser_generator/list1_generating.rb +3 -3
- data/lib/rattler/{back_end → compiler}/parser_generator/list_generator.rb +2 -2
- data/lib/rattler/{back_end → compiler}/parser_generator/match_generator.rb +10 -10
- data/lib/rattler/{back_end → compiler}/parser_generator/nested.rb +2 -2
- data/lib/rattler/compiler/parser_generator/node_action_generator.rb +49 -0
- data/lib/rattler/{back_end → compiler}/parser_generator/one_or_more_generating.rb +3 -3
- data/lib/rattler/{back_end → compiler}/parser_generator/optional_generating.rb +6 -22
- data/lib/rattler/compiler/parser_generator/predicate_propogating.rb +24 -0
- data/lib/rattler/{back_end → compiler}/parser_generator/repeat_generator.rb +2 -2
- data/lib/rattler/compiler/parser_generator/rule_generator.rb +66 -0
- data/lib/rattler/compiler/parser_generator/rule_set_generator.rb +33 -0
- data/lib/rattler/compiler/parser_generator/semantic_action_generator.rb +58 -0
- data/lib/rattler/compiler/parser_generator/sequence_generating.rb +138 -0
- data/lib/rattler/compiler/parser_generator/sequence_generator.rb +57 -0
- data/lib/rattler/{back_end → compiler}/parser_generator/skip_generator.rb +4 -18
- data/lib/rattler/compiler/parser_generator/skip_propogating.rb +16 -0
- data/lib/rattler/{back_end → compiler}/parser_generator/sub_generating.rb +19 -11
- data/lib/rattler/compiler/parser_generator/super_generator.rb +54 -0
- data/lib/rattler/{back_end → compiler}/parser_generator/token_generator.rb +3 -3
- data/lib/rattler/compiler/parser_generator/token_propogating.rb +10 -0
- data/lib/rattler/{back_end → compiler}/parser_generator/top_level.rb +2 -2
- data/lib/rattler/{back_end → compiler}/parser_generator/zero_or_more_generating.rb +5 -5
- data/lib/rattler/compiler/rattler.rtlr +201 -0
- data/lib/rattler/{back_end → compiler}/ruby_generator.rb +16 -25
- data/lib/rattler/parsers.rb +12 -33
- data/lib/rattler/parsers/action_code.rb +25 -16
- data/lib/rattler/{grammar → parsers}/analysis.rb +32 -11
- data/lib/rattler/parsers/apply.rb +10 -19
- data/lib/rattler/parsers/assert.rb +4 -14
- data/lib/rattler/parsers/atomic.rb +3 -10
- data/lib/rattler/parsers/attributed_sequence.rb +50 -0
- data/lib/rattler/parsers/back_reference.rb +19 -14
- data/lib/rattler/parsers/choice.rb +11 -12
- data/lib/rattler/parsers/combinator_parser.rb +15 -7
- data/lib/rattler/parsers/combining.rb +15 -9
- data/lib/rattler/parsers/disallow.rb +5 -12
- data/lib/rattler/parsers/e_symbol.rb +5 -14
- data/lib/rattler/parsers/eof.rb +10 -15
- data/lib/rattler/parsers/fail.rb +16 -26
- data/lib/rattler/{grammar → parsers}/grammar.rb +15 -20
- data/lib/rattler/parsers/label.rb +10 -16
- data/lib/rattler/parsers/list_parser.rb +14 -14
- data/lib/rattler/parsers/match.rb +5 -17
- data/lib/rattler/parsers/node_action.rb +72 -0
- data/lib/rattler/parsers/node_code.rb +47 -30
- data/lib/rattler/parsers/parser.rb +63 -32
- data/lib/rattler/parsers/parser_scope.rb +88 -0
- data/lib/rattler/parsers/predicate.rb +12 -10
- data/lib/rattler/parsers/repeat.rb +15 -8
- data/lib/rattler/parsers/rule.rb +8 -23
- data/lib/rattler/parsers/rule_set.rb +67 -12
- data/lib/rattler/parsers/semantic.rb +36 -0
- data/lib/rattler/parsers/semantic_action.rb +39 -0
- data/lib/rattler/parsers/sequence.rb +25 -40
- data/lib/rattler/parsers/sequencing.rb +40 -0
- data/lib/rattler/parsers/skip.rb +11 -12
- data/lib/rattler/parsers/super.rb +33 -0
- data/lib/rattler/parsers/token.rb +3 -13
- data/lib/rattler/rake_task.rb +50 -0
- data/lib/rattler/runner.rb +19 -22
- data/lib/rattler/runtime.rb +0 -10
- data/lib/rattler/runtime/extended_packrat_parser.rb +40 -45
- data/lib/rattler/runtime/packrat_parser.rb +17 -31
- data/lib/rattler/runtime/parse_failure.rb +16 -26
- data/lib/rattler/runtime/parse_node.rb +8 -18
- data/lib/rattler/runtime/parser.rb +6 -18
- data/lib/rattler/runtime/parser_helper.rb +3 -10
- data/lib/rattler/runtime/recursive_descent_parser.rb +26 -23
- data/lib/rattler/runtime/syntax_error.rb +0 -10
- data/lib/rattler/util.rb +2 -6
- data/lib/rattler/util/grammar_cli.rb +19 -0
- data/lib/rattler/util/graphviz.rb +6 -17
- data/lib/rattler/util/graphviz/digraph_builder.rb +10 -17
- data/lib/rattler/util/graphviz/node_builder.rb +45 -31
- data/lib/rattler/util/line_counter.rb +11 -20
- data/lib/rattler/util/node.rb +52 -30
- data/lib/rattler/util/parser_cli.rb +84 -0
- data/lib/rattler/util/parser_spec_helper.rb +8 -12
- data/spec/rattler/compiler/assert_compiler_examples.rb +284 -0
- data/spec/rattler/compiler/attributed_sequence_compiler_examples.rb +154 -0
- data/spec/rattler/compiler/disallow_compiler_examples.rb +293 -0
- data/spec/rattler/compiler/grammar_parser_spec.rb +700 -0
- data/spec/rattler/{back_end → compiler}/optimizer/flatten_choice_spec.rb +1 -1
- data/spec/rattler/{back_end → compiler}/optimizer/flatten_sequence_spec.rb +1 -1
- data/spec/rattler/compiler/optimizer/inline_regular_rules_spec.rb +50 -0
- data/spec/rattler/{back_end → compiler}/optimizer/join_match_capturing_sequence_spec.rb +106 -22
- data/spec/rattler/{back_end → compiler}/optimizer/join_match_choice_spec.rb +1 -1
- data/spec/rattler/{back_end → compiler}/optimizer/join_match_matching_sequence_spec.rb +1 -1
- data/spec/rattler/{back_end → compiler}/optimizer/join_predicate_bare_match_spec.rb +1 -1
- data/spec/rattler/{back_end → compiler}/optimizer/join_predicate_nested_match_spec.rb +1 -1
- data/spec/rattler/{back_end → compiler}/optimizer/join_predicate_or_bare_match_spec.rb +1 -1
- data/spec/rattler/{back_end → compiler}/optimizer/join_predicate_or_nested_match_spec.rb +1 -1
- data/spec/rattler/{back_end → compiler}/optimizer/reduce_repeat_match_spec.rb +1 -1
- data/spec/rattler/compiler/optimizer/remove_meaningless_wrapper_spec.rb +82 -0
- data/spec/rattler/{back_end → compiler}/optimizer/simplify_redundant_repeat_spec.rb +1 -1
- data/spec/rattler/{back_end → compiler}/optimizer/simplify_token_match_spec.rb +1 -1
- data/spec/rattler/{back_end → compiler}/optimizer_spec.rb +1 -1
- data/spec/rattler/{back_end → compiler}/parser_generator/apply_generator_spec.rb +1 -39
- data/spec/rattler/{back_end → compiler}/parser_generator/assert_generator_spec.rb +1 -55
- data/spec/rattler/compiler/parser_generator/attributed_sequence_generator_spec.rb +699 -0
- data/spec/rattler/{back_end → compiler}/parser_generator/back_reference_generator_spec.rb +3 -56
- data/spec/rattler/{back_end → compiler}/parser_generator/choice_generator_spec.rb +1 -63
- data/spec/rattler/{back_end → compiler}/parser_generator/disallow_generator_spec.rb +1 -55
- data/spec/rattler/{back_end → compiler}/parser_generator/e_symbol_generator_spec.rb +1 -39
- data/spec/rattler/{back_end → compiler}/parser_generator/eof_generator_spec.rb +1 -39
- data/spec/rattler/{back_end → compiler}/parser_generator/fail_generator_spec.rb +94 -23
- data/spec/rattler/compiler/parser_generator/grammar_generator_spec.rb +98 -0
- data/spec/rattler/compiler/parser_generator/group_match_generator_spec.rb +67 -0
- data/spec/rattler/{back_end → compiler}/parser_generator/group_match_spec.rb +1 -1
- data/spec/rattler/{back_end → compiler}/parser_generator/label_generator_spec.rb +1 -55
- data/spec/rattler/{back_end → compiler}/parser_generator/list0_generator_examples.rb +0 -88
- data/spec/rattler/{back_end → compiler}/parser_generator/list1_generator_examples.rb +0 -88
- data/spec/rattler/{back_end → compiler}/parser_generator/list_generator_spec.rb +1 -227
- data/spec/rattler/{back_end → compiler}/parser_generator/match_generator_spec.rb +1 -55
- data/spec/rattler/compiler/parser_generator/node_action_generator_spec.rb +135 -0
- data/spec/rattler/{back_end → compiler}/parser_generator/one_or_more_generator_examples.rb +0 -74
- data/spec/rattler/{back_end → compiler}/parser_generator/optional_generator_examples.rb +0 -62
- data/spec/rattler/{back_end → compiler}/parser_generator/repeat_generator_spec.rb +66 -1
- data/spec/rattler/{back_end → compiler}/parser_generator/rule_generator_spec.rb +3 -2
- data/spec/rattler/{back_end → compiler}/parser_generator/rule_set_generator_spec.rb +9 -27
- data/spec/rattler/compiler/parser_generator/semantic_action_generator_spec.rb +437 -0
- data/spec/rattler/{back_end → compiler}/parser_generator/sequence_generator_spec.rb +234 -68
- data/spec/rattler/{back_end → compiler}/parser_generator/skip_generator_spec.rb +1 -55
- data/spec/rattler/compiler/parser_generator/super_generator_spec.rb +93 -0
- data/spec/rattler/{back_end → compiler}/parser_generator/token_generator_spec.rb +1 -55
- data/spec/rattler/{back_end → compiler}/parser_generator/zero_or_more_generator_examples.rb +0 -74
- data/spec/rattler/{back_end → compiler}/ruby_generator_spec.rb +13 -13
- data/spec/rattler/compiler/semantic_action_compiler_examples.rb +57 -0
- data/spec/rattler/{back_end → compiler}/shared_compiler_examples.rb +111 -140
- data/spec/rattler/{back_end → compiler}/skip_compiler_examples.rb +60 -57
- data/spec/rattler/{back_end → compiler}/token_compiler_examples.rb +99 -104
- data/spec/rattler/compiler_spec.rb +67 -0
- data/spec/rattler/parsers/action_code_spec.rb +34 -18
- data/spec/rattler/{grammar → parsers}/analysis_spec.rb +13 -67
- data/spec/rattler/parsers/apply_spec.rb +6 -0
- data/spec/rattler/parsers/assert_spec.rb +38 -2
- data/spec/rattler/parsers/attributed_sequence_spec.rb +204 -0
- data/spec/rattler/parsers/back_reference_spec.rb +6 -0
- data/spec/rattler/parsers/choice_spec.rb +38 -1
- data/spec/rattler/parsers/combinator_parser_spec.rb +2 -1
- data/spec/rattler/parsers/disallow_spec.rb +38 -2
- data/spec/rattler/parsers/e_symbol_spec.rb +6 -0
- data/spec/rattler/parsers/eof_spec.rb +6 -0
- data/spec/rattler/parsers/fail_spec.rb +6 -0
- data/spec/rattler/{grammar → parsers}/grammar_spec.rb +10 -15
- data/spec/rattler/parsers/label_spec.rb +30 -0
- data/spec/rattler/parsers/list_parser_spec.rb +31 -2
- data/spec/rattler/parsers/match_spec.rb +6 -0
- data/spec/rattler/parsers/node_action_spec.rb +121 -0
- data/spec/rattler/parsers/parser_scope_spec.rb +105 -0
- data/spec/rattler/parsers/repeat_spec.rb +56 -0
- data/spec/rattler/parsers/rule_set_spec.rb +42 -0
- data/spec/rattler/parsers/semantic_action_spec.rb +89 -0
- data/spec/rattler/parsers/sequence_spec.rb +156 -12
- data/spec/rattler/parsers/skip_spec.rb +21 -0
- data/spec/rattler/parsers/super_spec.rb +45 -0
- data/spec/rattler/parsers/token_spec.rb +33 -14
- data/spec/rattler/runtime/extended_packrat_parser_spec.rb +10 -8
- data/spec/rattler/runtime/recursive_descent_parser_spec.rb +26 -0
- data/spec/rattler/runtime/shared_parser_examples.rb +22 -16
- data/spec/rattler/util/graphviz/node_builder_spec.rb +33 -17
- data/spec/rattler/util/line_counter_spec.rb +21 -21
- data/spec/rattler/util/node_spec.rb +62 -0
- data/spec/rattler_spec.rb +7 -41
- data/spec/spec_helper.rb +1 -2
- data/spec/support/combinator_parser_spec_helper.rb +1 -1
- data/spec/support/compiler_spec_helper.rb +0 -4
- data/spec/support/parser_generator_spec_helper.rb +7 -7
- data/spec/support/runtime_parser_spec_helper.rb +57 -3
- metadata +447 -303
- data/features/grammar/character_class.feature +0 -20
- data/features/grammar/nonterminal.feature +0 -24
- data/features/grammar/one_or_more.feature +0 -34
- data/features/grammar/ordered_choice.feature +0 -21
- data/features/grammar/posix_class.feature +0 -70
- data/features/grammar/sequence.feature +0 -20
- data/features/grammar/zero_or_more.feature +0 -34
- data/lib/rattler/back_end.rb +0 -22
- data/lib/rattler/back_end/compiler.rb +0 -128
- data/lib/rattler/back_end/optimizer.rb +0 -101
- data/lib/rattler/back_end/optimizer/inline_regular_rules.rb +0 -46
- data/lib/rattler/back_end/optimizer/join_match_sequence.rb +0 -17
- data/lib/rattler/back_end/optimizer/join_predicate_match.rb +0 -17
- data/lib/rattler/back_end/optimizer/join_predicate_or_match.rb +0 -17
- data/lib/rattler/back_end/optimizer/optimization_context.rb +0 -72
- data/lib/rattler/back_end/optimizer/remove_meaningless_wrapper.rb +0 -32
- data/lib/rattler/back_end/optimizer/specialize_repeat.rb +0 -40
- data/lib/rattler/back_end/parser_generator.rb +0 -113
- data/lib/rattler/back_end/parser_generator/direct_action_generator.rb +0 -45
- data/lib/rattler/back_end/parser_generator/dispatch_action_generator.rb +0 -45
- data/lib/rattler/back_end/parser_generator/group_match.rb +0 -26
- data/lib/rattler/back_end/parser_generator/label_generator.rb +0 -64
- data/lib/rattler/back_end/parser_generator/predicate_propogating.rb +0 -24
- data/lib/rattler/back_end/parser_generator/rule_generator.rb +0 -53
- data/lib/rattler/back_end/parser_generator/sequence_generator.rb +0 -190
- data/lib/rattler/back_end/parser_generator/skip_propogating.rb +0 -16
- data/lib/rattler/back_end/parser_generator/token_propogating.rb +0 -10
- data/lib/rattler/grammar.rb +0 -43
- data/lib/rattler/grammar/grammar_dsl.rb +0 -51
- data/lib/rattler/grammar/metagrammar.rb +0 -990
- data/lib/rattler/grammar/rattler.rtlr +0 -183
- data/lib/rattler/parsers/assert_code.rb +0 -31
- data/lib/rattler/parsers/direct_action.rb +0 -85
- data/lib/rattler/parsers/disallow_code.rb +0 -31
- data/lib/rattler/parsers/dispatch_action.rb +0 -121
- data/lib/rattler/parsers/effect_code.rb +0 -31
- data/lib/rattler/parsers/parser_dsl.rb +0 -414
- data/lib/rattler/parsers/semantic_assert.rb +0 -19
- data/lib/rattler/parsers/semantic_disallow.rb +0 -19
- data/lib/rattler/parsers/side_effect.rb +0 -19
- data/spec/rattler/back_end/assert_compiler_examples.rb +0 -187
- data/spec/rattler/back_end/compiler_spec.rb +0 -43
- data/spec/rattler/back_end/direct_action_compiler_examples.rb +0 -227
- data/spec/rattler/back_end/disallow_compiler_examples.rb +0 -187
- data/spec/rattler/back_end/dispatch_action_compiler_examples.rb +0 -225
- data/spec/rattler/back_end/optimizer/inline_regular_rules_spec.rb +0 -80
- data/spec/rattler/back_end/parser_generator/direct_action_generator_spec.rb +0 -204
- data/spec/rattler/back_end/parser_generator/dispatch_action_generator_spec.rb +0 -204
- data/spec/rattler/back_end/parser_generator/group_match_generator_spec.rb +0 -185
- data/spec/rattler/back_end/semantic_assert_compiler_examples.rb +0 -152
- data/spec/rattler/back_end/semantic_disallow_compiler_examples.rb +0 -152
- data/spec/rattler/back_end/side_effect_compiler_examples.rb +0 -227
- data/spec/rattler/grammar/grammar_parser_spec.rb +0 -626
- data/spec/rattler/parsers/direct_action_spec.rb +0 -224
- data/spec/rattler/parsers/dispatch_action_spec.rb +0 -209
- data/spec/rattler/parsers/node_code_spec.rb +0 -59
- data/spec/rattler/parsers/parser_dsl_spec.rb +0 -334
- data/spec/rattler/parsers/semantic_assert_spec.rb +0 -83
- data/spec/rattler/parsers/semantic_disallow_spec.rb +0 -83
- data/spec/rattler/parsers/side_effect_spec.rb +0 -214
@@ -0,0 +1,293 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
+
|
3
|
+
shared_examples_for 'a compiled parser with a disallow' do
|
4
|
+
include CompilerSpecHelper
|
5
|
+
include RuntimeParserSpecHelper
|
6
|
+
|
7
|
+
subject { compiled_parser }
|
8
|
+
|
9
|
+
let(:reference_parser) { combinator_parser grammar }
|
10
|
+
|
11
|
+
let(:grammar) { Rattler::Parsers::Grammar[Rattler::Parsers::RuleSet[*rules]] }
|
12
|
+
|
13
|
+
context 'with a nested match rule' do
|
14
|
+
let(:rules) { [
|
15
|
+
rule(:word) { disallow(/\w+/) }
|
16
|
+
] }
|
17
|
+
it { should parse(' ').succeeding.like reference_parser }
|
18
|
+
it { should parse('abc123 ').failing.like reference_parser }
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'with a nested eof rule' do
|
22
|
+
let(:rules) { [
|
23
|
+
rule(:foo) { disallow(eof) }
|
24
|
+
] }
|
25
|
+
it { should parse('foo').succeeding.like reference_parser }
|
26
|
+
it { should parse('').failing.like reference_parser }
|
27
|
+
it { should parse('foo').from(3).failing.like reference_parser }
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'with a nested "E" symbol rule' do
|
31
|
+
let(:rules) { [
|
32
|
+
rule(:foo) { disallow(e) }
|
33
|
+
] }
|
34
|
+
it { should parse('').failing.like reference_parser }
|
35
|
+
it { should parse('foo').failing.like reference_parser }
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'with a nested choice rule' do
|
39
|
+
let(:rules) { [
|
40
|
+
rule(:word) { disallow(match(/[[:alpha:]]/) | match(/[[:digit:]]/)) }
|
41
|
+
] }
|
42
|
+
it { should parse(' ').succeeding.like reference_parser }
|
43
|
+
it { should parse('abc123 ').failing.like reference_parser }
|
44
|
+
end
|
45
|
+
|
46
|
+
context 'with a nested sequence rule' do
|
47
|
+
let(:rules) { [
|
48
|
+
rule(:word) { disallow(match(/[[:alpha:]]+/) & match(/[[:digit:]]+/)) }
|
49
|
+
] }
|
50
|
+
it { should parse(' ').succeeding.like reference_parser }
|
51
|
+
it { should parse('abc123 ').failing.like reference_parser }
|
52
|
+
|
53
|
+
context 'with a semantic action' do
|
54
|
+
|
55
|
+
context 'when the expression has parameters' do
|
56
|
+
let(:rules) { [
|
57
|
+
rule(:a) {
|
58
|
+
disallow(match(/\d+/) >> semantic_action('|a| a.to_i * 2'))
|
59
|
+
}
|
60
|
+
] }
|
61
|
+
it { should parse(' ').succeeding.like reference_parser }
|
62
|
+
it { should parse('451a').failing.like reference_parser }
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'when the expression uses "_"' do
|
66
|
+
|
67
|
+
context 'given a single capture' do
|
68
|
+
let(:rules) { [
|
69
|
+
rule(:a) { disallow(match(/\d+/) >> semantic_action('_ * 2')) }
|
70
|
+
] }
|
71
|
+
it { should parse(' ').succeeding.like reference_parser }
|
72
|
+
it { should parse('451a').failing.like reference_parser }
|
73
|
+
end
|
74
|
+
|
75
|
+
context 'given multiple captures' do
|
76
|
+
let(:rules) { [
|
77
|
+
rule(:a) { disallow(
|
78
|
+
(match(/\d+/) & skip(/\s+/) & match(/\d+/)) >> semantic_action('_')
|
79
|
+
) }
|
80
|
+
] }
|
81
|
+
it { should parse(' ').succeeding.like reference_parser }
|
82
|
+
it { should parse('23 42').failing.like reference_parser }
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context 'when the expression uses labels' do
|
87
|
+
let(:rules) { [
|
88
|
+
rule(:a) { disallow(
|
89
|
+
label(:a, /\d+/) >> semantic_action('a.to_i * 2')
|
90
|
+
) }
|
91
|
+
] }
|
92
|
+
it { should parse(' ').succeeding.like reference_parser }
|
93
|
+
it { should parse('451a').failing.like reference_parser }
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
context 'with a nested optional rule' do
|
99
|
+
let(:rules) { [
|
100
|
+
rule(:word) { disallow(match(/\w+/).optional) }
|
101
|
+
] }
|
102
|
+
it { should parse(' ').failing.like reference_parser }
|
103
|
+
it { should parse('abc123 ').failing.like reference_parser }
|
104
|
+
end
|
105
|
+
|
106
|
+
context 'with a nested zero_or_more rule' do
|
107
|
+
let(:rules) { [
|
108
|
+
rule(:word) { disallow(match(/\w/).zero_or_more) }
|
109
|
+
] }
|
110
|
+
it { should parse(' ').failing.like reference_parser }
|
111
|
+
it { should parse('abc123 ').failing.like reference_parser }
|
112
|
+
end
|
113
|
+
|
114
|
+
context 'with a nested one_or_more rule' do
|
115
|
+
let(:rules) { [
|
116
|
+
rule(:word) { disallow(match(/\w/).one_or_more) }
|
117
|
+
] }
|
118
|
+
it { should parse(' ').succeeding.like reference_parser }
|
119
|
+
it { should parse('abc123 ').failing.like reference_parser }
|
120
|
+
end
|
121
|
+
|
122
|
+
context 'with a nested repeat rule' do
|
123
|
+
let(:rules) { [
|
124
|
+
rule(:word) { disallow(match(/\w/).repeat(2, nil)) }
|
125
|
+
] }
|
126
|
+
it { should parse('a ').succeeding.like reference_parser }
|
127
|
+
it { should parse('abc123 ').failing.like reference_parser }
|
128
|
+
|
129
|
+
context 'with zero-or-more bounds' do
|
130
|
+
let(:rules) { [
|
131
|
+
rule(:word) { disallow(match(/\w/).repeat(0, nil)) }
|
132
|
+
] }
|
133
|
+
it { should parse(' ').failing.like reference_parser }
|
134
|
+
it { should parse('abc123 ').failing.like reference_parser }
|
135
|
+
|
136
|
+
context 'with an upper bound' do
|
137
|
+
let(:rules) { [
|
138
|
+
rule(:word) { disallow(match(/\w/).repeat(0, 2)) }
|
139
|
+
] }
|
140
|
+
it { should parse(' ').failing.like reference_parser }
|
141
|
+
it { should parse('abc123 ').failing.like reference_parser }
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
context 'with one-or-more bounds' do
|
146
|
+
let(:rules) { [
|
147
|
+
rule(:word) { disallow(match(/\w/).repeat(1, nil)) }
|
148
|
+
] }
|
149
|
+
it { should parse(' ').succeeding.like reference_parser }
|
150
|
+
it { should parse('abc123 ').failing.like reference_parser }
|
151
|
+
|
152
|
+
context 'with an upper bound' do
|
153
|
+
let(:rules) { [
|
154
|
+
rule(:word) { disallow(match(/\w/).repeat(1, 2)) }
|
155
|
+
] }
|
156
|
+
it { should parse(' ').succeeding.like reference_parser }
|
157
|
+
it { should parse('abc123 ').failing.like reference_parser }
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
context 'with a nested list rule' do
|
163
|
+
let(:rules) { [
|
164
|
+
rule(:foo) { disallow match(/\w+/).list(match(/[,;]/), 2, nil) }
|
165
|
+
] }
|
166
|
+
it { should parse('foo ').succeeding.like reference_parser }
|
167
|
+
it { should parse('foo,bar;baz ').failing.like reference_parser }
|
168
|
+
|
169
|
+
context 'with an upper bound' do
|
170
|
+
let(:rules) { [
|
171
|
+
rule(:foo) {
|
172
|
+
disallow(match(/\w+/).list(match(/[,;]/), 2, 4))
|
173
|
+
}
|
174
|
+
] }
|
175
|
+
it { should parse('foo ').succeeding.like reference_parser }
|
176
|
+
it { should parse('foo,bar;baz ').failing.like reference_parser }
|
177
|
+
end
|
178
|
+
|
179
|
+
context 'with a non-capturing parser' do
|
180
|
+
let(:rules) { [
|
181
|
+
rule(:foo) {
|
182
|
+
disallow(skip(/\w+/).list(match(/[,;]/), 2, nil))
|
183
|
+
}
|
184
|
+
] }
|
185
|
+
it { should parse('foo ').succeeding.like reference_parser }
|
186
|
+
it { should parse('foo,bar;baz ').failing.like reference_parser }
|
187
|
+
|
188
|
+
context 'with an upper bound' do
|
189
|
+
let(:rules) { [
|
190
|
+
rule(:foo) {
|
191
|
+
disallow skip(/\w+/).list(match(/[,;]/), 2, 4)
|
192
|
+
}
|
193
|
+
] }
|
194
|
+
it { should parse('foo ').succeeding.like reference_parser }
|
195
|
+
it { should parse('foo,bar;baz ').failing.like reference_parser }
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
context 'with a nested apply rule' do
|
201
|
+
let(:rules) { [
|
202
|
+
rule(:foo) { match(:word) },
|
203
|
+
rule(:word) { disallow(/\w+/) }
|
204
|
+
] }
|
205
|
+
it { should parse(' ').succeeding.like reference_parser }
|
206
|
+
it { should parse('abc123 ').failing.like reference_parser }
|
207
|
+
end
|
208
|
+
|
209
|
+
context 'with a nested attributed sequence' do
|
210
|
+
|
211
|
+
context 'with a single capture and a semantic action' do
|
212
|
+
|
213
|
+
context 'when the action uses a parameter' do
|
214
|
+
let(:rules) { [
|
215
|
+
rule(:a) { disallow(match(/\d+/) >> semantic_action('|a| a.to_i')) }
|
216
|
+
] }
|
217
|
+
it { should parse(' ').succeeding.like reference_parser }
|
218
|
+
it { should parse('451a').failing.like reference_parser }
|
219
|
+
end
|
220
|
+
|
221
|
+
context 'when the action uses "_"' do
|
222
|
+
let(:rules) { [
|
223
|
+
rule(:a) { disallow(match(/\d+/) >> semantic_action('_.to_i')) }
|
224
|
+
] }
|
225
|
+
it { should parse(' ').succeeding.like reference_parser }
|
226
|
+
it { should parse('451a').failing.like reference_parser }
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
context 'with multiple captures and a semantic action' do
|
231
|
+
|
232
|
+
context 'when the action uses parameters' do
|
233
|
+
let(:rules) { [
|
234
|
+
rule(:a) {
|
235
|
+
disallow(
|
236
|
+
(match(/[a-z]+/) & match(/\d+/)) >> semantic_action('|a,b| b+a')
|
237
|
+
)
|
238
|
+
}
|
239
|
+
] }
|
240
|
+
it { should parse(' ').succeeding.like reference_parser }
|
241
|
+
it { should parse('abc123').failing.like reference_parser }
|
242
|
+
end
|
243
|
+
|
244
|
+
context 'when the action uses "_"' do
|
245
|
+
let(:rules) { [
|
246
|
+
rule(:a) {
|
247
|
+
disallow(
|
248
|
+
(match(/[a-z]+/) & match(/\d+/)) >> semantic_action('_.reverse')
|
249
|
+
)
|
250
|
+
}
|
251
|
+
] }
|
252
|
+
it { should parse(' ').succeeding.like reference_parser }
|
253
|
+
it { should parse('abc123').failing.like reference_parser }
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
context 'with a single labeled capture and a semantic action' do
|
258
|
+
let(:rules) { [
|
259
|
+
rule(:e) { disallow(label(:a, /\d+/) >> semantic_action('a.to_i')) }
|
260
|
+
] }
|
261
|
+
it { should parse(' ').succeeding.like reference_parser }
|
262
|
+
it { should parse('451a').failing.like reference_parser }
|
263
|
+
end
|
264
|
+
|
265
|
+
context 'with multiple labeled captures and a semantic action' do
|
266
|
+
let(:rules) { [
|
267
|
+
rule(:e) {
|
268
|
+
disallow(
|
269
|
+
(label(:a, /[a-z]+/) & label(:b, /\d+/)) >> semantic_action('b + a')
|
270
|
+
)
|
271
|
+
}
|
272
|
+
] }
|
273
|
+
it { should parse(' ').succeeding.like reference_parser }
|
274
|
+
it { should parse('abc123').failing.like reference_parser }
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
context 'with a nested token rule' do
|
279
|
+
let(:rules) { [
|
280
|
+
rule(:word) { disallow(token(/\w+/)) }
|
281
|
+
] }
|
282
|
+
it { should parse(' ').succeeding.like reference_parser }
|
283
|
+
it { should parse('abc123 ').failing.like reference_parser }
|
284
|
+
end
|
285
|
+
|
286
|
+
context 'with a nested skip rule' do
|
287
|
+
let(:rules) { [
|
288
|
+
rule(:word) { disallow(skip(/\w+/)) }
|
289
|
+
] }
|
290
|
+
it { should parse(' ').succeeding.like reference_parser }
|
291
|
+
it { should parse('abc123 ').failing.like reference_parser }
|
292
|
+
end
|
293
|
+
end
|
@@ -0,0 +1,700 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
|
2
|
+
|
3
|
+
include Rattler::Parsers
|
4
|
+
|
5
|
+
describe Rattler::Compiler::GrammarParser do
|
6
|
+
include Rattler::Util::ParserSpecHelper
|
7
|
+
|
8
|
+
let :posix_names do
|
9
|
+
%w{alnum alpha blank cntrl digit graph lower print punct space upper xdigit}
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '#match(:heading)' do
|
13
|
+
|
14
|
+
context 'given no contents' do
|
15
|
+
it 'parses as a hash with empty :requires and :includes' do
|
16
|
+
matching(' ').as(:heading).should result_in({
|
17
|
+
:requires => [],
|
18
|
+
:includes => []
|
19
|
+
})
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'given require statements' do
|
24
|
+
it 'parses as a hash with :requires' do
|
25
|
+
matching(%{
|
26
|
+
require 'rattler'
|
27
|
+
require 'my_language/semantics'
|
28
|
+
}).as(:heading).should result_in({
|
29
|
+
:requires => ["'rattler'", "'my_language/semantics'"],
|
30
|
+
:includes => []
|
31
|
+
})
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'given a require_relative statement' do
|
36
|
+
it 'translates the require_relative into ruby 1.8' do
|
37
|
+
matching("require_relative 'my_semantics'").as(:heading).should result_in({
|
38
|
+
:requires => ["File.expand_path('my_semantics', File.dirname(__FILE__))"],
|
39
|
+
:includes => []
|
40
|
+
})
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'given a parser declaration' do
|
45
|
+
it 'parses as a hash with :parser_name and base_name' do
|
46
|
+
matching(%{
|
47
|
+
parser FooParser < Rattler::Runtime::RecursiveDescentParser
|
48
|
+
}).as(:heading).should result_in({
|
49
|
+
:parser_name => 'FooParser',
|
50
|
+
:base_name => 'Rattler::Runtime::RecursiveDescentParser',
|
51
|
+
:requires => [],
|
52
|
+
:includes => []
|
53
|
+
})
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'given a grammar declaration' do
|
58
|
+
it 'parses as a hash with :grammar_name' do
|
59
|
+
matching('grammar FooGrammar').as(:heading).should result_in({
|
60
|
+
:grammar_name => 'FooGrammar',
|
61
|
+
:requires => [],
|
62
|
+
:includes => []
|
63
|
+
})
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context 'given include statements' do
|
68
|
+
it 'parses as a hash with :includes' do
|
69
|
+
matching(%{
|
70
|
+
include MyHelpers
|
71
|
+
include MyLanguage::Semantics
|
72
|
+
}).as(:heading).should result_in({
|
73
|
+
:requires => [],
|
74
|
+
:includes => ['MyHelpers', 'MyLanguage::Semantics']
|
75
|
+
})
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
context 'given a %start directive' do
|
80
|
+
it 'parses as a hash with :start_rule' do
|
81
|
+
matching(' %start expr ').as(:heading).should result_in({
|
82
|
+
:start_rule => 'expr',
|
83
|
+
:requires => [],
|
84
|
+
:includes => []
|
85
|
+
})
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe '#match(:rules)' do
|
91
|
+
|
92
|
+
context 'given a single rule' do
|
93
|
+
it 'parses as a RuleSet with a single Rule' do
|
94
|
+
matching(%{ int <- DIGIT+ }).as(:rules).should result_in(RuleSet[
|
95
|
+
Rule[:int, Match[/[[:digit:]]/].one_or_more, {:inline => false}]
|
96
|
+
])
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
context 'given multiple rules' do
|
101
|
+
it 'parses as a RuleSet with multiple Rules' do
|
102
|
+
matching(%{
|
103
|
+
word <- ALPHA+
|
104
|
+
int <- DIGIT+
|
105
|
+
}).as(:rules).should result_in(RuleSet[
|
106
|
+
Rule[:word, Match[/[[:alpha:]]/].one_or_more, {:inline => false}],
|
107
|
+
Rule[:int, Match[/[[:digit:]]/].one_or_more, {:inline => false}]
|
108
|
+
])
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe '#match(:expression)' do
|
114
|
+
|
115
|
+
context 'given a string literal' do
|
116
|
+
|
117
|
+
context 'delimited by double quotes' do
|
118
|
+
it 'parses as a regex match' do
|
119
|
+
matching(%{ "a string" }).as(:expression).
|
120
|
+
should result_in(Match[/a\ string/]).at(11)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
context 'delimited by single quotes' do
|
125
|
+
it 'parses as a regex match' do
|
126
|
+
matching(%{ 'a string' }).as(:expression).
|
127
|
+
should result_in(Match[/a\ string/]).at(11)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
context 'using "general delimited text" syntax' do
|
132
|
+
|
133
|
+
context 'with "(" and ")"' do
|
134
|
+
it 'parses as a regex match' do
|
135
|
+
matching(' %(a string) ').as(:expression).
|
136
|
+
should result_in(Match[/a\ string/]).at(12)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
context 'with "{" and "}"' do
|
141
|
+
it 'parses as a regex match' do
|
142
|
+
matching(' %{a string} ').as(:expression).
|
143
|
+
should result_in(Match[/a\ string/]).at(12)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
context 'with "[" and "]"' do
|
148
|
+
it 'parses as a regex match' do
|
149
|
+
matching(' %[a string] ').as(:expression).
|
150
|
+
should result_in(Match[/a\ string/]).at(12)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
context 'with "<" and ">"' do
|
155
|
+
it 'parses as a regex match' do
|
156
|
+
matching(' %<a string> ').as(:expression).
|
157
|
+
should result_in(Match[/a\ string/]).at(12)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
context 'with arbitrary delimiters' do
|
162
|
+
it 'parses as a regex match' do
|
163
|
+
matching(' %!a string! ').as(:expression).
|
164
|
+
should result_in(Match[/a\ string/]).at(12)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
context 'delimited by backquotes' do
|
170
|
+
it 'parses as a word literal' do
|
171
|
+
matching(%{ `where` }).as(:expression).should result_in(
|
172
|
+
Token[Sequence[Match[/where/], Disallow[Match[/[[:alnum:]_]/]]]]
|
173
|
+
).at(8)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
context 'with special characters' do
|
178
|
+
it 'escapes the special characters' do
|
179
|
+
matching(%{ "[...]" }).as(:expression).
|
180
|
+
should result_in(Match[/\[\.\.\.\]/]).at(8)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
context 'given a character class expression' do
|
186
|
+
|
187
|
+
context 'with a simple list of characters' do
|
188
|
+
it 'parses as a regex match' do
|
189
|
+
matching(' [abc123] ').as(:expression).
|
190
|
+
should result_in(Match[/[abc123]/]).at(9)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
context 'with octal codes' do
|
195
|
+
it 'parses as a regex match' do
|
196
|
+
matching(' [\010\012\015] ').as(:expression).
|
197
|
+
should result_in(Match[/[\010\012\015]/]).at(15)
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
context 'with hex codes' do
|
202
|
+
it 'parses as a regex match' do
|
203
|
+
matching(' [\x08\x0A\x0D] ').as(:expression).
|
204
|
+
should result_in(Match[/[\x08\x0A\x0D]/]).at(15)
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
context 'with a range of characters' do
|
209
|
+
it 'parses as a regex match' do
|
210
|
+
matching(' [A-F] ').as(:expression).
|
211
|
+
should result_in(Match[/[A-F]/]).at(6)
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
context 'with a range of octal codes' do
|
216
|
+
it 'parses as a regex match' do
|
217
|
+
matching(' [\000-\177] ').as(:expression).
|
218
|
+
should result_in(Match[/[\000-\177]/]).at(12)
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
context 'with a range of hex codes' do
|
223
|
+
it 'parses as a regex match' do
|
224
|
+
matching(' [\x00-\x7F] ').as(:expression).
|
225
|
+
should result_in(Match[/[\x00-\x7F]/]).at(12)
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
context 'given a "."' do
|
231
|
+
it 'parses as Match[/./]' do
|
232
|
+
matching(' . ').as(:expression).should result_in(Match[/./]).at(2)
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
context 'given a lower-case word' do
|
237
|
+
it 'parses as an Apply' do
|
238
|
+
matching(' fooBar ').as(:expression).should result_in(Apply[:fooBar]).at(7)
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
context 'given a upper-case word' do
|
243
|
+
it 'parses it as an Apply' do
|
244
|
+
matching(' FooBar ').as(:expression).should result_in(Apply[:FooBar]).at(7)
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
context 'given the EOF keyword' do
|
249
|
+
it 'parses as Eof[]' do
|
250
|
+
matching(' EOF ').as(:expression).should result_in(Eof[]).at(4)
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
context 'given the E symbol' do
|
255
|
+
it 'parses as ESymbol[]' do
|
256
|
+
matching(' E ').as(:expression).should result_in(ESymbol[]).at(2)
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
context 'given "super"' do
|
261
|
+
it 'parses as Super[:pending]' do
|
262
|
+
matching(' super ').as(:expression).
|
263
|
+
should result_in(Super[:pending]).at(6)
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
context 'given an upper-case POSIX class name' do
|
268
|
+
it 'parses as a Match of a POSIX character class' do
|
269
|
+
for name in posix_names
|
270
|
+
matching(" #{name.upcase} ").as(:expression).
|
271
|
+
should result_in(Match[Regexp.new("[[:#{name}:]]")]).
|
272
|
+
at(name.length + 1)
|
273
|
+
end
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
context 'given the non-POSIX WORD class name' do
|
278
|
+
it 'parses as syntactic sugar for [[:alnum:]_]' do
|
279
|
+
matching(' WORD ').as(:expression).
|
280
|
+
should result_in(Match[/[[:alnum:]_]/]).at(5)
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
context 'given a word prefixed with "$"' do
|
285
|
+
it 'parses as a back-reference' do
|
286
|
+
matching(' $foobar ').as(:expression).
|
287
|
+
should result_in(BackReference[:foobar]).at(8)
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
context 'given a term prefixed with "&"' do
|
292
|
+
it 'parses as an assert' do
|
293
|
+
matching(' &foo ').as(:expression).
|
294
|
+
should result_in(Assert[Apply[:foo]]).at(5)
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
context 'given a term prefixed with "!"' do
|
299
|
+
it 'parses as a disallow' do
|
300
|
+
matching(' !foo ').as(:expression).
|
301
|
+
should result_in(Disallow[Apply[:foo]]).at(5)
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
context 'given a term prefixed with "~"' do
|
306
|
+
it 'parses as a skip' do
|
307
|
+
matching(' ~foo ').as(:expression).
|
308
|
+
should result_in(Skip[Apply[:foo]]).at(5)
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
context 'given a term prefixed with "@"' do
|
313
|
+
it 'parses as a token' do
|
314
|
+
matching(' @foo ').as(:expression).
|
315
|
+
should result_in(Token[Apply[:foo]]).at(5)
|
316
|
+
end
|
317
|
+
end
|
318
|
+
|
319
|
+
context 'given a term prefixed with "~@"' do
|
320
|
+
it 'parses as a skip of a token' do
|
321
|
+
matching(' ~@(foo bar) ').as(:expression).
|
322
|
+
should result_in(Skip[Token[Apply[:foo] & Apply[:bar]]])
|
323
|
+
end
|
324
|
+
end
|
325
|
+
|
326
|
+
context 'given a term prefixed with a name followed by ":"' do
|
327
|
+
it 'parses as a labeled expression' do
|
328
|
+
matching(' val:foo ').as(:expression).
|
329
|
+
should result_in(Label[:val, Apply[:foo]]).at(8)
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
context 'given a fail expression' do
|
334
|
+
it 'parses as a Fail of type :expr' do
|
335
|
+
matching(' fail("bad!") ').as(:expression).
|
336
|
+
should result_in(Fail[:expr, 'bad!']).at(13)
|
337
|
+
matching(' fail "bad!" ').as(:expression).
|
338
|
+
should result_in(Fail[:expr, 'bad!']).at(12)
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
context 'given a fail_rule expression' do
|
343
|
+
it 'parses as a Fail of type :rule' do
|
344
|
+
matching(' fail_rule("bad!") ').as(:expression).
|
345
|
+
should result_in(Fail[:rule, 'bad!']).at(18)
|
346
|
+
matching(' fail_rule "bad!" ').as(:expression).
|
347
|
+
should result_in(Fail[:rule, 'bad!']).at(17)
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
context 'given a fail_parse expression' do
|
352
|
+
it 'parses as a Fail of type :parse' do
|
353
|
+
matching(' fail_parse("bad!") ').as(:expression).
|
354
|
+
should result_in(Fail[:parse, 'bad!']).at(19)
|
355
|
+
matching(' fail_parse "bad!" ').as(:expression).
|
356
|
+
should result_in(Fail[:parse, 'bad!']).at(18)
|
357
|
+
end
|
358
|
+
end
|
359
|
+
|
360
|
+
context 'given a semantic result' do
|
361
|
+
it 'parses as a SemanticAction' do
|
362
|
+
matching(' ^{ 42 } ').as(:expression).
|
363
|
+
should result_in(SemanticAction['42']).at(8)
|
364
|
+
end
|
365
|
+
end
|
366
|
+
|
367
|
+
context 'given a positive semantic predicate' do
|
368
|
+
it 'parses as an Assert of a SemanticAction' do
|
369
|
+
matching(' &{ 42 } ').as(:expression).
|
370
|
+
should result_in(Assert[SemanticAction['42']]).at(8)
|
371
|
+
end
|
372
|
+
end
|
373
|
+
|
374
|
+
context 'given a negative semantic predicate' do
|
375
|
+
it 'parses as a Disallow of a SemanticAction' do
|
376
|
+
matching(' !{ 42 } ').as(:expression).
|
377
|
+
should result_in(Disallow[SemanticAction['42']]).at(8)
|
378
|
+
end
|
379
|
+
end
|
380
|
+
|
381
|
+
context 'given a semantic side-effect predicate' do
|
382
|
+
it 'parses as a Skip of a SemanticAction' do
|
383
|
+
matching(' ~{ 42 } ').as(:expression).
|
384
|
+
should result_in(Skip[SemanticAction['42']]).at(8)
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
context 'given an optional expression' do
|
389
|
+
it 'parses as a Repeat with optional bounds' do
|
390
|
+
matching(' expr? ').as(:expression).
|
391
|
+
should result_in(Repeat[Apply[:expr], 0, 1]).at(6)
|
392
|
+
end
|
393
|
+
end
|
394
|
+
|
395
|
+
context 'given a zero-or-more expression' do
|
396
|
+
it 'parses as a Repeat with zero-or-more bounds' do
|
397
|
+
matching(' expr* ').as(:expression).
|
398
|
+
should result_in(Repeat[Apply[:expr], 0, nil]).at(6)
|
399
|
+
end
|
400
|
+
end
|
401
|
+
|
402
|
+
context 'given a one-or-more expression' do
|
403
|
+
it 'parses as a Repeat with one-or-more bounds' do
|
404
|
+
matching(' expr+ ').as(:expression).
|
405
|
+
should result_in(Repeat[Apply[:expr], 1, nil]).at(6)
|
406
|
+
end
|
407
|
+
end
|
408
|
+
|
409
|
+
context 'given a generalized repeat expression' do
|
410
|
+
context 'with a single count' do
|
411
|
+
it 'parses as a Repeat with the count as both lower and upper bounds' do
|
412
|
+
matching(' expr 2 ').as(:expression).
|
413
|
+
should result_in(Repeat[Apply[:expr], 2, 2]).at(7)
|
414
|
+
end
|
415
|
+
end
|
416
|
+
|
417
|
+
context 'with a range' do
|
418
|
+
it 'parses as a Repeat with lower and upper bounds' do
|
419
|
+
matching(' expr 2..4 ').as(:expression).
|
420
|
+
should result_in(Repeat[Apply[:expr], 2, 4]).at(10)
|
421
|
+
end
|
422
|
+
|
423
|
+
context 'with no upper bound' do
|
424
|
+
it 'parses as a Repeat with no upper bound' do
|
425
|
+
matching(' expr 2.. ').as(:expression).
|
426
|
+
should result_in(Repeat[Apply[:expr], 2, nil]).at(9)
|
427
|
+
end
|
428
|
+
end
|
429
|
+
end
|
430
|
+
|
431
|
+
context 'with an "?" suffix' do
|
432
|
+
it 'parses as an optional Repeat' do
|
433
|
+
matching(' expr 3.. ? ').as(:expression).
|
434
|
+
should result_in(Repeat[Apply[:expr], 3, nil].optional).at(11)
|
435
|
+
end
|
436
|
+
end
|
437
|
+
end
|
438
|
+
|
439
|
+
context 'given a zero-or-more list expression' do
|
440
|
+
it 'parses as a ListParser with zero-or-more bounds' do
|
441
|
+
matching(' expr *, ";" ').as(:expression).
|
442
|
+
should result_in(ListParser[Apply[:expr], Match[/;/], 0, nil]).at(12)
|
443
|
+
end
|
444
|
+
end
|
445
|
+
|
446
|
+
context 'given a one-or-more list expression' do
|
447
|
+
it 'parses as a ListParser with one-or-more bounds' do
|
448
|
+
matching(' expr +, ";" ').as(:expression).
|
449
|
+
should result_in(ListParser[Apply[:expr], Match[/;/], 1, nil]).at(12)
|
450
|
+
end
|
451
|
+
end
|
452
|
+
|
453
|
+
context 'given a generalized list expression' do
|
454
|
+
context 'with a single count' do
|
455
|
+
it 'parses as a ListParser with the count as both lower and upper bounds' do
|
456
|
+
matching(' expr 2, ";" ').as(:expression).
|
457
|
+
should result_in(ListParser[Apply[:expr], Match[/;/], 2, 2]).at(12)
|
458
|
+
end
|
459
|
+
end
|
460
|
+
|
461
|
+
context 'with a range' do
|
462
|
+
it 'parses as a ListParser with lower and upper bounds' do
|
463
|
+
matching(' expr 2..4, ";" ').as(:expression).
|
464
|
+
should result_in(ListParser[Apply[:expr], Match[/;/], 2, 4]).at(15)
|
465
|
+
end
|
466
|
+
|
467
|
+
context 'with no upper bound' do
|
468
|
+
it 'parses as a Repeat with no upper bound' do
|
469
|
+
matching(' expr 2.., ";" ').as(:expression).
|
470
|
+
should result_in(ListParser[Apply[:expr], Match[/;/], 2, nil]).at(14)
|
471
|
+
end
|
472
|
+
end
|
473
|
+
end
|
474
|
+
end
|
475
|
+
|
476
|
+
context 'given a sequence expression' do
|
477
|
+
it 'parses as a Sequence' do
|
478
|
+
matching(' name "=" value ').as(:expression).
|
479
|
+
should result_in(Sequence[Apply[:name], Match[%r{=}], Apply[:value]]).at(15)
|
480
|
+
end
|
481
|
+
|
482
|
+
context 'with a nested sequence expression' do
|
483
|
+
it 'parses as a nested Sequence' do
|
484
|
+
matching(' a (b c) d ').as(:expression).
|
485
|
+
should result_in(Sequence[
|
486
|
+
Apply[:a],
|
487
|
+
Sequence[Apply[:b], Apply[:c]],
|
488
|
+
Apply[:d]
|
489
|
+
]).at(10)
|
490
|
+
end
|
491
|
+
end
|
492
|
+
|
493
|
+
context 'with a semantic result' do
|
494
|
+
it 'parses as a Sequence with a SemanticAction' do
|
495
|
+
matching(' a b ^{|a,b| a + b } ').as(:expression).
|
496
|
+
should result_in(Sequence[
|
497
|
+
Apply[:a],
|
498
|
+
Apply[:b],
|
499
|
+
SemanticAction['|a,b| a + b']
|
500
|
+
]).at(20)
|
501
|
+
end
|
502
|
+
end
|
503
|
+
|
504
|
+
context 'with a semantic side-effect' do
|
505
|
+
it 'parses as a Sequence with a Skip of a SemanticAction' do
|
506
|
+
matching(' a b ~{|a,b| a + b } ').as(:expression).
|
507
|
+
should result_in(Sequence[
|
508
|
+
Apply[:a],
|
509
|
+
Apply[:b],
|
510
|
+
Skip[SemanticAction['|a,b| a + b']]
|
511
|
+
]).at(20)
|
512
|
+
end
|
513
|
+
end
|
514
|
+
end
|
515
|
+
|
516
|
+
context 'given an attributed expression' do
|
517
|
+
|
518
|
+
context 'with a single term and a semantic action' do
|
519
|
+
it 'parses as an AttributedSequence' do
|
520
|
+
matching(' digits {|_| _.to_i} ').as(:expression).
|
521
|
+
should result_in(AttributedSequence[
|
522
|
+
Apply[:digits], SemanticAction['|_| _.to_i']
|
523
|
+
]).at(20)
|
524
|
+
end
|
525
|
+
end
|
526
|
+
|
527
|
+
context 'with a single term and a node action' do
|
528
|
+
|
529
|
+
context 'with just a class name' do
|
530
|
+
it 'parses as an AttributedSequence' do
|
531
|
+
matching(' expr <Expr> ').as(:expression).
|
532
|
+
should result_in(AttributedSequence[
|
533
|
+
Apply[:expr], NodeAction['Expr']
|
534
|
+
]).at(12)
|
535
|
+
end
|
536
|
+
end
|
537
|
+
|
538
|
+
context 'with a class name and a method name' do
|
539
|
+
it 'parses as an AttributedSequence with the method attribute' do
|
540
|
+
matching(' expr <Expr.create> ').as(:expression).
|
541
|
+
should result_in(AttributedSequence[
|
542
|
+
Apply[:expr], NodeAction['Expr', {:method => 'create'}]
|
543
|
+
]).at(19)
|
544
|
+
end
|
545
|
+
end
|
546
|
+
|
547
|
+
context 'with a class name and a node name' do
|
548
|
+
it 'parses as an AttributedSequence with the node name attribute' do
|
549
|
+
matching(' expr <Expr "EXPR"> ').as(:expression).
|
550
|
+
should result_in(AttributedSequence[
|
551
|
+
Apply[:expr],
|
552
|
+
NodeAction['Expr', {:node_attrs => {:name => 'EXPR'}}]
|
553
|
+
]).at(19)
|
554
|
+
end
|
555
|
+
end
|
556
|
+
|
557
|
+
context 'with class, method and node names' do
|
558
|
+
it 'parses as an AttributedSequence with the method and node name attributes' do
|
559
|
+
matching(' expr <Expr.create "EXPR"> ').as(:expression).
|
560
|
+
should result_in(AttributedSequence[
|
561
|
+
Apply[:expr],
|
562
|
+
NodeAction['Expr', { :method => 'create',
|
563
|
+
:node_attrs => {:name => 'EXPR'} }]
|
564
|
+
]).at(26)
|
565
|
+
end
|
566
|
+
end
|
567
|
+
|
568
|
+
context 'with no names' do
|
569
|
+
it 'parses as an AttributedSequence with a default NodeAction' do
|
570
|
+
matching(' expr <> ').as(:expression).
|
571
|
+
should result_in(AttributedSequence[
|
572
|
+
Apply[:expr], NodeAction['Rattler::Runtime::ParseNode']
|
573
|
+
]).at(8)
|
574
|
+
end
|
575
|
+
end
|
576
|
+
|
577
|
+
context 'with just a node name' do
|
578
|
+
it 'parses as an AttributedSequence with a node name attribute' do
|
579
|
+
matching(' expr <"EXPR"> ').as(:expression).
|
580
|
+
should result_in(AttributedSequence[
|
581
|
+
Apply[:expr],
|
582
|
+
NodeAction['Rattler::Runtime::ParseNode',
|
583
|
+
{:node_attrs => {:name => 'EXPR'}}]
|
584
|
+
]).at(14)
|
585
|
+
end
|
586
|
+
end
|
587
|
+
end
|
588
|
+
|
589
|
+
context 'with multiple terms and a semantic action' do
|
590
|
+
it 'parses as an AttributedSequence' do
|
591
|
+
matching(' name "=" value {|_| _.size }').as(:expression).
|
592
|
+
should result_in(AttributedSequence[
|
593
|
+
Apply[:name],
|
594
|
+
Match[%r{=}],
|
595
|
+
Apply[:value],
|
596
|
+
SemanticAction['|_| _.size']
|
597
|
+
]).at(29)
|
598
|
+
end
|
599
|
+
end
|
600
|
+
|
601
|
+
context 'with multiple terms and a node action' do
|
602
|
+
it 'parses as an AttributedSequence' do
|
603
|
+
matching(' name "=" value <Assign>').as(:expression).
|
604
|
+
should result_in(AttributedSequence[
|
605
|
+
Apply[:name],
|
606
|
+
Match[%r{=}],
|
607
|
+
Apply[:value],
|
608
|
+
NodeAction['Assign']
|
609
|
+
]).at(24)
|
610
|
+
end
|
611
|
+
end
|
612
|
+
end
|
613
|
+
|
614
|
+
context 'given a lone semantic action' do
|
615
|
+
it 'parses as a SemanticAction' do
|
616
|
+
matching(' { 42 } ').as(:expression).
|
617
|
+
should result_in(SemanticAction['42']).at(7)
|
618
|
+
end
|
619
|
+
end
|
620
|
+
|
621
|
+
context 'given a lone node action' do
|
622
|
+
it 'parses as a NodeAction' do
|
623
|
+
matching(' <Foo> ').as(:expression).
|
624
|
+
should result_in(NodeAction['Foo']).at(6)
|
625
|
+
end
|
626
|
+
end
|
627
|
+
|
628
|
+
context 'given a multiple-semantic-attirbuted expression' do
|
629
|
+
it 'parses as nested AttributedSequences' do
|
630
|
+
matching(' digits {|_| _.to_i } {|_| _ * 2 } ').as(:expression).
|
631
|
+
should result_in(AttributedSequence[
|
632
|
+
AttributedSequence[Apply[:digits], SemanticAction['|_| _.to_i']],
|
633
|
+
SemanticAction['|_| _ * 2']
|
634
|
+
]).at(34)
|
635
|
+
end
|
636
|
+
end
|
637
|
+
|
638
|
+
context 'given a multiple-node-attirbuted expression' do
|
639
|
+
it 'parses as nested AttributedSequences' do
|
640
|
+
matching(' digits <Int> <Expr> ').as(:expression).
|
641
|
+
should result_in(AttributedSequence[
|
642
|
+
AttributedSequence[Apply[:digits], NodeAction['Int']],
|
643
|
+
NodeAction['Expr']
|
644
|
+
]).at(20)
|
645
|
+
end
|
646
|
+
end
|
647
|
+
|
648
|
+
context 'given consecutive semantic-attributed expressions' do
|
649
|
+
it 'parses as nested AttributedSequences' do
|
650
|
+
matching(' digits {|_| _.to_i } foo {|_| _ * 2 } ').as(:expression).
|
651
|
+
should result_in(AttributedSequence[
|
652
|
+
AttributedSequence[
|
653
|
+
Apply[:digits], SemanticAction['|_| _.to_i']
|
654
|
+
],
|
655
|
+
Apply[:foo],
|
656
|
+
SemanticAction['|_| _ * 2']
|
657
|
+
]).at(38)
|
658
|
+
end
|
659
|
+
end
|
660
|
+
|
661
|
+
context 'given consecutive semantic-attributed expressions' do
|
662
|
+
it 'parses as nested AttributedSequences' do
|
663
|
+
matching(' digits <Int> foo <Foo> ').as(:expression).
|
664
|
+
should result_in(AttributedSequence[
|
665
|
+
AttributedSequence[
|
666
|
+
Apply[:digits], NodeAction['Int']
|
667
|
+
],
|
668
|
+
Apply[:foo],
|
669
|
+
NodeAction['Foo']
|
670
|
+
]).at(23)
|
671
|
+
end
|
672
|
+
end
|
673
|
+
|
674
|
+
context 'given an ordered choice expression' do
|
675
|
+
it 'parses as a Choice' do
|
676
|
+
matching(' string / number ').as(:expression).
|
677
|
+
should result_in(Choice[Apply[:string], Apply[:number]]).at(16)
|
678
|
+
end
|
679
|
+
|
680
|
+
context 'with sequences' do
|
681
|
+
it 'parses as a Choice of Sequences' do
|
682
|
+
matching(' foo bar / boo far ').as(:expression).
|
683
|
+
should result_in(Choice[
|
684
|
+
Sequence[Apply[:foo], Apply[:bar]],
|
685
|
+
Sequence[Apply[:boo], Apply[:far]]
|
686
|
+
]).at(18)
|
687
|
+
end
|
688
|
+
end
|
689
|
+
end
|
690
|
+
|
691
|
+
it 'skips normal whitespace' do
|
692
|
+
matching(" \n\t foo").as(:expression).should result_in(Apply[:foo]).at(8)
|
693
|
+
end
|
694
|
+
|
695
|
+
it 'skips comments' do
|
696
|
+
matching("\n# a comment\n\t foo").as(:expression).
|
697
|
+
should result_in(Apply[:foo]).at(18)
|
698
|
+
end
|
699
|
+
end
|
700
|
+
end
|