parsanol 1.3.128-arm-linux → 1.3.130-arm-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 +4 -4
- data/lib/parsanol/3.2/parsanol_native.so +2 -2
- data/lib/parsanol/3.3/parsanol_native.so +2 -2
- data/lib/parsanol/3.4/parsanol_native.so +2 -2
- data/lib/parsanol/4.0/parsanol_native.so +2 -2
- data/lib/parsanol/native/libparsanol.so +2 -2
- data/lib/parsanol/parg/artifact.rb +12 -0
- data/lib/parsanol/parg/bindings/artifact.rb +183 -0
- data/lib/parsanol/parg/bindings.rb +28 -5
- data/lib/parsanol/parg/imports.rb +17 -1
- data/lib/parsanol/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: '08291c7ebdfc64af963151769f7276a22723d98be2609c0299841b34bea18a67'
|
|
4
|
+
data.tar.gz: 3be47e65486f7e76ae124dc326713d7d7fb711295e423a85633e02917622cb1e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 03b12bbe3c4750b36e2575f8e39909e4337082596a7641e3b479ee75bc902ad0d4a3cda0677d8bfb91708abbfa1a3e719392b4b7763fb00d5af5ec15018621be
|
|
7
|
+
data.tar.gz: d1f717ea3d3c7836d9e270cb099742262f944422a094ae73bf215904921981c1da69b3ece4cc217eb43942b8ea0a54714aa194908cf1c80a33c11f55ceb94249
|
|
@@ -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:
|
|
4
|
-
sha256:
|
|
3
|
+
size: 39866820 bytes
|
|
4
|
+
sha256: d427de1a20cb3ce4b7f87f7b9785e1b972e24f0715e17fe642141743d84aa537
|
|
@@ -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:
|
|
4
|
-
sha256:
|
|
3
|
+
size: 40052048 bytes
|
|
4
|
+
sha256: ae5b75934aaa0b288ab140101dfa510f16d7590d15c27744ab5c40576b6c8c76
|
|
@@ -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:
|
|
4
|
-
sha256:
|
|
3
|
+
size: 40046192 bytes
|
|
4
|
+
sha256: ef69925f79b48d090ed69227d6dca2a4cf8d7dc6e2ca1cfe1ad4028b43bb7ada
|
|
@@ -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:
|
|
4
|
-
sha256:
|
|
3
|
+
size: 40055908 bytes
|
|
4
|
+
sha256: 4aa30d859f847ed62f581007ed01eaf3225df16066ffac565fff7014b8ee31aa
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
[diffend] Oversized file quarantined before diffing.
|
|
2
2
|
name: data/lib/parsanol/native/libparsanol.so
|
|
3
|
-
size:
|
|
4
|
-
sha256:
|
|
3
|
+
size: 36187320 bytes
|
|
4
|
+
sha256: 254ef54622a09917e602bb0e443b7125fa3a35a7a89d4c51300df7ff26019f3a
|
|
@@ -95,6 +95,18 @@ module Parsanol
|
|
|
95
95
|
source_hash == Digest::SHA256.hexdigest(source_text.to_s)
|
|
96
96
|
end
|
|
97
97
|
|
|
98
|
+
# The declared per-target binding artifact for this parse artifact
|
|
99
|
+
# (parsanol-ruby#432): the entry binding records extracted into
|
|
100
|
+
# their own checksummed artifact, pinned to this grammar by source
|
|
101
|
+
# hash. Targets: ruby, rs, ts, python.
|
|
102
|
+
def bindings_artifact(target)
|
|
103
|
+
Bindings::Artifact.emit(envelope, target)
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
def bindings_artifact_json(target)
|
|
107
|
+
Bindings::Artifact.emit_json(envelope, target)
|
|
108
|
+
end
|
|
109
|
+
|
|
98
110
|
def entries = envelope["entries"].keys
|
|
99
111
|
|
|
100
112
|
def entry(name)
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
|
|
5
|
+
module Parsanol
|
|
6
|
+
module PARG
|
|
7
|
+
module Bindings
|
|
8
|
+
# The declared per-target binding artifact (parsanol-ruby#432): from
|
|
9
|
+
# one compiled grammar the toolchain emits one checksummed bindings
|
|
10
|
+
# artifact per target, each carrying the entry binding records and
|
|
11
|
+
# pinned to its grammar by source hash. Declared and diffable, not
|
|
12
|
+
# baked: consumers pin and verify what they load.
|
|
13
|
+
#
|
|
14
|
+
# Boundary: the records carry AST construction only — the
|
|
15
|
+
# production-to-binding mapping. Semantics live in the model layer
|
|
16
|
+
# (LML), never here. Execution resources (preprocess steps and their
|
|
17
|
+
# tables) resolve from the PAIRED parse artifact, which is why
|
|
18
|
+
# #pair_with! is mandatory before #apply.
|
|
19
|
+
class Artifact
|
|
20
|
+
KIND = "parg-bindings"
|
|
21
|
+
TARGETS = %w[ruby rs ts python].freeze
|
|
22
|
+
SUPPORTED_BINDING_VERSION = 1
|
|
23
|
+
|
|
24
|
+
attr_reader :target, :binding_version, :grammar, :grammar_version,
|
|
25
|
+
:grammar_source_hash, :entries, :payload
|
|
26
|
+
|
|
27
|
+
class << self
|
|
28
|
+
# Emit the per-target bindings artifact from a compiled parse
|
|
29
|
+
# artifact envelope. Returns the verified artifact; the payload
|
|
30
|
+
# is checksummed with the artifact checksum scheme (canonical
|
|
31
|
+
# JSON sha256 over everything except the checksum itself), so
|
|
32
|
+
# every engine re-derives it identically.
|
|
33
|
+
def emit(envelope, target)
|
|
34
|
+
target = target.to_s
|
|
35
|
+
unless TARGETS.include?(target)
|
|
36
|
+
raise ArtifactError,
|
|
37
|
+
"unknown binding target #{target.inspect}; known: #{TARGETS.join(', ')}"
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
artifact = new(build(envelope, target))
|
|
41
|
+
artifact.verify
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# The emitted artifact as JSON (the bake/CLI surface).
|
|
45
|
+
def emit_json(envelope, target)
|
|
46
|
+
JSON.generate(emit(envelope, target).payload)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Parse and fully verify an emitted bindings artifact. `target:`
|
|
50
|
+
# pins the expected target; omit it in multi-target tooling that
|
|
51
|
+
# accepts any declared target.
|
|
52
|
+
def from_json(json, target: nil)
|
|
53
|
+
artifact = new(JSON.parse(json))
|
|
54
|
+
artifact.verify
|
|
55
|
+
artifact.verify_target!(target) unless target.nil?
|
|
56
|
+
artifact
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
private
|
|
60
|
+
|
|
61
|
+
def build(envelope, target)
|
|
62
|
+
payload = {
|
|
63
|
+
"artifact_kind" => KIND,
|
|
64
|
+
"target" => target,
|
|
65
|
+
"binding_version" => SUPPORTED_BINDING_VERSION,
|
|
66
|
+
"grammar" => envelope["grammar"],
|
|
67
|
+
"grammar_version" => envelope["version"],
|
|
68
|
+
"grammar_source_hash" => envelope["source_hash"],
|
|
69
|
+
"shape" => envelope["shape"],
|
|
70
|
+
"entries" => envelope["entries"].to_h do |name, entry|
|
|
71
|
+
[name, { "bindings" => entry["bindings"].to_a }]
|
|
72
|
+
end,
|
|
73
|
+
}
|
|
74
|
+
payload.merge("checksum" => Compiler.checksum(payload))
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def initialize(payload)
|
|
79
|
+
raise ArtifactError, "bindings artifact payload must be an object" unless payload.is_a?(Hash)
|
|
80
|
+
|
|
81
|
+
@payload = payload
|
|
82
|
+
@target = payload["target"]
|
|
83
|
+
@binding_version = payload["binding_version"]
|
|
84
|
+
@grammar = payload["grammar"]
|
|
85
|
+
@grammar_version = payload["grammar_version"]
|
|
86
|
+
@grammar_source_hash = payload["grammar_source_hash"]
|
|
87
|
+
@entries = payload["entries"]
|
|
88
|
+
@parg_artifact = nil
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Structural verification: kind, checksum, binding version,
|
|
92
|
+
# target, entries map. Every loader path goes through here.
|
|
93
|
+
def verify
|
|
94
|
+
unless @payload["artifact_kind"] == KIND
|
|
95
|
+
raise ArtifactError,
|
|
96
|
+
"not a #{KIND} artifact (artifact_kind #{@payload['artifact_kind'].inspect})"
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
expected = Compiler.checksum(@payload)
|
|
100
|
+
actual = @payload["checksum"]
|
|
101
|
+
unless actual.is_a?(String) && actual == expected
|
|
102
|
+
raise ArtifactError,
|
|
103
|
+
"bindings artifact checksum mismatch: expected #{expected}, got #{actual.inspect}"
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
unless TARGETS.include?(@target)
|
|
107
|
+
raise ArtifactError,
|
|
108
|
+
"unknown binding target #{@target.inspect}; known: #{TARGETS.join(', ')}"
|
|
109
|
+
end
|
|
110
|
+
unless @binding_version == SUPPORTED_BINDING_VERSION
|
|
111
|
+
raise ArtifactError,
|
|
112
|
+
"unsupported binding_version #{@binding_version.inspect} " \
|
|
113
|
+
"(supported: #{SUPPORTED_BINDING_VERSION})"
|
|
114
|
+
end
|
|
115
|
+
unless @entries.is_a?(Hash)
|
|
116
|
+
raise ArtifactError, "bindings artifact carries no entries map"
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
self
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
def verify_target!(target)
|
|
123
|
+
target = target.to_s
|
|
124
|
+
return if @target == target
|
|
125
|
+
|
|
126
|
+
raise ArtifactError,
|
|
127
|
+
"bindings artifact targets #{@target.inspect}, not #{target.inspect}"
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
# Pair with the parse artifact this layer was compiled from: same
|
|
131
|
+
# grammar, same version, same source. The pairing is what lets
|
|
132
|
+
# apply resolve preprocess references — they live in the parse
|
|
133
|
+
# artifact's checksummed envelope.
|
|
134
|
+
def pair_with!(parg_artifact)
|
|
135
|
+
envelope = parg_artifact.envelope
|
|
136
|
+
mismatches = []
|
|
137
|
+
mismatches << "grammar (#{@grammar.inspect} vs #{envelope['grammar'].inspect})" if @grammar != envelope["grammar"]
|
|
138
|
+
if @grammar_version != envelope["version"]
|
|
139
|
+
mismatches << "version (#{@grammar_version.inspect} vs #{envelope['version'].inspect})"
|
|
140
|
+
end
|
|
141
|
+
if @grammar_source_hash != envelope["source_hash"]
|
|
142
|
+
mismatches << "source_hash (#{@grammar_source_hash.inspect} vs #{envelope['source_hash'].inspect})"
|
|
143
|
+
end
|
|
144
|
+
unless mismatches.empty?
|
|
145
|
+
raise ArtifactError,
|
|
146
|
+
"bindings artifact does not pair with the parse artifact: #{mismatches.join(', ')}"
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
@parg_artifact = parg_artifact
|
|
150
|
+
self
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def entry(name)
|
|
154
|
+
@entries.fetch(name) { raise ArtifactError, "unknown entry #{name.inspect}" }
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def bindings(name)
|
|
158
|
+
entry(name)["bindings"]
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def entry_names
|
|
162
|
+
@entries.keys
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# Materialize the bound map from a parse shape using the DECLARED
|
|
166
|
+
# records. The paired parse artifact supplies entry context and
|
|
167
|
+
# preprocess resolution; the same Bindings.apply runs as for the
|
|
168
|
+
# embedded records, so a standalone artifact and its parse
|
|
169
|
+
# artifact's baked records produce identical bound maps.
|
|
170
|
+
def apply(entry_name, shape)
|
|
171
|
+
parg = @parg_artifact
|
|
172
|
+
if parg.nil?
|
|
173
|
+
raise ArtifactError,
|
|
174
|
+
"pair_with! the parse artifact before applying bindings"
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
crafted = { "name" => entry_name, "bindings" => bindings(entry_name) }
|
|
178
|
+
Bindings.apply(parg, crafted, shape)
|
|
179
|
+
end
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
end
|
|
@@ -8,6 +8,9 @@ module Parsanol
|
|
|
8
8
|
# producing the attribute hash that fills a lutaml-model class:
|
|
9
9
|
# capture collection -> preprocessing -> type cast -> path assignment.
|
|
10
10
|
module Bindings
|
|
11
|
+
# The declared per-target binding artifact (parsanol-ruby#432).
|
|
12
|
+
autoload :Artifact, "parsanol/parg/bindings/artifact"
|
|
13
|
+
|
|
11
14
|
module_function
|
|
12
15
|
|
|
13
16
|
def apply(artifact, entry, shape)
|
|
@@ -36,11 +39,14 @@ module Parsanol
|
|
|
36
39
|
# bound map (parsanol-ruby#413): a capture present in the parse
|
|
37
40
|
# but bound nowhere is silent data loss, the one case the
|
|
38
41
|
# binding layer's other checks miss. Absence in the TREE is
|
|
39
|
-
# legitimate optionality and never raises.
|
|
40
|
-
#
|
|
41
|
-
#
|
|
42
|
+
# legitimate optionality and never raises. Delivery is EITHER
|
|
43
|
+
# the binding's own leaf/prefix reaching the map (the capture
|
|
44
|
+
# may rename on the way — capture "doc_year" binds under path
|
|
45
|
+
# "year", parsanol-ruby#434) OR the capture name appearing as a
|
|
46
|
+
# key anywhere in the map: a `(raw)` binding carries its entire
|
|
42
47
|
# subtree, so captures nested inside a raw-bound ancestor are
|
|
43
|
-
# delivered through it (parsanol-ruby#427 — BS 9113
|
|
48
|
+
# delivered through it (parsanol-ruby#427 — BS 9113
|
|
49
|
+
# bundled_list).
|
|
44
50
|
bound_keys = {}
|
|
45
51
|
walk_keys = lambda do |node|
|
|
46
52
|
case node
|
|
@@ -53,7 +59,7 @@ module Parsanol
|
|
|
53
59
|
walk_keys.call(out)
|
|
54
60
|
lost = bindings.select do |binding|
|
|
55
61
|
capture = binding["capture"].to_sym
|
|
56
|
-
present.include?(capture) && !bound_keys.key?(capture)
|
|
62
|
+
present.include?(capture) && !bound?(out, binding) && !bound_keys.key?(capture)
|
|
57
63
|
end
|
|
58
64
|
unless lost.empty?
|
|
59
65
|
raise BindError,
|
|
@@ -63,6 +69,23 @@ module Parsanol
|
|
|
63
69
|
out
|
|
64
70
|
end
|
|
65
71
|
|
|
72
|
+
# Did this binding contribute anything to the bound map? Scalars
|
|
73
|
+
# bind under their leaf key; array groups bind under their prefix.
|
|
74
|
+
# The leaf is the PATH's tail, so a capture-to-path rename reads
|
|
75
|
+
# as delivered when its own path landed (parsanol-ruby#434).
|
|
76
|
+
def bound?(out, binding)
|
|
77
|
+
path = binding["path"].to_s
|
|
78
|
+
if path.include?("[]")
|
|
79
|
+
prefix = path.split("[]").first.to_sym
|
|
80
|
+
rows = out[prefix]
|
|
81
|
+
rows.is_a?(Array) && rows.any? do |row|
|
|
82
|
+
row.is_a?(Hash) && row.key?(leaf_key(binding))
|
|
83
|
+
end
|
|
84
|
+
else
|
|
85
|
+
out.key?(leaf_key(binding))
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
66
89
|
# Canonical test-value form: one equality surface for capture and
|
|
67
90
|
# example expectations on both sides of the comparison (Slice vs
|
|
68
91
|
# source literal was comparing heterogeneous types). Terminals
|
|
@@ -46,6 +46,12 @@ module Parsanol
|
|
|
46
46
|
|
|
47
47
|
document.rules[qualified] = copy(node, prefix)
|
|
48
48
|
end
|
|
49
|
+
# The `atomic` exemption rides the rule name: a component's
|
|
50
|
+
# atomic rules qualify with everything else, or the exemption
|
|
51
|
+
# never matches post-merge.
|
|
52
|
+
used.atomic_rules.each do |name|
|
|
53
|
+
document.atomic_rules << "#{prefix}#{name}"
|
|
54
|
+
end
|
|
49
55
|
used.entries.each do |entry, rule|
|
|
50
56
|
document.entries["#{prefix}#{entry}"] = "#{prefix}#{rule}"
|
|
51
57
|
end
|
|
@@ -79,7 +85,17 @@ module Parsanol
|
|
|
79
85
|
when :pred
|
|
80
86
|
Node.new(:pred, node.a, copy(node.b, prefix), node.c)
|
|
81
87
|
when :cap then Node.new(:cap, node.a, copy(node.b, prefix))
|
|
82
|
-
|
|
88
|
+
# A qualified reference (`other.rule`) already names its own
|
|
89
|
+
# imported grammar — prefixing would double-qualify it
|
|
90
|
+
# (cross-import references compose: the other grammar's rules
|
|
91
|
+
# are prefixed by their own merge).
|
|
92
|
+
when :ref
|
|
93
|
+
name = node.a.to_s
|
|
94
|
+
if name.include?(".")
|
|
95
|
+
Node.new(:ref, name)
|
|
96
|
+
else
|
|
97
|
+
Node.new(:ref, "#{prefix}#{name}")
|
|
98
|
+
end
|
|
83
99
|
else node
|
|
84
100
|
end
|
|
85
101
|
end
|
data/lib/parsanol/version.rb
CHANGED
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.
|
|
4
|
+
version: 1.3.130
|
|
5
5
|
platform: arm-linux
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
@@ -101,6 +101,7 @@ files:
|
|
|
101
101
|
- lib/parsanol/parg/artifact.rb
|
|
102
102
|
- lib/parsanol/parg/authoring.rb
|
|
103
103
|
- lib/parsanol/parg/bindings.rb
|
|
104
|
+
- lib/parsanol/parg/bindings/artifact.rb
|
|
104
105
|
- lib/parsanol/parg/cli.rb
|
|
105
106
|
- lib/parsanol/parg/compiler.rb
|
|
106
107
|
- lib/parsanol/parg/derive.rb
|