rley 0.8.06 → 0.8.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +23 -2
  3. data/CHANGELOG.md +21 -1
  4. data/LICENSE.txt +1 -1
  5. data/README.md +1 -1
  6. data/appveyor.yml +1 -3
  7. data/examples/NLP/benchmark_pico_en.rb +6 -6
  8. data/examples/NLP/engtagger.rb +6 -6
  9. data/examples/general/calc_iter1/calc_lexer.rb +1 -1
  10. data/examples/general/calc_iter2/calc_lexer.rb +1 -1
  11. data/examples/general/left.rb +1 -1
  12. data/examples/general/right.rb +1 -1
  13. data/examples/tokenizer/loxxy_raw_scanner.rex.rb +3 -0
  14. data/examples/tokenizer/loxxy_tokenizer.rb +2 -2
  15. data/examples/tokenizer/run_tokenizer.rb +1 -1
  16. data/examples/tokenizer/{tokens.yaml → tokens.yml} +0 -0
  17. data/lib/rley/constants.rb +1 -1
  18. data/lib/rley/engine.rb +2 -2
  19. data/lib/rley/interface.rb +3 -3
  20. data/lib/rley/lexical/token.rb +1 -1
  21. data/lib/rley/ptree/non_terminal_node.rb +1 -1
  22. data/lib/rley/rgn/all_notation_nodes.rb +5 -0
  23. data/lib/rley/{notation → rgn}/ast_builder.rb +19 -12
  24. data/lib/rley/{notation → rgn}/ast_node.rb +13 -12
  25. data/lib/rley/{notation → rgn}/ast_visitor.rb +10 -10
  26. data/lib/rley/rgn/composite_node.rb +28 -0
  27. data/lib/rley/{notation → rgn}/grammar.rb +1 -1
  28. data/lib/rley/{notation → rgn}/grammar_builder.rb +86 -124
  29. data/lib/rley/{notation → rgn}/parser.rb +7 -7
  30. data/lib/rley/rgn/repetition_node.rb +62 -0
  31. data/lib/rley/rgn/sequence_node.rb +30 -0
  32. data/lib/rley/{notation → rgn}/symbol_node.rb +15 -7
  33. data/lib/rley/{notation → rgn}/tokenizer.rb +71 -60
  34. data/lib/rley/syntax/grm_symbol.rb +0 -4
  35. data/lib/rley/syntax/non_terminal.rb +4 -0
  36. data/lib/rley/syntax/terminal.rb +10 -6
  37. data/spec/rley/parser/dangling_else_spec.rb +3 -3
  38. data/spec/rley/parser/gfg_earley_parser_spec.rb +48 -50
  39. data/spec/rley/{notation → rgn}/grammar_builder_spec.rb +58 -54
  40. data/spec/rley/{notation → rgn}/parser_spec.rb +36 -24
  41. data/spec/rley/rgn/repetition_node_spec.rb +56 -0
  42. data/spec/rley/rgn/sequence_node_spec.rb +48 -0
  43. data/spec/rley/rgn/symbol_node_spec.rb +33 -0
  44. data/spec/rley/{notation → rgn}/tokenizer_spec.rb +2 -2
  45. data/spec/rley/support/ambiguous_grammar_helper.rb +2 -2
  46. data/spec/rley/support/grammar_int_seq_helper.rb +2 -2
  47. metadata +40 -33
  48. data/lib/rley/notation/all_notation_nodes.rb +0 -4
  49. data/lib/rley/notation/grouping_node.rb +0 -23
  50. data/lib/rley/notation/sequence_node.rb +0 -35
@@ -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
- # Constructor.
11
- # @param aName [String] The name of the grammar symbol.
12
- def initialize(aName)
13
- super(aName)
14
- self.generative = true
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
- return true
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/notation/grammar_builder'
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::Notation::GrammarBuilder.new do
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::Notation::GrammarBuilder.new do
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', # Initialization
296
- 'S => . sequence | 0', # start rule
297
- 'S => . | 0', # start rule
298
- '.sequence | 0', # call rule
299
- 'S. | 0', # exit rule
300
- 'sequence => . sequence comma integer | 0', # start rule
301
- 'sequence => . integer | 0', # start rule
302
- '.integer | 0', # call rule
303
- 'integer => . digit_plus | 0', # start rule
304
- '.digit_plus | 0', # call rule
305
- 'digit_plus => . digit_plus digit | 0', # start rule (generated)
306
- 'digit_plus => . digit | 0' # start rule (generated)
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
- 'digit_plus => digit . | 0', # Scan
314
- 'digit_plus. | 0', # exit rule
315
- 'integer => digit_plus . | 0', # end rule
316
- 'digit_plus => digit_plus . digit | 0', # rule (generated)
317
- 'integer. | 0', # exit rule
318
- 'sequence => integer . | 0', # end rule
319
- 'sequence. | 0', # exit rule
320
- 'S => sequence . | 0', # end rule
321
- 'sequence => sequence . comma integer | 0', # rule
322
- 'S. | 0' # exit rule
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', # Scan
330
- '.integer | 2', # call rule
331
- 'integer => . digit_plus | 2', # start rule
332
- '.digit_plus | 2', # call rule
333
- 'digit_plus => . digit_plus digit | 2', # start rule (generated)
334
- 'digit_plus => . digit | 2' # start rule (generated)
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
- 'digit_plus => digit . | 2', # Scan
342
- 'digit_plus. | 2', # exit rule
343
- 'integer => digit_plus . | 2', # end rule
344
- 'digit_plus => digit_plus . digit | 2', # rule (generated)
345
- 'integer. | 2', # exit rule
346
- 'sequence => sequence comma integer . | 0', # rule
347
- 'sequence. | 0', # exit rule
348
- 'S => sequence . | 0', # end rule
349
- 'sequence => sequence . comma integer | 0' # rule
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
- 'digit_plus => digit_plus digit . | 2', # Scan
357
- 'digit_plus. | 2', # exit rule
358
- 'integer => digit_plus . | 2', # end rule
359
- 'digit_plus => digit_plus . digit | 2', #
360
- 'integer. | 2', # exit rule
361
- 'sequence => sequence comma integer . | 0', # rule
362
- 'sequence. | 0', # exit rule
363
- 'S => sequence . | 0' # end rule
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 = Notation::GrammarBuilder.new do
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 = Notation::GrammarBuilder.new do
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 = Notation::GrammarBuilder.new do
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/notation/grammar_builder'
6
+ require_relative '../../../lib/rley/rgn/grammar_builder'
7
7
 
8
8
  module Rley # Open this namespace to avoid module qualifier prefixes
9
- module Notation # Open this namespace to avoid module qualifier prefixes
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 == 'arguments_qmark' }
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('arguments_qmark')
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('declaration_star' => 'declaration_star declaration').tag suffix_star_more
141
- # implicitly called: rule('declaration_star' => '').tag suffix_star_last
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 == 'declaration_star' }
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('declaration_star')
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 == 'digit_plus' }
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('digit_plus')
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(4)
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('seq_EQUAL_expression_qmark')
187
- (p0, p1, p2) = instance.productions[1..3]
188
- expect(p0.lhs.name).to eq('seq_EQUAL_expression')
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('seq_EQUAL_expression_qmark')
194
- expect(p1.rhs[0].name).to eq('seq_EQUAL_expression')
195
- expect(p1.name).to eq('_qmark_one')
196
-
197
- expect(p2.lhs.name).to eq('seq_EQUAL_expression_qmark')
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('seq_OR_logic_and_star')
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('seq_OR_logic_and_star')
224
- expect(p1.rhs[0].name).to eq('seq_OR_logic_and_star')
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('seq_OR_logic_and_star')
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('seq_TO_POINT_plus')
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('seq_TO_POINT_plus')
255
- expect(p1.rhs[0].name).to eq('seq_TO_POINT_plus')
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('seq_TO_POINT_plus')
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('seq_ELSE_stmt' => 'ELSE stmt').tag 'return_children'
272
- # implicitly called: rule('seq_ELSE_stmt_qmark' => 'seq_ELSE_stmt ').tag suffix_plus_more
273
- # implicitly called: rule('seq_ELSE_stmt_qmark' => '').tag suffix_plus_one
274
- expect(instance.productions.size).to eq(4)
275
- first_prod = instance.productions.first
276
- expect(first_prod.lhs.name).to eq('if_stmt')
277
- expect(first_prod.rhs.members[5].name).to eq('seq_ELSE_stmt_qmark')
278
-
279
- (p0, p1, p2) = instance.productions[1..3]
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('seq_ELSE_stmt_qmark')
290
- expect(p1.rhs[0].name).to eq('seq_ELSE_stmt')
291
- expect(p1.name).to eq('_qmark_one')
292
-
293
- expect(p2.lhs.name).to eq('seq_ELSE_stmt_qmark')
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/notation/ast_builder'
5
+ require_relative '../../../lib/rley/rgn/ast_builder'
6
6
  # Load the class under test
7
- require_relative '../../../lib/rley/notation/parser'
7
+ require_relative '../../../lib/rley/rgn/parser'
8
8
 
9
9
  module Rley
10
- module Notation
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 od CSTs: they have a deeply nested structure
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.repetition).to eq(:exactly_one)
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(SymbolNode)
107
- expect(ptree.root.name).to eq('member_seq')
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(SymbolNode)
116
- expect(ptree.root.name).to eq('member')
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.subnodes[0]).to be_kind_of(SymbolNode)
126
- expect(ptree.root.subnodes[0].name).to eq('declaration')
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(SequenceNode)
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].subnodes[0]).to be_kind_of(SymbolNode)
147
- expect(ptree.root.subnodes[3].subnodes[0].name).to eq('ELSE')
148
- expect(ptree.root.subnodes[3].subnodes[1]).to be_kind_of(SymbolNode)
149
- expect(ptree.root.subnodes[3].subnodes[1].name).to eq('statement')
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(SymbolNode)
157
- expect(ptree.root.name).to eq('member_seq')
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(SequenceNode)
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.subnodes[0]).to be_kind_of(SymbolNode)
176
- expect(optional.subnodes[0].name).to eq('ELSE')
177
- expect(optional.subnodes[0].annotation).to eq({ 'match_closest' => 'IF' })
178
- expect(optional.subnodes[1].name).to eq('statement')
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