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.
- checksums.yaml +4 -4
- data/.rubocop.yml +362 -62
- data/.travis.yml +6 -6
- data/CHANGELOG.md +20 -4
- data/LICENSE.txt +1 -1
- data/README.md +7 -7
- data/examples/NLP/engtagger.rb +193 -190
- data/examples/NLP/nano_eng/nano_en_demo.rb +7 -11
- data/examples/NLP/nano_eng/nano_grammar.rb +21 -21
- data/examples/NLP/pico_en_demo.rb +2 -2
- data/examples/data_formats/JSON/cli_options.rb +1 -1
- data/examples/data_formats/JSON/json_ast_builder.rb +21 -27
- data/examples/data_formats/JSON/json_ast_nodes.rb +12 -21
- data/examples/data_formats/JSON/json_demo.rb +1 -2
- data/examples/data_formats/JSON/json_grammar.rb +13 -13
- data/examples/data_formats/JSON/json_lexer.rb +8 -8
- data/examples/data_formats/JSON/json_minifier.rb +1 -1
- data/examples/general/calc_iter1/calc_ast_builder.rb +13 -10
- data/examples/general/calc_iter1/calc_ast_nodes.rb +23 -37
- data/examples/general/calc_iter1/calc_grammar.rb +7 -6
- data/examples/general/calc_iter1/calc_lexer.rb +6 -4
- data/examples/general/calc_iter1/spec/calculator_spec.rb +5 -5
- data/examples/general/calc_iter2/calc_ast_builder.rb +5 -3
- data/examples/general/calc_iter2/calc_ast_nodes.rb +27 -43
- data/examples/general/calc_iter2/calc_grammar.rb +12 -12
- data/examples/general/calc_iter2/calc_lexer.rb +11 -10
- data/examples/general/calc_iter2/spec/calculator_spec.rb +26 -26
- data/examples/general/left.rb +2 -2
- data/examples/general/right.rb +2 -2
- data/lib/rley.rb +1 -1
- data/lib/rley/base/dotted_item.rb +28 -31
- data/lib/rley/base/grm_items_builder.rb +6 -0
- data/lib/rley/constants.rb +2 -2
- data/lib/rley/engine.rb +22 -25
- data/lib/rley/formatter/asciitree.rb +3 -3
- data/lib/rley/formatter/bracket_notation.rb +1 -8
- data/lib/rley/formatter/debug.rb +6 -6
- data/lib/rley/formatter/json.rb +2 -2
- data/lib/rley/gfg/call_edge.rb +1 -1
- data/lib/rley/gfg/edge.rb +5 -5
- data/lib/rley/gfg/end_vertex.rb +2 -6
- data/lib/rley/gfg/epsilon_edge.rb +1 -5
- data/lib/rley/gfg/grm_flow_graph.rb +27 -23
- data/lib/rley/gfg/item_vertex.rb +10 -10
- data/lib/rley/gfg/non_terminal_vertex.rb +4 -4
- data/lib/rley/gfg/scan_edge.rb +1 -1
- data/lib/rley/gfg/shortcut_edge.rb +2 -2
- data/lib/rley/gfg/start_vertex.rb +4 -8
- data/lib/rley/gfg/vertex.rb +43 -39
- data/lib/rley/interface.rb +16 -0
- data/lib/rley/lexical/token_range.rb +6 -6
- data/lib/rley/notation/all_notation_nodes.rb +2 -0
- data/lib/rley/notation/ast_builder.rb +191 -0
- data/lib/rley/notation/ast_node.rb +44 -0
- data/lib/rley/notation/ast_visitor.rb +113 -0
- data/lib/rley/notation/grammar.rb +49 -0
- data/lib/rley/notation/grammar_builder.rb +504 -0
- data/lib/rley/notation/grouping_node.rb +23 -0
- data/lib/rley/notation/parser.rb +56 -0
- data/lib/rley/notation/sequence_node.rb +35 -0
- data/lib/rley/notation/symbol_node.rb +29 -0
- data/lib/rley/notation/tokenizer.rb +192 -0
- data/lib/rley/parse_forest_visitor.rb +5 -5
- data/lib/rley/parse_rep/ast_base_builder.rb +48 -11
- data/lib/rley/parse_rep/cst_builder.rb +5 -6
- data/lib/rley/parse_rep/parse_forest_builder.rb +22 -18
- data/lib/rley/parse_rep/parse_forest_factory.rb +3 -3
- data/lib/rley/parse_rep/parse_rep_creator.rb +14 -16
- data/lib/rley/parse_rep/parse_tree_builder.rb +4 -4
- data/lib/rley/parse_rep/parse_tree_factory.rb +27 -27
- data/lib/rley/parse_tree_visitor.rb +1 -1
- data/lib/rley/parser/error_reason.rb +4 -5
- data/lib/rley/parser/gfg_chart.rb +118 -26
- data/lib/rley/parser/gfg_parsing.rb +22 -33
- data/lib/rley/parser/parse_entry.rb +25 -31
- data/lib/rley/parser/parse_entry_set.rb +19 -16
- data/lib/rley/parser/parse_entry_tracker.rb +4 -4
- data/lib/rley/parser/parse_tracer.rb +13 -13
- data/lib/rley/parser/parse_walker_factory.rb +23 -28
- data/lib/rley/ptree/non_terminal_node.rb +7 -5
- data/lib/rley/ptree/parse_tree.rb +3 -3
- data/lib/rley/ptree/parse_tree_node.rb +5 -5
- data/lib/rley/ptree/terminal_node.rb +7 -7
- data/lib/rley/rley_error.rb +12 -12
- data/lib/rley/sppf/alternative_node.rb +6 -6
- data/lib/rley/sppf/composite_node.rb +7 -7
- data/lib/rley/sppf/epsilon_node.rb +3 -3
- data/lib/rley/sppf/leaf_node.rb +3 -3
- data/lib/rley/sppf/parse_forest.rb +16 -16
- data/lib/rley/sppf/sppf_node.rb +7 -8
- data/lib/rley/sppf/token_node.rb +3 -3
- data/lib/rley/syntax/{grammar_builder.rb → base_grammar_builder.rb} +61 -23
- data/lib/rley/syntax/grammar.rb +5 -5
- data/lib/rley/syntax/grm_symbol.rb +7 -7
- data/lib/rley/syntax/match_closest.rb +43 -0
- data/lib/rley/syntax/non_terminal.rb +9 -15
- data/lib/rley/syntax/production.rb +16 -10
- data/lib/rley/syntax/symbol_seq.rb +7 -9
- data/lib/rley/syntax/terminal.rb +4 -5
- data/lib/rley/syntax/verbatim_symbol.rb +3 -3
- data/lib/support/base_tokenizer.rb +19 -18
- data/spec/rley/base/dotted_item_spec.rb +2 -2
- data/spec/rley/engine_spec.rb +23 -21
- data/spec/rley/formatter/asciitree_spec.rb +7 -7
- data/spec/rley/formatter/bracket_notation_spec.rb +13 -13
- data/spec/rley/formatter/json_spec.rb +1 -1
- data/spec/rley/gfg/end_vertex_spec.rb +5 -5
- data/spec/rley/gfg/grm_flow_graph_spec.rb +2 -2
- data/spec/rley/gfg/item_vertex_spec.rb +10 -10
- data/spec/rley/gfg/non_terminal_vertex_spec.rb +3 -3
- data/spec/rley/gfg/shortcut_edge_spec.rb +1 -1
- data/spec/rley/gfg/start_vertex_spec.rb +5 -5
- data/spec/rley/gfg/vertex_spec.rb +3 -3
- data/spec/rley/lexical/token_range_spec.rb +16 -16
- data/spec/rley/lexical/token_spec.rb +2 -2
- data/spec/rley/notation/grammar_builder_spec.rb +302 -0
- data/spec/rley/notation/parser_spec.rb +184 -0
- data/spec/rley/notation/tokenizer_spec.rb +370 -0
- data/spec/rley/parse_forest_visitor_spec.rb +165 -163
- data/spec/rley/parse_rep/ambiguous_parse_spec.rb +44 -44
- data/spec/rley/parse_rep/ast_builder_spec.rb +6 -7
- data/spec/rley/parse_rep/cst_builder_spec.rb +5 -5
- data/spec/rley/parse_rep/groucho_spec.rb +24 -26
- data/spec/rley/parse_rep/parse_forest_builder_spec.rb +27 -27
- data/spec/rley/parse_rep/parse_forest_factory_spec.rb +8 -8
- data/spec/rley/parse_rep/parse_tree_factory_spec.rb +3 -3
- data/spec/rley/parse_tree_visitor_spec.rb +10 -8
- data/spec/rley/parser/dangling_else_spec.rb +445 -0
- data/spec/rley/parser/error_reason_spec.rb +6 -6
- data/spec/rley/parser/gfg_earley_parser_spec.rb +120 -12
- data/spec/rley/parser/gfg_parsing_spec.rb +6 -13
- data/spec/rley/parser/parse_entry_spec.rb +19 -19
- data/spec/rley/parser/parse_walker_factory_spec.rb +10 -10
- data/spec/rley/ptree/non_terminal_node_spec.rb +5 -3
- data/spec/rley/ptree/parse_tree_node_spec.rb +4 -4
- data/spec/rley/ptree/terminal_node_spec.rb +6 -6
- data/spec/rley/sppf/alternative_node_spec.rb +6 -6
- data/spec/rley/sppf/non_terminal_node_spec.rb +3 -3
- data/spec/rley/sppf/token_node_spec.rb +4 -4
- data/spec/rley/support/ambiguous_grammar_helper.rb +4 -5
- data/spec/rley/support/grammar_abc_helper.rb +3 -5
- data/spec/rley/support/grammar_ambig01_helper.rb +5 -6
- data/spec/rley/support/grammar_arr_int_helper.rb +5 -6
- data/spec/rley/support/grammar_b_expr_helper.rb +5 -6
- data/spec/rley/support/grammar_int_seq_helper.rb +51 -0
- data/spec/rley/support/grammar_l0_helper.rb +14 -17
- data/spec/rley/support/grammar_pb_helper.rb +8 -7
- data/spec/rley/support/grammar_sppf_helper.rb +3 -3
- data/spec/rley/syntax/{grammar_builder_spec.rb → base_grammar_builder_spec.rb} +35 -16
- data/spec/rley/syntax/grammar_spec.rb +6 -6
- data/spec/rley/syntax/grm_symbol_spec.rb +1 -1
- data/spec/rley/syntax/match_closest_spec.rb +46 -0
- data/spec/rley/syntax/non_terminal_spec.rb +8 -8
- data/spec/rley/syntax/production_spec.rb +17 -13
- data/spec/rley/syntax/symbol_seq_spec.rb +2 -2
- data/spec/rley/syntax/terminal_spec.rb +5 -5
- data/spec/rley/syntax/verbatim_symbol_spec.rb +1 -1
- data/spec/spec_helper.rb +0 -12
- data/spec/support/base_tokenizer_spec.rb +7 -2
- metadata +48 -74
- data/.simplecov +0 -7
- data/lib/rley/parser/parse_state.rb +0 -83
- data/lib/rley/parser/parse_state_tracker.rb +0 -59
- data/lib/rley/parser/state_set.rb +0 -101
- data/spec/rley/parser/parse_state_spec.rb +0 -125
- data/spec/rley/parser/parse_tracer_spec.rb +0 -200
- 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
|
-
|
46
|
-
|
47
|
-
|
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
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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 =>
|
36
|
-
if
|
35
|
+
rescue StandardError => e
|
36
|
+
if e.message =~ /^Ambiguous/
|
37
37
|
$stderr.puts parsing
|
38
38
|
end
|
39
|
-
raise
|
39
|
+
raise e
|
40
40
|
end
|
41
|
-
|
41
|
+
|
42
42
|
a_builder.done!
|
43
43
|
|
44
|
-
|
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
|
-
|
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
|
-
|
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
|
@@ -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
|
-
|
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
|
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 = [
|
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
|
-
|
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
|
-
|
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
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
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
|
-
|
59
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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 <<
|
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
|