parsanol 1.3.83-arm-linux → 1.3.85-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/repetition.rb +21 -14
- data/lib/parsanol/native/serializer.rb +4 -1
- data/lib/parsanol/native.rb +44 -2
- 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: b8fb8fead38031f96872f7aae3373ff012794c1733d534d759c6ac57e38cdb95
|
|
4
|
+
data.tar.gz: 11c3fbeae81c61325155c805cb31c8a0aefa6a29a3fa6979349912c715e0c596
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 02254b1575071cd812a89e9cc18559df5d1c0fe75038928d159a52d9e448374505765e69e98e7eca201730639ca212424d2c9ac183e198b1ef6e71a3aab080fd
|
|
7
|
+
data.tar.gz: 28dd52ef90e9930b67deea237f40b63f0c68ea7526c6d9dbe6653536f8f265977ee238e3cd91b6b5e83e571152b579788193c3749048adb84254c98e381255f6
|
|
@@ -48,16 +48,25 @@ module Parsanol
|
|
|
48
48
|
# Internal value for comparisons (nil becomes infinity)
|
|
49
49
|
@max_internal = max_count || Float::INFINITY
|
|
50
50
|
|
|
51
|
-
#
|
|
52
|
-
|
|
51
|
+
# Error messages render LAZILY (error_msgs): construction is
|
|
52
|
+
# hot-path builder/injector work, and stringifying the whole
|
|
53
|
+
# subtree eagerly is exponential on shared cross-referencing
|
|
54
|
+
# grammars (the same class of cost Sequence's fail_msg had,
|
|
55
|
+
# parsanol-ruby#180/#184).
|
|
53
56
|
@extra_error = "Extra input after last repetition"
|
|
54
57
|
end
|
|
55
58
|
|
|
56
59
|
# Error messages hash (for compatibility)
|
|
57
60
|
def error_msgs
|
|
58
|
-
{ minrep:
|
|
61
|
+
{ minrep: min_error, unconsumed: @extra_error }
|
|
59
62
|
end
|
|
60
63
|
|
|
64
|
+
# Rendered lazily and memoized on first failure (see initialize).
|
|
65
|
+
def min_error
|
|
66
|
+
@min_error ||= "Expected at least #{@min} of #{@parslet.inspect}"
|
|
67
|
+
end
|
|
68
|
+
private :min_error
|
|
69
|
+
|
|
61
70
|
# Executes the repetition.
|
|
62
71
|
#
|
|
63
72
|
# @param source [Parsanol::Source] input
|
|
@@ -110,8 +119,6 @@ module Parsanol
|
|
|
110
119
|
first
|
|
111
120
|
end
|
|
112
121
|
|
|
113
|
-
private
|
|
114
|
-
|
|
115
122
|
# Optional match (0 or 1)
|
|
116
123
|
def try_maybe(source, context, _consume_all)
|
|
117
124
|
success, value = @parslet.apply(source, context, false)
|
|
@@ -136,39 +143,39 @@ module Parsanol
|
|
|
136
143
|
success, value = @parslet.apply(source, context, consume_all)
|
|
137
144
|
return ok([@result_tag, value]) if success
|
|
138
145
|
|
|
139
|
-
context.err_at(self, source,
|
|
146
|
+
context.err_at(self, source, min_error, source.bytepos, [value])
|
|
140
147
|
end
|
|
141
148
|
|
|
142
149
|
def double_match(source, context, consume_all)
|
|
143
150
|
success, v1 = @parslet.apply(source, context, false)
|
|
144
151
|
unless success
|
|
145
|
-
return context.err_at(self, source,
|
|
152
|
+
return context.err_at(self, source, min_error, source.bytepos,
|
|
146
153
|
[v1])
|
|
147
154
|
end
|
|
148
155
|
|
|
149
156
|
success, v2 = @parslet.apply(source, context, consume_all)
|
|
150
157
|
return ok([@result_tag, v1, v2]) if success
|
|
151
158
|
|
|
152
|
-
context.err_at(self, source,
|
|
159
|
+
context.err_at(self, source, min_error, source.bytepos, [v2])
|
|
153
160
|
end
|
|
154
161
|
|
|
155
162
|
def triple_match(source, context, consume_all)
|
|
156
163
|
success, v1 = @parslet.apply(source, context, false)
|
|
157
164
|
unless success
|
|
158
|
-
return context.err_at(self, source,
|
|
165
|
+
return context.err_at(self, source, min_error, source.bytepos,
|
|
159
166
|
[v1])
|
|
160
167
|
end
|
|
161
168
|
|
|
162
169
|
success, v2 = @parslet.apply(source, context, false)
|
|
163
170
|
unless success
|
|
164
|
-
return context.err_at(self, source,
|
|
171
|
+
return context.err_at(self, source, min_error, source.bytepos,
|
|
165
172
|
[v2])
|
|
166
173
|
end
|
|
167
174
|
|
|
168
175
|
success, v3 = @parslet.apply(source, context, consume_all)
|
|
169
176
|
return ok([@result_tag, v1, v2, v3]) if success
|
|
170
177
|
|
|
171
|
-
context.err_at(self, source,
|
|
178
|
+
context.err_at(self, source, min_error, source.bytepos, [v3])
|
|
172
179
|
end
|
|
173
180
|
|
|
174
181
|
# General repetition: builds the tagged result Array in place so
|
|
@@ -205,7 +212,7 @@ module Parsanol
|
|
|
205
212
|
# Check minimum bound
|
|
206
213
|
if occurrence < @min
|
|
207
214
|
source.bytepos = start_pos
|
|
208
|
-
return context.err_at(self, source,
|
|
215
|
+
return context.err_at(self, source, min_error, start_pos,
|
|
209
216
|
failure_children(last_failure))
|
|
210
217
|
end
|
|
211
218
|
|
|
@@ -283,7 +290,7 @@ module Parsanol
|
|
|
283
290
|
if occurrence < @min
|
|
284
291
|
context.release_array(positions)
|
|
285
292
|
source.bytepos = start_pos
|
|
286
|
-
return context.err_at(self, source,
|
|
293
|
+
return context.err_at(self, source, min_error, start_pos,
|
|
287
294
|
failure_children(last_failure))
|
|
288
295
|
end
|
|
289
296
|
|
|
@@ -303,7 +310,7 @@ module Parsanol
|
|
|
303
310
|
# Check minimum
|
|
304
311
|
if occurrence < @min
|
|
305
312
|
source.bytepos = start_pos
|
|
306
|
-
return context.err_at(self, source,
|
|
313
|
+
return context.err_at(self, source, min_error, start_pos,
|
|
307
314
|
failure_children(last_failure))
|
|
308
315
|
end
|
|
309
316
|
|
|
@@ -334,7 +334,10 @@ module Parsanol
|
|
|
334
334
|
inner_id = serialize_atom(atom.wrapped_atom)
|
|
335
335
|
payload = {
|
|
336
336
|
"atom" => inner_id,
|
|
337
|
-
|
|
337
|
+
# a whitespace-only trivia declaration (whitespace: :space with
|
|
338
|
+
# no capture:) has no capturer map — the wire field is optional
|
|
339
|
+
# (relaton with the expressir grammar, parsanol-ruby#180)
|
|
340
|
+
"rules" => atom.capturers&.map { |marker, label| [marker, label.to_s] } || [],
|
|
338
341
|
}
|
|
339
342
|
# parsanol-ruby#180: the optional whitespace kind — units that
|
|
340
343
|
# match no marker record under it (source-preserving grammars).
|
data/lib/parsanol/native.rb
CHANGED
|
@@ -202,6 +202,38 @@ module Parsanol
|
|
|
202
202
|
stats
|
|
203
203
|
end
|
|
204
204
|
|
|
205
|
+
# True when the grammar carries no atoms the native tier cannot
|
|
206
|
+
# express (Dynamic callbacks, artifact custom bindings). Cached by
|
|
207
|
+
# grammar identity — the scan walks the atom tree once.
|
|
208
|
+
def native_expressible?(grammar)
|
|
209
|
+
root = grammar.is_a?(Parsanol::Parser) ? grammar.root : grammar
|
|
210
|
+
cache = (@expressible_cache ||= {}.compare_by_identity)
|
|
211
|
+
cache.fetch(root) do
|
|
212
|
+
expressible = !contains_inexpressible?(root, {}.compare_by_identity)
|
|
213
|
+
cache[root] = expressible
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
def contains_inexpressible?(atom, seen)
|
|
218
|
+
return false if seen.key?(atom)
|
|
219
|
+
|
|
220
|
+
seen[atom] = true
|
|
221
|
+
case atom
|
|
222
|
+
when Parsanol::Atoms::Dynamic, Parsanol::Atoms::CustomRef then true
|
|
223
|
+
when Parsanol::Atoms::Sequence, Parsanol::Atoms::Alternative
|
|
224
|
+
children = atom.respond_to?(:parslets) ? atom.parslets : atom.alternatives
|
|
225
|
+
children.any? { |child| contains_inexpressible?(child, seen) }
|
|
226
|
+
when Parsanol::Atoms::Entity, Parsanol::Atoms::Repetition,
|
|
227
|
+
Parsanol::Atoms::Named, Parsanol::Atoms::Capture, Parsanol::Atoms::Ignored,
|
|
228
|
+
Parsanol::Atoms::Trivia, Parsanol::Atoms::TriviaCapture, Parsanol::Atoms::Lookahead
|
|
229
|
+
inner = atom.respond_to?(:parslet) ? atom.parslet : nil
|
|
230
|
+
inner ||= atom.wrapped_atom if atom.respond_to?(:wrapped_atom)
|
|
231
|
+
inner && contains_inexpressible?(inner, seen)
|
|
232
|
+
else
|
|
233
|
+
false
|
|
234
|
+
end
|
|
235
|
+
end
|
|
236
|
+
|
|
205
237
|
# Translates a native backend failure into the Parsanol error protocol.
|
|
206
238
|
#
|
|
207
239
|
# When the grammar atom is at hand, reparses through the pure Ruby
|
|
@@ -227,9 +259,19 @@ module Parsanol
|
|
|
227
259
|
# across long parses (#123).
|
|
228
260
|
message = error.message
|
|
229
261
|
if parsanol_grammar && (pos_str = message[NATIVE_POS_MARKER, 1])
|
|
262
|
+
# The interpreter reparse exists to RECOVER grammars the
|
|
263
|
+
# native tier cannot express (Dynamic/CustomRef atoms —
|
|
264
|
+
# parsanol-ruby#80/#129). For grammars without them the
|
|
265
|
+
# native failure is authoritative and the deepest-position
|
|
266
|
+
# diagnostics ride in this message — reparsing through the
|
|
267
|
+
# interpreter buys nothing and, on capture-heavy injected
|
|
268
|
+
# grammars, explodes (#190: the interpreter memo never
|
|
269
|
+
# stores capture-spanning outcomes).
|
|
230
270
|
source = Parsanol::Source.new(input)
|
|
231
|
-
|
|
232
|
-
|
|
271
|
+
unless native_expressible?(grammar)
|
|
272
|
+
success, value = grammar.run_with_context(source, nil, true)
|
|
273
|
+
return grammar.finalize_result(value) if success
|
|
274
|
+
end
|
|
233
275
|
|
|
234
276
|
pos = pos_str.to_i
|
|
235
277
|
msg = message.sub(NATIVE_POS_MARKER, "")
|
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.85
|
|
5
5
|
platform: arm-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-09 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
|