rattler 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.rdoc CHANGED
@@ -14,7 +14,7 @@ A language syntax is specified in a grammar using the Rattler syntax. Parser
14
14
  classes and modules can be generated statically using the "rtlr" command or
15
15
  dynamically from strings.
16
16
 
17
- {RDoc}[http://rubydoc.info/gems/rattler/0.4.0/frames]
17
+ {RDoc}[http://rubydoc.info/gems/rattler/0.4.1/frames]
18
18
 
19
19
  == FEATURES:
20
20
 
@@ -4,7 +4,8 @@ Feature: Node Actions
4
4
  expression. A node type is an object (typically a class) that responds to
5
5
  the #parsed method. It means to pass the parse results to #parsed and use
6
6
  the value returned as the parse result. The parse results are passed as an
7
- Array and any attributes are included in a Hash.
7
+ Array and any attributes are included in a Hash. The action can optionally
8
+ include a name.
8
9
 
9
10
  In order to create node objects as parse results
10
11
  As a language designer
@@ -28,4 +29,16 @@ Feature: Node Actions
28
29
  integer <- @DIGIT+ <>
29
30
  """
30
31
  When I parse "42"
31
- Then the parse result should be Rattler::Runtime::ParseNode["42"]
32
+ Then the parse result should be Rattler::Runtime::ParseNode["42"]
33
+
34
+ Scenario: Class and node name
35
+ Given a grammar with:
36
+ """
37
+ expr <- @DIGIT+ ~'+' @DIGIT+ <Expr "sum">
38
+ """
39
+ And a class definition:
40
+ """
41
+ class Expr < Rattler::Runtime::ParseNode; end
42
+ """
43
+ When I parse "42+23"
44
+ Then the parse result should be Expr[["42", "23"], {:name => "sum"}]
@@ -14,5 +14,13 @@ module Rattler::BackEnd::ParserGenerator
14
14
  num_groups
15
15
  end
16
16
 
17
+ def parse(scanner, rules, scope={})
18
+ scanner.scan(re) && if num_groups == 1
19
+ scanner[1]
20
+ else
21
+ (1..num_groups).map {|_| scanner[_] }
22
+ end
23
+ end
24
+
17
25
  end
18
26
  end
@@ -218,8 +218,72 @@ module Rattler
218
218
  @scanner.skip(/(?>(?>(?>[[:space:]])+|(?>\#)(?>(?>[^\n])*))*)((?>(?>(?>(?>[[:space:]])+|(?>\#)(?>(?>[^\n])*))*)(?>(?>[[:lower:]])(?>(?>[[:alnum:]_])*))|(?>(?>(?>[[:space:]])+|(?>\#)(?>(?>[^\n])*))*)(?>(?>(?>(?>[[:upper:]])(?>(?>[[:alnum:]_])*)(?>::))*)(?>[[:upper:]])(?>(?>[[:alnum:]_])*)))(?>(?>(?>\.)(?>(?>(?>(?>[[:space:]])+|(?>\#)(?>(?>[^\n])*))*)(?>(?>[[:lower:]])(?>(?>[[:alnum:]_])*))))?))/) &&
219
219
  @scanner[1]
220
220
  end) ? [r] : [])) &&
221
+ (r0_2 = ((r = begin
222
+ begin
223
+ @scanner.skip(/(?>(?>(?>[[:space:]])+|(?>\#)(?>(?>[^\n])*))*)((?>")(?>(?>(?>\\)(?>.)|[^"])*)(?>"))/) &&
224
+ @scanner[1]
225
+ end ||
226
+ begin
227
+ @scanner.skip(/(?>(?>(?>[[:space:]])+|(?>\#)(?>(?>[^\n])*))*)((?>')(?>(?>(?>\\)(?>.)|[^'])*)(?>'))/) &&
228
+ @scanner[1]
229
+ end ||
230
+ begin
231
+ @scanner.skip(/(?>(?>(?>[[:space:]])+|(?>\#)(?>(?>[^\n])*))*)((?>%\()(?>(?>(?>\\)(?>.)|[^)])*)(?>\)))/) &&
232
+ @scanner[1]
233
+ end ||
234
+ begin
235
+ @scanner.skip(/(?>(?>(?>[[:space:]])+|(?>\#)(?>(?>[^\n])*))*)((?>%\{)(?>(?>(?>\\)(?>.)|[^}])*)(?>\}))/) &&
236
+ @scanner[1]
237
+ end ||
238
+ begin
239
+ @scanner.skip(/(?>(?>(?>[[:space:]])+|(?>\#)(?>(?>[^\n])*))*)((?>%\[)(?>(?>(?>\\)(?>.)|[^\]])*)(?>\]))/) &&
240
+ @scanner[1]
241
+ end ||
242
+ begin
243
+ @scanner.skip(/(?>(?>(?>[[:space:]])+|(?>\#)(?>(?>[^\n])*))*)((?>%<)(?>(?>(?>\\)(?>.)|[^>])*)(?>>))/) &&
244
+ @scanner[1]
245
+ end ||
246
+ begin
247
+ p1 = @scanner.pos
248
+ begin
249
+ @scanner.skip(/(?>(?>[[:space:]])+|(?>\#)(?>(?>[^\n])*))*/) &&
250
+ begin
251
+ p2 = @scanner.pos
252
+ begin
253
+ @scanner.skip(/%/) &&
254
+ (r2_0 = @scanner.scan(/[[:punct:]]/)) &&
255
+ begin
256
+ while begin
257
+ @scanner.skip(/(?>\\)(?>.)/) ||
258
+ begin
259
+ p3 = @scanner.pos
260
+ begin
261
+ @scanner.skip(/(?!#{r2_0})/) &&
262
+ @scanner.skip(/./) &&
263
+ true
264
+ end || begin
265
+ @scanner.pos = p3
266
+ false
267
+ end
268
+ end
269
+ end; end
270
+ true
271
+ end &&
272
+ @scanner.skip(/#{r2_0}/) &&
273
+ @scanner.string[p2...(@scanner.pos)]
274
+ end || begin
275
+ @scanner.pos = p2
276
+ false
277
+ end
278
+ end
279
+ end || begin
280
+ @scanner.pos = p1
281
+ false
282
+ end
283
+ end
284
+ end) ? [r] : [])) &&
221
285
  @scanner.skip(/(?>(?>(?>[[:space:]])+|(?>\#)(?>(?>[^\n])*))*)(?>>)/) &&
222
- DispatchAction.parsed(select_captures([r0_0, r0_1]))
286
+ DispatchAction.parsed(select_captures([r0_0, r0_1, r0_2]))
223
287
  end || begin
224
288
  @scanner.pos = p0
225
289
  false
@@ -44,7 +44,7 @@ include Rattler::Parsers
44
44
  expression <- expression ~'/' attributed <Choice>
45
45
  / attributed
46
46
 
47
- attributed <- attributed ~'<' node_action? ~'>' <DispatchAction>
47
+ attributed <- attributed ~'<' node_action? literal? ~'>' <DispatchAction>
48
48
  / attributed ~'{' action ~'}' <DirectAction>
49
49
  / terms
50
50
 
@@ -25,8 +25,13 @@ module Rattler::Parsers
25
25
 
26
26
  # @private
27
27
  def self.parsed(results, *_) #:nodoc:
28
- attributed, optional_attribute = results
29
- self[attributed, optional_attribute.first || @@node_defaults[:target]]
28
+ attributed, optional_attribute, optional_name = results
29
+ a = self[attributed, optional_attribute.first || @@node_defaults[:target]]
30
+ unless optional_name.empty?
31
+ a.with_attrs(:target_attrs => {:name => eval(optional_name.first, TOPLEVEL_BINDING)})
32
+ else
33
+ a
34
+ end
30
35
  end
31
36
 
32
37
  # @private
@@ -59,10 +64,11 @@ module Rattler::Parsers
59
64
  super(children, self.class.parse_attrs_arg(attrs_arg))
60
65
  @@node_defaults.each {|k, v| attrs[k] ||= v } unless attrs[:code]
61
66
  @method_name = attrs[:method]
67
+ @target_attrs = attrs[:target_attrs] || {}
62
68
  end
63
69
 
64
70
  # the name of the method used as the symantic action
65
- attr_reader :method_name
71
+ attr_reader :method_name, :target_attrs
66
72
 
67
73
  # If the wrapped parser matches at the parse position, return the result
68
74
  # of applying the symantic action, otherwise return a false value.
@@ -84,7 +90,7 @@ module Rattler::Parsers
84
90
  end
85
91
 
86
92
  def bindable_code
87
- @bindable_code ||= NodeCode.new(target, method_name)
93
+ @bindable_code ||= NodeCode.new(target, method_name, target_attrs)
88
94
  end
89
95
 
90
96
  def bind(scope, bind_args)
@@ -15,12 +15,13 @@ module Rattler::Parsers
15
15
  self.new(action.target, action.method_name)
16
16
  end
17
17
 
18
- def initialize(target_name, method_name)
18
+ def initialize(target_name, method_name, target_attrs = {})
19
19
  @target_name = target_name
20
20
  @method_name = method_name
21
+ @target_attrs = target_attrs
21
22
  end
22
23
 
23
- attr_reader :target_name, :method_name
24
+ attr_reader :target_name, :method_name, :target_attrs
24
25
 
25
26
  def bind(scope, bind_args)
26
27
  args = [array_expr(bind_args)]
@@ -28,6 +29,7 @@ module Rattler::Parsers
28
29
  labeled = '{' + scope.map {|k, v| ":#{k} => #{v}"}.join(', ') + '}'
29
30
  args << ":labeled => #{labeled}"
30
31
  end
32
+ target_attrs.each {|k, v| args << ":#{k} => #{v.inspect}" }
31
33
  t = target_name == 'self' ? '' : "#{target_name}."
32
34
  "#{t}#{method_name}(#{args.join ', '})"
33
35
  end
@@ -18,7 +18,13 @@ module Rattler::Util::GraphViz
18
18
  # Yield any children of +o+ that should be represented as separate nodes in
19
19
  # the graph.
20
20
  def each_child_of(o)
21
- o.each {|_| yield _ } if array_like? o and not record_like? o
21
+ if array_like? o and not record_like? o
22
+ if o.respond_to? :to_hash
23
+ o.each {|k, v| yield Mapping.new(k, v) }
24
+ else
25
+ o.each {|_| yield _ }
26
+ end
27
+ end
22
28
  end
23
29
 
24
30
  # Return the options for a node representing +o+.
@@ -31,7 +37,7 @@ module Rattler::Util::GraphViz
31
37
  # @return the shape option for a node representing +o+.
32
38
  def node_shape(o)
33
39
  case o
34
- when Hash, Array
40
+ when Array, Hash, Mapping
35
41
  'circle'
36
42
  when String, Numeric, Symbol
37
43
  'plaintext'
@@ -49,6 +55,8 @@ module Rattler::Util::GraphViz
49
55
  record_label(o, o)
50
56
  elsif array_like? o
51
57
  type_label(o)
58
+ elsif o.respond_to? :to_str
59
+ "\"#{o}\""
52
60
  else
53
61
  o.inspect
54
62
  end
@@ -58,6 +66,7 @@ module Rattler::Util::GraphViz
58
66
  case o
59
67
  when Hash then '\\{\\}'
60
68
  when Array then '\\[\\]'
69
+ when Mapping then '-&gt;'
61
70
  else o.respond_to?(:name) ? o.name : o.class.name
62
71
  end
63
72
  end
@@ -73,12 +82,26 @@ module Rattler::Util::GraphViz
73
82
  end
74
83
 
75
84
  def record_label(o, h)
76
- '{' + ([type_label(o)] + hash_content_labels(h)).join('|') + '}'
85
+ fields = h.reject {|k,v| k == :name }
86
+ '{' + ([type_label(o)] + hash_content_labels(fields)).join('|') + '}'
77
87
  end
78
88
 
79
89
  def hash_content_labels(h)
80
90
  h.map {|pair| '{' + pair.map {|_| _.inspect }.join('|') + '}' }
81
91
  end
82
92
 
93
+ # @private
94
+ class Mapping #:nodoc:
95
+ def initialize(key, value)
96
+ @key = key
97
+ @value = value
98
+ end
99
+ attr_reader :key, :value
100
+ def each
101
+ yield key
102
+ yield value
103
+ end
104
+ end
105
+
83
106
  end
84
107
  end
@@ -5,6 +5,13 @@ describe Rattler::BackEnd::Compiler do
5
5
  include CompilerSpecHelper
6
6
 
7
7
  describe '.compile_parser result' do
8
+
9
+ let :compiled_parser do
10
+ described_class.compile_parser compiled_parser_base, grammar
11
+ end
12
+
13
+ let(:compiled_parser_base) { Rattler::Runtime::RecursiveDescentParser }
14
+
8
15
  it_behaves_like 'a compiled parser'
9
16
  end
10
17
 
@@ -0,0 +1,16 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+ require File.expand_path(File.dirname(__FILE__) + '/shared_compiler_examples')
3
+
4
+ describe Rattler::BackEnd::Optimizer do
5
+ include CompilerSpecHelper
6
+
7
+ describe '.optimize result' do
8
+
9
+ let :compiled_parser do
10
+ combinator_parser described_class.optimize(grammar)
11
+ end
12
+
13
+ it_behaves_like 'a compiled parser'
14
+
15
+ end
16
+ end
@@ -0,0 +1,51 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../../spec_helper')
2
+
3
+ include Rattler::BackEnd::ParserGenerator
4
+
5
+ describe GroupMatch do
6
+ include CombinatorParserSpecHelper
7
+
8
+ let(:single_group) { GroupMatch[Match[/\s*(\w+)/], {:num_groups => 1}] }
9
+ let(:multi_group) { GroupMatch[Match[/\s*(\w+)\s+(\w+)/], {:num_groups => 2}] }
10
+
11
+ describe '#parse' do
12
+
13
+ context 'with a single group' do
14
+
15
+ subject { single_group }
16
+
17
+ context 'when the regexp matches' do
18
+ it 'succeeds returning the matched group' do
19
+ parsing(' abc123 ').should result_in('abc123').at(8)
20
+ end
21
+ end
22
+
23
+ context 'when the regexp does not match' do
24
+ it 'fails' do
25
+ parsing('==').should fail
26
+ end
27
+ end
28
+ end
29
+
30
+ context 'with multiple groups' do
31
+
32
+ subject { multi_group }
33
+
34
+ context 'when the regexp matches' do
35
+ it 'succeeds returning the matched groups in an array' do
36
+ parsing(' abc 123 ').should result_in(['abc', '123']).at(8)
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ describe '#capturing?' do
43
+
44
+ subject { single_group }
45
+
46
+ it 'is true' do
47
+ subject.should be_capturing
48
+ end
49
+ end
50
+
51
+ end
@@ -1,15 +1,9 @@
1
1
  shared_examples_for 'a compiled parser' do
2
2
  include CompilerSpecHelper
3
3
 
4
- subject do
5
- described_class.compile_parser(compiled_parser_base, grammar)
6
- end
7
-
8
- let :reference_parser do
9
- Rattler::Parsers::CombinatorParser.as_class(grammar.rules.first, grammar.rules)
10
- end
4
+ subject { compiled_parser }
11
5
 
12
- let(:compiled_parser_base) { Rattler::Runtime::RecursiveDescentParser }
6
+ let(:reference_parser) { combinator_parser grammar }
13
7
 
14
8
  ########## match ##########
15
9
  context 'with a match rule' do
@@ -167,20 +167,90 @@ describe Rattler::Grammar::GrammarParser do
167
167
  end
168
168
  end
169
169
 
170
- it 'parses dispatch-action-attributed expressions' do
171
- matching(' expr <Expr> ').as(:expression).
172
- should result_in(DispatchAction[Apply[:expr], {:target => 'Expr', :method => 'parsed'}]).
173
- at(12)
170
+ context 'given a dispatch-action-attributed expression' do
171
+
172
+ context 'given an action with a class name' do
173
+ it 'parses as a DispatchAction with the default method' do
174
+ matching(' expr <Expr> ').as(:expression).
175
+ should result_in(DispatchAction[Apply[:expr],
176
+ {:target => 'Expr', :method => 'parsed'}
177
+ ]).at(12)
178
+ end
179
+
180
+ context 'with a literal' do
181
+ it 'uses the literal as the name' do
182
+ matching(' expr <Expr "expression"> ').as(:expression).
183
+ should result_in(DispatchAction[Apply[:expr],
184
+ {:target => 'Expr', :method => 'parsed',
185
+ :target_attrs => {:name => 'expression'} }
186
+ ]).at(25)
187
+ end
188
+ end
189
+ end
190
+
191
+ context 'given an action with a class and method names' do
192
+ it 'parses as a DispatchAction with the default method' do
193
+ matching(' expr <Expr.eval> ').as(:expression).
194
+ should result_in(DispatchAction[Apply[:expr],
195
+ {:target => 'Expr', :method => 'eval'}
196
+ ]).at(17)
197
+ end
198
+
199
+ context 'with a literal' do
200
+ it 'uses the literal as the name' do
201
+ matching(' expr <Expr.eval "expression"> ').as(:expression).
202
+ should result_in(DispatchAction[Apply[:expr],
203
+ { :target => 'Expr', :method => 'eval',
204
+ :target_attrs => {:name => 'expression'} }
205
+ ]).at(30)
206
+ end
207
+ end
208
+ end
209
+
210
+ context 'given an empty action' do
211
+ it 'parses as a DispatchAction with the default target and method' do
212
+ matching(' expr <> ').as(:expression).
213
+ should result_in(DispatchAction[Apply[:expr],
214
+ {:target => 'Rattler::Runtime::ParseNode', :method => 'parsed'}
215
+ ]).at(8)
216
+ end
217
+ end
218
+
219
+ context 'given just a literal' do
220
+ it 'parses as a default node with the literal as the name' do
221
+ matching(' expr <"expression"> ').as(:expression).
222
+ should result_in(DispatchAction[Apply[:expr],
223
+ { :target => 'Rattler::Runtime::ParseNode',
224
+ :method => 'parsed',
225
+ :target_attrs => {:name => 'expression'} }
226
+ ]).at(20)
227
+ end
228
+ end
174
229
  end
175
230
 
176
- it 'parses direct-action-attributed expressions' do
177
- matching(' digits {|_| _.to_i} ').as(:expression).
178
- should result_in(DirectAction[Apply[:digits], '|_| _.to_i']).at(20)
231
+ context 'given direct-action-attributed expression' do
232
+ it 'parses as a DirectAction' do
233
+ matching(' digits {|_| _.to_i} ').as(:expression).
234
+ should result_in(DirectAction[Apply[:digits], '|_| _.to_i']).at(20)
235
+ end
179
236
  end
180
237
 
181
- it 'parses sequence expressions' do
182
- matching(' name "=" value ').as(:expression).
183
- should result_in(Sequence[Apply[:name], Match[%r{=}], Apply[:value]]).at(15)
238
+ context 'given a sequence expression' do
239
+ it 'parses as a Sequence' do
240
+ matching(' name "=" value ').as(:expression).
241
+ should result_in(Sequence[Apply[:name], Match[%r{=}], Apply[:value]]).at(15)
242
+ end
243
+
244
+ context 'with a nested sequence expression' do
245
+ it 'parses as a nested Sequence' do
246
+ matching(' a (b c) d ').as(:expression).
247
+ should result_in(Sequence[
248
+ Apply[:a],
249
+ Sequence[Apply[:b], Apply[:c]],
250
+ Apply[:d]
251
+ ]).at(10)
252
+ end
253
+ end
184
254
  end
185
255
 
186
256
  it 'parses attributed sequence expressions' do
@@ -3,14 +3,15 @@ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
3
3
  describe DispatchAction do
4
4
  include CombinatorParserSpecHelper
5
5
 
6
+ subject { DispatchAction[nested_parser] }
7
+
6
8
  describe '#parse' do
7
9
 
8
10
  context 'with a capturing parser' do
9
- subject do
10
- DispatchAction[
11
- Sequence[Match[/[[:alpha:]]+/], Match[/\=/], Match[/[[:digit:]]+/]]
12
- ]
13
- end
11
+
12
+ let (:nested_parser) { Sequence[
13
+ Match[/[[:alpha:]]+/], Match[/\=/], Match[/[[:digit:]]+/]
14
+ ] }
14
15
 
15
16
  context 'when the parser matches' do
16
17
  it 'applies the action to the result' do
@@ -26,6 +27,18 @@ describe DispatchAction do
26
27
  end
27
28
  end
28
29
 
30
+ context 'with a non-capturing parser' do
31
+
32
+ let (:nested_parser) { Skip[Match[/,/]] }
33
+
34
+ context 'when the parser matches' do
35
+ it 'applies the action to an empty array' do
36
+ parsing(', ').
37
+ should result_in(Rattler::Runtime::ParseNode.parsed([])).at(1)
38
+ end
39
+ end
40
+ end
41
+
29
42
  context 'with a token parser' do
30
43
 
31
44
  subject { DispatchAction[Token[Match[/\w+/]]] }
@@ -2,10 +2,11 @@ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
2
 
3
3
  describe Rattler::Parsers::NodeCode do
4
4
 
5
- subject { described_class.new(target_name, method_name) }
5
+ subject { described_class.new(target_name, method_name, target_attrs) }
6
6
 
7
7
  let(:target_name) { 'Expr' }
8
8
  let(:method_name) { 'parsed' }
9
+ let(:target_attrs) { {} }
9
10
 
10
11
  describe '#bind' do
11
12
 
@@ -44,5 +45,15 @@ describe Rattler::Parsers::NodeCode do
44
45
  should == 'Expr.parsed([a, b], :labeled => {:word => w})'
45
46
  end
46
47
  end
48
+
49
+ context 'with target_attrs' do
50
+
51
+ let(:target_attrs) { {:name => 'expression'} }
52
+
53
+ it '' do
54
+ subject.bind(scope, ['a', 'b']).
55
+ should == 'Expr.parsed([a, b], :name => "expression")'
56
+ end
57
+ end
47
58
  end
48
59
  end
@@ -3,6 +3,46 @@ require 'set'
3
3
 
4
4
  describe Rattler::Util::GraphViz::NodeBuilder do
5
5
 
6
+ describe '#node_label' do
7
+
8
+ context 'given a number' do
9
+ it 'returns a number as a string' do
10
+ subject.node_label(42).should == '42'
11
+ end
12
+ end
13
+
14
+ context 'given a string' do
15
+ it 'returns the string surrounded by escaped quotes' do
16
+ subject.node_label('abc').should == '"abc"'
17
+ end
18
+ end
19
+
20
+ context 'given an unnamed record-like object' do
21
+ it 'returns a record label with the class name' do
22
+ subject.node_label(Rattler::Util::Node[]).should == '{Rattler::Util::Node}'
23
+ end
24
+ end
25
+
26
+ context 'given a named record-like object' do
27
+ it 'returns a record label with a name' do
28
+ subject.node_label(Rattler::Util::Node[{:name => 'IDENT'}]).
29
+ should == '{IDENT}'
30
+ end
31
+ end
32
+
33
+ context 'given an array-like object' do
34
+ it 'returns "[]" escaped' do
35
+ subject.node_label(['let', 'x', '=', '1']).should == '\\[\\]'
36
+ end
37
+ end
38
+
39
+ context 'given a hash with compound values' do
40
+ it 'returns "{}" escaped' do
41
+ subject.node_label({:a => 'a', :b => ['a1', 'a2']}).should == '\\{\\}'
42
+ end
43
+ end
44
+ end
45
+
6
46
  describe '#array_like?' do
7
47
 
8
48
  context 'given an array' do
@@ -11,7 +51,7 @@ describe Rattler::Util::GraphViz::NodeBuilder do
11
51
  end
12
52
  end
13
53
 
14
- context 'given a hash' do
54
+ context 'given a simple hash' do
15
55
  it 'returns true' do
16
56
  subject.array_like?({:a => 'a'}).should be_true
17
57
  end
@@ -62,10 +102,10 @@ describe Rattler::Util::GraphViz::NodeBuilder do
62
102
 
63
103
  let(:object) { {:a => ['a1', 'a2'], :b => 'b'} }
64
104
 
65
- it 'iterates over the pairs' do
105
+ it 'iterates over the pairs yielding Mappings' do
66
106
  children = Set[]
67
107
  subject.each_child_of(object) {|_| children << _ }
68
- children.should == Set[[:a, ['a1', 'a2']], [:b, 'b']]
108
+ children.should have(2).mappings
69
109
  end
70
110
  end
71
111
 
@@ -6,6 +6,10 @@ module CompilerSpecHelper
6
6
  Rattler::Grammar::Grammar.new(Rattler::Parsers.define(&block))
7
7
  end
8
8
 
9
+ def combinator_parser(g)
10
+ Rattler::Parsers::CombinatorParser.as_class(g.rules.first, g.rules)
11
+ end
12
+
9
13
  RSpec::Matchers.define :parse do |source|
10
14
  match do |parser_class|
11
15
  parser = parser_class.new(source)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rattler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.4.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,12 +9,12 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-03-12 00:00:00.000000000 -08:00
12
+ date: 2011-03-15 00:00:00.000000000 -07:00
13
13
  default_executable: rtlr
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: bundler
17
- requirement: &74294690 !ruby/object:Gem::Requirement
17
+ requirement: &72971210 !ruby/object:Gem::Requirement
18
18
  none: false
19
19
  requirements:
20
20
  - - ~>
@@ -22,10 +22,10 @@ dependencies:
22
22
  version: 1.0.0
23
23
  type: :development
24
24
  prerelease: false
25
- version_requirements: *74294690
25
+ version_requirements: *72971210
26
26
  - !ruby/object:Gem::Dependency
27
27
  name: jeweler
28
- requirement: &74294440 !ruby/object:Gem::Requirement
28
+ requirement: &72970960 !ruby/object:Gem::Requirement
29
29
  none: false
30
30
  requirements:
31
31
  - - ~>
@@ -33,10 +33,10 @@ dependencies:
33
33
  version: 1.5.2
34
34
  type: :development
35
35
  prerelease: false
36
- version_requirements: *74294440
36
+ version_requirements: *72970960
37
37
  - !ruby/object:Gem::Dependency
38
38
  name: rspec
39
- requirement: &74268930 !ruby/object:Gem::Requirement
39
+ requirement: &72970700 !ruby/object:Gem::Requirement
40
40
  none: false
41
41
  requirements:
42
42
  - - ! '>='
@@ -44,10 +44,10 @@ dependencies:
44
44
  version: 2.3.0
45
45
  type: :development
46
46
  prerelease: false
47
- version_requirements: *74268930
47
+ version_requirements: *72970700
48
48
  - !ruby/object:Gem::Dependency
49
49
  name: cucumber
50
- requirement: &74268690 !ruby/object:Gem::Requirement
50
+ requirement: &72970430 !ruby/object:Gem::Requirement
51
51
  none: false
52
52
  requirements:
53
53
  - - ! '>='
@@ -55,10 +55,10 @@ dependencies:
55
55
  version: 0.8.0
56
56
  type: :development
57
57
  prerelease: false
58
- version_requirements: *74268690
58
+ version_requirements: *72970430
59
59
  - !ruby/object:Gem::Dependency
60
60
  name: aruba
61
- requirement: &74268420 !ruby/object:Gem::Requirement
61
+ requirement: &72970180 !ruby/object:Gem::Requirement
62
62
  none: false
63
63
  requirements:
64
64
  - - ! '>='
@@ -66,10 +66,10 @@ dependencies:
66
66
  version: 0.3.0
67
67
  type: :development
68
68
  prerelease: false
69
- version_requirements: *74268420
69
+ version_requirements: *72970180
70
70
  - !ruby/object:Gem::Dependency
71
71
  name: yard
72
- requirement: &74268160 !ruby/object:Gem::Requirement
72
+ requirement: &72969930 !ruby/object:Gem::Requirement
73
73
  none: false
74
74
  requirements:
75
75
  - - ! '>='
@@ -77,10 +77,10 @@ dependencies:
77
77
  version: 0.6.0
78
78
  type: :development
79
79
  prerelease: false
80
- version_requirements: *74268160
80
+ version_requirements: *72969930
81
81
  - !ruby/object:Gem::Dependency
82
82
  name: watchr
83
- requirement: &74267920 !ruby/object:Gem::Requirement
83
+ requirement: &72969680 !ruby/object:Gem::Requirement
84
84
  none: false
85
85
  requirements:
86
86
  - - ! '>='
@@ -88,10 +88,10 @@ dependencies:
88
88
  version: 0.5.5
89
89
  type: :development
90
90
  prerelease: false
91
- version_requirements: *74267920
91
+ version_requirements: *72969680
92
92
  - !ruby/object:Gem::Dependency
93
93
  name: ruby-graphviz
94
- requirement: &74267680 !ruby/object:Gem::Requirement
94
+ requirement: &72969430 !ruby/object:Gem::Requirement
95
95
  none: false
96
96
  requirements:
97
97
  - - ! '>='
@@ -99,7 +99,7 @@ dependencies:
99
99
  version: 0.9.6
100
100
  type: :development
101
101
  prerelease: false
102
- version_requirements: *74267680
102
+ version_requirements: *72969430
103
103
  description: Simple language recognition tool for Ruby based on packrat parsing
104
104
  email: jarhart@gmail.com
105
105
  executables:
@@ -274,6 +274,7 @@ files:
274
274
  - spec/rattler/back_end/optimizer/reduce_repeat_match_spec.rb
275
275
  - spec/rattler/back_end/optimizer/simplify_redundant_repeat_spec.rb
276
276
  - spec/rattler/back_end/optimizer/simplify_token_match_spec.rb
277
+ - spec/rattler/back_end/optimizer_spec.rb
277
278
  - spec/rattler/back_end/parser_generator/apply_generator_spec.rb
278
279
  - spec/rattler/back_end/parser_generator/assert_generator_spec.rb
279
280
  - spec/rattler/back_end/parser_generator/back_reference_generator_spec.rb
@@ -283,6 +284,7 @@ files:
283
284
  - spec/rattler/back_end/parser_generator/dispatch_action_generator_spec.rb
284
285
  - spec/rattler/back_end/parser_generator/fail_generator_spec.rb
285
286
  - spec/rattler/back_end/parser_generator/group_match_generator_spec.rb
287
+ - spec/rattler/back_end/parser_generator/group_match_spec.rb
286
288
  - spec/rattler/back_end/parser_generator/label_generator_spec.rb
287
289
  - spec/rattler/back_end/parser_generator/list1_generator_spec.rb
288
290
  - spec/rattler/back_end/parser_generator/list_generator_spec.rb
@@ -356,7 +358,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
356
358
  version: '0'
357
359
  segments:
358
360
  - 0
359
- hash: -463546417
361
+ hash: 156917203
360
362
  required_rubygems_version: !ruby/object:Gem::Requirement
361
363
  none: false
362
364
  requirements:
@@ -416,6 +418,7 @@ test_files:
416
418
  - spec/rattler/back_end/optimizer/reduce_repeat_match_spec.rb
417
419
  - spec/rattler/back_end/optimizer/simplify_redundant_repeat_spec.rb
418
420
  - spec/rattler/back_end/optimizer/simplify_token_match_spec.rb
421
+ - spec/rattler/back_end/optimizer_spec.rb
419
422
  - spec/rattler/back_end/parser_generator/apply_generator_spec.rb
420
423
  - spec/rattler/back_end/parser_generator/assert_generator_spec.rb
421
424
  - spec/rattler/back_end/parser_generator/back_reference_generator_spec.rb
@@ -425,6 +428,7 @@ test_files:
425
428
  - spec/rattler/back_end/parser_generator/dispatch_action_generator_spec.rb
426
429
  - spec/rattler/back_end/parser_generator/fail_generator_spec.rb
427
430
  - spec/rattler/back_end/parser_generator/group_match_generator_spec.rb
431
+ - spec/rattler/back_end/parser_generator/group_match_spec.rb
428
432
  - spec/rattler/back_end/parser_generator/label_generator_spec.rb
429
433
  - spec/rattler/back_end/parser_generator/list1_generator_spec.rb
430
434
  - spec/rattler/back_end/parser_generator/list_generator_spec.rb