parsanol 1.3.16-aarch64-linux → 1.3.18-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 +0 -0
- data/lib/parsanol/3.3/parsanol_native.so +0 -0
- data/lib/parsanol/3.4/parsanol_native.so +0 -0
- data/lib/parsanol/4.0/parsanol_native.so +0 -0
- data/lib/parsanol/atoms/base.rb +7 -5
- data/lib/parsanol/native/ffi.rb +127 -0
- data/lib/parsanol/native/parser.rb +8 -1
- data/lib/parsanol/native.rb +6 -0
- data/lib/parsanol/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ec79b496ea0dd5cf94aeb9601343133f685c31782ad573ede40947f4c9ded214
|
|
4
|
+
data.tar.gz: 747502b04cf7510313812bde6e4606a741582a2489f2ad745482cf1f47b36a4e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5bb8a32f322259c12432d610bb1f526db17caf038be37819b089db8e9f9aad991fa2bac63141fe35edacb34841f24a609a0837152dfc1e6427baf53e13a0413c
|
|
7
|
+
data.tar.gz: e1feaa6b11461e52844d7d3152ca00a28e9ee939da21575536560bed7049500a70bb664062bc61416c0d86531735f9aac994e8f4fc8d004b4e20876d12263fc7
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
data/lib/parsanol/atoms/base.rb
CHANGED
|
@@ -148,6 +148,13 @@ module Parsanol
|
|
|
148
148
|
to_s(TOP)
|
|
149
149
|
end
|
|
150
150
|
|
|
151
|
+
# Finalizes result by flattening. Public: the native error
|
|
152
|
+
# fallback (both extension and ffi tiers) calls it cross-object to
|
|
153
|
+
# finalize a recovered tree.
|
|
154
|
+
def finalize_result(value)
|
|
155
|
+
flatten(value)
|
|
156
|
+
end
|
|
157
|
+
|
|
151
158
|
protected
|
|
152
159
|
|
|
153
160
|
# Pre-allocated constant result tuples
|
|
@@ -180,11 +187,6 @@ module Parsanol
|
|
|
180
187
|
# Alias for ok (legacy compatibility)
|
|
181
188
|
alias succ ok
|
|
182
189
|
|
|
183
|
-
# Finalizes result by flattening.
|
|
184
|
-
def finalize_result(value)
|
|
185
|
-
flatten(value)
|
|
186
|
-
end
|
|
187
|
-
|
|
188
190
|
private
|
|
189
191
|
|
|
190
192
|
# Converts raw input to Source if needed.
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Parsanol
|
|
4
|
+
module Native
|
|
5
|
+
# Rust engine for runtimes that cannot load C-API extensions
|
|
6
|
+
# (JRuby, TruffleRuby, or an MRI whose platform gem is absent and
|
|
7
|
+
# cannot build one). Binds the parsanol cdylib's C ABI through the
|
|
8
|
+
# `ffi` gem: grammars register once into Rust-side handles keyed by
|
|
9
|
+
# serialized structure; results cross the boundary as flat-u64 batch
|
|
10
|
+
# arrays decoded by the same BatchDecoder used elsewhere.
|
|
11
|
+
module Ffi
|
|
12
|
+
class Error < StandardError
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
class << self
|
|
16
|
+
@available = nil
|
|
17
|
+
|
|
18
|
+
def available?
|
|
19
|
+
return @available unless @available.nil?
|
|
20
|
+
|
|
21
|
+
@available = begin
|
|
22
|
+
require "ffi"
|
|
23
|
+
lib = locate_library
|
|
24
|
+
lib && bind_library(lib)
|
|
25
|
+
rescue LoadError, StandardError
|
|
26
|
+
false
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Registers (once, cached) and parses. +grammar+ is a grammar
|
|
31
|
+
# atom or a pre-serialized JSON string. Mirrors Native.parse's
|
|
32
|
+
# contract, including the single reporter-pass fallback to the
|
|
33
|
+
# pure-Ruby engine for parslet-compatible failure errors.
|
|
34
|
+
def parse(grammar, input)
|
|
35
|
+
unless available? && @binding
|
|
36
|
+
raise Error, "parsanol FFI library not available"
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
if grammar.is_a?(String)
|
|
40
|
+
json = grammar
|
|
41
|
+
atom = nil
|
|
42
|
+
else
|
|
43
|
+
json = ::Parsanol::Native::Parser.serialize_grammar(grammar)
|
|
44
|
+
atom = grammar
|
|
45
|
+
end
|
|
46
|
+
handle = ((@handles ||= {})[json] ||= @binding.c_register(json))
|
|
47
|
+
raise Error, "grammar registration failed" if handle.zero?
|
|
48
|
+
|
|
49
|
+
written = parse_into(handle, input)
|
|
50
|
+
if written.positive?
|
|
51
|
+
return ::Parsanol::Native::BatchDecoder.decode_and_flatten(
|
|
52
|
+
@buffer.read_array_of_uint64(written), input, ::Parsanol::Slice
|
|
53
|
+
)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
message = @binding.c_last_error.to_s
|
|
57
|
+
if atom
|
|
58
|
+
return ::Parsanol::Native.raise_native_parse_error(
|
|
59
|
+
RuntimeError.new(message), atom, input
|
|
60
|
+
)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
raise Error, "parse failed: #{message}"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
private
|
|
67
|
+
|
|
68
|
+
# Search order: explicit override, gem-vendored cdylib next to
|
|
69
|
+
# this file, then the system linker path.
|
|
70
|
+
def locate_library
|
|
71
|
+
candidates = []
|
|
72
|
+
env = ENV.fetch("PARSANOL_FFI_LIB", nil)
|
|
73
|
+
candidates << env if env && !env.empty?
|
|
74
|
+
here = File.dirname(__FILE__)
|
|
75
|
+
%w[libparsanol.dylib libparsanol.so parsanol.dll].each do |name|
|
|
76
|
+
path = File.expand_path(name, here)
|
|
77
|
+
candidates << path if File.file?(path)
|
|
78
|
+
end
|
|
79
|
+
candidates << "parsanol"
|
|
80
|
+
candidates.each do |cand|
|
|
81
|
+
return cand if File.file?(cand)
|
|
82
|
+
|
|
83
|
+
begin
|
|
84
|
+
FFI::DynamicLibrary.open(cand, FFI::DynamicLibrary::RTLD_NOW)
|
|
85
|
+
return cand
|
|
86
|
+
rescue StandardError
|
|
87
|
+
next
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
nil
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def bind_library(path) # rubocop:disable Naming/PredicateMethod -- binds and reports success
|
|
94
|
+
binding_mod = Module.new do
|
|
95
|
+
extend FFI::Library
|
|
96
|
+
|
|
97
|
+
ffi_lib path
|
|
98
|
+
attach_function :c_register, :parsanol_c_register,
|
|
99
|
+
%i[string], :uint64
|
|
100
|
+
attach_function :c_parse, :parsanol_c_parse,
|
|
101
|
+
%i[uint64 string pointer size_t], :long_long
|
|
102
|
+
attach_function :c_last_error, :parsanol_c_last_error,
|
|
103
|
+
[], :string
|
|
104
|
+
attach_function :c_release, :parsanol_c_release,
|
|
105
|
+
%i[uint64], :void
|
|
106
|
+
end
|
|
107
|
+
# Probe the symbols now so a mismatched library fails loudly
|
|
108
|
+
# at availability time, not at first parse.
|
|
109
|
+
probe = binding_mod.c_last_error
|
|
110
|
+
@binding = binding_mod
|
|
111
|
+
@buffer = nil
|
|
112
|
+
!probe.nil? || true
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# Two-call buffer protocol: cap=0 asks for the needed size, then
|
|
116
|
+
# one allocation carries the whole batch.
|
|
117
|
+
def parse_into(handle, input)
|
|
118
|
+
needed = @binding.c_parse(handle, input, nil, 0)
|
|
119
|
+
return needed unless needed.negative?
|
|
120
|
+
|
|
121
|
+
@buffer = FFI::MemoryPointer.new(:uint64, -needed)
|
|
122
|
+
@binding.c_parse(handle, input, @buffer, -needed)
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
end
|
|
@@ -18,7 +18,7 @@ module Parsanol
|
|
|
18
18
|
def available?
|
|
19
19
|
return @cached_available unless @cached_available.nil?
|
|
20
20
|
|
|
21
|
-
@
|
|
21
|
+
@ext_loaded = begin
|
|
22
22
|
# Try versioned path first (released gem), then non-versioned (local dev)
|
|
23
23
|
ruby_version = RUBY_VERSION.split(".").take(2).join(".")
|
|
24
24
|
begin
|
|
@@ -30,6 +30,13 @@ module Parsanol
|
|
|
30
30
|
rescue LoadError
|
|
31
31
|
false
|
|
32
32
|
end
|
|
33
|
+
@cached_available = @ext_loaded || Ffi.available?
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# True when the MRI C-API extension is loaded; false when the
|
|
37
|
+
# engine runs through the ffi-gem cdylib tier instead.
|
|
38
|
+
def extension_loaded?
|
|
39
|
+
@ext_loaded ? true : false
|
|
33
40
|
end
|
|
34
41
|
|
|
35
42
|
# Parse input with a Ruby grammar, returning clean AST.
|
data/lib/parsanol/native.rb
CHANGED
|
@@ -10,6 +10,8 @@ require "parsanol/native/batch_decoder"
|
|
|
10
10
|
|
|
11
11
|
module Parsanol
|
|
12
12
|
module Native
|
|
13
|
+
# ffi-gem cdylib tier: lazy — only loaded when the MRI extension is absent.
|
|
14
|
+
autoload :Ffi, "parsanol/native/ffi"
|
|
13
15
|
class << self
|
|
14
16
|
# Check if native extension is available
|
|
15
17
|
def available?
|
|
@@ -38,6 +40,10 @@ module Parsanol
|
|
|
38
40
|
def parse(grammar, input)
|
|
39
41
|
raise LoadError, "Native parser not available" unless available?
|
|
40
42
|
|
|
43
|
+
# ffi-gem tier (JRuby/TruffleRuby/no-binary MRI): same contract,
|
|
44
|
+
# batch-decoded results, single reporter-pass error fallback.
|
|
45
|
+
return Ffi.parse(grammar, input) unless Parser.extension_loaded?
|
|
46
|
+
|
|
41
47
|
# Both sub-methods return the final decoded tree; on native failure
|
|
42
48
|
# they fall back to the pure-Ruby parser, whose result is already
|
|
43
49
|
# final and must not be transformed again.
|
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.18
|
|
5
5
|
platform: aarch64-linux
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-09-
|
|
11
|
+
date: 2026-09-16 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rake
|
|
@@ -200,6 +200,7 @@ files:
|
|
|
200
200
|
- lib/parsanol/native.rb
|
|
201
201
|
- lib/parsanol/native/batch_decoder.rb
|
|
202
202
|
- lib/parsanol/native/dynamic.rb
|
|
203
|
+
- lib/parsanol/native/ffi.rb
|
|
203
204
|
- lib/parsanol/native/parser.rb
|
|
204
205
|
- lib/parsanol/native/serializer.rb
|
|
205
206
|
- lib/parsanol/native/transformer.rb
|