rley 0.8.06 → 0.8.10
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 +23 -2
- data/CHANGELOG.md +21 -1
- data/LICENSE.txt +1 -1
- data/README.md +1 -1
- data/appveyor.yml +1 -3
- data/examples/NLP/benchmark_pico_en.rb +6 -6
- data/examples/NLP/engtagger.rb +6 -6
- data/examples/general/calc_iter1/calc_lexer.rb +1 -1
- data/examples/general/calc_iter2/calc_lexer.rb +1 -1
- data/examples/general/left.rb +1 -1
- data/examples/general/right.rb +1 -1
- data/examples/tokenizer/loxxy_raw_scanner.rex.rb +3 -0
- data/examples/tokenizer/loxxy_tokenizer.rb +2 -2
- data/examples/tokenizer/run_tokenizer.rb +1 -1
- data/examples/tokenizer/{tokens.yaml → tokens.yml} +0 -0
- data/lib/rley/constants.rb +1 -1
- data/lib/rley/engine.rb +2 -2
- data/lib/rley/interface.rb +3 -3
- data/lib/rley/lexical/token.rb +1 -1
- data/lib/rley/ptree/non_terminal_node.rb +1 -1
- data/lib/rley/rgn/all_notation_nodes.rb +5 -0
- data/lib/rley/{notation → rgn}/ast_builder.rb +19 -12
- data/lib/rley/{notation → rgn}/ast_node.rb +13 -12
- data/lib/rley/{notation → rgn}/ast_visitor.rb +10 -10
- data/lib/rley/rgn/composite_node.rb +28 -0
- data/lib/rley/{notation → rgn}/grammar.rb +1 -1
- data/lib/rley/{notation → rgn}/grammar_builder.rb +86 -124
- data/lib/rley/{notation → rgn}/parser.rb +7 -7
- data/lib/rley/rgn/repetition_node.rb +62 -0
- data/lib/rley/rgn/sequence_node.rb +30 -0
- data/lib/rley/{notation → rgn}/symbol_node.rb +15 -7
- data/lib/rley/{notation → rgn}/tokenizer.rb +71 -60
- data/lib/rley/syntax/grm_symbol.rb +0 -4
- data/lib/rley/syntax/non_terminal.rb +4 -0
- data/lib/rley/syntax/terminal.rb +10 -6
- data/spec/rley/parser/dangling_else_spec.rb +3 -3
- data/spec/rley/parser/gfg_earley_parser_spec.rb +48 -50
- data/spec/rley/{notation → rgn}/grammar_builder_spec.rb +58 -54
- data/spec/rley/{notation → rgn}/parser_spec.rb +36 -24
- data/spec/rley/rgn/repetition_node_spec.rb +56 -0
- data/spec/rley/rgn/sequence_node_spec.rb +48 -0
- data/spec/rley/rgn/symbol_node_spec.rb +33 -0
- data/spec/rley/{notation → rgn}/tokenizer_spec.rb +2 -2
- data/spec/rley/support/ambiguous_grammar_helper.rb +2 -2
- data/spec/rley/support/grammar_int_seq_helper.rb +2 -2
- metadata +40 -33
- data/lib/rley/notation/all_notation_nodes.rb +0 -4
- data/lib/rley/notation/grouping_node.rb +0 -23
- data/lib/rley/notation/sequence_node.rb +0 -35
data/lib/rley/syntax/terminal.rb
CHANGED
@@ -7,25 +7,29 @@ module Rley # This module is used as a namespace
|
|
7
7
|
# A terminal symbol represents a class of words in the language
|
8
8
|
# defined the grammar.
|
9
9
|
class Terminal < GrmSymbol
|
10
|
-
#
|
11
|
-
#
|
12
|
-
|
13
|
-
|
14
|
-
|
10
|
+
# An indicator that tells whether the grammar symbol can generate a
|
11
|
+
# non-empty string of terminals.
|
12
|
+
# @return [TrueClass]
|
13
|
+
def generative?
|
14
|
+
true
|
15
15
|
end
|
16
16
|
|
17
17
|
# Return true iff the symbol is a terminal
|
18
|
+
# @return [TrueClass]
|
18
19
|
def terminal?
|
19
|
-
|
20
|
+
true
|
20
21
|
end
|
21
22
|
|
22
23
|
# @return [false] Return true if the symbol derives
|
23
24
|
# the empty string. As terminal symbol corresponds to a input token
|
24
25
|
# it is by definition non-nullable.
|
26
|
+
# @return [FalseClass]
|
25
27
|
def nullable?
|
26
28
|
false
|
27
29
|
end
|
28
30
|
|
31
|
+
# Return a readable text representation of the instance
|
32
|
+
# @return [String] The symbol name
|
29
33
|
def to_s
|
30
34
|
name
|
31
35
|
end
|
@@ -9,7 +9,7 @@ require_relative '../../../lib/rley/syntax/base_grammar_builder'
|
|
9
9
|
require_relative '../../../lib/rley/lexical/token'
|
10
10
|
require_relative '../../../lib/rley/base/dotted_item'
|
11
11
|
require_relative '../../../lib/rley/parser/gfg_parsing'
|
12
|
-
require_relative '../../../lib/rley/
|
12
|
+
require_relative '../../../lib/rley/rgn/grammar_builder'
|
13
13
|
|
14
14
|
require_relative '../support/expectation_helper'
|
15
15
|
|
@@ -64,7 +64,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
64
64
|
context 'Ambiguous parse: ' do
|
65
65
|
# Factory method. Creates a grammar builder for a simple grammar.
|
66
66
|
def grammar_if_else_amb
|
67
|
-
builder = Rley::
|
67
|
+
builder = Rley::RGN::GrammarBuilder.new do
|
68
68
|
add_terminals('IF', 'THEN', 'ELSE')
|
69
69
|
add_terminals('FALSE', 'TRUE', 'INTEGER')
|
70
70
|
|
@@ -290,7 +290,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
290
290
|
|
291
291
|
# Factory method. Creates a grammar builder for a simple grammar.
|
292
292
|
def grammar_if_else
|
293
|
-
builder = Rley::
|
293
|
+
builder = Rley::RGN::GrammarBuilder.new do
|
294
294
|
add_terminals('IF', 'THEN', 'ELSE')
|
295
295
|
add_terminals('FALSE', 'TRUE', 'INTEGER')
|
296
296
|
|
@@ -22,7 +22,6 @@ require_relative '../support/expectation_helper'
|
|
22
22
|
require_relative '../../../lib/rley/parser/gfg_earley_parser'
|
23
23
|
|
24
24
|
module Rley # Open this namespace to avoid module qualifier prefixes
|
25
|
-
# rubocop: disable Metrics/BlockLength
|
26
25
|
module Parser # Open this namespace to avoid module qualifier prefixes
|
27
26
|
describe GFGEarleyParser do
|
28
27
|
include GrammarABCHelper # Mix-in module with builder for grammar abc
|
@@ -292,75 +291,75 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
292
291
|
###################### S(0): . 6, 36, 216
|
293
292
|
# Expectation chart[0]:
|
294
293
|
expected = [
|
295
|
-
'.S | 0',
|
296
|
-
'S => . sequence | 0',
|
297
|
-
'S => . | 0',
|
298
|
-
'.sequence | 0',
|
299
|
-
'S. | 0',
|
300
|
-
'sequence => . sequence comma integer | 0',
|
301
|
-
'sequence => . integer | 0',
|
302
|
-
'.integer | 0',
|
303
|
-
'integer => .
|
304
|
-
'.
|
305
|
-
'
|
306
|
-
'
|
294
|
+
'.S | 0', # Initialization
|
295
|
+
'S => . sequence | 0', # start rule
|
296
|
+
'S => . | 0', # start rule
|
297
|
+
'.sequence | 0', # call rule
|
298
|
+
'S. | 0', # exit rule
|
299
|
+
'sequence => . sequence comma integer | 0', # start rule
|
300
|
+
'sequence => . integer | 0', # start rule
|
301
|
+
'.integer | 0', # call rule
|
302
|
+
'integer => . rep_digit_plus | 0', # start rule
|
303
|
+
'.rep_digit_plus | 0', # call rule
|
304
|
+
'rep_digit_plus => . rep_digit_plus digit | 0', # start rule (generated)
|
305
|
+
'rep_digit_plus => . digit | 0' # start rule (generated)
|
307
306
|
]
|
308
307
|
compare_entry_texts(parse_result.chart[0], expected)
|
309
308
|
|
310
309
|
###################### S(1): 6 ., 36, 216
|
311
310
|
# Expectation chart[1]:
|
312
311
|
expected = [
|
313
|
-
'
|
314
|
-
'
|
315
|
-
'integer =>
|
316
|
-
'
|
317
|
-
'integer. | 0',
|
318
|
-
'sequence => integer . | 0',
|
319
|
-
'sequence. | 0',
|
320
|
-
'S => sequence . | 0',
|
321
|
-
'sequence => sequence . comma integer | 0',
|
322
|
-
'S. | 0'
|
312
|
+
'rep_digit_plus => digit . | 0', # Scan
|
313
|
+
'rep_digit_plus. | 0', # exit rule
|
314
|
+
'integer => rep_digit_plus . | 0', # end rule
|
315
|
+
'rep_digit_plus => rep_digit_plus . digit | 0', # rule (generated)
|
316
|
+
'integer. | 0', # exit rule
|
317
|
+
'sequence => integer . | 0', # end rule
|
318
|
+
'sequence. | 0', # exit rule
|
319
|
+
'S => sequence . | 0', # end rule
|
320
|
+
'sequence => sequence . comma integer | 0', # rule
|
321
|
+
'S. | 0' # exit rule
|
323
322
|
]
|
324
323
|
compare_entry_texts(parse_result.chart[1], expected)
|
325
324
|
|
326
325
|
###################### S(2): 6 , . 36, 216
|
327
326
|
# Expectation chart[2]:
|
328
327
|
expected = [
|
329
|
-
'sequence => sequence comma . integer | 0',
|
330
|
-
'.integer | 2',
|
331
|
-
'integer => .
|
332
|
-
'.
|
333
|
-
'
|
334
|
-
'
|
328
|
+
'sequence => sequence comma . integer | 0', # Scan
|
329
|
+
'.integer | 2', # call rule
|
330
|
+
'integer => . rep_digit_plus | 2', # start rule
|
331
|
+
'.rep_digit_plus | 2', # call rule
|
332
|
+
'rep_digit_plus => . rep_digit_plus digit | 2', # start rule (generated)
|
333
|
+
'rep_digit_plus => . digit | 2' # start rule (generated)
|
335
334
|
]
|
336
335
|
compare_entry_texts(parse_result.chart[2], expected)
|
337
336
|
|
338
337
|
###################### S(3): 6 , 3 . 6. , 216
|
339
338
|
# Expectation chart[3]:
|
340
339
|
expected = [
|
341
|
-
'
|
342
|
-
'
|
343
|
-
'integer =>
|
344
|
-
'
|
345
|
-
'integer. | 2',
|
346
|
-
'sequence => sequence comma integer . | 0',
|
347
|
-
'sequence. | 0',
|
348
|
-
'S => sequence . | 0',
|
349
|
-
'sequence => sequence . comma integer | 0'
|
340
|
+
'rep_digit_plus => digit . | 2', # Scan
|
341
|
+
'rep_digit_plus. | 2', # exit rule
|
342
|
+
'integer => rep_digit_plus . | 2', # end rule
|
343
|
+
'rep_digit_plus => rep_digit_plus . digit | 2', # rule (generated)
|
344
|
+
'integer. | 2', # exit rule
|
345
|
+
'sequence => sequence comma integer . | 0', # rule
|
346
|
+
'sequence. | 0', # exit rule
|
347
|
+
'S => sequence . | 0', # end rule
|
348
|
+
'sequence => sequence . comma integer | 0' # rule
|
350
349
|
]
|
351
350
|
compare_entry_texts(parse_result.chart[3], expected)
|
352
351
|
|
353
352
|
###################### S(4): 6 , 36 . . , 216
|
354
353
|
# Expectation chart[4]:
|
355
354
|
expected = [
|
356
|
-
'
|
357
|
-
'
|
358
|
-
'integer =>
|
359
|
-
'
|
360
|
-
'integer. | 2',
|
361
|
-
'sequence => sequence comma integer . | 0',
|
362
|
-
'sequence. | 0',
|
363
|
-
'S => sequence . | 0'
|
355
|
+
'rep_digit_plus => rep_digit_plus digit . | 2', # Scan
|
356
|
+
'rep_digit_plus. | 2', # exit rule
|
357
|
+
'integer => rep_digit_plus . | 2', # end rule
|
358
|
+
'rep_digit_plus => rep_digit_plus . digit | 2', #
|
359
|
+
'integer. | 2', # exit rule
|
360
|
+
'sequence => sequence comma integer . | 0', # rule
|
361
|
+
'sequence. | 0', # exit rule
|
362
|
+
'S => sequence . | 0' # end rule
|
364
363
|
]
|
365
364
|
compare_entry_texts(parse_result.chart[4], expected)
|
366
365
|
end
|
@@ -372,7 +371,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
372
371
|
# A => ;
|
373
372
|
t_x = Syntax::Terminal.new('x')
|
374
373
|
|
375
|
-
builder =
|
374
|
+
builder = RGN::GrammarBuilder.new do
|
376
375
|
add_terminals(t_x)
|
377
376
|
rule 'Ss' => 'A A x'
|
378
377
|
rule 'A' => []
|
@@ -932,7 +931,7 @@ MSG
|
|
932
931
|
# S => ;
|
933
932
|
# This grammar requires a time that is quadratic in the number of
|
934
933
|
# input tokens
|
935
|
-
builder =
|
934
|
+
builder = RGN::GrammarBuilder.new do
|
936
935
|
add_terminals('a')
|
937
936
|
rule('S' => 'a S')
|
938
937
|
rule('S' => '')
|
@@ -1021,7 +1020,7 @@ MSG
|
|
1021
1020
|
# An implicit EOF marker is a special terminal
|
1022
1021
|
# that denotes the end of input string but doesn't
|
1023
1022
|
# appear explicitly as some character or text in the input.
|
1024
|
-
builder =
|
1023
|
+
builder = RGN::GrammarBuilder.new do
|
1025
1024
|
add_terminals('a', 'b', 'EOF')
|
1026
1025
|
|
1027
1026
|
rule('S' => 'a_or_b* EOF')
|
@@ -1038,6 +1037,5 @@ MSG
|
|
1038
1037
|
end # context
|
1039
1038
|
end # describe
|
1040
1039
|
end # module
|
1041
|
-
# rubocop: enable Metrics/BlockLength
|
1042
1040
|
end # module
|
1043
1041
|
# End of file
|
@@ -3,10 +3,10 @@
|
|
3
3
|
require_relative '../../spec_helper'
|
4
4
|
|
5
5
|
# Load the class under test
|
6
|
-
require_relative '../../../lib/rley/
|
6
|
+
require_relative '../../../lib/rley/rgn/grammar_builder'
|
7
7
|
|
8
8
|
module Rley # Open this namespace to avoid module qualifier prefixes
|
9
|
-
module
|
9
|
+
module RGN # Open this namespace to avoid module qualifier prefixes
|
10
10
|
describe GrammarBuilder do
|
11
11
|
context 'Initialization without argument:' do
|
12
12
|
it 'could be created without argument' do
|
@@ -123,11 +123,12 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
123
123
|
# implicitly called: rule('arguments_qmark' => 'arguments').tag suffix_qmark_one
|
124
124
|
# implicitly called: rule('arguments_qmark' => '').tag suffix_qmark_none
|
125
125
|
expect(instance.productions.size).to eq(3)
|
126
|
-
prod_star = instance.productions.select { |prod| prod.lhs.name == '
|
126
|
+
prod_star = instance.productions.select { |prod| prod.lhs.name == 'rep_arguments_qmark' }
|
127
127
|
expect(prod_star.size).to eq(2)
|
128
128
|
first_prod = instance.productions.first
|
129
129
|
expect(first_prod.lhs.name).to eq('argument_list')
|
130
|
-
expect(first_prod.rhs.members[1].name).to eq('
|
130
|
+
expect(first_prod.rhs.members[1].name).to eq('rep_arguments_qmark')
|
131
|
+
expect(instance.productions.last.rhs.members).to be_empty
|
131
132
|
end
|
132
133
|
|
133
134
|
it "should support Kleene's star" do
|
@@ -137,14 +138,14 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
137
138
|
instance.rule 'program' => 'declaration* EOF'
|
138
139
|
instance.grammar_complete!
|
139
140
|
|
140
|
-
# implicitly called: rule('
|
141
|
-
# implicitly called: rule('
|
141
|
+
# implicitly called: rule('rep_declaration_star' => 'rep_declaration_star declaration').tag suffix_star_more
|
142
|
+
# implicitly called: rule('rep_declaration_star' => '').tag suffix_star_last
|
142
143
|
expect(instance.productions.size).to eq(3)
|
143
|
-
prod_star = instance.productions.select { |prod| prod.lhs.name == '
|
144
|
+
prod_star = instance.productions.select { |prod| prod.lhs.name == 'rep_declaration_star' }
|
144
145
|
expect(prod_star.size).to eq(2)
|
145
146
|
first_prod = instance.productions.first
|
146
147
|
expect(first_prod.lhs.name).to eq('program')
|
147
|
-
expect(first_prod.rhs.members[0].name).to eq('
|
148
|
+
expect(first_prod.rhs.members[0].name).to eq('rep_declaration_star')
|
148
149
|
end
|
149
150
|
|
150
151
|
it "should support symbols decorated with Kleene's plus" do
|
@@ -163,11 +164,11 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
163
164
|
# implicitly called: rule('digit_plus' => 'digit_plus digit').tag suffix_plus_more
|
164
165
|
# implicitly called: rule('digit_plus' => 'digit').tag suffix_plus_last
|
165
166
|
expect(instance.productions.size).to eq(7) # Two additional rules generated
|
166
|
-
prod_plus = instance.productions.select { |prod| prod.lhs.name == '
|
167
|
+
prod_plus = instance.productions.select { |prod| prod.lhs.name == 'rep_digit_plus' }
|
167
168
|
expect(prod_plus.size).to eq(2)
|
168
169
|
val_prod = instance.productions[4]
|
169
170
|
expect(val_prod.lhs.name).to eq('value')
|
170
|
-
expect(val_prod.rhs.members[0].name).to eq('
|
171
|
+
expect(val_prod.rhs.members[0].name).to eq('rep_digit_plus')
|
171
172
|
end
|
172
173
|
|
173
174
|
it 'should support optional grouping' do
|
@@ -180,21 +181,23 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
180
181
|
# implicitly called: rule('seq_EQUAL_expression' => 'EQUAL expression').tag 'return_children'
|
181
182
|
# implicitly called: rule('seq_EQUAL_expression_qmark' => 'seq_EQUAL_expression').tag suffix_qmark_one
|
182
183
|
# implicitly called: rule('seq_EQUAL_expression_qmark' => '').tag suffix_qmark_none
|
183
|
-
expect(instance.productions.size).to eq(
|
184
|
+
expect(instance.productions.size).to eq(3)
|
184
185
|
first_prod = instance.productions.first
|
185
186
|
expect(first_prod.lhs.name).to eq('var_decl')
|
186
|
-
expect(first_prod.rhs.members[2].name).to eq('
|
187
|
-
(
|
188
|
-
expect(p0.lhs.name).to eq('
|
189
|
-
expect(p0.rhs[0].name).to eq('EQUAL')
|
190
|
-
expect(p0.rhs[1].name).to eq('expression')
|
191
|
-
expect(p0.name).to eq('return_children')
|
192
|
-
|
193
|
-
expect(p1.lhs.name).to eq('
|
194
|
-
expect(p1.rhs[0].name).to eq('
|
195
|
-
expect(p1.name).to eq('
|
196
|
-
|
197
|
-
expect(
|
187
|
+
expect(first_prod.rhs.members[2].name).to eq('rep_seq_EQUAL_expression_qmark')
|
188
|
+
(p1, p2) = instance.productions[1..2]
|
189
|
+
# expect(p0.lhs.name).to eq('rep_seq_EQUAL_expression_qmark')
|
190
|
+
# expect(p0.rhs[0].name).to eq('EQUAL')
|
191
|
+
# expect(p0.rhs[1].name).to eq('expression')
|
192
|
+
# expect(p0.name).to eq('return_children')
|
193
|
+
|
194
|
+
expect(p1.lhs.name).to eq('rep_seq_EQUAL_expression_qmark')
|
195
|
+
expect(p1.rhs[0].name).to eq('EQUAL')
|
196
|
+
expect(p1.rhs[1].name).to eq('expression')
|
197
|
+
# expect(p1.rhs[0].name).to eq('seq_EQUAL_expression')
|
198
|
+
expect(p1.name).to eq('return_children') # TODO _qmark_one
|
199
|
+
|
200
|
+
expect(p2.lhs.name).to eq('rep_seq_EQUAL_expression_qmark')
|
198
201
|
expect(p2.rhs).to be_empty
|
199
202
|
expect(p2.name).to eq('_qmark_none')
|
200
203
|
end
|
@@ -212,7 +215,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
212
215
|
expect(instance.productions.size).to eq(4)
|
213
216
|
first_prod = instance.productions.first
|
214
217
|
expect(first_prod.lhs.name).to eq('logic_or')
|
215
|
-
expect(first_prod.rhs.members[1].name).to eq('
|
218
|
+
expect(first_prod.rhs.members[1].name).to eq('rep_seq_OR_logic_and_star')
|
216
219
|
|
217
220
|
(p0, p1, p2) = instance.productions[1..3]
|
218
221
|
expect(p0.lhs.name).to eq('seq_OR_logic_and')
|
@@ -220,12 +223,12 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
220
223
|
expect(p0.rhs[1].name).to eq('logic_and')
|
221
224
|
expect(p0.name).to eq('return_children')
|
222
225
|
|
223
|
-
expect(p1.lhs.name).to eq('
|
224
|
-
expect(p1.rhs[0].name).to eq('
|
226
|
+
expect(p1.lhs.name).to eq('rep_seq_OR_logic_and_star')
|
227
|
+
expect(p1.rhs[0].name).to eq('rep_seq_OR_logic_and_star')
|
225
228
|
expect(p1.rhs[1].name).to eq('seq_OR_logic_and')
|
226
229
|
expect(p1.name).to eq('_star_more')
|
227
230
|
|
228
|
-
expect(p2.lhs.name).to eq('
|
231
|
+
expect(p2.lhs.name).to eq('rep_seq_OR_logic_and_star')
|
229
232
|
expect(p2.rhs).to be_empty
|
230
233
|
expect(p2.name).to eq('_star_none')
|
231
234
|
end
|
@@ -243,7 +246,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
243
246
|
expect(instance.productions.size).to eq(4)
|
244
247
|
first_prod = instance.productions.first
|
245
248
|
expect(first_prod.lhs.name).to eq('path')
|
246
|
-
expect(first_prod.rhs.members[1].name).to eq('
|
249
|
+
expect(first_prod.rhs.members[1].name).to eq('rep_seq_TO_POINT_plus')
|
247
250
|
|
248
251
|
(p0, p1, p2) = instance.productions[1..3]
|
249
252
|
expect(p0.lhs.name).to eq('seq_TO_POINT')
|
@@ -251,12 +254,12 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
251
254
|
expect(p0.rhs[1].name).to eq('POINT')
|
252
255
|
expect(p0.name).to eq('return_children')
|
253
256
|
|
254
|
-
expect(p1.lhs.name).to eq('
|
255
|
-
expect(p1.rhs[0].name).to eq('
|
257
|
+
expect(p1.lhs.name).to eq('rep_seq_TO_POINT_plus')
|
258
|
+
expect(p1.rhs[0].name).to eq('rep_seq_TO_POINT_plus')
|
256
259
|
expect(p1.rhs[1].name).to eq('seq_TO_POINT')
|
257
260
|
expect(p1.name).to eq('_plus_more')
|
258
261
|
|
259
|
-
expect(p2.lhs.name).to eq('
|
262
|
+
expect(p2.lhs.name).to eq('rep_seq_TO_POINT_plus')
|
260
263
|
expect(p2.rhs[0].name).to eq('seq_TO_POINT')
|
261
264
|
expect(p2.name).to eq('_plus_one')
|
262
265
|
end
|
@@ -268,29 +271,30 @@ module Rley # Open this namespace to avoid module qualifier prefixes
|
|
268
271
|
instance.rule('if_stmt' => st)
|
269
272
|
instance.grammar_complete!
|
270
273
|
|
271
|
-
# implicitly called: rule('
|
272
|
-
# implicitly called: rule('
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
expect(
|
277
|
-
expect(
|
278
|
-
|
279
|
-
(p0
|
280
|
-
expect(p0.
|
281
|
-
expect(p0.
|
282
|
-
expect(p0.
|
283
|
-
expect(p0.
|
284
|
-
expect(p0.constraints.
|
285
|
-
|
286
|
-
expect(
|
287
|
-
expect(
|
288
|
-
|
289
|
-
expect(p1.
|
290
|
-
expect(p1.
|
291
|
-
expect(p1.
|
292
|
-
|
293
|
-
|
274
|
+
# implicitly called: rule('rep_seq_ELSE_stmt_qmark' => 'ELSE stmt').tag return_children'
|
275
|
+
# implicitly called: rule('rep_seq_ELSE_stmt_qmark' => '').tag suffix_qmark_none
|
276
|
+
expect(instance.productions.size).to eq(3)
|
277
|
+
(p0, p1, p2) = instance.productions[0..2]
|
278
|
+
expect(p0.lhs.name).to eq('if_stmt')
|
279
|
+
expect(p0.rhs.members[5].name).to eq('rep_seq_ELSE_stmt_qmark')
|
280
|
+
# expect(p0.lhs.name).to eq('seq_ELSE_stmt')
|
281
|
+
# expect(p0.rhs[0].name).to eq('ELSE')
|
282
|
+
# expect(p0.rhs[1].name).to eq('stmt')
|
283
|
+
# expect(p0.name).to eq('return_children')
|
284
|
+
# expect(p0.constraints.size).to eq(1)
|
285
|
+
# expect(p0.constraints[0]).to be_kind_of(Syntax::MatchClosest)
|
286
|
+
# expect(p0.constraints[0].idx_symbol).to eq(0) # ELSE is on position 0
|
287
|
+
# expect(p0.constraints[0].closest_symb).to eq('IF')
|
288
|
+
|
289
|
+
expect(p1.lhs.name).to eq('rep_seq_ELSE_stmt_qmark')
|
290
|
+
expect(p1.rhs[0].name).to eq('ELSE')
|
291
|
+
expect(p1.rhs[1].name).to eq('stmt')
|
292
|
+
expect(p1.name).to eq('return_children')
|
293
|
+
expect(p1.constraints.size).to eq(1)
|
294
|
+
expect(p1.constraints[0]).to be_kind_of(Syntax::MatchClosest)
|
295
|
+
expect(p1.constraints[0].closest_symb).to eq('IF')
|
296
|
+
|
297
|
+
expect(p2.lhs.name).to eq('rep_seq_ELSE_stmt_qmark')
|
294
298
|
expect(p2.rhs).to be_empty
|
295
299
|
expect(p2.name).to eq('_qmark_none')
|
296
300
|
end
|
@@ -2,12 +2,12 @@
|
|
2
2
|
|
3
3
|
require_relative '../../spec_helper' # Use the RSpec framework
|
4
4
|
|
5
|
-
require_relative '../../../lib/rley/
|
5
|
+
require_relative '../../../lib/rley/rgn/ast_builder'
|
6
6
|
# Load the class under test
|
7
|
-
require_relative '../../../lib/rley/
|
7
|
+
require_relative '../../../lib/rley/rgn/parser'
|
8
8
|
|
9
9
|
module Rley
|
10
|
-
module
|
10
|
+
module RGN
|
11
11
|
describe Parser do
|
12
12
|
subject { Parser.new }
|
13
13
|
|
@@ -44,7 +44,7 @@ module Rley
|
|
44
44
|
it 'should parse single symbol names' do
|
45
45
|
samples = %w[IF ifCondition statement]
|
46
46
|
|
47
|
-
# One drawback
|
47
|
+
# One drawback of CSTs: they have a deeply nested structure
|
48
48
|
samples.each do |source|
|
49
49
|
ptree = subject.parse(source)
|
50
50
|
expect(ptree.root).to be_kind_of(Rley::PTree::NonTerminalNode)
|
@@ -82,7 +82,7 @@ module Rley
|
|
82
82
|
ptree = subject.parse(source)
|
83
83
|
expect(ptree.root).to be_kind_of(SymbolNode)
|
84
84
|
expect(ptree.root.name).to eq(source)
|
85
|
-
expect(ptree.root.
|
85
|
+
expect(ptree.root.annotation).to be_empty
|
86
86
|
end
|
87
87
|
end
|
88
88
|
|
@@ -103,8 +103,10 @@ module Rley
|
|
103
103
|
optional = 'member_seq?'
|
104
104
|
|
105
105
|
ptree = subject.parse(optional)
|
106
|
-
expect(ptree.root).to be_kind_of(
|
107
|
-
expect(ptree.root.name).to eq('
|
106
|
+
expect(ptree.root).to be_kind_of(RepetitionNode)
|
107
|
+
expect(ptree.root.name).to eq('rep_member_seq_qmark')
|
108
|
+
expect(ptree.root.child).to be_kind_of(SymbolNode)
|
109
|
+
expect(ptree.root.child.name).to eq('member_seq')
|
108
110
|
expect(ptree.root.repetition).to eq(:zero_or_one)
|
109
111
|
end
|
110
112
|
|
@@ -112,8 +114,10 @@ module Rley
|
|
112
114
|
one_or_more = 'member+'
|
113
115
|
|
114
116
|
ptree = subject.parse(one_or_more)
|
115
|
-
expect(ptree.root).to be_kind_of(
|
116
|
-
expect(ptree.root.name).to eq('
|
117
|
+
expect(ptree.root).to be_kind_of(RepetitionNode)
|
118
|
+
expect(ptree.root.name).to eq('rep_member_plus')
|
119
|
+
expect(ptree.root.child).to be_kind_of(SymbolNode)
|
120
|
+
expect(ptree.root.child.name).to eq('member')
|
117
121
|
expect(ptree.root.repetition).to eq(:one_or_more)
|
118
122
|
end
|
119
123
|
|
@@ -122,12 +126,14 @@ module Rley
|
|
122
126
|
|
123
127
|
ptree = subject.parse(zero_or_more)
|
124
128
|
expect(ptree.root).to be_kind_of(SequenceNode)
|
125
|
-
expect(ptree.root.
|
126
|
-
expect(ptree.root.subnodes[0]
|
129
|
+
expect(ptree.root.name).to eq('seq_rep_declaration_star_EOF')
|
130
|
+
expect(ptree.root.subnodes[0]).to be_kind_of(RepetitionNode)
|
131
|
+
expect(ptree.root.subnodes[0].name).to eq('rep_declaration_star')
|
127
132
|
expect(ptree.root.subnodes[0].repetition).to eq(:zero_or_more)
|
133
|
+
expect(ptree.root.subnodes[0].child).to be_kind_of(SymbolNode)
|
134
|
+
expect(ptree.root.subnodes[0].child.name).to eq('declaration')
|
128
135
|
expect(ptree.root.subnodes[1]).to be_kind_of(SymbolNode)
|
129
136
|
expect(ptree.root.subnodes[1].name).to eq('EOF')
|
130
|
-
expect(ptree.root.subnodes[1].repetition).to eq(:exactly_one)
|
131
137
|
end
|
132
138
|
|
133
139
|
it 'should parse a grouping with a modifier' do
|
@@ -141,21 +147,25 @@ module Rley
|
|
141
147
|
expect(ptree.root.subnodes[1].name).to eq('ifCondition')
|
142
148
|
expect(ptree.root.subnodes[2]).to be_kind_of(SymbolNode)
|
143
149
|
expect(ptree.root.subnodes[2].name).to eq('statement')
|
144
|
-
expect(ptree.root.subnodes[3]).to be_kind_of(
|
150
|
+
expect(ptree.root.subnodes[3]).to be_kind_of(RepetitionNode)
|
151
|
+
expect(ptree.root.subnodes[3].name).to eq('rep_seq_ELSE_statement_qmark')
|
145
152
|
expect(ptree.root.subnodes[3].repetition).to eq(:zero_or_one)
|
146
|
-
expect(ptree.root.subnodes[3].
|
147
|
-
expect(ptree.root.subnodes[3].subnodes[0]
|
148
|
-
expect(ptree.root.subnodes[3].subnodes[
|
149
|
-
expect(ptree.root.subnodes[3].subnodes[1]
|
153
|
+
expect(ptree.root.subnodes[3].child).to be_kind_of(SequenceNode)
|
154
|
+
expect(ptree.root.subnodes[3].child.subnodes[0]).to be_kind_of(SymbolNode)
|
155
|
+
expect(ptree.root.subnodes[3].child.subnodes[0].name).to eq('ELSE')
|
156
|
+
expect(ptree.root.subnodes[3].child.subnodes[1]).to be_kind_of(SymbolNode)
|
157
|
+
expect(ptree.root.subnodes[3].child.subnodes[1].name).to eq('statement')
|
150
158
|
end
|
151
159
|
|
152
160
|
it 'should parse an annotated symbol' do
|
153
161
|
optional = 'member_seq{repeat: 0..1}'
|
154
162
|
|
155
163
|
ptree = subject.parse(optional)
|
156
|
-
expect(ptree.root).to be_kind_of(
|
157
|
-
expect(ptree.root.name).to eq('
|
164
|
+
expect(ptree.root).to be_kind_of(RepetitionNode)
|
165
|
+
expect(ptree.root.name).to eq('rep_member_seq_qmark')
|
158
166
|
expect(ptree.root.repetition).to eq(:zero_or_one)
|
167
|
+
expect(ptree.root.child).to be_kind_of(SymbolNode)
|
168
|
+
expect(ptree.root.child.name).to eq('member_seq')
|
159
169
|
end
|
160
170
|
|
161
171
|
it 'should parse a grouping with embedded annotation' do
|
@@ -170,12 +180,14 @@ module Rley
|
|
170
180
|
expect(ptree.root.subnodes[2]).to be_kind_of(SymbolNode)
|
171
181
|
expect(ptree.root.subnodes[2].name).to eq('statement')
|
172
182
|
optional = ptree.root.subnodes[3]
|
173
|
-
expect(optional).to be_kind_of(
|
183
|
+
expect(optional).to be_kind_of(RepetitionNode)
|
184
|
+
expect(optional.name).to eq('rep_seq_ELSE_statement_qmark')
|
174
185
|
expect(optional.repetition).to eq(:zero_or_one)
|
175
|
-
expect(optional.
|
176
|
-
expect(optional.subnodes[0]
|
177
|
-
expect(optional.subnodes[0].
|
178
|
-
expect(optional.subnodes[
|
186
|
+
expect(optional.child).to be_kind_of(SequenceNode)
|
187
|
+
expect(optional.child.subnodes[0]).to be_kind_of(SymbolNode)
|
188
|
+
expect(optional.child.subnodes[0].name).to eq('ELSE')
|
189
|
+
expect(optional.child.subnodes[0].annotation).to eq({ 'match_closest' => 'IF' })
|
190
|
+
expect(optional.child.subnodes[1].name).to eq('statement')
|
179
191
|
end
|
180
192
|
end # context
|
181
193
|
end # describe
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../../spec_helper'
|
4
|
+
|
5
|
+
require_relative '../../../lib/rley/lexical/token'
|
6
|
+
require_relative '../../../lib/rley/rgn/symbol_node'
|
7
|
+
|
8
|
+
# Load the class under test
|
9
|
+
require_relative '../../../lib/rley/rgn/repetition_node'
|
10
|
+
|
11
|
+
module Rley # Open this namespace to avoid module qualifier prefixes
|
12
|
+
module RGN # Open this namespace to avoid module qualifier prefixes
|
13
|
+
describe RepetitionNode do
|
14
|
+
let(:a_name) { 'arguments' }
|
15
|
+
let(:a_pos) { Lexical::Position.new(3, 4) }
|
16
|
+
let(:a_child) { SymbolNode.new(a_pos, a_name) }
|
17
|
+
let(:star) { :zero_or_more }
|
18
|
+
|
19
|
+
# Default instantiation rule
|
20
|
+
subject { RepetitionNode.new(a_child, star) }
|
21
|
+
|
22
|
+
context 'Initialization:' do
|
23
|
+
it 'should be created with a child node and a symbol' do
|
24
|
+
expect { RepetitionNode.new(a_child, star) }.not_to raise_error
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should know its child' do
|
28
|
+
expect(subject.subnodes.size).to eq(1)
|
29
|
+
expect(subject.subnodes.first).to eq(a_child)
|
30
|
+
expect(subject.child).to eq(a_child)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should know its repetition' do
|
34
|
+
expect(subject.repetition).to eq(star)
|
35
|
+
end
|
36
|
+
end # context
|
37
|
+
|
38
|
+
context 'Provided services:' do
|
39
|
+
it 'should know its name' do
|
40
|
+
# Case repetition == :zero_or_one
|
41
|
+
instance = RepetitionNode.new(a_child, :zero_or_one)
|
42
|
+
expect(instance.name).to eq('rep_arguments_qmark')
|
43
|
+
|
44
|
+
# Case repetition == :zero_or_more
|
45
|
+
expect(subject.name).to eq('rep_arguments_star')
|
46
|
+
|
47
|
+
# Case repetition == :one_or_more
|
48
|
+
instance = RepetitionNode.new(a_child, :one_or_more)
|
49
|
+
expect(instance.name).to eq('rep_arguments_plus')
|
50
|
+
end
|
51
|
+
end # context
|
52
|
+
end # describe
|
53
|
+
end # module
|
54
|
+
end # module
|
55
|
+
|
56
|
+
# End of file
|