rley 0.6.07 → 0.6.08

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