citrus 2.3.1 → 2.3.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -8,23 +8,19 @@ require 'strscan'
8
8
  module Citrus
9
9
  autoload :File, 'citrus/file'
10
10
 
11
- VERSION = [2, 3, 1]
11
+ # The current version of Citrus as [major, minor, patch].
12
+ VERSION = [2, 3, 2]
12
13
 
13
- # Returns the current version of Citrus as a string.
14
- def self.version
15
- VERSION.join('.')
16
- end
17
-
18
- # A pattern to match any character, including \\n.
14
+ # A pattern to match any character, including newline.
19
15
  DOT = /./m
20
16
 
21
17
  Infinity = 1.0 / 0
22
18
 
23
19
  CLOSE = -1
24
20
 
25
- # Parses the given Citrus +code+ using +options+.
26
- def self.parse(code, options={})
27
- File.parse(code, options)
21
+ # Returns the current version of Citrus as a string.
22
+ def self.version
23
+ VERSION.join('.')
28
24
  end
29
25
 
30
26
  # Evaluates the given Citrus parsing expression grammar +code+ in the global
@@ -37,25 +33,31 @@ module Citrus
37
33
  # end
38
34
  # end
39
35
  # CITRUS
36
+ # # => [MyGrammar]
40
37
  #
41
- def self.eval(code)
42
- parse(code).value
38
+ def self.eval(code, options={})
39
+ File.parse(code, options).value
43
40
  end
44
41
 
45
42
  # Evaluates the given expression and creates a new Rule object from it.
46
43
  #
47
44
  # Citrus.rule('"a" | "b"')
45
+ # # => #<Citrus::Rule: ... >
48
46
  #
49
- def self.rule(expr)
50
- parse(expr, :root => :rule_body).value
47
+ def self.rule(expr, options={})
48
+ File.parse(expr, options.merge(:root => :rule_body)).value
51
49
  end
52
50
 
53
51
  # Loads the grammar from the given +file+ into the global scope using #eval.
54
- def self.load(file)
52
+ #
53
+ # Citrus.load('mygrammar')
54
+ # # => [MyGrammar]
55
+ #
56
+ def self.load(file, options={})
55
57
  file << '.citrus' unless ::File.file?(file)
56
- raise "Cannot find file #{file}" unless ::File.file?(file)
57
- raise "Cannot read file #{file}" unless ::File.readable?(file)
58
- eval(::File.read(file))
58
+ raise ArgumentError, "Cannot find file #{file}" unless ::File.file?(file)
59
+ raise ArgumentError, "Cannot read file #{file}" unless ::File.readable?(file)
60
+ eval(::File.read(file), options)
59
61
  end
60
62
 
61
63
  # A standard error class that all Citrus errors extend.
@@ -157,14 +159,19 @@ module Citrus
157
159
  lines[line_index(pos)]
158
160
  end
159
161
 
162
+ # Returns +true+ when using memoization to cache match results.
163
+ def memoized?
164
+ false
165
+ end
166
+
160
167
  # Returns an array of events for the given +rule+ at the current pointer
161
168
  # position. Objects in this array may be one of three types: a Rule,
162
169
  # Citrus::CLOSE, or a length (integer).
163
170
  def exec(rule, events=[])
164
- index = events.size
165
171
  position = pos
172
+ index = events.size
166
173
 
167
- if rule.exec(self, events).size > index
174
+ if apply_rule(rule, position, events).size > index
168
175
  position += events[-1]
169
176
  @max_offset = position if position > @max_offset
170
177
  end
@@ -177,25 +184,27 @@ module Citrus
177
184
  # Returns the length of a match for the given +rule+ at the current pointer
178
185
  # position, +nil+ if none can be made.
179
186
  def test(rule)
180
- start = pos
181
- events = rule.exec(self)
182
- self.pos = start
187
+ position = pos
188
+ events = apply_rule(rule, position, [])
189
+ self.pos = position
183
190
  events[-1]
184
191
  end
185
192
 
186
- # Returns +true+ when using memoization to cache match results.
187
- def memoized?
188
- false
193
+ private
194
+
195
+ # Appends all events for +rule+ at the given +position+ to +events+.
196
+ def apply_rule(rule, position, events)
197
+ rule.exec(self, events)
189
198
  end
190
199
  end
191
200
 
192
- # A MemoizingInput is an Input that caches segments of the event stream for
201
+ # A MemoizedInput is an Input that caches segments of the event stream for
193
202
  # particular rules in a parse. This technique (also known as "Packrat"
194
203
  # parsing) guarantees parsers will operate in linear time but costs
195
204
  # significantly more in terms of time and memory required to perform a parse.
196
205
  # For more information, please read the paper on Packrat parsing at
197
206
  # http://pdos.csail.mit.edu/~baford/packrat/icfp02/.
198
- class MemoizingInput < Input
207
+ class MemoizedInput < Input
199
208
  def initialize(string)
200
209
  super(string)
201
210
  @cache = {}
@@ -214,31 +223,30 @@ module Citrus
214
223
  super
215
224
  end
216
225
 
217
- def exec(rule, events=[]) # :nodoc:
218
- position = pos
226
+ # Returns +true+ when using memoization to cache match results.
227
+ def memoized?
228
+ true
229
+ end
230
+
231
+ private
232
+
233
+ def apply_rule(rule, position, events) # :nodoc:
219
234
  memo = @cache[rule] ||= {}
220
235
 
221
236
  if memo[position]
222
237
  @cache_hits += 1
238
+ events.concat(memo[position])
223
239
  else
224
- memo[position] = rule.exec(self)
225
- end
240
+ index = events.size
241
+ rule.exec(self, events)
226
242
 
227
- if memo[position].size > 0
228
- events.concat(memo[position])
229
- position += events[-1]
230
- @max_offset = position if position > @max_offset
243
+ # Memoize the result so we can use it next time this same rule is
244
+ # executed at this position.
245
+ memo[position] = events.slice(index, events.size)
231
246
  end
232
247
 
233
- self.pos = position
234
-
235
248
  events
236
249
  end
237
-
238
- # Returns +true+ when using memoization to cache match results.
239
- def memoized?
240
- true
241
- end
242
250
  end
243
251
 
244
252
  # Inclusion of this module into another extends the receiver with the grammar
@@ -281,8 +289,9 @@ module Citrus
281
289
  # option. Otherwise, all options are the same as in Rule#parse.
282
290
  def parse(string, options={})
283
291
  rule_name = options.delete(:root) || root
292
+ raise Error, "No root rule specified" unless rule_name
284
293
  rule = rule(rule_name)
285
- raise 'No rule named "%s"' % rule_name unless rule
294
+ raise Error, "No rule named \"#{rule_name}\"" unless rule
286
295
  rule.parse(string, options)
287
296
  end
288
297
 
@@ -511,7 +520,7 @@ module Citrus
511
520
  mod = Module.new { define_method(:value, &mod) }
512
521
  end
513
522
 
514
- raise ArgumentError unless Module === mod
523
+ raise ArgumentError, "Extension must be a Module" unless Module === mod
515
524
 
516
525
  @extension = mod
517
526
  end
@@ -519,22 +528,29 @@ module Citrus
519
528
  # The module this rule uses to extend new matches.
520
529
  attr_reader :extension
521
530
 
531
+ # The default set of options to use when calling #parse or #test.
532
+ def default_options # :nodoc:
533
+ { :consume => true,
534
+ :memoize => false,
535
+ :offset => 0
536
+ }
537
+ end
538
+
522
539
  # Attempts to parse the given +string+ and return a Match if any can be
523
- # made. The +options+ may contain any of the following keys:
540
+ # made. +options+ may contain any of the following keys:
524
541
  #
525
- # offset:: The offset in +string+ at which to start the parse. Defaults
526
- # to 0.
542
+ # consume:: If this is +true+ a ParseError will be raised unless the
543
+ # entire input string is consumed. Defaults to +true+.
527
544
  # memoize:: If this is +true+ the matches generated during a parse are
528
- # memoized. See Input#memoize! for more information. Defaults to
545
+ # memoized. See MemoizedInput for more information. Defaults to
529
546
  # +false+.
530
- # consume:: If this is +true+ a ParseError will be raised during a parse
531
- # unless the entire input string is consumed. Defaults to
532
- # +true+.
547
+ # offset:: The offset in +string+ at which to start parsing. Defaults
548
+ # to 0.
533
549
  def parse(string, options={})
534
- opts = default_parse_options.merge(options)
550
+ opts = default_options.merge(options)
535
551
 
536
552
  input = if opts[:memoize]
537
- MemoizingInput.new(string)
553
+ MemoizedInput.new(string)
538
554
  else
539
555
  Input.new(string)
540
556
  end
@@ -551,18 +567,13 @@ module Citrus
551
567
  Match.new(string.slice(opts[:offset], length), events)
552
568
  end
553
569
 
554
- # The default set of options to use when parsing.
555
- def default_parse_options # :nodoc:
556
- { :offset => 0,
557
- :memoize => false,
558
- :consume => true
559
- }
560
- end
561
-
562
570
  # Tests whether or not this rule matches on the given +string+. Returns the
563
- # length of the match if any can be made, +nil+ otherwise.
564
- def test(string)
565
- Input.new(string).test(self)
571
+ # length of the match if any can be made, +nil+ otherwise. Accepts the same
572
+ # +options+ as #parse.
573
+ def test(string, options={})
574
+ parse(string, options).length
575
+ rescue ParseError
576
+ nil
566
577
  end
567
578
 
568
579
  # Returns +true+ if this rule is a Terminal.
@@ -1027,7 +1038,7 @@ module Citrus
1027
1038
  events << CLOSE
1028
1039
  events << length
1029
1040
  else
1030
- events.slice!(start, events.size)
1041
+ events.slice!(start, index)
1031
1042
  end
1032
1043
 
1033
1044
  events
@@ -1088,7 +1099,7 @@ module Citrus
1088
1099
  events << CLOSE
1089
1100
  events << length
1090
1101
  else
1091
- events.slice!(start, events.size)
1102
+ events.slice!(start, index)
1092
1103
  end
1093
1104
 
1094
1105
  events
@@ -1380,6 +1391,6 @@ class Object
1380
1391
  namespace = respond_to?(:const_set) ? self : Object
1381
1392
  namespace.const_set(name, Citrus::Grammar.new(&block))
1382
1393
  rescue NameError
1383
- raise ArgumentError, 'Invalid grammar name: %s' % name
1394
+ raise ArgumentError, "Invalid grammar name: #{name}"
1384
1395
  end
1385
1396
  end
@@ -2,8 +2,7 @@ require File.expand_path('../helper', __FILE__)
2
2
 
3
3
  class InputTest < Test::Unit::TestCase
4
4
  def test_memoized?
5
- assert !Input.new('').memoized?
6
- assert MemoizingInput.new('').memoized?
5
+ assert_equal(false, Input.new('').memoized?)
7
6
  end
8
7
 
9
8
  def test_offsets_new
@@ -23,7 +22,7 @@ class InputTest < Test::Unit::TestCase
23
22
  assert_equal("def\n", input.line)
24
23
  end
25
24
 
26
- def test_events
25
+ def test_exec
27
26
  a = Rule.for('a')
28
27
  b = Rule.for('b')
29
28
  c = Rule.for('c')
@@ -56,7 +55,7 @@ class InputTest < Test::Unit::TestCase
56
55
  assert_equal(expected_events, events)
57
56
  end
58
57
 
59
- def test_events2
58
+ def test_exec2
60
59
  a = Rule.for('a')
61
60
  b = Rule.for('b')
62
61
  c = Choice.new([ a, b ])
@@ -100,89 +99,4 @@ class InputTest < Test::Unit::TestCase
100
99
 
101
100
  assert_equal(expected_events, events)
102
101
  end
103
-
104
- grammar :LetterA do
105
- rule :top do
106
- any(:three_as, :two_as, :one_a)
107
- end
108
-
109
- rule :three_as do
110
- rep(:one_a, 3, 3)
111
- end
112
-
113
- rule :two_as do
114
- rep(:one_a, 2, 2)
115
- end
116
-
117
- rule :one_a do
118
- "a"
119
- end
120
- end
121
-
122
- def test_cache_hits1
123
- input = MemoizingInput.new('a')
124
- input.exec(LetterA.rule(:top))
125
- assert_equal(3, input.cache_hits)
126
- end
127
-
128
- def test_cache_hits2
129
- input = MemoizingInput.new('aa')
130
- input.exec(LetterA.rule(:top))
131
- assert_equal(2, input.cache_hits)
132
- end
133
-
134
- def test_cache_hits3
135
- input = MemoizingInput.new('aaa')
136
- input.exec(LetterA.rule(:top))
137
- assert_equal(0, input.cache_hits)
138
- end
139
-
140
- grammar :Addition do
141
- rule :additive do
142
- all(:number, :plus, label(any(:additive, :number), 'term')) {
143
- number.value + term.value
144
- }
145
- end
146
-
147
- rule :number do
148
- all(/[0-9]+/, :space) {
149
- strip.to_i
150
- }
151
- end
152
-
153
- rule :plus do
154
- all('+', :space)
155
- end
156
-
157
- rule :space do
158
- /[ \t]*/
159
- end
160
- end
161
-
162
- def test_match
163
- match = Addition.parse('+', :root => :plus)
164
- assert(match)
165
- assert(match.matches)
166
- assert_equal(2, match.matches.length)
167
-
168
- match = Addition.parse('+ ', :root => :plus)
169
- assert(match)
170
- assert(match.matches)
171
- assert_equal(2, match.matches.length)
172
-
173
- match = Addition.parse('99', :root => :number)
174
- assert(match)
175
- assert(match.matches)
176
- assert_equal(2, match.matches.length)
177
-
178
- match = Addition.parse('99 ', :root => :number)
179
- assert(match)
180
- assert(match.matches)
181
- assert_equal(2, match.matches.length)
182
-
183
- match = Addition.parse('1+2')
184
- assert(match)
185
- assert(match.matches)
186
- assert_equal(3, match.matches.length)
187
- end
188
102
  end
@@ -67,4 +67,53 @@ class MatchTest < Test::Unit::TestCase
67
67
  assert_equal(3, m.matches.length)
68
68
  end
69
69
  end
70
+
71
+ grammar :Addition do
72
+ rule :additive do
73
+ all(:number, :plus, label(any(:additive, :number), 'term')) {
74
+ number.value + term.value
75
+ }
76
+ end
77
+
78
+ rule :number do
79
+ all(/[0-9]+/, :space) {
80
+ strip.to_i
81
+ }
82
+ end
83
+
84
+ rule :plus do
85
+ all('+', :space)
86
+ end
87
+
88
+ rule :space do
89
+ /[ \t]*/
90
+ end
91
+ end
92
+
93
+ def test_matches2
94
+ match = Addition.parse('+', :root => :plus)
95
+ assert(match)
96
+ assert(match.matches)
97
+ assert_equal(2, match.matches.length)
98
+
99
+ match = Addition.parse('+ ', :root => :plus)
100
+ assert(match)
101
+ assert(match.matches)
102
+ assert_equal(2, match.matches.length)
103
+
104
+ match = Addition.parse('99', :root => :number)
105
+ assert(match)
106
+ assert(match.matches)
107
+ assert_equal(2, match.matches.length)
108
+
109
+ match = Addition.parse('99 ', :root => :number)
110
+ assert(match)
111
+ assert(match.matches)
112
+ assert_equal(2, match.matches.length)
113
+
114
+ match = Addition.parse('1+2')
115
+ assert(match)
116
+ assert(match.matches)
117
+ assert_equal(3, match.matches.length)
118
+ end
70
119
  end
@@ -0,0 +1,43 @@
1
+ require File.expand_path('../helper', __FILE__)
2
+
3
+ class MemoizedInputTest < Test::Unit::TestCase
4
+ def test_memoized?
5
+ assert MemoizedInput.new('').memoized?
6
+ end
7
+
8
+ grammar :LetterA do
9
+ rule :top do
10
+ any(:three_as, :two_as, :one_a)
11
+ end
12
+
13
+ rule :three_as do
14
+ rep(:one_a, 3, 3)
15
+ end
16
+
17
+ rule :two_as do
18
+ rep(:one_a, 2, 2)
19
+ end
20
+
21
+ rule :one_a do
22
+ "a"
23
+ end
24
+ end
25
+
26
+ def test_cache_hits1
27
+ input = MemoizedInput.new('a')
28
+ input.exec(LetterA.rule(:top))
29
+ assert_equal(3, input.cache_hits)
30
+ end
31
+
32
+ def test_cache_hits2
33
+ input = MemoizedInput.new('aa')
34
+ input.exec(LetterA.rule(:top))
35
+ assert_equal(2, input.cache_hits)
36
+ end
37
+
38
+ def test_cache_hits3
39
+ input = MemoizedInput.new('aaa')
40
+ input.exec(LetterA.rule(:top))
41
+ assert_equal(0, input.cache_hits)
42
+ end
43
+ end
metadata CHANGED
@@ -3,33 +3,32 @@ name: citrus
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
- - 2
7
- - 3
8
- - 1
9
- version: 2.3.1
6
+ - 2
7
+ - 3
8
+ - 2
9
+ version: 2.3.2
10
10
  platform: ruby
11
11
  authors:
12
- - Michael Jackson
12
+ - Michael Jackson
13
13
  autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-12-31 00:00:00 -08:00
17
+ date: 2011-01-02 00:00:00 -08:00
18
18
  default_executable:
19
19
  dependencies:
20
- - !ruby/object:Gem::Dependency
21
- name: rake
22
- prerelease: false
23
- requirement: &id001 !ruby/object:Gem::Requirement
24
- none: false
25
- requirements:
26
- - - ">="
27
- - !ruby/object:Gem::Version
28
- segments:
29
- - 0
30
- version: "0"
31
- type: :development
32
- version_requirements: *id001
20
+ - !ruby/object:Gem::Dependency
21
+ name: rake
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ version: "0"
30
+ type: :development
31
+ version_requirements: *id001
33
32
  description: Parsing Expressions for Ruby
34
33
  email: mjijackson@gmail.com
35
34
  executables: []
@@ -37,112 +36,112 @@ executables: []
37
36
  extensions: []
38
37
 
39
38
  extra_rdoc_files:
40
- - README
39
+ - README
41
40
  files:
42
- - benchmark/seqpar.citrus
43
- - benchmark/seqpar.gnuplot
44
- - benchmark/seqpar.rb
45
- - doc/background.markdown
46
- - doc/example.markdown
47
- - doc/extras.markdown
48
- - doc/index.markdown
49
- - doc/license.markdown
50
- - doc/links.markdown
51
- - doc/syntax.markdown
52
- - doc/testing.markdown
53
- - examples/calc.citrus
54
- - examples/calc.rb
55
- - examples/ip.citrus
56
- - examples/ip.rb
57
- - lib/citrus/file.rb
58
- - lib/citrus.rb
59
- - test/_files/alias.citrus
60
- - test/_files/grammar1.citrus
61
- - test/_files/grammar2.citrus
62
- - test/_files/rule1.citrus
63
- - test/_files/rule2.citrus
64
- - test/_files/rule3.citrus
65
- - test/_files/super.citrus
66
- - test/_files/super2.citrus
67
- - test/alias_test.rb
68
- - test/and_predicate_test.rb
69
- - test/but_predicate_test.rb
70
- - test/calc_file_test.rb
71
- - test/calc_test.rb
72
- - test/choice_test.rb
73
- - test/extension_test.rb
74
- - test/file_test.rb
75
- - test/grammar_test.rb
76
- - test/helper.rb
77
- - test/input_test.rb
78
- - test/label_test.rb
79
- - test/match_test.rb
80
- - test/multibyte_test.rb
81
- - test/not_predicate_test.rb
82
- - test/parse_error_test.rb
83
- - test/repeat_test.rb
84
- - test/sequence_test.rb
85
- - test/string_terminal_test.rb
86
- - test/super_test.rb
87
- - test/terminal_test.rb
88
- - citrus.gemspec
89
- - Rakefile
90
- - README
41
+ - benchmark/seqpar.citrus
42
+ - benchmark/seqpar.gnuplot
43
+ - benchmark/seqpar.rb
44
+ - doc/background.markdown
45
+ - doc/example.markdown
46
+ - doc/extras.markdown
47
+ - doc/index.markdown
48
+ - doc/license.markdown
49
+ - doc/links.markdown
50
+ - doc/syntax.markdown
51
+ - doc/testing.markdown
52
+ - examples/calc.citrus
53
+ - examples/calc.rb
54
+ - examples/ip.citrus
55
+ - examples/ip.rb
56
+ - lib/citrus.rb
57
+ - lib/citrus/file.rb
58
+ - test/alias_test.rb
59
+ - test/and_predicate_test.rb
60
+ - test/but_predicate_test.rb
61
+ - test/calc_file_test.rb
62
+ - test/calc_test.rb
63
+ - test/choice_test.rb
64
+ - test/extension_test.rb
65
+ - test/file_test.rb
66
+ - test/grammar_test.rb
67
+ - test/helper.rb
68
+ - test/input_test.rb
69
+ - test/label_test.rb
70
+ - test/match_test.rb
71
+ - test/memoized_input_test.rb
72
+ - test/multibyte_test.rb
73
+ - test/not_predicate_test.rb
74
+ - test/parse_error_test.rb
75
+ - test/repeat_test.rb
76
+ - test/sequence_test.rb
77
+ - test/string_terminal_test.rb
78
+ - test/super_test.rb
79
+ - test/terminal_test.rb
80
+ - test/_files/alias.citrus
81
+ - test/_files/grammar1.citrus
82
+ - test/_files/grammar2.citrus
83
+ - test/_files/rule1.citrus
84
+ - test/_files/rule2.citrus
85
+ - test/_files/rule3.citrus
86
+ - test/_files/super.citrus
87
+ - test/_files/super2.citrus
88
+ - citrus.gemspec
89
+ - Rakefile
90
+ - README
91
91
  has_rdoc: true
92
92
  homepage: http://mjijackson.com/citrus
93
93
  licenses: []
94
94
 
95
95
  post_install_message:
96
96
  rdoc_options:
97
- - --line-numbers
98
- - --inline-source
99
- - --title
100
- - Citrus
101
- - --main
102
- - Citrus
97
+ - --line-numbers
98
+ - --inline-source
99
+ - --title
100
+ - Citrus
101
+ - --main
102
+ - Citrus
103
103
  require_paths:
104
- - lib
104
+ - lib
105
105
  required_ruby_version: !ruby/object:Gem::Requirement
106
- none: false
107
106
  requirements:
108
- - - ">="
109
- - !ruby/object:Gem::Version
110
- segments:
111
- - 0
112
- version: "0"
107
+ - - ">="
108
+ - !ruby/object:Gem::Version
109
+ segments:
110
+ - 0
111
+ version: "0"
113
112
  required_rubygems_version: !ruby/object:Gem::Requirement
114
- none: false
115
113
  requirements:
116
- - - ">="
117
- - !ruby/object:Gem::Version
118
- segments:
119
- - 0
120
- version: "0"
114
+ - - ">="
115
+ - !ruby/object:Gem::Version
116
+ segments:
117
+ - 0
118
+ version: "0"
121
119
  requirements: []
122
120
 
123
121
  rubyforge_project:
124
- rubygems_version: 1.3.7
122
+ rubygems_version: 1.3.6
125
123
  signing_key:
126
124
  specification_version: 3
127
125
  summary: Parsing Expressions for Ruby
128
126
  test_files:
129
- - test/alias_test.rb
130
- - test/and_predicate_test.rb
131
- - test/but_predicate_test.rb
132
- - test/calc_file_test.rb
133
- - test/calc_test.rb
134
- - test/choice_test.rb
135
- - test/extension_test.rb
136
- - test/file_test.rb
137
- - test/grammar_test.rb
138
- - test/input_test.rb
139
- - test/label_test.rb
140
- - test/match_test.rb
141
- - test/multibyte_test.rb
142
- - test/not_predicate_test.rb
143
- - test/parse_error_test.rb
144
- - test/repeat_test.rb
145
- - test/sequence_test.rb
146
- - test/string_terminal_test.rb
147
- - test/super_test.rb
148
- - test/terminal_test.rb
127
+ - test/alias_test.rb
128
+ - test/and_predicate_test.rb
129
+ - test/but_predicate_test.rb
130
+ - test/calc_file_test.rb
131
+ - test/calc_test.rb
132
+ - test/choice_test.rb
133
+ - test/extension_test.rb
134
+ - test/file_test.rb
135
+ - test/grammar_test.rb
136
+ - test/input_test.rb
137
+ - test/label_test.rb
138
+ - test/match_test.rb
139
+ - test/memoized_input_test.rb
140
+ - test/multibyte_test.rb
141
+ - test/not_predicate_test.rb
142
+ - test/parse_error_test.rb
143
+ - test/repeat_test.rb
144
+ - test/sequence_test.rb
145
+ - test/string_terminal_test.rb
146
+ - test/super_test.rb
147
+ - test/terminal_test.rb