rley 0.8.14 → 0.8.15
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/.rubocop.yml +20 -2
- data/CHANGELOG.md +3 -0
- data/examples/general/calc_iter1/spec/calculator_spec.rb +9 -9
- data/examples/general/calc_iter2/spec/calculator_spec.rb +39 -39
- data/examples/general/recursive_right.rb +2 -2
- data/lib/rley/constants.rb +1 -1
- data/lib/rley/gfg/grm_flow_graph.rb +0 -1
- data/lib/rley/parser/parse_entry_set.rb +0 -1
- data/lib/rley/parser/parse_walker_factory.rb +0 -1
- data/lib/rley/rgn/grammar_builder.rb +0 -2
- data/lib/rley/rgn/tokenizer.rb +1 -1
- data/lib/rley/syntax/base_grammar_builder.rb +0 -1
- data/lib/rley/syntax/grammar.rb +0 -1
- data/spec/rley/base/dotted_item_spec.rb +46 -46
- data/spec/rley/base/grm_items_builder_spec.rb +1 -1
- data/spec/rley/engine_spec.rb +50 -50
- data/spec/rley/formatter/asciitree_spec.rb +8 -8
- data/spec/rley/formatter/bracket_notation_spec.rb +10 -10
- data/spec/rley/formatter/debug_spec.rb +10 -10
- data/spec/rley/formatter/json_spec.rb +6 -7
- data/spec/rley/gfg/call_edge_spec.rb +6 -6
- data/spec/rley/gfg/edge_spec.rb +8 -7
- data/spec/rley/gfg/end_vertex_spec.rb +8 -7
- data/spec/rley/gfg/epsilon_edge_spec.rb +5 -4
- data/spec/rley/gfg/grm_flow_graph_spec.rb +33 -34
- data/spec/rley/gfg/item_vertex_spec.rb +34 -36
- data/spec/rley/gfg/non_terminal_vertex_spec.rb +12 -12
- data/spec/rley/gfg/return_edge_spec.rb +6 -6
- data/spec/rley/gfg/scan_edge_spec.rb +7 -6
- data/spec/rley/gfg/shortcut_edge_spec.rb +15 -15
- data/spec/rley/gfg/start_vertex_spec.rb +8 -8
- data/spec/rley/gfg/vertex_spec.rb +18 -18
- data/spec/rley/lexical/literal_spec.rb +5 -5
- data/spec/rley/lexical/token_range_spec.rb +55 -55
- data/spec/rley/lexical/token_spec.rb +17 -16
- data/spec/rley/parse_forest_visitor_spec.rb +30 -32
- data/spec/rley/parse_rep/ambiguous_parse_spec.rb +2 -2
- data/spec/rley/parse_rep/ast_builder_spec.rb +30 -30
- data/spec/rley/parse_rep/cst_builder_spec.rb +85 -85
- data/spec/rley/parse_rep/groucho_spec.rb +23 -23
- data/spec/rley/parse_rep/parse_forest_builder_spec.rb +42 -42
- data/spec/rley/parse_rep/parse_forest_factory_spec.rb +10 -12
- data/spec/rley/parse_rep/parse_tree_factory_spec.rb +10 -15
- data/spec/rley/parse_tree_visitor_spec.rb +43 -46
- data/spec/rley/parser/dangling_else_spec.rb +12 -12
- data/spec/rley/parser/error_reason_spec.rb +37 -37
- data/spec/rley/parser/gfg_chart_spec.rb +27 -29
- data/spec/rley/parser/gfg_earley_parser_spec.rb +55 -56
- data/spec/rley/parser/gfg_parsing_spec.rb +106 -103
- data/spec/rley/parser/parse_entry_set_spec.rb +63 -61
- data/spec/rley/parser/parse_entry_spec.rb +73 -71
- data/spec/rley/parser/parse_walker_factory_spec.rb +14 -15
- data/spec/rley/ptree/non_terminal_node_spec.rb +16 -16
- data/spec/rley/ptree/parse_tree_node_spec.rb +11 -11
- data/spec/rley/ptree/parse_tree_spec.rb +6 -8
- data/spec/rley/ptree/terminal_node_spec.rb +6 -6
- data/spec/rley/rgn/grammar_builder_spec.rb +69 -67
- data/spec/rley/rgn/parser_spec.rb +63 -63
- data/spec/rley/rgn/repetition_node_spec.rb +15 -15
- data/spec/rley/rgn/sequence_node_spec.rb +10 -10
- data/spec/rley/rgn/symbol_node_spec.rb +5 -6
- data/spec/rley/rgn/tokenizer_spec.rb +68 -67
- data/spec/rley/sppf/alternative_node_spec.rb +16 -16
- data/spec/rley/sppf/non_terminal_node_spec.rb +20 -20
- data/spec/rley/sppf/token_node_spec.rb +13 -13
- data/spec/rley/syntax/base_grammar_builder_spec.rb +76 -86
- data/spec/rley/syntax/grammar_spec.rb +40 -78
- data/spec/rley/syntax/grm_symbol_spec.rb +7 -7
- data/spec/rley/syntax/match_closest_spec.rb +8 -8
- data/spec/rley/syntax/non_terminal_spec.rb +25 -25
- data/spec/rley/syntax/production_spec.rb +33 -33
- data/spec/rley/syntax/symbol_seq_spec.rb +27 -27
- data/spec/rley/syntax/terminal_spec.rb +12 -11
- data/spec/support/base_tokenizer_spec.rb +9 -8
- metadata +2 -2
data/spec/rley/engine_spec.rb
CHANGED
@@ -11,37 +11,37 @@ require_relative '../../lib/rley/engine'
|
|
11
11
|
|
12
12
|
module Rley # Open this namespace to avoid module qualifier prefixes
|
13
13
|
describe Engine do
|
14
|
-
subject {
|
14
|
+
subject(:an_engine) { described_class.new }
|
15
15
|
|
16
16
|
context 'Creation and initialization:' do
|
17
|
-
it '
|
18
|
-
expect {
|
17
|
+
it 'is created without argument' do
|
18
|
+
expect { described_class.new }.not_to raise_error
|
19
19
|
end
|
20
20
|
|
21
|
-
it '
|
21
|
+
it 'is created with block argument' do
|
22
22
|
expect do
|
23
|
-
|
23
|
+
described_class.new do |config|
|
24
24
|
config.parse_repr = :raw
|
25
25
|
end
|
26
26
|
end.not_to raise_error
|
27
27
|
end
|
28
28
|
|
29
|
-
it "
|
30
|
-
expect(
|
29
|
+
it "doesn't have a link to a grammar yet" do
|
30
|
+
expect(an_engine.grammar).to be_nil
|
31
31
|
end
|
32
32
|
end # context
|
33
33
|
|
34
34
|
context 'Grammar building:' do
|
35
|
-
it '
|
36
|
-
|
35
|
+
it 'builds grammar' do
|
36
|
+
an_engine.build_grammar do
|
37
37
|
add_terminals('a', 'b', 'c')
|
38
38
|
add_production('S' => 'A')
|
39
39
|
add_production('A' => 'a A c')
|
40
40
|
add_production('A' => 'b')
|
41
41
|
end
|
42
42
|
|
43
|
-
expect(
|
44
|
-
expect(
|
43
|
+
expect(an_engine.grammar).to be_a(Rley::Syntax::Grammar)
|
44
|
+
expect(an_engine.grammar.rules.size).to eq(3)
|
45
45
|
end
|
46
46
|
end # context
|
47
47
|
|
@@ -78,34 +78,34 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
78
78
|
end
|
79
79
|
|
80
80
|
context 'Parsing:' do
|
81
|
-
subject do
|
82
|
-
instance =
|
81
|
+
subject(:an_engine) do
|
82
|
+
instance = described_class.new
|
83
83
|
add_sample_grammar(instance)
|
84
84
|
instance
|
85
85
|
end
|
86
86
|
|
87
|
-
it '
|
87
|
+
it 'parses a stream of tokens' do
|
88
88
|
sample_text = 'a a b c c'
|
89
89
|
tokenizer = ABCTokenizer.new(sample_text)
|
90
|
-
result =
|
90
|
+
result = an_engine.parse(tokenizer)
|
91
91
|
expect(result).to be_success
|
92
92
|
end
|
93
93
|
end # context
|
94
94
|
|
95
95
|
context 'Parse tree manipulation:' do
|
96
|
-
subject do
|
97
|
-
instance = Engine.new
|
98
|
-
add_sample_grammar(instance)
|
99
|
-
instance
|
100
|
-
end
|
101
|
-
|
102
96
|
let(:sample_tokenizer) do
|
103
97
|
sample_text = 'a a b c c'
|
104
98
|
ABCTokenizer.new(sample_text)
|
105
99
|
end
|
106
100
|
|
107
|
-
|
108
|
-
instance =
|
101
|
+
subject(:an_engine) do
|
102
|
+
instance = described_class.new
|
103
|
+
add_sample_grammar(instance)
|
104
|
+
instance
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'builds a parse tree even for a nullable production' do
|
108
|
+
instance = described_class.new
|
109
109
|
instance.build_grammar do
|
110
110
|
add_terminals('a', 'b', 'c')
|
111
111
|
add_production 'S' => 'A BC'
|
@@ -121,31 +121,31 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
121
121
|
expect { instance.to_ptree(raw_result) }.not_to raise_error
|
122
122
|
end
|
123
123
|
|
124
|
-
it '
|
125
|
-
raw_result =
|
126
|
-
ptree =
|
127
|
-
expect(ptree).to
|
124
|
+
it 'builds default parse trees' do
|
125
|
+
raw_result = an_engine.parse(sample_tokenizer)
|
126
|
+
ptree = an_engine.convert(raw_result)
|
127
|
+
expect(ptree).to be_a(PTree::ParseTree)
|
128
128
|
end
|
129
129
|
|
130
|
-
it '
|
130
|
+
it 'builds custom parse trees' do
|
131
131
|
# Cheating: we point to default tree builder (CST)
|
132
|
-
|
133
|
-
raw_result =
|
134
|
-
ptree =
|
135
|
-
expect(ptree).to
|
132
|
+
an_engine.configuration.repr_builder = ParseRep::CSTBuilder
|
133
|
+
raw_result = an_engine.parse(sample_tokenizer)
|
134
|
+
ptree = an_engine.convert(raw_result)
|
135
|
+
expect(ptree).to be_a(PTree::ParseTree)
|
136
136
|
end
|
137
137
|
|
138
|
-
it '
|
139
|
-
raw_result =
|
140
|
-
ptree =
|
141
|
-
visitor =
|
142
|
-
expect(visitor).to
|
138
|
+
it 'provides a parse visitor' do
|
139
|
+
raw_result = an_engine.parse(sample_tokenizer)
|
140
|
+
ptree = an_engine.to_ptree(raw_result)
|
141
|
+
visitor = an_engine.ptree_visitor(ptree)
|
142
|
+
expect(visitor).to be_a(ParseTreeVisitor)
|
143
143
|
end
|
144
144
|
end # context
|
145
145
|
|
146
146
|
context 'Parse forest manipulation:' do
|
147
|
-
subject do
|
148
|
-
instance =
|
147
|
+
subject(:an_engine) do
|
148
|
+
instance = described_class.new
|
149
149
|
add_sample_grammar(instance)
|
150
150
|
instance
|
151
151
|
end
|
@@ -155,8 +155,8 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
155
155
|
ABCTokenizer.new(sample_text)
|
156
156
|
end
|
157
157
|
|
158
|
-
it '
|
159
|
-
instance =
|
158
|
+
it 'builds a parse forest even for a nullable production' do
|
159
|
+
instance = described_class.new
|
160
160
|
instance.build_grammar do
|
161
161
|
add_terminals('a', 'b', 'c')
|
162
162
|
add_production 'S' => 'A BC'
|
@@ -172,17 +172,17 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
172
172
|
expect { instance.to_pforest(raw_result) }.not_to raise_error
|
173
173
|
end
|
174
174
|
|
175
|
-
it '
|
176
|
-
raw_result =
|
177
|
-
pforest =
|
178
|
-
expect(pforest).to
|
175
|
+
it 'builds parse forest' do
|
176
|
+
raw_result = an_engine.parse(sample_tokenizer)
|
177
|
+
pforest = an_engine.to_pforest(raw_result)
|
178
|
+
expect(pforest).to be_a(SPPF::ParseForest)
|
179
179
|
end
|
180
180
|
|
181
|
-
it '
|
182
|
-
raw_result =
|
183
|
-
ptree =
|
184
|
-
visitor =
|
185
|
-
expect(visitor).to
|
181
|
+
it 'provides a parse visitor' do
|
182
|
+
raw_result = an_engine.parse(sample_tokenizer)
|
183
|
+
ptree = an_engine.to_pforest(raw_result)
|
184
|
+
visitor = an_engine.pforest_visitor(ptree)
|
185
|
+
expect(visitor).to be_a(ParseForestVisitor)
|
186
186
|
end
|
187
187
|
end # context
|
188
188
|
end # describe
|
@@ -15,6 +15,8 @@ require_relative '../../../lib/rley/formatter/asciitree'
|
|
15
15
|
module Rley # Re-open the module to get rid of qualified names
|
16
16
|
module Formatter
|
17
17
|
describe Asciitree do
|
18
|
+
subject(:a_formatter) { described_class.new(destination) }
|
19
|
+
|
18
20
|
# Factory method. Build a production with the given sequence
|
19
21
|
# of symbols as its rhs.
|
20
22
|
let(:grammar_abc) do
|
@@ -55,25 +57,23 @@ module Rley # Re-open the module to get rid of qualified names
|
|
55
57
|
ptree = engine.convert(parse_result)
|
56
58
|
ptree
|
57
59
|
end
|
58
|
-
|
59
60
|
let(:destination) { StringIO.new(+'', 'w') }
|
60
|
-
subject { Asciitree.new(destination) }
|
61
61
|
|
62
62
|
context 'Standard creation & initialization:' do
|
63
|
-
it '
|
64
|
-
expect {
|
63
|
+
it 'is initialized with an IO argument' do
|
64
|
+
expect { described_class.new(StringIO.new(+'', 'w')) }.not_to raise_error
|
65
65
|
end
|
66
66
|
|
67
|
-
it '
|
68
|
-
expect(
|
67
|
+
it 'knows its output destination' do
|
68
|
+
expect(a_formatter.output).to eq(destination)
|
69
69
|
end
|
70
70
|
end # context
|
71
71
|
|
72
72
|
|
73
73
|
context 'Rendering:' do
|
74
|
-
it '
|
74
|
+
it 'renders a parse tree' do
|
75
75
|
visitor = Rley::ParseTreeVisitor.new(grm_abc_ptree1)
|
76
|
-
|
76
|
+
a_formatter.render(visitor)
|
77
77
|
expectations = <<-SNIPPET
|
78
78
|
S
|
79
79
|
+-- A
|
@@ -15,6 +15,8 @@ require_relative '../../../lib/rley/formatter/bracket_notation'
|
|
15
15
|
module Rley # Re-open the module to get rid of qualified names
|
16
16
|
module Formatter
|
17
17
|
describe BracketNotation do
|
18
|
+
subject(:a_formatter) { described_class.new(destination) }
|
19
|
+
|
18
20
|
# Factory method. Build a production with the given sequence
|
19
21
|
# of symbols as its rhs.
|
20
22
|
let(:grammar_abc) do
|
@@ -57,36 +59,34 @@ module Rley # Re-open the module to get rid of qualified names
|
|
57
59
|
end
|
58
60
|
|
59
61
|
let(:destination) { StringIO.new(+'', 'w') }
|
60
|
-
subject { BracketNotation.new(destination) }
|
61
62
|
|
62
63
|
context 'Standard creation & initialization:' do
|
63
|
-
it '
|
64
|
+
it 'is initialized with an IO argument' do
|
64
65
|
expect do
|
65
|
-
|
66
|
+
described_class.new(StringIO.new(+'', 'w'))
|
66
67
|
end.not_to raise_error
|
67
68
|
end
|
68
69
|
|
69
|
-
it '
|
70
|
-
expect(
|
70
|
+
it 'knows its output destination' do
|
71
|
+
expect(a_formatter.output).to eq(destination)
|
71
72
|
end
|
72
73
|
end # context
|
73
74
|
|
74
|
-
|
75
75
|
context 'Formatting events:' do
|
76
|
-
it '
|
76
|
+
it 'supports visit events of a parse tree' do
|
77
77
|
visitor = Rley::ParseTreeVisitor.new(grm_abc_ptree1)
|
78
|
-
|
78
|
+
a_formatter.render(visitor)
|
79
79
|
expectations = '[S [A [a a][A [a a][A [b b]][c c]][c c]]]'
|
80
80
|
expect(destination.string).to eq(expectations)
|
81
81
|
end
|
82
82
|
|
83
|
-
it '
|
83
|
+
it 'escapes square brackets' do
|
84
84
|
f_node = double('fake-node')
|
85
85
|
f_token = double('fake-token')
|
86
86
|
expect(f_node).to receive(:token).and_return(f_token)
|
87
87
|
expect(f_token).to receive(:lexeme).and_return('[][]')
|
88
88
|
|
89
|
-
|
89
|
+
a_formatter.after_terminal(f_node)
|
90
90
|
expectations = '\[\]\[\]]'
|
91
91
|
expect(destination.string).to eq(expectations)
|
92
92
|
end
|
@@ -79,24 +79,24 @@ module Rley # Re-open the module to get rid of qualified names
|
|
79
79
|
let(:destination) { StringIO.new(+'', 'w') }
|
80
80
|
|
81
81
|
context 'Standard creation & initialization:' do
|
82
|
-
it '
|
83
|
-
expect {
|
82
|
+
it 'is initialized with an IO argument' do
|
83
|
+
expect { described_class.new(StringIO.new(+'', 'w')) }.not_to raise_error
|
84
84
|
end
|
85
85
|
|
86
|
-
it '
|
87
|
-
instance =
|
86
|
+
it 'knows its output destination' do
|
87
|
+
instance = described_class.new(destination)
|
88
88
|
expect(instance.output).to eq(destination)
|
89
89
|
end
|
90
90
|
|
91
|
-
it '
|
92
|
-
instance =
|
91
|
+
it 'has a zero indentation' do
|
92
|
+
instance = described_class.new(destination)
|
93
93
|
expect(instance.indentation).to be_zero
|
94
94
|
end
|
95
95
|
end # context
|
96
96
|
|
97
97
|
context 'Formatting events:' do
|
98
|
-
it '
|
99
|
-
instance =
|
98
|
+
it 'supports visit events of a parse tree' do
|
99
|
+
instance = described_class.new(destination)
|
100
100
|
expect(instance.output).to eq(destination)
|
101
101
|
visitor = Rley::ParseTreeVisitor.new(grm_abc_ptree1)
|
102
102
|
instance.render(visitor)
|
@@ -133,8 +133,8 @@ SNIPPET
|
|
133
133
|
expect(destination.string).to eq(expectations)
|
134
134
|
end
|
135
135
|
|
136
|
-
it '
|
137
|
-
instance =
|
136
|
+
it 'supports visit events of a parse forest' do
|
137
|
+
instance = described_class.new(destination)
|
138
138
|
expect(instance.output).to eq(destination)
|
139
139
|
visitor = Rley::ParseForestVisitor.new(grm_sppf_pforest1)
|
140
140
|
instance.render(visitor)
|
@@ -54,24 +54,23 @@ module Rley # Re-open the module to get rid of qualified names
|
|
54
54
|
ptree = engine.convert(parse_result)
|
55
55
|
ptree
|
56
56
|
end
|
57
|
-
|
58
57
|
let(:destination) { StringIO.new(+'', 'w') }
|
59
58
|
|
60
59
|
context 'Standard creation & initialization:' do
|
61
|
-
it '
|
62
|
-
expect {
|
60
|
+
it 'is initialized with an IO argument' do
|
61
|
+
expect { described_class.new(StringIO.new(+'', 'w')) }.not_to raise_error
|
63
62
|
end
|
64
63
|
|
65
|
-
it '
|
66
|
-
instance =
|
64
|
+
it 'knows its output destination' do
|
65
|
+
instance = described_class.new(destination)
|
67
66
|
expect(instance.output).to eq(destination)
|
68
67
|
end
|
69
68
|
end # context
|
70
69
|
|
71
70
|
|
72
71
|
context 'Formatting events:' do
|
73
|
-
it '
|
74
|
-
instance =
|
72
|
+
it 'renders a parse tree in JSON' do
|
73
|
+
instance = described_class.new(destination)
|
75
74
|
visitor = Rley::ParseTreeVisitor.new(grm_abc_ptree1)
|
76
75
|
instance.render(visitor)
|
77
76
|
expectations = <<-SNIPPET
|
@@ -21,6 +21,8 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
21
21
|
return Syntax::Production.new(theLHS, theRHSSymbols)
|
22
22
|
end
|
23
23
|
|
24
|
+
subject(:an_edge) { described_class.new(vertex1, vertex2) }
|
25
|
+
|
24
26
|
let(:t_a) { Rley::Syntax::Terminal.new('a') }
|
25
27
|
let(:t_b) { Rley::Syntax::Terminal.new('b') }
|
26
28
|
let(:t_c) { Rley::Syntax::Terminal.new('c') }
|
@@ -28,21 +30,19 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
28
30
|
let(:nt_b_sequence) { Rley::Syntax::NonTerminal.new('b_sequence') }
|
29
31
|
let(:sample_prod) { build_prod(nt_sentence, t_a, nt_b_sequence, t_c) }
|
30
32
|
let(:sample_item) { Base::DottedItem.new(sample_prod, 1) }
|
31
|
-
|
32
33
|
let(:vertex1) { ItemVertex.new(sample_item) }
|
33
34
|
let(:vertex2) { StartVertex.new('to') }
|
34
|
-
subject { CallEdge.new(vertex1, vertex2) }
|
35
35
|
|
36
36
|
context 'Initialization:' do
|
37
|
-
it '
|
38
|
-
expect {
|
37
|
+
it 'is created with two vertice arguments' do
|
38
|
+
expect { described_class.new(vertex1, vertex2) }.not_to raise_error
|
39
39
|
end
|
40
40
|
end # context
|
41
41
|
|
42
42
|
context 'Provided services:' do
|
43
|
-
it '
|
43
|
+
it 'knows its key' do
|
44
44
|
expectation = "CALL_#{sample_prod.object_id}_#{sample_item.position}"
|
45
|
-
expect(
|
45
|
+
expect(an_edge.key).to eq(expectation)
|
46
46
|
end
|
47
47
|
end # context
|
48
48
|
end # describe
|
data/spec/rley/gfg/edge_spec.rb
CHANGED
@@ -11,21 +11,22 @@ require_relative '../../../lib/rley/gfg/edge'
|
|
11
11
|
module Rley # Open this namespace to avoid module qualifier prefixes
|
12
12
|
module GFG # Open this namespace to avoid module qualifier prefixes
|
13
13
|
describe Edge do
|
14
|
+
subject(:an_edge) { described_class.new(vertex1, vertex2) }
|
15
|
+
|
14
16
|
let(:vertex1) { StartVertex.new('from') }
|
15
17
|
let(:vertex2) { StartVertex.new('to') }
|
16
|
-
subject { Edge.new(vertex1, vertex2) }
|
17
18
|
|
18
19
|
context 'Initialization:' do
|
19
|
-
it '
|
20
|
-
expect {
|
20
|
+
it 'is created with two vertice arguments' do
|
21
|
+
expect { described_class.new(vertex1, vertex2) }.not_to raise_error
|
21
22
|
end
|
22
23
|
|
23
|
-
it '
|
24
|
-
expect(
|
24
|
+
it 'is registered by the predecessor vertex' do
|
25
|
+
expect(an_edge).to eq(vertex1.edges.last)
|
25
26
|
end
|
26
27
|
|
27
|
-
it '
|
28
|
-
expect(
|
28
|
+
it 'knows the successor vertex' do
|
29
|
+
expect(an_edge.successor).to eq(vertex2)
|
29
30
|
end
|
30
31
|
end # context
|
31
32
|
end # describe
|
@@ -9,24 +9,25 @@ require_relative '../../../lib/rley/gfg/end_vertex'
|
|
9
9
|
module Rley # Open this namespace to avoid module qualifier prefixes
|
10
10
|
module GFG # Open this namespace to avoid module qualifier prefixes
|
11
11
|
describe EndVertex do
|
12
|
+
subject(:a_vertex) { described_class.new(sample_nt) }
|
13
|
+
|
12
14
|
let(:sample_nt) { Syntax::NonTerminal.new('NT') }
|
13
|
-
subject { EndVertex.new(sample_nt) }
|
14
15
|
|
15
16
|
context 'Initialization:' do
|
16
|
-
it '
|
17
|
-
expect {
|
17
|
+
it 'is created with a non-terminal symbol' do
|
18
|
+
expect { described_class.new(sample_nt) }.not_to raise_error
|
18
19
|
end
|
19
20
|
|
20
|
-
it '
|
21
|
+
it 'knows its label' do
|
21
22
|
expect(sample_nt).to receive(:to_s).and_return('NT')
|
22
|
-
expect(
|
23
|
+
expect(a_vertex.label).to eq('NT.')
|
23
24
|
end
|
24
25
|
end # context
|
25
26
|
|
26
27
|
context 'Provided services:' do
|
27
|
-
it '
|
28
|
+
it 'provides human-readable representation of itself' do
|
28
29
|
pattern = /^#<Rley::GFG::EndVertex:\d+ label="NT\."/
|
29
|
-
expect(
|
30
|
+
expect(a_vertex.inspect).to match(pattern)
|
30
31
|
end
|
31
32
|
end # context
|
32
33
|
end # describe
|
@@ -10,14 +10,15 @@ require_relative '../../../lib/rley/gfg/epsilon_edge'
|
|
10
10
|
|
11
11
|
module Rley # Open this namespace to avoid module qualifier prefixes
|
12
12
|
module GFG # Open this namespace to avoid module qualifier prefixes
|
13
|
-
describe
|
13
|
+
describe EpsilonEdge do
|
14
|
+
subject { described_class.new(vertex1, vertex2) }
|
15
|
+
|
14
16
|
let(:vertex1) { StartVertex.new('from') }
|
15
17
|
let(:vertex2) { StartVertex.new('to') }
|
16
|
-
subject { EpsilonEdge.new(vertex1, vertex2) }
|
17
18
|
|
18
19
|
context 'Initialization:' do
|
19
|
-
it '
|
20
|
-
expect {
|
20
|
+
it 'is created with two vertice arguments' do
|
21
|
+
expect { described_class.new(vertex1, vertex2) }.not_to raise_error
|
21
22
|
end
|
22
23
|
end # context
|
23
24
|
end # describe
|
@@ -34,6 +34,9 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
|
+
# Default instantiation rule
|
38
|
+
subject(:a_graph) { described_class.new(items_from_grammar) }
|
39
|
+
|
37
40
|
# Factory method. Build a production with the given sequence
|
38
41
|
# of symbols as its rhs.
|
39
42
|
let(:grammar_abc) do
|
@@ -45,52 +48,48 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
45
48
|
# from the abc grammar
|
46
49
|
let(:items_from_grammar) { build_items_for_grammar(grammar_abc) }
|
47
50
|
|
48
|
-
# Default instantiation rule
|
49
|
-
subject { GrmFlowGraph.new(items_from_grammar) }
|
50
|
-
|
51
|
-
|
52
51
|
context 'Initialization:' do
|
53
|
-
it '
|
54
|
-
expect {
|
52
|
+
it 'is created with an array of dotted items' do
|
53
|
+
expect { described_class.new(items_from_grammar) }.not_to raise_error
|
55
54
|
end
|
56
55
|
|
57
|
-
it '
|
58
|
-
expect(
|
56
|
+
it 'knows its main start vertex' do
|
57
|
+
expect(a_graph.start_vertex).to eq(a_graph.vertices.first)
|
59
58
|
end
|
60
59
|
|
61
|
-
it '
|
60
|
+
it 'has the correct number of vertices' do
|
62
61
|
# Number of vertices = count of dotted items +...
|
63
62
|
# ... 2 * count of non-terminals
|
64
63
|
count_vertices = 2 * grammar_abc.non_terminals.size
|
65
64
|
count_vertices += items_from_grammar.size
|
66
|
-
expect(
|
65
|
+
expect(a_graph.vertices.size).to eq(count_vertices)
|
67
66
|
end
|
68
67
|
|
69
|
-
it '
|
68
|
+
it 'has for each non-terminal one start and end vertex' do
|
70
69
|
# Iterate over all non-terminals of grammar...
|
71
70
|
grammar_abc.non_terminals.each do |nterm|
|
72
71
|
# ...to each non-terminal there should be a start vertex
|
73
|
-
start_vertex =
|
74
|
-
expect(start_vertex).to
|
72
|
+
start_vertex = a_graph.start_vertex_for[nterm]
|
73
|
+
expect(start_vertex).to be_a(StartVertex)
|
75
74
|
expect(start_vertex.label).to eq(".#{nterm}")
|
76
75
|
|
77
76
|
# ...to each non-terminal there should be an end vertex
|
78
|
-
end_vertex =
|
79
|
-
expect(end_vertex).to
|
77
|
+
end_vertex = a_graph.end_vertex_for[nterm]
|
78
|
+
expect(end_vertex).to be_a(EndVertex)
|
80
79
|
expect(end_vertex.label).to eq("#{nterm}.")
|
81
80
|
end
|
82
81
|
end
|
83
82
|
|
84
|
-
it '
|
85
|
-
|
83
|
+
it 'has one or more entry edges per start vertex' do
|
84
|
+
a_graph.start_vertex_for.each_value do |a_start|
|
86
85
|
expect(a_start.edges.size >= 1).to be_truthy
|
87
86
|
a_start.edges.each do |edge|
|
88
|
-
expect(edge.successor.dotted_item
|
87
|
+
expect(edge.successor.dotted_item).to be_at_start
|
89
88
|
end
|
90
89
|
end
|
91
90
|
end
|
92
91
|
|
93
|
-
it '
|
92
|
+
it 'has the correct graph structure' do
|
94
93
|
# We use the abc grammar
|
95
94
|
expected = [
|
96
95
|
'.S --> S => . A',
|
@@ -108,10 +107,10 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
108
107
|
'A => b . --> A.'
|
109
108
|
]
|
110
109
|
|
111
|
-
compare_graph_expectations(
|
110
|
+
compare_graph_expectations(a_graph, expected)
|
112
111
|
end
|
113
112
|
|
114
|
-
it '
|
113
|
+
it 'handles empty productions' do
|
115
114
|
builder = Rley::Syntax::BaseGrammarBuilder.new
|
116
115
|
builder.add_terminals('a')
|
117
116
|
builder.add_production('S' => 'A')
|
@@ -121,7 +120,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
121
120
|
grammar = builder.grammar
|
122
121
|
items = build_items_for_grammar(grammar)
|
123
122
|
|
124
|
-
graph =
|
123
|
+
graph = described_class.new(items)
|
125
124
|
expected = [
|
126
125
|
'.S --> S => . A',
|
127
126
|
'.A --> A => . a',
|
@@ -137,8 +136,8 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
137
136
|
compare_graph_expectations(graph, expected)
|
138
137
|
end
|
139
138
|
|
140
|
-
it '
|
141
|
-
|
139
|
+
it 'has shortcut edges' do
|
140
|
+
a_graph.vertices.each do |a_vertex|
|
142
141
|
next unless a_vertex.kind_of?(ItemVertex)
|
143
142
|
|
144
143
|
if a_vertex.next_symbol.kind_of?(Syntax::NonTerminal)
|
@@ -177,9 +176,9 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
177
176
|
builder.grammar
|
178
177
|
end
|
179
178
|
|
180
|
-
it '
|
179
|
+
it 'provides depth-first traversal' do
|
181
180
|
result = []
|
182
|
-
|
181
|
+
a_graph.traverse_df(a_graph.start_vertex) do |vertex|
|
183
182
|
result << vertex.label
|
184
183
|
end
|
185
184
|
|
@@ -200,28 +199,28 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
200
199
|
expect(result).to eq(expected)
|
201
200
|
end
|
202
201
|
|
203
|
-
it '
|
202
|
+
it 'provides human-readable representation of itself' do
|
204
203
|
prefix = /^#<Rley::GFG::GrmFlowGraph:\d+ @vertices=\[/
|
205
|
-
expect(
|
204
|
+
expect(a_graph.inspect).to match(prefix)
|
206
205
|
pattern = /@vertices=\[#<Rley::GFG::StartVertex:\d+ label="\.S"/
|
207
|
-
expect(
|
206
|
+
expect(a_graph.inspect).to match(pattern)
|
208
207
|
suffix = /]>$/
|
209
|
-
expect(
|
208
|
+
expect(a_graph.inspect).to match(suffix)
|
210
209
|
end
|
211
210
|
|
212
|
-
it '
|
213
|
-
expect {
|
211
|
+
it 'performs a diagnosis of a correct grammar' do
|
212
|
+
expect { a_graph.diagnose }.not_to raise_error
|
214
213
|
grammar_abc.non_terminals.each do |nterm|
|
215
214
|
expect(nterm).not_to be_undefined
|
216
215
|
expect(nterm).not_to be_unreachable
|
217
216
|
end
|
218
217
|
end
|
219
218
|
|
220
|
-
it '
|
219
|
+
it 'detects when a non-terminal is unreachable' do
|
221
220
|
grammar = problematic_grammar
|
222
221
|
items = build_items_for_grammar(grammar)
|
223
222
|
|
224
|
-
graph =
|
223
|
+
graph = described_class.new(items)
|
225
224
|
expect { graph.diagnose }.not_to raise_error
|
226
225
|
grammar.non_terminals.each do |nterm|
|
227
226
|
expect(nterm).not_to be_undefined
|