rley 0.2.15 → 0.3.00

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.
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