parsanol 1.3.14-arm-linux → 1.3.16-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/atoms/base.rb +26 -6
- data/lib/parsanol/native/transformer.rb +8 -7
- data/lib/parsanol/native.rb +34 -14
- data/lib/parsanol/parser.rb +27 -23
- data/lib/parsanol/version.rb +1 -1
- data/lib/parsanol/vm.rb +1140 -0
- data/lib/parsanol.rb +1 -0
- 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: d8496db15cc90acf09d51ca06fb3fbeda98ed9a1cf010eee22177aef50d9b6e3
|
|
4
|
+
data.tar.gz: f11121252847374665e97bbe23881723c66314d960c7532246c3ed79f9ecd565
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 4d649379c1796c92079fe220dedc76fac3654805958fe956de43ee47f88099b0577621f219e51d052c35c2f0f063c919aaadfbd36789171e5dd709eac6babbba
|
|
7
|
+
data.tar.gz: d8e2af5697eb5d4cc745a71257d0c770d5b34dbd6e156e4da118e9516f16da348662575d8e892bb2ca466174e6abfed0c458b0658bb471c3a9b211159a4794f6
|
data/lib/parsanol/atoms/base.rb
CHANGED
|
@@ -30,9 +30,29 @@ module Parsanol
|
|
|
30
30
|
# @return [Object] the parsed result
|
|
31
31
|
# @raise [Parsanol::ParseFailed] on parse failure
|
|
32
32
|
def parse(source, options = {})
|
|
33
|
-
input = normalize_input(source)
|
|
34
33
|
must_consume_all = !options[:prefix]
|
|
35
34
|
|
|
35
|
+
# Compiled-VM fast path: String input, full-consumption semantics.
|
|
36
|
+
# On failure (or unsupported grammar / budget exhaustion) fall
|
|
37
|
+
# through to the interpreter, which also produces the exact
|
|
38
|
+
# cause-tree diagnostics. run_for memoizes heavy-backtracking
|
|
39
|
+
# grammars transparently.
|
|
40
|
+
if must_consume_all && source.is_a?(String) &&
|
|
41
|
+
(program = VM.program_for(self))
|
|
42
|
+
result = VM.run_for(self, program, source, true)
|
|
43
|
+
if result == VM::BAIL
|
|
44
|
+
# Internal bail: fall back to the interpreter and skip the VM
|
|
45
|
+
# for this grammar from now on.
|
|
46
|
+
VM.disable_for!(self)
|
|
47
|
+
elsif result.first
|
|
48
|
+
return finalize_result(result[1])
|
|
49
|
+
end
|
|
50
|
+
# Clean [false, nil]: the input does not parse — the interpreter
|
|
51
|
+
# reparse below produces the detailed cause tree.
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
input = normalize_input(source)
|
|
55
|
+
|
|
36
56
|
# Initial parse attempt (no error collection)
|
|
37
57
|
success, value = run_with_context(input, nil, must_consume_all)
|
|
38
58
|
return finalize_result(value) if success
|
|
@@ -160,6 +180,11 @@ module Parsanol
|
|
|
160
180
|
# Alias for ok (legacy compatibility)
|
|
161
181
|
alias succ ok
|
|
162
182
|
|
|
183
|
+
# Finalizes result by flattening.
|
|
184
|
+
def finalize_result(value)
|
|
185
|
+
flatten(value)
|
|
186
|
+
end
|
|
187
|
+
|
|
163
188
|
private
|
|
164
189
|
|
|
165
190
|
# Converts raw input to Source if needed.
|
|
@@ -198,11 +223,6 @@ module Parsanol
|
|
|
198
223
|
|
|
199
224
|
cause.raise
|
|
200
225
|
end
|
|
201
|
-
|
|
202
|
-
# Finalizes result by flattening.
|
|
203
|
-
def finalize_result(value)
|
|
204
|
-
flatten(value)
|
|
205
|
-
end
|
|
206
226
|
end
|
|
207
227
|
end
|
|
208
228
|
end
|
|
@@ -132,9 +132,11 @@ module Parsanol
|
|
|
132
132
|
# Transform the value
|
|
133
133
|
transformed = transform(value, named: true)
|
|
134
134
|
|
|
135
|
-
# Check if value is a tagged repetition from native parser
|
|
135
|
+
# Check if value is a tagged repetition from native parser.
|
|
136
|
+
# The Rust handle path tags with Symbols, the batch decoder with
|
|
137
|
+
# ":repetition" Strings — accept both.
|
|
136
138
|
is_tagged_repetition = value.is_a?(Array) && !value.empty? &&
|
|
137
|
-
|
|
139
|
+
[REPETITION_SYM, REPETITION_TAG].include?(value.first)
|
|
138
140
|
|
|
139
141
|
# Check RAW value for repetition pattern BEFORE transformation
|
|
140
142
|
# Array with items that all have the parent key
|
|
@@ -203,13 +205,12 @@ module Parsanol
|
|
|
203
205
|
# Empty array from repetition stays as empty array
|
|
204
206
|
if transformed.empty?
|
|
205
207
|
{ sym_key => EMPTY_ARRAY }
|
|
206
|
-
#
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
208
|
+
# Hash items already carry their own capture names — a
|
|
209
|
+
# repetition of named captures keeps them as-is (parslet
|
|
210
|
+
# semantics); only unnamed items get the parent name per item.
|
|
211
|
+
elsif transformed.all?(Hash)
|
|
210
212
|
{ sym_key => transformed }
|
|
211
213
|
else
|
|
212
|
-
# Wrap each item with the name
|
|
213
214
|
{ sym_key => transformed.map { |item| { sym_key => item } } }
|
|
214
215
|
end
|
|
215
216
|
elsif transformed.is_a?(::Parsanol::Slice) && transformed.empty?
|
data/lib/parsanol/native.rb
CHANGED
|
@@ -38,14 +38,14 @@ module Parsanol
|
|
|
38
38
|
def parse(grammar, input)
|
|
39
39
|
raise LoadError, "Native parser not available" unless available?
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
41
|
+
# Both sub-methods return the final decoded tree; on native failure
|
|
42
|
+
# they fall back to the pure-Ruby parser, whose result is already
|
|
43
|
+
# final and must not be transformed again.
|
|
44
|
+
if grammar.is_a?(String)
|
|
45
|
+
parse_json_grammar(grammar, input)
|
|
46
|
+
else
|
|
47
|
+
parse_atom_grammar(grammar, input)
|
|
48
|
+
end
|
|
49
49
|
end
|
|
50
50
|
|
|
51
51
|
# Memory-bounded parsing without packrat cache.
|
|
@@ -65,12 +65,14 @@ module Parsanol
|
|
|
65
65
|
Parser.serialize_grammar(grammar)
|
|
66
66
|
end
|
|
67
67
|
|
|
68
|
+
# Decode here, not around the fallback: raise_native_parse_error
|
|
69
|
+
# returns the Ruby parser's already-final tree on success.
|
|
68
70
|
begin
|
|
69
|
-
|
|
71
|
+
BatchDecoder.decode_and_flatten(_parse_fresh_raw(grammar_json, input),
|
|
72
|
+
input, Parsanol::Slice)
|
|
70
73
|
rescue RuntimeError => e
|
|
71
74
|
raise_native_parse_error(e, grammar, input)
|
|
72
75
|
end
|
|
73
|
-
BatchDecoder.decode_and_flatten(raw_ast, input, Parsanol::Slice)
|
|
74
76
|
end
|
|
75
77
|
|
|
76
78
|
# Parse and return RAW AST without transformation.
|
|
@@ -192,7 +194,20 @@ module Parsanol
|
|
|
192
194
|
# pre-serialized JSON grammars the native message is wrapped in a
|
|
193
195
|
# Parsanol::ParseFailed directly.
|
|
194
196
|
def raise_native_parse_error(error, grammar, input)
|
|
195
|
-
|
|
197
|
+
if grammar.respond_to?(:parse)
|
|
198
|
+
# One interpreter pass with the error reporter attached covers
|
|
199
|
+
# both jobs: a success means the native backend could not
|
|
200
|
+
# express the grammar (recover the tree), a failure raises the
|
|
201
|
+
# parslet-compatible cause tree. The native backend has
|
|
202
|
+
# already failed, so a separate plain attempt first would be a
|
|
203
|
+
# wasted parse.
|
|
204
|
+
reporter = Parsanol::ErrorReporter::Tree.new
|
|
205
|
+
source = Parsanol::Source.new(input)
|
|
206
|
+
success, value = grammar.run_with_context(source, reporter, true)
|
|
207
|
+
return grammar.finalize_result(value) if success
|
|
208
|
+
|
|
209
|
+
value.raise
|
|
210
|
+
end
|
|
196
211
|
|
|
197
212
|
source = Parsanol::Source.new(input)
|
|
198
213
|
cause = Parsanol::Cause.new(error.message, source, source.bytepos)
|
|
@@ -201,7 +216,8 @@ module Parsanol
|
|
|
201
216
|
|
|
202
217
|
# Pre-serialized JSON grammar path (library authors with cached JSON).
|
|
203
218
|
def parse_json_grammar(grammar_json, input)
|
|
204
|
-
_parse_raw(grammar_json, input)
|
|
219
|
+
BatchDecoder.decode_and_flatten(_parse_raw(grammar_json, input),
|
|
220
|
+
input, Parsanol::Slice)
|
|
205
221
|
rescue RuntimeError => e
|
|
206
222
|
raise_native_parse_error(e, grammar_json, input)
|
|
207
223
|
end
|
|
@@ -212,12 +228,16 @@ module Parsanol
|
|
|
212
228
|
handle = Parser.grammar_handle(grammar)
|
|
213
229
|
|
|
214
230
|
begin
|
|
215
|
-
_parse_handle(handle, input)
|
|
231
|
+
BatchDecoder.decode_and_flatten(_parse_handle(handle, input),
|
|
232
|
+
input, Parsanol::Slice)
|
|
216
233
|
rescue ArgumentError
|
|
217
234
|
# Handle dropped Rust-side (e.g. cache cleared): re-register once.
|
|
218
235
|
Parser.invalidate_handle(handle)
|
|
219
236
|
begin
|
|
220
|
-
|
|
237
|
+
BatchDecoder.decode_and_flatten(
|
|
238
|
+
_parse_handle(Parser.grammar_handle(grammar), input),
|
|
239
|
+
input, Parsanol::Slice
|
|
240
|
+
)
|
|
221
241
|
rescue RuntimeError => e
|
|
222
242
|
raise_native_parse_error(e, grammar, input)
|
|
223
243
|
end
|
data/lib/parsanol/parser.rb
CHANGED
|
@@ -109,32 +109,36 @@ module Parsanol
|
|
|
109
109
|
# result[:name].to_s # => "hello"
|
|
110
110
|
#
|
|
111
111
|
def parse(input, mode_or_opts = {}, **kwargs)
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
# Native backend by default; falls back to pure Ruby inside
|
|
118
|
-
# parse_native when the extension is missing.
|
|
119
|
-
parse_native(input, merged)
|
|
112
|
+
opts =
|
|
113
|
+
if mode_or_opts.is_a?(Hash)
|
|
114
|
+
mode_or_opts.merge(kwargs)
|
|
115
|
+
elsif mode_or_opts.nil?
|
|
116
|
+
kwargs
|
|
120
117
|
else
|
|
121
|
-
|
|
118
|
+
# New API: parse(input, :mode, **options)
|
|
119
|
+
kwargs[:mode] = mode_or_opts
|
|
120
|
+
kwargs
|
|
122
121
|
end
|
|
122
|
+
# parse(input, {mode: :ruby, ...}) is the same call shape a subclass
|
|
123
|
+
# forwarding options via super produces; :mode must be honored
|
|
124
|
+
# wherever it appears, or those callers silently get the native path.
|
|
125
|
+
mode = opts.delete(:mode) ||
|
|
126
|
+
(if Parsanol::Native.available? && !opts.key?(:prefix) &&
|
|
127
|
+
!opts.key?(:reporter)
|
|
128
|
+
:native
|
|
129
|
+
else
|
|
130
|
+
:ruby
|
|
131
|
+
end)
|
|
132
|
+
case mode
|
|
133
|
+
when :ruby
|
|
134
|
+
super(input, opts)
|
|
135
|
+
when :native
|
|
136
|
+
parse_native(input, opts)
|
|
137
|
+
when :json
|
|
138
|
+
parse_json(input, opts)
|
|
123
139
|
else
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
(Parsanol::Native.available? ? :native : :ruby)
|
|
127
|
-
case mode
|
|
128
|
-
when :ruby
|
|
129
|
-
super(input, kwargs)
|
|
130
|
-
when :native
|
|
131
|
-
parse_native(input, kwargs)
|
|
132
|
-
when :json
|
|
133
|
-
parse_json(input, kwargs)
|
|
134
|
-
else
|
|
135
|
-
raise ArgumentError,
|
|
136
|
-
"Unknown mode: #{mode}. Valid modes: :ruby, :native, :json"
|
|
137
|
-
end
|
|
140
|
+
raise ArgumentError,
|
|
141
|
+
"Unknown mode: #{mode}. Valid modes: :ruby, :native, :json"
|
|
138
142
|
end
|
|
139
143
|
end
|
|
140
144
|
|
data/lib/parsanol/version.rb
CHANGED