rley 0.3.04 → 0.3.05
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 +4 -4
- data/.rubocop.yml +7 -3
- data/CHANGELOG.md +3 -0
- data/Rakefile +30 -30
- data/examples/parsers/parsing_L0.rb +1 -1
- data/examples/parsers/parsing_L1.rb +1 -1
- data/examples/parsers/parsing_abc.rb +1 -1
- data/examples/parsers/parsing_ambig.rb +1 -1
- data/examples/parsers/parsing_another.rb +1 -1
- data/examples/parsers/parsing_b_expr.rb +1 -1
- data/examples/parsers/parsing_err_expr.rb +1 -1
- data/examples/parsers/parsing_groucho.rb +1 -1
- data/examples/parsers/parsing_right_recursive.rb +1 -1
- data/examples/parsers/parsing_tricky.rb +1 -1
- data/lib/rley/constants.rb +2 -2
- data/lib/rley/formatter/base_formatter.rb +0 -2
- data/lib/rley/formatter/debug.rb +0 -2
- data/lib/rley/formatter/json.rb +1 -3
- data/lib/rley/gfg/call_edge.rb +31 -30
- data/lib/rley/gfg/edge.rb +22 -23
- data/lib/rley/gfg/end_vertex.rb +22 -24
- data/lib/rley/gfg/epsilon_edge.rb +20 -21
- data/lib/rley/gfg/grm_flow_graph.rb +39 -39
- data/lib/rley/gfg/item_vertex.rb +16 -17
- data/lib/rley/gfg/non_terminal_vertex.rb +3 -4
- data/lib/rley/gfg/return_edge.rb +32 -31
- data/lib/rley/gfg/scan_edge.rb +25 -26
- data/lib/rley/gfg/shortcut_edge.rb +25 -26
- data/lib/rley/gfg/start_vertex.rb +0 -2
- data/lib/rley/gfg/vertex.rb +8 -8
- data/lib/rley/parse_forest_visitor.rb +113 -115
- data/lib/rley/parse_tree_visitor.rb +0 -2
- data/lib/rley/parser/base_parser.rb +27 -27
- data/lib/rley/parser/chart.rb +14 -14
- data/lib/rley/parser/dotted_item.rb +33 -33
- data/lib/rley/parser/earley_parser.rb +6 -6
- data/lib/rley/parser/gfg_chart.rb +8 -15
- data/lib/rley/parser/gfg_earley_parser.rb +15 -13
- data/lib/rley/parser/gfg_parsing.rb +26 -22
- data/lib/rley/parser/grm_items_builder.rb +3 -2
- data/lib/rley/parser/parse_entry.rb +3 -9
- data/lib/rley/parser/parse_entry_set.rb +14 -19
- data/lib/rley/parser/parse_entry_tracker.rb +56 -56
- data/lib/rley/parser/parse_forest_builder.rb +215 -214
- data/lib/rley/parser/parse_forest_factory.rb +57 -56
- data/lib/rley/parser/parse_state.rb +8 -11
- data/lib/rley/parser/parse_state_tracker.rb +56 -56
- data/lib/rley/parser/parse_tracer.rb +3 -3
- data/lib/rley/parser/parse_tree_builder.rb +10 -10
- data/lib/rley/parser/parse_walker_factory.rb +30 -33
- data/lib/rley/parser/parsing.rb +8 -8
- data/lib/rley/parser/state_set.rb +23 -26
- data/lib/rley/ptree/non_terminal_node.rb +1 -1
- data/lib/rley/ptree/token_range.rb +2 -2
- data/lib/rley/sppf/alternative_node.rb +32 -34
- data/lib/rley/sppf/composite_node.rb +27 -27
- data/lib/rley/sppf/epsilon_node.rb +26 -27
- data/lib/rley/sppf/leaf_node.rb +11 -12
- data/lib/rley/sppf/non_terminal_node.rb +37 -38
- data/lib/rley/sppf/sppf_node.rb +1 -1
- data/lib/rley/sppf/token_node.rb +29 -29
- data/lib/rley/syntax/grammar.rb +1 -3
- data/lib/rley/syntax/grammar_builder.rb +8 -8
- data/lib/rley/syntax/non_terminal.rb +2 -4
- data/lib/rley/syntax/production.rb +3 -3
- data/lib/rley/syntax/symbol_seq.rb +1 -1
- data/spec/rley/gfg/call_edge_spec.rb +50 -51
- data/spec/rley/gfg/edge_spec.rb +33 -33
- data/spec/rley/gfg/end_vertex_spec.rb +26 -27
- data/spec/rley/gfg/epsilon_edge_spec.rb +25 -25
- data/spec/rley/gfg/grm_flow_graph_spec.rb +1 -1
- data/spec/rley/gfg/item_vertex_spec.rb +3 -4
- data/spec/rley/gfg/return_edge_spec.rb +51 -51
- data/spec/rley/gfg/scan_edge_spec.rb +32 -30
- data/spec/rley/gfg/shortcut_edge_spec.rb +1 -1
- data/spec/rley/gfg/vertex_spec.rb +3 -3
- data/spec/rley/parse_forest_visitor_spec.rb +239 -238
- data/spec/rley/parser/dotted_item_spec.rb +1 -1
- data/spec/rley/parser/earley_parser_spec.rb +16 -16
- data/spec/rley/parser/gfg_earley_parser_spec.rb +30 -31
- data/spec/rley/parser/gfg_parsing_spec.rb +11 -10
- data/spec/rley/parser/grm_items_builder_spec.rb +2 -2
- data/spec/rley/parser/parse_entry_set_spec.rb +4 -4
- data/spec/rley/parser/parse_entry_spec.rb +0 -2
- data/spec/rley/parser/parse_forest_builder_spec.rb +82 -57
- data/spec/rley/parser/parse_forest_factory_spec.rb +84 -82
- data/spec/rley/parser/parse_walker_factory_spec.rb +10 -9
- data/spec/rley/parser/parsing_spec.rb +0 -1
- data/spec/rley/sppf/alternative_node_spec.rb +2 -2
- data/spec/rley/sppf/non_terminal_node_spec.rb +0 -1
- data/spec/rley/support/ambiguous_grammar_helper.rb +1 -1
- data/spec/rley/support/expectation_helper.rb +37 -36
- data/spec/rley/support/grammar_abc_helper.rb +17 -17
- data/spec/rley/support/grammar_b_expr_helper.rb +40 -39
- data/spec/rley/support/grammar_helper.rb +2 -1
- data/spec/rley/support/{grammar_L0_helper.rb → grammar_l0_helper.rb} +82 -81
- data/spec/rley/support/grammar_sppf_helper.rb +24 -25
- data/spec/rley/syntax/grammar_spec.rb +1 -1
- metadata +2 -2
@@ -126,7 +126,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
126
126
|
|
127
127
|
# Case: different productions
|
128
128
|
instance = DottedItem.new(empty_prod, 0)
|
129
|
-
expect(subject).not_to be_successor_of(
|
129
|
+
expect(subject).not_to be_successor_of(instance)
|
130
130
|
|
131
131
|
# Case: one position difference
|
132
132
|
instance = DottedItem.new(sample_prod, 0)
|
@@ -220,8 +220,8 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
220
220
|
######################
|
221
221
|
# Expectation chart[5]:
|
222
222
|
expected = [
|
223
|
-
"A => 'a' A 'c' . | 0",
|
224
|
-
'S => A . | 0'
|
223
|
+
"A => 'a' A 'c' . | 0", # scan from S(4) 1
|
224
|
+
'S => A . | 0' # complete from 0 and S(0) 0
|
225
225
|
]
|
226
226
|
state_set_5 = parse_result.chart[5]
|
227
227
|
expect(state_set_5.states.size).to eq(2)
|
@@ -325,7 +325,7 @@ SNIPPET
|
|
325
325
|
###################### S(5): 2 + 3 * 4 .
|
326
326
|
# Expectation chart[5]:
|
327
327
|
expected = [
|
328
|
-
'T => integer . | 4',
|
328
|
+
'T => integer . | 4', # scan from S(4) 2
|
329
329
|
"M => M '*' T . | 2", # complete from (1) and S(4) 1
|
330
330
|
"S => S '+' M . | 0", # complete from (2) and S(2) 1
|
331
331
|
"M => M . '*' T | 2", # complete from (2) and S(2) 2
|
@@ -357,14 +357,14 @@ SNIPPET
|
|
357
357
|
"Ss => . A A 'x' | 0", # Start rule
|
358
358
|
'A => . | 0', # predict from (1)
|
359
359
|
"Ss => A . A 'x' | 0", # modified predict from (1)
|
360
|
-
"Ss => A A . 'x' | 0"
|
360
|
+
"Ss => A A . 'x' | 0" # modified predict from (1)
|
361
361
|
]
|
362
362
|
compare_state_texts(parse_result.chart[0], expected)
|
363
363
|
|
364
364
|
###################### S(1): x .
|
365
365
|
# Expectation chart[1]:
|
366
366
|
expected = [
|
367
|
-
"Ss => A A 'x' . | 0"
|
367
|
+
"Ss => A A 'x' . | 0" # scan from S(0) 4
|
368
368
|
]
|
369
369
|
compare_state_texts(parse_result.chart[1], expected)
|
370
370
|
end
|
@@ -415,7 +415,7 @@ SNIPPET
|
|
415
415
|
###################### S(1): 2 . + 3 * 4
|
416
416
|
# Expectation chart[1]:
|
417
417
|
expected = [
|
418
|
-
'L => integer . | 0',
|
418
|
+
'L => integer . | 0', # scan from S(0) 4
|
419
419
|
'S => L . | 0', # complete from (1) and S(0) 4
|
420
420
|
'P => S . | 0', # complete from (2) and S(0) 1
|
421
421
|
"S => S . '+' S | 0", # complete from (2) and S(0) 2
|
@@ -439,7 +439,7 @@ SNIPPET
|
|
439
439
|
expected = [
|
440
440
|
'L => integer . | 2', # scan from S(2) 5
|
441
441
|
'S => L . | 2', # complete from (1) and S(2) 4
|
442
|
-
"S => S '+' S . | 0",
|
442
|
+
"S => S '+' S . | 0", # complete from (2) and S(2) 1
|
443
443
|
"S => S . '+' S | 2", # complete from (2) and S(2) 2
|
444
444
|
"S => S . '*' S | 2", # complete from (2) and S(2) 3
|
445
445
|
'P => S . | 0', # complete from (2) and S(0) 1
|
@@ -649,15 +649,15 @@ MSG
|
|
649
649
|
###################### S(1) == a . a / a
|
650
650
|
# Expectation chart[1]:
|
651
651
|
expected = [
|
652
|
-
"F => 'a' . | 0",
|
653
|
-
'E => F . | 0',
|
654
|
-
'Z => E . | 0',
|
655
|
-
'E => E . Q F | 0',
|
656
|
-
"Q => . '*' | 1",
|
657
|
-
"Q => . '/' | 1",
|
658
|
-
'Q => . | 1',
|
659
|
-
'E => E Q . F | 0',
|
660
|
-
"F => . 'a' | 1"
|
652
|
+
"F => 'a' . | 0", # scan from S(0) 4
|
653
|
+
'E => F . | 0', # complete from (1) and S(0) 3
|
654
|
+
'Z => E . | 0', # complete from (2) and S(0) 1
|
655
|
+
'E => E . Q F | 0', # complete from (2) and S(0) 2
|
656
|
+
"Q => . '*' | 1", # Predict from (4)
|
657
|
+
"Q => . '/' | 1", # Predict from (4)
|
658
|
+
'Q => . | 1', # Predict from (4)
|
659
|
+
'E => E Q . F | 0', # Modified predict from (4)
|
660
|
+
"F => . 'a' | 1" # Predict from (8)
|
661
661
|
]
|
662
662
|
compare_state_texts(parse_result.chart[1], expected)
|
663
663
|
|
@@ -66,11 +66,15 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
66
66
|
|
67
67
|
# Helper method that mimicks the output of a tokenizer
|
68
68
|
# for the language specified by grammar_expr
|
69
|
-
def grm2_tokens()
|
70
|
-
input_sequence = [
|
71
|
-
|
69
|
+
def grm2_tokens()
|
70
|
+
input_sequence = [
|
71
|
+
{ '2' => 'integer' },
|
72
|
+
'+',
|
73
|
+
{ '3' => 'integer' },
|
74
|
+
'*',
|
75
|
+
{ '4' => 'integer' }
|
72
76
|
]
|
73
|
-
return
|
77
|
+
return build_token_sequence(input_sequence, grammar_expr)
|
74
78
|
end
|
75
79
|
|
76
80
|
# Default instantiation rule
|
@@ -272,7 +276,7 @@ SNIPPET
|
|
272
276
|
"M => M . '*' T | 2", # end rule
|
273
277
|
'S. | 0', # exit rule
|
274
278
|
'P => S . | 0', # end rule
|
275
|
-
"S => S . '+' M | 0",
|
279
|
+
"S => S . '+' M | 0", # end rule
|
276
280
|
'P. | 0' # exit rule
|
277
281
|
]
|
278
282
|
compare_entry_texts(parse_result.chart[3], expected)
|
@@ -361,12 +365,12 @@ SNIPPET
|
|
361
365
|
builder.add_production('S' => %w(S * S))
|
362
366
|
builder.add_production('S' => 'L')
|
363
367
|
builder.add_production('L' => 'integer')
|
364
|
-
input_sequence = [
|
365
|
-
{'2' => 'integer'},
|
366
|
-
'+',
|
367
|
-
{'3' => 'integer'},
|
368
|
-
'*',
|
369
|
-
{'4' => 'integer'}
|
368
|
+
input_sequence = [
|
369
|
+
{ '2' => 'integer' },
|
370
|
+
'+',
|
371
|
+
{ '3' => 'integer' },
|
372
|
+
'*',
|
373
|
+
{ '4' => 'integer' }
|
370
374
|
]
|
371
375
|
tokens = build_token_sequence(input_sequence, builder.grammar)
|
372
376
|
instance = GFGEarleyParser.new(builder.grammar)
|
@@ -470,7 +474,7 @@ SNIPPET
|
|
470
474
|
'P. | 0' # exit rule
|
471
475
|
]
|
472
476
|
compare_entry_texts(parse_result.chart[5], expected)
|
473
|
-
|
477
|
+
|
474
478
|
expected_antecedents = {
|
475
479
|
'L => integer . | 4' => ['L => . integer | 4'],
|
476
480
|
'L. | 4' => ['L => integer . | 4'],
|
@@ -478,14 +482,14 @@ SNIPPET
|
|
478
482
|
'S. | 4' => ['S => L . | 4'],
|
479
483
|
"S => S '*' S . | 2" => ['S. | 4'],
|
480
484
|
"S => S '*' S . | 0" => ['S. | 4'],
|
481
|
-
"S => S . '+' S | 4" => ['S. | 4'],
|
485
|
+
"S => S . '+' S | 4" => ['S. | 4'],
|
482
486
|
"S => S . '*' S | 4" => ['S. | 4'],
|
483
487
|
'S. | 2' => ["S => S '*' S . | 2"],
|
484
488
|
'S. | 0' => ["S => S '*' S . | 0", "S => S '+' S . | 0"],
|
485
489
|
"S => S '+' S . | 0" => ['S. | 2'],
|
486
490
|
"S => S . '+' S | 2" => ['S. | 2'],
|
487
491
|
"S => S . '*' S | 2" => ['S. | 2'],
|
488
|
-
'P => S . | 0'
|
492
|
+
'P => S . | 0' => ['S. | 0'],
|
489
493
|
"S => S . '+' S | 0" => ['S. | 0'],
|
490
494
|
"S => S . '*' S | 0" => ['S. | 0'],
|
491
495
|
'P. | 0' => ['P => S . | 0']
|
@@ -518,7 +522,7 @@ SNIPPET
|
|
518
522
|
# Expectation chart[1]:
|
519
523
|
expected = [
|
520
524
|
'E => id . | 0', # scan 'abc'
|
521
|
-
'E. | 0',
|
525
|
+
'E. | 0', # exit rule
|
522
526
|
'S => E . | 0', # end rule
|
523
527
|
'E => E . + E | 0', # end rule
|
524
528
|
'S. | 0' # exit rule
|
@@ -603,14 +607,14 @@ MSG
|
|
603
607
|
builder.add_terminals(t_int, t_plus, t_lparen, t_rparen)
|
604
608
|
builder.add_production('S' => 'E')
|
605
609
|
builder.add_production('E' => 'int')
|
606
|
-
builder.add_production('E' => %w
|
607
|
-
builder.add_production('E' => %w(
|
608
|
-
input_sequence = [
|
609
|
-
{'7' => 'int'},
|
610
|
-
'+',
|
611
|
-
{'8' => 'int'},
|
612
|
-
'+',
|
613
|
-
{'9' => 'int'}
|
610
|
+
builder.add_production('E' => %w(( E + E )))
|
611
|
+
builder.add_production('E' => %w(E + E))
|
612
|
+
input_sequence = [
|
613
|
+
{ '7' => 'int' },
|
614
|
+
'+',
|
615
|
+
{ '8' => 'int' },
|
616
|
+
'+',
|
617
|
+
{ '9' => 'int' }
|
614
618
|
]
|
615
619
|
tokens = build_token_sequence(input_sequence, builder.grammar)
|
616
620
|
instance = GFGEarleyParser.new(builder.grammar)
|
@@ -644,7 +648,7 @@ MSG
|
|
644
648
|
expected = [
|
645
649
|
"E => E '+' . E | 0", # scan '+'
|
646
650
|
'.E | 2', # exit rule
|
647
|
-
|
651
|
+
'E => . int | 2', # start rule
|
648
652
|
"E => . '(' E '+' E ')' | 2", # start rule
|
649
653
|
"E => . E '+' E | 2" # start rule
|
650
654
|
]
|
@@ -718,7 +722,7 @@ MSG
|
|
718
722
|
builder.add_production('Q' => t_star)
|
719
723
|
builder.add_production('Q' => t_slash)
|
720
724
|
builder.add_production('Q' => []) # Empty production
|
721
|
-
|
725
|
+
|
722
726
|
tokens = build_token_sequence(%w(a a / a), builder.grammar)
|
723
727
|
instance = GFGEarleyParser.new(builder.grammar)
|
724
728
|
expect { instance.parse(tokens) }.not_to raise_error
|
@@ -823,9 +827,6 @@ MSG
|
|
823
827
|
# S => ;
|
824
828
|
# This grammar requires a time that is quadratic in the number of
|
825
829
|
# input tokens
|
826
|
-
|
827
|
-
t_x = Syntax::VerbatimSymbol.new('x')
|
828
|
-
|
829
830
|
builder = Syntax::GrammarBuilder.new
|
830
831
|
builder.add_terminals('a')
|
831
832
|
builder.add_production('S' => %w(a S))
|
@@ -909,10 +910,8 @@ MSG
|
|
909
910
|
]
|
910
911
|
compare_entry_texts(parse_result.chart[4], expected)
|
911
912
|
end
|
912
|
-
|
913
913
|
end # context
|
914
914
|
end # describe
|
915
915
|
end # module
|
916
916
|
end # module
|
917
|
-
|
918
|
-
# End of module
|
917
|
+
# End of file
|
@@ -79,8 +79,9 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
79
79
|
end
|
80
80
|
|
81
81
|
it 'should have no antecedence for the initial parse entry' do
|
82
|
-
|
83
|
-
expect(
|
82
|
+
antecedence = subject.antecedence
|
83
|
+
expect(antecedence.size).to eq(1)
|
84
|
+
expect(antecedence.fetch(subject.initial_entry)).to be_empty
|
84
85
|
end
|
85
86
|
|
86
87
|
=begin
|
@@ -186,7 +187,7 @@ SNIPPET
|
|
186
187
|
|
187
188
|
it 'should apply the scan rule correctly' do
|
188
189
|
# Filling manually first entry set...
|
189
|
-
fill_first_set
|
190
|
+
fill_first_set
|
190
191
|
# There are two entries expecting a terminal:
|
191
192
|
# ['A => . a A c', 'A => . b']
|
192
193
|
fourth_entry = subject.chart[0].entries[3] # 'A => . a A c'
|
@@ -201,15 +202,16 @@ SNIPPET
|
|
201
202
|
# Entry must be past the terminal symbol
|
202
203
|
expect(last_entry.vertex.label).to eq('A => a . A c')
|
203
204
|
expect(last_entry.origin).to eq(0)
|
204
|
-
|
205
|
+
antecedence = subject.antecedence
|
206
|
+
expect(antecedence.fetch(last_entry)).to eq([fourth_entry])
|
205
207
|
end
|
206
208
|
|
207
209
|
it 'should apply the exit rule correctly' do
|
208
210
|
# Filling manually first entry set...
|
209
|
-
fill_first_set
|
211
|
+
fill_first_set
|
210
212
|
|
211
213
|
# Initial manually first entry set...
|
212
|
-
seed_second_set
|
214
|
+
seed_second_set
|
213
215
|
|
214
216
|
# Given that the scanned token is 'b'...
|
215
217
|
# Then a new entry is added in next entry set
|
@@ -231,10 +233,10 @@ SNIPPET
|
|
231
233
|
|
232
234
|
it 'should apply the end rule correctly' do
|
233
235
|
# Filling manually first entry set...
|
234
|
-
fill_first_set
|
236
|
+
fill_first_set
|
235
237
|
|
236
238
|
# Initial manually first entry set...
|
237
|
-
seed_second_set
|
239
|
+
seed_second_set
|
238
240
|
last_entry = subject.chart[1].last
|
239
241
|
|
240
242
|
# Given that the scanned token is 'b'...
|
@@ -290,7 +292,6 @@ SNIPPET
|
|
290
292
|
end # context
|
291
293
|
|
292
294
|
context 'Parse forest building:' do
|
293
|
-
|
294
295
|
let(:sample_grammar1) do
|
295
296
|
builder = grammar_abc_builder
|
296
297
|
builder.grammar
|
@@ -318,7 +319,7 @@ SNIPPET
|
|
318
319
|
end
|
319
320
|
|
320
321
|
it 'should build a parse forest' do
|
321
|
-
expect{subject.parse_forest }.not_to raise_error
|
322
|
+
expect { subject.parse_forest }.not_to raise_error
|
322
323
|
|
323
324
|
end
|
324
325
|
=begin
|
@@ -31,7 +31,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
31
31
|
'A => a A . c',
|
32
32
|
'A => a A c .',
|
33
33
|
'A => . b',
|
34
|
-
'A => b .'
|
34
|
+
'A => b .'
|
35
35
|
]
|
36
36
|
expect(items.map(&:to_s)).to eq(expectations)
|
37
37
|
end
|
@@ -40,4 +40,4 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
40
40
|
end # module
|
41
41
|
end # module
|
42
42
|
|
43
|
-
# End of file
|
43
|
+
# End of file
|
@@ -20,10 +20,10 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
20
20
|
let(:t_a) { Rley::Syntax::Terminal.new('a') }
|
21
21
|
let(:t_b) { Rley::Syntax::Terminal.new('b') }
|
22
22
|
let(:t_c) { Rley::Syntax::Terminal.new('c') }
|
23
|
-
let(:
|
24
|
-
let(:repeated_prod) { build_prod(
|
23
|
+
let(:nt_rep_c) { Rley::Syntax::NonTerminal.new('Repetition') }
|
24
|
+
let(:repeated_prod) { build_prod(nt_rep_c, t_c, nt_rep_c) }
|
25
25
|
let(:nt_sentence) { Rley::Syntax::NonTerminal.new('Sentence') }
|
26
|
-
let(:sample_prod) { build_prod(nt_sentence, t_a, t_b, t_b,
|
26
|
+
let(:sample_prod) { build_prod(nt_sentence, t_a, t_b, t_b, nt_rep_c) }
|
27
27
|
|
28
28
|
let(:sample_item1) { Parser::DottedItem.new(sample_prod, 1) }
|
29
29
|
let(:sample_item2) { Parser::DottedItem.new(sample_prod, 2) }
|
@@ -88,7 +88,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
88
88
|
it 'should list the entries expecting a given non-terminal' do
|
89
89
|
# Case: an entry expecting a non-terminal
|
90
90
|
subject.push_entry(entry3)
|
91
|
-
expect(subject.entries4n_term(
|
91
|
+
expect(subject.entries4n_term(nt_rep_c)).to eq([entry3])
|
92
92
|
end
|
93
93
|
|
94
94
|
=begin
|
@@ -11,7 +11,6 @@ require_relative '../../../lib/rley/parser/parse_entry'
|
|
11
11
|
module Rley # Open this namespace to avoid module qualifier prefixes
|
12
12
|
module Parser # Open this namespace to avoid module qualifier prefixes
|
13
13
|
describe ParseEntry do
|
14
|
-
|
15
14
|
let(:t_a) { Syntax::Terminal.new('A') }
|
16
15
|
let(:t_b) { Syntax::Terminal.new('B') }
|
17
16
|
let(:t_c) { Syntax::Terminal.new('C') }
|
@@ -25,7 +24,6 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
25
24
|
Syntax::Production.new(nt_sentence, [])
|
26
25
|
end
|
27
26
|
|
28
|
-
|
29
27
|
let(:dotted_rule) { DottedItem.new(sample_prod, 2) }
|
30
28
|
let(:origin_val) { 3 }
|
31
29
|
let(:vertex_faked) { double('fake-vertex') }
|
@@ -5,7 +5,7 @@ require_relative '../../../lib/rley/parser/parse_walker_factory'
|
|
5
5
|
|
6
6
|
require_relative '../support/grammar_helper'
|
7
7
|
require_relative '../support/expectation_helper'
|
8
|
-
require_relative '../support/
|
8
|
+
require_relative '../support/grammar_l0_helper'
|
9
9
|
|
10
10
|
# Load the class under test
|
11
11
|
require_relative '../../../lib/rley/parser/parse_forest_builder'
|
@@ -23,13 +23,13 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
23
23
|
# contains a hidden left recursion and a cycle
|
24
24
|
builder = Syntax::GrammarBuilder.new
|
25
25
|
builder.add_terminals('a', 'b')
|
26
|
-
builder.add_production('Phi' =>
|
27
|
-
builder.add_production('S' => %w
|
28
|
-
builder.add_production('S' => %w
|
26
|
+
builder.add_production('Phi' => 'S')
|
27
|
+
builder.add_production('S' => %w(A T))
|
28
|
+
builder.add_production('S' => %w(a T))
|
29
29
|
builder.add_production('A' => 'a')
|
30
|
-
builder.add_production('A' => %w
|
30
|
+
builder.add_production('A' => %w(B A))
|
31
31
|
builder.add_production('B' => [])
|
32
|
-
builder.add_production('T' => %w(
|
32
|
+
builder.add_production('T' => %w(b b b))
|
33
33
|
builder.grammar
|
34
34
|
end
|
35
35
|
|
@@ -53,7 +53,9 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
53
53
|
|
54
54
|
# Emit a text representation of the current path.
|
55
55
|
def path_to_s()
|
56
|
-
text_parts = subject.curr_path.map
|
56
|
+
text_parts = subject.curr_path.map do |path_element|
|
57
|
+
path_element.to_string(0)
|
58
|
+
end
|
57
59
|
return text_parts.join('/')
|
58
60
|
end
|
59
61
|
|
@@ -70,10 +72,9 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
70
72
|
it 'should have an empty path' do
|
71
73
|
expect(subject.curr_path).to be_empty
|
72
74
|
end
|
73
|
-
end
|
75
|
+
end # context
|
74
76
|
|
75
77
|
context 'Parse forest construction' do
|
76
|
-
|
77
78
|
it 'should initialize the root node' do
|
78
79
|
first_event = walker.next
|
79
80
|
subject.receive_event(*first_event)
|
@@ -108,7 +109,8 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
108
109
|
event4 = walker.next
|
109
110
|
subject.receive_event(*event4)
|
110
111
|
|
111
|
-
|
112
|
+
parent_as_text = subject.curr_parent.to_string(0)
|
113
|
+
expect(parent_as_text).to eq('Alt(S => a T .)[0, 4]')
|
112
114
|
expected_path4 = 'Phi[0, 4]/S[0, 4]/Alt(S => a T .)[0, 4]'
|
113
115
|
expect(path_to_s).to eq(expected_path4)
|
114
116
|
expect(subject.curr_path[-2].refinement).to eq(:or)
|
@@ -136,7 +138,8 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
136
138
|
expect(path_to_s).to eq(expected_path6)
|
137
139
|
expect(subject.curr_parent.subnodes.size).to eq(1)
|
138
140
|
token_event6 = 'b[3, 4]'
|
139
|
-
|
141
|
+
child = subject.curr_parent.subnodes.first
|
142
|
+
expect(child.to_string(0)).to eq(token_event6)
|
140
143
|
|
141
144
|
event7 = walker.next
|
142
145
|
subject.receive_event(*event7)
|
@@ -146,7 +149,8 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
146
149
|
expect(path_to_s).to eq(expected_path7)
|
147
150
|
expect(subject.curr_parent.subnodes.size).to eq(2)
|
148
151
|
token_event7 = 'b[2, 3]'
|
149
|
-
|
152
|
+
child = subject.curr_parent.subnodes.first
|
153
|
+
expect(child.to_string(0)).to eq(token_event7)
|
150
154
|
|
151
155
|
event8 = walker.next
|
152
156
|
subject.receive_event(*event8)
|
@@ -156,7 +160,8 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
156
160
|
expect(path_to_s).to eq(expected_path8)
|
157
161
|
expect(subject.curr_parent.subnodes.size).to eq(3)
|
158
162
|
token_event8 = 'b[1, 2]'
|
159
|
-
|
163
|
+
child = subject.curr_parent.subnodes.first
|
164
|
+
expect(child.to_string(0)).to eq(token_event8)
|
160
165
|
|
161
166
|
event9 = walker.next
|
162
167
|
subject.receive_event(*event9)
|
@@ -168,19 +173,22 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
168
173
|
event10 = walker.next
|
169
174
|
subject.receive_event(*event10)
|
170
175
|
expect(event10[1].to_s).to eq('.T | 1')
|
171
|
-
|
176
|
+
parent_as_text = subject.curr_parent.to_string(0)
|
177
|
+
expect(parent_as_text).to eq('Alt(S => a T .)[0, 4]')
|
172
178
|
expected_path10 = 'Phi[0, 4]/S[0, 4]/Alt(S => a T .)[0, 4]'
|
173
179
|
expect(path_to_s).to eq(expected_path10)
|
174
180
|
|
175
181
|
event11 = walker.next
|
176
182
|
subject.receive_event(*event11)
|
177
183
|
expect(event11[1].to_s).to eq('S => a . T | 0')
|
178
|
-
|
184
|
+
parent_as_text = subject.curr_parent.to_string(0)
|
185
|
+
expect(parent_as_text).to eq('Alt(S => a T .)[0, 4]')
|
179
186
|
expected_path11 = 'Phi[0, 4]/S[0, 4]/Alt(S => a T .)[0, 4]'
|
180
187
|
expect(path_to_s).to eq(expected_path11)
|
181
188
|
expect(subject.curr_parent.subnodes.size).to eq(2)
|
182
189
|
token_event11 = 'a[0, 1]'
|
183
|
-
|
190
|
+
child = subject.curr_parent.subnodes.first
|
191
|
+
expect(child.to_string(0)).to eq(token_event11)
|
184
192
|
|
185
193
|
event12 = walker.next
|
186
194
|
subject.receive_event(*event12)
|
@@ -219,7 +227,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
219
227
|
|
220
228
|
event16 = walker.next
|
221
229
|
subject.receive_event(*event16)
|
222
|
-
expect(event16[0]).to eq(:backtrack)
|
230
|
+
expect(event16[0]).to eq(:backtrack) # Backtrack event!
|
223
231
|
expect(event16[1].to_s).to eq('S. | 0')
|
224
232
|
expect(subject.curr_parent.to_string(0)).to eq('S[0, 4]')
|
225
233
|
expected_path16 = 'Phi[0, 4]/S[0, 4]'
|
@@ -229,7 +237,8 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
229
237
|
event17 = walker.next
|
230
238
|
subject.receive_event(*event17)
|
231
239
|
expect(event17[1].to_s).to eq('S => A T . | 0')
|
232
|
-
|
240
|
+
parent_as_text = subject.curr_parent.to_string(0)
|
241
|
+
expect(parent_as_text).to eq('Alt(S => A T .)[0, 4]')
|
233
242
|
expected_path17 = 'Phi[0, 4]/S[0, 4]/Alt(S => A T .)[0, 4]'
|
234
243
|
expect(path_to_s).to eq(expected_path17)
|
235
244
|
expect(subject.curr_path[-2].refinement).to eq(:or)
|
@@ -243,16 +252,18 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
243
252
|
|
244
253
|
event18 = walker.next
|
245
254
|
subject.receive_event(*event18)
|
246
|
-
expect(event18[0]).to eq(:revisit)
|
255
|
+
expect(event18[0]).to eq(:revisit) # Revisit event!
|
247
256
|
expect(event18[1].to_s).to eq('T. | 1')
|
248
|
-
|
257
|
+
parent_as_text = subject.curr_parent.to_string(0)
|
258
|
+
expect(parent_as_text).to eq('Alt(S => A T .)[0, 4]')
|
249
259
|
expected_path18 = 'Phi[0, 4]/S[0, 4]/Alt(S => A T .)[0, 4]'
|
250
260
|
expect(path_to_s).to eq(expected_path18)
|
251
261
|
|
252
262
|
event19 = walker.next
|
253
263
|
subject.receive_event(*event19)
|
254
264
|
expect(event19[1].to_s).to eq('S => A . T | 0')
|
255
|
-
|
265
|
+
parent_as_text = subject.curr_parent.to_string(0)
|
266
|
+
expect(parent_as_text).to eq('Alt(S => A T .)[0, 4]')
|
256
267
|
expected_path19 = 'Phi[0, 4]/S[0, 4]/Alt(S => A T .)[0, 4]'
|
257
268
|
expect(path_to_s).to eq(expected_path19)
|
258
269
|
|
@@ -268,8 +279,10 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
268
279
|
event21 = walker.next
|
269
280
|
subject.receive_event(*event21)
|
270
281
|
expect(event21[1].to_s).to eq('A => a . | 0')
|
271
|
-
|
272
|
-
|
282
|
+
parent_as_text = subject.curr_parent.to_string(0)
|
283
|
+
expect(parent_as_text).to eq('Alt(A => a .)[0, 1]')
|
284
|
+
path_prefix = 'Phi[0, 4]/S[0, 4]/Alt(S => A T .)[0, 4]/A[0, 1]/'
|
285
|
+
expected_path21 = path_prefix + 'Alt(A => a .)[0, 1]'
|
273
286
|
expect(path_to_s).to eq(expected_path21)
|
274
287
|
expect(subject.curr_path[-2].refinement).to eq(:or)
|
275
288
|
|
@@ -283,7 +296,8 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
283
296
|
event23 = walker.next
|
284
297
|
subject.receive_event(*event23)
|
285
298
|
expect(event23[1].to_s).to eq('.A | 0')
|
286
|
-
|
299
|
+
parent_as_text = subject.curr_parent.to_string(0)
|
300
|
+
expect(parent_as_text).to eq('Alt(S => A T .)[0, 4]')
|
287
301
|
expected_path23 = 'Phi[0, 4]/S[0, 4]/Alt(S => A T .)[0, 4]'
|
288
302
|
expect(path_to_s).to eq(expected_path23)
|
289
303
|
|
@@ -318,7 +332,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
318
332
|
|
319
333
|
event27 = walker.next
|
320
334
|
subject.receive_event(*event27)
|
321
|
-
expect(event27[0]).to eq(:backtrack)
|
335
|
+
expect(event27[0]).to eq(:backtrack) # Backtrack event!
|
322
336
|
expect(event27[1].to_s).to eq('A. | 0')
|
323
337
|
expect(subject.curr_parent.to_string(0)).to eq('A[0, 1]')
|
324
338
|
expected_path27 = 'Phi[0, 4]/S[0, 4]/Alt(S => A T .)[0, 4]/A[0, 1]'
|
@@ -328,24 +342,28 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
328
342
|
subject.receive_event(*event28)
|
329
343
|
expect(event28[0]).to eq(:visit)
|
330
344
|
expect(event28[1].to_s).to eq('A => B A . | 0')
|
331
|
-
|
332
|
-
|
345
|
+
parent_as_text = subject.curr_parent.to_string(0)
|
346
|
+
expect(parent_as_text).to eq('Alt(A => B A .)[0, 1]')
|
347
|
+
path_prefix = 'Phi[0, 4]/S[0, 4]/Alt(S => A T .)[0, 4]/A[0, 1]/'
|
348
|
+
expected_path28 = path_prefix + 'Alt(A => B A .)[0, 1]'
|
333
349
|
expect(path_to_s).to eq(expected_path28)
|
334
350
|
|
335
351
|
event29 = walker.next
|
336
352
|
subject.receive_event(*event29)
|
337
|
-
expect(event29[0]).to eq(:revisit)
|
353
|
+
expect(event29[0]).to eq(:revisit) # Revisit event!
|
338
354
|
expect(event29[1].to_s).to eq('A. | 0')
|
339
|
-
|
340
|
-
|
355
|
+
parent_as_text = subject.curr_parent.to_string(0)
|
356
|
+
expect(parent_as_text).to eq('Alt(A => B A .)[0, 1]')
|
357
|
+
expected_path29 = path_prefix + 'Alt(A => B A .)[0, 1]'
|
341
358
|
expect(path_to_s).to eq(expected_path29)
|
342
359
|
|
343
360
|
event30 = walker.next
|
344
361
|
subject.receive_event(*event30)
|
345
362
|
expect(event30[0]).to eq(:visit)
|
346
363
|
expect(event30[1].to_s).to eq('A => B . A | 0')
|
347
|
-
|
348
|
-
|
364
|
+
parent_as_text = subject.curr_parent.to_string(0)
|
365
|
+
expect(parent_as_text).to eq('Alt(A => B A .)[0, 1]')
|
366
|
+
expected_path30 = path_prefix + 'Alt(A => B A .)[0, 1]'
|
349
367
|
expect(path_to_s).to eq(expected_path30)
|
350
368
|
|
351
369
|
event31 = walker.next
|
@@ -353,7 +371,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
353
371
|
expect(event31[0]).to eq(:visit)
|
354
372
|
expect(event31[1].to_s).to eq('B. | 0')
|
355
373
|
expect(subject.curr_parent.to_string(0)).to eq('B[0, 0]')
|
356
|
-
expected_path31 =
|
374
|
+
expected_path31 = path_prefix + 'Alt(A => B A .)[0, 1]/B[0, 0]'
|
357
375
|
expect(path_to_s).to eq(expected_path31)
|
358
376
|
|
359
377
|
event32 = walker.next
|
@@ -362,15 +380,16 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
362
380
|
# Empty production!
|
363
381
|
expect(event32[1].to_s).to eq('B => . | 0')
|
364
382
|
expect(subject.curr_parent.to_string(0)).to eq('B[0, 0]')
|
365
|
-
expected_path30 =
|
383
|
+
expected_path30 = path_prefix + 'Alt(A => B A .)[0, 1]/B[0, 0]'
|
366
384
|
expect(path_to_s).to eq(expected_path30)
|
367
385
|
|
368
386
|
event33 = walker.next
|
369
387
|
subject.receive_event(*event33)
|
370
388
|
expect(event33[0]).to eq(:visit)
|
371
389
|
expect(event33[1].to_s).to eq('.B | 0')
|
372
|
-
|
373
|
-
|
390
|
+
parent_as_text = subject.curr_parent.to_string(0)
|
391
|
+
expect(parent_as_text).to eq('Alt(A => B A .)[0, 1]')
|
392
|
+
expected_path33 = path_prefix + 'Alt(A => B A .)[0, 1]'
|
374
393
|
expect(path_to_s).to eq(expected_path33)
|
375
394
|
|
376
395
|
event34 = walker.next
|
@@ -378,14 +397,15 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
378
397
|
expect(event34[0]).to eq(:visit)
|
379
398
|
expect(event34[1].to_s).to eq('A => . B A | 0')
|
380
399
|
expect(subject.curr_parent.to_string(0)).to eq('A[0, 1]')
|
381
|
-
|
382
|
-
expect(path_to_s).to eq(
|
400
|
+
path34 = 'Phi[0, 4]/S[0, 4]/Alt(S => A T .)[0, 4]/A[0, 1]'
|
401
|
+
expect(path_to_s).to eq(path34)
|
383
402
|
|
384
403
|
event35 = walker.next
|
385
404
|
subject.receive_event(*event35)
|
386
405
|
expect(event35[0]).to eq(:revisit)
|
387
406
|
expect(event35[1].to_s).to eq('.A | 0')
|
388
|
-
|
407
|
+
parent_as_text = subject.curr_parent.to_string(0)
|
408
|
+
expect(parent_as_text).to eq('Alt(S => A T .)[0, 4]')
|
389
409
|
expected_path35 = 'Phi[0, 4]/S[0, 4]/Alt(S => A T .)[0, 4]'
|
390
410
|
expect(path_to_s).to eq(expected_path35)
|
391
411
|
|
@@ -410,18 +430,18 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
410
430
|
context 'Natural language processing' do
|
411
431
|
include GrammarL0Helper
|
412
432
|
|
413
|
-
let(:
|
414
|
-
builder =
|
433
|
+
let(:grammar_l0) do
|
434
|
+
builder = grammar_l0_builder
|
415
435
|
builder.grammar
|
416
436
|
end
|
417
437
|
|
418
438
|
let(:sentence_tokens) do
|
419
439
|
sentence = 'I prefer a morning flight'
|
420
|
-
|
440
|
+
tokenizer_l0(sentence, grammar_l0)
|
421
441
|
end
|
422
442
|
|
423
443
|
let(:sentence_result) do
|
424
|
-
parser = Parser::GFGEarleyParser.new(
|
444
|
+
parser = Parser::GFGEarleyParser.new(grammar_l0)
|
425
445
|
parser.parse(sentence_tokens)
|
426
446
|
end
|
427
447
|
|
@@ -500,7 +520,8 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
500
520
|
expect(path_to_s).to eq(expected_path8)
|
501
521
|
expect(subject.curr_parent.subnodes.size).to eq(1)
|
502
522
|
token_event8 = 'Noun[4, 5]'
|
503
|
-
|
523
|
+
child = subject.curr_parent.subnodes.first
|
524
|
+
expect(child.to_string(0)).to eq(token_event8)
|
504
525
|
|
505
526
|
event9 = walker.next
|
506
527
|
subject.receive_event(*event9)
|
@@ -515,27 +536,28 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
515
536
|
expect(event10[0]).to eq(:visit)
|
516
537
|
expect(event10[1].to_s).to eq('Nominal. | 3')
|
517
538
|
expect(subject.curr_parent.to_string(0)).to eq('Nominal[3, 4]')
|
518
|
-
|
519
|
-
expect(path_to_s).to eq(
|
539
|
+
path10 = 'S[0, 5]/VP[1, 5]/NP[2, 5]/Nominal[3, 5]/Nominal[3, 4]'
|
540
|
+
expect(path_to_s).to eq(path10)
|
520
541
|
|
521
542
|
event11 = walker.next
|
522
543
|
subject.receive_event(*event11)
|
523
544
|
expect(event11[0]).to eq(:visit)
|
524
545
|
expect(event11[1].to_s).to eq('Nominal => Noun . | 3')
|
525
546
|
expect(subject.curr_parent.to_string(0)).to eq('Nominal[3, 4]')
|
526
|
-
|
527
|
-
expect(path_to_s).to eq(
|
547
|
+
path11 = 'S[0, 5]/VP[1, 5]/NP[2, 5]/Nominal[3, 5]/Nominal[3, 4]'
|
548
|
+
expect(path_to_s).to eq(path11)
|
528
549
|
expect(subject.curr_parent.subnodes.size).to eq(1)
|
529
550
|
token_event11 = 'Noun[3, 4]'
|
530
|
-
|
551
|
+
child = subject.curr_parent.subnodes.first
|
552
|
+
expect(child.to_string(0)).to eq(token_event11)
|
531
553
|
|
532
554
|
event12 = walker.next
|
533
555
|
subject.receive_event(*event12)
|
534
556
|
expect(event12[0]).to eq(:visit)
|
535
557
|
expect(event12[1].to_s).to eq('Nominal => . Noun | 3')
|
536
558
|
expect(subject.curr_parent.to_string(0)).to eq('Nominal[3, 4]')
|
537
|
-
|
538
|
-
expect(path_to_s).to eq(
|
559
|
+
path12 = 'S[0, 5]/VP[1, 5]/NP[2, 5]/Nominal[3, 5]/Nominal[3, 4]'
|
560
|
+
expect(path_to_s).to eq(path12)
|
539
561
|
|
540
562
|
event13 = walker.next
|
541
563
|
subject.receive_event(*event13)
|
@@ -569,7 +591,8 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
569
591
|
expected_path16 = 'S[0, 5]/VP[1, 5]/NP[2, 5]'
|
570
592
|
expect(path_to_s).to eq(expected_path16)
|
571
593
|
token_event16 = 'Determiner[2, 3]'
|
572
|
-
|
594
|
+
child = subject.curr_parent.subnodes.first
|
595
|
+
expect(child.to_string(0)).to eq(token_event16)
|
573
596
|
|
574
597
|
event17 = walker.next
|
575
598
|
subject.receive_event(*event17)
|
@@ -595,7 +618,8 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
595
618
|
expected_path19 = 'S[0, 5]/VP[1, 5]'
|
596
619
|
expect(path_to_s).to eq(expected_path19)
|
597
620
|
token_event19 = 'Verb[1, 2]'
|
598
|
-
|
621
|
+
child = subject.curr_parent.subnodes.first
|
622
|
+
expect(child.to_string(0)).to eq(token_event19)
|
599
623
|
|
600
624
|
event20 = walker.next
|
601
625
|
subject.receive_event(*event20)
|
@@ -637,8 +661,9 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
637
661
|
expected_path24 = 'S[0, 5]/NP[0, 1]'
|
638
662
|
expect(path_to_s).to eq(expected_path24)
|
639
663
|
token_event24 = 'Pronoun[0, 1]'
|
640
|
-
|
641
|
-
|
664
|
+
child = subject.curr_parent.subnodes.first
|
665
|
+
expect(child.to_string(0)).to eq(token_event24)
|
666
|
+
|
642
667
|
event25 = walker.next
|
643
668
|
subject.receive_event(*event25)
|
644
669
|
expect(event25[0]).to eq(:visit)
|
@@ -668,10 +693,10 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
668
693
|
expect(event28[0]).to eq(:visit)
|
669
694
|
expect(event28[1].to_s).to eq('.S | 0')
|
670
695
|
expected_path28 = ''
|
671
|
-
expect(path_to_s).to eq(expected_path28)
|
696
|
+
expect(path_to_s).to eq(expected_path28)
|
672
697
|
end
|
673
698
|
end # context
|
674
699
|
end # describe
|
675
700
|
end # module
|
676
701
|
end # module
|
677
|
-
# End of file
|
702
|
+
# End of file
|