rley 0.6.07 → 0.6.08

Sign up to get free protection for your applications and to get access to all the features.
@@ -5,7 +5,8 @@ module Rley # This module is used as a namespace
5
5
  # Utility class that helps to create a representation of a parse from
6
6
  # a given Parsing object.
7
7
  class ParseRepCreator
8
- # @return [GFGParsing] Link to Parsing object (= results of recognizer)
8
+ # @return [Rley::Parser::GFGParsing]
9
+ # Link to Parsing object (= results of recognizer)
9
10
  attr_reader(:parsing)
10
11
 
11
12
  # Constructor. Creates and initialize a ParseRepCreator instance.
@@ -15,7 +16,8 @@ module Rley # This module is used as a namespace
15
16
  end
16
17
 
17
18
  # Factory method that produces the representation of the parse.
18
- # @return [ParseTree] The parse representation.
19
+ # @return [Rley::PTree::ParseTree, Rley::SPPF::ParseForest]
20
+ # The parse representation.
19
21
  def create(aBuilder = nil)
20
22
  a_walker = walker(parsing)
21
23
  a_builder = builder(parsing, aBuilder)
@@ -97,9 +97,9 @@ module Rley # This module is used as a namespace
97
97
  # @param msg [Symbol] event to notify
98
98
  # @param args [Array] arguments of the notification.
99
99
  def broadcast(msg, *args)
100
- subscribers.each do |a_subscriber|
101
- next unless a_subscriber.respond_to?(msg)
102
- a_subscriber.send(msg, *args)
100
+ subscribers.each do |subscr|
101
+ next unless subscr.respond_to?(msg) || subscr.respond_to?(:accept_all)
102
+ subscr.send(msg, *args)
103
103
  end
104
104
  end
105
105
  end # class
@@ -20,9 +20,9 @@ module Rley # This module is used as a namespace
20
20
  @root = theRootNode
21
21
  end
22
22
 
23
- # Notify the builder that the construction is over.
24
- # This method can be overriden
25
- def done!()
23
+ # Notification from the builder telling that the parse tree construction
24
+ # is over. This method can be overriden.
25
+ def done!
26
26
  @root.done!
27
27
  end
28
28
 
@@ -28,6 +28,12 @@ module Rley # This module is used as a namespace
28
28
  def to_string(indentation)
29
29
  return "Alt(#{label})#{range.to_string(indentation)}"
30
30
  end
31
+
32
+ # Part of the 'visitee' role in Visitor design pattern.
33
+ # @param aVisitor[ParseTreeVisitor] the visitor
34
+ def accept(aVisitor)
35
+ aVisitor.visit_alternative(self)
36
+ end
31
37
  end # class
32
38
  end # module
33
39
  end # module
@@ -7,6 +7,8 @@ module Rley # This module is used as a namespace
7
7
  class CompositeNode < SPPFNode
8
8
  # @return [Array<SPFFNode>] Sub-nodes (children).
9
9
  attr_reader(:subnodes)
10
+
11
+ alias children subnodes
10
12
 
11
13
  # Constructor
12
14
  # @param aRange [Lexical::TokenRange]
@@ -17,6 +17,12 @@ module Rley # This module is used as a namespace
17
17
  def to_string(indentation)
18
18
  return "_#{range.to_string(indentation)}"
19
19
  end
20
+
21
+ # Part of the 'visitee' role in Visitor design pattern.
22
+ # @param aVisitor[ParseTreeVisitor] the visitor
23
+ def accept(aVisitor)
24
+ aVisitor.visit_epsilon(self)
25
+ end
20
26
  end # class
21
27
  end # module
22
28
  end # module
@@ -14,7 +14,7 @@ module Rley # This module is used as a namespace
14
14
 
15
15
  # Constructor
16
16
  # @param aNonTerminal [Syntax::NonTerminal]
17
- # @param aRange [Lexical::TokenRange]
17
+ # @param aRange [Lexical::TokenRange]
18
18
  def initialize(aNonTerminal, aRange)
19
19
  super(aRange)
20
20
  @symbol = aNonTerminal
@@ -22,7 +22,7 @@ module Rley # This module is used as a namespace
22
22
  end
23
23
 
24
24
  # Add a sub-node (child) to this one.
25
- # @param aSubnode [SPPFNode]
25
+ # @param aSubnode [SPPFNode]
26
26
  def add_subnode(aSubnode)
27
27
  if refinement == :or
28
28
  subnodes << aSubnode
@@ -33,10 +33,16 @@ module Rley # This module is used as a namespace
33
33
 
34
34
  # Emit a (formatted) string representation of the node.
35
35
  # Mainly used for diagnosis/debugging purposes.
36
- # @return [String] a text representation of the node.
36
+ # @return [String] a text representation of the node.
37
37
  def to_string(indentation)
38
38
  return "#{symbol.name}#{range.to_string(indentation)}"
39
39
  end
40
+
41
+ # Part of the 'visitee' role in Visitor design pattern.
42
+ # @param aVisitor[ParseTreeVisitor] the visitor
43
+ def accept(aVisitor)
44
+ aVisitor.visit_nonterminal(self)
45
+ end
40
46
  end # class
41
47
  end # module
42
48
  end # module
@@ -30,7 +30,7 @@ module Rley # This module is used as a namespace
30
30
  end
31
31
 
32
32
  # Notification that the SPPF construction is over
33
- def done!()
33
+ def done!
34
34
  end
35
35
 
36
36
  # Returns true if the given node is present in the forest.
@@ -43,6 +43,17 @@ module Rley # This module is used as a namespace
43
43
  def ambiguous?()
44
44
  return @is_ambiguous
45
45
  end
46
+
47
+ # Create an Enumerator that helps to iterate over the possible parse trees.
48
+ # That enumerator will generate a parse tree when called with `next` method.
49
+ # @return [Enumerator]
50
+ def to_ptree_enum()
51
+ # How to implement?
52
+ # One visits the forest => beware of dependency
53
+ # At each visited item create a corresponding tree node.
54
+ # At end of visit & stack not empty
55
+ # Re-generate another ptree
56
+ end
46
57
 
47
58
  # Part of the 'visitee' role in the Visitor design pattern.
48
59
  # A visitee is expected to accept the visit from a visitor object
@@ -25,6 +25,12 @@ module Rley # This module is used as a namespace
25
25
  def to_string(indentation)
26
26
  return "#{token.terminal.name}#{range.to_string(indentation)}"
27
27
  end
28
+
29
+ # Part of the 'visitee' role in Visitor design pattern.
30
+ # @param aVisitor[ParseTreeVisitor] the visitor
31
+ def accept(aVisitor)
32
+ aVisitor.visit_terminal(self)
33
+ end
28
34
  end # class
29
35
  end # module
30
36
  end # module
@@ -3,7 +3,6 @@ require_relative '../spec_helper'
3
3
 
4
4
  require_relative '../../lib/rley/lexical/token'
5
5
  require_relative '../../lib/rley/parse_rep/cst_builder'
6
- require_relative '../../lib/rley/parse_tree_visitor'
7
6
 
8
7
  # Load the class under test
9
8
  require_relative '../../lib/rley/engine'
@@ -93,10 +92,10 @@ module Rley # Open this namespace to avoid module qualifier prefixes
93
92
  add_sample_grammar(instance)
94
93
  instance
95
94
  end
96
-
95
+
97
96
  let(:sample_tokenizer) do
98
97
  sample_text = 'a a b c c'
99
- ABCTokenizer.new(sample_text)
98
+ ABCTokenizer.new(sample_text)
100
99
  end
101
100
 
102
101
  it 'should build default parse trees' do
@@ -107,18 +106,45 @@ module Rley # Open this namespace to avoid module qualifier prefixes
107
106
 
108
107
  it 'should build custom parse trees' do
109
108
  # Cheating: we point to default tree builder (CST)
110
- subject.configuration.repr_builder = ParseRep::CSTBuilder
109
+ subject.configuration.repr_builder = ParseRep::CSTBuilder
111
110
  raw_result = subject.parse(sample_tokenizer)
112
111
  ptree = subject.convert(raw_result)
113
112
  expect(ptree).to be_kind_of(PTree::ParseTree)
114
113
  end
115
-
114
+
116
115
  it 'should provide a parse visitor' do
117
116
  raw_result = subject.parse(sample_tokenizer)
118
117
  ptree = subject.to_ptree(raw_result)
119
118
  visitor = subject.ptree_visitor(ptree)
120
119
  expect(visitor).to be_kind_of(ParseTreeVisitor)
121
- end
120
+ end
121
+ end # context
122
+
123
+ context 'Parse forest manipulation:' do
124
+ subject do
125
+ instance = Engine.new
126
+ add_sample_grammar(instance)
127
+ instance
128
+ end
129
+
130
+ let(:sample_tokenizer) do
131
+ sample_text = 'a a b c c'
132
+ ABCTokenizer.new(sample_text)
133
+ end
134
+
135
+ it 'should build parse forest' do
136
+ raw_result = subject.parse(sample_tokenizer)
137
+ pforest = subject.to_pforest(raw_result)
138
+ expect(pforest).to be_kind_of(SPPF::ParseForest)
139
+ end
140
+
141
+ it 'should provide a parse visitor' do
142
+ raw_result = subject.parse(sample_tokenizer)
143
+ ptree = subject.to_pforest(raw_result)
144
+ visitor = subject.pforest_visitor(ptree)
145
+ expect(visitor).to be_kind_of(ParseForestVisitor)
146
+ end
147
+
122
148
  end # context
123
149
  end # describe
124
150
  end # module
@@ -1,19 +1,20 @@
1
1
  require_relative '../../spec_helper'
2
2
  require 'stringio'
3
3
 
4
- require_relative '../support/grammar_abc_helper'
5
4
  require_relative '../../../lib/rley/lexical/token'
6
- require_relative '../../../lib/rley/parser/gfg_earley_parser'
7
- require_relative '../../../lib/rley/ptree/parse_tree'
8
- require_relative '../../../lib/rley/parse_tree_visitor'
9
5
  require_relative '../../../lib/rley/engine'
6
+ require_relative '../support/grammar_abc_helper'
7
+ require_relative '../support/grammar_sppf_helper'
8
+
10
9
  # Load the class under test
11
10
  require_relative '../../../lib/rley/formatter/debug'
12
11
 
13
12
  module Rley # Re-open the module to get rid of qualified names
14
13
  module Formatter
15
14
  describe Debug do
16
- # Factory method. Build a production with the given sequence
15
+ include GrammarSPPFHelper # Mix-in module with builder for grammar sppf
16
+
17
+ # Factory method. Build a production with the given sequence
17
18
  # of symbols as its rhs.
18
19
  let(:grammar_abc) do
19
20
  sandbox = Object.new
@@ -21,18 +22,27 @@ module Rley # Re-open the module to get rid of qualified names
21
22
  builder = sandbox.grammar_abc_builder
22
23
  builder.grammar
23
24
  end
24
-
25
+
25
26
  # Variables for the terminal symbols
26
27
  let(:a_) { grammar_abc.name2symbol['a'] }
27
28
  let(:b_) { grammar_abc.name2symbol['b'] }
28
29
  let(:c_) { grammar_abc.name2symbol['c'] }
29
-
30
+
30
31
  # Helper method that mimicks the output of a tokenizer
31
32
  # for the language specified by grammar_abc
32
33
  let(:grm_abc_tokens1) do
33
34
  %w[a a b c c].map { |ch| Lexical::Token.new(ch, ch) }
34
35
  end
35
36
 
37
+ let(:grammar_sppf) do
38
+ builder = grammar_sppf_builder
39
+ builder.grammar
40
+ end
41
+
42
+ let(:sample_tokens) do
43
+ %w[a b b b].map { |ch| Lexical::Token.new(ch, ch) }
44
+ end
45
+
36
46
  # Factory method that builds a sample parse tree.
37
47
  # Generated tree has the following structure:
38
48
  # S[0,5]
@@ -47,30 +57,43 @@ module Rley # Re-open the module to get rid of qualified names
47
57
  # Capital letters represent non-terminal nodes
48
58
  let(:grm_abc_ptree1) do
49
59
  engine = Rley::Engine.new
50
- engine.use_grammar(grammar_abc)
60
+ engine.use_grammar(grammar_abc)
51
61
  parse_result = engine.parse(grm_abc_tokens1)
52
62
  ptree = engine.convert(parse_result)
53
63
  ptree
54
64
  end
55
-
65
+
66
+ # Factory method that builds a sample parse forest.
67
+ # Generated forest has the following structure:
68
+ let(:grm_sppf_pforest1) do
69
+ engine = Rley::Engine.new
70
+ engine.use_grammar(grammar_sppf)
71
+ parse_result = engine.parse(sample_tokens)
72
+ engine.to_pforest(parse_result)
73
+ end
74
+
56
75
  let(:destination) { StringIO.new('', 'w') }
57
76
 
58
77
  context 'Standard creation & initialization:' do
59
78
  it 'should be initialized with an IO argument' do
60
79
  expect { Debug.new(StringIO.new('', 'w')) }.not_to raise_error
61
80
  end
62
-
81
+
63
82
  it 'should know its output destination' do
64
83
  instance = Debug.new(destination)
65
84
  expect(instance.output).to eq(destination)
66
85
  end
86
+
87
+ it 'should have a zero indentation' do
88
+ instance = Debug.new(destination)
89
+ expect(instance.indentation).to be_zero
90
+ end
67
91
  end # context
68
-
69
92
 
70
-
71
- context 'Formatting events:' do
93
+ context 'Formatting events:' do
72
94
  it 'should support visit events of a parse tree' do
73
95
  instance = Debug.new(destination)
96
+ expect(instance.output).to eq(destination)
74
97
  visitor = Rley::ParseTreeVisitor.new(grm_abc_ptree1)
75
98
  instance.render(visitor)
76
99
  expectations = <<-SNIPPET
@@ -102,6 +125,96 @@ before_ptree
102
125
  after_subnodes
103
126
  after_non_terminal
104
127
  after_ptree
128
+ SNIPPET
129
+ expect(destination.string).to eq(expectations)
130
+ end
131
+
132
+ it 'should support visit events of a parse forest' do
133
+ instance = Debug.new(destination)
134
+ expect(instance.output).to eq(destination)
135
+ visitor = Rley::ParseForestVisitor.new(grm_sppf_pforest1)
136
+ instance.render(visitor)
137
+ expectations = <<-SNIPPET
138
+ before_pforest
139
+ before_non_terminal
140
+ before_subnodes
141
+ before_non_terminal
142
+ before_subnodes
143
+ before_alternative
144
+ before_subnodes
145
+ before_terminal
146
+ after_terminal
147
+ before_non_terminal
148
+ before_subnodes
149
+ before_terminal
150
+ after_terminal
151
+ before_terminal
152
+ after_terminal
153
+ before_terminal
154
+ after_terminal
155
+ after_subnodes
156
+ after_non_terminal
157
+ after_subnodes
158
+ after_alternative
159
+ before_alternative
160
+ before_subnodes
161
+ before_non_terminal
162
+ before_subnodes
163
+ before_alternative
164
+ before_subnodes
165
+ before_terminal
166
+ after_terminal
167
+ after_subnodes
168
+ after_alternative
169
+ before_alternative
170
+ before_subnodes
171
+ before_non_terminal
172
+ before_subnodes
173
+ before_epsilon
174
+ after_epsilon
175
+ after_subnodes
176
+ after_non_terminal
177
+ before_non_terminal
178
+ before_subnodes
179
+ before_alternative
180
+ before_subnodes
181
+ before_terminal
182
+ after_terminal
183
+ after_subnodes
184
+ after_alternative
185
+ before_alternative
186
+ before_subnodes
187
+ before_non_terminal
188
+ before_subnodes
189
+ before_epsilon
190
+ after_epsilon
191
+ after_subnodes
192
+ after_non_terminal
193
+ after_subnodes
194
+ after_alternative
195
+ after_subnodes
196
+ after_non_terminal
197
+ after_subnodes
198
+ after_alternative
199
+ after_subnodes
200
+ after_non_terminal
201
+ before_non_terminal
202
+ before_subnodes
203
+ before_terminal
204
+ after_terminal
205
+ before_terminal
206
+ after_terminal
207
+ before_terminal
208
+ after_terminal
209
+ after_subnodes
210
+ after_non_terminal
211
+ after_subnodes
212
+ after_alternative
213
+ after_subnodes
214
+ after_non_terminal
215
+ after_subnodes
216
+ after_non_terminal
217
+ after_pforest
105
218
  SNIPPET
106
219
  expect(destination.string).to eq(expectations)
107
220
  end
@@ -4,8 +4,10 @@ require_relative './support/grammar_helper'
4
4
  require_relative './support/grammar_sppf_helper'
5
5
  require_relative '../../lib/rley/lexical/token'
6
6
  require_relative '../../lib/rley/parser/gfg_earley_parser'
7
+ require_relative '../../lib/rley/parse_rep/parse_forest_factory'
7
8
  require_relative '../../lib/rley/sppf/non_terminal_node'
8
9
  require_relative '../../lib/rley/sppf/parse_forest'
10
+ require_relative '../../lib/rley/formatter/debug'
9
11
 
10
12
  # Load the class under test
11
13
  require_relative '../../lib/rley/parse_forest_visitor'
@@ -31,7 +33,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
31
33
  end
32
34
 
33
35
  # A forest with just a root node
34
- let(:rooted_forest) do
36
+ let(:forest_root) do
35
37
  parser = Parser::GFGEarleyParser.new(grammar_sppf)
36
38
  parse_result = parser.parse(sample_tokens)
37
39
  accepting_entry = parse_result.accepting_entry
@@ -40,37 +42,27 @@ module Rley # Open this namespace to avoid module qualifier prefixes
40
42
  Rley::SPPF::ParseForest.new(root_node)
41
43
  end
42
44
 
43
- =begin
44
45
  # Factory method that builds a sample parse forest.
45
46
  # Generated forest has the following structure:
46
- # S[0,5]
47
- # +- A[0,5]
48
- # +- a[0,0]
49
- # +- A[1,4]
50
- # | +- a[1,1]
51
- # | +- A[2,3]
52
- # | | +- b[2,3]
53
- # | +- c[3,4]
54
- # +- c[4,5]
55
- # Capital letters represent non-terminal nodes
56
- let(:grm_abc_pforest1) do
57
- parser = Parser::EarleyParser.new(grammar_abc)
58
- parse_result = parser.parse(grm_abc_tokens1)
59
- parse_result.parse_forest
47
+ let(:grm_sppf_pforest1) do
48
+ parser = Parser::GFGEarleyParser.new(grammar_sppf)
49
+ parse_result = parser.parse(sample_tokens)
50
+ factory = ParseRep::ParseForestFactory.new(parse_result)
51
+ factory.create
60
52
  end
61
- =end
53
+
62
54
 
63
55
  # Default instantiation rule
64
- subject { ParseForestVisitor.new(rooted_forest) }
56
+ subject { ParseForestVisitor.new(forest_root) }
65
57
 
66
58
 
67
59
  context 'Standard creation & initialization:' do
68
60
  it 'should be initialized with a parse forest argument' do
69
- expect { ParseForestVisitor.new(rooted_forest) }.not_to raise_error
61
+ expect { ParseForestVisitor.new(forest_root) }.not_to raise_error
70
62
  end
71
63
 
72
64
  it 'should know the parse forest to visit' do
73
- expect(subject.pforest).to eq(rooted_forest)
65
+ expect(subject.pforest).to eq(forest_root)
74
66
  end
75
67
 
76
68
  it "shouldn't have subscribers at start" do
@@ -104,134 +96,370 @@ module Rley # Open this namespace to avoid module qualifier prefixes
104
96
  end
105
97
  end # context
106
98
 
99
+ class EventDispatcher
100
+ # return [Array<Proc>]
101
+ attr_accessor(:expectations)
102
+ attr_reader(:event_count)
107
103
 
108
- context 'Notifying visit events:' do
109
- # Use doubles/mocks to simulate subscribers
110
- let(:listener1) { double('fake-subscriber1') }
111
- let(:listener2) { double('fake-subscriber2') }
112
-
113
- it 'should react to the start_visit_pforest message' do
114
- subject.subscribe(listener1)
115
-
116
- # Notify subscribers when start the visit of the pforest
117
- expect(listener1).to receive(:before_pforest).with(rooted_forest)
118
- subject.start_visit_pforest(rooted_forest)
119
- end
120
- =begin
121
- # Default instantiation rule
122
- subject do
123
- instance = ParseForestVisitor.new(grm_abc_pforest1)
124
- instance.subscribe(listener1)
125
- instance
104
+ def initialize
105
+ @event_count = 0
126
106
  end
127
107
 
128
-
129
-
130
- # Sample non-terminal node
131
- let(:nterm_node) do
132
- first_big_a = grm_abc_pforest1.root.children[0]
133
- second_big_a = first_big_a.children[1]
134
- second_big_a.children[1]
108
+ def accept_all
109
+ true
135
110
  end
136
111
 
137
- # Sample terminal node
138
- let(:term_node) { nterm_node.children[0] }
139
-
140
- it 'should react to the start_visit_pforest message' do
141
- # Notify subscribers when start the visit of the pforest
142
- expect(listener1).to receive(:before_pforest).with(grm_abc_pforest1)
143
- subject.start_visit_pforest(grm_abc_pforest1)
112
+ def method_missing(mth, *args)
113
+ if expectations.at(event_count)
114
+ if mth =~ /_subnodes$/
115
+ parent = args[0]
116
+ children = args[1]
117
+ expectations[event_count].call(mth, parent, children)
118
+ else
119
+ actual_item = args[0]
120
+ expectations[event_count].call(mth, actual_item)
121
+ end
122
+ end
123
+ @event_count += 1
144
124
  end
125
+ end # class
145
126
 
146
- it 'should react to the start_visit_nonterminal message' do
147
- # Notify subscribers when start the visit of a non-terminal node
148
- expect(listener1).to receive(:before_non_terminal).with(nterm_node)
149
- subject.visit_nonterminal(nterm_node)
127
+ context 'Notifying visit events:' do
128
+ # expectations [Array<Array<Symbol, String>>]
129
+ def check_event(actual_event, actual_item, expectations)
130
+ (event, item) = expectations
131
+ expect(actual_event).to eq(event)
132
+ case item
133
+ when String
134
+ expect(actual_item.to_string(0)).to eq(item)
135
+ end
150
136
  end
151
137
 
152
- it 'should react to the visit_children message' do
153
- # Notify subscribers when start the visit of children nodes
154
- children = nterm_node.children
155
- args = [nterm_node, children]
156
- expect(listener1).to receive(:before_children).with(*args)
157
- expect(listener1).to receive(:before_terminal).with(children[0])
158
- expect(listener1).to receive(:after_terminal).with(children[0])
159
- expect(listener1).to receive(:after_children).with(nterm_node, children)
160
- subject.send(:traverse_children, nterm_node)
138
+ def check_legs(expectations)
139
+ (parent, path_signature) = subject.legs[-1]
140
+ expect(parent.to_string(0)).to eq(expectations[0])
141
+ expect(path_signature).to eq(expectations[1])
161
142
  end
162
143
 
163
- it 'should react to the end_visit_nonterminal message' do
164
- # Notify subscribers when ending the visit of a non-terminal node
165
- expect(listener1).to receive(:after_non_terminal).with(nterm_node)
166
- subject.end_visit_nonterminal(nterm_node)
144
+ def check_node_accesses(node, paths)
145
+ actual_paths = subject.node_accesses.fetch(node)
146
+ expect(actual_paths).to eq(paths)
167
147
  end
168
148
 
169
- it 'should react to the visit_terminal message' do
170
- # Notify subscribers when start & ending the visit of a terminal node
171
- expect(listener1).to receive(:before_terminal).with(term_node)
172
- expect(listener1).to receive(:after_terminal).with(term_node)
173
- subject.visit_terminal(term_node)
174
- end
149
+ let(:checker) { EventDispatcher.new }
175
150
 
176
- it 'should react to the end_visit_pforest message' do
177
- # Notify subscribers when ending the visit of the pforest
178
- expect(listener1).to receive(:after_pforest).with(grm_abc_pforest1)
179
- subject.end_visit_pforest(grm_abc_pforest1)
151
+ # Default instantiation rule
152
+ subject do
153
+ instance = ParseForestVisitor.new(grm_sppf_pforest1)
154
+ instance.subscribe(checker)
155
+ instance
180
156
  end
181
157
 
182
- it 'should begin the visit when requested' do
183
- # Reminder: parse forest structure is
184
- # S[0,5]
185
- # +- A[0,5]
186
- # +- a[0,0]
187
- # +- A[1,4]
188
- # | +- a[1,1]
189
- # | +- A[2,3]
190
- # | | +- b[2,3]
191
- # | +- c[3,4]
192
- # +- c[4,5]
193
- root = grm_abc_pforest1.root
194
- children = root.children
195
- big_a_1 = children[0]
196
- big_a_1_children = big_a_1.children
197
- big_a_2 = big_a_1_children[1]
198
- big_a_2_children = big_a_2.children
199
- big_a_3 = big_a_2_children[1]
200
- big_a_3_children = big_a_3.children
201
- expectations = [
202
- [:before_pforest, [grm_abc_pforest1]],
203
- [:before_non_terminal, [root]],
204
- [:before_children, [root, children]],
205
- [:before_non_terminal, [big_a_1]],
206
- [:before_children, [big_a_1, big_a_1_children]],
207
- [:before_terminal, [big_a_1_children[0]]],
208
- [:after_terminal, [big_a_1_children[0]]],
209
- [:before_non_terminal, [big_a_2]],
210
- [:before_children, [big_a_2, big_a_2_children]],
211
- [:before_terminal, [big_a_2_children[0]]],
212
- [:after_terminal, [big_a_2_children[0]]],
213
- [:before_non_terminal, [big_a_3]],
214
- [:before_children, [big_a_3, big_a_3_children]],
215
- [:before_terminal, [big_a_3_children[0]]],
216
- [:after_terminal, [big_a_3_children[0]]],
217
- [:after_children, [big_a_3, big_a_3_children]],
218
- [:before_terminal, [big_a_2_children[2]]],
219
- [:after_terminal, [big_a_2_children[2]]],
220
- [:after_children, [big_a_2, big_a_2_children]],
221
- [:before_terminal, [big_a_1_children[2]]],
222
- [:after_terminal, [big_a_1_children[2]]],
223
- [:after_children, [big_a_1, big_a_1_children]],
224
- [:after_children, [root, children]],
225
- [:after_pforest, [grm_abc_pforest1]]
158
+ it 'should react to the start_visit_pforest message' do
159
+ # Notify subscribers when start the visit of the pforest
160
+ # expect(listener1).to receive(:before_pforest).with(forest_root)
161
+ checker.expectations = [
162
+ ->(event, item) {
163
+ check_event(event, item, [:before_pforest, grm_sppf_pforest1])
164
+ },
165
+ ->(event, item) {
166
+ check_event(event, item, [:before_non_terminal, 'Phi[0, 4]'])
167
+ },
168
+ ->(event, parent, children) {
169
+ check_event(event, parent, [:before_subnodes, 'Phi[0, 4]'])
170
+ expect(children.size).to eq(1)
171
+ },
172
+ ->(event, item) {
173
+ check_event(event, item, [:before_non_terminal, 'S[0, 4]'])
174
+ check_legs(['S[0, 4]', 2]) # 2
175
+ check_node_accesses(item, [2])
176
+ },
177
+ ->(event, parent, children) {
178
+ check_event(event, parent, [:before_subnodes, 'S[0, 4]'])
179
+ expect(children.size).to eq(2)
180
+ },
181
+ ->(event, item) {
182
+ check_event(event, item, [:before_alternative, 'Alt(S => a T .)[0, 4]'])
183
+ check_legs(['Alt(S => a T .)[0, 4]', 6]) # 2 * 3
184
+ check_node_accesses(item, [6])
185
+ },
186
+ ->(event, parent, children) {
187
+ check_event(event, parent, [:before_subnodes, 'Alt(S => a T .)[0, 4]'])
188
+ expect(children.size).to eq(2)
189
+ },
190
+ ->(event, item) {
191
+ check_event(event, item, [:before_terminal, 'a[0, 1]'])
192
+ },
193
+ ->(event, item) {
194
+ check_event(event, item, [:after_terminal, 'a[0, 1]'])
195
+ },
196
+ ->(event, item) {
197
+ check_event(event, item, [:before_non_terminal, 'T[1, 4]'])
198
+ check_legs(['T[1, 4]', 66]) # 2 * 3 * 11
199
+ check_node_accesses(item, [66])
200
+ },
201
+ ->(event, parent, children) {
202
+ check_event(event, parent, [:before_subnodes, 'T[1, 4]'])
203
+ expect(children.size).to eq(3)
204
+ },
205
+ ->(event, item) {
206
+ check_event(event, item, [:before_terminal, 'b[1, 2]'])
207
+ },
208
+ ->(event, item) {
209
+ check_event(event, item, [:after_terminal, 'b[1, 2]'])
210
+ },
211
+ ->(event, item) {
212
+ check_event(event, item, [:before_terminal, 'b[2, 3]'])
213
+ },
214
+ ->(event, item) {
215
+ check_event(event, item, [:after_terminal, 'b[2, 3]'])
216
+ },
217
+ ->(event, item) {
218
+ check_event(event, item, [:before_terminal, 'b[3, 4]'])
219
+ },
220
+ ->(event, item) {
221
+ check_event(event, item, [:after_terminal, 'b[3, 4]'])
222
+ },
223
+ ->(event, parent, children) {
224
+ check_event(event, parent, [:after_subnodes, 'T[1, 4]'])
225
+ },
226
+ ->(event, item) {
227
+ check_event(event, item, [:after_non_terminal, 'T[1, 4]'])
228
+ },
229
+ ->(event, parent, children) {
230
+ check_event(event, parent, [:after_subnodes, 'Alt(S => a T .)[0, 4]'])
231
+ expect(children.size).to eq(2)
232
+ check_legs(['Alt(S => a T .)[0, 4]', 6]) # 2 * 3
233
+ },
234
+ ->(event, item) {
235
+ check_event(event, item, [:after_alternative, 'Alt(S => a T .)[0, 4]'])
236
+ },
237
+ ->(event, item) {
238
+ check_event(event, item, [:before_alternative, 'Alt(S => A T .)[0, 4]'])
239
+ check_legs(['Alt(S => A T .)[0, 4]', 10]) # 2 * 5
240
+ check_node_accesses(item, [10])
241
+ },
242
+ ->(event, parent, children) {
243
+ check_event(event, parent, [:before_subnodes, 'Alt(S => A T .)[0, 4]'])
244
+ expect(children.size).to eq(2)
245
+ },
246
+ ->(event, item) {
247
+ check_event(event, item, [:before_non_terminal, 'A[0, 1]'])
248
+ check_legs(['A[0, 1]', 230]) # 2 * 5 * 23
249
+ check_node_accesses(item, [230])
250
+ },
251
+ ->(event, parent, children) {
252
+ check_event(event, parent, [:before_subnodes, 'A[0, 1]'])
253
+ expect(children.size).to eq(2)
254
+ },
255
+ ->(event, item) {
256
+ check_event(event, item, [:before_alternative, 'Alt(A => a .)[0, 1]'])
257
+ check_legs(['Alt(A => a .)[0, 1]', 7130]) # 2 * 5 * 23 * 31
258
+ check_node_accesses(item, [7130])
259
+ # p(subject.legs)
260
+ },
261
+ ->(event, parent, children) {
262
+ check_event(event, parent, [:before_subnodes, 'Alt(A => a .)[0, 1]'])
263
+ expect(children.size).to eq(1)
264
+ },
265
+ ->(event, item) {
266
+ check_event(event, item, [:before_terminal, 'a[0, 1]'])
267
+ },
268
+ ->(event, item) {
269
+ check_event(event, item, [:after_terminal, 'a[0, 1]'])
270
+ },
271
+ ->(event, parent, children) {
272
+ check_event(event, parent, [:after_subnodes, 'Alt(A => a .)[0, 1]'])
273
+ check_legs(['Alt(A => a .)[0, 1]', 7130]) # 2 * 5 * 23 * 31
274
+ },
275
+ ->(event, item) {
276
+ check_event(event, item, [:after_alternative, 'Alt(A => a .)[0, 1]'])
277
+ },
278
+ ->(event, item) {
279
+ check_event(event, item, [:before_alternative, 'Alt(A => B A .)[0, 1]'])
280
+ check_legs(['Alt(A => B A .)[0, 1]', 8510]) # 2 * 5 * 23 * 37
281
+ check_node_accesses(item, [8510])
282
+ },
283
+ ->(event, parent, children) {
284
+ check_event(event, parent, [:before_subnodes, 'Alt(A => B A .)[0, 1]'])
285
+ expect(children.size).to eq(2)
286
+ },
287
+ ->(event, item) {
288
+ check_event(event, item, [:before_non_terminal, 'B[0, 0]'])
289
+ check_legs(['B[0, 0]', 365930]) # 2 * 5 * 23 * 37 * 43
290
+ check_node_accesses(item, [365930])
291
+ },
292
+ ->(event, parent, children) {
293
+ check_event(event, parent, [:before_subnodes, 'B[0, 0]'])
294
+ expect(children.size).to eq(1)
295
+ },
296
+ ->(event, item) {
297
+ check_event(event, item, [:before_epsilon, '_[0, 0]'])
298
+ },
299
+ ->(event, item) {
300
+ check_event(event, item, [:after_epsilon, '_[0, 0]'])
301
+ },
302
+ ->(event, parent, children) {
303
+ check_event(event, parent, [:after_subnodes, 'B[0, 0]'])
304
+ check_legs(['B[0, 0]', 365930]) # 2 * 5 * 23 * 37 * 43
305
+ },
306
+ ->(event, item) {
307
+ check_event(event, item, [:after_non_terminal, 'B[0, 0]'])
308
+ },
309
+ ->(event, item) {
310
+ check_event(event, item, [:before_non_terminal, 'A[0, 1]'])
311
+ check_legs(['A[0, 1]', 399970]) # 2 * 5 * 23 * 37 * 47
312
+ check_node_accesses(item, [230, 399970])
313
+ },
314
+ ->(event, parent, children) {
315
+ check_event(event, parent, [:before_subnodes, 'A[0, 1]'])
316
+ expect(children.size).to eq(2)
317
+ },
318
+ ->(event, item) {
319
+ check_event(event, item, [:before_alternative, 'Alt(A => a .)[0, 1]'])
320
+ check_legs(['Alt(A => a .)[0, 1]', 12399070]) # 2 * 5 * 23 * 37 * 47 * 31
321
+ check_node_accesses(item, [7130, 12399070])
322
+ },
323
+ ->(event, parent, children) {
324
+ check_event(event, parent, [:before_subnodes, 'Alt(A => a .)[0, 1]'])
325
+ expect(children.size).to eq(1)
326
+ },
327
+ ->(event, item) {
328
+ check_event(event, item, [:before_terminal, 'a[0, 1]'])
329
+ },
330
+ ->(event, item) {
331
+ check_event(event, item, [:after_terminal, 'a[0, 1]'])
332
+ },
333
+ ->(event, parent, children) {
334
+ check_event(event, parent, [:after_subnodes, 'Alt(A => a .)[0, 1]'])
335
+ check_legs(['Alt(A => a .)[0, 1]', 12399070]) # 2 * 5 * 23 * 37 * 47 * 31
336
+ },
337
+ ->(event, item) {
338
+ check_event(event, item, [:after_alternative, 'Alt(A => a .)[0, 1]'])
339
+ },
340
+ ->(event, item) {
341
+ check_event(event, item, [:before_alternative, 'Alt(A => B A .)[0, 1]'])
342
+ # For prime factoring: https://www.calculatorsoup.com/calculators/math/prime-factors.php
343
+ check_legs(['Alt(A => B A .)[0, 1]', 399970]) # 2 * 5 * 23 * 37 * 47
344
+ check_node_accesses(item, [8510, 399970])
345
+ },
346
+ ->(event, parent, children) {
347
+ check_event(event, parent, [:before_subnodes, 'Alt(A => B A .)[0, 1]'])
348
+ expect(children.size).to eq(2)
349
+ },
350
+ ->(event, item) {
351
+ check_event(event, item, [:before_non_terminal, 'B[0, 0]'])
352
+ check_legs(['B[0, 0]', 17198710]) # 2 * 5 * 23 * 37 * 47 * 43
353
+ check_node_accesses(item, [365930, 17198710])
354
+ },
355
+ ->(event, parent, children) {
356
+ check_event(event, parent, [:before_subnodes, 'B[0, 0]'])
357
+ expect(children.size).to eq(1)
358
+ },
359
+ ->(event, item) {
360
+ check_event(event, item, [:before_epsilon, '_[0, 0]'])
361
+ },
362
+ ->(event, item) {
363
+ check_event(event, item, [:after_epsilon, '_[0, 0]'])
364
+ },
365
+ ->(event, parent, children) {
366
+ check_event(event, parent, [:after_subnodes, 'B[0, 0]'])
367
+ check_legs(['B[0, 0]', 17198710]) # 2 * 5 * 23 * 37 * 43 * 47
368
+ },
369
+ ->(event, item) {
370
+ check_event(event, item, [:after_non_terminal, 'B[0, 0]'])
371
+ },
372
+ ->(event, parent, children) {
373
+ check_event(event, parent, [:after_subnodes, 'Alt(A => B A .)[0, 1]'])
374
+ check_legs(['Alt(A => B A .)[0, 1]', 399970]) # 2 * 5 * 23 * 37 * 47
375
+ check_node_accesses(parent, [8510, 399970])
376
+ },
377
+ ->(event, item) {
378
+ check_event(event, item, [:after_alternative, 'Alt(A => B A .)[0, 1]'])
379
+ },
380
+ ->(event, parent, children) {
381
+ check_event(event, parent, [:after_subnodes, 'A[0, 1]'])
382
+ check_legs(['A[0, 1]', 399970]) # 2 * 5 * 23 * 37 * 47
383
+ },
384
+ ->(event, item) {
385
+ check_event(event, item, [:after_non_terminal, 'A[0, 1]'])
386
+ },
387
+ ->(event, parent, children) {
388
+ check_event(event, parent, [:after_subnodes, 'Alt(A => B A .)[0, 1]'])
389
+ check_legs(['Alt(A => B A .)[0, 1]', 8510]) # 2 * 5 * 23 * 37
390
+ },
391
+ ->(event, item) {
392
+ check_event(event, item, [:after_alternative, 'Alt(A => B A .)[0, 1]'])
393
+ },
394
+ ->(event, parent, children) {
395
+ check_event(event, parent, [:after_subnodes, 'A[0, 1]'])
396
+ check_legs(['A[0, 1]', 230]) # 2 * 5 * 23
397
+ },
398
+ ->(event, item) {
399
+ check_event(event, item, [:after_non_terminal, 'A[0, 1]'])
400
+ },
401
+ ->(event, item) {
402
+ check_event(event, item, [:before_non_terminal, 'T[1, 4]'])
403
+ check_legs(['T[1, 4]', 290]) # 2 * 5 * 29
404
+ check_node_accesses(item, [66, 290])
405
+ },
406
+ ->(event, parent, children) {
407
+ check_event(event, parent, [:before_subnodes, 'T[1, 4]'])
408
+ expect(children.size).to eq(3)
409
+ },
410
+ ->(event, item) {
411
+ check_event(event, item, [:before_terminal, 'b[1, 2]'])
412
+ },
413
+ ->(event, item) {
414
+ check_event(event, item, [:after_terminal, 'b[1, 2]'])
415
+ },
416
+ ->(event, item) {
417
+ check_event(event, item, [:before_terminal, 'b[2, 3]'])
418
+ },
419
+ ->(event, item) {
420
+ check_event(event, item, [:after_terminal, 'b[2, 3]'])
421
+ },
422
+ ->(event, item) {
423
+ check_event(event, item, [:before_terminal, 'b[3, 4]'])
424
+ },
425
+ ->(event, item) {
426
+ check_event(event, item, [:after_terminal, 'b[3, 4]'])
427
+ },
428
+ ->(event, parent, children) {
429
+ check_event(event, parent, [:after_subnodes, 'T[1, 4]'])
430
+ },
431
+ ->(event, item) {
432
+ check_event(event, item, [:after_non_terminal, 'T[1, 4]'])
433
+ },
434
+ ->(event, parent, children) {
435
+ check_event(event, parent, [:after_subnodes, 'Alt(S => A T .)[0, 4]'])
436
+ expect(children.size).to eq(2)
437
+ check_legs(['Alt(S => A T .)[0, 4]', 10]) # 2 * 5
438
+ },
439
+ ->(event, item) {
440
+ check_event(event, item, [:after_alternative, 'Alt(S => A T .)[0, 4]'])
441
+ },
442
+ ->(event, parent, children) {
443
+ check_event(event, parent, [:after_subnodes, 'S[0, 4]'])
444
+ expect(children.size).to eq(2)
445
+ check_legs(['S[0, 4]', 2]) # 2
446
+ },
447
+ ->(event, item) {
448
+ check_event(event, item, [:after_non_terminal, 'S[0, 4]'])
449
+ },
450
+ ->(event, parent, children) {
451
+ check_event(event, parent, [:after_subnodes, 'Phi[0, 4]'])
452
+ expect(children.size).to eq(1)
453
+ },
454
+ ->(event, item) {
455
+ check_event(event, item, [:after_non_terminal, 'Phi[0, 4]'])
456
+ },
457
+ ->(event, item) {
458
+ check_event(event, item, [:after_pforest, grm_sppf_pforest1])
459
+ }
226
460
  ]
227
- expectations.each do |(msg, args)|
228
- expect(listener1).to receive(msg).with(*args).ordered
229
- end
230
-
231
- # Here we go...
232
461
  subject.start
233
462
  end
234
- =end
235
463
  end # context
236
464
  end # describe
237
465
  end # module