cofgratx 0.0.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.
@@ -0,0 +1,2 @@
1
+ class RuleError < Exception
2
+ end
@@ -0,0 +1,25 @@
1
+ class Terminal
2
+ attr_accessor :terminal
3
+
4
+ def initialize param
5
+ unless %w{Regexp String}.include? param.class.name
6
+ raise ArgumentError.new("expected Regular Expression or String; got #{param.class.name}")
7
+ end
8
+ param = param.class == String ?
9
+ Regexp.escape(param) :
10
+ param.source
11
+
12
+ @terminal = Regexp.compile "^(" + param +")"
13
+ end
14
+
15
+ def match? string
16
+ (@terminal =~ string) == 0
17
+ end
18
+
19
+ def extract string
20
+ return [nil, string] unless @terminal =~ string
21
+ terminal_match = $1
22
+ [ $1, string[terminal_match.length..-1] ]
23
+ end
24
+
25
+ end
@@ -0,0 +1,33 @@
1
+ class TranslationRepetitionSet
2
+
3
+ attr_accessor :offset, :translations
4
+
5
+ def initialize offset = 1, *translations
6
+ self.offset = offset
7
+ self.translations = translations
8
+ end
9
+
10
+ def offset= offset
11
+ if offset.class.name != "Fixnum"
12
+ raise ArgumentError.new("expected Fixnum; got '#{offset.class.name}'")
13
+ elsif offset <= 0
14
+ raise ArgumentError.new("expected positive Fixnum; got '#{offset}'")
15
+ end
16
+
17
+ @offset = offset.to_i
18
+ end
19
+
20
+ def translations= *translations
21
+ good_parts = []
22
+ [ translations ].flatten.each do |translation|
23
+ if ! [Fixnum, String].include? translation.class
24
+ raise ArgumentError.new("expected Fixnum or String; got #{translation.class.name}")
25
+ elsif translation.class == Fixnum and translation <= 0
26
+ raise TranslationRepetitionSetError.new("subrule number cannot be less than 1")
27
+ end
28
+ good_parts << translation
29
+ end
30
+ @translations = good_parts
31
+ end
32
+
33
+ end
@@ -0,0 +1,2 @@
1
+ class TranslationRepetitionSetError < Exception
2
+ end
@@ -0,0 +1,3 @@
1
+ module Cofgratx
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,423 @@
1
+ require 'spec_helper'
2
+ require 'cofgratx/cfg/terminal'
3
+ require 'cofgratx/cfg/repetition'
4
+ require 'cofgratx/cfg/translation_repetition_set_error'
5
+ require 'cofgratx/cfg/translation_repetition_set'
6
+ require 'cofgratx/cfg/rule_error'
7
+ require 'cofgratx/cfg/grammar_error'
8
+ require 'cofgratx/cfg/rule'
9
+ require 'cofgratx/cfg/non_terminal'
10
+ require 'cofgratx/cfg/grammar'
11
+
12
+ describe Grammar do
13
+ context ".initialize" do
14
+ it { expect{ described_class.new }.to_not raise_error }
15
+ end
16
+
17
+ context ".add_rules" do
18
+ before do
19
+ @grammar = described_class.new
20
+ end
21
+
22
+ it "allows rule symbols to be given without rules" do
23
+ expect_any_instance_of(NonTerminal).to receive(:add_rules).with(no_args).and_call_original
24
+
25
+ expect( @grammar.rules.keys.size ).to equal 0
26
+ @grammar.add_rules :one
27
+ expect( @grammar.rules.keys.size ).to equal 1
28
+ expect( @grammar.rules.values.first.class ).to equal NonTerminal
29
+ end
30
+
31
+ it "allows non terminal names to be given as strings or symbols" do
32
+ expect( @grammar.rules.keys.size ).to equal 0
33
+ @grammar.add_rules :one, [ [Terminal.new(/a/)] ,[] ]
34
+ expect( @grammar.rules.keys.size ).to equal 1
35
+
36
+ @grammar.add_rules "one", [ [Terminal.new(/b/)] ,[] ]
37
+ expect( @grammar.rules.keys.size ).to equal 1
38
+ end
39
+
40
+ it "converts symbols in the subrule arrays to nonterminals" do
41
+ expect( @grammar.rules.keys.size ).to equal 0
42
+ @grammar.add_rules :one, [ [:S] ,[] ]
43
+ expect( @grammar.rules.keys ).to match_array [ :one, :S ]
44
+ expect( @grammar.rules[:one].rules.map(&:rule) ).to match_array [ [@grammar.rules[:S]] ]
45
+ end
46
+
47
+ it "adds a rule with translation" do
48
+ expect( @grammar.rules.keys.size ).to equal 0
49
+ expect{
50
+ @grammar.add_rules :one,
51
+ [ [Terminal.new(/a/), Terminal.new("b"), :two, Repetition.new(",")],
52
+ [1,2,TranslationRepetitionSet.new(1,3,2,1,"STOP")]
53
+ ]
54
+ }.to_not raise_error
55
+ expect( @grammar.rules.keys.size ).to equal 2
56
+ end
57
+
58
+ it "adds a rule with invalid translation for nonexistant repetition" do
59
+ expect( @grammar.rules.keys.size ).to equal 0
60
+ expect{
61
+ @grammar.add_rules :one,
62
+ [ [Terminal.new(/a/), Terminal.new("b"), :two],
63
+ [1,2,TranslationRepetitionSet.new(1,3,2,1,"STOP")]
64
+ ]
65
+ }.to raise_error GrammarError, "rule does not contain repetition"
66
+ expect{
67
+ @grammar.add_rules :one,
68
+ [ [Terminal.new(/a/), Terminal.new("b"), :two, Repetition.new(",")],
69
+ [1,2,TranslationRepetitionSet.new(1,3,9,1,"STOP")]
70
+ ]
71
+ }.to raise_error GrammarError, "rule contains fewer parts than the TranslationRepetitionSet has for a translation: [3, 9, 1, \"STOP\"]"
72
+ expect{
73
+ @grammar.add_rules :one,
74
+ [ [Terminal.new(/a/), Terminal.new("b"), :two],
75
+ [1,4]
76
+ ]
77
+ }.to raise_error GrammarError, "rule contains fewer parts than translation number: 4"
78
+
79
+ expect( @grammar.rules.keys.size ).to equal 2
80
+ end
81
+
82
+ it "add several rules some with translations" do
83
+ expect( @grammar.rules.keys.size ).to equal 0
84
+ expect{
85
+ @grammar.add_rules :one,
86
+ [ [Terminal.new(/a/), Terminal.new("b"), :two, Repetition.new(",")],
87
+ [1,2,TranslationRepetitionSet.new(1,3,2,1,"STOP")]
88
+ ],
89
+ [ [:one, :three, :one],
90
+ [1,":",2]
91
+ ]
92
+ }.to_not raise_error
93
+ expect( @grammar.rules.keys.size ).to equal 3
94
+ end
95
+
96
+ context "bad rules and translations" do
97
+ it "does not add bad rules" do
98
+ expect( @grammar.rules.keys.size ).to equal 0
99
+ expect{
100
+ @grammar.add_rules :one,
101
+ [ ["BAD", :two, Repetition.new(",")],
102
+ [1,2,TranslationRepetitionSet.new(1,3,2,1,"STOP")]
103
+ ]
104
+ }.to raise_error
105
+ expect( @grammar.rules.keys.size ).to equal 2
106
+ expect( @grammar.rules[:one].rules.map(&:rule) ).to match_array [ ]
107
+ expect( @grammar.rules[:two].rules.map(&:rule) ).to match_array [ ]
108
+ end
109
+
110
+ it "does not rules when a bad rule is also given" do
111
+ expect( @grammar.rules.keys.size ).to equal 0
112
+ expect{
113
+ @grammar.add_rules :one,
114
+ [ [Terminal.new("GOOD")], [] ],
115
+ [ ["BAD", :two, Repetition.new(",")],
116
+ [1,2,TranslationRepetitionSet.new(1,3,2,1,"STOP")]
117
+ ]
118
+ }.to raise_error ArgumentError, "expected Terminal, NonTerminal or Repetition; got String"
119
+ expect( @grammar.rules.keys.size ).to equal 2
120
+ expect( @grammar.rules[:one].rules.map(&:rule) ).to match_array [ ]
121
+ expect( @grammar.rules[:two].rules.map(&:rule) ).to match_array [ ]
122
+ end
123
+
124
+ it "does not remove good rules already added" do
125
+ @terminal_a = Terminal.new("a")
126
+ expect{ @grammar.add_rules :one, [ [@terminal_a, :two], [] ] }.to_not raise_error
127
+ expect( @grammar.rules.keys.size ).to equal 2
128
+ expect( @grammar.rules[:one].rules.map(&:rule) ).to match_array [ [@terminal_a, @grammar.rules[:two]] ]
129
+ expect{
130
+ @grammar.add_rules :one,
131
+ [ ["BAD", Repetition.new(",")],
132
+ [1,2,TranslationRepetitionSet.new(1,2,1,"STOP")]
133
+ ]
134
+ }.to raise_error
135
+ expect( @grammar.rules.keys.size ).to equal 2
136
+ expect( @grammar.rules[:one].rules.map(&:rule) ).to match_array [ [@terminal_a, @grammar.rules[:two]] ]
137
+ end
138
+
139
+ it "does not add rules with bad translations" do
140
+ expect( @grammar.rules.keys.size ).to equal 0
141
+ expect{
142
+ @grammar.add_rules :one,
143
+ [ [Terminal.new("BAD")],
144
+ [1,2,3.14159]
145
+ ]
146
+ }.to raise_error
147
+ expect( @grammar.rules.keys.size ).to equal 1
148
+ expect( @grammar.rules[:one].rules.map(&:rule) ).to match_array [ ]
149
+ expect( @grammar.rules[:one].rules.map(&:translation) ).to match_array [ ]
150
+
151
+ expect{
152
+ @grammar.add_rules :one,
153
+ [ [Terminal.new("GOOD"), Terminal.new("GOOD"), Terminal.new("GOOD"), :two],
154
+ [1,2,TranslationRepetitionSet.new(1,3,2,1,"STOP")]
155
+ ]
156
+ }.to raise_error GrammarError
157
+ expect{
158
+ @grammar.add_rules :one,
159
+ [ [:two, Repetition.new(",")],
160
+ [1,2,TranslationRepetitionSet.new(1,9)]
161
+ ]
162
+ }.to raise_error GrammarError
163
+ expect{
164
+ @grammar.add_rules :one,
165
+ [ [:two, Repetition.new(",")],
166
+ [12]
167
+ ]
168
+ }.to raise_error GrammarError
169
+ end
170
+
171
+ it "does not add any rules when bad translations are also given" do
172
+ expect( @grammar.rules.keys.size ).to equal 0
173
+ expect{
174
+ @grammar.add_rules :one,
175
+ [ [Terminal.new("GOOD")], ["DONT LET ME IN"] ],
176
+ [ [Terminal.new("BAD")],
177
+ [1,2,6.011]
178
+ ]
179
+ }.to raise_error
180
+ expect( @grammar.rules.keys.size ).to equal 1
181
+ expect( @grammar.rules[:one].rules.map(&:rule) ).to match_array [ ]
182
+ expect( @grammar.rules[:one].rules.map(&:translation) ).to match_array [ ]
183
+ end
184
+
185
+ it "does not remove good rules and translations already added" do
186
+ @terminal_a = Terminal.new("a")
187
+ expect{ @grammar.add_rules :one, [ [@terminal_a, :two], [1,2] ] }.to_not raise_error
188
+ expect( @grammar.rules.keys.size ).to equal 2
189
+ expect( @grammar.rules[:one].rules.map(&:rule) ).to match_array [ [@terminal_a, @grammar.rules[:two]] ]
190
+ expect( @grammar.rules[:one].rules.map(&:translation) ).to match_array [ [1,2] ]
191
+ expect{
192
+ @grammar.add_rules :one,
193
+ [ [Terminal.new("BAD"), Repetition.new(",")],
194
+ [1,2,2.718]
195
+ ]
196
+ }.to raise_error
197
+ expect( @grammar.rules.keys.size ).to equal 2
198
+ expect( @grammar.rules[:one].rules.map(&:rule) ).to match_array [ [@terminal_a, @grammar.rules[:two]] ]
199
+ expect( @grammar.rules[:one].rules.map(&:translation) ).to match_array [ [1,2] ]
200
+ end
201
+ end
202
+ end
203
+
204
+ context ".clear_rule" do
205
+ it "wipes out the productions for a given nonterminal" do
206
+ @grammar = described_class.new
207
+ @terminal_a = Terminal.new("a")
208
+ expect{ @grammar.add_rules :one, [ [@terminal_a], [1] ] }.to_not raise_error
209
+ expect( @grammar.rules[:one].rules.map(&:rule) ).to match_array [ [@terminal_a] ]
210
+ expect( @grammar.rules[:one].rules.map(&:translation) ).to match_array [ [1] ]
211
+ expect{ @grammar.clear_rule :one }.to_not raise_error
212
+ expect( @grammar.rules[:one].rules.map(&:rule) ).to match_array []
213
+ expect( @grammar.rules[:one].rules.map(&:translation) ).to match_array []
214
+ end
215
+ end
216
+
217
+ context ".match?" do
218
+ before(:all) do
219
+ @terminal_a = Terminal.new("a")
220
+ @terminal_b = Terminal.new("b")
221
+ @repetition = Repetition.new(" and ")
222
+ end
223
+
224
+ context "simple grammar" do
225
+ before(:all) do
226
+ @simple_grammar = described_class.new
227
+ @simple_grammar.add_rules :one, [ [@terminal_a, :one], [] ]
228
+ @simple_grammar.add_rules :one, [ [@terminal_a], [] ]
229
+
230
+ @empty_grammar = described_class.new
231
+ @empty_grammar.add_rules :Z, [ [], [] ]
232
+ end
233
+
234
+ it{ expect( @simple_grammar.match?("a", "one") ).to be_truthy }
235
+ it{ expect( @simple_grammar.match?("a", :one) ).to be_truthy }
236
+ it{ expect( @simple_grammar.match?("aa", :one) ).to be_truthy }
237
+ it{ expect( @simple_grammar.match?("aaaa", :one) ).to be_truthy }
238
+ it{ expect( @simple_grammar.match?("aaaaaa", :one) ).to be_truthy }
239
+
240
+ it{ expect( @simple_grammar.match?("", "one") ).to be_falsey }
241
+ it{ expect( @simple_grammar.match?("ab", :one) ).to be_falsey }
242
+ it{ expect( @simple_grammar.match?(" a ", :one) ).to be_falsey }
243
+ it{ expect( @simple_grammar.match?("NO", :one) ).to be_falsey }
244
+
245
+ it{ expect( @empty_grammar.match?("", :Z) ).to be_truthy }
246
+ it{ expect( @empty_grammar.match?("NO", :Z) ).to be_falsey }
247
+ it{ expect( @empty_grammar.match?(" ", :Z) ).to be_falsey }
248
+ end
249
+
250
+ context "comlpex grammar" do
251
+ before(:all) do
252
+ @terminal_a = Terminal.new("a")
253
+ @terminal_b = Terminal.new("b")
254
+ @repetition = Repetition.new(" and ")
255
+ @complex_grammar = described_class.new
256
+ @grammar_with_self_referential_rule = described_class.new
257
+
258
+ @complex_grammar.add_rules :S, [ [@terminal_a, :A, @terminal_a, @repetition], [] ], [ [@terminal_a], [] ]
259
+ @complex_grammar.add_rules :A, [ [@terminal_b, :S, @terminal_b], [] ], [ [], [] ]
260
+
261
+ #the problem with the rule below, the nonterminal keeps going down forever, maybe add something that stops it, or start
262
+ #unwinding the stack once it goes too deep. Either way, not all legal grammars will be able to be processed.
263
+ #Or maybe make it illegal to have a nonterminal as the first (which should still be a legal production, but makes
264
+ #creating a solution easier)
265
+ @grammar_with_self_referential_rule.add_rules :S, [ [@terminal_a, :S, @terminal_a], [] ], [ [@terminal_a], [] ] , [ [:S, @repetition], [] ]
266
+ #@complex_grammar2.add_rules :A, [ [@terminal_b, :S, @terminal_b], [] ], [ [], [] ]
267
+ end
268
+
269
+ it{ expect( @complex_grammar.match?("a", :S) ).to be_truthy }
270
+ it{ expect( @complex_grammar.match?("aa", :S) ).to be_truthy }
271
+ it{ expect( @complex_grammar.match?("ababa", :S) ).to be_truthy }
272
+ it{ expect( @complex_grammar.match?("ababaababa", :S) ).to be_truthy }
273
+ it{ expect( @complex_grammar.match?("aa and ababababa", :S) ).to be_truthy }
274
+ it{ expect( @complex_grammar.match?("aa and aa", :S) ).to be_truthy }
275
+ it{ expect( @complex_grammar.match?("ababa", :S) ).to be_truthy }
276
+
277
+ #Bug
278
+ it{ expect{ @grammar_with_self_referential_rule.match?("a", :S) }.to raise_error(SystemStackError) }
279
+ #it{ expect( @grammar_with_self_referential_rule.match?("aa", :S) ).to be_truthy }
280
+ #it{ expect( @grammar_with_self_referential_rule.match?("ababa", :S) ).to be_truthy }
281
+ #it{ expect( @grammar_with_self_referential_rule.match?("ababaababa", :S) ).to be_truthy }
282
+ #it{ expect( @grammar_with_self_referential_rule.match?("aa and ababababa", :S) ).to be_truthy }
283
+ #it{ expect( @grammar_with_self_referential_rule.match?("aa and a", :S) ).to be_truthy }
284
+ #it{ expect( @grammar_with_self_referential_rule.match?("ababa", :S) ).to be_truthy }
285
+
286
+ it{ expect( @complex_grammar.match?("", :S) ).to be_falsey }
287
+ it{ expect( @complex_grammar.match?("a but also stuff that isn't in the grammar", :S) ).to be_falsey }
288
+ it{ expect( @complex_grammar.match?(" ababa", :S) ).to be_falsey }
289
+ end
290
+ end
291
+
292
+ context ".translate" do
293
+ before(:all) do
294
+ @terminal_a = Terminal.new("a")
295
+ @terminal_b = Terminal.new("b")
296
+ @repetition = Repetition.new(" and ")
297
+ end
298
+
299
+ context "simple grammar - no actual translations" do
300
+ before(:all) do
301
+ @simple_grammar = described_class.new
302
+ @simple_grammar.add_rules :one, [ [@terminal_a, :one], [] ]
303
+ @simple_grammar.add_rules :one, [ [@terminal_a], [] ]
304
+
305
+ @empty_grammar = described_class.new
306
+ @empty_grammar.add_rules :Z, [ [], [] ]
307
+ end
308
+
309
+ it{ expect( @simple_grammar.translate("a", "one") ).to match_array [ ["a", ""] ] }
310
+ it{ expect( @simple_grammar.translate("a", :one) ).to match_array [ ["a", ""] ] }
311
+ it{ expect( @simple_grammar.translate("aa", :one) ).to match_array [ ["aa", ""] ] }
312
+ it{ expect( @simple_grammar.translate("aaaa", :one) ).to match_array [ ["aaaa", ""] ] }
313
+ it{ expect( @simple_grammar.translate("aaaaaa", :one) ).to match_array [ ["aaaaaa", ""] ] }
314
+
315
+ it{ expect( @simple_grammar.translate("", "one") ).to match_array [ ] }
316
+ it{ expect( @simple_grammar.translate("ab", :one) ).to match_array [ ] }
317
+ it{ expect( @simple_grammar.translate(" a ", :one) ).to match_array [ ] }
318
+ it{ expect( @simple_grammar.translate("NO", :one) ).to match_array [ ] }
319
+
320
+ it{ expect( @empty_grammar.translate("", :Z) ).to match_array [ ["",""] ] }
321
+ it{ expect( @empty_grammar.translate("NO", :Z) ).to match_array [ ] }
322
+ it{ expect( @empty_grammar.translate(" ", :Z) ).to match_array [ ] }
323
+ end
324
+
325
+ context "comlpex grammar - no actual translations" do
326
+ before(:all) do
327
+ @terminal_a = Terminal.new("a")
328
+ @terminal_b = Terminal.new("b")
329
+ @repetition = Repetition.new(" and ")
330
+ @complex_grammar = described_class.new
331
+ @grammar_with_self_referential_rule = described_class.new
332
+
333
+ @complex_grammar.add_rules :S, [ [@terminal_a, :A, @terminal_a, @repetition], [] ], [ [@terminal_a], [] ]
334
+ @complex_grammar.add_rules :A, [ [@terminal_b, :S, @terminal_b], [] ], [ [], [] ]
335
+
336
+ #the problem with the rule below, the nonterminal keeps going down forever, maybe add something that stops it, or start
337
+ #unwinding the stack once it goes too deep. Either way, not all legal grammars will be able to be processed.
338
+ #Or maybe make it illegal to have a nonterminal as the first (which should still be a legal production, but makes
339
+ #creating a solution easier)
340
+ @grammar_with_self_referential_rule.add_rules :S, [ [@terminal_a, :S, @terminal_a], [] ], [ [@terminal_a], [] ] , [ [:S, @repetition], [] ]
341
+ #@complex_grammar2.add_rules :A, [ [@terminal_b, :S, @terminal_b], [] ], [ [], [] ]
342
+ end
343
+
344
+ it{ expect( @complex_grammar.translate("a", :S) ).to match_array [ ["a",""] ] }
345
+ it{ expect( @complex_grammar.translate("aa", :S) ).to match_array [ ["aa",""] ] }
346
+ it{ expect( @complex_grammar.translate("ababa", :S) ).to match_array [ ["ababa",""] ] }
347
+ it{ expect( @complex_grammar.translate("ababaababa", :S) ).to match_array [ ["ababaababa",""] ] }
348
+ it{ expect( @complex_grammar.translate("aa and ababababa", :S) ).to match_array [ ["aa and ababababa",""] ] }
349
+ it{ expect( @complex_grammar.translate("aa and aa", :S) ).to match_array [ ["aa and aa",""] ] }
350
+
351
+ #Bug
352
+ it{ expect{ @grammar_with_self_referential_rule.translate("a", :S) }.to raise_error(SystemStackError) }
353
+
354
+ it{ expect( @complex_grammar.translate("", :S) ).to match_array [] }
355
+ it{ expect( @complex_grammar.translate("a but also stuff that isn't in the grammar", :S) ).to match_array [] }
356
+ it{ expect( @complex_grammar.translate(" ababa", :S) ).to match_array [] }
357
+ end
358
+
359
+ context "simple grammar - translations" do
360
+ before(:all) do
361
+ #@tx_rep_set = TranslationRepetitionSet.new(1, ":", 2, 1, ";")
362
+
363
+ @simple_grammar = described_class.new
364
+ @simple_grammar.add_rules :one, [ [@terminal_a, :one], [2,1] ]
365
+ @simple_grammar.add_rules :one, [ [@terminal_a], ["IWasTheLastA"] ]
366
+
367
+ @empty_grammar = described_class.new
368
+ @empty_grammar.add_rules :Z, [ [], ["Translate nothing"] ]
369
+ end
370
+
371
+ it{ expect( @simple_grammar.translate("a", "one") ).to match_array [ ["IWasTheLastA", ""] ] }
372
+ it{ expect( @simple_grammar.translate("a", :one) ).to match_array [ ["IWasTheLastA", ""] ] }
373
+ it{ expect( @simple_grammar.translate("aa", :one) ).to match_array [ ["IWasTheLastAa", ""] ] }
374
+ it{ expect( @simple_grammar.translate("aaaa", :one) ).to match_array [ ["IWasTheLastAaaa", ""] ] }
375
+ it{ expect( @simple_grammar.translate("aaaaaa", :one) ).to match_array [ ["IWasTheLastAaaaaa", ""] ] }
376
+
377
+ it{ expect( @simple_grammar.translate("", "one") ).to match_array [ ] }
378
+ it{ expect( @simple_grammar.translate("ab", :one) ).to match_array [ ] }
379
+ it{ expect( @simple_grammar.translate(" a ", :one) ).to match_array [ ] }
380
+ it{ expect( @simple_grammar.translate("NO", :one) ).to match_array [ ] }
381
+
382
+ it{ expect( @empty_grammar.translate("", :Z) ).to match_array [ ["Translate nothing",""] ] }
383
+ it{ expect( @empty_grammar.translate("NO", :Z) ).to match_array [ ] }
384
+ it{ expect( @empty_grammar.translate(" ", :Z) ).to match_array [ ] }
385
+ end
386
+
387
+ context "comlpex grammar - translations" do
388
+ before(:all) do
389
+ @tx_rep_set = TranslationRepetitionSet.new(3, "[", 4,"&",3,1,"&",2, "]")
390
+
391
+ @terminal_a = Terminal.new("a")
392
+ @terminal_b = Terminal.new("b")
393
+ @repetition = Repetition.new(" and ")
394
+ @complex_grammar = described_class.new
395
+ @grammar_with_self_referential_rule = described_class.new
396
+
397
+ @complex_grammar.add_rules :S, [ [@terminal_a, :A, @terminal_a, @repetition], [1,3,4," ",2,":",@tx_rep_set] ], [ [@terminal_a], ["IWasALoneA"] ]
398
+ @complex_grammar.add_rules :A, [ [@terminal_b, :S, @terminal_b], ["<",2,">"] ], [ [], ["-IWasNothing-"] ]
399
+
400
+ #Add self referential grammar and grammar with rules having nonterminals as the first thing in a production
401
+ #When that bug is fixed
402
+ @grammar_with_self_referential_rule.add_rules :S, [ [@terminal_a, :S, @terminal_a], [2] ], [ [@terminal_a], ["JustAnA"] ] , [ [:S, @repetition], [1,2] ]
403
+ end
404
+
405
+ it{ expect( @complex_grammar.translate("a", :S) ).to match_array [ ["IWasALoneA",""] ] }
406
+ it{ expect( @complex_grammar.translate("aa", :S) ).to match_array [ ["aa -IWasNothing-:",""] ] }
407
+ it{ expect( @complex_grammar.translate("ababa", :S) ).to match_array [ ["aa <IWasALoneA>:",""] ] }
408
+ it{ expect( @complex_grammar.translate("ababaababa", :S) ).to match_array [ ["aa <aa <aa -IWasNothing-:>:>:", ""] ] }
409
+ it{ expect( @complex_grammar.translate("aa and ababababa", :S) ).to match_array [ ["aa and -IWasNothing-:", ""] ] }
410
+ it{ expect( @complex_grammar.translate("aa and aa and ababa and aa and ababa and ababaababa", :S) ).to match_array [
411
+ ["aa and -IWasNothing-:[ and &aa&<IWasALoneA>][ and &aa&-IWasNothing-][ and &aa&<IWasALoneA>][&aa&<aa <aa -IWasNothing-:>:>]", ""]
412
+ ] }
413
+
414
+ #Bug
415
+ it{ expect{ @grammar_with_self_referential_rule.translate("a", :S) }.to raise_error(SystemStackError) }
416
+
417
+ it{ expect( @complex_grammar.translate("", :S) ).to match_array [] }
418
+ it{ expect( @complex_grammar.translate("a but also stuff that isn't in the grammar", :S) ).to match_array [] }
419
+ it{ expect( @complex_grammar.translate(" ababa", :S) ).to match_array [] }
420
+ end
421
+ end
422
+
423
+ end