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
@@ -12,24 +12,26 @@ require 'pathname'
12
12
  module Rattler
13
13
  # <tt>Rattler::Runner</tt> defines the command-line parser generator.
14
14
  class Runner
15
-
15
+
16
16
  ERRNO_USAGE = 1 # Invalid command line arguments
17
17
  ERRNO_READ_ERROR = 2 # Error reading grammar file
18
18
  ERRNO_WRITE_ERROR = 3 # Error writing parser file
19
19
  ERRNO_PARSE_ERROR = 4 # Error parsing grammar
20
20
  ERRNO_GEN_ERROR = 5 # Error generaing ruby code
21
-
21
+
22
22
  # Run the command-line parser
23
23
  #
24
24
  # @param (see #initialize)
25
25
  def self.run(args)
26
26
  self.new(args).run
27
27
  end
28
-
28
+
29
29
  # Create a new command-line parser.
30
30
  #
31
31
  # @param [Array] args the command-line arguments
32
32
  def initialize(args)
33
+ @standalone = false
34
+ @optimize = true
33
35
  options.parse!(args)
34
36
  if args.size == 1
35
37
  @srcfname = Pathname.new(args.shift)
@@ -38,7 +40,7 @@ module Rattler
38
40
  exit ERRNO_USAGE
39
41
  end
40
42
  end
41
-
43
+
42
44
  # Run the command-line parser.
43
45
  def run
44
46
  if result = analyze
@@ -48,48 +50,69 @@ module Rattler
48
50
  exit ERRNO_PARSE_ERROR
49
51
  end
50
52
  end
51
-
53
+
52
54
  private
53
-
55
+
54
56
  def options
55
57
  @options ||= OptionParser.new do |opts|
58
+
56
59
  opts.banner = "Usage: #{File.basename($0)} FILENAME [options]"
60
+
57
61
  opts.separator ''
62
+
63
+ opts.on '-l', '--lib DIRECTORY',
64
+ 'Specify the destination lib directory' do |libdir|
65
+ @libdir = Pathname.new(libdir)
66
+ end
67
+
58
68
  opts.on '-d', '--dest DIRECTORY',
59
- 'Specify the destination directory' do |destdir|
60
- @destdir = Pathname.new(destdir).realpath
69
+ 'Specify an explicit destination directory' do |destdir|
70
+ @destdir = Pathname.new(destdir)
61
71
  end
72
+
62
73
  opts.on '-o', '--output FILENAME',
63
- 'Specify a different output filename' do |ofname|
74
+ 'Specify a different output filename ("-" = STDOUT)' do |ofname|
64
75
  @ofname = ofname
65
76
  end
77
+
66
78
  opts.on '-f', '--force',
67
79
  'Force overwrite if the output file exists' do |f|
68
80
  @force = f
69
81
  end
82
+
83
+ opts.on '-s', '--standalone',
84
+ 'Optimize for use as a standalone parser' do |s|
85
+ @standalone = s
86
+ end
87
+
88
+ opts.on '-n', '--no-optimize',
89
+ 'Disable optimization' do |n|
90
+ @optimize = n
91
+ end
92
+
70
93
  opts.separator ''
94
+
71
95
  opts.on_tail '-h', '--help', 'Show this message' do
72
- puts opts
73
- exit
96
+ abort "#{opts}\n"
74
97
  end
75
98
  end
76
99
  end
77
-
100
+
78
101
  def parser
79
102
  @parser ||= Rattler::Grammar::GrammarParser.new(@srcfname.read)
80
103
  end
81
-
104
+
82
105
  def analyze
83
106
  parser.parse
84
107
  rescue Exception => e
85
108
  puts e
86
109
  exit ERRNO_READ_ERROR
87
110
  end
88
-
111
+
89
112
  def synthesize(g)
90
113
  open_output(g) do |io|
91
114
  begin
92
- io.puts(Rattler::BackEnd::ParserGenerator.code_for(g))
115
+ io.puts code_for(g)
93
116
  rescue Exception => e
94
117
  puts e
95
118
  exit ERRNO_GEN_ERROR
@@ -99,7 +122,15 @@ module Rattler
99
122
  puts e
100
123
  exit ERRNO_WRITE_ERROR
101
124
  end
102
-
125
+
126
+ def code_for(g)
127
+ Rattler::BackEnd::ParserGenerator.code_for g, generator_options
128
+ end
129
+
130
+ def generator_options
131
+ { :standalone => @standalone, :no_optimize => !@optimize }
132
+ end
133
+
103
134
  def open_output(g)
104
135
  if @ofname == '-'
105
136
  yield $stdout
@@ -107,32 +138,39 @@ module Rattler
107
138
  open_to_write(full_dest_name(g)) {|io| yield io }
108
139
  end
109
140
  end
110
-
141
+
111
142
  def report(dest)
112
143
  puts "#{relative_path @srcfname} -> #{relative_path dest}"
113
144
  end
114
-
145
+
115
146
  def open_to_write(dest)
116
- raise "File exists - #{relative_path dest}" if dest.exist? and not @force
147
+ if dest.exist? and not @force
148
+ raise "File exists - #{relative_path dest} (use --force to overwrite)"
149
+ end
117
150
  dest.dirname.mkpath
118
151
  report(dest)
119
152
  dest.open('w') { |f| yield f }
120
153
  end
121
-
154
+
122
155
  def full_dest_name(g)
123
156
  names = g.name.split('::').map {|_| underscore _ }
124
- names[-1] = @ofname || (names[-1] + '.rb')
125
- destdir.join(*names)
157
+ ofname = @ofname || (names[-1] + '.rb')
158
+ if @destdir
159
+ @destdir.join(ofname)
160
+ else
161
+ names[-1] = ofname
162
+ libdir.join(*names)
163
+ end
126
164
  end
127
-
128
- def destdir
129
- @destdir ||= Pathname.getwd
165
+
166
+ def libdir
167
+ @libdir ||= Pathname.getwd
130
168
  end
131
-
169
+
132
170
  def relative_path(p)
133
171
  p.dirname.realpath.relative_path_from(Pathname.getwd) + p.basename
134
172
  end
135
-
173
+
136
174
  # copied shamelessly from ActiveSupport
137
175
  def underscore(camel_cased_word)
138
176
  camel_cased_word.to_s.gsub(/::/, '/').
@@ -141,6 +179,6 @@ module Rattler
141
179
  tr("-", "_").
142
180
  downcase
143
181
  end
144
-
182
+
145
183
  end
146
184
  end
@@ -28,33 +28,39 @@ module Rattler::Runtime
28
28
  @lr_stack = []
29
29
  end
30
30
 
31
- private
32
-
33
- # @private
34
- def apply!(rule_name, start_pos) #:nodoc:
35
- lr = LR.new(false, rule_name, nil)
36
- @lr_stack.push lr
37
- m = inject_memo rule_name, start_pos, lr, start_pos, nil, nil
38
- result = eval_rule rule_name
39
- @lr_stack.pop
40
- if lr.head
41
- m.end_pos = @scanner.pos
42
- lr.seed = result
43
- lr_answer rule_name, start_pos, m
31
+ def apply(rule_name)
32
+ start_pos = @scanner.pos
33
+ if m = memo_lr(rule_name, start_pos)
34
+ recall m, rule_name
44
35
  else
45
- memorize m, result
36
+ lr = LR.new(false, rule_name, nil)
37
+ @lr_stack.push lr
38
+ m = inject_memo rule_name, start_pos, lr, start_pos
39
+ result = eval_rule rule_name
40
+ @lr_stack.pop
41
+ if lr.head
42
+ m.end_pos = @scanner.pos
43
+ lr.seed = result
44
+ lr_answer rule_name, start_pos, m
45
+ else
46
+ save m, result
47
+ end
46
48
  end
47
49
  end
48
50
 
51
+ alias_method :memoize_lr, :apply
52
+
53
+ private
54
+
49
55
  # @private
50
- def memo(rule_name, start_pos) #:nodoc:
51
- m = super
56
+ def memo_lr(rule_name, start_pos) #:nodoc:
57
+ m = memo(rule_name, start_pos)
52
58
  head = @heads[start_pos] or return m
53
59
  if !m && !head.involves?(rule_name)
54
- return inject_memo rule_name, start_pos, false, start_pos, nil, nil
60
+ return inject_fail rule_name, start_pos
55
61
  end
56
62
  if head.eval_set.delete(rule_name)
57
- memorize m, eval_rule(rule_name)
63
+ save m, eval_rule(rule_name)
58
64
  end
59
65
  return m
60
66
  end
@@ -84,7 +90,7 @@ module Rattler::Runtime
84
90
  if head.rule_name == rule_name
85
91
  grow_lr(rule_name, start_pos, m, head) if m.result = m.result.seed
86
92
  else
87
- memorize m, m.result.seed
93
+ save m, m.result.seed
88
94
  end
89
95
  end
90
96
 
@@ -99,7 +105,7 @@ module Rattler::Runtime
99
105
  @heads.delete(start_pos)
100
106
  return recall m, rule_name
101
107
  end
102
- memorize m, result
108
+ save m, result
103
109
  end
104
110
  end
105
111
 
@@ -27,10 +27,6 @@ module Rattler::Runtime
27
27
  @memo = Hash.new {|h, rule_name| h[rule_name] = {} }
28
28
  end
29
29
 
30
- # @private
31
- alias_method :eval_rule, :apply
32
- private :eval_rule
33
-
34
30
  protected
35
31
 
36
32
  # Apply a rule by dispatching to the method associated with the given rule
@@ -47,51 +43,51 @@ module Rattler::Runtime
47
43
  if m = memo(rule_name, start_pos)
48
44
  recall m, rule_name
49
45
  else
50
- apply! rule_name, start_pos
46
+ m = inject_fail rule_name, start_pos
47
+ save m, eval_rule(rule_name)
51
48
  end
52
49
  end
53
50
 
51
+ alias_method :memoize, :apply
52
+
53
+ alias_method :eval_rule, :send
54
+
54
55
  private
55
56
 
56
57
  # @private
57
- def apply!(rule_name, start_pos) #:nodoc:
58
- m = inject_memo rule_name, start_pos, false, start_pos, start_pos, 'left-recursion detected'
59
- memorize m, eval_rule(rule_name)
58
+ def memo(rule_name, start_pos) #:nodoc:
59
+ @memo[rule_name][start_pos]
60
60
  end
61
61
 
62
- def memo(rule_name, start_pos)
63
- @memo[rule_name][start_pos]
62
+ # @private
63
+ def inject_memo(rule_name, start_pos, result, end_pos) #:nodoc:
64
+ @memo[rule_name][start_pos] = MemoEntry.new(result, end_pos)
64
65
  end
65
66
 
66
- def inject_memo(rule_name, start_pos, result, end_pos, failure_pos, failure_msg)
67
- @memo[rule_name][start_pos] = MemoEntry.new(result, end_pos, failure_pos, failure_msg)
67
+ # @private
68
+ def inject_fail(rule_name, fail_pos) #:nodoc:
69
+ @memo[rule_name][fail_pos] = MemoEntry.new(false, fail_pos)
68
70
  end
69
71
 
70
72
  # @private
71
- def memorize(m, result) #:nodoc:
73
+ def save(m, result) #:nodoc:
72
74
  m.end_pos = @scanner.pos
73
- m.failure_pos = @failure_pos
74
- m.failure_msg = @failure_msg
75
75
  m.result = result
76
76
  end
77
77
 
78
78
  # @private
79
79
  def recall(m, rule_name) #:nodoc:
80
80
  @scanner.pos = m.end_pos
81
- @failure_pos = m.failure_pos
82
- @failure_msg = m.failure_msg
83
81
  m.result
84
82
  end
85
83
 
86
84
  # @private
87
85
  class MemoEntry #:nodoc:
88
- def initialize(result, end_pos, failure_pos, failure_msg)
86
+ def initialize(result, end_pos)
89
87
  @result = result
90
88
  @end_pos = end_pos
91
- @failure_pos = failure_pos
92
- @failure_msg = failure_msg
93
89
  end
94
- attr_accessor :result, :end_pos, :failure_pos, :failure_msg
90
+ attr_accessor :result, :end_pos
95
91
  end
96
92
 
97
93
  end
@@ -14,7 +14,7 @@ module Rattler::Runtime
14
14
  #
15
15
  # @author Jason Arhart
16
16
  #
17
- class Parser
17
+ class Parser < Rattler::Util::Node
18
18
 
19
19
  # Parse +source+ and raise a {SyntaxError} if the parse fails.
20
20
  #
@@ -25,6 +25,16 @@ module Rattler::Runtime
25
25
  self.new(source, options).parse!
26
26
  end
27
27
 
28
+ # Parse the entirety of +source+ and raise a {SyntaxError} if the parse
29
+ # fails.
30
+ #
31
+ # @param (see #initialize)
32
+ # @raise (see #parse!)
33
+ # @return (see #parse!)
34
+ def self.parse_fully!(source, options={})
35
+ self.new(source, options).parse_fully!
36
+ end
37
+
28
38
  # Create a new parser to parse +source+.
29
39
  #
30
40
  # @param [String] source the source to parse
@@ -71,7 +81,7 @@ module Rattler::Runtime
71
81
  #
72
82
  # @return (see #parse_fully)
73
83
  def parse_fully!
74
- parse_full or raise_error
84
+ parse_fully or raise_error
75
85
  end
76
86
 
77
87
  # The current parse position
@@ -38,7 +38,7 @@ module Rattler::Runtime
38
38
  # @return (see #apply)
39
39
  #
40
40
  def match(rule_name)
41
- apply(rule_name) or fail { rule_name }
41
+ send @rule_method_names[rule_name] or fail { rule_name }
42
42
  end
43
43
 
44
44
  def method_missing(symbol, *args)
@@ -59,16 +59,8 @@ module Rattler::Runtime
59
59
  match start_rule
60
60
  end
61
61
 
62
- # Apply a rule by dispatching to the method associated with the given rule
63
- # name, which is named by <tt>"match_#{rule_name}"<tt>. This method is
64
- # called by +match+ and should not be called directly.
65
- #
66
- # @param [Symbol] rule_name the name of the rule to apply
67
- #
68
- # @return the result of applying the rule
69
- #
70
- def apply(rule_name)
71
- send @rule_method_names[rule_name]
62
+ def apply(rule_method_name)
63
+ send rule_method_name
72
64
  end
73
65
 
74
66
  end
@@ -12,5 +12,6 @@ module Rattler
12
12
  autoload :LineCounter, 'rattler/util/line_counter'
13
13
  autoload :Node, 'rattler/util/node'
14
14
  autoload :ParserSpecHelper, 'rattler/util/parser_spec_helper'
15
+ autoload :GraphViz, 'rattler/util/graphviz'
15
16
  end
16
- end
17
+ end
@@ -0,0 +1,29 @@
1
+ #
2
+ # = rattler/util/graphviz.rb
3
+ #
4
+ # Author:: Jason Arhart
5
+ # Documentation:: Author
6
+ #
7
+ require 'rattler/util'
8
+
9
+ module Rattler::Util
10
+ #
11
+ # The +GraphViz+ provides utilities to build GraphViz objects representing
12
+ # trees of nodes.
13
+ #
14
+ # @author Jason Arhart
15
+ #
16
+ module GraphViz
17
+
18
+ autoload :DigraphBuilder, 'rattler/util/graphviz/digraph_builder'
19
+ autoload :NodeBuilder, 'rattler/util/graphviz/node_builder'
20
+
21
+ # Return a new +GraphViz+ digraph object representing +root+.
22
+ #
23
+ # @return a new +GraphViz+ digraph object representing +root+
24
+ def self.digraph(root)
25
+ DigraphBuilder.digraph(root)
26
+ end
27
+
28
+ end
29
+ end