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
@@ -0,0 +1,46 @@
1
+ #
2
+ # = rattler/parsers/back_reference.rb
3
+ #
4
+ # Author:: Jason Arhart
5
+ # Documentation:: Author
6
+ #
7
+
8
+ require 'rattler/parsers'
9
+
10
+ module Rattler::Parsers
11
+ #
12
+ # +BackReference+ matches the labeled result of an earlier match.
13
+ #
14
+ # @author Jason Arhart
15
+ #
16
+ class BackReference < Parser
17
+
18
+ def self.[](ref_label)
19
+ self.new(:ref_label => ref_label.to_sym)
20
+ end
21
+
22
+ def self.parsed(results, *_)
23
+ self[results.first[1..-1]]
24
+ end
25
+
26
+ def parse(scanner, rules, scope={})
27
+ scanner.scan Regexp.compile(Regexp.escape scope[ref_label])
28
+ end
29
+
30
+ def re_expr(scope)
31
+ "/#{re_source scope}/"
32
+ end
33
+
34
+ def re_source(scope)
35
+ '#{' + Regexp.escape(scope[ref_label].to_s) + '}'
36
+ end
37
+
38
+ # @param (see Parser#with_ws)
39
+ # @return (see Parser#with_ws)
40
+ def with_ws(ws)
41
+ ws.skip & self
42
+ end
43
+
44
+ end
45
+
46
+ end
@@ -16,27 +16,26 @@ module Rattler::Parsers
16
16
  #
17
17
  class Choice < Parser
18
18
  include Combining
19
- include MatchJoining
20
-
19
+
21
20
  # @private
22
21
  def self.parsed(results, *_) #:nodoc:
23
22
  results.reduce(:|)
24
23
  end
25
-
24
+
26
25
  # Try each parser in order until one succeeds and return that result.
27
26
  #
28
27
  # @param (see Parser#parse_labeled)
29
28
  #
30
29
  # @return the result of the first parser that matches, or +false+
31
- def parse(scanner, rules, labeled = {})
30
+ def parse(scanner, rules, scope = {})
32
31
  for child in children
33
- if r = child.parse_labeled(scanner, rules, labeled)
32
+ if r = child.parse(scanner, rules, scope)
34
33
  return r
35
34
  end
36
35
  end
37
36
  false
38
37
  end
39
-
38
+
40
39
  # Return a new parser that tries this parser first and if it fails tries
41
40
  # +other+.
42
41
  #
@@ -45,38 +44,6 @@ module Rattler::Parsers
45
44
  def |(other)
46
45
  Choice[(children + [other])]
47
46
  end
48
-
49
- protected
50
-
51
- def optimized_children
52
- join_matches super
53
- end
54
-
55
- def token_optimized_children
56
- join_matches super
57
- end
58
-
59
- def skip_optimized_children
60
- join_matches super
61
- end
62
-
63
- def match_join(matches)
64
- matches.map {|_| _.re.source }.join('|')
65
- end
66
-
67
- def join_matches(parsers)
68
- super flatten_choices(parsers)
69
- end
70
-
71
- private
72
-
73
- def flatten_choices(parsers)
74
- if parsers.all? {|_| Choice === _ }
75
- parsers.map {|_| _.to_a }.reduce(:+)
76
- else
77
- parsers
78
- end
79
- end
80
-
47
+
81
48
  end
82
49
  end
@@ -0,0 +1,32 @@
1
+ #
2
+ # = rattler/parsers/rule_set.rb
3
+ #
4
+ # Author:: Jason Arhart
5
+ # Documentation:: Author
6
+ #
7
+
8
+ require 'rattler/parsers'
9
+
10
+ module Rattler::Parsers
11
+ class CombinatorParser < Rattler::Runtime::Parser
12
+
13
+ def self.as_class(start_rule, rule_set)
14
+ new_class = Class.new(self)
15
+ new_class.send :define_method, :initialize do |source|
16
+ super source, start_rule, rule_set
17
+ end
18
+ new_class
19
+ end
20
+
21
+ def initialize(source, start_rule, rule_set)
22
+ super source
23
+ @start_rule = start_rule
24
+ @rule_set = rule_set
25
+ end
26
+
27
+ def __parse__
28
+ @start_rule.parse(@scanner, @rule_set)
29
+ end
30
+
31
+ end
32
+ end
@@ -8,40 +8,14 @@
8
8
  module Rattler::Parsers
9
9
  # @private
10
10
  module Combining #:nodoc:
11
-
11
+
12
12
  def capturing?
13
13
  @capturing ||= any? {|child| child.capturing? }
14
14
  end
15
-
15
+
16
16
  def with_ws(ws)
17
17
  self.class.new(children.map {|_| _.with_ws(ws) }, attrs)
18
18
  end
19
-
20
- def optimized
21
- self.class.new(optimized_children, attrs)
22
- end
23
-
24
- def token_optimized
25
- self.class.new(token_optimized_children, attrs)
26
- end
27
-
28
- def skip_optimized
29
- self.class.new(skip_optimized_children, attrs)
30
- end
31
-
32
- protected
33
-
34
- def optimized_children
35
- children.map {|_| _.optimized }
36
- end
37
-
38
- def token_optimized_children
39
- children.map {|_| _.token_optimized }
40
- end
41
-
42
- def skip_optimized_children
43
- children.map {|_| _.skip_optimized }
44
- end
45
-
19
+
46
20
  end
47
21
  end
@@ -16,16 +16,16 @@ module Rattler::Parsers
16
16
  #
17
17
  class DirectAction < Parser
18
18
  include Combining
19
-
19
+
20
20
  def self.[](child, code)
21
21
  self.new(child, :code => code)
22
22
  end
23
-
23
+
24
24
  # @private
25
25
  def self.parsed(results, *_) #:nodoc:
26
26
  self[*results]
27
27
  end
28
-
28
+
29
29
  # If the wrapped parser matches at the parse position, return the result
30
30
  # of applying the symantic action, otherwise return a false value.
31
31
  #
@@ -33,48 +33,45 @@ module Rattler::Parsers
33
33
  #
34
34
  # @return the result of applying the symantic action, or a false value if
35
35
  # the parse failed.
36
- def parse(scanner, rules, l = {})
37
- labeled = {}
38
- if result = child.parse(scanner, rules, labeled)
36
+ def parse(scanner, rules, scope = {})
37
+ if result = parse_child(child, scanner, rules, scope) {|_| scope = _ }
39
38
  if not capturing?
40
39
  apply([])
41
40
  elsif result.respond_to?(:to_ary)
42
- apply(result, labeled)
41
+ apply(result, scope)
43
42
  else
44
- apply([result], labeled)
43
+ apply([result], scope)
45
44
  end
46
45
  end
47
46
  end
48
-
47
+
49
48
  def bindable_code
50
49
  @bindable_code ||= ActionCode.new(code)
51
50
  end
52
-
53
- def bind(*args)
54
- bindable_code.bind(*args)
55
- end
56
-
57
- # @private
58
- def token_optimized #:nodoc:
59
- child.token_optimized
60
- end
61
-
62
- # @private
63
- def skip_optimized #:nodoc:
64
- child.skip_optimized
51
+
52
+ def bind(scope, bind_args)
53
+ bindable_code.bind(scope, bind_args)
65
54
  end
66
-
55
+
67
56
  private
68
-
69
- def apply(results, labeled={})
70
- l = {}
71
- labeled.each {|k, v| l[k] = v.inspect }
57
+
58
+ def parse_child(child, scanner, rules, scope)
59
+ if child.is_a? Sequence
60
+ child.parse_and_yield_scope(scanner, rules, scope) {|_| yield _ }
61
+ else
62
+ child.parse(scanner, rules, scope) {|_| yield _ }
63
+ end
64
+ end
65
+
66
+ def apply(results, scope={})
67
+ code_scope = {}
68
+ scope.each {|k, v| code_scope[k] = v.inspect }
72
69
  if child.variable_capture_count?
73
- eval(bind([results.inspect], l))
70
+ eval(bind(code_scope, [results.inspect]))
74
71
  else
75
- eval(bind(results.map {|_| _.inspect }, l))
72
+ eval(bind(code_scope, results.map {|_| _.inspect }))
76
73
  end
77
74
  end
78
-
75
+
79
76
  end
80
77
  end
@@ -13,33 +13,19 @@ module Rattler::Parsers
13
13
  # and vice versa.
14
14
  #
15
15
  class Disallow < Predicate
16
-
16
+
17
17
  # Succeed and return +true+ if and only if decorated parser fails. Never
18
18
  # consumes any input.
19
19
  #
20
20
  # @param (see Parser#parse_labeled)
21
21
  #
22
22
  # @return [Boolean] +true+ if the decorated parser fails
23
- def parse(scanner, rules, labeled = {})
23
+ def parse(scanner, rules, scope = {})
24
24
  pos = scanner.pos
25
- result = !child.parse(scanner, rules)
25
+ result = !child.parse(scanner, rules, scope)
26
26
  scanner.pos = pos
27
27
  result
28
28
  end
29
-
30
- # Return a parser that parses identically but may have a more optimized
31
- # structure.
32
- #
33
- # @return a parser that parses identically but may have a more optimized
34
- # structure
35
- def optimized
36
- Disallow[child.optimized]
37
- end
38
-
39
- # @private
40
- def as_match #:nodoc:
41
- Match[child.disallow_re] if Match === child
42
- end
43
-
29
+
44
30
  end
45
31
  end
@@ -16,19 +16,19 @@ module Rattler::Parsers
16
16
  #
17
17
  class DispatchAction < Parser
18
18
  include Combining
19
-
19
+
20
20
  # @private
21
21
  @@node_defaults = {
22
22
  :target => 'Rattler::Runtime::ParseNode',
23
23
  :method => 'parsed'
24
24
  }
25
-
25
+
26
26
  # @private
27
27
  def self.parsed(results, *_) #:nodoc:
28
28
  attributed, optional_attribute = results
29
29
  self[attributed, optional_attribute.first || @@node_defaults[:target]]
30
30
  end
31
-
31
+
32
32
  # @private
33
33
  def self.parse_attrs_arg(arg) #:nodoc:
34
34
  case arg
@@ -40,7 +40,7 @@ module Rattler::Parsers
40
40
  { :target => arg.to_s.strip }
41
41
  end
42
42
  end
43
-
43
+
44
44
  # Create a new parser that decorates a parser to peform a symantic
45
45
  # on success.
46
46
  #
@@ -60,10 +60,10 @@ module Rattler::Parsers
60
60
  @@node_defaults.each {|k, v| attrs[k] ||= v } unless attrs[:code]
61
61
  @method_name = attrs[:method]
62
62
  end
63
-
63
+
64
64
  # the name of the method used as the symantic action
65
65
  attr_reader :method_name
66
-
66
+
67
67
  # If the wrapped parser matches at the parse position, return the result
68
68
  # of applying the symantic action, otherwise return a false value.
69
69
  #
@@ -71,39 +71,44 @@ module Rattler::Parsers
71
71
  #
72
72
  # @return the result of applying the symantic action, or a false value if
73
73
  # the parse failed.
74
- def parse(scanner, rules, l = {})
75
- labeled = {}
76
- if result = child.parse(scanner, rules, labeled)
74
+ def parse(scanner, rules, scope = {})
75
+ if result = parse_child(child, scanner, rules, scope) {|_| scope = _ }
77
76
  if not capturing?
78
77
  apply([])
79
78
  elsif result.respond_to?(:to_ary)
80
- apply(result, labeled)
79
+ apply(result, scope)
81
80
  else
82
- apply([result], labeled)
81
+ apply([result], scope)
83
82
  end
84
83
  end
85
84
  end
86
-
87
- # @private
88
- def token_optimized #:nodoc:
89
- child.token_optimized
85
+
86
+ def bindable_code
87
+ @bindable_code ||= NodeCode.new(target, method_name)
90
88
  end
91
-
92
- # @private
93
- def skip_optimized #:nodoc:
94
- child.skip_optimized
89
+
90
+ def bind(scope, bind_args)
91
+ bindable_code.bind(scope, bind_args)
95
92
  end
96
-
93
+
97
94
  private
98
-
99
- def apply(results, labeled={})
100
- attrs = labeled.empty? ? {} : {:labeled => labeled}
95
+
96
+ def parse_child(child, scanner, rules, scope)
97
+ if child.is_a? Sequence
98
+ child.parse_and_yield_scope(scanner, rules, scope) {|_| yield _ }
99
+ else
100
+ child.parse(scanner, rules, scope) {|_| yield _ }
101
+ end
102
+ end
103
+
104
+ def apply(results, scope={})
105
+ attrs = scope.empty? ? {} : {:labeled => scope}
101
106
  target_class.send method_name, results, attrs
102
107
  end
103
-
108
+
104
109
  def target_class
105
110
  @target_class ||= target.split('::').inject(Kernel, :const_get)
106
111
  end
107
-
112
+
108
113
  end
109
114
  end
@@ -17,45 +17,36 @@ module Rattler::Parsers
17
17
  #
18
18
  class Label < Parser
19
19
  include Combining
20
-
20
+
21
21
  # @private
22
22
  def self.parsed(results, *_) #:nodoc:
23
23
  self[*results]
24
24
  end
25
-
25
+
26
26
  # Create a new parser that decorates +parser+ and associates +label+ with
27
27
  # +parser+'s parse result on success.
28
28
  def self.[](label, parser)
29
29
  self.new(parser, :label => label.to_sym)
30
30
  end
31
-
31
+
32
32
  # Always +true+
33
33
  # @return true
34
34
  def labeled?
35
35
  true
36
36
  end
37
-
37
+
38
38
  # Delegate to the decorated parser and associate #label with the parse
39
39
  # result if successful.
40
40
  #
41
41
  # @param (see Parser#parse_labeled)
42
42
  #
43
43
  # @return the decorated parser's parse result
44
- def parse(scanner, rules, labeled = {})
45
- child.parse(scanner, rules, labeled)
46
- end
47
-
48
- # Parse and on success associate the label with the parse result if
49
- # +capturing?+.
50
- #
51
- # @param (see Parser#parse_labeled)
52
- # @return (see Parser#parse_labeled)
53
- def parse_labeled(scanner, rules, labeled)
54
- if r = super
55
- labeled[label] = r if capturing?
56
- r
44
+ def parse(scanner, rules, scope = {})
45
+ if result = child.parse(scanner, rules, scope) {|_| scope = _ }
46
+ yield scope.merge(label => result) if block_given?
47
+ result
57
48
  end
58
49
  end
59
-
50
+
60
51
  end
61
52
  end