rley 0.0.15 → 0.0.16
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 +8 -8
- data/CHANGELOG.md +8 -0
- data/lib/rley/constants.rb +1 -1
- data/lib/rley/parser/dotted_item.rb +15 -0
- data/lib/rley/parser/parse_state.rb +8 -0
- data/lib/rley/syntax/grammar.rb +2 -2
- data/lib/rley/syntax/grm_symbol.rb +6 -0
- data/lib/rley/syntax/symbol_seq.rb +3 -1
- data/lib/rley/syntax/verbatim_symbol.rb +6 -0
- data/spec/rley/parser/dotted_item_spec.rb +5 -0
- data/spec/rley/parser/earley_parser_spec.rb +160 -258
- data/spec/rley/parser/parse_state_spec.rb +5 -0
- data/spec/rley/syntax/grm_symbol_spec.rb +6 -0
- data/spec/rley/syntax/verbatim_symbol_spec.rb +7 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
N2UzY2I3ZGYxOWEyMDIyOTg4NTc3OGNmZjBmNmQ2ZjE1ZjVjYjI4ZQ==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
YWZjNjYzZmFkOWEyNjU2NGU1NjVmOWU2ZDdjZThiZjBhNzEyMTVmZg==
|
7
7
|
!binary "U0hBNTEy":
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
MTNlOThlZTYzNjBkZTMzNzBmOGYwM2RkNmM0M2IxNGQyMmU5NTZjMjQyMTM5
|
10
|
+
MzFmZGNmYTIyYWExMDc3ZjA0Nzc1YTc1ZWI5YjIwYjBiMzgzYTQ0Mjk3NDk3
|
11
|
+
MDVmYjk2NGUxMGY0NzBmOTk1NmFkY2I2YjNlZmRhZDk2MGMyYTA=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
ZDI3MWMzMzVjMDBkZDFiZDlmODNmM2MwYTI1ZTFiM2I1YmY3NjY1MDQ4Mjlj
|
14
|
+
ZDA4ZWFlZDFjZGNhNmM4YTJiYjg0YmM1ZGI0ZGExMmQxN2U5NzlmNDg2MTA3
|
15
|
+
MWRhZDdkYTBkODJhOWZmZDI2NDFmNGVlZWI5MDRmMTQyMTQwN2E=
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
### 0.0.16 / 2014-11-23
|
2
|
+
* [NEW] Method `DottedItem#to_s` Returns a text representation of an instance.
|
3
|
+
* [NEW] Method `ParseState#to_s`
|
4
|
+
* [NEW] Method `GrmSymbol#to_s`
|
5
|
+
* [NEW] Method `VerbatimSymbol#to_s`
|
6
|
+
* [CHANGE] File `earley_parser_spec.rb`: Parse tests refactored.
|
7
|
+
|
8
|
+
|
1
9
|
### 0.0.15 / 2014-11-20
|
2
10
|
* [FIX] `EarleyParser` class source code was out-of-sync.
|
3
11
|
|
data/lib/rley/constants.rb
CHANGED
@@ -30,6 +30,21 @@ module Rley # This module is used as a namespace
|
|
30
30
|
@position = valid_position(aPosition)
|
31
31
|
end
|
32
32
|
|
33
|
+
# Return a String representation of the dotted item.
|
34
|
+
# @return [String]
|
35
|
+
def to_s()
|
36
|
+
prefix = "#{production.lhs} => "
|
37
|
+
text_values = production.rhs.map(&:to_s)
|
38
|
+
if position < 0
|
39
|
+
text_values << '.'
|
40
|
+
else
|
41
|
+
text_values.insert(position, '.')
|
42
|
+
end
|
43
|
+
suffix = text_values.join(' ')
|
44
|
+
|
45
|
+
return prefix + suffix
|
46
|
+
end
|
47
|
+
|
33
48
|
# Return true if the dot position is at the start of the rhs.
|
34
49
|
def at_start?()
|
35
50
|
return position == 0 || position == -2
|
@@ -36,6 +36,14 @@ module Rley # This module is used as a namespace
|
|
36
36
|
return dotted_rule.next_symbol
|
37
37
|
end
|
38
38
|
|
39
|
+
# Give a String representation of itself.
|
40
|
+
# The format of the text representation is
|
41
|
+
# "format of dotted rule" + " | " + origin
|
42
|
+
# @return [String]
|
43
|
+
def to_s()
|
44
|
+
return dotted_rule.to_s + " | #{origin}"
|
45
|
+
end
|
46
|
+
|
39
47
|
private
|
40
48
|
|
41
49
|
# Return the validated dotted item(rule)
|
data/lib/rley/syntax/grammar.rb
CHANGED
@@ -53,7 +53,7 @@ module Rley # This module is used as a namespace
|
|
53
53
|
@symbols << the_lhs unless @symbols.include? the_lhs
|
54
54
|
|
55
55
|
# TODO: remove quadratic execution time
|
56
|
-
aProduction.rhs.
|
56
|
+
aProduction.rhs.each do |symb|
|
57
57
|
next if symbols.include? symb
|
58
58
|
@symbols << symb
|
59
59
|
end
|
@@ -68,7 +68,7 @@ module Rley # This module is used as a namespace
|
|
68
68
|
|
69
69
|
# Drop productions with one terminal in rhs or with a nullable lhs
|
70
70
|
filtered_rules = rules.reject do |prod|
|
71
|
-
prod.lhs.nullable? || prod.rhs.
|
71
|
+
prod.lhs.nullable? || prod.rhs.find do |symb|
|
72
72
|
symb.kind_of?(Terminal)
|
73
73
|
end
|
74
74
|
end
|
@@ -11,6 +11,12 @@ module Rley # This module is used as a namespace
|
|
11
11
|
def initialize(aName)
|
12
12
|
@name = aName.dup
|
13
13
|
end
|
14
|
+
|
15
|
+
# The String representation of the grammar symbol
|
16
|
+
# @return [String]
|
17
|
+
def to_s()
|
18
|
+
return name.to_s
|
19
|
+
end
|
14
20
|
|
15
21
|
end # class
|
16
22
|
end # module
|
@@ -5,7 +5,7 @@ module Rley # This module is used as a namespace
|
|
5
5
|
# A symbol sequence is a suite of grammar symbols
|
6
6
|
class SymbolSeq
|
7
7
|
extend Forwardable
|
8
|
-
def_delegators :@members, :empty?, :size, :[]
|
8
|
+
def_delegators :@members, :empty?, :size, :[], :each, :find, :map
|
9
9
|
|
10
10
|
# The sequence of symbols
|
11
11
|
attr_reader(:members)
|
@@ -28,6 +28,8 @@ module Rley # This module is used as a namespace
|
|
28
28
|
|
29
29
|
return result
|
30
30
|
end
|
31
|
+
|
32
|
+
|
31
33
|
end # class
|
32
34
|
end # module
|
33
35
|
end # module
|
@@ -12,6 +12,12 @@ module Rley # This module is used as a namespace
|
|
12
12
|
super(aText) # Do we need to separate the text from the name?
|
13
13
|
@text = aText.dup
|
14
14
|
end
|
15
|
+
|
16
|
+
# The String representation of the verbatim symbol
|
17
|
+
# @return [String]
|
18
|
+
def to_s()
|
19
|
+
return "'#{text}'"
|
20
|
+
end
|
15
21
|
end # class
|
16
22
|
end # module
|
17
23
|
end # module
|
@@ -94,6 +94,11 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
94
94
|
it 'should know the symbol after the dot' do
|
95
95
|
expect(subject.next_symbol).to eq(t_b)
|
96
96
|
end
|
97
|
+
|
98
|
+
it 'should give its text representation' do
|
99
|
+
expectation = "sentence => A . B C"
|
100
|
+
expect(subject.to_s).to eq(expectation)
|
101
|
+
end
|
97
102
|
end
|
98
103
|
|
99
104
|
end # describe
|
@@ -149,20 +149,11 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
149
149
|
end # context
|
150
150
|
|
151
151
|
context 'Parsing: ' do
|
152
|
-
# Helper method. Compare the data from the parse state
|
153
|
-
# with values from expectation hash.
|
154
|
-
def compare_state(aState, expectations)
|
155
|
-
expect(aState.origin).to eq(expectations[:origin])
|
156
|
-
dotted_item = aState.dotted_rule
|
157
|
-
expect(dotted_item.production).to eq(expectations[:production])
|
158
|
-
expect(dotted_item.position).to eq(expectations[:dot])
|
159
|
-
end
|
160
|
-
|
161
152
|
# Helper method. Compare the data from all the parse states
|
162
|
-
# of a given StateSet with an array of expectation
|
163
|
-
def
|
153
|
+
# of a given StateSet with an array of expectation string.
|
154
|
+
def compare_state_texts(aStateSet, expectations)
|
164
155
|
(0...expectations.size).each do |i|
|
165
|
-
|
156
|
+
expect(aStateSet.states[i].to_s).to eq(expectations[i])
|
166
157
|
end
|
167
158
|
end
|
168
159
|
|
@@ -172,79 +163,65 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
172
163
|
|
173
164
|
######################
|
174
165
|
# Expectation chart[0]:
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
{ origin: 0, production: prod_S, dot: 0 },
|
180
|
-
{ origin: 0, production: prod_A1, dot: 0 },
|
181
|
-
{ origin: 0, production: prod_A2, dot: 0 }
|
166
|
+
expected = [
|
167
|
+
"S => . A | 0", # start rule
|
168
|
+
"A => . 'a' A 'c' | 0", # predict from 0
|
169
|
+
"A => . 'b' | 0" # predict from 0
|
182
170
|
]
|
183
|
-
|
171
|
+
compare_state_texts(parse_result.chart[0], expected)
|
184
172
|
|
185
173
|
######################
|
186
|
-
state_set_1 = parse_result.chart[1]
|
187
|
-
expect(state_set_1.states.size).to eq(3)
|
188
174
|
# Expectation chart[1]:
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
{ origin: 0, production: prod_A1, dot: 1 },
|
194
|
-
{ origin: 1, production: prod_A1, dot: 0 },
|
195
|
-
{ origin: 1, production: prod_A2, dot: 0 }
|
175
|
+
expected = [
|
176
|
+
"A => 'a' . A 'c' | 0", # scan from S(0) 1
|
177
|
+
"A => . 'a' A 'c' | 1", # predict from 0
|
178
|
+
"A => . 'b' | 1" # predict from 0
|
196
179
|
]
|
197
|
-
|
180
|
+
state_set_1 = parse_result.chart[1]
|
181
|
+
expect(state_set_1.states.size).to eq(3)
|
182
|
+
compare_state_texts(state_set_1, expected)
|
198
183
|
|
199
184
|
######################
|
200
|
-
state_set_2 = parse_result.chart[2]
|
201
|
-
expect(state_set_2.states.size).to eq(3)
|
202
185
|
# Expectation chart[2]:
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
{ origin: 1, production: prod_A1, dot: 1 },
|
208
|
-
{ origin: 2, production: prod_A1, dot: 0 },
|
209
|
-
{ origin: 2, production: prod_A2, dot: 0 }
|
186
|
+
expected = [
|
187
|
+
"A => 'a' . A 'c' | 1", # scan from S(0) 1
|
188
|
+
"A => . 'a' A 'c' | 2", # predict from 0
|
189
|
+
"A => . 'b' | 2" # predict from 0
|
210
190
|
]
|
211
|
-
|
191
|
+
state_set_2 = parse_result.chart[2]
|
192
|
+
expect(state_set_2.states.size).to eq(3)
|
193
|
+
compare_state_texts(state_set_2, expected)
|
212
194
|
|
213
195
|
######################
|
214
|
-
state_set_3 = parse_result.chart[3]
|
215
|
-
expect(state_set_3.states.size).to eq(2)
|
216
196
|
# Expectation chart[3]:
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
{ origin: 2, production: prod_A2, dot: -1 },
|
221
|
-
{ origin: 1, production: prod_A1, dot: 2 }
|
197
|
+
expected = [
|
198
|
+
"A => 'b' . | 2", # scan from S(2) 2
|
199
|
+
"A => 'a' A . 'c' | 1" # complete from 0 and S(2) 0
|
222
200
|
]
|
223
|
-
|
201
|
+
state_set_3 = parse_result.chart[3]
|
202
|
+
expect(state_set_3.states.size).to eq(2)
|
203
|
+
compare_state_texts(state_set_3, expected)
|
204
|
+
|
224
205
|
|
225
206
|
######################
|
226
|
-
state_set_4 = parse_result.chart[4]
|
227
|
-
expect(state_set_4.states.size).to eq(2)
|
228
207
|
# Expectation chart[4]:
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
{ origin: 1, production: prod_A1, dot: -1 },
|
233
|
-
{ origin: 0, production: prod_A1, dot: 2 }
|
208
|
+
expected = [
|
209
|
+
"A => 'a' A 'c' . | 1", # scan from S(3) 1
|
210
|
+
"A => 'a' A . 'c' | 0" # complete from 0 and S(1) 0
|
234
211
|
]
|
235
|
-
|
212
|
+
state_set_4 = parse_result.chart[4]
|
213
|
+
expect(state_set_4.states.size).to eq(2)
|
214
|
+
compare_state_texts(state_set_4, expected)
|
236
215
|
|
237
216
|
######################
|
238
|
-
state_set_5 = parse_result.chart[5]
|
239
|
-
expect(state_set_5.states.size).to eq(2)
|
240
217
|
# Expectation chart[5]:
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
{ origin: 0, production: prod_A1, dot: -1 },
|
245
|
-
{ origin: 0, production: prod_S, dot: -1 }
|
218
|
+
expected = [
|
219
|
+
"A => 'a' A 'c' . | 0", # scan from S(4) 1
|
220
|
+
"S => A . | 0" # complete from 0 and S(0) 0
|
246
221
|
]
|
247
|
-
|
222
|
+
state_set_5 = parse_result.chart[5]
|
223
|
+
expect(state_set_5.states.size).to eq(2)
|
224
|
+
compare_state_texts(state_set_5, expected)
|
248
225
|
end
|
249
226
|
|
250
227
|
it 'should parse a valid simple expression' do
|
@@ -254,112 +231,85 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
254
231
|
|
255
232
|
###################### S(0): . 2 + 3 * 4
|
256
233
|
# Expectation chart[0]:
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
{ origin: 0, production: prod_P, dot: 0 },
|
265
|
-
{ origin: 0, production: prod_S1, dot: 0 },
|
266
|
-
{ origin: 0, production: prod_S2, dot: 0 },
|
267
|
-
{ origin: 0, production: prod_M1, dot: 0 },
|
268
|
-
{ origin: 0, production: prod_M2, dot: 0 },
|
269
|
-
{ origin: 0, production: prod_T, dot: 0 }
|
234
|
+
expected = [
|
235
|
+
"P => . S | 0", # start rule
|
236
|
+
"S => . S '+' M | 0", # predict from (1)
|
237
|
+
"S => . M | 0", # predict from (1)
|
238
|
+
"M => . M '*' T | 0", # predict from (3)
|
239
|
+
"M => . T | 0", # predict from (3)
|
240
|
+
"T => . integer | 0" # predict from (3)
|
270
241
|
]
|
271
|
-
|
242
|
+
compare_state_texts(parse_result.chart[0], expected)
|
243
|
+
|
272
244
|
|
273
245
|
###################### S(1): 2 . + 3 * 4
|
274
246
|
# Expectation chart[1]:
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
{ origin: 0, production: prod_T, dot: -1 },
|
283
|
-
{ origin: 0, production: prod_M2, dot: -1 },
|
284
|
-
{ origin: 0, production: prod_S2, dot: -1 },
|
285
|
-
{ origin: 0, production: prod_M1, dot: 1 },
|
286
|
-
{ origin: 0, production: prod_P, dot: -1 },
|
287
|
-
{ origin: 0, production: prod_S1, dot: 1 }
|
247
|
+
expected = [
|
248
|
+
"T => integer . | 0", # scan from S(0) 6
|
249
|
+
"M => T . | 0", # complete from (1) and S(0) 5
|
250
|
+
"S => M . | 0", # complete from (2) and S(0) 3
|
251
|
+
"M => M . '*' T | 0", # complete from (2) and S(0) 4
|
252
|
+
"P => S . | 0", # complete from (4) and S(0) 1
|
253
|
+
"S => S . '+' M | 0" # complete from (4) and S(0) 2
|
288
254
|
]
|
289
|
-
|
255
|
+
compare_state_texts(parse_result.chart[1], expected)
|
290
256
|
|
291
257
|
|
292
258
|
###################### S(2): 2 + . 3 * 4
|
293
259
|
# Expectation chart[2]:
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
{ origin: 0, production: prod_S1, dot: 2 },
|
300
|
-
{ origin: 2, production: prod_M1, dot: 0 },
|
301
|
-
{ origin: 2, production: prod_M2, dot: 0 },
|
302
|
-
{ origin: 2, production: prod_T, dot: 0 }
|
260
|
+
expected = [
|
261
|
+
"S => S '+' . M | 0", # scan from S(1) 6
|
262
|
+
"M => . M '*' T | 2", # predict from (1)
|
263
|
+
"M => . T | 2", # predict from (1)
|
264
|
+
"T => . integer | 2" # predict from (3)
|
303
265
|
]
|
304
|
-
|
266
|
+
compare_state_texts(parse_result.chart[2], expected)
|
267
|
+
|
305
268
|
|
306
269
|
###################### S(3): 2 + 3 . * 4
|
307
270
|
# Expectation chart[3]:
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
{ origin: 2, production: prod_T, dot: -1 },
|
315
|
-
{ origin: 2, production: prod_M2, dot: -1 },
|
316
|
-
{ origin: 0, production: prod_S1, dot: -1 },
|
317
|
-
{ origin: 2, production: prod_M1, dot: 1 },
|
318
|
-
{ origin: 0, production: prod_P, dot: -1 }
|
271
|
+
expected = [
|
272
|
+
"T => integer . | 2", # scan from S(2) 4
|
273
|
+
"M => T . | 2", # complete from (1) and S(2) 3
|
274
|
+
"S => S '+' M . | 0", # complete from (1) and S(2) 1
|
275
|
+
"M => M . '*' T | 2", # complete from (2) and S(2) 2
|
276
|
+
"P => S . | 0" # complete from (4) and S(0) 1
|
319
277
|
]
|
320
|
-
|
278
|
+
compare_state_texts(parse_result.chart[3], expected)
|
321
279
|
|
322
280
|
###################### S(4): 2 + 3 * . 4
|
323
281
|
# Expectation chart[4]:
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
expectations = [
|
328
|
-
{ origin: 2, production: prod_M1, dot: 2 },
|
329
|
-
{ origin: 4, production: prod_T, dot: 0 }
|
282
|
+
expected = [
|
283
|
+
"M => M '*' . T | 2", # scan from S(3) 4
|
284
|
+
"T => . integer | 4" # predict from (1)
|
330
285
|
]
|
331
|
-
|
286
|
+
compare_state_texts(parse_result.chart[4], expected)
|
332
287
|
|
333
288
|
###################### S(5): 2 + 3 * 4 .
|
334
289
|
# Expectation chart[5]:
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
{ origin: 4, production: prod_T, dot: -1 },
|
342
|
-
{ origin: 2, production: prod_M1, dot: -1 },
|
343
|
-
{ origin: 0, production: prod_S1, dot: -1 },
|
344
|
-
{ origin: 2, production: prod_M1, dot: 1 },
|
345
|
-
{ origin: 0, production: prod_P, dot: -1 }
|
290
|
+
expected = [
|
291
|
+
"T => integer . | 4", # scan from S(4) 2
|
292
|
+
"M => M '*' T . | 2", # complete from (1) and S(4) 1
|
293
|
+
"S => S '+' M . | 0", # complete from (2) and S(2) 1
|
294
|
+
"M => M . '*' T | 2", # complete from (2) and S(2) 2
|
295
|
+
"P => S . | 0" # complete from (3) and S(2) 2
|
346
296
|
]
|
347
|
-
|
297
|
+
compare_state_texts(parse_result.chart[5], expected)
|
348
298
|
end
|
349
|
-
|
350
|
-
|
299
|
+
|
300
|
+
|
351
301
|
it 'should parse an ambiguous grammar' do
|
352
302
|
# Grammar 3: A ambiguous arithmetic expression language
|
353
303
|
# (based on example in article on Earley's algorithm in Wikipedia)
|
354
|
-
# P
|
355
|
-
# S
|
356
|
-
# S
|
357
|
-
# S
|
358
|
-
# T
|
304
|
+
# P => S.
|
305
|
+
# S => S "+" S.
|
306
|
+
# S => S "*" S.
|
307
|
+
# S => T.
|
308
|
+
# T => an integer number token.
|
359
309
|
t_int = Syntax::Literal.new('integer', /[-+]?\d+/)
|
360
310
|
t_plus = Syntax::VerbatimSymbol.new('+')
|
361
311
|
t_star = Syntax::VerbatimSymbol.new('*')
|
362
|
-
|
312
|
+
|
363
313
|
builder = Syntax::GrammarBuilder.new
|
364
314
|
builder.add_terminals(t_int, t_plus, t_star)
|
365
315
|
builder.add_production('P' => 'S')
|
@@ -394,49 +344,35 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
394
344
|
|
395
345
|
###################### S(0) == . a a c c
|
396
346
|
# Expectation chart[0]:
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
{ origin: 0, production: prod_S, dot: 0 },
|
402
|
-
{ origin: 0, production: prod_A1, dot: 0 },
|
403
|
-
{ origin: 0, production: prod_A2, dot: 0 }
|
347
|
+
expected = [
|
348
|
+
"S => . A | 0", # start rule
|
349
|
+
"A => . 'a' A 'c' | 0", # predict from 0
|
350
|
+
"A => . 'b' | 0" # predict from 0
|
404
351
|
]
|
405
|
-
|
352
|
+
compare_state_texts(parse_result.chart[0], expected)
|
406
353
|
|
407
354
|
###################### S(1) == a . a c c
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
# 1: A -> . "a" A "c", 1 # predict from 0
|
413
|
-
# 2: A -> . "b", 1 # predict from 0
|
414
|
-
expectations = [
|
415
|
-
{ origin: 0, production: prod_A1, dot: 1 },
|
416
|
-
{ origin: 1, production: prod_A1, dot: 0 },
|
417
|
-
{ origin: 1, production: prod_A2, dot: 0 }
|
355
|
+
expected = [
|
356
|
+
"A => 'a' . A 'c' | 0", # scan from S(0) 1
|
357
|
+
"A => . 'a' A 'c' | 1", # predict from 0
|
358
|
+
"A => . 'b' | 1" # predict from 0
|
418
359
|
]
|
419
|
-
|
360
|
+
compare_state_texts(parse_result.chart[1], expected)
|
420
361
|
|
421
362
|
###################### S(2) == a a . c c
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
# 1: A -> . "a" A "c", 2 # predict from 0
|
427
|
-
# 2: A -> . "b", 2 # predict from 0
|
428
|
-
expectations = [
|
429
|
-
{ origin: 1, production: prod_A1, dot: 1 },
|
430
|
-
{ origin: 2, production: prod_A1, dot: 0 },
|
431
|
-
{ origin: 2, production: prod_A2, dot: 0 }
|
363
|
+
expected = [
|
364
|
+
"A => 'a' . A 'c' | 1", # scan from S(0) 1
|
365
|
+
"A => . 'a' A 'c' | 2", # predict from 0
|
366
|
+
"A => . 'b' | 2" # predict from 0
|
432
367
|
]
|
433
|
-
|
368
|
+
compare_state_texts(parse_result.chart[2], expected)
|
369
|
+
|
434
370
|
|
435
371
|
###################### S(3) == a a c? c
|
436
372
|
state_set_3 = parse_result.chart[3]
|
437
373
|
expect(state_set_3.states).to be_empty # This is an error symptom
|
438
374
|
end
|
439
|
-
|
375
|
+
|
440
376
|
it 'should parse a grammar with nullable nonterminals' do
|
441
377
|
# Grammar 4: A grammar with nullable nonterminal
|
442
378
|
# based on example in "Parsing Techniques" book (D. Grune, C. Jabobs)
|
@@ -446,11 +382,11 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
446
382
|
# F ::= a.
|
447
383
|
# Q ::= *.
|
448
384
|
# Q ::= /.
|
449
|
-
# Q ::=.
|
385
|
+
# Q ::=.
|
450
386
|
t_a = Syntax::VerbatimSymbol.new('a')
|
451
387
|
t_star = Syntax::VerbatimSymbol.new('*')
|
452
388
|
t_slash = Syntax::VerbatimSymbol.new('/')
|
453
|
-
|
389
|
+
|
454
390
|
builder = Syntax::GrammarBuilder.new
|
455
391
|
builder.add_terminals(t_a, t_star, t_slash)
|
456
392
|
builder.add_production('Z' => 'E')
|
@@ -458,8 +394,8 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
458
394
|
builder.add_production('E' => 'F')
|
459
395
|
builder.add_production('F' => t_a)
|
460
396
|
builder.add_production('Q' => t_star)
|
461
|
-
builder.add_production('Q' => t_slash)
|
462
|
-
builder.add_production('Q' => []) # Empty production
|
397
|
+
builder.add_production('Q' => t_slash)
|
398
|
+
builder.add_production('Q' => []) # Empty production
|
463
399
|
tokens = [
|
464
400
|
Token.new('a', t_a),
|
465
401
|
Token.new('a', t_a),
|
@@ -473,111 +409,77 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
473
409
|
prod_Q1 = builder.productions[4]
|
474
410
|
prod_Q2 = builder.productions[5]
|
475
411
|
prod_Q3 = builder.productions[6]
|
476
|
-
|
412
|
+
|
477
413
|
instance = EarleyParser.new(builder.grammar)
|
478
414
|
expect { instance.parse(tokens) }.not_to raise_error
|
479
415
|
parse_result = instance.parse(tokens)
|
480
416
|
expect(parse_result.success?).to eq(true)
|
481
|
-
|
417
|
+
|
482
418
|
###################### S(0) == . a a / a
|
483
419
|
# Expectation chart[0]:
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
{ origin: 0, production: prod_Z, dot: 0 },
|
490
|
-
{ origin: 0, production: prod_E1, dot: 0 },
|
491
|
-
{ origin: 0, production: prod_E2, dot: 0 },
|
492
|
-
{ origin: 0, production: prod_F, dot: 0 }
|
420
|
+
expected = [
|
421
|
+
"Z => . E | 0", # start rule
|
422
|
+
"E => . E Q F | 0", # predict from (1)
|
423
|
+
"E => . F | 0", # predict from (1)
|
424
|
+
"F => . 'a' | 0" # predict from (3)
|
493
425
|
]
|
494
|
-
|
426
|
+
compare_state_texts(parse_result.chart[0], expected)
|
495
427
|
|
496
428
|
###################### S(1) == a . a / a
|
497
429
|
# Expectation chart[1]:
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
503
|
-
|
504
|
-
|
505
|
-
|
506
|
-
|
507
|
-
|
508
|
-
{ origin: 0, production: prod_F, dot: -1 },
|
509
|
-
{ origin: 0, production: prod_E2, dot: -1 },
|
510
|
-
{ origin: 0, production: prod_Z, dot: -1 },
|
511
|
-
{ origin: 0, production: prod_E1, dot: 1 },
|
512
|
-
{ origin: 1, production: prod_Q1, dot: 0 },
|
513
|
-
{ origin: 1, production: prod_Q2, dot: 0 },
|
514
|
-
{ origin: 1, production: prod_Q3, dot: -2 },
|
515
|
-
{ origin: 0, production: prod_E1, dot: 2 },
|
516
|
-
{ origin: 1, production: prod_F, dot: 0 }
|
430
|
+
expected = [
|
431
|
+
"F => 'a' . | 0", # scan from S(0) 4
|
432
|
+
"E => F . | 0", # complete from (1) and S(0) 3
|
433
|
+
"Z => E . | 0", # complete from (2) and S(0) 1
|
434
|
+
"E => E . Q F | 0", # complete from (2) and S(0) 2
|
435
|
+
"Q => . '*' | 1", # Predict from (4)
|
436
|
+
"Q => . '/' | 1", # Predict from (4)
|
437
|
+
"Q => . | 1", # Predict from (4)
|
438
|
+
"E => E Q . F | 0", # Modified predict from (4)
|
439
|
+
"F => . 'a' | 1" # Predict from (8)
|
517
440
|
]
|
518
|
-
|
441
|
+
compare_state_texts(parse_result.chart[1], expected)
|
519
442
|
|
520
443
|
###################### S(2) == a a . / a
|
521
444
|
# Expectation chart[2]:
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
530
|
-
|
531
|
-
|
532
|
-
{ origin: 1, production: prod_F, dot: -1 },
|
533
|
-
{ origin: 0, production: prod_E1, dot: -1 },
|
534
|
-
{ origin: 0, production: prod_Z, dot: -1 },
|
535
|
-
{ origin: 0, production: prod_E1, dot: 1 },
|
536
|
-
{ origin: 2, production: prod_Q1, dot: 0 },
|
537
|
-
{ origin: 2, production: prod_Q2, dot: 0 },
|
538
|
-
{ origin: 2, production: prod_Q3, dot: -2 },
|
539
|
-
{ origin: 0, production: prod_E1, dot: 2 },
|
540
|
-
{ origin: 2, production: prod_F, dot: 0 },
|
445
|
+
expected = [
|
446
|
+
"F => 'a' . | 1", # scan from S(1) 9
|
447
|
+
"E => E Q F . | 0", # complete from (1) and S(1) 8
|
448
|
+
"Z => E . | 0", # complete from (1) and S(0) 1
|
449
|
+
"E => E . Q F | 0", # complete from (1) and S(0) 2
|
450
|
+
"Q => . '*' | 2", # Predict from (4)
|
451
|
+
"Q => . '/' | 2", # Predict from (4)
|
452
|
+
"Q => . | 2", # Predict from (4)
|
453
|
+
"E => E Q . F | 0", # Complete from (5) and S(1) 4
|
454
|
+
"F => . 'a' | 2" # Predict from (8)
|
541
455
|
]
|
542
|
-
|
456
|
+
compare_state_texts(parse_result.chart[2], expected)
|
457
|
+
|
543
458
|
|
544
459
|
###################### S(3) == a a / . a
|
545
460
|
# Expectation chart[3]:
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
{ origin: 2, production: prod_Q2, dot: -1 },
|
551
|
-
{ origin: 0, production: prod_E1, dot: 2 },
|
552
|
-
{ origin: 3, production: prod_F, dot: 0 }
|
461
|
+
expected = [
|
462
|
+
"Q => '/' . | 2", # scan from S(2) 6
|
463
|
+
"E => E Q . F | 0", # complete from (1) and S(1) 4
|
464
|
+
"F => . 'a' | 3" # Predict from (2)
|
553
465
|
]
|
554
|
-
|
466
|
+
compare_state_texts(parse_result.chart[3], expected)
|
467
|
+
|
555
468
|
|
556
|
-
|
557
469
|
###################### S(4) == a a / a .
|
558
470
|
# Expectation chart[4]:
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
{ origin: 3, production: prod_F, dot: -1 },
|
570
|
-
{ origin: 0, production: prod_E1, dot: -1 },
|
571
|
-
{ origin: 0, production: prod_Z, dot: -1 },
|
572
|
-
{ origin: 0, production: prod_E1, dot: 1 },
|
573
|
-
{ origin: 4, production: prod_Q1, dot: 0 },
|
574
|
-
{ origin: 4, production: prod_Q2, dot: 0 },
|
575
|
-
{ origin: 4, production: prod_Q3, dot: -2 },
|
576
|
-
{ origin: 0, production: prod_E1, dot: 2 },
|
577
|
-
{ origin: 4, production: prod_F, dot: 0 },
|
471
|
+
expected = [
|
472
|
+
"F => 'a' . | 3", # scan from S(3) 3
|
473
|
+
"E => E Q F . | 0", # complete from (1) and S(3) 2
|
474
|
+
"Z => E . | 0", # complete from (2) and S(0) 1
|
475
|
+
"E => E . Q F | 0", # complete from (2) and S(0) 2
|
476
|
+
"Q => . '*' | 4", # Predict from (4)
|
477
|
+
"Q => . '/' | 4", # Predict from (4)
|
478
|
+
"Q => . | 4", # Predict from (4)
|
479
|
+
"E => E Q . F | 0", # Modified predict from (4)
|
480
|
+
"F => . 'a' | 4" # Predict from (8)
|
578
481
|
]
|
579
|
-
|
580
|
-
|
482
|
+
compare_state_texts(parse_result.chart[4], expected)
|
581
483
|
end
|
582
484
|
end # context
|
583
485
|
|
@@ -90,6 +90,11 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
90
90
|
it 'should know the next expected symbol' do
|
91
91
|
expect(subject.next_symbol).to eq(t_c)
|
92
92
|
end
|
93
|
+
|
94
|
+
it 'should know its text representation' do
|
95
|
+
expected = 'sentence => A B . C | 3'
|
96
|
+
expect(subject.to_s).to eq(expected)
|
97
|
+
end
|
93
98
|
end # context
|
94
99
|
|
95
100
|
end # describe
|
@@ -18,6 +18,12 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
18
18
|
expect(subject.name).to eq(sample_name)
|
19
19
|
end
|
20
20
|
end # context
|
21
|
+
|
22
|
+
context 'Provided services:' do
|
23
|
+
it 'should give its text representation' do
|
24
|
+
expect(subject.to_s).to eq(sample_name)
|
25
|
+
end
|
26
|
+
end # context
|
21
27
|
|
22
28
|
end # describe
|
23
29
|
end # module
|
@@ -22,6 +22,13 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
22
22
|
expect(subject.text).to eq(sample_name)
|
23
23
|
end
|
24
24
|
end # context
|
25
|
+
|
26
|
+
context 'Provided services:' do
|
27
|
+
it 'should give its text representation' do
|
28
|
+
expected = "'#{sample_name}'"
|
29
|
+
expect(subject.to_s).to eq(expected)
|
30
|
+
end
|
31
|
+
end # context
|
25
32
|
|
26
33
|
end # describe
|
27
34
|
end # module
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rley
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.16
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dimitri Geshef
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-11-
|
11
|
+
date: 2014-11-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|