parsanol 1.3.82 → 1.3.84
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/skip.rb +35 -21
- data/lib/parsanol/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 538f5154142806cd3797526af8304d450faf55e3ea08af3215990a9abab94538
|
|
4
|
+
data.tar.gz: 5e42a6e8f10a85f3dbdcff23895ef6e745aa2af46d9cb513100094efb045817b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d75b5ea646136ce92dcf4a811f4bd1341dd1c5372eec6e2b91d9d8734a1d3acdd8b4301f6cb671a90a5211c02444b6f2a0f5cff5d2902cb1e40fb56cf8c960e2
|
|
7
|
+
data.tar.gz: fe20987b02a24520432855e5ab081f14f8b0075fa7d4b21306ae15793942738ea5c71a64dc51db5a8acefd372161f5d7ef624f9f6c9ac42bbf129406d84b9e84
|
|
@@ -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/skip.rb
CHANGED
|
@@ -107,12 +107,15 @@ module Parsanol
|
|
|
107
107
|
@markers = markers
|
|
108
108
|
@whitespace_kind = whitespace_kind
|
|
109
109
|
@wrapper_ids = {}.compare_by_identity
|
|
110
|
-
|
|
111
|
-
|
|
110
|
+
# Results keyed per injection context: the same shared atom
|
|
111
|
+
# can be reached both inside and outside repetition interiors,
|
|
112
|
+
# and the refinement injects differently there.
|
|
113
|
+
@memo = { true => {}.compare_by_identity, false => {}.compare_by_identity }
|
|
114
|
+
@in_progress = { true => {}.compare_by_identity, false => {}.compare_by_identity }
|
|
112
115
|
end
|
|
113
116
|
|
|
114
117
|
def inject(atom, entry: false)
|
|
115
|
-
injected = walk(atom)
|
|
118
|
+
injected = walk(atom, false)
|
|
116
119
|
return injected unless entry
|
|
117
120
|
|
|
118
121
|
Atoms::Sequence.new(maybe, injected, maybe)
|
|
@@ -139,55 +142,66 @@ module Parsanol
|
|
|
139
142
|
@wrapper_ids.key?(atom)
|
|
140
143
|
end
|
|
141
144
|
|
|
142
|
-
|
|
143
|
-
|
|
145
|
+
# +rep_interior+: the d54a29e refinement (PARG's owner-set
|
|
146
|
+
# semantics, now aligned for the DSL): no injection inside
|
|
147
|
+
# repetition interiors except through rule references — their
|
|
148
|
+
# bodies are fresh injection scopes. Wrapping char-level
|
|
149
|
+
# terminals inside a repetition consumes trivia within the
|
|
150
|
+
# ENCLOSING capture's scope and mis-attaches recorded units when
|
|
151
|
+
# the iteration fails.
|
|
152
|
+
def walk(atom, rep_interior)
|
|
153
|
+
cached = @memo[rep_interior][atom]
|
|
144
154
|
return cached if cached
|
|
145
|
-
return atom if @in_progress.key?(atom)
|
|
155
|
+
return atom if @in_progress[rep_interior].key?(atom)
|
|
146
156
|
return atom if atom.equal?(@skip_atom)
|
|
147
157
|
|
|
148
|
-
@in_progress[atom] = true
|
|
158
|
+
@in_progress[rep_interior][atom] = true
|
|
149
159
|
injected =
|
|
150
160
|
case atom
|
|
151
161
|
when Atoms::Sequence
|
|
152
162
|
out = []
|
|
153
163
|
atom.parslets.each do |child|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
164
|
+
walked = walk(child, rep_interior)
|
|
165
|
+
unless rep_interior || wrapper?(walked) || walked.is_a?(Atoms::Trivia)
|
|
166
|
+
out << maybe
|
|
167
|
+
end
|
|
168
|
+
out << walked
|
|
157
169
|
end
|
|
158
170
|
out.length == 1 ? out.first : Atoms::Sequence.new(*out)
|
|
159
171
|
when Atoms::Alternative
|
|
160
|
-
Atoms::Alternative.new(*atom.alternatives.map { |a| walk(a) })
|
|
172
|
+
Atoms::Alternative.new(*atom.alternatives.map { |a| walk(a, rep_interior) })
|
|
161
173
|
when Atoms::Repetition
|
|
162
174
|
if wrapper?(atom)
|
|
163
175
|
atom
|
|
164
176
|
else
|
|
165
|
-
Atoms::Repetition.new(walk(atom.parslet), atom.min, atom.max,
|
|
177
|
+
Atoms::Repetition.new(walk(atom.parslet, true), atom.min, atom.max,
|
|
166
178
|
atom.result_tag)
|
|
167
179
|
end
|
|
168
180
|
when Atoms::Named
|
|
169
|
-
Atoms::Named.new(walk(atom.parslet), atom.name)
|
|
181
|
+
Atoms::Named.new(walk(atom.parslet, rep_interior), atom.name)
|
|
170
182
|
when Atoms::Lookahead
|
|
171
|
-
Atoms::Lookahead.new(walk(atom.bound_parslet), atom.positive)
|
|
183
|
+
Atoms::Lookahead.new(walk(atom.bound_parslet, rep_interior), atom.positive)
|
|
172
184
|
when Atoms::Ignored
|
|
173
|
-
Atoms::Ignored.new(walk(atom.wrapped_atom))
|
|
185
|
+
Atoms::Ignored.new(walk(atom.wrapped_atom, rep_interior))
|
|
174
186
|
when Atoms::Entity
|
|
175
187
|
# Rule bodies own their injection when the grammar declares
|
|
176
188
|
# skip on every rule (PARG); in the DSL surface the root tree
|
|
177
|
-
# is walked once, so descend through resolved bodies with
|
|
178
|
-
#
|
|
189
|
+
# is walked once, so descend through resolved bodies with
|
|
190
|
+
# the in-progress set guarding recursion. A rule body is a
|
|
191
|
+
# fresh injection scope even inside a repetition interior —
|
|
192
|
+
# the d54a29e exception is for rule-reference children.
|
|
179
193
|
begin
|
|
180
|
-
walk(atom.parslet)
|
|
194
|
+
walk(atom.parslet, false)
|
|
181
195
|
rescue StandardError
|
|
182
196
|
atom
|
|
183
197
|
end
|
|
184
198
|
when Atoms::Str, Atoms::Re
|
|
185
|
-
Atoms::Sequence.new(maybe, atom)
|
|
199
|
+
rep_interior ? atom : Atoms::Sequence.new(maybe, atom)
|
|
186
200
|
else
|
|
187
201
|
atom
|
|
188
202
|
end
|
|
189
|
-
@in_progress.delete(atom)
|
|
190
|
-
@memo[atom] = injected
|
|
203
|
+
@in_progress[rep_interior].delete(atom)
|
|
204
|
+
@memo[rep_interior][atom] = injected
|
|
191
205
|
injected
|
|
192
206
|
end
|
|
193
207
|
end
|
data/lib/parsanol/version.rb
CHANGED