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
@@ -16,13 +16,13 @@ module Rley # This module is used as a namespace
16
16
  # nodes) and using a step by step approach.
17
17
  class CSTBuilder < ParseTreeBuilder
18
18
  protected
19
-
19
+
20
20
  # Method to override
21
21
  # Create a parse tree object with given
22
22
  # node as root node.
23
23
  def create_tree(aRootNode)
24
24
  return Rley::PTree::ParseTree.new(aRootNode)
25
- end
25
+ end
26
26
 
27
27
  # Method to override
28
28
  # Factory method for creating a node object for the given
@@ -42,10 +42,9 @@ module Rley # This module is used as a namespace
42
42
  # @param theChildren [Array] Children nodes (one per rhs symbol)
43
43
  def new_parent_node(aProduction, aRange, _tokens, theChildren)
44
44
  node = Rley::PTree::NonTerminalNode.new(aProduction.lhs, aRange)
45
- if theChildren
46
- theChildren.reverse_each { |child| node.add_subnode(child) }
47
- end
48
- return node
45
+ theChildren&.reverse_each { |child| node.add_subnode(child) }
46
+
47
+ node
49
48
  end
50
49
  end # class
51
50
  end # module
@@ -44,7 +44,7 @@ module Rley # This module is used as a namespace
44
44
  end
45
45
 
46
46
  # Notify the builder that the construction is over
47
- def done!()
47
+ def done!
48
48
  result.done!
49
49
  end
50
50
 
@@ -64,7 +64,7 @@ module Rley # This module is used as a namespace
64
64
  end
65
65
 
66
66
  # Return the current_parent node
67
- def curr_parent()
67
+ def curr_parent
68
68
  curr_path.last
69
69
  end
70
70
 
@@ -110,18 +110,18 @@ module Rley # This module is used as a namespace
110
110
  def process_item_entry(anEvent, anEntry, anIndex)
111
111
  case anEvent
112
112
  when :visit
113
- if anEntry.exit_entry?
113
+ if anEntry.exit_entry? && last_visitee.end_entry? &&
114
+ last_visitee.antecedents.size > 1
114
115
  # Previous entry was an end entry (X. pattern)
115
116
  # Does the previous entry have multiple antecedent?
116
- if last_visitee.end_entry? && last_visitee.antecedents.size > 1
117
- # Store current path for later backtracking
118
- # puts "Store backtrack context #{last_visitee}"
119
- # puts "path [#{curr_path.map{|e|e.to_string(0)}.join(', ')}]"
120
- entry2path_to_alt[last_visitee] = curr_path.dup
121
- curr_parent.refinement = :or
122
-
123
- create_alternative_node(anEntry)
124
- end
117
+
118
+ # Store current path for later backtracking
119
+ # puts "Store backtrack context #{last_visitee}"
120
+ # puts "path [#{curr_path.map{|e|e.to_string(0)}.join(', ')}]"
121
+ entry2path_to_alt[last_visitee] = curr_path.dup
122
+ curr_parent.refinement = :or
123
+
124
+ create_alternative_node(anEntry)
125
125
  end
126
126
 
127
127
  # Does this entry have multiple antecedent?
@@ -155,6 +155,7 @@ module Rley # This module is used as a namespace
155
155
  # Restore path
156
156
  @curr_path = entry2path_to_alt[anEntry].dup
157
157
  raise StandardError, 'path is nil' if curr_path.nil?
158
+
158
159
  create_alternative_node(anEntry)
159
160
 
160
161
  when :revisit
@@ -178,7 +179,7 @@ module Rley # This module is used as a namespace
178
179
 
179
180
  # Create an empty parse forest
180
181
  def create_forest(aRootNode)
181
- return Rley::SPPF::ParseForest.new(aRootNode)
182
+ Rley::SPPF::ParseForest.new(aRootNode)
182
183
  end
183
184
 
184
185
  # Factory method. Build and return an SPPF non-terminal node.
@@ -189,7 +190,7 @@ module Rley # This module is used as a namespace
189
190
  add_subnode(new_node)
190
191
  # puts "FOREST ADD #{curr_parent.key if curr_parent}/#{new_node.key}"
191
192
 
192
- return new_node
193
+ new_node
193
194
  end
194
195
 
195
196
  # Add an alternative node to the forest
@@ -201,7 +202,7 @@ module Rley # This module is used as a namespace
201
202
  result.is_ambiguous = true
202
203
  # puts "FOREST ADD #{alternative.key}"
203
204
 
204
- return alternative
205
+ alternative
205
206
  end
206
207
 
207
208
  # create a token node,
@@ -215,7 +216,7 @@ module Rley # This module is used as a namespace
215
216
  candidate = add_node_to_forest(new_node)
216
217
  entry2node[anEntry] = candidate
217
218
 
218
- return candidate
219
+ candidate
219
220
  end
220
221
 
221
222
  def create_epsilon_node(anEntry, anIndex)
@@ -223,7 +224,7 @@ module Rley # This module is used as a namespace
223
224
  candidate = add_node_to_forest(new_node)
224
225
  entry2node[anEntry] = candidate
225
226
 
226
- return candidate
227
+ candidate
227
228
  end
228
229
 
229
230
  # Add the given node if not yet present in parse forest
@@ -238,16 +239,19 @@ module Rley # This module is used as a namespace
238
239
  end
239
240
  add_subnode(new_node, false)
240
241
 
241
- return new_node
242
+ new_node
242
243
  end
243
244
 
244
245
  # Add the given node as sub-node of current parent node
245
246
  # Optionally add the node to the current path
247
+ # rubocop: disable Style/OptionalBooleanParameter
246
248
  def add_subnode(aNode, addToPath = true)
247
249
  raise StandardError, 'node is nil' if aNode.nil?
250
+
248
251
  curr_parent.add_subnode(aNode) unless curr_path.empty?
249
252
  curr_path << aNode if addToPath
250
253
  end
254
+ # rubocop: enable Style/OptionalBooleanParameter
251
255
  end # class
252
256
  end # module
253
257
  end # module
@@ -15,13 +15,13 @@ module Rley # This module is used as a namespace
15
15
  def builder(aParseResult, _builder = nil)
16
16
  ParseForestBuilder.new(aParseResult.tokens)
17
17
  end
18
-
18
+
19
19
  # When an end vertex is re-visited then jump
20
20
  # its corresponding start vertex. This behaviour
21
21
  # makes sense for sharing nodes.
22
- def jump_to_start()
22
+ def jump_to_start
23
23
  true
24
- end
24
+ end
25
25
  end # class
26
26
  end # module
27
27
  end # module
@@ -7,18 +7,18 @@ module Rley # This module is used as a namespace
7
7
  # Utility class that helps to create a representation of a parse from
8
8
  # a given Parsing object.
9
9
  class ParseRepCreator
10
- # @return [Rley::Parser::GFGParsing]
10
+ # @return [Rley::Parser::GFGParsing]
11
11
  # Link to Parsing object (= results of recognizer)
12
12
  attr_reader(:parsing)
13
-
13
+
14
14
  # Constructor. Creates and initialize a ParseRepCreator instance.
15
15
  # @return [ParseRepCreator]
16
16
  def initialize(aParsingResult)
17
17
  @parsing = aParsingResult
18
- end
19
-
18
+ end
19
+
20
20
  # Factory method that produces the representation of the parse.
21
- # @return [Rley::PTree::ParseTree, Rley::SPPF::ParseForest]
21
+ # @return [Rley::PTree::ParseTree, Rley::SPPF::ParseForest]
22
22
  # The parse representation.
23
23
  def create(aBuilder = nil)
24
24
  a_walker = walker(parsing)
@@ -32,20 +32,20 @@ module Rley # This module is used as a namespace
32
32
  end
33
33
  rescue StopIteration
34
34
  # Do nothing: gobble the exception
35
- rescue StandardError => exc
36
- if exc.message =~ /^Ambiguous/
35
+ rescue StandardError => e
36
+ if e.message =~ /^Ambiguous/
37
37
  $stderr.puts parsing
38
38
  end
39
- raise exc
39
+ raise e
40
40
  end
41
-
41
+
42
42
  a_builder.done!
43
43
 
44
- return a_builder.result
44
+ a_builder.result
45
45
  end
46
-
46
+
47
47
  private
48
-
48
+
49
49
  # Create a Parsing walker, that is, an object
50
50
  # that will iterate over the relevant nodes (= parsing entries)
51
51
  # of a GFGParsing
@@ -58,13 +58,11 @@ module Rley # This module is used as a namespace
58
58
 
59
59
  # By default, when a end vertex is re-visited don't jump
60
60
  # its corresponding start vertex.
61
- def jump_to_start()
61
+ def jump_to_start
62
62
  false
63
63
  end
64
-
65
64
  end # class
66
65
  end # module
67
66
  end # module
68
67
 
69
- # End of file
70
-
68
+ # End of file
@@ -50,7 +50,7 @@ module Rley # This module is used as a namespace
50
50
  end
51
51
 
52
52
  # Notify the builder that the parse tree construction is complete.
53
- def done!()
53
+ def done!
54
54
  result.done!
55
55
  end
56
56
 
@@ -92,7 +92,7 @@ module Rley # This module is used as a namespace
92
92
  private
93
93
 
94
94
  # Return the top of stack element.
95
- def tos()
95
+ def tos
96
96
  @stack.last
97
97
  end
98
98
 
@@ -207,7 +207,7 @@ module Rley # This module is used as a namespace
207
207
  # @param anEntry [ParseEntry] The entry being visited
208
208
  def terminal_before_dot?(anEntry)
209
209
  prev_symbol = anEntry.prev_symbol
210
- return prev_symbol && prev_symbol.terminal?
210
+ prev_symbol&.terminal?
211
211
  end
212
212
 
213
213
  # A terminal symbol was detected at left of dot.
@@ -260,7 +260,7 @@ module Rley # This module is used as a namespace
260
260
  non_terminal = anEntry.vertex.lhs
261
261
  end
262
262
 
263
- return non_terminal
263
+ non_terminal
264
264
  end
265
265
  end # class
266
266
  end # module
@@ -1,27 +1,27 @@
1
- # frozen_string_literal: true
2
-
3
- require_relative 'parse_rep_creator'
4
- # require_relative 'parse_tree_builder' # TODO remove this line
5
- require_relative 'cst_builder'
6
-
7
- module Rley # This module is used as a namespace
8
- module ParseRep # This module is used as a namespace
9
- # Utility class that helps to create a ParseTree from
10
- # a given Parsing object.
11
- class ParseTreeFactory < ParseRepCreator
12
- protected
13
-
14
- # Create a Builder, that is, an object
15
- # that will create piece by piece the forest
16
- def builder(aParseResult, aBuilder = nil)
17
- if aBuilder
18
- aBuilder.new(aParseResult.tokens)
19
- else
20
- CSTBuilder.new(aParseResult.tokens)
21
- end
22
- end
23
- end # class
24
- end # module
25
- end # module
26
-
27
- # End of file
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'parse_rep_creator'
4
+ # require_relative 'parse_tree_builder' # TODO remove this line
5
+ require_relative 'cst_builder'
6
+
7
+ module Rley # This module is used as a namespace
8
+ module ParseRep # This module is used as a namespace
9
+ # Utility class that helps to create a ParseTree from
10
+ # a given Parsing object.
11
+ class ParseTreeFactory < ParseRepCreator
12
+ protected
13
+
14
+ # Create a Builder, that is, an object
15
+ # that will create piece by piece the forest
16
+ def builder(aParseResult, aBuilder = nil)
17
+ if aBuilder
18
+ aBuilder.new(aParseResult.tokens)
19
+ else
20
+ CSTBuilder.new(aParseResult.tokens)
21
+ end
22
+ end
23
+ end # class
24
+ end # module
25
+ end # module
26
+
27
+ # End of file
@@ -37,7 +37,7 @@ module Rley # This module is used as a namespace
37
37
  end
38
38
 
39
39
  # The signal to begin the visit of the parse tree.
40
- def start()
40
+ def start
41
41
  ptree.accept(self)
42
42
  end
43
43
 
@@ -17,7 +17,7 @@ module Rley # Module used as a namespace
17
17
  end
18
18
 
19
19
  # @return [String] the result of invoking reason.to_s
20
- def message()
20
+ def message
21
21
  return to_s
22
22
  end
23
23
 
@@ -27,11 +27,10 @@ module Rley # Module used as a namespace
27
27
  end
28
28
  end # class
29
29
 
30
-
31
30
  # This parse error occurs when no input for parsing was provided
32
31
  # while the grammar requires some non-empty input.
33
32
  class NoInput < ErrorReason
34
- def initialize()
33
+ def initialize
35
34
  super(0)
36
35
  end
37
36
 
@@ -61,7 +60,7 @@ module Rley # Module used as a namespace
61
60
 
62
61
  protected
63
62
 
64
- def position()
63
+ def position
65
64
  return last_token.position if last_token.respond_to?(:position)
66
65
 
67
66
  rank + 1
@@ -76,7 +75,7 @@ module Rley # Module used as a namespace
76
75
  else
77
76
  "'#{term_names[0]}'"
78
77
  end
79
- return explain
78
+ explain
80
79
  end
81
80
  end # class
82
81
 
@@ -12,38 +12,52 @@ module Rley # This module is used as a namespace
12
12
  # the chart is an array with n + 1 entry sets.
13
13
  class GFGChart
14
14
  # @return [Array<ParseEntrySet>] entry sets (one per input token + 1)
15
- attr_reader(:sets)
15
+ attr_reader :sets
16
+
17
+ # @return [Array<Array<Syntax::MatchClosest>>]
18
+ attr_reader :constraints
16
19
 
17
20
  # @param aGFGraph [GFG::GrmFlowGraph] The GFG for the grammar in use.
18
21
  def initialize(aGFGraph)
19
- @sets = [ ParseEntrySet.new ]
22
+ @sets = [ParseEntrySet.new]
23
+ @constraints = [[]]
20
24
  push_entry(aGFGraph.start_vertex, 0, 0, :start_rule)
21
25
  end
22
26
 
23
27
  # @return [Syntax::NonTerminal] the start symbol of the grammar.
24
- def start_symbol()
25
- return sets.first.entries[0].vertex.non_terminal
28
+ def start_symbol
29
+ sets.first.entries[0].vertex.non_terminal
26
30
  end
27
31
 
28
32
  # @param index [Integer]
29
33
  # @return [ParseEntrySet] Access the entry set at given position.
30
34
  def [](index)
31
- return sets[index]
35
+ sets[index]
32
36
  end
33
37
 
34
38
  # Return the index value of the last non-empty entry set.
35
39
  # @return [Integer]
36
- def last_index()
40
+ def last_index
37
41
  first_empty = sets.find_index(&:empty?)
38
- index = if first_empty.nil?
39
- sets.size - 1
40
- else
41
- first_empty.zero? ? 0 : first_empty - 1
42
- end
43
-
44
- return index
42
+ if first_empty.nil?
43
+ sets.size - 1
44
+ else
45
+ first_empty.zero? ? 0 : first_empty - 1
46
+ end
45
47
  end
46
48
 
49
+ # if an entry corresponds to dotted item with a constraint
50
+ # make this constraint active for this index
51
+ # :before 'IF'
52
+ # search backwards to find nearest 'IF' scan rule
53
+ # in n+1, retrieve all items with IF . pattern
54
+ # create a lambda
55
+ # for every subsequent push_entry with same index,
56
+ # the lambda checks the condition (i.e pattern: ELSE . )
57
+ # if the condition is false, then push new entry
58
+ # if the condition is true but the consequent is false, then discard push action
59
+ # consequent: candidate refers to same dotted_item and same origin, then condition is false
60
+
47
61
  # Push a parse entry for the chart entry with given index
48
62
  # @param anIndex [Integer] The rank of the token in the input stream.
49
63
  # @return [ParseEntry] the passed parse entry if it is pushed
@@ -53,27 +67,59 @@ module Rley # This module is used as a namespace
53
67
  # puts " anOrigin: #{anOrigin}"
54
68
  # puts " anIndex: #{anIndex}"
55
69
  # puts " _reason: #{_reason}"
56
- new_entry = ParseEntry.new(aVertex, anOrigin)
57
70
  if anIndex == sets.size
58
- err_msg = "Internal error: unexpected push reason #{reason}"
59
- raise StandardError, err_msg if reason != :scan_rule
71
+ if reason == :scan_rule
72
+ add_entry_set
73
+ else
74
+ err_msg = "Internal error: unexpected push reason #{reason}"
75
+ raise StandardError, err_msg
76
+ end
77
+ end
78
+
79
+ reject = false
80
+ unless constraints[anIndex].empty?
81
+ constraints[anIndex].each do |ct|
82
+ case ct
83
+ when Syntax::MatchClosest
84
+ not_found = sets[anIndex][0].prev_symbol != aVertex.prev_symbol
85
+ next if not_found
86
+
87
+ some_mismatch = ct.entries.find do |en|
88
+ (en.vertex.dotted_item.production == aVertex.dotted_item.production) &&
89
+ (en.origin != anOrigin)
90
+ end
91
+ reject = true if some_mismatch
92
+ end
93
+ end
94
+ end
95
+
96
+ return nil if reject
97
+
98
+ new_entry = ParseEntry.new(aVertex, anOrigin)
99
+ result = self[anIndex].push_entry(new_entry)
60
100
 
61
- add_entry_set
101
+ if aVertex.kind_of?(GFG::ItemVertex) && aVertex.dotted_item.constraint
102
+ ct = aVertex.dotted_item.constraint
103
+
104
+ case ct
105
+ when Syntax::MatchClosest
106
+ update_match_closest(ct, anIndex)
107
+ end
108
+ constraints[anIndex] << ct
62
109
  end
63
- pushed = self[anIndex].push_entry(new_entry)
64
110
 
65
- return pushed
111
+ result
66
112
  end
67
113
 
68
114
  # Retrieve the first parse entry added to this chart
69
115
  # @return [ParseEntry]
70
- def initial_entry()
71
- return sets[0].first
116
+ def initial_entry
117
+ sets[0].first
72
118
  end
73
119
 
74
120
  # Retrieve the entry that corresponds to a complete and successful parse
75
121
  # @return [ParseEntry]
76
- def accepting_entry()
122
+ def accepting_entry
77
123
  # Success can be detected as follows:
78
124
  # The last chart entry set has at least one complete parse entry
79
125
  # for the start symbol with an origin == 0
@@ -95,7 +141,7 @@ module Rley # This module is used as a namespace
95
141
 
96
142
  success_entries.first
97
143
  end
98
-
144
+
99
145
  # @return [Integer] The number of states.
100
146
  def count_states
101
147
  sets.size
@@ -103,6 +149,7 @@ module Rley # This module is used as a namespace
103
149
 
104
150
  # @return [Integer] The total number of entries.
105
151
  def count_entries
152
+ # rubocop: disable Lint/UselessAssignment
106
153
  sets.reduce(0) do |sub_result, a_set|
107
154
  sub_result += a_set.size
108
155
  end
@@ -114,6 +161,26 @@ module Rley # This module is used as a namespace
114
161
  sub_result += a_set.count_edges
115
162
  end
116
163
  end
164
+ # rubocop: enable Lint/UselessAssignment
165
+
166
+ # Retrieve all entries that have a given terminal before the dot.
167
+ # @param criteria [Hash{Symbol => String}]
168
+ def search_entries(atIndex, criteria)
169
+ entries = sets[atIndex].entries
170
+ keyword = criteria.keys[0]
171
+ found = []
172
+ entries.each do |e|
173
+ case keyword
174
+ when :before # terminal before dot
175
+ term_name = criteria[keyword]
176
+ if e.dotted_entry? && e.vertex.dotted_item.position > -2
177
+ found << e if e.prev_symbol&.name == criteria[keyword]
178
+ end
179
+ end
180
+ end
181
+
182
+ found
183
+ end
117
184
 
118
185
  # @ return [String] A human-readable representation of the chart.
119
186
  def to_s
@@ -121,17 +188,42 @@ module Rley # This module is used as a namespace
121
188
  sets.each_with_index do |a_set, i|
122
189
  result << "State[#{i}]\n"
123
190
  a_set.entries.each do |item|
124
- result << ' ' + item.to_s + "\n"
191
+ result << " #{item}\n"
125
192
  end
126
193
  end
127
-
194
+
128
195
  result
129
196
  end
130
197
 
131
198
  private
132
199
 
133
- def add_entry_set()
200
+ def add_entry_set
134
201
  @sets << ParseEntrySet.new
202
+ @constraints << []
203
+ end
204
+
205
+ def update_match_closest(aConstraint, anIndex)
206
+ # Locate in the chart the closest matching terminal...
207
+ i = anIndex - 1
208
+ loop do
209
+ first_entry = sets[i][0]
210
+ prev_symbol = first_entry.prev_symbol
211
+ break if prev_symbol.name == aConstraint.closest_symb
212
+ i -= 1
213
+ break if i < 0
214
+ end
215
+
216
+ # Retrieve all entries of the kind: closest_symb .
217
+ if i > 0
218
+ entries = sets[i].entries.select do |en|
219
+ if en.prev_symbol
220
+ en.prev_symbol.name == aConstraint.closest_symb
221
+ else
222
+ false
223
+ end
224
+ end
225
+ aConstraint.entries = entries
226
+ end
135
227
  end
136
228
  end # class
137
229
  end # module