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