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