parsanol 1.3.82-arm-linux → 1.3.84-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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 755c4aaa1b93bb1331ff3a845e21cc87b73451a63676776590fe76b17b398056
4
- data.tar.gz: 46c3065db82aab1b10d5eae3ff1027772f3fcbad30d1851356fa1e7c8777db87
3
+ metadata.gz: 7fe58dafe54c7d48c133db50eaa7e71e289405348f4f9127a6cebb381efd648f
4
+ data.tar.gz: 4150bbf3e58d1f56733309bf297d249b17b1896a5f5406ae28bcd18ab93cbed0
5
5
  SHA512:
6
- metadata.gz: 044e61d3fc124a973e5a03bffb3814fac6fd5c695f860a713457cd592927146c9aa328db2460ca460010ee23cb514325825a831e721f537c00fbeb9f70956f24
7
- data.tar.gz: d4d50039baa8eed43d7be5232bce8a0d66e8b1f72aeac9b6c124a6ccd0673125def471e49796c78969b324cd0463696c20c30081ef1ef33a0f55a0bf7330a315
6
+ metadata.gz: 4c5193545cbf0c4c9d8d4993e218876192d134a6085d8ba667f241f1ee7528a8919a6603f3be1a605eecb8b2146933997c44536f5861359c652bbf0d6cfac35e
7
+ data.tar.gz: 837871fe2d1de062d73ed4eb47dac35e471346fb3926218b83c54fda9088fb27ba2b5a581cd4176c05854580df0ffd23dc0d6ac4223bd1024942c2d09ee6bd98
@@ -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
- # Pre-built error messages
52
- @min_error = "Expected at least #{min_count} of #{parser.inspect}"
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: @min_error, unconsumed: @extra_error }
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, @min_error, source.bytepos, [value])
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, @min_error, source.bytepos,
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, @min_error, source.bytepos, [v2])
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, @min_error, source.bytepos,
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, @min_error, source.bytepos,
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, @min_error, source.bytepos, [v3])
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, @min_error, start_pos,
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, @min_error, start_pos,
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, @min_error, start_pos,
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
- "rules" => atom.capturers.map { |marker, label| [marker, label.to_s] },
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
- @memo = {}.compare_by_identity
111
- @in_progress = {}.compare_by_identity
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
- def walk(atom)
143
- cached = @memo[atom]
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
- injected = walk(child)
155
- out << maybe unless wrapper?(injected) || injected.is_a?(Atoms::Trivia)
156
- out << injected
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 the
178
- # identity visited-set guarding recursion.
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Parsanol
4
- VERSION = "1.3.82"
4
+ VERSION = "1.3.84"
5
5
  end
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.82
4
+ version: 1.3.84
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-08 00:00:00.000000000 Z
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