parsanol 1.3.62 → 1.3.63

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: dc7df8984ab8f887379dc43d351e628656048cf4fd2a4bdd359b0b8b45341ce0
4
- data.tar.gz: 38f9a43f7d4bf61621ef843d672f66883d5eee7abbe9af596b065499f89dcb12
3
+ metadata.gz: f7ad59a2f852639eec49d8aaf0cfce4be63d8e13a20941b7db8f325244445e47
4
+ data.tar.gz: b4f7021d4c4dd9f30df4eddf64b2109da9005291b4d39edadd5075e54c6600c0
5
5
  SHA512:
6
- metadata.gz: 60c1f94221c0f97ebd61f27f6e409667630b0fd013aeabebab44cbb4918a8f22e951878ffce3f9d40b8a48d7a7bf4f4fb99c160efe11fdefe682beac63c48dca
7
- data.tar.gz: b3fa201e5e2290698c3532eee6ba251a88547c4627348c791c08406b849ad651136ab65281ffa2f72b9629999b4af261679379f8f5e3d014ad82670ba0360349
6
+ metadata.gz: d5fe08eb23fa452e06432cb8b72cb101b257b854fb33ae71455fd8c2a0d81356704f66fd11af330392783aa6c6a5b4730df1884718459c5d4acfe3abc74b8b48
7
+ data.tar.gz: b2d8251fc66c8d47085bf6338457975b6f29e707a173c8e107d5755137bd850ead86c6d130b6410b29e4155e87ae4c67cac3739278f0ddd4a7826fc94ffba53e
@@ -28,8 +28,13 @@ module Parsanol
28
28
  unless envelope["shape"] == SUPPORTED_SHAPE
29
29
  raise ArtifactError,
30
30
  "unsupported artifact shape #{envelope['shape'].inspect} " \
31
- "(this runtime implements #{SUPPORTED_SHAPE.inspect})"
31
+ "(this runtime implements #{SUPPORTED_SHAPE.inspect}; the " \
32
+ "contract is docs/PARSANOL-SHAPE-v2.md in parsanol-rs — " \
33
+ "a shape bump requires a new engine family, artifacts " \
34
+ "declaring #{SUPPORTED_SHAPE.inspect} parse identically forever)"
32
35
  end
36
+ bindings = envelope["bindings"]
37
+ validate_bindings!(bindings) unless bindings.nil?
33
38
  @envelope = envelope
34
39
  @path = path
35
40
  @tables_dir = tables_dir
@@ -139,15 +144,27 @@ module Parsanol
139
144
 
140
145
  # Structured parse diagnostics (PN 2): {offset, message} for the
141
146
  # deepest failure of the most recent parse attempt on this entry.
147
+ # Structured parse diagnostics — the flat v1 wire format every
148
+ # backend agrees on (parsanol-rs#145): offset, the expected-symbol
149
+ # list, and a message, fetched out-of-band so success paths pay
150
+ # nothing. Full cause trees stay a Ruby-side diagnostic.
142
151
  def parse_with_diagnostics(entry_name, input, mode: :native)
143
152
  shape = parse(entry_name, input, mode: mode)
144
- { "ok" => true, "offset" => nil, "message" => nil, "shape" => shape }
153
+ { "ok" => true, "offset" => nil, "expected" => [],
154
+ "message" => nil, "shape" => shape }
145
155
  rescue Parsanol::ParseFailed => e
146
156
  cause = deepest_cause(e.parse_failure_cause)
147
157
  { "ok" => false, "offset" => cause&.position,
158
+ "expected" => expected_labels_for(cause),
148
159
  "message" => cause&.message || e.message, "shape" => nil }
149
160
  end
150
161
 
162
+ def expected_labels_for(cause)
163
+ return [] unless cause.respond_to?(:expected)
164
+
165
+ Array(cause.expected)
166
+ end
167
+
151
168
  def deepest_cause(cause)
152
169
  return cause if cause.nil? || cause.children.empty?
153
170
 
@@ -169,7 +186,7 @@ module Parsanol
169
186
 
170
187
  file = declared
171
188
  path = File.join(@tables_dir.to_s, file)
172
- raw = path.end_with?(".json") ? JSON.parse(PARG.read_utf8(path)) : YAML.safe_load_file(path, aliases: true)
189
+ raw = path.end_with?(".json") ? JSON.parse(PARG.read_utf8(path)) : YAML.safe_load(PARG.read_utf8(path), aliases: true)
173
190
  rows = case raw
174
191
  when Hash
175
192
  raw.map { |key, value| { "name" => key.to_s }.merge(value.to_h.transform_keys(&:to_s)) }
@@ -179,6 +196,39 @@ module Parsanol
179
196
  @table_cache[name] = rows
180
197
  end
181
198
 
199
+ # The envelope's optional grammar-to-model bindings section
200
+ # (envelope v2, parsanol-rs#143): capture name -> model attribute
201
+ # paths, type casts, cardinality, and preprocessing step refs,
202
+ # declared once and consumed identically by every tier's binder.
203
+ # Phase 1 validates the section's shape and exposes it as data.
204
+ def bindings
205
+ envelope["bindings"]
206
+ end
207
+
208
+ BINDINGS_ALLOWED_KEYS = %w[captures entries version].freeze
209
+
210
+ def validate_bindings!(bindings)
211
+ unless bindings.is_a?(Hash)
212
+ raise ArtifactError, "bindings section must be a map (got #{bindings.class})"
213
+ end
214
+
215
+ unknown = bindings.keys - BINDINGS_ALLOWED_KEYS
216
+ unless unknown.empty?
217
+ raise ArtifactError, "bindings section has unknown keys: #{unknown.inspect}"
218
+ end
219
+
220
+ (bindings["captures"] || {}).each do |name, spec|
221
+ unless spec.is_a?(Hash) && spec["path"].is_a?(String)
222
+ raise ArtifactError,
223
+ "bindings capture #{name.inspect} must declare a string :path"
224
+ end
225
+ end
226
+ rescue ArtifactError
227
+ raise
228
+ rescue StandardError => e
229
+ raise ArtifactError, "malformed bindings section: #{e.class}: #{e.message}"
230
+ end
231
+
182
232
  def compiler
183
233
  @compiler ||= begin
184
234
  document = Parser.new(envelope.fetch("source")).parse
@@ -40,9 +40,13 @@ module Parsanol
40
40
  end
41
41
  end
42
42
 
43
- def initialize(document, tables_dir)
43
+ def initialize(document, tables_dir, bindings: nil)
44
44
  @document = document
45
45
  @tables_dir = tables_dir
46
+ # Envelope v2 (parsanol-rs#143): grammar-to-model bindings bake
47
+ # into the checksummed envelope so every tier consumes one
48
+ # declaration. Data pass-through in phase 1.
49
+ @bindings = bindings
46
50
  @atom_cache = {}
47
51
  @first_cache = {}.compare_by_identity
48
52
  @ref_stack = []
@@ -396,6 +400,7 @@ module Parsanol
396
400
  [name, entry_envelope(rule)]
397
401
  end
398
402
  envelope = {
403
+ "bindings" => @bindings,
399
404
  "version" => @document.version,
400
405
  "grammar" => @document.grammar_name,
401
406
  "shape" => "parsanol-tree/v2",
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Parsanol
4
- VERSION = "1.3.62"
4
+ VERSION = "1.3.63"
5
5
  end
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.62
4
+ version: 1.3.63
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.