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
@@ -8,116 +8,106 @@ require_relative '../../../lib/rley/syntax/base_grammar_builder'
|
|
8
8
|
module Rley # Open this namespace to avoid module qualifier prefixes
|
9
9
|
module Syntax # Open this namespace to avoid module qualifier prefixes
|
10
10
|
describe BaseGrammarBuilder do
|
11
|
+
subject(:a_builder) { described_class.new }
|
12
|
+
|
11
13
|
context 'Initialization without argument:' do
|
12
|
-
it '
|
13
|
-
expect {
|
14
|
+
it 'is created without argument' do
|
15
|
+
expect { described_class.new }.not_to raise_error
|
14
16
|
end
|
15
17
|
|
16
|
-
it '
|
17
|
-
expect(
|
18
|
+
it 'has no grammar symbols at start' do
|
19
|
+
expect(a_builder.symbols).to be_empty
|
18
20
|
end
|
19
21
|
|
20
|
-
it '
|
21
|
-
expect(
|
22
|
+
it 'has no productions at start' do
|
23
|
+
expect(a_builder.productions).to be_empty
|
22
24
|
end
|
23
25
|
end # context
|
24
26
|
|
25
27
|
context 'Initialization with argument:' do
|
26
|
-
it '
|
28
|
+
it 'is created with a block argument' do
|
27
29
|
expect do
|
28
|
-
|
30
|
+
described_class.new { nil }
|
29
31
|
end.not_to raise_error
|
30
32
|
end
|
31
33
|
|
32
|
-
it '
|
33
|
-
instance =
|
34
|
+
it 'has grammar symbols from block argument' do
|
35
|
+
instance = described_class.new do
|
34
36
|
add_terminals('a', 'b', 'c')
|
35
37
|
end
|
36
38
|
expect(instance.symbols.size).to eq(3)
|
37
39
|
end
|
38
40
|
|
39
|
-
it '
|
40
|
-
expect(
|
41
|
+
it 'has no productions at start' do
|
42
|
+
expect(a_builder.productions).to be_empty
|
41
43
|
end
|
42
44
|
end # context
|
43
45
|
|
44
46
|
context 'Adding symbols:' do
|
45
|
-
it '
|
46
|
-
|
47
|
-
expect(
|
48
|
-
expect(
|
49
|
-
expect(
|
50
|
-
expect(
|
51
|
-
expect(
|
52
|
-
expect(
|
53
|
-
expect(
|
54
|
-
end
|
55
|
-
|
56
|
-
it '
|
57
|
-
a = Terminal.new('a')
|
58
|
-
b = Terminal.new('b')
|
59
|
-
c = Terminal.new('c')
|
60
|
-
|
61
|
-
subject.add_terminals(a, b, c)
|
62
|
-
expect(subject.symbols.size).to eq(3)
|
63
|
-
expect(subject.symbols['a']).to eq(a)
|
64
|
-
expect(subject.symbols['b']).to eq(b)
|
65
|
-
expect(subject.symbols['c']).to eq(c)
|
66
|
-
end
|
67
|
-
|
68
|
-
it 'should accept already built terminals' do
|
47
|
+
it 'builds terminals from their names' do
|
48
|
+
a_builder.add_terminals('a', 'b', 'c')
|
49
|
+
expect(a_builder.symbols.size).to eq(3)
|
50
|
+
expect(a_builder.symbols['a']).to be_a(Terminal)
|
51
|
+
expect(a_builder.symbols['a'].name).to eq('a')
|
52
|
+
expect(a_builder.symbols['b']).to be_a(Terminal)
|
53
|
+
expect(a_builder.symbols['b'].name).to eq('b')
|
54
|
+
expect(a_builder.symbols['c']).to be_a(Terminal)
|
55
|
+
expect(a_builder.symbols['c'].name).to eq('c')
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'accepts already built terminals' do
|
69
59
|
a = Terminal.new('a')
|
70
60
|
b = Terminal.new('b')
|
71
61
|
c = Terminal.new('c')
|
72
62
|
|
73
|
-
|
74
|
-
expect(
|
75
|
-
expect(
|
76
|
-
expect(
|
77
|
-
expect(
|
63
|
+
a_builder.add_terminals(a, b, c)
|
64
|
+
expect(a_builder.symbols.size).to eq(3)
|
65
|
+
expect(a_builder.symbols['a']).to eq(a)
|
66
|
+
expect(a_builder.symbols['b']).to eq(b)
|
67
|
+
expect(a_builder.symbols['c']).to eq(c)
|
78
68
|
end
|
79
69
|
end # context
|
80
70
|
|
81
71
|
context 'Adding productions:' do
|
82
|
-
subject do
|
83
|
-
instance =
|
72
|
+
subject(:a_builder) do
|
73
|
+
instance = described_class.new
|
84
74
|
instance.add_terminals('a', 'b', 'c')
|
85
75
|
instance
|
86
76
|
end
|
87
77
|
|
88
|
-
it '
|
78
|
+
it 'adds a valid production' do
|
89
79
|
# case of a rhs representation that consists of one name
|
90
|
-
expect {
|
91
|
-
expect(
|
92
|
-
new_prod =
|
93
|
-
expect(new_prod.lhs).to eq(
|
94
|
-
expect(new_prod.rhs[0]).to eq(
|
95
|
-
|
96
|
-
|
97
|
-
expect(
|
98
|
-
new_prod =
|
99
|
-
expect(new_prod.lhs).to eq(
|
100
|
-
expect_rhs = [
|
80
|
+
expect { a_builder.add_production('S' => 'A') }.not_to raise_error
|
81
|
+
expect(a_builder.productions.size).to eq(1)
|
82
|
+
new_prod = a_builder.productions[0]
|
83
|
+
expect(new_prod.lhs).to eq(a_builder['S'])
|
84
|
+
expect(new_prod.rhs[0]).to eq(a_builder['A'])
|
85
|
+
|
86
|
+
a_builder.add_production('A' => %w[a A c])
|
87
|
+
expect(a_builder.productions.size).to eq(2)
|
88
|
+
new_prod = a_builder.productions.last
|
89
|
+
expect(new_prod.lhs).to eq(a_builder['A'])
|
90
|
+
expect_rhs = [a_builder['a'], a_builder['A'], a_builder['c']]
|
101
91
|
expect(new_prod.rhs.members).to eq(expect_rhs)
|
102
92
|
|
103
93
|
# Try another syntax
|
104
|
-
|
105
|
-
expect(
|
106
|
-
new_prod =
|
107
|
-
expect(new_prod.lhs).to eq(
|
108
|
-
expect_rhs = [
|
94
|
+
a_builder.add_production('A' => 'a A c')
|
95
|
+
expect(a_builder.productions.size).to eq(3)
|
96
|
+
new_prod = a_builder.productions.last
|
97
|
+
expect(new_prod.lhs).to eq(a_builder['A'])
|
98
|
+
expect_rhs = [a_builder['a'], a_builder['A'], a_builder['c']]
|
109
99
|
expect(new_prod.rhs.members).to eq(expect_rhs)
|
110
100
|
|
111
101
|
# BaseGrammarBuilder#rule is an alias of add_production
|
112
|
-
|
113
|
-
expect(
|
114
|
-
new_prod =
|
115
|
-
expect(new_prod.lhs).to eq(
|
116
|
-
expect(new_prod.rhs[0]).to eq(
|
102
|
+
a_builder.rule('A' => ['b'])
|
103
|
+
expect(a_builder.productions.size).to eq(4)
|
104
|
+
new_prod = a_builder.productions.last
|
105
|
+
expect(new_prod.lhs).to eq(a_builder['A'])
|
106
|
+
expect(new_prod.rhs[0]).to eq(a_builder['b'])
|
117
107
|
end
|
118
108
|
|
119
|
-
it "
|
120
|
-
instance =
|
109
|
+
it "supports Kleene's plus" do
|
110
|
+
instance = described_class.new
|
121
111
|
instance.add_terminals('plus', 'minus', 'digit')
|
122
112
|
|
123
113
|
instance.add_production('integer' => 'value')
|
@@ -136,8 +126,8 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
136
126
|
end # context
|
137
127
|
|
138
128
|
context 'Building grammar:' do
|
139
|
-
subject do
|
140
|
-
instance =
|
129
|
+
subject(:a_builder) do
|
130
|
+
instance = described_class.new do
|
141
131
|
add_terminals('a', 'b', 'c')
|
142
132
|
add_production('S' => ['A'])
|
143
133
|
add_production('A' => %w[a A c])
|
@@ -147,47 +137,47 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
147
137
|
instance
|
148
138
|
end
|
149
139
|
|
150
|
-
it '
|
151
|
-
expect(
|
152
|
-
grm =
|
153
|
-
expect(grm.rules).to eq(
|
140
|
+
it 'builds a grammar' do
|
141
|
+
expect(a_builder.grammar).to be_a(Grammar)
|
142
|
+
grm = a_builder.grammar
|
143
|
+
expect(grm.rules).to eq(a_builder.productions)
|
154
144
|
|
155
|
-
# Invoking the factory method again
|
145
|
+
# Invoking the factory method again returns
|
156
146
|
# the same grammar object
|
157
|
-
second_time =
|
147
|
+
second_time = a_builder.grammar
|
158
148
|
expect(second_time).to eq(grm)
|
159
149
|
end
|
160
150
|
|
161
|
-
it '
|
162
|
-
instance =
|
151
|
+
it 'complains in absence of symbols' do
|
152
|
+
instance = described_class.new
|
163
153
|
err = StandardError
|
164
154
|
msg = 'No symbol found for grammar'
|
165
155
|
expect { instance.grammar }.to raise_error(err, msg)
|
166
156
|
end
|
167
157
|
|
168
|
-
it '
|
169
|
-
instance =
|
158
|
+
it 'complains in absence of productions' do
|
159
|
+
instance = described_class.new
|
170
160
|
instance.add_terminals('a', 'b', 'c')
|
171
161
|
err = StandardError
|
172
162
|
msg = 'No production found for grammar'
|
173
163
|
expect { instance.grammar }.to raise_error(err, msg)
|
174
164
|
end
|
175
165
|
|
176
|
-
it '
|
166
|
+
it 'complains if one or more terminals are useless' do
|
177
167
|
# Add one useless terminal symbol
|
178
|
-
|
168
|
+
a_builder.add_terminals('d')
|
179
169
|
|
180
170
|
err = StandardError
|
181
171
|
msg = 'Useless terminal symbol(s): d.'
|
182
|
-
expect {
|
172
|
+
expect { a_builder.grammar }.to raise_error(err, msg)
|
183
173
|
|
184
174
|
# Add another useless terminal
|
185
|
-
|
175
|
+
a_builder.add_terminals('e')
|
186
176
|
msg = 'Useless terminal symbol(s): d, e.'
|
187
|
-
expect {
|
177
|
+
expect { a_builder.grammar }.to raise_error(err, msg)
|
188
178
|
end
|
189
179
|
|
190
|
-
it '
|
180
|
+
it 'builds a grammar with nullable nonterminals' do
|
191
181
|
# Grammar 4: A grammar with nullable nonterminal
|
192
182
|
# based on example in "Parsing Techniques" book (D. Grune, C. Jabobs)
|
193
183
|
# S ::= E.
|
@@ -201,7 +191,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
201
191
|
t_star = Terminal.new('*')
|
202
192
|
t_slash = Terminal.new('/')
|
203
193
|
|
204
|
-
builder =
|
194
|
+
builder = described_class.new
|
205
195
|
builder.add_terminals(t_a, t_star, t_slash)
|
206
196
|
builder.add_production('S' => 'E')
|
207
197
|
builder.add_production('E' => %w[E Q F])
|
@@ -29,6 +29,11 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
29
29
|
result
|
30
30
|
end
|
31
31
|
|
32
|
+
subject(:a_grammar) do
|
33
|
+
productions = [prod_S, prod_A1, prod_A2]
|
34
|
+
described_class.new(productions)
|
35
|
+
end
|
36
|
+
|
32
37
|
# Grammar 1: arithmetical expressions with integers
|
33
38
|
let(:grm1_ops) do
|
34
39
|
operators = %w[+ - * / ( )]
|
@@ -83,91 +88,50 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
83
88
|
let(:prod_A2) { Production.new(nt_A, [b_]) }
|
84
89
|
let(:prod_A3) { Production.new(nt_A, [c_, nt_C]) }
|
85
90
|
|
86
|
-
=begin
|
87
|
-
# Non-terminals that specify the lexicon of the language
|
88
|
-
let(:noun) { NonTerminal.new('Noun') }
|
89
|
-
let(:noun_list) { %w(flights breeze trip morning) }
|
90
|
-
let(:verb) { NonTerminal.new('Verb') }
|
91
|
-
let(:verb_list) { %w(is prefer like need want fly) }
|
92
|
-
let(:adjective) { NonTerminal.new('Adjective') }
|
93
|
-
let(:adjective_list) { %w(cheapest non-stop first latest other direct) }
|
94
|
-
let(:pronoun) { NonTerminal.new('Pronoun') }
|
95
|
-
let(:pronoun_list) { %w(me I you it) }
|
96
|
-
let(:proper_noun) { NonTerminal.new('Proper_noun') }
|
97
|
-
let(:proper_noun_list) do [ 'Alaska', 'Baltimore', 'Los Angeles',
|
98
|
-
'Chicago', 'United', 'American' ]
|
99
|
-
end
|
100
|
-
let(:determiner) { NonTerminal.new('Determiner') }
|
101
|
-
let(:determiner_list) { %w(the a an this these that) }
|
102
|
-
let(:preposition) { NonTerminal.new('Preposition') }
|
103
|
-
let(:preposition_list) { %w(from to on near) }
|
104
|
-
let(:conjunction) { NonTerminal.new('Conjunction') }
|
105
|
-
let(:conjunction_list) { %w(and or but) }
|
106
|
-
|
107
|
-
let(:noun_prods) { prods_for_list(noun, noun_list) }
|
108
|
-
let(:verb_prods) { prods_for_list(verb, verb_list) }
|
109
|
-
let(:adjective_prods) { prods_for_list(adjective, adjective_list) }
|
110
|
-
let(:pronoun_prods) { prods_for_list(pronoun, pronoun_list) }
|
111
|
-
let(:proper_pronoun_prods) do
|
112
|
-
prods_for_list(proper_pronoun, proper_pronoun_list)
|
113
|
-
end
|
114
|
-
let(:determiner_prods) { prods_for_list(determiner, determiner_list) }
|
115
|
-
let(:preposition_prods) { prods_for_list(preposition, preposition_list) }
|
116
|
-
let(:conjunction_prods) { prods_for_list(conjunction, conjunction_list) }
|
117
|
-
|
118
|
-
# Productions for the L0 language (from Jurafki & Martin)
|
119
|
-
let(:nominal_prods) { Production}
|
120
|
-
=end
|
121
|
-
|
122
|
-
subject do
|
123
|
-
productions = [prod_S, prod_A1, prod_A2]
|
124
|
-
Grammar.new(productions)
|
125
|
-
end
|
126
|
-
|
127
91
|
context 'Initialization:' do
|
128
|
-
it '
|
129
|
-
expect {
|
92
|
+
it 'is created with a list of productions' do
|
93
|
+
expect { described_class.new([prod_S, prod_A1, prod_A2]) }.not_to raise_error
|
130
94
|
end
|
131
95
|
|
132
|
-
it '
|
133
|
-
expect(
|
96
|
+
it 'knows its productions' do
|
97
|
+
expect(a_grammar.rules).to eq([prod_S, prod_A1, prod_A2])
|
134
98
|
end
|
135
99
|
|
136
|
-
it '
|
137
|
-
expect(
|
100
|
+
it 'knows its start symbol' do
|
101
|
+
expect(a_grammar.start_symbol).to eq(nt_S)
|
138
102
|
end
|
139
103
|
|
140
|
-
it '
|
141
|
-
expect(
|
104
|
+
it 'knows all its symbols' do
|
105
|
+
expect(a_grammar.symbols).to eq([nt_S, nt_A, a_, c_, b_])
|
142
106
|
end
|
143
107
|
|
144
|
-
it '
|
145
|
-
expect(
|
108
|
+
it 'knows all its non-terminal symbols' do
|
109
|
+
expect(a_grammar.non_terminals).to eq([nt_S, nt_A])
|
146
110
|
end
|
147
111
|
|
148
|
-
it '
|
149
|
-
expect(
|
112
|
+
it 'knows its start production' do
|
113
|
+
expect(a_grammar.start_production).to eq(prod_S)
|
150
114
|
end
|
151
115
|
end # context
|
152
116
|
|
153
117
|
context 'Provided services:' do
|
154
|
-
it '
|
155
|
-
expect(
|
156
|
-
expect(
|
157
|
-
expect(
|
158
|
-
expect(
|
159
|
-
expect(
|
118
|
+
it 'retrieves its symbols from their name' do
|
119
|
+
expect(a_grammar.name2symbol['S']).to eq(nt_S)
|
120
|
+
expect(a_grammar.name2symbol['A']).to eq(nt_A)
|
121
|
+
expect(a_grammar.name2symbol['a']).to eq(a_)
|
122
|
+
expect(a_grammar.name2symbol['b']).to eq(b_)
|
123
|
+
expect(a_grammar.name2symbol['c']).to eq(c_)
|
160
124
|
end
|
161
125
|
|
162
|
-
it '
|
163
|
-
|
126
|
+
it 'ensures that each production has a name' do
|
127
|
+
a_grammar.rules.each do |prod|
|
164
128
|
expect(prod.name).to match(Regexp.new("#{prod.lhs.name}_\\d$"))
|
165
129
|
end
|
166
130
|
end
|
167
131
|
end # context
|
168
132
|
|
169
133
|
context 'Grammar diagnosis:' do
|
170
|
-
it '
|
134
|
+
it 'marks any non-terminal that has no production' do
|
171
135
|
# S ::= A.
|
172
136
|
# S ::= B.
|
173
137
|
# A ::= "a" .
|
@@ -176,13 +140,13 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
176
140
|
prod_S2 = Rley::Syntax::Production.new(nt_S, [nt_B])
|
177
141
|
prod_A = Rley::Syntax::Production.new(nt_A, [a_])
|
178
142
|
prod_B = Rley::Syntax::Production.new(nt_B, [nt_C, b_]) # C undefined
|
179
|
-
instance =
|
143
|
+
instance = described_class.new([prod_S1, prod_S2, prod_A, prod_B])
|
180
144
|
undefineds = instance.non_terminals.select(&:undefined?)
|
181
145
|
expect(undefineds.size).to eq(1)
|
182
146
|
expect(undefineds.first).to eq(nt_C)
|
183
147
|
end
|
184
148
|
|
185
|
-
it '
|
149
|
+
it 'marks any non-terminal as generative or not' do
|
186
150
|
# S ::= A.
|
187
151
|
# S ::= B.
|
188
152
|
# A ::= "a" .
|
@@ -191,14 +155,14 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
191
155
|
prod_S2 = Rley::Syntax::Production.new(nt_S, [nt_B])
|
192
156
|
prod_A = Rley::Syntax::Production.new(nt_A, [a_])
|
193
157
|
prod_B = Rley::Syntax::Production.new(nt_B, [nt_C, b_]) # C undefined
|
194
|
-
instance =
|
158
|
+
instance = described_class.new([prod_S1, prod_S2, prod_A, prod_B])
|
195
159
|
partitioning = instance.non_terminals.partition(&:generative?)
|
196
160
|
expect(partitioning[0].size).to eq(2)
|
197
161
|
expect(partitioning[0]).to eq([nt_S, nt_A])
|
198
162
|
expect(partitioning[1]).to eq([nt_B, nt_C])
|
199
163
|
end
|
200
164
|
|
201
|
-
it "
|
165
|
+
it "does a diagnosis even for 'loopy' grammars" do
|
202
166
|
# 'S' => 'A'
|
203
167
|
# 'S' => 'B'
|
204
168
|
# 'A' => 'a'
|
@@ -211,7 +175,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
211
175
|
prd_B = Rley::Syntax::Production.new(nt_B, [nt_C])
|
212
176
|
prd_C = Rley::Syntax::Production.new(nt_C, [nt_D])
|
213
177
|
prd_D = Rley::Syntax::Production.new(nt_D, [nt_B])
|
214
|
-
instance =
|
178
|
+
instance = described_class.new([prd_S1, prd_S2, prd_A, prd_B, prd_C, prd_D])
|
215
179
|
partitioning = instance.non_terminals.partition(&:generative?)
|
216
180
|
expect(partitioning[0].size).to eq(2)
|
217
181
|
expect(partitioning[0]).to eq([nt_S, nt_A])
|
@@ -223,8 +187,8 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
223
187
|
end # context
|
224
188
|
|
225
189
|
context 'Non-nullable grammar:' do
|
226
|
-
it '
|
227
|
-
nonterms =
|
190
|
+
it 'marks all its nonterminals as non-nullable' do
|
191
|
+
nonterms = a_grammar.non_terminals
|
228
192
|
nonterms.each do |nterm|
|
229
193
|
expect(nterm).not_to be_nullable
|
230
194
|
end
|
@@ -232,24 +196,22 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
232
196
|
end # context
|
233
197
|
|
234
198
|
context 'Nullable grammars:' do
|
235
|
-
subject do
|
199
|
+
subject(:nullable_grammar) do
|
236
200
|
prod_A4 = Production.new(nt_A, [])
|
237
201
|
productions = [prod_S, prod_A1, prod_A2, prod_A4]
|
238
|
-
|
202
|
+
described_class.new(productions)
|
239
203
|
end
|
240
204
|
|
241
|
-
it '
|
205
|
+
it 'marks its nullable nonterminals' do
|
242
206
|
# In the default grammar, all nonterminals are nullable
|
243
|
-
nonterms =
|
244
|
-
nonterms.
|
245
|
-
expect(nterm).to be_nullable
|
246
|
-
end
|
207
|
+
nonterms = nullable_grammar.non_terminals
|
208
|
+
expect(nonterms).to all(be_nullable)
|
247
209
|
end
|
248
210
|
|
249
|
-
it '
|
211
|
+
it 'marks its nullable productions' do
|
250
212
|
# Given the above productions, here are our expectations:
|
251
213
|
expectations = [true, false, false, true]
|
252
|
-
actuals =
|
214
|
+
actuals = nullable_grammar.rules.map(&:nullable?)
|
253
215
|
expect(actuals).to eq(expectations)
|
254
216
|
end
|
255
217
|
end # context
|
@@ -8,22 +8,22 @@ require_relative '../../../lib/rley/syntax/grm_symbol'
|
|
8
8
|
module Rley # Open this namespace to avoid module qualifier prefixes
|
9
9
|
module Syntax # Open this namespace to avoid module qualifier prefixes
|
10
10
|
describe GrmSymbol do
|
11
|
+
subject(:grammar_symb) { described_class.new(sample_name) }
|
11
12
|
let(:sample_name) { 'NP' }
|
12
|
-
subject { GrmSymbol.new(sample_name) }
|
13
13
|
|
14
14
|
context 'Initialization:' do
|
15
|
-
it '
|
16
|
-
expect {
|
15
|
+
it 'is created with a name' do
|
16
|
+
expect { described_class.new('NP') }.not_to raise_error
|
17
17
|
end
|
18
18
|
|
19
|
-
it '
|
20
|
-
expect(
|
19
|
+
it 'knows its name' do
|
20
|
+
expect(grammar_symb.name).to eq(sample_name)
|
21
21
|
end
|
22
22
|
end # context
|
23
23
|
|
24
24
|
context 'Provided services:' do
|
25
|
-
it '
|
26
|
-
expect(
|
25
|
+
it 'gives its text representation' do
|
26
|
+
expect(grammar_symb.to_s).to eq(sample_name)
|
27
27
|
end
|
28
28
|
end # context
|
29
29
|
end # describe
|
@@ -15,6 +15,8 @@ require_relative '../../../lib/rley/syntax/match_closest'
|
|
15
15
|
module Rley # Open this namespace to avoid module qualifier prefixes
|
16
16
|
module Syntax # Open this namespace to avoid module qualifier prefixes
|
17
17
|
describe MatchClosest do
|
18
|
+
subject(:constraint) { described_class.new(prod.rhs.members, 4, 'IF') }
|
19
|
+
|
18
20
|
# 'stmt' => 'IF boolean THEN stmt ELSE stmt'
|
19
21
|
let(:boolean) { NonTerminal.new('boolean') }
|
20
22
|
let(:stmt) { NonTerminal.new('stmt') }
|
@@ -24,19 +26,17 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
24
26
|
let(:sequence) { [if_t, boolean, then_t, stmt, else_t, stmt] }
|
25
27
|
let(:prod) { Production.new(stmt, sequence) }
|
26
28
|
|
27
|
-
subject { MatchClosest.new(prod.rhs.members, 4, 'IF') }
|
28
|
-
|
29
29
|
context 'Initialization:' do
|
30
|
-
it '
|
31
|
-
expect {
|
30
|
+
it 'is created with an symbol seq., an indice and a name' do
|
31
|
+
expect { described_class.new(prod.rhs.members, 4, 'IF') }.not_to raise_error
|
32
32
|
end
|
33
33
|
|
34
|
-
it '
|
35
|
-
expect(
|
34
|
+
it 'knows the index argument' do
|
35
|
+
expect(constraint.idx_symbol).to eq(4) # ELSE at position 4
|
36
36
|
end
|
37
37
|
|
38
|
-
it '
|
39
|
-
expect(
|
38
|
+
it 'knows the name of preceding symbol to pair with' do
|
39
|
+
expect(constraint.closest_symb).to eq('IF')
|
40
40
|
end
|
41
41
|
end # context
|
42
42
|
end # describe
|
@@ -8,47 +8,47 @@ require_relative '../../../lib/rley/syntax/non_terminal'
|
|
8
8
|
module Rley # Open this namespace to avoid module qualifier prefixes
|
9
9
|
module Syntax # Open this namespace to avoid module qualifier prefixes
|
10
10
|
describe NonTerminal do
|
11
|
+
subject(:a_nonterm) { described_class.new(sample_name) }
|
11
12
|
let(:sample_name) { 'noun' }
|
12
|
-
subject { NonTerminal.new(sample_name) }
|
13
13
|
|
14
14
|
context 'Initialization:' do
|
15
|
-
it '
|
16
|
-
expect {
|
15
|
+
it 'is created with a name' do
|
16
|
+
expect { described_class.new('noun') }.not_to raise_error
|
17
17
|
end
|
18
18
|
|
19
|
-
it '
|
20
|
-
expect(
|
19
|
+
it 'knows its name' do
|
20
|
+
expect(a_nonterm.name).to eq(sample_name)
|
21
21
|
end
|
22
22
|
|
23
|
-
it '
|
24
|
-
expect(
|
23
|
+
it 'knows that is a not a terminal' do
|
24
|
+
expect(a_nonterm).not_to be_terminal
|
25
25
|
end
|
26
26
|
end # context
|
27
27
|
|
28
28
|
|
29
29
|
context 'Provided services:' do
|
30
|
-
it '
|
31
|
-
expect(
|
32
|
-
|
33
|
-
expect(
|
34
|
-
|
35
|
-
expect(
|
30
|
+
it 'knows whether it is nullable' do
|
31
|
+
expect(a_nonterm.nullable?).to be_nil
|
32
|
+
a_nonterm.nullable = true
|
33
|
+
expect(a_nonterm).to be_nullable
|
34
|
+
a_nonterm.nullable = false
|
35
|
+
expect(a_nonterm).not_to be_nullable
|
36
36
|
end
|
37
37
|
|
38
|
-
it '
|
39
|
-
expect(
|
40
|
-
|
41
|
-
expect(
|
42
|
-
|
43
|
-
expect(
|
38
|
+
it 'knows whether it is defined' do
|
39
|
+
expect(a_nonterm.undefined?).to be_nil
|
40
|
+
a_nonterm.undefined = true
|
41
|
+
expect(a_nonterm).to be_undefined
|
42
|
+
a_nonterm.undefined = false
|
43
|
+
expect(a_nonterm).not_to be_undefined
|
44
44
|
end
|
45
45
|
|
46
|
-
it '
|
47
|
-
expect(
|
48
|
-
|
49
|
-
expect(
|
50
|
-
|
51
|
-
expect(
|
46
|
+
it 'knows whether it is generative' do
|
47
|
+
expect(a_nonterm.generative?).to be_nil
|
48
|
+
a_nonterm.generative = true
|
49
|
+
expect(a_nonterm).to be_generative
|
50
|
+
a_nonterm.generative = false
|
51
|
+
expect(a_nonterm).not_to be_generative
|
52
52
|
end
|
53
53
|
end # context
|
54
54
|
end # describe
|