rley 0.7.06 → 0.8.01
Sign up to get free protection for your applications and to get access to all the features.
- 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
|