rley 0.2.15 → 0.3.00

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -0
  3. data/lib/rley/constants.rb +1 -1
  4. data/lib/rley/gfg/call_edge.rb +30 -0
  5. data/lib/rley/gfg/edge.rb +4 -0
  6. data/lib/rley/gfg/end_vertex.rb +1 -1
  7. data/lib/rley/gfg/epsilon_edge.rb +0 -4
  8. data/lib/rley/gfg/grm_flow_graph.rb +32 -7
  9. data/lib/rley/gfg/item_vertex.rb +71 -25
  10. data/lib/rley/gfg/non_terminal_vertex.rb +10 -1
  11. data/lib/rley/gfg/return_edge.rb +31 -0
  12. data/lib/rley/gfg/scan_edge.rb +2 -1
  13. data/lib/rley/gfg/shortcut_edge.rb +26 -0
  14. data/lib/rley/gfg/start_vertex.rb +2 -2
  15. data/lib/rley/gfg/vertex.rb +27 -1
  16. data/lib/rley/parse_forest_visitor.rb +115 -0
  17. data/lib/rley/parser/base_parser.rb +27 -0
  18. data/lib/rley/parser/dotted_item.rb +11 -0
  19. data/lib/rley/parser/earley_parser.rb +3 -15
  20. data/lib/rley/parser/gfg_chart.rb +106 -0
  21. data/lib/rley/parser/gfg_earley_parser.rb +139 -0
  22. data/lib/rley/parser/gfg_parsing.rb +384 -0
  23. data/lib/rley/parser/parse_entry.rb +148 -0
  24. data/lib/rley/parser/parse_entry_set.rb +104 -0
  25. data/lib/rley/parser/parse_entry_tracker.rb +56 -0
  26. data/lib/rley/parser/parse_forest_builder.rb +229 -0
  27. data/lib/rley/parser/parse_forest_factory.rb +54 -0
  28. data/lib/rley/parser/parse_walker_factory.rb +237 -0
  29. data/lib/rley/ptree/token_range.rb +14 -1
  30. data/lib/rley/sppf/alternative_node.rb +34 -0
  31. data/lib/rley/sppf/composite_node.rb +27 -0
  32. data/lib/rley/sppf/epsilon_node.rb +27 -0
  33. data/lib/rley/sppf/leaf_node.rb +12 -0
  34. data/lib/rley/sppf/non_terminal_node.rb +38 -0
  35. data/lib/rley/sppf/parse_forest.rb +48 -0
  36. data/lib/rley/sppf/sppf_node.rb +24 -0
  37. data/lib/rley/sppf/token_node.rb +29 -0
  38. data/lib/rley/syntax/grammar_builder.rb +16 -12
  39. data/lib/rley/syntax/grm_symbol.rb +6 -0
  40. data/lib/rley/syntax/terminal.rb +5 -0
  41. data/spec/rley/gfg/call_edge_spec.rb +51 -0
  42. data/spec/rley/gfg/end_vertex_spec.rb +1 -0
  43. data/spec/rley/gfg/grm_flow_graph_spec.rb +24 -2
  44. data/spec/rley/gfg/item_vertex_spec.rb +75 -6
  45. data/spec/rley/gfg/non_terminal_vertex_spec.rb +14 -0
  46. data/spec/rley/gfg/return_edge_spec.rb +51 -0
  47. data/spec/rley/gfg/shortcut_edge_spec.rb +43 -0
  48. data/spec/rley/gfg/vertex_spec.rb +52 -37
  49. data/spec/rley/parse_forest_visitor_spec.rb +238 -0
  50. data/spec/rley/parser/dotted_item_spec.rb +29 -8
  51. data/spec/rley/parser/gfg_chart_spec.rb +138 -0
  52. data/spec/rley/parser/gfg_earley_parser_spec.rb +918 -0
  53. data/spec/rley/parser/gfg_parsing_spec.rb +565 -0
  54. data/spec/rley/parser/parse_entry_set_spec.rb +179 -0
  55. data/spec/rley/parser/parse_entry_spec.rb +208 -0
  56. data/spec/rley/parser/parse_forest_builder_spec.rb +382 -0
  57. data/spec/rley/parser/parse_forest_factory_spec.rb +81 -0
  58. data/spec/rley/parser/parse_walker_factory_spec.rb +235 -0
  59. data/spec/rley/parser/state_set_spec.rb +4 -0
  60. data/spec/rley/sppf/alternative_node_spec.rb +72 -0
  61. data/spec/rley/sppf/antecedence_graph.rb +87 -0
  62. data/spec/rley/sppf/forest_representation.rb +136 -0
  63. data/spec/rley/sppf/gfg_representation.rb +111 -0
  64. data/spec/rley/sppf/non_terminal_node_spec.rb +64 -0
  65. data/spec/rley/support/ambiguous_grammar_helper.rb +36 -36
  66. data/spec/rley/support/expectation_helper.rb +36 -0
  67. data/spec/rley/support/grammar_helper.rb +28 -0
  68. data/spec/rley/support/grammar_sppf_helper.rb +25 -0
  69. data/spec/rley/syntax/grammar_builder_spec.rb +5 -0
  70. data/spec/rley/syntax/non_terminal_spec.rb +4 -0
  71. data/spec/rley/syntax/terminal_spec.rb +4 -0
  72. metadata +58 -2
@@ -0,0 +1,43 @@
1
+ require_relative '../../spec_helper'
2
+ require_relative '../../../lib/rley/syntax/non_terminal'
3
+
4
+ # Load the class under test
5
+ require_relative '../../../lib/rley/gfg/shortcut_edge'
6
+
7
+ module Rley # Open this namespace to avoid module qualifier prefixes
8
+ module GFG # Open this namespace to avoid module qualifier prefixes
9
+ describe Edge do
10
+ let(:nt_b_sequence) { Rley::Syntax::NonTerminal.new('b_sequence') }
11
+
12
+ let(:vertex1) { double('fake_vertex1') }
13
+ let(:vertex2) { double('fake_vertex2') }
14
+ subject { ShortcutEdge.new(vertex1, vertex2) }
15
+
16
+ context 'Initialization:' do
17
+ it 'should be created with two vertice arguments & a non-terminal' do
18
+ allow(vertex1).to receive(:shortcut=)
19
+ allow(vertex1).to receive(:next_symbol).and_return(nt_b_sequence)
20
+
21
+ expect { ShortcutEdge.new(vertex1, vertex2) }
22
+ .not_to raise_error
23
+ end
24
+
25
+ it 'should know the successor vertex' do
26
+ allow(vertex1).to receive(:shortcut=)
27
+ allow(vertex1).to receive(:next_symbol).and_return(nt_b_sequence)
28
+
29
+ expect(subject.successor).to eq(vertex2)
30
+ end
31
+
32
+ it 'should know the related terminal' do
33
+ allow(vertex1).to receive(:shortcut=)
34
+ allow(vertex1).to receive(:next_symbol).and_return(nt_b_sequence)
35
+
36
+ expect(subject.nonterminal).to eq(nt_b_sequence)
37
+ end
38
+ end # context
39
+ end # describe
40
+ end # module
41
+ end # module
42
+
43
+ # End of file
@@ -1,38 +1,53 @@
1
- require_relative '../../spec_helper'
2
-
3
- # Load the class under test
4
- require_relative '../../../lib/rley/gfg/vertex'
5
-
6
- module Rley # Open this namespace to avoid module qualifier prefixes
7
- module GFG # Open this namespace to avoid module qualifier prefixes
8
- describe Vertex do
9
- subject { Vertex.new() }
10
-
11
- context 'Initialization:' do
12
- it 'should be created without argument' do
13
- expect { Vertex.new() }.not_to raise_error
14
- end
15
-
16
- it "shouldn't have edges at start" do
17
- expect(subject.edges.empty?).to eq(true)
18
- end
19
- end # context
20
-
21
- context 'Provided services:' do
22
- it 'should accept new edges' do
23
- edge1 = double('fake-edge1')
24
- edge2 = double('fake-edge2')
25
-
26
- expect { subject.add_edge(edge1) }.not_to raise_error
27
- expect(subject.edges.size).to eq(1)
28
- expect(subject.edges.last).to eq(edge1)
29
- expect { subject.add_edge(edge2) }.not_to raise_error
30
- expect(subject.edges.size).to eq(2)
31
- expect(subject.edges.last).to eq(edge2)
32
- end
33
- end # context
34
- end # describe
35
- end # module
36
- end # module
37
-
1
+ require_relative '../../spec_helper'
2
+
3
+ # Load the class under test
4
+ require_relative '../../../lib/rley/gfg/vertex'
5
+
6
+ module Rley # Open this namespace to avoid module qualifier prefixes
7
+ module GFG # Open this namespace to avoid module qualifier prefixes
8
+ describe Vertex do
9
+ subject { Vertex.new() }
10
+
11
+ context 'Initialization:' do
12
+ it 'should be created without argument' do
13
+ expect { Vertex.new() }.not_to raise_error
14
+ end
15
+
16
+ it "shouldn't have edges at start" do
17
+ expect(subject.edges.empty?).to eq(true)
18
+ end
19
+ end # context
20
+
21
+ context 'Provided services:' do
22
+ it 'should know whether it has a dot at the end of the rhs' do
23
+ expect(subject).not_to be_complete
24
+ end
25
+
26
+ it 'should know the previous symbol (if any) in the rhs' do
27
+ expect(subject.prev_symbol).to be_nil
28
+ end
29
+
30
+ it 'should know the next symbol (if any) in the rhs' do
31
+ expect(subject.next_symbol).to be_nil
32
+ end
33
+
34
+ it 'should accept at most one new edge' do
35
+ edge1 = double('fake-edge1')
36
+ edge2 = double('fake-edge2')
37
+
38
+ expect { subject.add_edge(edge1) }.not_to raise_error
39
+ expect(subject.edges.size).to eq(1)
40
+ expect(subject.edges.last).to eq(edge1)
41
+
42
+ err = StandardError
43
+ msg = 'At most one edge accepted'
44
+ expect { subject.add_edge(edge2) }.to raise_error err, msg
45
+ expect(subject.edges.size).to eq(1)
46
+ expect(subject.edges.last).to eq(edge1)
47
+ end
48
+ end # context
49
+ end # describe
50
+ end # module
51
+ end # module
52
+
38
53
  # End of file
@@ -0,0 +1,238 @@
1
+ require_relative '../spec_helper'
2
+
3
+ require_relative './support/grammar_helper'
4
+ require_relative './support/grammar_sppf_helper'
5
+ require_relative '../../lib/rley/parser/token'
6
+ require_relative '../../lib/rley/parser/gfg_earley_parser'
7
+ require_relative '../../lib/rley/sppf/non_terminal_node'
8
+ require_relative '../../lib/rley/sppf/parse_forest'
9
+
10
+ # Load the class under test
11
+ require_relative '../../lib/rley/parse_forest_visitor'
12
+
13
+ module Rley # Open this namespace to avoid module qualifier prefixes
14
+ describe ParseForestVisitor do
15
+ include GrammarSPPFHelper # Mix-in module with builder for grammar sppf
16
+ include GrammarHelper # Mix-in with token factory method
17
+
18
+ # Assumption the aParseEntry corresponds to an end GFG node
19
+ def create_non_terminal_node(aParseEntry, aRange)
20
+ a_vertex = aParseEntry.vertex
21
+ return Rley::SPPF::NonTerminalNode.new(a_vertex.non_terminal, aRange)
22
+ end
23
+
24
+ let(:grammar_sppf) do
25
+ builder = grammar_sppf_builder
26
+ builder.grammar
27
+ end
28
+
29
+ let(:sample_tokens) do
30
+ build_token_sequence(%w(a b b b), grammar_sppf)
31
+ end
32
+
33
+ # A forest with just a root node
34
+ let(:rooted_forest) do
35
+ parser = Parser::GFGEarleyParser.new(grammar_sppf)
36
+ parse_result = parser.parse(sample_tokens)
37
+ full_range = { low: 0, high: parse_result.chart.last_index }
38
+ root_node = create_non_terminal_node(parse_result.accepting_entry, full_range)
39
+ Rley::SPPF::ParseForest.new(root_node)
40
+ end
41
+
42
+ =begin
43
+ # Factory method that builds a sample parse forest.
44
+ # Generated forest has the following structure:
45
+ # S[0,5]
46
+ # +- A[0,5]
47
+ # +- a[0,0]
48
+ # +- A[1,4]
49
+ # | +- a[1,1]
50
+ # | +- A[2,3]
51
+ # | | +- b[2,3]
52
+ # | +- c[3,4]
53
+ # +- c[4,5]
54
+ # Capital letters represent non-terminal nodes
55
+ let(:grm_abc_pforest1) do
56
+ parser = Parser::EarleyParser.new(grammar_abc)
57
+ parse_result = parser.parse(grm_abc_tokens1)
58
+ parse_result.parse_forest
59
+ end
60
+ =end
61
+
62
+ # Default instantiation rule
63
+ subject { ParseForestVisitor.new(rooted_forest) }
64
+
65
+
66
+ context 'Standard creation & initialization:' do
67
+ it 'should be initialized with a parse forest argument' do
68
+ expect { ParseForestVisitor.new(rooted_forest) }.not_to raise_error
69
+ end
70
+
71
+ it 'should know the parse forest to visit' do
72
+ expect(subject.pforest).to eq(rooted_forest)
73
+ end
74
+
75
+ it "shouldn't have subscribers at start" do
76
+ expect(subject.subscribers).to be_empty
77
+ end
78
+ end # context
79
+
80
+
81
+ context 'Subscribing:' do
82
+ let(:listener1) { double('fake-subscriber1') }
83
+ let(:listener2) { double('fake-subscriber2') }
84
+
85
+ it 'should allow subscriptions' do
86
+ subject.subscribe(listener1)
87
+ expect(subject.subscribers.size).to eq(1)
88
+ expect(subject.subscribers).to eq([listener1])
89
+
90
+ subject.subscribe(listener2)
91
+ expect(subject.subscribers.size).to eq(2)
92
+ expect(subject.subscribers).to eq([listener1, listener2])
93
+ end
94
+
95
+ it 'should allow un-subcriptions' do
96
+ subject.subscribe(listener1)
97
+ subject.subscribe(listener2)
98
+ subject.unsubscribe(listener2)
99
+ expect(subject.subscribers.size).to eq(1)
100
+ expect(subject.subscribers).to eq([listener1])
101
+ subject.unsubscribe(listener1)
102
+ expect(subject.subscribers).to be_empty
103
+ end
104
+ end # context
105
+
106
+
107
+ context 'Notifying visit events:' do
108
+ # Use doubles/mocks to simulate subscribers
109
+ let(:listener1) { double('fake-subscriber1') }
110
+ let(:listener2) { double('fake-subscriber2') }
111
+
112
+ it 'should react to the start_visit_pforest message' do
113
+ subject.subscribe(listener1)
114
+
115
+ # Notify subscribers when start the visit of the pforest
116
+ expect(listener1).to receive(:before_pforest).with(rooted_forest)
117
+ subject.start_visit_pforest(rooted_forest)
118
+ end
119
+ =begin
120
+ # Default instantiation rule
121
+ subject do
122
+ instance = ParseForestVisitor.new(grm_abc_pforest1)
123
+ instance.subscribe(listener1)
124
+ instance
125
+ end
126
+
127
+
128
+
129
+ # Sample non-terminal node
130
+ let(:nterm_node) do
131
+ first_big_a = grm_abc_pforest1.root.children[0]
132
+ second_big_a = first_big_a.children[1]
133
+ second_big_a.children[1]
134
+ end
135
+
136
+ # Sample terminal node
137
+ let(:term_node) { nterm_node.children[0] }
138
+
139
+ it 'should react to the start_visit_pforest message' do
140
+ # Notify subscribers when start the visit of the pforest
141
+ expect(listener1).to receive(:before_pforest).with(grm_abc_pforest1)
142
+ subject.start_visit_pforest(grm_abc_pforest1)
143
+ end
144
+
145
+ it 'should react to the start_visit_nonterminal message' do
146
+ # Notify subscribers when start the visit of a non-terminal node
147
+ expect(listener1).to receive(:before_non_terminal).with(nterm_node)
148
+ subject.visit_nonterminal(nterm_node)
149
+ end
150
+
151
+ it 'should react to the visit_children message' do
152
+ # Notify subscribers when start the visit of children nodes
153
+ children = nterm_node.children
154
+ args = [nterm_node, children]
155
+ expect(listener1).to receive(:before_children).with(*args)
156
+ expect(listener1).to receive(:before_terminal).with(children[0])
157
+ expect(listener1).to receive(:after_terminal).with(children[0])
158
+ expect(listener1).to receive(:after_children).with(nterm_node, children)
159
+ subject.send(:traverse_children, nterm_node)
160
+ end
161
+
162
+ it 'should react to the end_visit_nonterminal message' do
163
+ # Notify subscribers when ending the visit of a non-terminal node
164
+ expect(listener1).to receive(:after_non_terminal).with(nterm_node)
165
+ subject.end_visit_nonterminal(nterm_node)
166
+ end
167
+
168
+ it 'should react to the visit_terminal message' do
169
+ # Notify subscribers when start & ending the visit of a terminal node
170
+ expect(listener1).to receive(:before_terminal).with(term_node)
171
+ expect(listener1).to receive(:after_terminal).with(term_node)
172
+ subject.visit_terminal(term_node)
173
+ end
174
+
175
+ it 'should react to the end_visit_pforest message' do
176
+ # Notify subscribers when ending the visit of the pforest
177
+ expect(listener1).to receive(:after_pforest).with(grm_abc_pforest1)
178
+ subject.end_visit_pforest(grm_abc_pforest1)
179
+ end
180
+
181
+ it 'should begin the visit when requested' do
182
+ # Reminder: parse forest structure is
183
+ # S[0,5]
184
+ # +- A[0,5]
185
+ # +- a[0,0]
186
+ # +- A[1,4]
187
+ # | +- a[1,1]
188
+ # | +- A[2,3]
189
+ # | | +- b[2,3]
190
+ # | +- c[3,4]
191
+ # +- c[4,5]
192
+ root = grm_abc_pforest1.root
193
+ children = root.children
194
+ big_a_1 = children[0]
195
+ big_a_1_children = big_a_1.children
196
+ big_a_2 = big_a_1_children[1]
197
+ big_a_2_children = big_a_2.children
198
+ big_a_3 = big_a_2_children[1]
199
+ big_a_3_children = big_a_3.children
200
+ expectations = [
201
+ [:before_pforest, [grm_abc_pforest1]],
202
+ [:before_non_terminal, [root]],
203
+ [:before_children, [root, children]],
204
+ [:before_non_terminal, [big_a_1]],
205
+ [:before_children, [big_a_1, big_a_1_children]],
206
+ [:before_terminal, [big_a_1_children[0]]],
207
+ [:after_terminal, [big_a_1_children[0]]],
208
+ [:before_non_terminal, [big_a_2]],
209
+ [:before_children, [big_a_2, big_a_2_children]],
210
+ [:before_terminal, [big_a_2_children[0]]],
211
+ [:after_terminal, [big_a_2_children[0]]],
212
+ [:before_non_terminal, [big_a_3]],
213
+ [:before_children, [big_a_3, big_a_3_children]],
214
+ [:before_terminal, [big_a_3_children[0]]],
215
+ [:after_terminal, [big_a_3_children[0]]],
216
+ [:after_children, [big_a_3, big_a_3_children]],
217
+ [:before_terminal, [big_a_2_children[2]]],
218
+ [:after_terminal, [big_a_2_children[2]]],
219
+ [:after_children, [big_a_2, big_a_2_children]],
220
+ [:before_terminal, [big_a_1_children[2]]],
221
+ [:after_terminal, [big_a_1_children[2]]],
222
+ [:after_children, [big_a_1, big_a_1_children]],
223
+ [:after_children, [root, children]],
224
+ [:after_pforest, [grm_abc_pforest1]]
225
+ ]
226
+ expectations.each do |(msg, args)|
227
+ allow(listener1).to receive(msg).with(*args).ordered
228
+ end
229
+
230
+ # Here we go...
231
+ subject.start
232
+ end
233
+ =end
234
+ end # context
235
+ end # describe
236
+ end # module
237
+
238
+ # End of file
@@ -91,36 +91,57 @@ module Rley # Open this namespace to avoid module qualifier prefixes
91
91
 
92
92
  it 'should know the symbol before the dot' do
93
93
  expect(subject.prev_symbol).to eq(t_a)
94
-
94
+
95
95
  # Case of an empty production
96
96
  instance = DottedItem.new(empty_prod, 0)
97
97
  expect(instance.prev_symbol).to be_nil
98
-
98
+
99
99
  # Case of a dot at start position
100
100
  instance = DottedItem.new(sample_prod, 0)
101
- expect(instance.prev_symbol).to be_nil
101
+ expect(instance.prev_symbol).to be_nil
102
102
  end
103
103
 
104
104
  it 'should know the symbol after the dot' do
105
105
  expect(subject.next_symbol).to eq(t_b)
106
106
  end
107
-
107
+
108
108
  it 'should calculate the previous position of the dot' do
109
109
  expect(subject.prev_position).to eq(0)
110
-
110
+
111
111
  # Case of an empty production
112
112
  instance = DottedItem.new(empty_prod, 0)
113
113
  expect(instance.prev_position).to be_nil
114
-
114
+
115
115
  # Case of a dot at start position
116
116
  instance = DottedItem.new(sample_prod, 0)
117
- expect(instance.prev_position).to be_nil
117
+ expect(instance.prev_position).to be_nil
118
118
 
119
119
  # Case of single symbol production
120
120
  instance = DottedItem.new(other_prod, 1)
121
- expect(instance.prev_position).to eq(0)
121
+ expect(instance.prev_position).to eq(0)
122
122
  end
123
123
 
124
+ it 'should determine if it is a successor of another dotted item' do
125
+ expect(subject).not_to be_successor_of(subject)
126
+
127
+ # Case: different productions
128
+ instance = DottedItem.new(empty_prod, 0)
129
+ expect(subject).not_to be_successor_of(subject)
130
+
131
+ # Case: one position difference
132
+ instance = DottedItem.new(sample_prod, 0)
133
+ expect(subject).to be_successor_of(instance)
134
+ expect(instance).not_to be_successor_of(subject)
135
+
136
+ # Case: more than one position difference
137
+ instance2 = DottedItem.new(sample_prod, 2)
138
+ expect(instance).not_to be_successor_of(instance2)
139
+ expect(subject).not_to be_successor_of(instance2)
140
+ expect(instance2).to be_successor_of(subject)
141
+ end
142
+
143
+
144
+
124
145
  it 'should give its text representation' do
125
146
  expectation = 'sentence => A . B C'
126
147
  expect(subject.to_s).to eq(expectation)
@@ -0,0 +1,138 @@
1
+ require_relative '../../spec_helper'
2
+ require 'stringio'
3
+
4
+ require_relative '../../../lib/rley/syntax/terminal'
5
+ require_relative '../../../lib/rley/parser/token'
6
+ require_relative '../../../lib/rley/gfg/start_vertex'
7
+ require_relative '../../../lib/rley/parser/parse_entry'
8
+ require_relative '../../../lib/rley/parser/parse_tracer'
9
+ require_relative '../../../lib/rley/parser/grm_items_builder'
10
+ require_relative '../../../lib/rley/gfg/grm_flow_graph'
11
+ require_relative '../support/grammar_abc_helper'
12
+
13
+
14
+ # Load the class under test
15
+ require_relative '../../../lib/rley/parser/gfg_chart'
16
+
17
+ module Rley # Open this namespace to avoid module qualifier prefixes
18
+ module Parser # Open this namespace to avoid module qualifier prefixes
19
+ describe GFGChart do
20
+ include GrammarABCHelper # Mix-in module with builder for grammar abc
21
+
22
+ # Helper method. Create an array of dotted items
23
+ # from the given grammar
24
+ def build_items_for_grammar(aGrammar)
25
+ helper = Object.new
26
+ helper.extend(Parser::GrmItemsBuilder)
27
+ return helper.build_dotted_items(aGrammar)
28
+ end
29
+
30
+ let(:count_token) { 20 }
31
+ let(:output) { StringIO.new('', 'w') }
32
+
33
+ # Factory method. Build a production with the given sequence
34
+ # of symbols as its rhs.
35
+ let(:grammar_abc) do
36
+ builder = grammar_abc_builder
37
+ builder.grammar
38
+ end
39
+
40
+ let(:token_seq) do
41
+ literals = %w(a a b c c)
42
+ literals.map { |lexeme| Token.new(lexeme, nil) }
43
+ end
44
+
45
+ # Helper method. Create an array of dotted items
46
+ # from the abc grammar
47
+ let(:items_from_grammar) { build_items_for_grammar(grammar_abc) }
48
+ let(:sample_gfg) { GFG::GrmFlowGraph.new(items_from_grammar) }
49
+ let(:sample_tracer) { ParseTracer.new(0, output, token_seq) }
50
+ let(:sample_start_symbol) { sample_gfg.start_vertex.non_terminal }
51
+
52
+
53
+ # Default instantiation rule
54
+ subject { GFGChart.new(count_token, sample_gfg, sample_tracer) }
55
+
56
+
57
+ context 'Initialization:' do
58
+ it 'should be created with start vertex, token count, tracer' do
59
+ expect { GFGChart.new(count_token, sample_gfg, sample_tracer) }
60
+ .not_to raise_error
61
+ end
62
+
63
+ it 'should have correct entry set count' do
64
+ expect(subject.sets.size).to eq(count_token + 1)
65
+ end
66
+
67
+ it 'should reference a tracer' do
68
+ expect(subject.tracer).to eq(sample_tracer)
69
+ end
70
+
71
+ it 'should know the start symbol' do
72
+ expect(subject.start_symbol).to eq(sample_start_symbol)
73
+ end
74
+
75
+ it 'should know the initial parse entry' do
76
+ expect(subject.initial_entry.vertex).to eq(sample_gfg.start_vertex)
77
+ expect(subject.initial_entry.origin).to eq(0)
78
+ end
79
+ =begin
80
+
81
+ it 'should know the start dotted rule' do
82
+ expect(subject.start_dotted_rule).to eq(dotted_rule)
83
+ end
84
+
85
+
86
+ =end
87
+ end # context
88
+
89
+ context 'Provided services:' do
90
+ =begin
91
+ let(:t_a) { Syntax::Terminal.new('a') }
92
+ let(:t_b) { Syntax::Terminal.new('b') }
93
+ let(:t_c) { Syntax::Terminal.new('c') }
94
+ let(:nt_sentence) { Syntax::NonTerminal.new('sentence') }
95
+
96
+ let(:sample_prod) do
97
+ Syntax::Production.new(nt_sentence, [t_a, t_b, t_c])
98
+ end
99
+
100
+ let(:origin_val) { 3 }
101
+ let(:dotted_rule) { DottedItem.new(sample_prod, 2) }
102
+ let(:complete_rule) { DottedItem.new(sample_prod, 3) }
103
+ let(:sample_parse_state) { ParseState.new(dotted_rule, origin_val) }
104
+ let(:sample_tracer) { ParseTracer.new(1, output, token_seq) }
105
+
106
+ # Factory method.
107
+ def parse_state(origin, aDottedRule)
108
+ ParseState.new(aDottedRule, origin)
109
+ end
110
+
111
+
112
+ it 'should trace its initialization' do
113
+ subject[0] # Force constructor call here
114
+ expectation = <<-SNIPPET
115
+ ['I', 'saw', 'John', 'with', 'a', 'dog']
116
+ |. I . saw . John . with . a . dog .|
117
+ |> . . . . . .| [0:0] sentence => A B . C
118
+ SNIPPET
119
+ expect(output.string).to eq(expectation)
120
+ end
121
+
122
+ it 'should trace parse state pushing' do
123
+ subject[0] # Force constructor call here
124
+ output.string = ''
125
+
126
+ subject.push_state(dotted_rule, 3, 5, :prediction)
127
+ expectation = <<-SNIPPET
128
+ |. . . > .| [3:5] sentence => A B . C
129
+ SNIPPET
130
+ expect(output.string).to eq(expectation)
131
+ end
132
+ =end
133
+ end # context
134
+ end # describe
135
+ end # module
136
+ end # module
137
+
138
+ # End of file