rattler 0.3.0 → 0.4.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.
Files changed (182) hide show
  1. data/README.rdoc +57 -37
  2. data/features/command_line/dest_option.feature +8 -21
  3. data/features/command_line/lib_option.feature +37 -0
  4. data/features/command_line/parser_generator.feature +7 -4
  5. data/features/grammar/back_reference.feature +37 -0
  6. data/features/grammar/fail.feature +3 -3
  7. data/features/grammar/labels.feature +11 -3
  8. data/features/grammar/list_matching.feature +14 -5
  9. data/features/grammar/literal.feature +30 -4
  10. data/features/grammar/nonterminal.feature +1 -1
  11. data/features/grammar/ordered_choice.feature +2 -2
  12. data/features/grammar/skip_operator.feature +1 -1
  13. data/features/grammar/symantic_action.feature +7 -7
  14. data/features/grammar/whitespace.feature +2 -2
  15. data/features/step_definitions/grammar_steps.rb +2 -2
  16. data/lib/rattler/back_end.rb +1 -0
  17. data/lib/rattler/back_end/compiler.rb +19 -20
  18. data/lib/rattler/back_end/optimizer.rb +100 -0
  19. data/lib/rattler/back_end/optimizer/composite_reducing.rb +18 -0
  20. data/lib/rattler/back_end/optimizer/flatten_choice.rb +31 -0
  21. data/lib/rattler/back_end/optimizer/flatten_sequence.rb +59 -0
  22. data/lib/rattler/back_end/optimizer/flattening.rb +17 -0
  23. data/lib/rattler/back_end/optimizer/inline_regular_rules.rb +46 -0
  24. data/lib/rattler/back_end/optimizer/join_match_capturing_sequence.rb +71 -0
  25. data/lib/rattler/back_end/optimizer/join_match_choice.rb +37 -0
  26. data/lib/rattler/back_end/optimizer/join_match_matching_sequence.rb +38 -0
  27. data/lib/rattler/back_end/optimizer/join_match_sequence.rb +17 -0
  28. data/lib/rattler/back_end/optimizer/join_predicate_bare_match.rb +68 -0
  29. data/lib/rattler/back_end/optimizer/join_predicate_match.rb +17 -0
  30. data/lib/rattler/back_end/optimizer/join_predicate_nested_match.rb +37 -0
  31. data/lib/rattler/back_end/optimizer/join_predicate_or_bare_match.rb +68 -0
  32. data/lib/rattler/back_end/optimizer/join_predicate_or_match.rb +17 -0
  33. data/lib/rattler/back_end/optimizer/join_predicate_or_nested_match.rb +36 -0
  34. data/lib/rattler/back_end/optimizer/match_joining.rb +60 -0
  35. data/lib/rattler/back_end/optimizer/optimization.rb +94 -0
  36. data/lib/rattler/back_end/optimizer/optimization_context.rb +72 -0
  37. data/lib/rattler/back_end/optimizer/optimization_sequence.rb +37 -0
  38. data/lib/rattler/back_end/optimizer/optimize_children.rb +46 -0
  39. data/lib/rattler/back_end/optimizer/reduce_repeat_match.rb +44 -0
  40. data/lib/rattler/back_end/optimizer/remove_meaningless_wrapper.rb +32 -0
  41. data/lib/rattler/back_end/optimizer/simplify_redundant_repeat.rb +43 -0
  42. data/lib/rattler/back_end/optimizer/simplify_token_match.rb +38 -0
  43. data/lib/rattler/back_end/parser_generator.rb +21 -14
  44. data/lib/rattler/back_end/parser_generator/apply_generator.rb +35 -35
  45. data/lib/rattler/back_end/parser_generator/assert_generator.rb +29 -30
  46. data/lib/rattler/back_end/parser_generator/back_reference_generator.rb +93 -0
  47. data/lib/rattler/back_end/parser_generator/choice_generator.rb +33 -49
  48. data/lib/rattler/back_end/parser_generator/direct_action_generator.rb +14 -14
  49. data/lib/rattler/back_end/parser_generator/disallow_generator.rb +29 -30
  50. data/lib/rattler/back_end/parser_generator/dispatch_action_generator.rb +11 -13
  51. data/lib/rattler/back_end/parser_generator/expr_generator.rb +36 -56
  52. data/lib/rattler/back_end/parser_generator/fail_generator.rb +18 -18
  53. data/lib/rattler/back_end/parser_generator/group_match.rb +18 -0
  54. data/lib/rattler/back_end/parser_generator/group_match_generator.rb +76 -0
  55. data/lib/rattler/back_end/parser_generator/label_generator.rb +25 -6
  56. data/lib/rattler/back_end/parser_generator/list1_generator.rb +7 -7
  57. data/lib/rattler/back_end/parser_generator/list_generating.rb +19 -20
  58. data/lib/rattler/back_end/parser_generator/list_generator.rb +5 -5
  59. data/lib/rattler/back_end/parser_generator/match_generator.rb +52 -52
  60. data/lib/rattler/back_end/parser_generator/one_or_more_generator.rb +6 -6
  61. data/lib/rattler/back_end/parser_generator/optional_generator.rb +30 -29
  62. data/lib/rattler/back_end/parser_generator/predicate_propogating.rb +8 -8
  63. data/lib/rattler/back_end/parser_generator/repeat_generating.rb +23 -25
  64. data/lib/rattler/back_end/parser_generator/rule_generator.rb +27 -79
  65. data/lib/rattler/back_end/parser_generator/rule_set_generator.rb +102 -0
  66. data/lib/rattler/back_end/parser_generator/sequence_generator.rb +49 -41
  67. data/lib/rattler/back_end/parser_generator/skip_generator.rb +14 -20
  68. data/lib/rattler/back_end/parser_generator/skip_propogating.rb +4 -4
  69. data/lib/rattler/back_end/parser_generator/sub_generating.rb +6 -0
  70. data/lib/rattler/back_end/parser_generator/token_generator.rb +12 -12
  71. data/lib/rattler/back_end/parser_generator/token_propogating.rb +2 -2
  72. data/lib/rattler/back_end/parser_generator/zero_or_more_generator.rb +4 -4
  73. data/lib/rattler/grammar.rb +4 -3
  74. data/lib/rattler/grammar/analysis.rb +91 -0
  75. data/lib/rattler/grammar/grammar.rb +37 -25
  76. data/lib/rattler/grammar/grammar_parser.rb +19 -11
  77. data/lib/rattler/grammar/metagrammar.rb +569 -800
  78. data/lib/rattler/grammar/rattler.rtlr +162 -144
  79. data/lib/rattler/parsers.rb +5 -1
  80. data/lib/rattler/parsers/action_code.rb +29 -15
  81. data/lib/rattler/parsers/apply.rb +5 -5
  82. data/lib/rattler/parsers/assert.rb +4 -18
  83. data/lib/rattler/parsers/back_reference.rb +46 -0
  84. data/lib/rattler/parsers/choice.rb +6 -39
  85. data/lib/rattler/parsers/combinator_parser.rb +32 -0
  86. data/lib/rattler/parsers/combining.rb +3 -29
  87. data/lib/rattler/parsers/direct_action.rb +27 -30
  88. data/lib/rattler/parsers/disallow.rb +4 -18
  89. data/lib/rattler/parsers/dispatch_action.rb +30 -25
  90. data/lib/rattler/parsers/label.rb +9 -18
  91. data/lib/rattler/parsers/list.rb +3 -34
  92. data/lib/rattler/parsers/list1.rb +4 -36
  93. data/lib/rattler/parsers/list_parser.rb +64 -0
  94. data/lib/rattler/parsers/match.rb +7 -42
  95. data/lib/rattler/parsers/node_code.rb +44 -0
  96. data/lib/rattler/parsers/one_or_more.rb +7 -27
  97. data/lib/rattler/parsers/optional.rb +5 -25
  98. data/lib/rattler/parsers/parser.rb +16 -44
  99. data/lib/rattler/parsers/parser_dsl.rb +13 -3
  100. data/lib/rattler/parsers/predicate.rb +4 -12
  101. data/lib/rattler/parsers/rule.rb +18 -19
  102. data/lib/rattler/parsers/rule_set.rb +63 -0
  103. data/lib/rattler/parsers/sequence.rb +12 -46
  104. data/lib/rattler/parsers/skip.rb +12 -26
  105. data/lib/rattler/parsers/token.rb +6 -21
  106. data/lib/rattler/parsers/zero_or_more.rb +6 -26
  107. data/lib/rattler/runner.rb +66 -28
  108. data/lib/rattler/runtime/extended_packrat_parser.rb +26 -20
  109. data/lib/rattler/runtime/packrat_parser.rb +17 -21
  110. data/lib/rattler/runtime/parser.rb +12 -2
  111. data/lib/rattler/runtime/recursive_descent_parser.rb +3 -11
  112. data/lib/rattler/util.rb +2 -1
  113. data/lib/rattler/util/graphviz.rb +29 -0
  114. data/lib/rattler/util/graphviz/digraph_builder.rb +71 -0
  115. data/lib/rattler/util/graphviz/node_builder.rb +84 -0
  116. data/lib/rattler/util/node.rb +37 -19
  117. data/lib/rattler/util/parser_spec_helper.rb +61 -35
  118. data/spec/rattler/back_end/compiler_spec.rb +6 -860
  119. data/spec/rattler/back_end/optimizer/flatten_choice_spec.rb +70 -0
  120. data/spec/rattler/back_end/optimizer/flatten_sequence_spec.rb +130 -0
  121. data/spec/rattler/back_end/optimizer/inline_regular_rules_spec.rb +80 -0
  122. data/spec/rattler/back_end/optimizer/join_match_capturing_sequence_spec.rb +241 -0
  123. data/spec/rattler/back_end/optimizer/join_match_choice_spec.rb +100 -0
  124. data/spec/rattler/back_end/optimizer/join_match_matching_sequence_spec.rb +112 -0
  125. data/spec/rattler/back_end/optimizer/join_predicate_bare_match_spec.rb +194 -0
  126. data/spec/rattler/back_end/optimizer/join_predicate_nested_match_spec.rb +180 -0
  127. data/spec/rattler/back_end/optimizer/join_predicate_or_bare_match_spec.rb +153 -0
  128. data/spec/rattler/back_end/optimizer/join_predicate_or_nested_match_spec.rb +153 -0
  129. data/spec/rattler/back_end/optimizer/reduce_repeat_match_spec.rb +98 -0
  130. data/spec/rattler/back_end/optimizer/simplify_redundant_repeat_spec.rb +226 -0
  131. data/spec/rattler/back_end/optimizer/simplify_token_match_spec.rb +85 -0
  132. data/spec/rattler/back_end/parser_generator/apply_generator_spec.rb +38 -33
  133. data/spec/rattler/back_end/parser_generator/assert_generator_spec.rb +38 -33
  134. data/spec/rattler/back_end/parser_generator/back_reference_generator_spec.rb +181 -0
  135. data/spec/rattler/back_end/parser_generator/choice_generator_spec.rb +38 -33
  136. data/spec/rattler/back_end/parser_generator/direct_action_generator_spec.rb +38 -33
  137. data/spec/rattler/back_end/parser_generator/disallow_generator_spec.rb +38 -33
  138. data/spec/rattler/back_end/parser_generator/dispatch_action_generator_spec.rb +38 -33
  139. data/spec/rattler/back_end/parser_generator/group_match_generator_spec.rb +185 -0
  140. data/spec/rattler/back_end/parser_generator/label_generator_spec.rb +38 -33
  141. data/spec/rattler/back_end/parser_generator/list1_generator_spec.rb +10 -5
  142. data/spec/rattler/back_end/parser_generator/list_generator_spec.rb +10 -5
  143. data/spec/rattler/back_end/parser_generator/match_generator_spec.rb +38 -33
  144. data/spec/rattler/back_end/parser_generator/one_or_more_generator_spec.rb +38 -33
  145. data/spec/rattler/back_end/parser_generator/optional_generator_spec.rb +38 -33
  146. data/spec/rattler/back_end/parser_generator/rule_generator_spec.rb +13 -46
  147. data/spec/rattler/back_end/parser_generator/rule_set_generator_spec.rb +97 -0
  148. data/spec/rattler/back_end/parser_generator/sequence_generator_spec.rb +38 -33
  149. data/spec/rattler/back_end/parser_generator/skip_generator_spec.rb +38 -33
  150. data/spec/rattler/back_end/parser_generator/token_generator_spec.rb +38 -33
  151. data/spec/rattler/back_end/parser_generator/zero_or_more_generator_spec.rb +39 -34
  152. data/spec/rattler/back_end/shared_compiler_examples.rb +885 -0
  153. data/spec/rattler/grammar/analysis_spec.rb +167 -0
  154. data/spec/rattler/grammar/grammar_parser_spec.rb +169 -179
  155. data/spec/rattler/grammar/grammar_spec.rb +24 -21
  156. data/spec/rattler/parsers/action_code_spec.rb +64 -19
  157. data/spec/rattler/parsers/apply_spec.rb +9 -9
  158. data/spec/rattler/parsers/back_reference_spec.rb +38 -0
  159. data/spec/rattler/parsers/combinator_parser_spec.rb +14 -0
  160. data/spec/rattler/parsers/direct_action_spec.rb +16 -2
  161. data/spec/rattler/parsers/dispatch_action_spec.rb +15 -32
  162. data/spec/rattler/parsers/fail_spec.rb +6 -4
  163. data/spec/rattler/parsers/label_spec.rb +10 -28
  164. data/spec/rattler/parsers/node_code_spec.rb +48 -0
  165. data/spec/rattler/parsers/parser_dsl_spec.rb +1 -1
  166. data/spec/rattler/parsers/rule_set_spec.rb +35 -0
  167. data/spec/rattler/parsers/sequence_spec.rb +15 -24
  168. data/spec/rattler/runtime/extended_packrat_parser_spec.rb +22 -17
  169. data/spec/rattler/runtime/packrat_parser_spec.rb +1 -1
  170. data/spec/rattler/runtime/parse_node_spec.rb +15 -19
  171. data/spec/rattler/runtime/recursive_descent_parser_spec.rb +1 -1
  172. data/spec/rattler/runtime/shared_parser_examples.rb +61 -28
  173. data/spec/rattler/util/graphviz/node_builder_spec.rb +84 -0
  174. data/spec/rattler/util/node_spec.rb +92 -65
  175. data/spec/rattler_spec.rb +16 -16
  176. data/spec/support/combinator_parser_spec_helper.rb +19 -18
  177. data/spec/support/compiler_spec_helper.rb +56 -87
  178. data/spec/support/runtime_parser_spec_helper.rb +6 -14
  179. metadata +117 -22
  180. data/features/grammar/regex.feature +0 -24
  181. data/lib/rattler/parsers/match_joining.rb +0 -67
  182. data/lib/rattler/parsers/rules.rb +0 -43
@@ -1,22 +1,23 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/../../../spec_helper')
2
2
 
3
+ include Rattler::BackEnd::ParserGenerator
3
4
  include Rattler::Parsers
4
5
 
5
- describe Rattler::BackEnd::ParserGenerator::DisallowGenerator do
6
-
6
+ describe DisallowGenerator do
7
+
7
8
  include ParserGeneratorSpecHelper
8
-
9
+
9
10
  let(:disallow) { Disallow[Match[/\d/]] }
10
-
11
+
11
12
  describe '#gen_basic' do
12
-
13
+
13
14
  context 'when nested' do
14
15
  it 'generates nested negative lookahead code' do
15
16
  nested_code {|g| g.gen_basic disallow }.
16
17
  should == '(@scanner.skip(/(?!\d)/) && true)'
17
18
  end
18
19
  end
19
-
20
+
20
21
  context 'when top-level' do
21
22
  it 'generates top level negative lookahead code' do
22
23
  top_level_code {|g| g.gen_basic disallow }.
@@ -24,31 +25,31 @@ describe Rattler::BackEnd::ParserGenerator::DisallowGenerator do
24
25
  end
25
26
  end
26
27
  end
27
-
28
+
28
29
  describe '#gen_assert' do
29
-
30
+
30
31
  context 'when nested' do
31
32
  it 'generates "false"' do
32
33
  nested_code {|g| g.gen_assert disallow }.should == 'false'
33
34
  end
34
35
  end
35
-
36
+
36
37
  context 'when top-level' do
37
38
  it 'generates "false"' do
38
39
  top_level_code {|g| g.gen_assert disallow }.should == 'false'
39
40
  end
40
41
  end
41
42
  end
42
-
43
+
43
44
  describe '#gen_disallow' do
44
-
45
+
45
46
  context 'when nested' do
46
47
  it 'generates nested negative lookahead code' do
47
48
  nested_code {|g| g.gen_disallow disallow }.
48
49
  should == '(@scanner.skip(/(?!\d)/) && true)'
49
50
  end
50
51
  end
51
-
52
+
52
53
  context 'when top-level' do
53
54
  it 'generates top level negative lookahead code' do
54
55
  top_level_code {|g| g.gen_disallow disallow }.
@@ -56,12 +57,14 @@ describe Rattler::BackEnd::ParserGenerator::DisallowGenerator do
56
57
  end
57
58
  end
58
59
  end
59
-
60
+
60
61
  describe '#gen_dispatch_action' do
61
-
62
+
63
+ let(:code) { NodeCode.new('Word', 'parsed') }
64
+
62
65
  context 'when nested' do
63
66
  it 'generates nested negative lookahead code with a dispatch action' do
64
- nested_code {|g| g.gen_dispatch_action disallow, 'Word', 'parsed' }.
67
+ nested_code {|g| g.gen_dispatch_action disallow, code }.
65
68
  should == (<<-CODE).strip
66
69
  begin
67
70
  @scanner.skip(/(?!\\d)/) &&
@@ -70,10 +73,10 @@ end
70
73
  CODE
71
74
  end
72
75
  end
73
-
76
+
74
77
  context 'when top-level' do
75
78
  it 'generates top level negative lookahead code with a dispatch action' do
76
- top_level_code {|g| g.gen_dispatch_action disallow, 'Word', 'parsed' }.
79
+ top_level_code {|g| g.gen_dispatch_action disallow, code }.
77
80
  should == (<<-CODE).strip
78
81
  @scanner.skip(/(?!\\d)/) &&
79
82
  Word.parsed([])
@@ -81,12 +84,14 @@ Word.parsed([])
81
84
  end
82
85
  end
83
86
  end
84
-
87
+
85
88
  describe '#gen_direct_action' do
86
-
89
+
90
+ let(:code) { ActionCode.new(':t') }
91
+
87
92
  context 'when nested' do
88
93
  it 'generates nested negative lookahead code with a direct action' do
89
- nested_code {|g| g.gen_direct_action disallow, ActionCode.new(':t') }.
94
+ nested_code {|g| g.gen_direct_action disallow, code }.
90
95
  should == (<<-CODE).strip
91
96
  begin
92
97
  @scanner.skip(/(?!\\d)/) &&
@@ -95,10 +100,10 @@ end
95
100
  CODE
96
101
  end
97
102
  end
98
-
103
+
99
104
  context 'when top-level' do
100
105
  it 'generates top level negative lookahead code with a direct action' do
101
- top_level_code {|g| g.gen_direct_action disallow, ActionCode.new(':t') }.
106
+ top_level_code {|g| g.gen_direct_action disallow, code }.
102
107
  should == (<<-CODE).strip
103
108
  @scanner.skip(/(?!\\d)/) &&
104
109
  (:t)
@@ -106,9 +111,9 @@ end
106
111
  end
107
112
  end
108
113
  end
109
-
114
+
110
115
  describe '#gen_token' do
111
-
116
+
112
117
  context 'when nested' do
113
118
  it 'generates nested negative lookahead and empty string string code' do
114
119
  nested_code {|g| g.gen_token disallow }.
@@ -120,7 +125,7 @@ end
120
125
  CODE
121
126
  end
122
127
  end
123
-
128
+
124
129
  context 'when top-level' do
125
130
  it 'generates top-level negative lookahead and empty string string code' do
126
131
  top_level_code {|g| g.gen_token disallow }.
@@ -131,16 +136,16 @@ end
131
136
  end
132
137
  end
133
138
  end
134
-
139
+
135
140
  describe '#gen_skip' do
136
-
141
+
137
142
  context 'when nested' do
138
143
  it 'generates nested negative lookahead code' do
139
144
  nested_code {|g| g.gen_skip disallow }.
140
145
  should == '(@scanner.skip(/(?!\d)/) && true)'
141
146
  end
142
147
  end
143
-
148
+
144
149
  context 'when top-level' do
145
150
  it 'generates top level negative lookahead code' do
146
151
  top_level_code {|g| g.gen_skip disallow }.
@@ -148,32 +153,32 @@ end
148
153
  end
149
154
  end
150
155
  end
151
-
156
+
152
157
  describe '#gen_intermediate' do
153
158
  it 'generates intermediate negative lookahead code' do
154
159
  nested_code {|g| g.gen_intermediate disallow }.
155
160
  should == '@scanner.skip(/(?!\d)/)'
156
161
  end
157
162
  end
158
-
163
+
159
164
  describe '#gen_intermediate_assert' do
160
165
  it 'generates "false"' do
161
166
  nested_code {|g| g.gen_intermediate_assert disallow }.should == 'false'
162
167
  end
163
168
  end
164
-
169
+
165
170
  describe '#gen_intermediate_disallow' do
166
171
  it 'generates intermediate negative lookahead code' do
167
172
  nested_code {|g| g.gen_intermediate_disallow disallow }.
168
173
  should == '@scanner.skip(/(?!\d)/)'
169
174
  end
170
175
  end
171
-
176
+
172
177
  describe '#gen_intermediate_skip' do
173
178
  it 'generates intermediate negative lookahead code' do
174
179
  nested_code {|g| g.gen_intermediate_skip disallow }.
175
180
  should == '@scanner.skip(/(?!\d)/)'
176
181
  end
177
182
  end
178
-
183
+
179
184
  end
@@ -1,15 +1,16 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/../../../spec_helper')
2
2
 
3
+ include Rattler::BackEnd::ParserGenerator
3
4
  include Rattler::Parsers
4
5
 
5
- describe Rattler::BackEnd::ParserGenerator::DispatchActionGenerator do
6
-
6
+ describe DispatchActionGenerator do
7
+
7
8
  include ParserGeneratorSpecHelper
8
-
9
+
9
10
  let(:action) { DispatchAction[Match[/\w+/]] }
10
-
11
+
11
12
  describe '#gen_basic' do
12
-
13
+
13
14
  context 'when nested' do
14
15
  it 'generates nested matching code with a dispatch action' do
15
16
  nested_code {|g| g.gen_basic action }.
@@ -21,7 +22,7 @@ end
21
22
  CODE
22
23
  end
23
24
  end
24
-
25
+
25
26
  context 'when top-level' do
26
27
  it 'generates top level matching code with a dispatch action' do
27
28
  top_level_code {|g| g.gen_basic action }.
@@ -32,16 +33,16 @@ Rattler::Runtime::ParseNode.parsed([r])
32
33
  end
33
34
  end
34
35
  end
35
-
36
+
36
37
  describe '#gen_assert' do
37
-
38
+
38
39
  context 'when nested' do
39
40
  it 'generates nested positive lookahead code' do
40
41
  nested_code {|g| g.gen_assert action }.
41
42
  should == '(@scanner.skip(/(?=\w+)/) && true)'
42
43
  end
43
44
  end
44
-
45
+
45
46
  context 'when top-level' do
46
47
  it 'generates top level positive lookahead code' do
47
48
  top_level_code {|g| g.gen_assert action }.
@@ -49,16 +50,16 @@ Rattler::Runtime::ParseNode.parsed([r])
49
50
  end
50
51
  end
51
52
  end
52
-
53
+
53
54
  describe '#gen_disallow' do
54
-
55
+
55
56
  context 'when nested' do
56
57
  it 'generates nested negative lookahead code' do
57
58
  nested_code {|g| g.gen_disallow action }.
58
59
  should == '(@scanner.skip(/(?!\w+)/) && true)'
59
60
  end
60
61
  end
61
-
62
+
62
63
  context 'when top-level' do
63
64
  it 'generates top level negative lookahead code' do
64
65
  top_level_code {|g| g.gen_disallow action }.
@@ -66,12 +67,14 @@ Rattler::Runtime::ParseNode.parsed([r])
66
67
  end
67
68
  end
68
69
  end
69
-
70
+
70
71
  describe '#gen_dispatch_action' do
71
-
72
+
73
+ let(:code) { NodeCode.new('Word', 'parsed') }
74
+
72
75
  context 'when nested' do
73
76
  it 'generates nested matching code with nested dispatch actions' do
74
- nested_code {|g| g.gen_dispatch_action action, 'Word', 'parsed' }.
77
+ nested_code {|g| g.gen_dispatch_action action, code }.
75
78
  should == (<<-CODE).strip
76
79
  begin
77
80
  (r = begin
@@ -83,10 +86,10 @@ end
83
86
  CODE
84
87
  end
85
88
  end
86
-
89
+
87
90
  context 'when top-level' do
88
91
  it 'generates top level matching code with nested dispatch actions' do
89
- top_level_code {|g| g.gen_dispatch_action action, 'Word', 'parsed' }.
92
+ top_level_code {|g| g.gen_dispatch_action action, code }.
90
93
  should == (<<-CODE).strip
91
94
  (r = begin
92
95
  (r = @scanner.scan(/\\w+/)) &&
@@ -97,12 +100,14 @@ Word.parsed([r])
97
100
  end
98
101
  end
99
102
  end
100
-
103
+
101
104
  describe '#gen_direct_action' do
102
-
105
+
106
+ let(:code) { ActionCode.new('|_| _.children') }
107
+
103
108
  context 'when nested' do
104
109
  it 'generates nested matching code with a dispatch action and a direct action' do
105
- nested_code {|g| g.gen_direct_action action, ActionCode.new('|_| _.children') }.
110
+ nested_code {|g| g.gen_direct_action action, code }.
106
111
  should == (<<-CODE).strip
107
112
  begin
108
113
  (r = begin
@@ -114,10 +119,10 @@ end
114
119
  CODE
115
120
  end
116
121
  end
117
-
122
+
118
123
  context 'when top-level' do
119
124
  it 'generates top level matching code with a dispatch action and a direct action' do
120
- top_level_code {|g| g.gen_direct_action action, ActionCode.new('|_| _.children') }.
125
+ top_level_code {|g| g.gen_direct_action action, code }.
121
126
  should == (<<-CODE).strip
122
127
  (r = begin
123
128
  (r = @scanner.scan(/\\w+/)) &&
@@ -128,16 +133,16 @@ end) &&
128
133
  end
129
134
  end
130
135
  end
131
-
136
+
132
137
  describe '#gen_token' do
133
-
138
+
134
139
  context 'when nested' do
135
140
  it 'generates nested token matching code' do
136
141
  nested_code {|g| g.gen_token action }.
137
142
  should == '@scanner.scan(/\w+/)'
138
143
  end
139
144
  end
140
-
145
+
141
146
  context 'when top-level' do
142
147
  it 'generates top level token matching code' do
143
148
  top_level_code {|g| g.gen_token action }.
@@ -145,16 +150,16 @@ end) &&
145
150
  end
146
151
  end
147
152
  end
148
-
153
+
149
154
  describe '#gen_skip' do
150
-
155
+
151
156
  context 'when nested' do
152
157
  it 'generates nested skipping code' do
153
158
  nested_code {|g| g.gen_skip action }.
154
159
  should == '(@scanner.skip(/\w+/) && true)'
155
160
  end
156
161
  end
157
-
162
+
158
163
  context 'when top-level' do
159
164
  it 'generates top level skipping code' do
160
165
  top_level_code {|g| g.gen_skip action }.
@@ -162,7 +167,7 @@ end) &&
162
167
  end
163
168
  end
164
169
  end
165
-
170
+
166
171
  describe '#gen_intermediate' do
167
172
  it 'generates nested matching code with a dispatch action' do
168
173
  nested_code {|g| g.gen_intermediate action }.
@@ -174,26 +179,26 @@ end
174
179
  CODE
175
180
  end
176
181
  end
177
-
182
+
178
183
  describe '#gen_intermediate_assert' do
179
184
  it 'generates intermediate positive lookahead code' do
180
185
  nested_code {|g| g.gen_intermediate_assert action }.
181
186
  should == '@scanner.skip(/(?=\w+)/)'
182
187
  end
183
188
  end
184
-
189
+
185
190
  describe '#gen_intermediate_disallow' do
186
191
  it 'generates intermediate negative lookahead code' do
187
192
  nested_code {|g| g.gen_intermediate_disallow action }.
188
193
  should == '@scanner.skip(/(?!\w+)/)'
189
194
  end
190
195
  end
191
-
196
+
192
197
  describe '#gen_intermediate_skip' do
193
198
  it 'generates intermediate skipping code' do
194
199
  nested_code {|g| g.gen_intermediate_skip action }.
195
200
  should == '@scanner.skip(/\w+/)'
196
201
  end
197
202
  end
198
-
203
+
199
204
  end
@@ -0,0 +1,185 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../../spec_helper')
2
+
3
+ include Rattler::BackEnd::ParserGenerator
4
+ include Rattler::Parsers
5
+
6
+ describe GroupMatchGenerator do
7
+
8
+ include ParserGeneratorSpecHelper
9
+
10
+ let(:single_group) { GroupMatch[Match[/\s*(\w+)/], {:num_groups => 1}] }
11
+
12
+ let(:multi_group) { GroupMatch[Match[/\s*(\w+)\s+(\w+)/], {:num_groups => 2}] }
13
+
14
+ describe '#gen_basic' do
15
+
16
+ context 'given a single-group match' do
17
+
18
+ context 'when nested' do
19
+ it 'generates nested regex group matching code returning the group' do
20
+ nested_code {|g| g.gen_basic single_group }.
21
+ should == (<<-CODE).strip
22
+ begin
23
+ @scanner.skip(/\\s*(\\w+)/) &&
24
+ @scanner[1]
25
+ end
26
+ CODE
27
+ end
28
+ end
29
+
30
+ context 'when top-level' do
31
+ it 'generates top-level regex group matching code returning the group' do
32
+ top_level_code {|g| g.gen_basic single_group }.
33
+ should == (<<-CODE).strip
34
+ @scanner.skip(/\\s*(\\w+)/) &&
35
+ @scanner[1]
36
+ CODE
37
+ end
38
+ end
39
+ end
40
+
41
+ context 'given a multi-group match' do
42
+
43
+ context 'when nested' do
44
+ it 'generates nested regex matching code returning an array of groups' do
45
+ nested_code {|g| g.gen_basic multi_group }.
46
+ should == (<<-CODE).strip
47
+ begin
48
+ @scanner.skip(/\\s*(\\w+)\\s+(\\w+)/) &&
49
+ [@scanner[1], @scanner[2]]
50
+ end
51
+ CODE
52
+ end
53
+ end
54
+
55
+ context 'when top-level' do
56
+ it 'generates top-level regex matching code returning an array of groups' do
57
+ top_level_code {|g| g.gen_basic multi_group }.
58
+ should == (<<-CODE).strip
59
+ @scanner.skip(/\\s*(\\w+)\\s+(\\w+)/) &&
60
+ [@scanner[1], @scanner[2]]
61
+ CODE
62
+ end
63
+ end
64
+ end
65
+ end
66
+
67
+ describe '#gen_dispatch_action' do
68
+
69
+ let(:code) { NodeCode.new('Word', 'parsed') }
70
+
71
+ context 'given a single-group match' do
72
+
73
+ let(:match) { single_group }
74
+
75
+ context 'when nested' do
76
+ it 'generates nested regex group matching code with a dispatch action' do
77
+ nested_code {|g| g.gen_dispatch_action match, code }.
78
+ should == (<<-CODE).strip
79
+ begin
80
+ @scanner.skip(/\\s*(\\w+)/) &&
81
+ Word.parsed([@scanner[1]])
82
+ end
83
+ CODE
84
+ end
85
+ end
86
+
87
+ context 'when top-level' do
88
+ it 'generates top-level regex group matching code with a dispatch action' do
89
+ top_level_code {|g| g.gen_dispatch_action match, code }.
90
+ should == (<<-CODE).strip
91
+ @scanner.skip(/\\s*(\\w+)/) &&
92
+ Word.parsed([@scanner[1]])
93
+ CODE
94
+ end
95
+ end
96
+ end
97
+
98
+ context 'given a multi-group match' do
99
+
100
+ let(:match) { multi_group }
101
+
102
+ context 'when nested' do
103
+ it 'generates nested regex group matching code with a dispatch action' do
104
+ nested_code {|g| g.gen_dispatch_action match, code }.
105
+ should == (<<-CODE).strip
106
+ begin
107
+ @scanner.skip(/\\s*(\\w+)\\s+(\\w+)/) &&
108
+ Word.parsed([@scanner[1], @scanner[2]])
109
+ end
110
+ CODE
111
+ end
112
+ end
113
+
114
+ context 'when top-level' do
115
+ it 'generates top-level regex group matching code with a dispatch action' do
116
+ top_level_code {|g| g.gen_dispatch_action match, code }.
117
+ should == (<<-CODE).strip
118
+ @scanner.skip(/\\s*(\\w+)\\s+(\\w+)/) &&
119
+ Word.parsed([@scanner[1], @scanner[2]])
120
+ CODE
121
+ end
122
+ end
123
+ end
124
+ end
125
+
126
+ describe '#gen_direct_action' do
127
+
128
+ context 'given a single-group match' do
129
+
130
+ let(:match) { single_group }
131
+ let(:code) { ActionCode.new('_.to_sym') }
132
+
133
+ context 'when nested' do
134
+ it 'generates nested regex matching code with a direct action' do
135
+ nested_code {|g| g.gen_direct_action match, code }.
136
+ should == (<<-CODE).strip
137
+ begin
138
+ @scanner.skip(/\\s*(\\w+)/) &&
139
+ (@scanner[1].to_sym)
140
+ end
141
+ CODE
142
+ end
143
+ end
144
+
145
+ context 'when top-level' do
146
+ it 'generates top level regex matching code with a direct action' do
147
+ top_level_code {|g| g.gen_direct_action match, code }.
148
+ should == (<<-CODE).strip
149
+ @scanner.skip(/\\s*(\\w+)/) &&
150
+ (@scanner[1].to_sym)
151
+ CODE
152
+ end
153
+ end
154
+ end
155
+
156
+ context 'given a multi-group match' do
157
+
158
+ let(:match) { multi_group }
159
+ let(:code) { ActionCode.new('_.size') }
160
+
161
+ context 'when nested' do
162
+ it 'generates nested regex matching code with a direct action' do
163
+ nested_code {|g| g.gen_direct_action match, code }.
164
+ should == (<<-CODE).strip
165
+ begin
166
+ @scanner.skip(/\\s*(\\w+)\\s+(\\w+)/) &&
167
+ ([@scanner[1], @scanner[2]].size)
168
+ end
169
+ CODE
170
+ end
171
+ end
172
+
173
+ context 'when top-level' do
174
+ it 'generates top level regex matching code with a direct action' do
175
+ top_level_code {|g| g.gen_direct_action match, code }.
176
+ should == (<<-CODE).strip
177
+ @scanner.skip(/\\s*(\\w+)\\s+(\\w+)/) &&
178
+ ([@scanner[1], @scanner[2]].size)
179
+ CODE
180
+ end
181
+ end
182
+
183
+ end
184
+ end
185
+ end