parsanol 1.3.131-aarch64-linux → 1.3.133-aarch64-linux

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: cab7e7f96b08e9558a216f4658540a8ad88572a1ca3a0adb2c77602ee2ed3b61
4
- data.tar.gz: ffb527fbf0a3bbd5a99da93148b52f1264a5bf9c9055e1c56e712223aaca9efc
3
+ metadata.gz: 38474555e976a3aa4a84b09f2dc64e2adcbeccc5eeb75c9f3e8340e9472b2812
4
+ data.tar.gz: 057f7f9b2e5671584186480cde69550e6a0614bde21727ee55541dc38ab5a2be
5
5
  SHA512:
6
- metadata.gz: c7e577f8fe5d6c850d6d03950462b41d8f38ef82f0f9b8b64bc066abf321b436a21a5805402276b02238049f0de97d932b109da152855e0f19e826ea6ed6fa38
7
- data.tar.gz: 440e7adc83c768447f378b3b1cebccd73fd1e25e1bd1905eef09ea938ee8d6c2d2c980296b783507453da935ef373c9ac1c41eb7bce519f10cbba903e88442a3
6
+ metadata.gz: ded7ceea7811c46b653da8e7965ed32504d8db2fc2b6b5aba0793f0f5f37306f7a5e2dfc29f1b6365e6255019782c05325ae6102042699720945d072b8b008a4
7
+ data.tar.gz: f4cae04649e108d2e7b5b5f2f506a7ae4c45d02a24565ba86d3d131fbb60b0808c55e21dc220e738e617b27310f4c72392baf53ba4e2b67c51ce0be63ff41137
@@ -1,4 +1,4 @@
1
1
  [diffend] Oversized file quarantined before diffing.
2
2
  name: data/lib/parsanol/3.2/parsanol_native.so
3
- size: 47415752 bytes
4
- sha256: b5df655f1f7e38d27146c84678d78ebf1ac7fe0979ee0318932b95e7ccaf61f4
3
+ size: 47412264 bytes
4
+ sha256: ad5843845e6d583178abc630acb3bf6ea77f7944beb00d3f4312dc19a0e12f7e
@@ -1,4 +1,4 @@
1
1
  [diffend] Oversized file quarantined before diffing.
2
2
  name: data/lib/parsanol/3.3/parsanol_native.so
3
- size: 47650784 bytes
4
- sha256: 729b12a5631399a9c51ca0c6e5379a8f7845988b1a39c5f7eff37f48c37bed4c
3
+ size: 47647304 bytes
4
+ sha256: ae55584ad3bb49b78d5f2a2f496cf47bcf6bb89070484f98ff936d45de6a1ad7
@@ -1,4 +1,4 @@
1
1
  [diffend] Oversized file quarantined before diffing.
2
2
  name: data/lib/parsanol/3.4/parsanol_native.so
3
- size: 47646368 bytes
4
- sha256: f2b4449cac1d28ef08ab661c81c6c63ef43efc34dc47983361df95a32443b9b0
3
+ size: 47647080 bytes
4
+ sha256: a0a07b8bb12f97e21c7e4056df1c4971ed51578080306b4a4c7961610374ba1b
@@ -1,4 +1,4 @@
1
1
  [diffend] Oversized file quarantined before diffing.
2
2
  name: data/lib/parsanol/4.0/parsanol_native.so
3
- size: 47656376 bytes
4
- sha256: c058a8a40c01d04c483705050364261dffec34a911fdcd284f2bafc49dd2ce52
3
+ size: 47657088 bytes
4
+ sha256: bc004ef9e5f6794a52c01ec04536c34d32a9a129c6ee2076c545efec1b1bae7d
@@ -1,4 +1,4 @@
1
1
  [diffend] Oversized file quarantined before diffing.
2
2
  name: data/lib/parsanol/native/libparsanol.so
3
- size: 43124920 bytes
4
- sha256: c1ba12fc7ff6c821f87cb4e4d0bb533abb6891ce5457e44b223f1535e4e98542
3
+ size: 43125664 bytes
4
+ sha256: 63ef8e072548f50461d5624438deb51e41bb60f0b0d1a57c5bb76695367a645d
@@ -22,7 +22,12 @@ module Parsanol
22
22
  compile to an artifact envelope;
23
23
  --bindings also writes one
24
24
  checksummed per-target binding
25
- artifact beside it (#432)
25
+ artifact beside it (#432);
26
+ --model-bindings FILE embeds a
27
+ rule -> model sidecar (JSON/YAML)
28
+ in the artifact
29
+ bindings <artifact.json> dump the embedded rule -> model
30
+ binding table as JSON (coradoc#307)
26
31
  test <file.parg|artifact.json> run the grammar's test section
27
32
  parse <file> [--entry E] INPUT parse one input; prints the tree
28
33
  and the bound captures
@@ -75,6 +80,7 @@ module Parsanol
75
80
  when "lint" then lint
76
81
  when "export" then export_grammar
77
82
  when "diff" then diff_artifacts
83
+ when "bindings" then dump_bindings
78
84
  when "lsp" then Lsp.new.run && 0
79
85
  else
80
86
  warn USAGE
@@ -145,6 +151,9 @@ module Parsanol
145
151
  source = @argv.shift
146
152
  out = flag_value("-o") || default_artifact_name(source)
147
153
  envelope = compile_source(source).envelope
154
+ if (sidecar = flag_value("--model-bindings"))
155
+ envelope = ModelBindings.embed(envelope, ModelBindings.load(sidecar))
156
+ end
148
157
  # Seal: the exact text written is the exact text the byte-level
149
158
  # checksum covers (Compiler.seal_json includes the trailing
150
159
  # newline).
@@ -162,6 +171,18 @@ module Parsanol
162
171
  0
163
172
  end
164
173
 
174
+ # `parg bindings ARTIFACT`: the embedded rule -> model table as JSON.
175
+ def dump_bindings
176
+ path = @argv.shift
177
+ unless path
178
+ warn "usage: parsanol parg bindings ARTIFACT.json"
179
+ return 2
180
+ end
181
+ envelope = ModelBindings.read_envelope(path)
182
+ puts ModelBindings.dump(envelope)
183
+ 0
184
+ end
185
+
165
186
  # Every --bindings flag value, `all` expanded to the target set.
166
187
  # Empty when the flag is absent (compile emits no binding artifacts).
167
188
  def bindings_targets
@@ -61,7 +61,8 @@ module Parsanol
61
61
  # unicode_tables — is byte-stable when the grammar's behavior is
62
62
  # unchanged. Mirrors the cross-engine parity view.
63
63
  SEMANTICS_EXCLUDED = %w[checksum byte_checksum compiler_version
64
- unicode_tables semantics_hash validated].freeze
64
+ unicode_tables semantics_hash validated
65
+ model_bindings].freeze
65
66
 
66
67
  def self.semantics_hash(envelope)
67
68
  payload = envelope.except(*SEMANTICS_EXCLUDED)
@@ -0,0 +1,126 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "json"
4
+ require "yaml"
5
+
6
+ module Parsanol
7
+ module PARG
8
+ # The rule -> model binding table embedded in an artifact (coradoc#307).
9
+ #
10
+ # A sidecar (JSON or YAML) declares, per rule, which model a raw-tree
11
+ # node inflates to:
12
+ #
13
+ # version: 1
14
+ # rules:
15
+ # thematic_break:
16
+ # keys: [hr] # exact capture-key set of the node
17
+ # model: HorizontalRule
18
+ # captures: {} # attribute => scalar capture key
19
+ # children: {} # attribute => nested-node capture key
20
+ # defaults: { style: "---" } # attributes fixed by the rule
21
+ #
22
+ # `parg compile --model-bindings FILE` embeds it under the envelope's
23
+ # additive "model_bindings" key; artifacts compiled without a sidecar
24
+ # carry no such key and are byte-identical to before. The table is not
25
+ # parse semantics, so semantics_hash ignores it; the checksum covers it.
26
+ module ModelBindings
27
+ KEY = "model_bindings"
28
+ VERSION = 1
29
+ RULE_FIELDS = %w[keys model captures children defaults].freeze
30
+
31
+ module_function
32
+
33
+ # @param path [String] a .json / .yml / .yaml sidecar
34
+ # @return [Hash] the validated, string-keyed table
35
+ def load(path)
36
+ text = File.read(path, encoding: Encoding::UTF_8)
37
+ raw = File.extname(path).match?(/\.ya?ml\z/i) ? YAML.safe_load(text) : JSON.parse(text)
38
+ normalize(raw)
39
+ rescue JSON::ParserError, Psych::SyntaxError => e
40
+ raise ArtifactError, "model bindings #{path}: #{e.message}"
41
+ end
42
+
43
+ # @return [Hash] the table with every rule filled to the full shape
44
+ def normalize(raw)
45
+ raise ArtifactError, "model bindings: expected a mapping" unless raw.is_a?(Hash)
46
+
47
+ table = stringify(raw)
48
+ unless table["version"] == VERSION
49
+ raise ArtifactError, "model bindings: unsupported version #{table['version'].inspect} (want #{VERSION})"
50
+ end
51
+
52
+ rules = table["rules"]
53
+ raise ArtifactError, "model bindings: `rules` must be a mapping" unless rules.is_a?(Hash)
54
+
55
+ { "version" => VERSION, "rules" => rules.to_h { |name, rule| [name, normalize_rule(name, rule)] } }
56
+ end
57
+
58
+ def normalize_rule(name, rule)
59
+ raise ArtifactError, "model bindings: rule #{name.inspect} must be a mapping" unless rule.is_a?(Hash)
60
+
61
+ unknown = rule.keys - RULE_FIELDS
62
+ raise ArtifactError, "model bindings: rule #{name.inspect} has unknown field #{unknown.first.inspect}" unless unknown.empty?
63
+ unless rule["model"].is_a?(String) && !rule["model"].empty?
64
+ raise ArtifactError, "model bindings: rule #{name.inspect} needs a `model`"
65
+ end
66
+ unless rule["keys"].is_a?(Array) && !rule["keys"].empty?
67
+ raise ArtifactError, "model bindings: rule #{name.inspect} needs non-empty `keys`"
68
+ end
69
+
70
+ {
71
+ "keys" => rule["keys"].map(&:to_s),
72
+ "model" => rule["model"],
73
+ "captures" => hash_field(name, rule, "captures"),
74
+ "children" => hash_field(name, rule, "children"),
75
+ "defaults" => hash_field(name, rule, "defaults"),
76
+ }
77
+ end
78
+
79
+ def hash_field(name, rule, field)
80
+ value = rule.fetch(field, {})
81
+ raise ArtifactError, "model bindings: rule #{name.inspect} `#{field}` must be a mapping" unless value.is_a?(Hash)
82
+
83
+ value
84
+ end
85
+
86
+ def stringify(value)
87
+ case value
88
+ when Hash then value.to_h { |key, item| [key.to_s, stringify(item)] }
89
+ when Array then value.map { |item| stringify(item) }
90
+ else value
91
+ end
92
+ end
93
+
94
+ # Embed a table in an envelope and re-seal the canonical checksum.
95
+ def embed(envelope, table)
96
+ sealed = envelope.merge(KEY => table)
97
+ sealed["checksum"] = Compiler.checksum(sealed)
98
+ sealed
99
+ end
100
+
101
+ # Read an artifact file for the dump: JSON plus checksum verification
102
+ # only, so no grammar source and no custom-atom class is needed.
103
+ def read_envelope(path)
104
+ envelope = JSON.parse(File.read(path, encoding: Encoding::UTF_8))
105
+ unless envelope.is_a?(Hash) && envelope["checksum"] == Compiler.checksum(envelope)
106
+ raise ArtifactError, "#{path}: artifact checksum mismatch"
107
+ end
108
+
109
+ envelope
110
+ rescue JSON::ParserError => e
111
+ raise ArtifactError, "#{path}: #{e.message}"
112
+ end
113
+
114
+ # @return [Hash, nil] the embedded table, nil for an artifact without one
115
+ def from(envelope)
116
+ envelope[KEY]
117
+ end
118
+
119
+ # The machine-readable dump: rule -> model/keys/captures/children/defaults.
120
+ def dump(envelope)
121
+ table = from(envelope) || { "version" => VERSION, "rules" => {} }
122
+ JSON.pretty_generate(table)
123
+ end
124
+ end
125
+ end
126
+ end
data/lib/parsanol/parg.rb CHANGED
@@ -26,6 +26,7 @@ module Parsanol
26
26
  autoload :Compiler, "parsanol/parg/compiler"
27
27
  autoload :Artifact, "parsanol/parg/artifact"
28
28
  autoload :Bindings, "parsanol/parg/bindings"
29
+ autoload :ModelBindings, "parsanol/parg/model_bindings"
29
30
  autoload :Render, "parsanol/parg/render"
30
31
  autoload :Derive, "parsanol/parg/derive"
31
32
  autoload :SelfHost, "parsanol/parg/selfhost"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Parsanol
4
- VERSION = "1.3.131"
4
+ VERSION = "1.3.133"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: parsanol
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.131
4
+ version: 1.3.133
5
5
  platform: aarch64-linux
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-11-03 00:00:00.000000000 Z
11
+ date: 2026-11-04 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A small Ruby library for constructing parsers in the PEG (Parsing Expression
14
14
  Grammar) fashion. Parsanol provides Parslet-compatible API with additional features
@@ -120,6 +120,7 @@ files:
120
120
  - lib/parsanol/parg/lints.rb
121
121
  - lib/parsanol/parg/lsp.rb
122
122
  - lib/parsanol/parg/lutaml.rb
123
+ - lib/parsanol/parg/model_bindings.rb
123
124
  - lib/parsanol/parg/node.rb
124
125
  - lib/parsanol/parg/parser.rb
125
126
  - lib/parsanol/parg/preprocess.rb