rley 0.8.15 → 0.9.02
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/CHANGELOG.md +17 -0
- data/Gemfile +8 -0
- data/lib/rley/constants.rb +2 -2
- data/lib/rley/engine.rb +3 -1
- data/lib/rley/formatter/asciitree.rb +4 -1
- data/lib/rley/gfg/epsilon_edge.rb +0 -2
- data/lib/rley/gfg/grm_flow_graph.rb +7 -8
- data/lib/rley/gfg/item_vertex.rb +1 -1
- data/lib/rley/gfg/vertex.rb +11 -0
- data/lib/rley/lexical/token.rb +10 -3
- data/lib/rley/parse_forest_visitor.rb +3 -3
- data/lib/rley/parse_rep/ast_base_builder.rb +6 -5
- data/lib/rley/parse_rep/parse_forest_builder.rb +4 -2
- data/lib/rley/parse_rep/parse_tree_builder.rb +14 -2
- data/lib/rley/parse_rep/parse_tree_factory.rb +1 -1
- data/lib/rley/parser/error_reason.rb +2 -2
- data/lib/rley/parser/gfg_chart.rb +2 -2
- data/lib/rley/parser/gfg_earley_parser.rb +2 -2
- data/lib/rley/parser/gfg_parsing.rb +1 -1
- data/lib/rley/parser/parse_entry.rb +4 -4
- data/lib/rley/parser/parse_entry_set.rb +4 -1
- data/lib/rley/parser/parse_entry_tracker.rb +10 -7
- data/lib/rley/parser/parse_walker_factory.rb +9 -7
- data/lib/rley/ptree/parse_tree_node.rb +6 -0
- data/lib/rley/ptree/terminal_node.rb +1 -1
- data/lib/rley/rgn/ast_builder.rb +2 -2
- data/lib/rley/rgn/ast_node.rb +11 -1
- data/lib/rley/rgn/ast_visitor.rb +2 -2
- data/lib/rley/rgn/composite_node.rb +1 -1
- data/lib/rley/rgn/grammar_builder.rb +12 -12
- data/lib/rley/rgn/parser.rb +2 -2
- data/lib/rley/rley_error.rb +0 -4
- data/lib/rley/sppf/composite_node.rb +6 -0
- data/lib/rley/sppf/parse_forest.rb +7 -7
- data/lib/rley/sppf/sppf_node.rb +15 -1
- data/lib/rley/syntax/base_grammar_builder.rb +3 -11
- data/lib/rley/syntax/grammar.rb +9 -3
- data/lib/rley/syntax/production.rb +1 -1
- metadata +15 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1f4f4a6f94d92e3d014a12bf3f979d2be06139987df1754006992468f8968fb5
|
4
|
+
data.tar.gz: c2a708692519342e598b33acb39dfdc098209f2508255c90b355d832bf279d0a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fcb1d7119d6475ddf9ad8c87d64ccb645e8fa80082b0dc004647141146db54d7ecba1d788280dc6ab3e62fdaf70cc814b4e6d67d365d0bddbdeaec0c11218510
|
7
|
+
data.tar.gz: a689799d6eeac5238c6baee2f4b6d0cad0b6f6e1c66e32e3e294279d5388f4c7774a603e2f55870f33d9b8cd513908c7ab810f312f70ce01c077d8c167391970
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,20 @@
|
|
1
|
+
### 0.9.02 / 2025-03-18
|
2
|
+
Version bumped.
|
3
|
+
* [FIX] Change in previous version in method `ParseTreeBuilder#terminal_before_dot?` was code breaking.
|
4
|
+
* [CHANGE] File `rley.gemspec`: made the external dependencies more lenient...
|
5
|
+
|
6
|
+
|
7
|
+
### 0.9.01 / 2025-03-16
|
8
|
+
Version bumped.
|
9
|
+
* [CHANGED] Updated `.rbs` signature files.
|
10
|
+
|
11
|
+
### 0.9.00 / 2025-03-08
|
12
|
+
Version bumped.
|
13
|
+
* [NEW] Added `sig` folder with `.rbs` signature files.
|
14
|
+
- [FIX] Broken Cucumber test. Replaced reference to `GrammarBuilder` by `BaseGrammarBuilder`.
|
15
|
+
- [FIX] File `rley.gemspec` now returns a GemSpecification as expected by Bundler.
|
16
|
+
- [CHANGE] File `Gemfile` refers to gemspec
|
17
|
+
|
1
18
|
### 0.8.15 / 2025-02-28
|
2
19
|
- [FIX] Re-styled spec files
|
3
20
|
|
data/Gemfile
ADDED
data/lib/rley/constants.rb
CHANGED
@@ -5,10 +5,10 @@
|
|
5
5
|
|
6
6
|
module Rley # Module used as a namespace
|
7
7
|
# The version number of the gem.
|
8
|
-
Version = '0.
|
8
|
+
Version = '0.9.02'
|
9
9
|
|
10
10
|
# Brief description of the gem.
|
11
|
-
Description = "
|
11
|
+
Description = "A parsing library based on the Earley's parsing algorithm."
|
12
12
|
|
13
13
|
# Constant Rley::RootDir contains the absolute path of Rley's
|
14
14
|
# start directory. Note: it also ends with a slash character.
|
data/lib/rley/engine.rb
CHANGED
@@ -19,6 +19,7 @@ module Rley # This module is used as a namespace
|
|
19
19
|
# Constructor with default initialization.
|
20
20
|
def initialize
|
21
21
|
super()
|
22
|
+
# @type self: EngineConfig
|
22
23
|
self.parse_repr = :parse_tree
|
23
24
|
self.repr_builder = :default
|
24
25
|
self.diagnose = false
|
@@ -80,7 +81,7 @@ module Rley # This module is used as a namespace
|
|
80
81
|
aTokenizer.each do |a_token|
|
81
82
|
next unless a_token
|
82
83
|
|
83
|
-
if a_token.terminal.
|
84
|
+
if a_token.terminal.is_a?(String)
|
84
85
|
term_name = a_token.terminal
|
85
86
|
term_symb = grammar.name2symbol[term_name]
|
86
87
|
a_token.instance_variable_set(:@terminal, term_symb)
|
@@ -133,6 +134,7 @@ module Rley # This module is used as a namespace
|
|
133
134
|
result = factory.create(configuration.repr_builder)
|
134
135
|
end
|
135
136
|
|
137
|
+
# @type var result : Rley::SPPF::ParseForest
|
136
138
|
result
|
137
139
|
end
|
138
140
|
|
@@ -82,9 +82,10 @@ module Rley # This module is used as a namespace
|
|
82
82
|
def rank_of(aChild)
|
83
83
|
if curr_path.empty?
|
84
84
|
rank = 'root'
|
85
|
-
elsif curr_path[-1].subnodes.size == 1
|
85
|
+
elsif curr_path[-1].subnodes.size == 1 # steep:ignore
|
86
86
|
rank = 'first_and_last'
|
87
87
|
else
|
88
|
+
# @type var parent : Rley::PTree::NonTerminalNode
|
88
89
|
parent = curr_path[-1]
|
89
90
|
siblings = parent.subnodes
|
90
91
|
siblings_last_index = siblings.size - 1
|
@@ -96,6 +97,8 @@ module Rley # This module is used as a namespace
|
|
96
97
|
end
|
97
98
|
end
|
98
99
|
ranks << rank
|
100
|
+
|
101
|
+
rank
|
99
102
|
end
|
100
103
|
|
101
104
|
# 'root', 'first', 'first_and_last', 'last', 'other'
|
@@ -40,7 +40,7 @@ module Rley # This module is used as a namespace
|
|
40
40
|
attr_reader :vertices
|
41
41
|
|
42
42
|
# The vertex marked as start node of the graph
|
43
|
-
# @return [StartVertex
|
43
|
+
# @return [StartVertex]
|
44
44
|
attr_reader :start_vertex
|
45
45
|
|
46
46
|
# A Hash with pairs of the form: non-terminal symbol => start node
|
@@ -188,7 +188,7 @@ module Rley # This module is used as a namespace
|
|
188
188
|
# For debugging purposes
|
189
189
|
def print_vertex(aText, aVertex)
|
190
190
|
print "#{aText} "
|
191
|
-
if aVertex.
|
191
|
+
if aVertex.is_a?(NonTerminalVertex)
|
192
192
|
puts "#{aVertex.class} #{aVertex.non_terminal.name}"
|
193
193
|
else
|
194
194
|
p(aVertex.label)
|
@@ -222,7 +222,7 @@ module Rley # This module is used as a namespace
|
|
222
222
|
productions.each do |prod|
|
223
223
|
all_nterms << prod.lhs
|
224
224
|
nterms_of_rhs = prod.rhs.members.select do |symb|
|
225
|
-
symb.
|
225
|
+
symb.is_a?(Syntax::NonTerminal)
|
226
226
|
end
|
227
227
|
all_nterms.merge(nterms_of_rhs)
|
228
228
|
end
|
@@ -285,7 +285,7 @@ module Rley # This module is used as a namespace
|
|
285
285
|
# At least one symbol before the dot
|
286
286
|
# Retrieve the symbol before the dot...
|
287
287
|
prev_symbol = current_item.prev_symbol
|
288
|
-
if prev_symbol.
|
288
|
+
if prev_symbol.is_a?(Syntax::Terminal)
|
289
289
|
build_scan_edge(vertices[-2], new_vertex)
|
290
290
|
else
|
291
291
|
# ...non-terminal
|
@@ -294,7 +294,7 @@ module Rley # This module is used as a namespace
|
|
294
294
|
end
|
295
295
|
|
296
296
|
prev_symbol = current_item.prev_symbol
|
297
|
-
if prev_symbol&.
|
297
|
+
if prev_symbol&.is_a?(Syntax::NonTerminal)
|
298
298
|
build_shortcut_edge(prev_vertex, new_vertex)
|
299
299
|
end
|
300
300
|
prev_vertex = new_vertex
|
@@ -355,8 +355,7 @@ module Rley # This module is used as a namespace
|
|
355
355
|
end_vertex = end_vertex_for[aCallEdge.successor.non_terminal]
|
356
356
|
|
357
357
|
# Retrieve the return edge with specified key
|
358
|
-
|
359
|
-
return return_edge
|
358
|
+
end_vertex.edges.find { |edge| edge.key == ret_key }
|
360
359
|
end
|
361
360
|
|
362
361
|
# Mark non-terminal symbols that cannot be derived from the start symbol.
|
@@ -372,7 +371,7 @@ module Rley # This module is used as a namespace
|
|
372
371
|
# and mark all visited non-terminals as reachable
|
373
372
|
traverse_df(start_vertex) do |a_vertex|
|
374
373
|
# print_vertex(' Visiting', a_vertex)
|
375
|
-
if a_vertex.
|
374
|
+
if a_vertex.is_a?(StartVertex)
|
376
375
|
a_vertex.non_terminal.unreachable = false
|
377
376
|
end
|
378
377
|
end
|
data/lib/rley/gfg/item_vertex.rb
CHANGED
@@ -30,7 +30,7 @@ module Rley # This module is used as a namespace
|
|
30
30
|
# Set the "shortcut" edge.
|
31
31
|
# @param aShortcut [ShortcutEdge] the "shortcut" edge.
|
32
32
|
def shortcut=(aShortcut)
|
33
|
-
unless aShortcut.
|
33
|
+
unless aShortcut.is_a?(ShortcutEdge)
|
34
34
|
raise StandardError, 'Invalid shortcut argument'
|
35
35
|
end
|
36
36
|
|
data/lib/rley/gfg/vertex.rb
CHANGED
@@ -69,6 +69,17 @@ module Rley # This module is used as a namespace
|
|
69
69
|
edges << arrow
|
70
70
|
end
|
71
71
|
|
72
|
+
# The label of this vertex.
|
73
|
+
# It is the same as the label of the corresponding dotted item.
|
74
|
+
# @return [String] Label for this vertex
|
75
|
+
def label
|
76
|
+
raise NotImplementedError
|
77
|
+
end
|
78
|
+
|
79
|
+
def dotted_item
|
80
|
+
raise NotImplementedError
|
81
|
+
end
|
82
|
+
|
72
83
|
protected
|
73
84
|
|
74
85
|
# Validation method for adding an outgoing edge to the vertex.
|
data/lib/rley/lexical/token.rb
CHANGED
@@ -5,13 +5,20 @@ module Rley # This module is used as a namespace
|
|
5
5
|
# as return values from a tokenizer / lexer.
|
6
6
|
module Lexical
|
7
7
|
# A Position is the location of a lexeme within a source file.
|
8
|
-
Position
|
8
|
+
class Position
|
9
|
+
attr_reader :line
|
10
|
+
attr_reader :column
|
11
|
+
|
12
|
+
def initialize(aLine, aCol)
|
13
|
+
@line = aLine
|
14
|
+
@column = aCol
|
15
|
+
end
|
16
|
+
|
9
17
|
def to_s
|
10
18
|
"line #{line}, column #{column}"
|
11
19
|
end
|
12
20
|
end
|
13
21
|
|
14
|
-
|
15
22
|
# In Rley, a (lexical) token is an object created by a lexer (tokenizer)
|
16
23
|
# and passed to the parser. Such token an object is created when a lexer
|
17
24
|
# detects that a sequence of characters(a lexeme) from the input stream
|
@@ -27,7 +34,7 @@ module Rley # This module is used as a namespace
|
|
27
34
|
# @return [String] Input substring that is an instance of the terminal.
|
28
35
|
attr_reader(:lexeme)
|
29
36
|
|
30
|
-
# @return [
|
37
|
+
# @return [Syntax::Terminal] The name of terminal symbol matching the lexeme.
|
31
38
|
attr_reader(:terminal)
|
32
39
|
|
33
40
|
# @return [Position] The position -in "editor" coordinates- of the lexeme in the source file.
|
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# require 'pry'
|
4
3
|
require 'prime'
|
5
4
|
|
6
5
|
module Rley # This module is used as a namespace
|
@@ -145,9 +144,10 @@ module Rley # This module is used as a namespace
|
|
145
144
|
# Let's proceed with the visit of children
|
146
145
|
children.each_with_index do |a_node, i|
|
147
146
|
edge_sign = aParentNode.signatures[i]
|
148
|
-
if a_node.
|
147
|
+
if a_node.is_a?(SPPF::CompositeNode)
|
149
148
|
push_node(a_node, edge_sign)
|
150
149
|
access_paths = node_accesses[a_node]
|
150
|
+
# @type var last_path : Integer
|
151
151
|
last_path = legs.last[-1]
|
152
152
|
path_reused = access_paths.include?(last_path)
|
153
153
|
unless path_reused
|
@@ -178,8 +178,8 @@ module Rley # This module is used as a namespace
|
|
178
178
|
if legs.empty?
|
179
179
|
legs << [aCompositeNode, anEdgeSignature]
|
180
180
|
else
|
181
|
+
# @type var path_signature : Integer
|
181
182
|
path_signature = legs.last[-1]
|
182
|
-
# binding.pry if anEdgeSignature == 37 && path_signature != 230
|
183
183
|
if (path_signature % anEdgeSignature).zero?
|
184
184
|
legs << [aCompositeNode, path_signature]
|
185
185
|
else
|
@@ -94,9 +94,10 @@ module Rley # This module is used as a namespace
|
|
94
94
|
klass = terminal2node.fetch(aTerminal.name, terminalnode_class)
|
95
95
|
if klass.is_a?(Hash)
|
96
96
|
# Lexical ambiguity...
|
97
|
-
klass = klass.fetch(aProduction.name)
|
97
|
+
klass = klass.fetch(aProduction.name) # steep:ignore ArgumentTypeMismatch
|
98
98
|
end
|
99
|
-
|
99
|
+
|
100
|
+
klass.new(aToken, aTokenPosition) # steep:ignore
|
100
101
|
end
|
101
102
|
|
102
103
|
# Method to override.
|
@@ -106,7 +107,7 @@ module Rley # This module is used as a namespace
|
|
106
107
|
# @param theTokens [Array] The input tokens
|
107
108
|
# @param theChildren [Array] Children nodes (one per rhs symbol)
|
108
109
|
def new_parent_node(aProduction, aRange, theTokens, theChildren)
|
109
|
-
mth_name = method_name(aProduction.name)
|
110
|
+
mth_name = method_name(aProduction.name) # steep:ignore ArgumentTypeMismatch
|
110
111
|
if respond_to?(mth_name, true)
|
111
112
|
node = send(mth_name, aProduction, aRange, theTokens, theChildren)
|
112
113
|
else
|
@@ -139,7 +140,7 @@ module Rley # This module is used as a namespace
|
|
139
140
|
# Implicit rule generated for * modifier
|
140
141
|
# rule('X') => 'X item'.as '_star_more'
|
141
142
|
def reduce__star_more(_production, _range, _tokens, theChildren)
|
142
|
-
theChildren[0] << theChildren[1]
|
143
|
+
theChildren[0] << theChildren[1] # steep:ignore NoMethod
|
143
144
|
theChildren[0]
|
144
145
|
end
|
145
146
|
|
@@ -152,7 +153,7 @@ module Rley # This module is used as a namespace
|
|
152
153
|
# Implicit rule generated for + modifier
|
153
154
|
# rule('X') => 'X item'.as '_plus_more'
|
154
155
|
def reduce__plus_more(_production, _range, _tokens, theChildren)
|
155
|
-
theChildren[0] << theChildren[1]
|
156
|
+
theChildren[0] << theChildren[1] # steep:ignore NoMethod
|
156
157
|
theChildren[0]
|
157
158
|
end
|
158
159
|
|
@@ -148,7 +148,7 @@ module Rley # This module is used as a namespace
|
|
148
148
|
# ... without changing current path
|
149
149
|
create_epsilon_node(anEntry, anIndex)
|
150
150
|
end
|
151
|
-
curr_path.pop if curr_parent.
|
151
|
+
curr_path.pop if curr_parent.is_a?(SPPF::AlternativeNode)
|
152
152
|
end
|
153
153
|
|
154
154
|
when :backtrack
|
@@ -172,7 +172,7 @@ module Rley # This module is used as a namespace
|
|
172
172
|
# ... without changing current path
|
173
173
|
create_epsilon_node(anEntry, anIndex)
|
174
174
|
end
|
175
|
-
curr_path.pop if curr_parent.
|
175
|
+
curr_path.pop if curr_parent.is_a?(SPPF::AlternativeNode)
|
176
176
|
end
|
177
177
|
end
|
178
178
|
end
|
@@ -221,6 +221,8 @@ module Rley # This module is used as a namespace
|
|
221
221
|
|
222
222
|
def create_epsilon_node(anEntry, anIndex)
|
223
223
|
new_node = SPPF::EpsilonNode.new(anIndex)
|
224
|
+
|
225
|
+
# @type var candidate : SPPF::EpsilonNode
|
224
226
|
candidate = add_node_to_forest(new_node)
|
225
227
|
entry2node[anEntry] = candidate
|
226
228
|
|
@@ -19,6 +19,7 @@ module Rley # This module is used as a namespace
|
|
19
19
|
# @param aSymbol [Syntax::Symbol] A symbol from grammar.
|
20
20
|
def initialize(aRange, aSymbol)
|
21
21
|
super
|
22
|
+
# @type self:CSTRawNode
|
22
23
|
self.range = aRange
|
23
24
|
self.symbol = aSymbol
|
24
25
|
self.children = nil
|
@@ -77,7 +78,7 @@ module Rley # This module is used as a namespace
|
|
77
78
|
|
78
79
|
protected
|
79
80
|
|
80
|
-
# Return the stack
|
81
|
+
# Return the stack of CSTRawNode
|
81
82
|
attr_reader(:stack)
|
82
83
|
|
83
84
|
# Overriding method.
|
@@ -180,6 +181,7 @@ module Rley # This module is used as a namespace
|
|
180
181
|
# For debugging purposes
|
181
182
|
raise StandardError if previous_tos.symbol != non_terminal
|
182
183
|
|
184
|
+
# @type var previous_tos : CSTRawNode
|
183
185
|
new_node = new_parent_node(rule, previous_tos.range,
|
184
186
|
tokens, previous_tos.children)
|
185
187
|
if stack.empty?
|
@@ -207,7 +209,9 @@ module Rley # This module is used as a namespace
|
|
207
209
|
# @param anEntry [ParseEntry] The entry being visited
|
208
210
|
def terminal_before_dot?(anEntry)
|
209
211
|
prev_symbol = anEntry.prev_symbol
|
210
|
-
|
212
|
+
|
213
|
+
# @type var prev_symbol : Syntax::GrmSymbol
|
214
|
+
prev_symbol.nil? ? false : prev_symbol.terminal?
|
211
215
|
end
|
212
216
|
|
213
217
|
# A terminal symbol was detected at left of dot.
|
@@ -262,6 +266,14 @@ module Rley # This module is used as a namespace
|
|
262
266
|
|
263
267
|
non_terminal
|
264
268
|
end
|
269
|
+
|
270
|
+
def new_leaf_node(_aProduction, _aTerminal, _aTokenPosition, _aToken)
|
271
|
+
raise NotImplementedError
|
272
|
+
end
|
273
|
+
|
274
|
+
def new_parent_node(_aProduction, _aRange, _theTokens, _theChildren)
|
275
|
+
raise NotImplementedError
|
276
|
+
end
|
265
277
|
end # class
|
266
278
|
end # module
|
267
279
|
end # module
|
@@ -15,7 +15,7 @@ module Rley # This module is used as a namespace
|
|
15
15
|
# that will create piece by piece the forest
|
16
16
|
def builder(aParseResult, aBuilder = nil)
|
17
17
|
if aBuilder
|
18
|
-
aBuilder.new(aParseResult.tokens)
|
18
|
+
aBuilder.new(aParseResult.tokens) # steep:ignore UnexpectedPositionalArgument
|
19
19
|
else
|
20
20
|
CSTBuilder.new(aParseResult.tokens)
|
21
21
|
end
|
@@ -7,11 +7,11 @@ module Rley # Module used as a namespace
|
|
7
7
|
# detected by Rley.
|
8
8
|
class ErrorReason
|
9
9
|
# @!attribute [r] rank
|
10
|
-
# @return [
|
10
|
+
# @return [Integer] The rank number of the offending input token
|
11
11
|
attr_reader(:rank)
|
12
12
|
|
13
13
|
# Constructor
|
14
|
-
# @param aRank [
|
14
|
+
# @param aRank [Integer] The sequence number of the offending input token.
|
15
15
|
def initialize(aRank)
|
16
16
|
@rank = aRank
|
17
17
|
end
|
@@ -98,7 +98,7 @@ module Rley # This module is used as a namespace
|
|
98
98
|
new_entry = ParseEntry.new(aVertex, anOrigin)
|
99
99
|
result = self[anIndex].push_entry(new_entry)
|
100
100
|
|
101
|
-
if aVertex.
|
101
|
+
if aVertex.is_a?(GFG::ItemVertex) && aVertex.dotted_item.constraint
|
102
102
|
ct = aVertex.dotted_item.constraint
|
103
103
|
|
104
104
|
case ct
|
@@ -198,8 +198,8 @@ module Rley # This module is used as a namespace
|
|
198
198
|
private
|
199
199
|
|
200
200
|
def add_entry_set
|
201
|
-
@sets << ParseEntrySet.new
|
202
201
|
@constraints << []
|
202
|
+
@sets << ParseEntrySet.new
|
203
203
|
end
|
204
204
|
|
205
205
|
def update_match_closest(aConstraint, anIndex)
|
@@ -32,7 +32,7 @@ module Rley # This module is used as a namespace
|
|
32
32
|
|
33
33
|
aTokenSequence.each_with_index do |token, i|
|
34
34
|
parse_for_token(result, i)
|
35
|
-
if token.terminal.
|
35
|
+
if token.terminal.is_a?(String)
|
36
36
|
symb = grammar.name2symbol[token.terminal]
|
37
37
|
token.instance_variable_set(:@terminal, symb)
|
38
38
|
end
|
@@ -51,7 +51,7 @@ module Rley # This module is used as a namespace
|
|
51
51
|
result.chart[index].each do |entry|
|
52
52
|
# Is entry of the form? [A => alpha . B beta, k]...
|
53
53
|
next_symbol = entry.next_symbol
|
54
|
-
if next_symbol.
|
54
|
+
if next_symbol.is_a?(Syntax::NonTerminal)
|
55
55
|
# ...apply the Call rule
|
56
56
|
call_rule(result, entry, index)
|
57
57
|
end
|
@@ -338,7 +338,7 @@ module Rley # This module is used as a namespace
|
|
338
338
|
full_range = { low: 0, high: anIndex }
|
339
339
|
start_production = chart.start_dotted_rule.production
|
340
340
|
|
341
|
-
ParseForestBuilder.new(start_production, full_range)
|
341
|
+
ParseRep::ParseForestBuilder.new(start_production, full_range)
|
342
342
|
end
|
343
343
|
|
344
344
|
# Factory method. Creates and initializes a ParseEntryTracker instance.
|
@@ -62,13 +62,13 @@ module Rley # This module is used as a namespace
|
|
62
62
|
|
63
63
|
# Returns true iff the vertex is a start vertex (i.e. of the form: .X)
|
64
64
|
def start_entry?
|
65
|
-
vertex.
|
65
|
+
vertex.is_a?(GFG::StartVertex)
|
66
66
|
end
|
67
67
|
|
68
68
|
# Returns true iff the vertex is at the start of rhs
|
69
69
|
# (i.e. of the form: X => .Y
|
70
70
|
def entry_entry?
|
71
|
-
return false unless vertex.
|
71
|
+
return false unless vertex.is_a?(GFG::ItemVertex)
|
72
72
|
|
73
73
|
vertex.dotted_item.at_start?
|
74
74
|
end
|
@@ -76,7 +76,7 @@ module Rley # This module is used as a namespace
|
|
76
76
|
# Returns true iff the vertex corresponds to a dotted item
|
77
77
|
# X => Y
|
78
78
|
def dotted_entry?
|
79
|
-
vertex.
|
79
|
+
vertex.is_a?(GFG::ItemVertex)
|
80
80
|
end
|
81
81
|
|
82
82
|
# Returns true iff the vertex is at end of rhs (i.e. of the form: X => Y.)
|
@@ -86,7 +86,7 @@ module Rley # This module is used as a namespace
|
|
86
86
|
|
87
87
|
# Returns true iff the vertex is an end vertex (i.e. of the form: X.)
|
88
88
|
def end_entry?
|
89
|
-
vertex.
|
89
|
+
vertex.is_a?(GFG::EndVertex)
|
90
90
|
end
|
91
91
|
|
92
92
|
# Return the symbol before the dot (if any)
|
@@ -62,6 +62,7 @@ module Rley # This module is used as a namespace
|
|
62
62
|
# @return [ParseEntry] the passed parse entry if it pushes it
|
63
63
|
def push_entry(anEntry)
|
64
64
|
entry_key = anEntry.hash
|
65
|
+
# @type var result : ParseEntry | false
|
65
66
|
result = membership.fetch(entry_key, false)
|
66
67
|
unless result
|
67
68
|
@entries << anEntry
|
@@ -71,6 +72,7 @@ module Rley # This module is used as a namespace
|
|
71
72
|
result = anEntry
|
72
73
|
end
|
73
74
|
|
75
|
+
# @type var result : ParseEntry
|
74
76
|
result
|
75
77
|
end
|
76
78
|
|
@@ -111,9 +113,10 @@ module Rley # This module is used as a namespace
|
|
111
113
|
|
112
114
|
def add_lookup4symbol(anEntry)
|
113
115
|
symb = anEntry.next_symbol
|
114
|
-
if symb.
|
116
|
+
if symb.is_a?(Syntax::Terminal)
|
115
117
|
@entries4term[symb] << anEntry
|
116
118
|
else
|
119
|
+
# @type var symb : Syntax::NonTerminal
|
117
120
|
@entries4n_term[symb] << anEntry
|
118
121
|
end
|
119
122
|
end
|
@@ -21,31 +21,34 @@ module Rley # This module is used as a namespace
|
|
21
21
|
|
22
22
|
# Write accessor. Sets the value of the entry set index
|
23
23
|
def entry_set_index=(anIndex)
|
24
|
-
@entry_set_index = anIndex
|
25
24
|
@processed_entries = {}
|
25
|
+
@entry_set_index = anIndex
|
26
26
|
end
|
27
27
|
|
28
28
|
# Write accessor. Set the given parse entry as the current one.
|
29
29
|
def parse_entry=(aParseEntry)
|
30
30
|
raise StandardError, 'Nil parse entry' if aParseEntry.nil?
|
31
31
|
|
32
|
-
@parse_entry
|
32
|
+
# @type var parse_entry : Rley::Parser::ParseEntry
|
33
33
|
processed_entries[parse_entry] = true
|
34
|
+
@parse_entry = aParseEntry
|
34
35
|
end
|
35
36
|
|
36
37
|
# Take the first provided entry that wasn't processed yet.
|
37
|
-
def select_entry(
|
38
|
-
a_entry =
|
39
|
-
self.parse_entry = a_entry
|
38
|
+
def select_entry(entries)
|
39
|
+
a_entry = entries.find { |st| !processed_entries.include?(st) }
|
40
|
+
self.parse_entry = a_entry # steep:ignore
|
40
41
|
end
|
41
42
|
|
42
43
|
# The dotted item for the current parse entry.
|
44
|
+
# @return [Rley::Base::DottedItem, nil]
|
43
45
|
def curr_dotted_item
|
44
|
-
parse_entry.
|
46
|
+
parse_entry&.vertex.dotted_item # steep:ignore
|
45
47
|
end
|
46
48
|
|
49
|
+
# @return [Syntax::GrmSymbol, nil] Return the symbol before the dot
|
47
50
|
def symbol_on_left
|
48
|
-
curr_dotted_item
|
51
|
+
curr_dotted_item&.prev_symbol
|
49
52
|
end
|
50
53
|
|
51
54
|
# Notification that one begins with the previous entry set
|
@@ -118,8 +118,9 @@ module Rley # This module is used as a namespace
|
|
118
118
|
# rubocop: disable Lint/DuplicateBranch
|
119
119
|
def visit_entry(anEntry, aContext)
|
120
120
|
index = aContext.entry_set_index
|
121
|
-
aContext.nterm2start[[anEntry, index]] if anEntry.start_entry?
|
121
|
+
aContext.nterm2start[[anEntry, index]] if anEntry.start_entry? # steep:ignore
|
122
122
|
|
123
|
+
# @type var event : [Symbol, ParseEntry, Integer]
|
123
124
|
if aContext.visitees.include?(anEntry) # Already visited?...
|
124
125
|
case anEntry.vertex
|
125
126
|
when GFG::EndVertex
|
@@ -155,8 +156,8 @@ module Rley # This module is used as a namespace
|
|
155
156
|
end
|
156
157
|
# rubocop: enable Lint/DuplicateBranch
|
157
158
|
|
158
|
-
def detect_scan_edge(
|
159
|
-
nil unless
|
159
|
+
def detect_scan_edge(ctx)
|
160
|
+
nil unless ctx.curr_entry.dotted_entry?
|
160
161
|
end
|
161
162
|
|
162
163
|
# Given the current entry from context object
|
@@ -178,22 +179,22 @@ module Rley # This module is used as a namespace
|
|
178
179
|
new_entry = aContext.curr_entry.antecedents.first
|
179
180
|
events = [new_entry]
|
180
181
|
traversed_edge = new_entry.vertex.edges.first
|
181
|
-
if new_entry.vertex.
|
182
|
+
if new_entry.vertex.is_a?(GFG::EndVertex)
|
182
183
|
# Return edge encountered
|
183
184
|
# Push current entry onto stack
|
184
185
|
# puts "Push on return stack #{aContext.curr_entry}"
|
185
186
|
aContext.return_stack << aContext.curr_entry
|
186
|
-
elsif traversed_edge.
|
187
|
+
elsif traversed_edge.is_a?(GFG::CallEdge)
|
187
188
|
# Pop top of stack
|
188
189
|
err_msg = 'Return stack empty!'
|
189
190
|
raise ScriptError, err_msg if aContext.return_stack.empty?
|
190
191
|
|
191
192
|
aContext.return_stack.pop
|
192
193
|
# puts "Pop from return stack matching entry #{new_entry}"
|
193
|
-
elsif traversed_edge.
|
194
|
+
elsif traversed_edge.is_a?(GFG::ScanEdge)
|
194
195
|
# Scan edge encountered, decrease sigma set index
|
195
196
|
aContext.entry_set_index -= 1
|
196
|
-
elsif traversed_edge.
|
197
|
+
elsif traversed_edge.is_a?(GFG::EpsilonEdge)
|
197
198
|
# Do nothing
|
198
199
|
else
|
199
200
|
raise NotImplementedError, "edge is a #{traversed_edge.class}"
|
@@ -269,6 +270,7 @@ module Rley # This module is used as a namespace
|
|
269
270
|
raise ScriptError, 'Empty return stack' if aContext.return_stack.empty?
|
270
271
|
|
271
272
|
# Retrieve top of stack
|
273
|
+
# @type var tos : Rley::Parser::ParseEntry
|
272
274
|
tos = aContext.return_stack.pop
|
273
275
|
tos_dotted_item = tos.vertex.dotted_item
|
274
276
|
|
@@ -37,6 +37,12 @@ module Rley # This module is used as a namespace
|
|
37
37
|
def to_s
|
38
38
|
"#{symbol.name}#{range.to_string(0)}"
|
39
39
|
end
|
40
|
+
|
41
|
+
# Part of the 'visitee' role in Visitor design pattern.
|
42
|
+
# @param aVisitor[ParseTreeVisitor] the visitor
|
43
|
+
def accept(aVisitor)
|
44
|
+
raise NotImplementedError
|
45
|
+
end
|
40
46
|
end # class
|
41
47
|
end # module
|
42
48
|
end # module
|
@@ -14,7 +14,7 @@ module Rley # This module is used as a namespace
|
|
14
14
|
# (major, minor) =
|
15
15
|
|
16
16
|
# Use '1.class' trick to support both Integer and Fixnum classes
|
17
|
-
range = aPos.
|
17
|
+
range = aPos.is_a?(1.class) ? { low: aPos, high: aPos + 1 } : aPos
|
18
18
|
super(aToken.terminal, range)
|
19
19
|
@token = aToken
|
20
20
|
end
|
data/lib/rley/rgn/ast_builder.rb
CHANGED
@@ -29,7 +29,7 @@ module Rley
|
|
29
29
|
protected
|
30
30
|
|
31
31
|
def terminal2node
|
32
|
-
Terminal2NodeClass
|
32
|
+
Terminal2NodeClass # steep:ignore UnknownConstant
|
33
33
|
end
|
34
34
|
|
35
35
|
# Method override
|
@@ -166,7 +166,7 @@ module Rley
|
|
166
166
|
# rule('key_value' => 'KEY value')
|
167
167
|
def reduce_raw_pair(_production, _range, _tokens, theChildren)
|
168
168
|
key = theChildren[0].token.lexeme
|
169
|
-
value = if theChildren[1].
|
169
|
+
value = if theChildren[1].is_a?(Rley::PTree::TerminalNode)
|
170
170
|
theChildren[1].token.lexeme
|
171
171
|
else
|
172
172
|
theChildren[1]
|
data/lib/rley/rgn/ast_node.rb
CHANGED
@@ -22,7 +22,7 @@ module Rley
|
|
22
22
|
def annotation_to_text
|
23
23
|
map_arr = []
|
24
24
|
@annotation.each_pair do |key, val|
|
25
|
-
literal = val.
|
25
|
+
literal = val.is_a?(String) ? "'#{val}'" : val
|
26
26
|
map_arr << "#{key}: #{literal}"
|
27
27
|
end
|
28
28
|
|
@@ -34,6 +34,16 @@ module Rley
|
|
34
34
|
# Default: do nothing ...
|
35
35
|
end
|
36
36
|
|
37
|
+
# @nodoc
|
38
|
+
def name
|
39
|
+
raise NotImplementedError
|
40
|
+
end
|
41
|
+
|
42
|
+
# @nodoc
|
43
|
+
def to_text
|
44
|
+
raise NotImplementedError
|
45
|
+
end
|
46
|
+
|
37
47
|
# Abstract method (must be overriden in subclasses).
|
38
48
|
# Part of the 'visitee' role in Visitor design pattern.
|
39
49
|
# @param _visitor [ASTVisitor] the visitor
|
data/lib/rley/rgn/ast_visitor.rb
CHANGED
@@ -75,7 +75,7 @@ module Rley
|
|
75
75
|
|
76
76
|
# Visit event. The visitor is about to visit the subnodes of a non
|
77
77
|
# terminal node.
|
78
|
-
# @param aParentNode [
|
78
|
+
# @param aParentNode [CompositeNode] the parent node.
|
79
79
|
def traverse_subnodes(aParentNode)
|
80
80
|
subnodes = aParentNode.subnodes
|
81
81
|
broadcast(:before_subnodes, aParentNode, subnodes)
|
@@ -88,7 +88,7 @@ module Rley
|
|
88
88
|
|
89
89
|
# Visit event. The visitor is about to visit one given subnode of a non
|
90
90
|
# terminal node.
|
91
|
-
# @param aParentNode [
|
91
|
+
# @param aParentNode [CompositeNode] the parent node.
|
92
92
|
# @param index [integer] index of child subnode
|
93
93
|
def traverse_given_subnode(aParentNode, index)
|
94
94
|
subnode = aParentNode.subnodes[index]
|
@@ -7,7 +7,7 @@ require_relative '../syntax/match_closest'
|
|
7
7
|
module Rley # This module is used as a namespace
|
8
8
|
# Namespace for classes that define RGN (Rley Grammar Notation)
|
9
9
|
module RGN # This module is used as a namespace
|
10
|
-
# Structure used by Rley to generate
|
10
|
+
# Structure used by Rley to generate implicit production rules.
|
11
11
|
RawRule = Struct.new(:lhs, :rhs, :tag, :simple, :constraints)
|
12
12
|
|
13
13
|
# Builder GoF pattern. Builder builds a complex object
|
@@ -65,10 +65,10 @@ module Rley # This module is used as a namespace
|
|
65
65
|
# Add the given marker symbol to the grammar of the language
|
66
66
|
# @param aMarkerSymbol [String] A marker symbol
|
67
67
|
# @return [void]
|
68
|
-
def add_marker(aMarkerSymbol)
|
69
|
-
|
70
|
-
|
71
|
-
end
|
68
|
+
# def add_marker(aMarkerSymbol)
|
69
|
+
# new_symb = build_symbol(Syntax::Marker, aMarkerSymbol)
|
70
|
+
# symbols[new_symb.name] = new_symb
|
71
|
+
# end
|
72
72
|
|
73
73
|
# Add a production rule in the grammar given one
|
74
74
|
# key-value pair of the form: String => String.
|
@@ -85,7 +85,7 @@ module Rley # This module is used as a namespace
|
|
85
85
|
def add_production(aProductionRepr)
|
86
86
|
aProductionRepr.each_pair do |(lhs_name, rhs_repr)|
|
87
87
|
lhs = get_grm_symbol(lhs_name)
|
88
|
-
rhs = rhs_repr.
|
88
|
+
rhs = rhs_repr.is_a?(Array) && rhs_repr.empty? ? '' : rhs_repr.strip
|
89
89
|
constraints = []
|
90
90
|
if rhs.empty?
|
91
91
|
rhs_members = []
|
@@ -96,7 +96,7 @@ module Rley # This module is used as a namespace
|
|
96
96
|
visitor.subscribe(self)
|
97
97
|
visitor.start
|
98
98
|
root_node = ast.root
|
99
|
-
constraints = root_node.constraints unless root_node.
|
99
|
+
constraints = root_node.constraints unless root_node.is_a?(SymbolNode)
|
100
100
|
|
101
101
|
rhs_members = visitor2rhs.delete(visitor)
|
102
102
|
end
|
@@ -120,12 +120,12 @@ module Rley # This module is used as a namespace
|
|
120
120
|
|
121
121
|
# Check that each terminal appears at least in a rhs of a production
|
122
122
|
all_terminals = symbols.values.select do |a_symb|
|
123
|
-
a_symb.
|
123
|
+
a_symb.is_a?(Syntax::Terminal)
|
124
124
|
end
|
125
125
|
in_use = Set.new
|
126
126
|
productions.each do |prod|
|
127
127
|
prod.rhs.members.each do |symb|
|
128
|
-
in_use << symb if symb.
|
128
|
+
in_use << symb if symb.is_a?(Syntax::Terminal)
|
129
129
|
end
|
130
130
|
end
|
131
131
|
|
@@ -293,7 +293,7 @@ module Rley # This module is used as a namespace
|
|
293
293
|
aProductionRepr.each_pair do |(lhs_name, rhs_repr)|
|
294
294
|
lhs = get_grm_symbol(lhs_name)
|
295
295
|
|
296
|
-
if rhs_repr.
|
296
|
+
if rhs_repr.is_a?(String)
|
297
297
|
rhs = rhs_repr.strip.scan(/\S+/)
|
298
298
|
else
|
299
299
|
rhs = rhs_repr
|
@@ -338,7 +338,7 @@ module Rley # This module is used as a namespace
|
|
338
338
|
# @param aSymbolArg [GrmSymbol-like or String]
|
339
339
|
# @return [Array] list of grammar symbols
|
340
340
|
def build_symbol(aClass, aSymbolArg)
|
341
|
-
if aSymbolArg.
|
341
|
+
if aSymbolArg.is_a?(Syntax::GrmSymbol)
|
342
342
|
aSymbolArg
|
343
343
|
else
|
344
344
|
aClass.new(aSymbolArg)
|
@@ -385,7 +385,7 @@ module Rley # This module is used as a namespace
|
|
385
385
|
end
|
386
386
|
|
387
387
|
def node_base_name(aNode)
|
388
|
-
if aNode.
|
388
|
+
if aNode.is_a?(SymbolNode)
|
389
389
|
aNode.name
|
390
390
|
else
|
391
391
|
sequence_name(aNode)
|
data/lib/rley/rgn/parser.rb
CHANGED
@@ -37,7 +37,7 @@ module Rley
|
|
37
37
|
|
38
38
|
# Parse the given RGN snippet into a parse tree.
|
39
39
|
# @param source [String] Snippet to parse
|
40
|
-
# @return [Rley::ParseTree] A parse tree equivalent to the RGN input.
|
40
|
+
# @return [Rley::PTree::ParseTree] A parse tree equivalent to the RGN input.
|
41
41
|
def parse(source)
|
42
42
|
lexer = Tokenizer.new(source)
|
43
43
|
result = engine.parse(lexer.tokens)
|
@@ -49,7 +49,7 @@ module Rley
|
|
49
49
|
raise SyntaxError, line1 + line2
|
50
50
|
end
|
51
51
|
|
52
|
-
|
52
|
+
engine.convert(result) # engine.to_ptree(result)
|
53
53
|
end
|
54
54
|
end # class
|
55
55
|
end # module
|
data/lib/rley/rley_error.rb
CHANGED
@@ -1,12 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
# File: rley_error.rb
|
4
|
-
|
5
3
|
module Rley # Module used as a namespace
|
6
4
|
# @abstract
|
7
5
|
# Base class for any exception explicitly raised by Rley code.
|
8
6
|
class RleyError < StandardError
|
9
7
|
end # class
|
10
8
|
end # module
|
11
|
-
|
12
|
-
# End of file
|
@@ -34,6 +34,12 @@ module Rley # This module is used as a namespace
|
|
34
34
|
def key
|
35
35
|
@key ||= to_string(0)
|
36
36
|
end
|
37
|
+
|
38
|
+
# Part of the 'visitee' role in Visitor design pattern.
|
39
|
+
# @param aVisitor[ParseTreeVisitor] the visitor
|
40
|
+
def accept(aVisitor)
|
41
|
+
raise NotImplementedError
|
42
|
+
end
|
37
43
|
end # class
|
38
44
|
end # module
|
39
45
|
end # module
|
@@ -51,13 +51,13 @@ module Rley # This module is used as a namespace
|
|
51
51
|
# parse trees. That enumerator will generate a parse tree when
|
52
52
|
# called with `next` method.
|
53
53
|
# @return [Enumerator]
|
54
|
-
def to_ptree_enum
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
end
|
54
|
+
# def to_ptree_enum
|
55
|
+
# # How to implement?
|
56
|
+
# # One visits the forest => beware of dependency
|
57
|
+
# # At each visited item create a corresponding tree node.
|
58
|
+
# # At end of visit & stack not empty
|
59
|
+
# # Re-generate another ptree
|
60
|
+
# end
|
61
61
|
|
62
62
|
# Part of the 'visitee' role in the Visitor design pattern.
|
63
63
|
# A visitee is expected to accept the visit from a visitor object
|
data/lib/rley/sppf/sppf_node.rb
CHANGED
@@ -20,9 +20,23 @@ module Rley # This module is used as a namespace
|
|
20
20
|
# Return the origin, that is, the index of the
|
21
21
|
# first token matched by this node.
|
22
22
|
# @return [Integer]
|
23
|
-
def origin
|
23
|
+
def origin # steep:ignore MethodBodyTypeMismatch
|
24
24
|
range.low
|
25
25
|
end
|
26
|
+
|
27
|
+
# Emit a (formatted) string representation of the node.
|
28
|
+
# Mainly used for diagnosis/debugging purposes.
|
29
|
+
# @param indentation [Integer]
|
30
|
+
# @return [String]
|
31
|
+
def to_string(indentation)
|
32
|
+
raise NotImplementedError
|
33
|
+
end
|
34
|
+
|
35
|
+
# Part of the 'visitee' role in Visitor design pattern.
|
36
|
+
# @param aVisitor[ParseForestVisitor] the visitor
|
37
|
+
def accept(aVisitor)
|
38
|
+
raise NotImplementedError
|
39
|
+
end
|
26
40
|
end # class
|
27
41
|
end # module
|
28
42
|
end # module
|
@@ -53,14 +53,6 @@ module Rley # This module is used as a namespace
|
|
53
53
|
symbols.merge!(new_symbs)
|
54
54
|
end
|
55
55
|
|
56
|
-
# Add the given marker symbol to the grammar of the language
|
57
|
-
# @param aMarkerSymbol [Syntax::Marker] A mazker symbol
|
58
|
-
# @return [void]
|
59
|
-
def add_marker(aMarkerSymbol)
|
60
|
-
new_symb = build_symbol(Marker, aMarkerSymbol)
|
61
|
-
symbols[aMarkerSymbol.name] = new_symb
|
62
|
-
end
|
63
|
-
|
64
56
|
# Add a production rule in the grammar given one
|
65
57
|
# key-value pair of the form: String => Array.
|
66
58
|
# Where the key is the name of the non-terminal appearing in the
|
@@ -106,12 +98,12 @@ module Rley # This module is used as a namespace
|
|
106
98
|
|
107
99
|
# Check that each terminal appears at least in a rhs of a production
|
108
100
|
all_terminals = symbols.values.select do |a_symb|
|
109
|
-
a_symb.
|
101
|
+
a_symb.is_a?(Terminal)
|
110
102
|
end
|
111
103
|
in_use = Set.new
|
112
104
|
productions.each do |prod|
|
113
105
|
prod.rhs.members.each do |symb|
|
114
|
-
in_use << symb if symb.
|
106
|
+
in_use << symb if symb.is_a?(Syntax::Terminal)
|
115
107
|
end
|
116
108
|
end
|
117
109
|
|
@@ -168,7 +160,7 @@ module Rley # This module is used as a namespace
|
|
168
160
|
# @param aSymbolArg [GrmSymbol-like or String]
|
169
161
|
# @return [Array] list of grammar symbols
|
170
162
|
def build_symbol(aClass, aSymbolArg)
|
171
|
-
if aSymbolArg.
|
163
|
+
if aSymbolArg.is_a?(GrmSymbol)
|
172
164
|
aSymbolArg
|
173
165
|
else
|
174
166
|
aClass.new(aSymbolArg)
|
data/lib/rley/syntax/grammar.rb
CHANGED
@@ -48,7 +48,7 @@ module Rley # This module is used as a namespace
|
|
48
48
|
|
49
49
|
# @return [Array] The list of non-terminals in the grammar.
|
50
50
|
def non_terminals
|
51
|
-
@non_terminals ||= symbols.select { |s| s.
|
51
|
+
@non_terminals ||= symbols.select { |s| s.is_a?(NonTerminal) }
|
52
52
|
end
|
53
53
|
|
54
54
|
# @return [Production] The start production of the grammar (i.e.
|
@@ -73,6 +73,7 @@ module Rley # This module is used as a namespace
|
|
73
73
|
add_symbol(the_lhs)
|
74
74
|
|
75
75
|
aProduction.rhs.each { |symb| add_symbol(symb) }
|
76
|
+
aProduction
|
76
77
|
end
|
77
78
|
|
78
79
|
# If the production is anonymous, then assign it
|
@@ -81,12 +82,15 @@ module Rley # This module is used as a namespace
|
|
81
82
|
return unless aProduction.name.nil?
|
82
83
|
|
83
84
|
index = rules.find_index(aProduction)
|
85
|
+
# @type var index : Integer
|
86
|
+
|
84
87
|
prefix = aProduction.lhs.name.dup
|
85
88
|
previous = index.zero? ? nil : rules[index - 1]
|
86
89
|
if previous.nil? || previous.lhs != aProduction.lhs
|
87
90
|
suffix = '_0'
|
88
91
|
else
|
89
|
-
|
92
|
+
# @type var previous : Production
|
93
|
+
prev_serial = previous.name&.match(/_(\d+)$/)
|
90
94
|
if prev_serial
|
91
95
|
suffix = "_#{prev_serial[1].to_i + 1}"
|
92
96
|
else
|
@@ -144,6 +148,8 @@ module Rley # This module is used as a namespace
|
|
144
148
|
end
|
145
149
|
|
146
150
|
last_considered = nil
|
151
|
+
# @type var last_considered : Rley::Syntax::GrmSymbol
|
152
|
+
|
147
153
|
a_rule.rhs.members.each do |symbol|
|
148
154
|
last_considered = symbol
|
149
155
|
break unless symbol.generative?
|
@@ -199,7 +205,7 @@ module Rley # This module is used as a namespace
|
|
199
205
|
# Drop productions with one terminal in rhs or with a nullable lhs
|
200
206
|
filtered_rules = rules.reject do |prod|
|
201
207
|
prod.lhs.nullable? || prod.rhs.find do |symb|
|
202
|
-
symb.
|
208
|
+
symb.is_a?(Terminal)
|
203
209
|
end
|
204
210
|
end
|
205
211
|
|
@@ -92,7 +92,7 @@ module Rley # This module is used as a namespace
|
|
92
92
|
# Validation method. Return the validated input argument or
|
93
93
|
# raise an exception.
|
94
94
|
def valid_lhs(aNonTerminal)
|
95
|
-
unless aNonTerminal.
|
95
|
+
unless aNonTerminal.is_a?(NonTerminal)
|
96
96
|
msg_prefix = 'Left side of production must be a non-terminal symbol'
|
97
97
|
msg_suffix = ", found a #{aNonTerminal.class} instead."
|
98
98
|
raise StandardError, msg_prefix + msg_suffix
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rley
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.02
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dimitri Geshef
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-
|
10
|
+
date: 2025-03-18 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: prime
|
@@ -29,47 +29,47 @@ dependencies:
|
|
29
29
|
requirements:
|
30
30
|
- - "~>"
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: 13
|
32
|
+
version: '13'
|
33
33
|
- - ">="
|
34
34
|
- !ruby/object:Gem::Version
|
35
|
-
version: 13.
|
35
|
+
version: 13.0.6
|
36
36
|
type: :development
|
37
37
|
prerelease: false
|
38
38
|
version_requirements: !ruby/object:Gem::Requirement
|
39
39
|
requirements:
|
40
40
|
- - "~>"
|
41
41
|
- !ruby/object:Gem::Version
|
42
|
-
version: 13
|
42
|
+
version: '13'
|
43
43
|
- - ">="
|
44
44
|
- !ruby/object:Gem::Version
|
45
|
-
version: 13.
|
45
|
+
version: 13.0.6
|
46
46
|
- !ruby/object:Gem::Dependency
|
47
47
|
name: rspec
|
48
48
|
requirement: !ruby/object:Gem::Requirement
|
49
49
|
requirements:
|
50
50
|
- - "~>"
|
51
51
|
- !ruby/object:Gem::Version
|
52
|
-
version: 3.
|
52
|
+
version: '3.1'
|
53
53
|
- - ">="
|
54
54
|
- !ruby/object:Gem::Version
|
55
|
-
version: 3.12
|
55
|
+
version: '3.12'
|
56
56
|
type: :development
|
57
57
|
prerelease: false
|
58
58
|
version_requirements: !ruby/object:Gem::Requirement
|
59
59
|
requirements:
|
60
60
|
- - "~>"
|
61
61
|
- !ruby/object:Gem::Version
|
62
|
-
version: 3.
|
62
|
+
version: '3.1'
|
63
63
|
- - ">="
|
64
64
|
- !ruby/object:Gem::Version
|
65
|
-
version: 3.12
|
65
|
+
version: '3.12'
|
66
66
|
- !ruby/object:Gem::Dependency
|
67
67
|
name: yard
|
68
68
|
requirement: !ruby/object:Gem::Requirement
|
69
69
|
requirements:
|
70
70
|
- - "~>"
|
71
71
|
- !ruby/object:Gem::Version
|
72
|
-
version: 0.9
|
72
|
+
version: '0.9'
|
73
73
|
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
75
|
version: 0.9.34
|
@@ -79,7 +79,7 @@ dependencies:
|
|
79
79
|
requirements:
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: 0.9
|
82
|
+
version: '0.9'
|
83
83
|
- - ">="
|
84
84
|
- !ruby/object:Gem::Version
|
85
85
|
version: 0.9.34
|
@@ -95,6 +95,7 @@ files:
|
|
95
95
|
- ".ruby-gemset"
|
96
96
|
- ".yardopts"
|
97
97
|
- CHANGELOG.md
|
98
|
+
- Gemfile
|
98
99
|
- LICENSE.txt
|
99
100
|
- README.md
|
100
101
|
- Rakefile
|
@@ -316,9 +317,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
316
317
|
- !ruby/object:Gem::Version
|
317
318
|
version: '0'
|
318
319
|
requirements: []
|
319
|
-
rubygems_version: 3.6.
|
320
|
+
rubygems_version: 3.6.6
|
320
321
|
specification_version: 4
|
321
|
-
summary:
|
322
|
+
summary: A parsing library based on the Earley's parsing algorithm.
|
322
323
|
test_files:
|
323
324
|
- spec/rley/base/dotted_item_spec.rb
|
324
325
|
- spec/rley/base/grm_items_builder_spec.rb
|