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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a40f12d1d7a5fc67b1ef3255e9d9c5f4c38fd6a8fb266995974beec982728ca1
4
- data.tar.gz: 297a013726a6e9ff9e81b385a8074e45afd5e9a22739e28852219f35cd1ad3a4
3
+ metadata.gz: da894739a391336f9b9f65a65abc87da1fe51b3f3268c0c2334638e53f5adb8f
4
+ data.tar.gz: 6777a602a63a37e599fdc1ed9c38f82eb8b01a30a12a23c24bbed7518f37e5cf
5
5
  SHA512:
6
- metadata.gz: 6f171865bebc41146db262fcbdf5f05bdd3daf0e424cf29eaf26351408ca5d35db904057dfd64f0b57bd6a18190e48596bfd2af21ebfbf75d79a7fbc421c2bd1
7
- data.tar.gz: d69f48dcc19e090e4b7c0fa880f142d9a76ff95e1aa6d8f73803558902c66621abbc7f28d24ca683ecadab7a5f6855fb88913dfecf05e5699a12780e98722ff7
6
+ metadata.gz: 0fad1aa5febfc712a767578c4ca4d9c9c6cf3def48ed7f6fe97a66a95e45d0e628a4285660eb14b40e6d0b72bbd6422868b85ea901d84318382f23aa5744378b
7
+ data.tar.gz: 6ab9b3b4461592a3a5e91accd57d0341c59c7f878985b01fd89b73fe91c8abd71eacedd6246d0c79a2fd57547607415c0932e73cfb2c2e61b3adb2af5165a9a6
@@ -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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Parsanol
4
- VERSION = "1.3.65"
4
+ VERSION = "1.3.66"
5
5
  end
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
- raise Parsanol::GrammarError,
198
- "wrong grammar: alternative branch #{idx} " \
199
- "(#{branch.inspect}) can match empty input and is not " \
200
- "the last branch — ordered choice commits to its empty " \
201
- "match, so #{atom.alternatives.size - idx - 1} later " \
202
- "branch(es) can never match at positions where it " \
203
- "matches empty. Reorder branches so empty-matchable " \
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;
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: parsanol
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.65
4
+ version: 1.3.66
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.