rley 0.2.15 → 0.3.00
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -0
- data/lib/rley/constants.rb +1 -1
- data/lib/rley/gfg/call_edge.rb +30 -0
- data/lib/rley/gfg/edge.rb +4 -0
- data/lib/rley/gfg/end_vertex.rb +1 -1
- data/lib/rley/gfg/epsilon_edge.rb +0 -4
- data/lib/rley/gfg/grm_flow_graph.rb +32 -7
- data/lib/rley/gfg/item_vertex.rb +71 -25
- data/lib/rley/gfg/non_terminal_vertex.rb +10 -1
- data/lib/rley/gfg/return_edge.rb +31 -0
- data/lib/rley/gfg/scan_edge.rb +2 -1
- data/lib/rley/gfg/shortcut_edge.rb +26 -0
- data/lib/rley/gfg/start_vertex.rb +2 -2
- data/lib/rley/gfg/vertex.rb +27 -1
- data/lib/rley/parse_forest_visitor.rb +115 -0
- data/lib/rley/parser/base_parser.rb +27 -0
- data/lib/rley/parser/dotted_item.rb +11 -0
- data/lib/rley/parser/earley_parser.rb +3 -15
- data/lib/rley/parser/gfg_chart.rb +106 -0
- data/lib/rley/parser/gfg_earley_parser.rb +139 -0
- data/lib/rley/parser/gfg_parsing.rb +384 -0
- data/lib/rley/parser/parse_entry.rb +148 -0
- data/lib/rley/parser/parse_entry_set.rb +104 -0
- data/lib/rley/parser/parse_entry_tracker.rb +56 -0
- data/lib/rley/parser/parse_forest_builder.rb +229 -0
- data/lib/rley/parser/parse_forest_factory.rb +54 -0
- data/lib/rley/parser/parse_walker_factory.rb +237 -0
- data/lib/rley/ptree/token_range.rb +14 -1
- data/lib/rley/sppf/alternative_node.rb +34 -0
- data/lib/rley/sppf/composite_node.rb +27 -0
- data/lib/rley/sppf/epsilon_node.rb +27 -0
- data/lib/rley/sppf/leaf_node.rb +12 -0
- data/lib/rley/sppf/non_terminal_node.rb +38 -0
- data/lib/rley/sppf/parse_forest.rb +48 -0
- data/lib/rley/sppf/sppf_node.rb +24 -0
- data/lib/rley/sppf/token_node.rb +29 -0
- data/lib/rley/syntax/grammar_builder.rb +16 -12
- data/lib/rley/syntax/grm_symbol.rb +6 -0
- data/lib/rley/syntax/terminal.rb +5 -0
- data/spec/rley/gfg/call_edge_spec.rb +51 -0
- data/spec/rley/gfg/end_vertex_spec.rb +1 -0
- data/spec/rley/gfg/grm_flow_graph_spec.rb +24 -2
- data/spec/rley/gfg/item_vertex_spec.rb +75 -6
- data/spec/rley/gfg/non_terminal_vertex_spec.rb +14 -0
- data/spec/rley/gfg/return_edge_spec.rb +51 -0
- data/spec/rley/gfg/shortcut_edge_spec.rb +43 -0
- data/spec/rley/gfg/vertex_spec.rb +52 -37
- data/spec/rley/parse_forest_visitor_spec.rb +238 -0
- data/spec/rley/parser/dotted_item_spec.rb +29 -8
- data/spec/rley/parser/gfg_chart_spec.rb +138 -0
- data/spec/rley/parser/gfg_earley_parser_spec.rb +918 -0
- data/spec/rley/parser/gfg_parsing_spec.rb +565 -0
- data/spec/rley/parser/parse_entry_set_spec.rb +179 -0
- data/spec/rley/parser/parse_entry_spec.rb +208 -0
- data/spec/rley/parser/parse_forest_builder_spec.rb +382 -0
- data/spec/rley/parser/parse_forest_factory_spec.rb +81 -0
- data/spec/rley/parser/parse_walker_factory_spec.rb +235 -0
- data/spec/rley/parser/state_set_spec.rb +4 -0
- data/spec/rley/sppf/alternative_node_spec.rb +72 -0
- data/spec/rley/sppf/antecedence_graph.rb +87 -0
- data/spec/rley/sppf/forest_representation.rb +136 -0
- data/spec/rley/sppf/gfg_representation.rb +111 -0
- data/spec/rley/sppf/non_terminal_node_spec.rb +64 -0
- data/spec/rley/support/ambiguous_grammar_helper.rb +36 -36
- data/spec/rley/support/expectation_helper.rb +36 -0
- data/spec/rley/support/grammar_helper.rb +28 -0
- data/spec/rley/support/grammar_sppf_helper.rb +25 -0
- data/spec/rley/syntax/grammar_builder_spec.rb +5 -0
- data/spec/rley/syntax/non_terminal_spec.rb +4 -0
- data/spec/rley/syntax/terminal_spec.rb +4 -0
- metadata +58 -2
@@ -0,0 +1,48 @@
|
|
1
|
+
require_relative 'token_node'
|
2
|
+
require_relative 'non_terminal_node'
|
3
|
+
|
4
|
+
module Rley # This module is used as a namespace
|
5
|
+
module SPPF # This module is used as a namespace
|
6
|
+
# TODO change comment
|
7
|
+
# A parse tree (a.k.a. concrete syntax tree) is a tree-based representation
|
8
|
+
# for the parse that corresponds to the input text. In a parse tree,
|
9
|
+
# a node corresponds to a grammar symbol used during the parsing:
|
10
|
+
# - a leaf node maps to a terminal symbol occurring in
|
11
|
+
# the input, and
|
12
|
+
# - a intermediate node maps to a non-terminal node reduced
|
13
|
+
# during the parse.
|
14
|
+
# The root node corresponds to the main/start symbol of the grammar.
|
15
|
+
class ParseForest
|
16
|
+
# The root node of the forest
|
17
|
+
attr_reader(:root)
|
18
|
+
|
19
|
+
# A Hash with pairs of the kind node key => node
|
20
|
+
attr_reader(:key2node)
|
21
|
+
|
22
|
+
# @param theRootNode [ParseForestNode] The root node of the parse tree.
|
23
|
+
def initialize(theRootNode)
|
24
|
+
@root = theRootNode
|
25
|
+
@key2node = {}
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns true if the given node is present in the forest.
|
29
|
+
def include?(aNode)
|
30
|
+
return key2node.include?(aNode)
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
# Part of the 'visitee' role in the Visitor design pattern.
|
35
|
+
# A visitee is expected to accept the visit from a visitor object
|
36
|
+
# @param aVisitor [ParseForestVisitor] the visitor object
|
37
|
+
def accept(aVisitor)
|
38
|
+
aVisitor.start_visit_pforest(self)
|
39
|
+
|
40
|
+
# Let's proceed with the visit of nodes
|
41
|
+
root.accept(aVisitor) if root
|
42
|
+
|
43
|
+
aVisitor.end_visit_pforest(self)
|
44
|
+
end
|
45
|
+
end # class
|
46
|
+
end # module
|
47
|
+
end # module
|
48
|
+
# End of file
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require_relative '../ptree/token_range'
|
2
|
+
|
3
|
+
module Rley # This module is used as a namespace
|
4
|
+
module SPPF # This module is used as a namespace
|
5
|
+
# Abstract class. The generalization for all kinds of nodes
|
6
|
+
# occurring in a shared packed parse forest.
|
7
|
+
class SPPFNode
|
8
|
+
|
9
|
+
# A range of indices for tokens matching this node.
|
10
|
+
attr_reader(:range)
|
11
|
+
|
12
|
+
def initialize(aRange)
|
13
|
+
@range = PTree::TokenRange.new(aRange)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Return the origin (= lower bound of the range
|
17
|
+
# = position of first token matched by the symbol)
|
18
|
+
def origin()
|
19
|
+
return range.low
|
20
|
+
end
|
21
|
+
end # class
|
22
|
+
end # module
|
23
|
+
end # module
|
24
|
+
# End of file
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require_relative 'leaf_node'
|
2
|
+
|
3
|
+
module Rley # This module is used as a namespace
|
4
|
+
module SPPF # This module is used as a namespace
|
5
|
+
# A node in a parse forest that matches exactly one
|
6
|
+
# token from the input
|
7
|
+
class TokenNode < LeafNode
|
8
|
+
attr_reader(:token)
|
9
|
+
|
10
|
+
# aPosition is the position of the token in the input stream.
|
11
|
+
def initialize(aToken, aPosition)
|
12
|
+
range = {low: aPosition, high: aPosition + 1}
|
13
|
+
super(range)
|
14
|
+
@token = aToken
|
15
|
+
end
|
16
|
+
|
17
|
+
# Emit a (formatted) string representation of the node.
|
18
|
+
# Mainly used for diagnosis/debugging purposes.
|
19
|
+
def to_string(indentation)
|
20
|
+
return "#{token.terminal.name}#{range.to_string(indentation)}"
|
21
|
+
end
|
22
|
+
|
23
|
+
def key()
|
24
|
+
@key ||= to_string(0)
|
25
|
+
end
|
26
|
+
end # class
|
27
|
+
end # module
|
28
|
+
end # module
|
29
|
+
# End of file
|
@@ -67,21 +67,25 @@ module Rley # This module is used as a namespace
|
|
67
67
|
end
|
68
68
|
|
69
69
|
# Given the grammar symbols and productions added to the builder,
|
70
|
-
# build the resulting grammar.
|
70
|
+
# build the resulting grammar (if not yet done).
|
71
71
|
def grammar()
|
72
|
-
|
73
|
-
|
74
|
-
|
72
|
+
unless @grammar
|
73
|
+
fail StandardError, 'No symbol found for grammar' if symbols.empty?
|
74
|
+
if productions.empty?
|
75
|
+
fail StandardError, 'No production found for grammar'
|
76
|
+
end
|
77
|
+
|
78
|
+
# Check that each non-terminal appears at least once in lhs.
|
79
|
+
all_non_terminals = symbols.values.select { |s| s.is_a?(NonTerminal) }
|
80
|
+
all_non_terminals.each do |n_term|
|
81
|
+
next if productions.any? { |prod| n_term == prod.lhs }
|
82
|
+
fail StandardError, "Nonterminal #{n_term.name} not rewritten"
|
83
|
+
end
|
84
|
+
|
85
|
+
@grammar = Grammar.new(productions.dup)
|
75
86
|
end
|
76
87
|
|
77
|
-
|
78
|
-
all_non_terminals = symbols.values.select { |s| s.is_a?(NonTerminal) }
|
79
|
-
all_non_terminals.each do |n_term|
|
80
|
-
next if productions.any? { |prod| n_term == prod.lhs }
|
81
|
-
fail StandardError, "Nonterminal #{n_term.name} not rewritten"
|
82
|
-
end
|
83
|
-
|
84
|
-
return Grammar.new(productions.dup)
|
88
|
+
return @grammar
|
85
89
|
end
|
86
90
|
|
87
91
|
private
|
@@ -12,6 +12,12 @@ module Rley # This module is used as a namespace
|
|
12
12
|
@name = aName.dup
|
13
13
|
end
|
14
14
|
|
15
|
+
# Return true iff the symbol is a terminal
|
16
|
+
def terminal?()
|
17
|
+
# Default implementation to override if necessary
|
18
|
+
return false
|
19
|
+
end
|
20
|
+
|
15
21
|
# The String representation of the grammar symbol
|
16
22
|
# @return [String]
|
17
23
|
def to_s()
|
data/lib/rley/syntax/terminal.rb
CHANGED
@@ -12,6 +12,11 @@ module Rley # This module is used as a namespace
|
|
12
12
|
super(aName)
|
13
13
|
end
|
14
14
|
|
15
|
+
# Return true iff the symbol is a terminal
|
16
|
+
def terminal?()
|
17
|
+
return true
|
18
|
+
end
|
19
|
+
|
15
20
|
# @return [false] Return true if the symbol derives
|
16
21
|
# the empty string. As terminal symbol corresponds to a input token
|
17
22
|
# it is by definition non-nullable.
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
|
3
|
+
require_relative '../../../lib/rley/syntax/terminal'
|
4
|
+
require_relative '../../../lib/rley/syntax/non_terminal'
|
5
|
+
require_relative '../../../lib/rley/syntax/production'
|
6
|
+
require_relative '../../../lib/rley/parser/dotted_item'
|
7
|
+
require_relative '../../../lib/rley/gfg/start_vertex'
|
8
|
+
require_relative '../../../lib/rley/gfg/item_vertex'
|
9
|
+
|
10
|
+
# Load the class under test
|
11
|
+
require_relative '../../../lib/rley/gfg/call_edge'
|
12
|
+
|
13
|
+
module Rley # Open this namespace to avoid module qualifier prefixes
|
14
|
+
module GFG # Open this namespace to avoid module qualifier prefixes
|
15
|
+
describe CallEdge do
|
16
|
+
# Factory method. Builds a production with given left-hand side (LHS)
|
17
|
+
# and given RHS (right-hand side)
|
18
|
+
def build_prod(theLHS, *theRHSSymbols)
|
19
|
+
return Syntax::Production.new(theLHS, theRHSSymbols)
|
20
|
+
end
|
21
|
+
|
22
|
+
let(:t_a) { Rley::Syntax::Terminal.new('a') }
|
23
|
+
let(:t_b) { Rley::Syntax::Terminal.new('b') }
|
24
|
+
let(:t_c) { Rley::Syntax::Terminal.new('c') }
|
25
|
+
let(:nt_sentence) { Rley::Syntax::NonTerminal.new('sentence') }
|
26
|
+
let(:nt_b_sequence) { Rley::Syntax::NonTerminal.new('b_sequence') }
|
27
|
+
let(:sample_prod) { build_prod(nt_sentence, t_a, nt_b_sequence, t_c) }
|
28
|
+
let(:sample_item) { Parser::DottedItem.new(sample_prod, 1) }
|
29
|
+
|
30
|
+
let(:vertex1) { ItemVertex.new(sample_item) }
|
31
|
+
let(:vertex2) { StartVertex.new('to') }
|
32
|
+
subject { CallEdge.new(vertex1, vertex2) }
|
33
|
+
|
34
|
+
context 'Initialization:' do
|
35
|
+
it 'should be created with two vertice arguments' do
|
36
|
+
expect { CallEdge.new(vertex1, vertex2) }.not_to raise_error
|
37
|
+
end
|
38
|
+
end # context
|
39
|
+
|
40
|
+
|
41
|
+
context 'Provided services:' do
|
42
|
+
it 'should know its key' do
|
43
|
+
expectation = "CALL_#{sample_prod.object_id}_#{sample_item.position}"
|
44
|
+
expect(subject.key).to eq(expectation)
|
45
|
+
end
|
46
|
+
end # context
|
47
|
+
end # describe
|
48
|
+
end # module
|
49
|
+
end # module
|
50
|
+
|
51
|
+
# End of file
|
@@ -1,5 +1,4 @@
|
|
1
1
|
require_relative '../../spec_helper'
|
2
|
-
require 'pp'
|
3
2
|
|
4
3
|
require_relative '../support/grammar_abc_helper'
|
5
4
|
require_relative '../../../lib/rley/parser/grm_items_builder'
|
@@ -53,6 +52,10 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
53
52
|
expect { GrmFlowGraph.new(items_from_grammar) }.not_to raise_error
|
54
53
|
end
|
55
54
|
|
55
|
+
it 'should know its main start vertex' do
|
56
|
+
expect(subject.start_vertex).to eq(subject.vertices.first)
|
57
|
+
end
|
58
|
+
|
56
59
|
it 'should have the correct number of vertices' do
|
57
60
|
# Number of vertices = count of dotted items +...
|
58
61
|
# ... 2 * count of non-terminals
|
@@ -128,9 +131,28 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
128
131
|
'A => a . --> A.',
|
129
132
|
'A => . --> A.'
|
130
133
|
]
|
131
|
-
|
134
|
+
|
132
135
|
compare_graph_expectations(graph, expected)
|
133
136
|
end
|
137
|
+
|
138
|
+
it 'should have shortcut edges' do
|
139
|
+
subject.vertices.each do |a_vertex|
|
140
|
+
next unless a_vertex.kind_of?(ItemVertex)
|
141
|
+
if a_vertex.next_symbol.kind_of?(Syntax::NonTerminal)
|
142
|
+
expect(a_vertex.shortcut).not_to be_nil
|
143
|
+
my_d_item = a_vertex.dotted_item
|
144
|
+
|
145
|
+
# Retrieve dotted item of shortcut successor
|
146
|
+
other_d_item = a_vertex.shortcut.successor.dotted_item
|
147
|
+
|
148
|
+
# Now the checks...
|
149
|
+
expect(my_d_item.production).to eq(other_d_item.production)
|
150
|
+
expect(my_d_item.position).to eq(other_d_item.prev_position)
|
151
|
+
else
|
152
|
+
expect(a_vertex.shortcut).to be_nil
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
134
156
|
end # context
|
135
157
|
end # describe
|
136
158
|
end # module
|
@@ -3,6 +3,7 @@ require_relative '../../../lib/rley/syntax/terminal'
|
|
3
3
|
require_relative '../../../lib/rley/syntax/non_terminal'
|
4
4
|
require_relative '../../../lib/rley/syntax/production'
|
5
5
|
require_relative '../../../lib/rley/parser/dotted_item'
|
6
|
+
require_relative '../../../lib/rley/gfg/shortcut_edge'
|
6
7
|
|
7
8
|
# Load the class under test
|
8
9
|
require_relative '../../../lib/rley/gfg/item_vertex'
|
@@ -10,20 +11,25 @@ require_relative '../../../lib/rley/gfg/item_vertex'
|
|
10
11
|
module Rley # Open this namespace to avoid module qualifier prefixes
|
11
12
|
module GFG # Open this namespace to avoid module qualifier prefixes
|
12
13
|
describe ItemVertex do
|
14
|
+
|
13
15
|
# Factory method. Builds a production with given left-hand side (LHS)
|
14
16
|
# and given RHS (right-hand side)
|
15
17
|
def build_prod(theLHS, *theRHSSymbols)
|
16
18
|
return Syntax::Production.new(theLHS, theRHSSymbols)
|
17
19
|
end
|
18
20
|
|
19
|
-
let(:t_a) { Rley::Syntax::Terminal.new('
|
20
|
-
let(:t_b) { Rley::Syntax::Terminal.new('
|
21
|
-
let(:t_c) { Rley::Syntax::Terminal.new('
|
21
|
+
let(:t_a) { Rley::Syntax::Terminal.new('a') }
|
22
|
+
let(:t_b) { Rley::Syntax::Terminal.new('b') }
|
23
|
+
let(:t_c) { Rley::Syntax::Terminal.new('c') }
|
22
24
|
let(:nt_sentence) { Rley::Syntax::NonTerminal.new('sentence') }
|
23
|
-
let(:
|
25
|
+
let(:nt_b_sequence) { Rley::Syntax::NonTerminal.new('b_sequence') }
|
26
|
+
let(:sample_prod) { build_prod(nt_sentence, t_a, nt_b_sequence, t_c) }
|
24
27
|
let(:other_prod) { build_prod(nt_sentence, t_a) }
|
28
|
+
let(:recursive_prod) {build_prod(nt_b_sequence, nt_b_sequence, t_b )}
|
29
|
+
let(:b_prod) {build_prod(nt_b_sequence, t_b )}
|
25
30
|
let(:empty_prod) { build_prod(nt_sentence) }
|
26
31
|
let(:sample_item) { Parser::DottedItem.new(sample_prod, 1) }
|
32
|
+
let(:next_item) { Parser::DottedItem.new(sample_prod, 2) }
|
27
33
|
subject { ItemVertex.new(sample_item) }
|
28
34
|
|
29
35
|
context 'Initialization:' do
|
@@ -34,15 +40,78 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
34
40
|
it 'should know its dotted item' do
|
35
41
|
expect(subject.dotted_item).to eq(sample_item)
|
36
42
|
end
|
43
|
+
|
44
|
+
it 'should not have any shortcut edge at start' do
|
45
|
+
expect(subject.shortcut).to be_nil
|
46
|
+
end
|
37
47
|
end # context
|
38
|
-
|
48
|
+
|
39
49
|
context 'Provided services:' do
|
40
50
|
it 'should know its label' do
|
41
51
|
expect(subject.label).to eq(sample_item.to_s)
|
42
52
|
end
|
53
|
+
|
54
|
+
it 'should know the lhs of the production' do
|
55
|
+
expect(subject.lhs).to eq(nt_sentence)
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'should know whether it has a dot at the end of the rhs' do
|
59
|
+
# Case: dot not at the end
|
60
|
+
expect(subject).not_to be_complete
|
61
|
+
|
62
|
+
# Case: dot at the end
|
63
|
+
instance1 = ItemVertex.new(Parser::DottedItem.new(sample_prod, 3))
|
64
|
+
expect(instance1).to be_complete
|
65
|
+
|
66
|
+
# Case: empty production
|
67
|
+
instance2 = ItemVertex.new(Parser::DottedItem.new(empty_prod, 0))
|
68
|
+
expect(instance2).to be_complete
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'should know the previous symbol (if any) in the rhs' do
|
72
|
+
# Case: dot is after first symbol
|
73
|
+
instance1 = ItemVertex.new(sample_item)
|
74
|
+
expect(instance1.prev_symbol).to eq(t_a)
|
75
|
+
|
76
|
+
# Case: dot is after second or later symbol
|
77
|
+
instance2 = ItemVertex.new(next_item)
|
78
|
+
expect(instance2.prev_symbol).to eq(nt_b_sequence)
|
79
|
+
|
80
|
+
# Case: dot is at begin
|
81
|
+
instance3 = ItemVertex.new(Parser::DottedItem.new(sample_prod, 0))
|
82
|
+
expect(instance3.prev_symbol).to be_nil
|
83
|
+
|
84
|
+
# Case: empty production
|
85
|
+
instance4 = ItemVertex.new(Parser::DottedItem.new(empty_prod, 0))
|
86
|
+
expect(instance4.prev_symbol).to be_nil
|
87
|
+
end
|
43
88
|
|
44
89
|
|
45
|
-
|
90
|
+
it 'should know the next symbol (if any) in the rhs' do
|
91
|
+
#Case: dot is not penultimate
|
92
|
+
expect(subject.next_symbol).to eq(nt_b_sequence)
|
93
|
+
|
94
|
+
# Case: dot is penultimate
|
95
|
+
instance1 = ItemVertex.new(next_item)
|
96
|
+
expect(instance1.next_symbol).to eq(t_c)
|
97
|
+
|
98
|
+
# Case: dot is at end
|
99
|
+
instance2 = ItemVertex.new(Parser::DottedItem.new(sample_prod, 3))
|
100
|
+
expect(instance2.next_symbol).to be_nil
|
101
|
+
|
102
|
+
# Case: empty production
|
103
|
+
instance3 = ItemVertex.new(Parser::DottedItem.new(empty_prod, 0))
|
104
|
+
expect(instance3.next_symbol).to be_nil
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'should accept a shortcut edge' do
|
108
|
+
next_vertex = ItemVertex.new(next_item)
|
109
|
+
|
110
|
+
# The ShortcutEdge constructor invokes the shortcut setter
|
111
|
+
shortcut = ShortcutEdge.new(subject, next_vertex)
|
112
|
+
expect(subject.shortcut).to eq(shortcut)
|
113
|
+
end
|
114
|
+
end # context
|
46
115
|
end # describe
|
47
116
|
end # module
|
48
117
|
end # module
|
@@ -17,6 +17,20 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
17
17
|
it 'should know its non-terminal' do
|
18
18
|
expect(subject.non_terminal).to eq(sample_nt)
|
19
19
|
end
|
20
|
+
|
21
|
+
|
22
|
+
it 'should accept at more than one outgoing edge' 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
|
+
|
30
|
+
expect { subject.add_edge(edge2) }.not_to raise_error
|
31
|
+
expect(subject.edges.size).to eq(2)
|
32
|
+
expect(subject.edges.last).to eq(edge2)
|
33
|
+
end
|
20
34
|
end # context
|
21
35
|
end # describe
|
22
36
|
end # module
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
|
3
|
+
require_relative '../../../lib/rley/syntax/terminal'
|
4
|
+
require_relative '../../../lib/rley/syntax/non_terminal'
|
5
|
+
require_relative '../../../lib/rley/syntax/production'
|
6
|
+
require_relative '../../../lib/rley/parser/dotted_item'
|
7
|
+
require_relative '../../../lib/rley/gfg/end_vertex'
|
8
|
+
require_relative '../../../lib/rley/gfg/item_vertex'
|
9
|
+
|
10
|
+
# Load the class under test
|
11
|
+
require_relative '../../../lib/rley/gfg/return_edge'
|
12
|
+
|
13
|
+
module Rley # Open this namespace to avoid module qualifier prefixes
|
14
|
+
module GFG # Open this namespace to avoid module qualifier prefixes
|
15
|
+
describe ReturnEdge do
|
16
|
+
# Factory method. Builds a production with given left-hand side (LHS)
|
17
|
+
# and given RHS (right-hand side)
|
18
|
+
def build_prod(theLHS, *theRHSSymbols)
|
19
|
+
return Syntax::Production.new(theLHS, theRHSSymbols)
|
20
|
+
end
|
21
|
+
|
22
|
+
let(:t_a) { Rley::Syntax::Terminal.new('a') }
|
23
|
+
let(:t_b) { Rley::Syntax::Terminal.new('b') }
|
24
|
+
let(:t_c) { Rley::Syntax::Terminal.new('c') }
|
25
|
+
let(:nt_sentence) { Rley::Syntax::NonTerminal.new('sentence') }
|
26
|
+
let(:nt_b_sequence) { Rley::Syntax::NonTerminal.new('b_sequence') }
|
27
|
+
let(:sample_prod) { build_prod(nt_sentence, t_a, nt_b_sequence, t_c) }
|
28
|
+
let(:sample_item) { Parser::DottedItem.new(sample_prod, 1) }
|
29
|
+
|
30
|
+
let(:vertex1) { EndVertex.new('from') }
|
31
|
+
let(:vertex2) { ItemVertex.new(sample_item) }
|
32
|
+
subject { ReturnEdge.new(vertex1, vertex2) }
|
33
|
+
|
34
|
+
context 'Initialization:' do
|
35
|
+
it 'should be created with two vertice arguments' do
|
36
|
+
expect { ReturnEdge.new(vertex1, vertex2) }.not_to raise_error
|
37
|
+
end
|
38
|
+
end # context
|
39
|
+
|
40
|
+
|
41
|
+
context 'Provided services:' do
|
42
|
+
it 'should know its key' do
|
43
|
+
expectation = "RET_#{sample_prod.object_id}_#{sample_item.position - 1}"
|
44
|
+
expect(subject.key).to eq(expectation)
|
45
|
+
end
|
46
|
+
end # context
|
47
|
+
end # describe
|
48
|
+
end # module
|
49
|
+
end # module
|
50
|
+
|
51
|
+
# End of file
|