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.
- checksums.yaml +15 -0
- data/.gitignore +14 -0
- data/.rspec +2 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +64 -0
- data/Rakefile +2 -0
- data/cofgratx.gemspec +24 -0
- data/lib/cofgratx.rb +10 -0
- data/lib/cofgratx/cfg/grammar.rb +46 -0
- data/lib/cofgratx/cfg/grammar_error.rb +2 -0
- data/lib/cofgratx/cfg/non_terminal.rb +54 -0
- data/lib/cofgratx/cfg/repetition.rb +9 -0
- data/lib/cofgratx/cfg/rule.rb +160 -0
- data/lib/cofgratx/cfg/rule_error.rb +2 -0
- data/lib/cofgratx/cfg/terminal.rb +25 -0
- data/lib/cofgratx/cfg/translation_repetition_set.rb +33 -0
- data/lib/cofgratx/cfg/translation_repetition_set_error.rb +2 -0
- data/lib/cofgratx/version.rb +3 -0
- data/spec/grammar_spec.rb +423 -0
- data/spec/non_terminal_spec.rb +126 -0
- data/spec/repetition_spec.rb +48 -0
- data/spec/rule_spec.rb +247 -0
- data/spec/spec_helper.rb +91 -0
- data/spec/terminal_spec.rb +60 -0
- data/spec/translation_repetition_set_spec.rb +68 -0
- metadata +119 -0
@@ -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,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
|