parsanol 1.3.65 → 1.3.66
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/lib/parsanol/parg/lutaml.rb +4 -0
- data/lib/parsanol/version.rb +1 -1
- data/lib/parsanol/vm.rb +25 -18
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: da894739a391336f9b9f65a65abc87da1fe51b3f3268c0c2334638e53f5adb8f
|
|
4
|
+
data.tar.gz: 6777a602a63a37e599fdc1ed9c38f82eb8b01a30a12a23c24bbed7518f37e5cf
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 0fad1aa5febfc712a767578c4ca4d9c9c6cf3def48ed7f6fe97a66a95e45d0e628a4285660eb14b40e6d0b72bbd6422868b85ea901d84318382f23aa5744378b
|
|
7
|
+
data.tar.gz: 6ab9b3b4461592a3a5e91accd57d0341c59c7f878985b01fd89b73fe91c8abd71eacedd6246d0c79a2fd57547607415c0932e73cfb2c2e61b3adb2af5165a9a6
|
data/lib/parsanol/parg/lutaml.rb
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# Standalone requires of this file bypass the parg autoload registry —
|
|
4
|
+
# declare the namespace dependency so Artifact resolves.
|
|
5
|
+
require "parsanol/parg"
|
|
6
|
+
|
|
3
7
|
module Parsanol
|
|
4
8
|
module PARG
|
|
5
9
|
# lutaml-model integration: register a PARG artifact as a lutaml-model
|
data/lib/parsanol/version.rb
CHANGED
data/lib/parsanol/vm.rb
CHANGED
|
@@ -175,8 +175,10 @@ module Parsanol
|
|
|
175
175
|
compiler.to_program
|
|
176
176
|
end
|
|
177
177
|
|
|
178
|
+
# Returns violation descriptions for this atom's ordered-choice
|
|
179
|
+
# branches (empty-matchable non-last branches shadow later ones).
|
|
178
180
|
def validate_choice_branches(atom)
|
|
179
|
-
atom.alternatives.each_with_index do |branch, idx|
|
|
181
|
+
atom.alternatives.each_with_index.filter_map do |branch, idx|
|
|
180
182
|
walk_branch = branch
|
|
181
183
|
next if idx == atom.alternatives.size - 1
|
|
182
184
|
|
|
@@ -194,14 +196,13 @@ module Parsanol
|
|
|
194
196
|
next if walk_branch.nil?
|
|
195
197
|
next unless Compiler.new.nullable?(walk_branch)
|
|
196
198
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
"ones come last, or make the branch non-empty."
|
|
199
|
+
"alternative branch #{idx} (#{branch.inspect}) can match " \
|
|
200
|
+
"empty input and is not the last branch — ordered choice " \
|
|
201
|
+
"commits to its empty match, so " \
|
|
202
|
+
"#{atom.alternatives.size - idx - 1} later branch(es) can " \
|
|
203
|
+
"never match at positions where it matches empty. Reorder " \
|
|
204
|
+
"branches so empty-matchable ones come last, or make the " \
|
|
205
|
+
"branch non-empty."
|
|
205
206
|
end
|
|
206
207
|
end
|
|
207
208
|
|
|
@@ -211,6 +212,7 @@ module Parsanol
|
|
|
211
212
|
# the grammar is wrong, and inputs it would mis-parse fail with a
|
|
212
213
|
# baffling cause. Raise before any input is seen.
|
|
213
214
|
def validate_alternatives(root)
|
|
215
|
+
violations = []
|
|
214
216
|
visited = {}.compare_by_identity
|
|
215
217
|
walk = lambda do |atom, depth|
|
|
216
218
|
next if atom.nil? || depth > 20
|
|
@@ -219,26 +221,26 @@ module Parsanol
|
|
|
219
221
|
visited[atom] = true
|
|
220
222
|
case atom
|
|
221
223
|
when Parsanol::Atoms::Alternative
|
|
222
|
-
validate_choice_branches(atom)
|
|
224
|
+
violations.concat(validate_choice_branches(atom))
|
|
223
225
|
atom.alternatives.each { |c| walk.call(c, depth + 1) }
|
|
224
226
|
when Parsanol::Atoms::Sequence
|
|
225
227
|
atom.parslets.each { |c| walk.call(c, depth + 1) }
|
|
226
228
|
when Parsanol::Atoms::Repetition, Parsanol::Atoms::Named
|
|
227
229
|
walk.call(atom.parslet, depth + 1)
|
|
228
|
-
when Parsanol::Atoms::Lookahead
|
|
229
|
-
walk.call(atom.bound_parslet, depth + 1)
|
|
230
|
-
when Parsanol::Atoms::Ignored
|
|
231
|
-
walk.call(atom.wrapped_atom, depth + 1)
|
|
232
230
|
when Parsanol::Atoms::Entity
|
|
231
|
+
# Rule bodies hide behind the entity wrapper; without this
|
|
232
|
+
# descent the lint passes DSL grammars that fail the same
|
|
233
|
+
# grammar compiled from PARG (where bodies are inlined).
|
|
234
|
+
# Entities that cannot resolve outside a parse are skipped.
|
|
233
235
|
begin
|
|
234
236
|
walk.call(atom.parslet, depth + 1)
|
|
235
|
-
rescue Parsanol::GrammarError
|
|
236
|
-
raise
|
|
237
237
|
rescue StandardError
|
|
238
|
-
# Lazily resolved / recursive entity that cannot resolve
|
|
239
|
-
# outside a parse: skip this branch of the walk.
|
|
240
238
|
nil
|
|
241
239
|
end
|
|
240
|
+
when Parsanol::Atoms::Lookahead
|
|
241
|
+
walk.call(atom.bound_parslet, depth + 1)
|
|
242
|
+
when Parsanol::Atoms::Ignored
|
|
243
|
+
walk.call(atom.wrapped_atom, depth + 1)
|
|
242
244
|
when Parsanol::Atoms::Scope
|
|
243
245
|
begin
|
|
244
246
|
walk.call(atom.block.call, depth + 1)
|
|
@@ -248,6 +250,11 @@ module Parsanol
|
|
|
248
250
|
end
|
|
249
251
|
end
|
|
250
252
|
walk.call(root, 0)
|
|
253
|
+
return if violations.empty?
|
|
254
|
+
|
|
255
|
+
raise Parsanol::GrammarError,
|
|
256
|
+
"wrong grammar: #{violations.size} shadowed-alternative " \
|
|
257
|
+
"violation(s):\n - #{violations.join('\n - ')}"
|
|
251
258
|
end
|
|
252
259
|
|
|
253
260
|
# Executes a compiled program. Returns [true, value] on success;
|