parsanol 1.3.90-aarch64-linux → 1.3.92-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 +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 +30 -8
- data/lib/parsanol/parg/cli.rb +36 -2
- data/lib/parsanol/parg/compiler.rb +6 -0
- data/lib/parsanol/parser.rb +7 -0
- data/lib/parsanol/skip.rb +36 -1
- data/lib/parsanol/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d97e0ef9b1ba9281cfce8b847384654d3420fdc8c0ad4fbd0284af5a35522653
|
|
4
|
+
data.tar.gz: 9836bdd4bf811c8bc7ef99820e0b0c96a088bfbf33cbf52749ffdf3adb4aa2f3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f0d8078fe690e009410e0c54268468370fe7897007cdbb261de6bca40f64301b1fb45a098f41beffe7beb3bfba1be2fbe0533864484e063d89081ebee4d0f791
|
|
7
|
+
data.tar.gz: 37346c31aeb72a9e5ca78fbee2135a43d10414134644633b8b224414a6eca32e162292d81bd8b9009dd91e9806617a72365d68681e670699c5f46b9f7b329086
|
|
@@ -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: 40176952 bytes
|
|
4
|
+
sha256: 58f5e7bcb9c7665ab38daba62f63533a89966dbe2b9e2d8c56d2c37bd7afeb37
|
|
@@ -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: 40412064 bytes
|
|
4
|
+
sha256: c2b4e8331d61feecb2146feb05047ff9b20da8543910429eb87c3111b6a871ed
|
|
@@ -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: 40403520 bytes
|
|
4
|
+
sha256: 35be9d4c9905ab8a9d0fcce4c55d7909850b093d1065cf658f131a2081f9ca31
|
|
@@ -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: 40413544 bytes
|
|
4
|
+
sha256: 62c8e268e3990442aa746edfd13a0d24bc2fe40cbd58db8a845c7dfb67efdab0
|
|
@@ -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: 35960704 bytes
|
|
4
|
+
sha256: 579c6ce133fca3eec741131db52977ea97348767e59d3cb1c8e0149dc6f1bb91
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require "digest"
|
|
3
4
|
require "json"
|
|
4
5
|
require "yaml"
|
|
5
6
|
|
|
@@ -11,20 +12,21 @@ module Parsanol
|
|
|
11
12
|
# consume; the embedded PARG source lets a Ruby runtime recompile the atom
|
|
12
13
|
# tree locally without any other dependency.
|
|
13
14
|
class Artifact
|
|
14
|
-
attr_reader :envelope, :path, :tables_dir
|
|
15
|
+
attr_reader :envelope, :path, :tables_dir, :imports_dir
|
|
15
16
|
|
|
16
|
-
def self.load(path, tables_dir: nil)
|
|
17
|
+
def self.load(path, tables_dir: nil, imports_dir: nil)
|
|
17
18
|
envelope = JSON.parse(PARG.read_utf8(path))
|
|
18
|
-
new(envelope, path, tables_dir || File.dirname(path)
|
|
19
|
+
new(envelope, path, tables_dir || File.dirname(path),
|
|
20
|
+
imports_dir: imports_dir)
|
|
19
21
|
end
|
|
20
22
|
|
|
21
|
-
def self.from_json(text, tables_dir: nil)
|
|
22
|
-
new(JSON.parse(text), nil, tables_dir)
|
|
23
|
+
def self.from_json(text, tables_dir: nil, imports_dir: nil)
|
|
24
|
+
new(JSON.parse(text), nil, tables_dir, imports_dir: imports_dir)
|
|
23
25
|
end
|
|
24
26
|
|
|
25
27
|
SUPPORTED_SHAPE = "parsanol-tree/v2"
|
|
26
28
|
|
|
27
|
-
def initialize(envelope, path, tables_dir)
|
|
29
|
+
def initialize(envelope, path, tables_dir, imports_dir: nil)
|
|
28
30
|
unless envelope["shape"] == SUPPORTED_SHAPE
|
|
29
31
|
raise ArtifactError,
|
|
30
32
|
"unsupported artifact shape #{envelope['shape'].inspect} " \
|
|
@@ -38,12 +40,30 @@ module Parsanol
|
|
|
38
40
|
@envelope = envelope
|
|
39
41
|
@path = path
|
|
40
42
|
@tables_dir = tables_dir
|
|
43
|
+
# parsanol-ruby#208: `use`-importing grammars need the imported
|
|
44
|
+
# sources when the pure-Ruby path recompiles the embedded source;
|
|
45
|
+
# in-memory artifacts (path nil) pass the directory explicitly.
|
|
46
|
+
@imports_dir = imports_dir
|
|
41
47
|
verify_checksum!
|
|
42
48
|
@compiler = nil
|
|
43
49
|
end
|
|
44
50
|
|
|
45
51
|
def version = envelope["version"]
|
|
46
52
|
|
|
53
|
+
# Freshness (parsanol-ruby#209): what source revision and compiler
|
|
54
|
+
# produced this artifact. `source_hash` is the SHA-256 of the .parg
|
|
55
|
+
# text at compile time; nil on artifacts baked before the field
|
|
56
|
+
# existed, so `fresh_against?` answers false rather than guessing.
|
|
57
|
+
def source_hash = envelope["source_hash"]
|
|
58
|
+
|
|
59
|
+
def compiler_version = envelope["compiler_version"]
|
|
60
|
+
|
|
61
|
+
def fresh_against?(source_text)
|
|
62
|
+
return false if source_hash.nil?
|
|
63
|
+
|
|
64
|
+
source_hash == Digest::SHA256.hexdigest(source_text.to_s)
|
|
65
|
+
end
|
|
66
|
+
|
|
47
67
|
def entries = envelope["entries"].keys
|
|
48
68
|
|
|
49
69
|
def entry(name)
|
|
@@ -263,8 +283,10 @@ module Parsanol
|
|
|
263
283
|
# without this the pure-Ruby path fails on artifacts whose
|
|
264
284
|
# native atom graphs inline everything. The imported sources
|
|
265
285
|
# sit beside the artifact (vendors ship them together).
|
|
266
|
-
|
|
267
|
-
|
|
286
|
+
dirs = [path ? File.dirname(path) : nil, @imports_dir]
|
|
287
|
+
.compact
|
|
288
|
+
.select { |dir| File.directory?(dir) }
|
|
289
|
+
Imports.merge!(document, dirs) unless dirs.empty?
|
|
268
290
|
Compiler.new(document, @tables_dir)
|
|
269
291
|
end
|
|
270
292
|
end
|
data/lib/parsanol/parg/cli.rb
CHANGED
|
@@ -22,6 +22,10 @@ module Parsanol
|
|
|
22
22
|
test <file.parg|artifact.json> run the grammar's test section
|
|
23
23
|
parse <file> [--entry E] INPUT parse one input; prints the tree
|
|
24
24
|
and the bound captures
|
|
25
|
+
check --source x.parg --artifact y.json
|
|
26
|
+
verify the artifact was compiled
|
|
27
|
+
from that source (source hash +
|
|
28
|
+
compiler version); exit 1 stale
|
|
25
29
|
repl <file> [--entry E] interactive parse loop (blank
|
|
26
30
|
line quits, :quit exits)
|
|
27
31
|
doc <file> [rule] print rule documentation
|
|
@@ -53,6 +57,7 @@ module Parsanol
|
|
|
53
57
|
when "test" then test
|
|
54
58
|
when "schema" then schema
|
|
55
59
|
when "parse" then parse
|
|
60
|
+
when "check" then check
|
|
56
61
|
when "repl" then repl
|
|
57
62
|
when "doc" then doc
|
|
58
63
|
when "lsp" then Lsp.new.run && 0
|
|
@@ -88,6 +93,33 @@ module Parsanol
|
|
|
88
93
|
0
|
|
89
94
|
end
|
|
90
95
|
|
|
96
|
+
# Freshness (parsanol-ruby#209): verify an artifact was compiled
|
|
97
|
+
# from the given source. The stale-shipped-artifact incident class
|
|
98
|
+
# (an old artifact silently taking precedence over the corrected
|
|
99
|
+
# grammar) is undetectable without the recorded source hash.
|
|
100
|
+
# Exit 0 fresh, 1 stale or unrecorded.
|
|
101
|
+
def check
|
|
102
|
+
source = flag_value("--source")
|
|
103
|
+
artifact_path = flag_value("--artifact")
|
|
104
|
+
unless source && artifact_path && File.file?(source) && File.file?(artifact_path)
|
|
105
|
+
warn USAGE
|
|
106
|
+
return 1
|
|
107
|
+
end
|
|
108
|
+
artifact = Artifact.load(artifact_path)
|
|
109
|
+
if artifact.source_hash.nil?
|
|
110
|
+
puts "STALE? #{artifact_path}: no source hash recorded (pre-freshness artifact)"
|
|
111
|
+
return 1
|
|
112
|
+
end
|
|
113
|
+
if artifact.fresh_against?(PARG.read_utf8(source))
|
|
114
|
+
puts "FRESH #{artifact_path} == #{source} (compiler #{artifact.compiler_version})"
|
|
115
|
+
0
|
|
116
|
+
else
|
|
117
|
+
puts "STALE #{artifact_path} does not match #{source} " \
|
|
118
|
+
"(built from #{artifact.source_hash[0, 12]}… by #{artifact.compiler_version})"
|
|
119
|
+
1
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
91
123
|
def test
|
|
92
124
|
target = @argv.shift
|
|
93
125
|
if File.directory?(target)
|
|
@@ -200,11 +232,13 @@ module Parsanol
|
|
|
200
232
|
|
|
201
233
|
def artifact_for(file)
|
|
202
234
|
if file.end_with?(".json")
|
|
203
|
-
Parsanol::PARG::Artifact.load(file, tables_dir: @tables_dir || default_tables_dir(file)
|
|
235
|
+
Parsanol::PARG::Artifact.load(file, tables_dir: @tables_dir || default_tables_dir(file),
|
|
236
|
+
imports_dir: File.dirname(file))
|
|
204
237
|
else
|
|
205
238
|
artifact = compile_source(file)
|
|
206
239
|
Parsanol::PARG::Artifact.from_json(JSON.generate(artifact.envelope),
|
|
207
|
-
tables_dir: @tables_dir || default_tables_dir(file)
|
|
240
|
+
tables_dir: @tables_dir || default_tables_dir(file),
|
|
241
|
+
imports_dir: File.dirname(file))
|
|
208
242
|
end
|
|
209
243
|
end
|
|
210
244
|
|
|
@@ -758,6 +758,12 @@ module Parsanol
|
|
|
758
758
|
end,
|
|
759
759
|
"docs" => @document.docs,
|
|
760
760
|
"source" => @document.source,
|
|
761
|
+
# Freshness (parsanol-ruby#209): what the artifact was compiled
|
|
762
|
+
# from and with, so loaders can detect a stale artifact and fall
|
|
763
|
+
# back to a reference implementation instead of failing obscurely
|
|
764
|
+
# at parse time. Checksummed like the rest of the envelope.
|
|
765
|
+
"source_hash" => Digest::SHA256.hexdigest(@document.source.to_s),
|
|
766
|
+
"compiler_version" => Parsanol::VERSION,
|
|
761
767
|
}
|
|
762
768
|
if @document.skip_declaration
|
|
763
769
|
# parsanol-ruby#134: declared trivia rule. Injection is baked
|
data/lib/parsanol/parser.rb
CHANGED
|
@@ -77,6 +77,13 @@ module Parsanol
|
|
|
77
77
|
# `skip = trivia capture: comments` shape) instead of being
|
|
78
78
|
# discarded; whitespace-shaped units never record.
|
|
79
79
|
#
|
|
80
|
+
# +exempt:+ (parsanol-ruby#195) lists rule names whose bodies
|
|
81
|
+
# build WITHOUT injection — the DSL mirror of the PARG
|
|
82
|
+
# compiler's automatic skip-rule-closure exemption. Declare it
|
|
83
|
+
# for rules that manage their own trivia explicitly (expressir's
|
|
84
|
+
# remark rules): a wrapper inside them consumes text the rule
|
|
85
|
+
# itself captures, corrupting the value and double-recording it.
|
|
86
|
+
#
|
|
80
87
|
# @example
|
|
81
88
|
# class MyParser < Parsanol::Parser
|
|
82
89
|
# rule(:spaces) { match(/[ \t]/).repeat(1) }
|
data/lib/parsanol/skip.rb
CHANGED
|
@@ -41,11 +41,46 @@ module Parsanol
|
|
|
41
41
|
|
|
42
42
|
markers = capturer_markers(parser_instance, captures)
|
|
43
43
|
whitespace_kind = whitespace&.to_sym
|
|
44
|
-
exempt_names = exempt.nil? ?
|
|
44
|
+
exempt_names = Set.new(exempt.nil? ? [] : exempt.map(&:to_s))
|
|
45
|
+
exempt_names.merge(closure_names(skip_atom))
|
|
45
46
|
injector = Injector.new(skip_atom, markers, whitespace_kind, exempt_names)
|
|
46
47
|
[injector.inject(root_atom, entry: true), skip_atom]
|
|
47
48
|
end
|
|
48
49
|
|
|
50
|
+
# The skip rule's transitive rule-reference closure (parsanol-ruby#195
|
|
51
|
+
# follow-up): those rule bodies build without injection — the same
|
|
52
|
+
# exemption the PARG compiler applies to its skip declaration's
|
|
53
|
+
# closure. The docstring promised this; the code exempted only the
|
|
54
|
+
# skip atom itself. Rules the grammar manages explicitly stay
|
|
55
|
+
# declarable through +exempt:+ (their names merge with these).
|
|
56
|
+
def self.closure_names(skip_atom)
|
|
57
|
+
names = Set.new
|
|
58
|
+
seen = {}.compare_by_identity
|
|
59
|
+
queue = [skip_atom]
|
|
60
|
+
until queue.empty?
|
|
61
|
+
node = queue.shift
|
|
62
|
+
next if node.nil? || seen.key?(node)
|
|
63
|
+
|
|
64
|
+
seen[node] = true
|
|
65
|
+
case node
|
|
66
|
+
when Atoms::Entity
|
|
67
|
+
names << node.rule_name.to_s
|
|
68
|
+
begin
|
|
69
|
+
queue << node.parslet
|
|
70
|
+
rescue StandardError
|
|
71
|
+
nil
|
|
72
|
+
end
|
|
73
|
+
else
|
|
74
|
+
queue.concat(node.parslets) if node.respond_to?(:parslets)
|
|
75
|
+
queue.concat(node.alternatives) if node.respond_to?(:alternatives)
|
|
76
|
+
queue << node.parslet if node.respond_to?(:parslet)
|
|
77
|
+
queue << node.bound_parslet if node.respond_to?(:bound_parslet)
|
|
78
|
+
queue << node.wrapped_atom if node.respond_to?(:wrapped_atom)
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
names
|
|
82
|
+
end
|
|
83
|
+
|
|
49
84
|
# Derives each capturer's leading literal (the leftmost Str the
|
|
50
85
|
# rule can start with) and keys the marker table by it — the same
|
|
51
86
|
# derivation the PARG compiler applies to its skip declaration. A
|
data/lib/parsanol/version.rb
CHANGED
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.
|
|
4
|
+
version: 1.3.92
|
|
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-10-
|
|
11
|
+
date: 2026-10-15 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
|