rley 0.7.06 → 0.8.01

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 (167) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +362 -62
  3. data/.travis.yml +6 -6
  4. data/CHANGELOG.md +20 -4
  5. data/LICENSE.txt +1 -1
  6. data/README.md +7 -7
  7. data/examples/NLP/engtagger.rb +193 -190
  8. data/examples/NLP/nano_eng/nano_en_demo.rb +7 -11
  9. data/examples/NLP/nano_eng/nano_grammar.rb +21 -21
  10. data/examples/NLP/pico_en_demo.rb +2 -2
  11. data/examples/data_formats/JSON/cli_options.rb +1 -1
  12. data/examples/data_formats/JSON/json_ast_builder.rb +21 -27
  13. data/examples/data_formats/JSON/json_ast_nodes.rb +12 -21
  14. data/examples/data_formats/JSON/json_demo.rb +1 -2
  15. data/examples/data_formats/JSON/json_grammar.rb +13 -13
  16. data/examples/data_formats/JSON/json_lexer.rb +8 -8
  17. data/examples/data_formats/JSON/json_minifier.rb +1 -1
  18. data/examples/general/calc_iter1/calc_ast_builder.rb +13 -10
  19. data/examples/general/calc_iter1/calc_ast_nodes.rb +23 -37
  20. data/examples/general/calc_iter1/calc_grammar.rb +7 -6
  21. data/examples/general/calc_iter1/calc_lexer.rb +6 -4
  22. data/examples/general/calc_iter1/spec/calculator_spec.rb +5 -5
  23. data/examples/general/calc_iter2/calc_ast_builder.rb +5 -3
  24. data/examples/general/calc_iter2/calc_ast_nodes.rb +27 -43
  25. data/examples/general/calc_iter2/calc_grammar.rb +12 -12
  26. data/examples/general/calc_iter2/calc_lexer.rb +11 -10
  27. data/examples/general/calc_iter2/spec/calculator_spec.rb +26 -26
  28. data/examples/general/left.rb +2 -2
  29. data/examples/general/right.rb +2 -2
  30. data/lib/rley.rb +1 -1
  31. data/lib/rley/base/dotted_item.rb +28 -31
  32. data/lib/rley/base/grm_items_builder.rb +6 -0
  33. data/lib/rley/constants.rb +2 -2
  34. data/lib/rley/engine.rb +22 -25
  35. data/lib/rley/formatter/asciitree.rb +3 -3
  36. data/lib/rley/formatter/bracket_notation.rb +1 -8
  37. data/lib/rley/formatter/debug.rb +6 -6
  38. data/lib/rley/formatter/json.rb +2 -2
  39. data/lib/rley/gfg/call_edge.rb +1 -1
  40. data/lib/rley/gfg/edge.rb +5 -5
  41. data/lib/rley/gfg/end_vertex.rb +2 -6
  42. data/lib/rley/gfg/epsilon_edge.rb +1 -5
  43. data/lib/rley/gfg/grm_flow_graph.rb +27 -23
  44. data/lib/rley/gfg/item_vertex.rb +10 -10
  45. data/lib/rley/gfg/non_terminal_vertex.rb +4 -4
  46. data/lib/rley/gfg/scan_edge.rb +1 -1
  47. data/lib/rley/gfg/shortcut_edge.rb +2 -2
  48. data/lib/rley/gfg/start_vertex.rb +4 -8
  49. data/lib/rley/gfg/vertex.rb +43 -39
  50. data/lib/rley/interface.rb +16 -0
  51. data/lib/rley/lexical/token_range.rb +6 -6
  52. data/lib/rley/notation/all_notation_nodes.rb +2 -0
  53. data/lib/rley/notation/ast_builder.rb +191 -0
  54. data/lib/rley/notation/ast_node.rb +44 -0
  55. data/lib/rley/notation/ast_visitor.rb +113 -0
  56. data/lib/rley/notation/grammar.rb +49 -0
  57. data/lib/rley/notation/grammar_builder.rb +504 -0
  58. data/lib/rley/notation/grouping_node.rb +23 -0
  59. data/lib/rley/notation/parser.rb +56 -0
  60. data/lib/rley/notation/sequence_node.rb +35 -0
  61. data/lib/rley/notation/symbol_node.rb +29 -0
  62. data/lib/rley/notation/tokenizer.rb +192 -0
  63. data/lib/rley/parse_forest_visitor.rb +5 -5
  64. data/lib/rley/parse_rep/ast_base_builder.rb +48 -11
  65. data/lib/rley/parse_rep/cst_builder.rb +5 -6
  66. data/lib/rley/parse_rep/parse_forest_builder.rb +22 -18
  67. data/lib/rley/parse_rep/parse_forest_factory.rb +3 -3
  68. data/lib/rley/parse_rep/parse_rep_creator.rb +14 -16
  69. data/lib/rley/parse_rep/parse_tree_builder.rb +4 -4
  70. data/lib/rley/parse_rep/parse_tree_factory.rb +27 -27
  71. data/lib/rley/parse_tree_visitor.rb +1 -1
  72. data/lib/rley/parser/error_reason.rb +4 -5
  73. data/lib/rley/parser/gfg_chart.rb +118 -26
  74. data/lib/rley/parser/gfg_parsing.rb +22 -33
  75. data/lib/rley/parser/parse_entry.rb +25 -31
  76. data/lib/rley/parser/parse_entry_set.rb +19 -16
  77. data/lib/rley/parser/parse_entry_tracker.rb +4 -4
  78. data/lib/rley/parser/parse_tracer.rb +13 -13
  79. data/lib/rley/parser/parse_walker_factory.rb +23 -28
  80. data/lib/rley/ptree/non_terminal_node.rb +7 -5
  81. data/lib/rley/ptree/parse_tree.rb +3 -3
  82. data/lib/rley/ptree/parse_tree_node.rb +5 -5
  83. data/lib/rley/ptree/terminal_node.rb +7 -7
  84. data/lib/rley/rley_error.rb +12 -12
  85. data/lib/rley/sppf/alternative_node.rb +6 -6
  86. data/lib/rley/sppf/composite_node.rb +7 -7
  87. data/lib/rley/sppf/epsilon_node.rb +3 -3
  88. data/lib/rley/sppf/leaf_node.rb +3 -3
  89. data/lib/rley/sppf/parse_forest.rb +16 -16
  90. data/lib/rley/sppf/sppf_node.rb +7 -8
  91. data/lib/rley/sppf/token_node.rb +3 -3
  92. data/lib/rley/syntax/{grammar_builder.rb → base_grammar_builder.rb} +61 -23
  93. data/lib/rley/syntax/grammar.rb +5 -5
  94. data/lib/rley/syntax/grm_symbol.rb +7 -7
  95. data/lib/rley/syntax/match_closest.rb +43 -0
  96. data/lib/rley/syntax/non_terminal.rb +9 -15
  97. data/lib/rley/syntax/production.rb +16 -10
  98. data/lib/rley/syntax/symbol_seq.rb +7 -9
  99. data/lib/rley/syntax/terminal.rb +4 -5
  100. data/lib/rley/syntax/verbatim_symbol.rb +3 -3
  101. data/lib/support/base_tokenizer.rb +19 -18
  102. data/spec/rley/base/dotted_item_spec.rb +2 -2
  103. data/spec/rley/engine_spec.rb +23 -21
  104. data/spec/rley/formatter/asciitree_spec.rb +7 -7
  105. data/spec/rley/formatter/bracket_notation_spec.rb +13 -13
  106. data/spec/rley/formatter/json_spec.rb +1 -1
  107. data/spec/rley/gfg/end_vertex_spec.rb +5 -5
  108. data/spec/rley/gfg/grm_flow_graph_spec.rb +2 -2
  109. data/spec/rley/gfg/item_vertex_spec.rb +10 -10
  110. data/spec/rley/gfg/non_terminal_vertex_spec.rb +3 -3
  111. data/spec/rley/gfg/shortcut_edge_spec.rb +1 -1
  112. data/spec/rley/gfg/start_vertex_spec.rb +5 -5
  113. data/spec/rley/gfg/vertex_spec.rb +3 -3
  114. data/spec/rley/lexical/token_range_spec.rb +16 -16
  115. data/spec/rley/lexical/token_spec.rb +2 -2
  116. data/spec/rley/notation/grammar_builder_spec.rb +302 -0
  117. data/spec/rley/notation/parser_spec.rb +184 -0
  118. data/spec/rley/notation/tokenizer_spec.rb +370 -0
  119. data/spec/rley/parse_forest_visitor_spec.rb +165 -163
  120. data/spec/rley/parse_rep/ambiguous_parse_spec.rb +44 -44
  121. data/spec/rley/parse_rep/ast_builder_spec.rb +6 -7
  122. data/spec/rley/parse_rep/cst_builder_spec.rb +5 -5
  123. data/spec/rley/parse_rep/groucho_spec.rb +24 -26
  124. data/spec/rley/parse_rep/parse_forest_builder_spec.rb +27 -27
  125. data/spec/rley/parse_rep/parse_forest_factory_spec.rb +8 -8
  126. data/spec/rley/parse_rep/parse_tree_factory_spec.rb +3 -3
  127. data/spec/rley/parse_tree_visitor_spec.rb +10 -8
  128. data/spec/rley/parser/dangling_else_spec.rb +445 -0
  129. data/spec/rley/parser/error_reason_spec.rb +6 -6
  130. data/spec/rley/parser/gfg_earley_parser_spec.rb +120 -12
  131. data/spec/rley/parser/gfg_parsing_spec.rb +6 -13
  132. data/spec/rley/parser/parse_entry_spec.rb +19 -19
  133. data/spec/rley/parser/parse_walker_factory_spec.rb +10 -10
  134. data/spec/rley/ptree/non_terminal_node_spec.rb +5 -3
  135. data/spec/rley/ptree/parse_tree_node_spec.rb +4 -4
  136. data/spec/rley/ptree/terminal_node_spec.rb +6 -6
  137. data/spec/rley/sppf/alternative_node_spec.rb +6 -6
  138. data/spec/rley/sppf/non_terminal_node_spec.rb +3 -3
  139. data/spec/rley/sppf/token_node_spec.rb +4 -4
  140. data/spec/rley/support/ambiguous_grammar_helper.rb +4 -5
  141. data/spec/rley/support/grammar_abc_helper.rb +3 -5
  142. data/spec/rley/support/grammar_ambig01_helper.rb +5 -6
  143. data/spec/rley/support/grammar_arr_int_helper.rb +5 -6
  144. data/spec/rley/support/grammar_b_expr_helper.rb +5 -6
  145. data/spec/rley/support/grammar_int_seq_helper.rb +51 -0
  146. data/spec/rley/support/grammar_l0_helper.rb +14 -17
  147. data/spec/rley/support/grammar_pb_helper.rb +8 -7
  148. data/spec/rley/support/grammar_sppf_helper.rb +3 -3
  149. data/spec/rley/syntax/{grammar_builder_spec.rb → base_grammar_builder_spec.rb} +35 -16
  150. data/spec/rley/syntax/grammar_spec.rb +6 -6
  151. data/spec/rley/syntax/grm_symbol_spec.rb +1 -1
  152. data/spec/rley/syntax/match_closest_spec.rb +46 -0
  153. data/spec/rley/syntax/non_terminal_spec.rb +8 -8
  154. data/spec/rley/syntax/production_spec.rb +17 -13
  155. data/spec/rley/syntax/symbol_seq_spec.rb +2 -2
  156. data/spec/rley/syntax/terminal_spec.rb +5 -5
  157. data/spec/rley/syntax/verbatim_symbol_spec.rb +1 -1
  158. data/spec/spec_helper.rb +0 -12
  159. data/spec/support/base_tokenizer_spec.rb +7 -2
  160. metadata +48 -74
  161. data/.simplecov +0 -7
  162. data/lib/rley/parser/parse_state.rb +0 -83
  163. data/lib/rley/parser/parse_state_tracker.rb +0 -59
  164. data/lib/rley/parser/state_set.rb +0 -101
  165. data/spec/rley/parser/parse_state_spec.rb +0 -125
  166. data/spec/rley/parser/parse_tracer_spec.rb +0 -200
  167. data/spec/rley/parser/state_set_spec.rb +0 -130
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Load the builder class
4
- require_relative '../../../lib/rley/syntax/grammar_builder'
4
+ require_relative '../../../lib/rley/syntax/base_grammar_builder'
5
5
  require_relative '../../../lib/support/base_tokenizer'
6
6
  require_relative '../../../lib/rley/lexical/token'
7
7
 
@@ -12,9 +12,9 @@ class GrammarPBHelper
12
12
  # expression based on example found in paper of
13
13
  # K. Pingali and G. Bilardi:
14
14
  # "A Graphical Model for Context-Free Grammar Parsing"
15
- def grammar()
15
+ def grammar
16
16
  @grammar ||= begin
17
- builder = Rley::Syntax::GrammarBuilder.new do
17
+ builder = Rley::Syntax::BaseGrammarBuilder.new do
18
18
  add_terminals('int', '+', '(', ')')
19
19
  rule 'S' => 'E'
20
20
  rule 'E' => 'int'
@@ -24,12 +24,13 @@ class GrammarPBHelper
24
24
  builder.grammar
25
25
  end
26
26
  end
27
-
27
+
28
28
  class PB_Tokenizer < BaseTokenizer
29
29
  protected
30
30
 
31
- def recognize_token()
32
- if (lexeme = scanner.scan(/[\(\)]/)) # Single characters
31
+ # rubocop: disable Lint/DuplicateBranch
32
+ def recognize_token
33
+ if (lexeme = scanner.scan(/[()]/)) # Single characters
33
34
  # Delimiters, separators => single character token
34
35
  build_token(lexeme, lexeme)
35
36
  elsif (lexeme = scanner.scan(/(?:\+)(?=\s|$)/)) # Isolated char
@@ -38,6 +39,7 @@ class GrammarPBHelper
38
39
  build_token('int', lexeme)
39
40
  end
40
41
  end
42
+ # rubocop: enable Lint/DuplicateBranch
41
43
  end # class
42
44
 
43
45
  # Basic tokenizer
@@ -46,6 +48,5 @@ class GrammarPBHelper
46
48
  tokenizer = PB_Tokenizer.new(aText)
47
49
  tokenizer.tokens
48
50
  end
49
-
50
51
  end # class
51
52
  # End of file
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Load the builder class
4
- require_relative '../../../lib/rley/syntax/grammar_builder'
4
+ require_relative '../../../lib/rley/syntax/base_grammar_builder'
5
5
 
6
6
 
7
7
  module GrammarSPPFHelper
@@ -10,8 +10,8 @@ module GrammarSPPFHelper
10
10
  # "SPPF-Style Parsing From Earley Recognizers" in
11
11
  # Notes in Theoretical Computer Science 203, (2008), pp. 53-67
12
12
  # contains a hidden left recursion and a cycle
13
- def grammar_sppf_builder()
14
- builder = Rley::Syntax::GrammarBuilder.new do
13
+ def grammar_sppf_builder
14
+ builder = Rley::Syntax::BaseGrammarBuilder.new do
15
15
  add_terminals('a', 'b')
16
16
  rule 'Phi' => 'S'
17
17
  rule 'S' => %w[A T]
@@ -3,14 +3,14 @@
3
3
  require_relative '../../spec_helper'
4
4
 
5
5
  # Load the class under test
6
- require_relative '../../../lib/rley/syntax/grammar_builder'
6
+ require_relative '../../../lib/rley/syntax/base_grammar_builder'
7
7
 
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
- describe GrammarBuilder do
10
+ describe BaseGrammarBuilder do
11
11
  context 'Initialization without argument:' do
12
12
  it 'could be created without argument' do
13
- expect { GrammarBuilder.new }.not_to raise_error
13
+ expect { BaseGrammarBuilder.new }.not_to raise_error
14
14
  end
15
15
 
16
16
  it 'should have no grammar symbols at start' do
@@ -24,13 +24,13 @@ module Rley # Open this namespace to avoid module qualifier prefixes
24
24
 
25
25
  context 'Initialization with argument:' do
26
26
  it 'could be created with a block argument' do
27
- expect do
28
- GrammarBuilder.new { nil }
27
+ expect do
28
+ BaseGrammarBuilder.new { nil }
29
29
  end.not_to raise_error
30
30
  end
31
31
 
32
32
  it 'could have grammar symbols from block argument' do
33
- instance = GrammarBuilder.new do
33
+ instance = BaseGrammarBuilder.new do
34
34
  add_terminals('a', 'b', 'c')
35
35
  end
36
36
  expect(instance.symbols.size).to eq(3)
@@ -80,7 +80,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
80
80
 
81
81
  context 'Adding productions:' do
82
82
  subject do
83
- instance = GrammarBuilder.new
83
+ instance = BaseGrammarBuilder.new
84
84
  instance.add_terminals('a', 'b', 'c')
85
85
  instance
86
86
  end
@@ -99,27 +99,46 @@ module Rley # Open this namespace to avoid module qualifier prefixes
99
99
  expect(new_prod.lhs).to eq(subject['A'])
100
100
  expect_rhs = [subject['a'], subject['A'], subject['c']]
101
101
  expect(new_prod.rhs.members).to eq(expect_rhs)
102
-
102
+
103
103
  # Try another syntax
104
104
  subject.add_production('A' => 'a A c')
105
105
  expect(subject.productions.size).to eq(3)
106
106
  new_prod = subject.productions.last
107
107
  expect(new_prod.lhs).to eq(subject['A'])
108
108
  expect_rhs = [subject['a'], subject['A'], subject['c']]
109
- expect(new_prod.rhs.members).to eq(expect_rhs)
109
+ expect(new_prod.rhs.members).to eq(expect_rhs)
110
110
 
111
- # GrammarBuilder#rule is an alias of add_production
111
+ # BaseGrammarBuilder#rule is an alias of add_production
112
112
  subject.rule('A' => ['b'])
113
113
  expect(subject.productions.size).to eq(4)
114
114
  new_prod = subject.productions.last
115
115
  expect(new_prod.lhs).to eq(subject['A'])
116
116
  expect(new_prod.rhs[0]).to eq(subject['b'])
117
117
  end
118
+
119
+ it "should support Kleene's plus" do
120
+ instance = BaseGrammarBuilder.new
121
+ instance.add_terminals('plus', 'minus', 'digit')
122
+
123
+ instance.add_production('integer' => 'value')
124
+ instance.add_production('integer' => 'sign value')
125
+ instance.add_production('sign' => 'plus')
126
+ instance.add_production('sign' => 'minus')
127
+ expect(instance.productions.size).to eq(4)
128
+ instance.add_production('value' => 'digit+')
129
+ expect(instance.productions.size).to eq(7) # Two additional rules generated
130
+ prod_plus = instance.productions.select { |prod| prod.lhs.name == 'digit_plus' }
131
+ expect(prod_plus.size).to eq(2)
132
+ last_prod = instance.productions.last
133
+ expect(last_prod.lhs.name).to eq('value')
134
+ expect(last_prod.rhs.members[0].name).to eq('digit_plus')
135
+ end
136
+
118
137
  end # context
119
138
 
120
139
  context 'Building grammar:' do
121
140
  subject do
122
- instance = GrammarBuilder.new do
141
+ instance = BaseGrammarBuilder.new do
123
142
  add_terminals('a', 'b', 'c')
124
143
  add_production('S' => ['A'])
125
144
  add_production('A' => %w[a A c])
@@ -141,14 +160,14 @@ module Rley # Open this namespace to avoid module qualifier prefixes
141
160
  end
142
161
 
143
162
  it 'should complain in absence of symbols' do
144
- instance = GrammarBuilder.new
163
+ instance = BaseGrammarBuilder.new
145
164
  err = StandardError
146
165
  msg = 'No symbol found for grammar'
147
166
  expect { instance.grammar }.to raise_error(err, msg)
148
167
  end
149
168
 
150
169
  it 'should complain in absence of productions' do
151
- instance = GrammarBuilder.new
170
+ instance = BaseGrammarBuilder.new
152
171
  instance.add_terminals('a', 'b', 'c')
153
172
  err = StandardError
154
173
  msg = 'No production found for grammar'
@@ -162,11 +181,11 @@ module Rley # Open this namespace to avoid module qualifier prefixes
162
181
  err = StandardError
163
182
  msg = 'Useless terminal symbol(s): d.'
164
183
  expect { subject.grammar }.to raise_error(err, msg)
165
-
184
+
166
185
  # Add another useless terminal
167
186
  subject.add_terminals('e')
168
187
  msg = 'Useless terminal symbol(s): d, e.'
169
- expect { subject.grammar }.to raise_error(err, msg)
188
+ expect { subject.grammar }.to raise_error(err, msg)
170
189
  end
171
190
 
172
191
  it 'should build a grammar with nullable nonterminals' do
@@ -183,7 +202,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
183
202
  t_star = VerbatimSymbol.new('*')
184
203
  t_slash = VerbatimSymbol.new('/')
185
204
 
186
- builder = GrammarBuilder.new
205
+ builder = BaseGrammarBuilder.new
187
206
  builder.add_terminals(t_a, t_star, t_slash)
188
207
  builder.add_production('S' => 'E')
189
208
  builder.add_production('E' => %w[E Q F])
@@ -74,7 +74,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
74
74
  let(:nt_A) { NonTerminal.new('A') }
75
75
  let(:nt_B) { NonTerminal.new('B') }
76
76
  let(:nt_C) { NonTerminal.new('C') }
77
- let(:nt_D) { NonTerminal.new('D') }
77
+ let(:nt_D) { NonTerminal.new('D') }
78
78
  let(:a_) { VerbatimSymbol.new('a') }
79
79
  let(:b_) { VerbatimSymbol.new('b') }
80
80
  let(:c_) { VerbatimSymbol.new('c') }
@@ -161,7 +161,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
161
161
  expect(subject.name2symbol['b']).to eq(b_)
162
162
  expect(subject.name2symbol['c']).to eq(c_)
163
163
  end
164
-
164
+
165
165
  it 'should ensure that each production has a name' do
166
166
  subject.rules.each do |prod|
167
167
  expect(prod.name).to match(Regexp.new("#{prod.lhs.name}_\\d$"))
@@ -218,8 +218,8 @@ module Rley # Open this namespace to avoid module qualifier prefixes
218
218
  partitioning = instance.non_terminals.partition(&:generative?)
219
219
  expect(partitioning[0].size).to eq(2)
220
220
  expect(partitioning[0]).to eq([nt_S, nt_A])
221
- expect(partitioning[1]).to eq([nt_B, nt_C, nt_D])
222
-
221
+ expect(partitioning[1]).to eq([nt_B, nt_C, nt_D])
222
+
223
223
  undefined = instance.non_terminals.select(&:undefined?)
224
224
  expect(undefined).to be_empty
225
225
  end
@@ -248,13 +248,13 @@ module Rley # Open this namespace to avoid module qualifier prefixes
248
248
  expect(nterm).to be_nullable
249
249
  end
250
250
  end
251
-
251
+
252
252
  it 'should mark its nullable productions' do
253
253
  # Given the above productions, here are our expectations:
254
254
  expectations = [true, false, false, true]
255
255
  actuals = subject.rules.map(&:nullable?)
256
256
  expect(actuals).to eq(expectations)
257
- end
257
+ end
258
258
  end # context
259
259
  end # describe
260
260
  end # module
@@ -20,7 +20,7 @@ module Rley # Open this namespace to avoid module qualifier prefixes
20
20
  expect(subject.name).to eq(sample_name)
21
21
  end
22
22
  end # context
23
-
23
+
24
24
  context 'Provided services:' do
25
25
  it 'should give its text representation' do
26
26
  expect(subject.to_s).to eq(sample_name)
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../../spec_helper'
4
+
5
+ require_relative '../../../lib/rley/syntax/terminal'
6
+ require_relative '../../../lib/rley/syntax/non_terminal'
7
+ require_relative '../../../lib/rley/syntax/symbol_seq'
8
+
9
+ # Load the class under test
10
+ require_relative '../../../lib/rley/syntax/production'
11
+
12
+ # Load the class under test
13
+ require_relative '../../../lib/rley/syntax/match_closest'
14
+
15
+ module Rley # Open this namespace to avoid module qualifier prefixes
16
+ module Syntax # Open this namespace to avoid module qualifier prefixes
17
+ describe MatchClosest do
18
+ # 'stmt' => 'IF boolean THEN stmt ELSE stmt'
19
+ let(:boolean) { NonTerminal.new('boolean') }
20
+ let(:stmt) { NonTerminal.new('stmt') }
21
+ let(:if_t) { Terminal.new('IF') }
22
+ let(:then_t) { Terminal.new('THEN') }
23
+ let(:else_t) { Terminal.new('ELSE') }
24
+ let(:sequence) { [if_t, boolean, then_t, stmt, else_t, stmt] }
25
+ let(:prod) { Production.new(stmt, sequence) }
26
+
27
+ subject{ MatchClosest.new(prod.rhs.members, 4, 'IF') }
28
+
29
+ context 'Initialization:' do
30
+ it 'should be created with an symbol seq., an indice and a name' do
31
+ expect { MatchClosest.new(prod.rhs.members, 4, 'IF') }.not_to raise_error
32
+ end
33
+
34
+ it 'should know the index argument' do
35
+ expect(subject.idx_symbol).to eq(4) # ELSE at position 4
36
+ end
37
+
38
+ it 'should know the name of preceding symbol to pair with' do
39
+ expect(subject.closest_symb).to eq('IF')
40
+ end
41
+ end # context
42
+ end # describe
43
+ end # module
44
+ end # module
45
+
46
+ # End of file
@@ -19,28 +19,28 @@ module Rley # Open this namespace to avoid module qualifier prefixes
19
19
  it 'should know its name' do
20
20
  expect(subject.name).to eq(sample_name)
21
21
  end
22
-
22
+
23
23
  it 'should know that is a not a terminal' do
24
24
  expect(subject).not_to be_terminal
25
25
  end
26
26
  end # context
27
27
 
28
-
29
- context 'Provided services:' do
28
+
29
+ context 'Provided services:' do
30
30
  it 'should know whether it is nullable' do
31
31
  expect(subject.nullable?).to be_nil
32
32
  subject.nullable = true
33
33
  expect(subject).to be_nullable
34
34
  subject.nullable = false
35
- expect(subject).not_to be_nullable
35
+ expect(subject).not_to be_nullable
36
36
  end
37
-
37
+
38
38
  it 'should know whether it is defined' do
39
39
  expect(subject.undefined?).to be_nil
40
40
  subject.undefined = true
41
41
  expect(subject).to be_undefined
42
42
  subject.undefined = false
43
- expect(subject).not_to be_undefined
43
+ expect(subject).not_to be_undefined
44
44
  end
45
45
 
46
46
  it 'should know whether it is generative' do
@@ -48,8 +48,8 @@ module Rley # Open this namespace to avoid module qualifier prefixes
48
48
  subject.generative = true
49
49
  expect(subject).to be_generative
50
50
  subject.generative = false
51
- expect(subject).not_to be_generative
52
- end
51
+ expect(subject).not_to be_generative
52
+ end
53
53
  end # context
54
54
  end # describe
55
55
  end # module
@@ -24,11 +24,11 @@ module Rley # Open this namespace to avoid module qualifier prefixes
24
24
  it 'should be created with a non-terminal and a symbol sequence' do
25
25
  expect { Production.new(sentence, sequence) }.not_to raise_error
26
26
  end
27
-
27
+
28
28
  it 'should complain when its rhs is nil' do
29
29
  err = StandardError
30
30
  msg_prefix = 'Right side of a production of the kind '
31
- msg_suffix = "'Sentence' => ... is nil."
31
+ msg_suffix = "'Sentence' => ... is nil."
32
32
  msg = msg_prefix + msg_suffix
33
33
  expect { Production.new(sentence, nil) }.to raise_error(err, msg)
34
34
  end
@@ -43,48 +43,52 @@ module Rley # Open this namespace to avoid module qualifier prefixes
43
43
  expect(subject.body).to eq(sequence)
44
44
  end
45
45
 
46
+ it 'should be free from constraints at start' do
47
+ expect(subject.constraints).to be_empty
48
+ end
49
+
46
50
  it 'should know whether its rhs is empty' do
47
51
  expect(subject).not_to be_empty
48
52
 
49
53
  instance = Production.new(sentence, [])
50
54
  expect(instance).to be_empty
51
55
  end
52
-
56
+
53
57
  it 'should be anonymous at creation' do
54
58
  expect(subject.name).to be_nil
55
59
  end
56
-
60
+
57
61
  it 'should complain if its lhs is not a non-terminal' do
58
62
  err = StandardError
59
63
  msg_prefix = 'Left side of production must be a non-terminal symbol'
60
- msg_suffix = ", found a #{String} instead."
64
+ msg_suffix = ", found a #{String} instead."
61
65
  msg = msg_prefix + msg_suffix
62
66
  expect { Production.new('wrong', sequence) }.to raise_error(err, msg)
63
67
  end
64
68
  end # context
65
-
69
+
66
70
  context 'Provided services:' do
67
71
  it 'should accept a name (i)' do
68
72
  a_name = 'nominem'
69
73
  subject.name = a_name
70
74
  expect(subject.name).to eq(a_name)
71
75
  end
72
-
76
+
73
77
  it 'should accept a name (ii)' do
74
78
  a_name = 'nominem'
75
79
  subject.as(a_name)
76
- expect(subject.name).to eq(a_name)
80
+ expect(subject.name).to eq(a_name)
77
81
  end
78
-
82
+
79
83
  it 'should provide human-readable representation of itself' do
80
84
  subject.name = 'some name'
81
85
  prefix = /^#<Rley::Syntax::Production:\d+ @name="some name"/
82
86
  expect(subject.inspect).to match(prefix)
83
- pattern = /@lhs=Sentence @rhs=#<Rley::Syntax::SymbolSeq/
87
+ pattern = /@lhs=Sentence @rhs=#<Rley::Syntax::SymbolSeq/
84
88
  expect(subject.inspect).to match(pattern)
85
- suffix = /> @generative=>$/
86
- expect(subject.inspect).to match(suffix)
87
- end
89
+ suffix = /> @generative=>$/
90
+ expect(subject.inspect).to match(suffix)
91
+ end
88
92
  end # context
89
93
  end # describe
90
94
  end # module
@@ -57,13 +57,13 @@ module Rley # Open this namespace to avoid module qualifier prefixes
57
57
  unequal_one = SymbolSeq.new([verb, pp, np])
58
58
  expect(subject == unequal_one).not_to eq(true)
59
59
  end
60
-
60
+
61
61
  it 'should complain when unable to compare' do
62
62
  err = StandardError
63
63
  msg = 'Cannot compare a SymbolSeq with a String'
64
64
  expect { subject == 'dummy-text' }.to raise_error(err, msg)
65
65
  end
66
-
66
+
67
67
  it 'should provide human-readable representation of itself' do
68
68
  suffix = /::SymbolSeq:\d+ @members=\["Verb", "NP", "PP"\]>$/
69
69
  expect(subject.inspect).to match(suffix)