parsanol 1.3.69-aarch64-linux → 1.3.71-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 +2 -2
- data/lib/parsanol/3.3/parsanol_native.so +2 -2
- data/lib/parsanol/3.4/parsanol_native.so +2 -2
- data/lib/parsanol/4.0/parsanol_native.so +2 -2
- data/lib/parsanol/atoms/context.rb +33 -0
- data/lib/parsanol/atoms/named.rb +24 -4
- data/lib/parsanol/atoms/trivia.rb +48 -0
- data/lib/parsanol/native/libparsanol.so +2 -2
- data/lib/parsanol/parg/artifact.rb +4 -1
- data/lib/parsanol/parg/compiler.rb +52 -1
- data/lib/parsanol/parg/document.rb +1 -1
- data/lib/parsanol/parg/parser.rb +23 -2
- data/lib/parsanol/version.rb +1 -1
- data/lib/parsanol/vm.rb +6 -0
- 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: 7521a5d8e982e8a4790eb217b8c3a3f21190247b411b6862bacb4e4a3a919af3
|
|
4
|
+
data.tar.gz: 581f51a2fb7b68a7ff5a79c149338fccd63ff4e09398fa5e5a73f1479e895104
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 398da535c6500293148c92a6616cfa9bbc7834893e8911fa38f515dad0f81dce3ab0bec8ff5281c5a1ec2f1ade77b4b8d9c23244e07606f82b10fd24b802a123
|
|
7
|
+
data.tar.gz: '0293cc80cd29a221f10bb739af8b7f41a2f33c85e23598ba1599edc67edb05a6606eb36ae119c3e929034f93a33bb0e2f31546855c5b987299a18378f31209ba'
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
[diffend] Oversized file quarantined before diffing.
|
|
2
2
|
name: data/lib/parsanol/3.2/parsanol_native.so
|
|
3
|
-
size:
|
|
4
|
-
sha256:
|
|
3
|
+
size: 39067688 bytes
|
|
4
|
+
sha256: 1336a78f2ee05d8e4599a6ee7dc70263b6774bedb1234ae109c02013c76be06c
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
[diffend] Oversized file quarantined before diffing.
|
|
2
2
|
name: data/lib/parsanol/3.3/parsanol_native.so
|
|
3
|
-
size:
|
|
4
|
-
sha256:
|
|
3
|
+
size: 39306936 bytes
|
|
4
|
+
sha256: 1981488f1c97656d97bd2c6b2b63bcfc0bc4ca98c27ab28743dfaf32150c4ffc
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
[diffend] Oversized file quarantined before diffing.
|
|
2
2
|
name: data/lib/parsanol/3.4/parsanol_native.so
|
|
3
|
-
size:
|
|
4
|
-
sha256:
|
|
3
|
+
size: 39310816 bytes
|
|
4
|
+
sha256: c4e57e00acce9397e2a7607e74b5bf679e572db69db4a32659990f59ded86028
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
[diffend] Oversized file quarantined before diffing.
|
|
2
2
|
name: data/lib/parsanol/4.0/parsanol_native.so
|
|
3
|
-
size:
|
|
4
|
-
sha256:
|
|
3
|
+
size: 39320888 bytes
|
|
4
|
+
sha256: 23eb16a3cc0a3204738f7b315571c530bdeaad70c7fee4c5e20846f4ea13064d
|
|
@@ -67,6 +67,11 @@ module Parsanol
|
|
|
67
67
|
# Injected-trivia depth: while positive, reported causes are
|
|
68
68
|
# marked trivia and never surface in diagnostics.
|
|
69
69
|
@trivia_depth = 0
|
|
70
|
+
# Captured trivia channel (parsanol-ruby#152): when the grammar
|
|
71
|
+
# declares `skip ... capture:`, matched trivia units land here
|
|
72
|
+
# and the NEXT successful Named capture attaches (and drains)
|
|
73
|
+
# them under `comments:`.
|
|
74
|
+
@pending_trivia = []
|
|
70
75
|
@evict_threshold = 200
|
|
71
76
|
@evict_counter = 0
|
|
72
77
|
@evict_interval = 100
|
|
@@ -258,6 +263,34 @@ module Parsanol
|
|
|
258
263
|
[false, @reporter.err(*)]
|
|
259
264
|
end
|
|
260
265
|
|
|
266
|
+
# Records one captured trivia unit (kind, text) for attachment to
|
|
267
|
+
# the next successful Named capture.
|
|
268
|
+
def push_captured_trivia(kind, text)
|
|
269
|
+
@pending_trivia << { kind: kind, text: text }
|
|
270
|
+
nil
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
# Snapshot for backtracking: a failed branch must not leak its
|
|
274
|
+
# half-recorded trivia into the successful alternative.
|
|
275
|
+
def take_pending_trivia_snapshot
|
|
276
|
+
@pending_trivia.dup
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
def restore_pending_trivia(snapshot)
|
|
280
|
+
@pending_trivia = snapshot
|
|
281
|
+
nil
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
# Drains pending captured trivia (attached by the next
|
|
285
|
+
# successful Named capture). Backtracking discards whatever has
|
|
286
|
+
# not been attached yet — the caller snapshots position and
|
|
287
|
+
# restores this list alongside.
|
|
288
|
+
def take_pending_trivia
|
|
289
|
+
list = @pending_trivia
|
|
290
|
+
@pending_trivia = []
|
|
291
|
+
list
|
|
292
|
+
end
|
|
293
|
+
|
|
261
294
|
# Brackets a parse inside injected trivia: causes reported while
|
|
262
295
|
# the depth is positive carry the trivia flag and never surface
|
|
263
296
|
# in rendered trees or deepest-failure positions.
|
data/lib/parsanol/atoms/named.rb
CHANGED
|
@@ -32,10 +32,32 @@ module Parsanol
|
|
|
32
32
|
# @param consume_all [Boolean] require full consumption
|
|
33
33
|
# @return [Array(Boolean, Object)] result
|
|
34
34
|
def apply(source, context, consume_all)
|
|
35
|
+
trivia_before = context.take_pending_trivia_snapshot
|
|
35
36
|
success, value = @parslet.apply(source, context, consume_all)
|
|
36
|
-
|
|
37
|
+
unless success
|
|
38
|
+
context.restore_pending_trivia(trivia_before)
|
|
39
|
+
return [false, value]
|
|
40
|
+
end
|
|
37
41
|
|
|
38
|
-
|
|
42
|
+
comments = context.take_pending_trivia
|
|
43
|
+
result = wrap_result(value)
|
|
44
|
+
result = attach_comments(result, comments) unless comments.empty?
|
|
45
|
+
ok(result)
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
private
|
|
49
|
+
|
|
50
|
+
# parsanol-ruby#152: trivia captured ahead of this capture rides
|
|
51
|
+
# with it under `comments:`. The attachment only fires when the
|
|
52
|
+
# grammar declared capture AND trivia actually preceded — key
|
|
53
|
+
# absence everywhere else keeps v1 trees byte-identical.
|
|
54
|
+
def attach_comments(result, comments)
|
|
55
|
+
list = comments.map { |unit| { unit[:kind] => unit[:text] } }
|
|
56
|
+
if result.is_a?(Hash)
|
|
57
|
+
result.merge(comments: list)
|
|
58
|
+
else
|
|
59
|
+
{ @name => result, comments: list }
|
|
60
|
+
end
|
|
39
61
|
end
|
|
40
62
|
|
|
41
63
|
# Named wrappers skip caching (inner parser handles it).
|
|
@@ -60,8 +82,6 @@ module Parsanol
|
|
|
60
82
|
@parslet.first_set
|
|
61
83
|
end
|
|
62
84
|
|
|
63
|
-
private
|
|
64
|
-
|
|
65
85
|
# Wraps matched value in labeled hash.
|
|
66
86
|
#
|
|
67
87
|
# @param matched [Object] matched value
|
|
@@ -17,5 +17,53 @@ module Parsanol
|
|
|
17
17
|
"trivia(#{@wrapped_atom.to_s(prec)})"
|
|
18
18
|
end
|
|
19
19
|
end
|
|
20
|
+
|
|
21
|
+
# parsanol-ruby#152: the skip-declared capture wrapper. Whitespace
|
|
22
|
+
# trivia stays Ignored; comment-shaped units (the grammar names the
|
|
23
|
+
# capture rules in the declaration) are recorded into the context
|
|
24
|
+
# channel for attachment to the next successful Named capture.
|
|
25
|
+
# Span discipline is unchanged: the matched bytes still contribute
|
|
26
|
+
# nothing to values or capture spans.
|
|
27
|
+
class TriviaCapture < Trivia
|
|
28
|
+
# +capturers+ maps leading-literal marker -> kind label (the
|
|
29
|
+
# compiler derives markers from each capturer rule's first Str
|
|
30
|
+
# atom, e.g. "//" => :line_comment); units not matching any
|
|
31
|
+
# marker are whitespace-shaped and stay unrecorded.
|
|
32
|
+
def initialize(atom, capturers)
|
|
33
|
+
super(atom)
|
|
34
|
+
@capturers = capturers
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def apply(source, context, consume_all)
|
|
38
|
+
context.with_trivia do
|
|
39
|
+
start = source.bytepos
|
|
40
|
+
ok, _value = @wrapped_atom.apply(source, context, consume_all)
|
|
41
|
+
if ok && source.bytepos > start
|
|
42
|
+
record(source, context, start, source.bytepos)
|
|
43
|
+
return ok(nil)
|
|
44
|
+
end
|
|
45
|
+
[ok, _value]
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def to_s_inner(_prec)
|
|
50
|
+
"trivia!(@wrapped_atom.to_s(prec))"
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
private
|
|
54
|
+
|
|
55
|
+
def record(source, context, start_pos, end_pos)
|
|
56
|
+
return unless @capturers
|
|
57
|
+
|
|
58
|
+
text = source.input[start_pos...end_pos]
|
|
59
|
+
# A trivia unit may lead with whitespace before the comment
|
|
60
|
+
# shape; markers test the comment head.
|
|
61
|
+
stripped = text.lstrip
|
|
62
|
+
marker, label = @capturers.find { |m, _label| stripped.start_with?(m) }
|
|
63
|
+
return unless marker
|
|
64
|
+
|
|
65
|
+
context.push_captured_trivia(label, stripped.strip)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
20
68
|
end
|
|
21
69
|
end
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
[diffend] Oversized file quarantined before diffing.
|
|
2
2
|
name: data/lib/parsanol/native/libparsanol.so
|
|
3
|
-
size:
|
|
4
|
-
sha256:
|
|
3
|
+
size: 34928224 bytes
|
|
4
|
+
sha256: 30c136ad62e8cd47f56529bd1f61218985ade298ac6f0965b4a8ec43bcef8e38
|
|
@@ -71,7 +71,10 @@ module Parsanol
|
|
|
71
71
|
|
|
72
72
|
root_atom(entry_name).parse(input)
|
|
73
73
|
when :ruby
|
|
74
|
-
|
|
74
|
+
# Deepest-failure reporting parity with the native engine: the
|
|
75
|
+
# default Tree reporter keeps the most recent (root) failure,
|
|
76
|
+
# which reports position 1:1 for grammars with entry wrappers.
|
|
77
|
+
root_atom(entry_name).parse(input, reporter: ErrorReporter::Deepest.new)
|
|
75
78
|
else
|
|
76
79
|
raise ArgumentError, "unknown mode #{mode.inspect} (use :native or :ruby)"
|
|
77
80
|
end
|
|
@@ -141,6 +141,51 @@ module Parsanol
|
|
|
141
141
|
end
|
|
142
142
|
end
|
|
143
143
|
|
|
144
|
+
# parsanol-ruby#152: capturer rules are the rules transitively
|
|
145
|
+
# referenced by the skip declaration whose leading literal is a
|
|
146
|
+
# non-whitespace marker — the comment shapes ("//", "/*", ...).
|
|
147
|
+
# Whitespace rules stay unrecorded trivia.
|
|
148
|
+
def skip_capturer_markers
|
|
149
|
+
@skip_capturer_markers ||= begin
|
|
150
|
+
markers = {}
|
|
151
|
+
seen = {}
|
|
152
|
+
collect = lambda do |node|
|
|
153
|
+
case node.kind
|
|
154
|
+
when :ref
|
|
155
|
+
next if seen[node.a]
|
|
156
|
+
|
|
157
|
+
seen[node.a] = true
|
|
158
|
+
literal = leading_literal(node.a)
|
|
159
|
+
markers[literal] = node.a.to_sym if literal && !literal.strip.empty?
|
|
160
|
+
collect.call(@document.rules[node.a]) if @document.rules.key?(node.a)
|
|
161
|
+
when :alt, :seq then node.a.each { |b| collect.call(b) }
|
|
162
|
+
when :rep, :opt, :cap then collect.call(node.a)
|
|
163
|
+
when :pred then collect.call(node.b)
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
collect.call(@document.skip_declaration)
|
|
167
|
+
markers
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def leading_literal(rule_name)
|
|
172
|
+
node = @document.rules[rule_name]
|
|
173
|
+
return nil unless node
|
|
174
|
+
|
|
175
|
+
literal = nil
|
|
176
|
+
walk = lambda do |n|
|
|
177
|
+
break if literal
|
|
178
|
+
|
|
179
|
+
case n.kind
|
|
180
|
+
when :lit then literal = n.a
|
|
181
|
+
when :seq, :alt then n.a.each { |c| walk.call(c) unless literal }
|
|
182
|
+
when :rep, :opt, :cap, :pred then walk.call(n.a || n.b) unless literal
|
|
183
|
+
end
|
|
184
|
+
end
|
|
185
|
+
walk.call(node)
|
|
186
|
+
literal
|
|
187
|
+
end
|
|
188
|
+
|
|
144
189
|
def skip_wrapper?(atom)
|
|
145
190
|
@skip_wrapper_ids&.key?(atom)
|
|
146
191
|
end
|
|
@@ -163,7 +208,13 @@ module Parsanol
|
|
|
163
208
|
# span-joined captures — and failures inside it never surface
|
|
164
209
|
# in diagnostics (rendered trees and deepest-failure
|
|
165
210
|
# positions skip trivia causes).
|
|
166
|
-
|
|
211
|
+
inner = Atoms::Repetition.new(atom, 0, 1)
|
|
212
|
+
wrapper =
|
|
213
|
+
if @document.skip_capture_key
|
|
214
|
+
Atoms::TriviaCapture.new(inner, skip_capturer_markers)
|
|
215
|
+
else
|
|
216
|
+
Atoms::Trivia.new(inner)
|
|
217
|
+
end
|
|
167
218
|
(@skip_wrapper_ids ||= {}.compare_by_identity)[wrapper] = true
|
|
168
219
|
wrapper
|
|
169
220
|
end
|
|
@@ -10,7 +10,7 @@ module Parsanol
|
|
|
10
10
|
Test = Struct.new(:entry, :kind, :input, :expect)
|
|
11
11
|
|
|
12
12
|
attr_accessor :grammar_name, :version, :source, :uses, :skip_declaration, :skip_source,
|
|
13
|
-
:atomic_rules
|
|
13
|
+
:atomic_rules, :skip_capture_key
|
|
14
14
|
attr_reader :rules, :bindings, :preprocess, :entries, :docs, :tests, :render, :derive,
|
|
15
15
|
:customs, :states
|
|
16
16
|
# Entries authored in this file (pre-import); nil-entry tests resolve
|
data/lib/parsanol/parg/parser.rb
CHANGED
|
@@ -21,7 +21,7 @@ module Parsanol
|
|
|
21
21
|
STATE_KEYWORDS = %w[custom state].freeze
|
|
22
22
|
KEYWORDS = %w[grammar as alt from_table column bindings render derive
|
|
23
23
|
preprocess entry table_lookup custom state set switch
|
|
24
|
-
skip until atomic].freeze
|
|
24
|
+
skip until atomic capture].freeze
|
|
25
25
|
|
|
26
26
|
def initialize(text)
|
|
27
27
|
@tokens = Lexer.new(text).tokens
|
|
@@ -170,6 +170,15 @@ module Parsanol
|
|
|
170
170
|
end
|
|
171
171
|
|
|
172
172
|
node = parse_choice
|
|
173
|
+
# parsanol-ruby#152 phase 2: `skip = trivia capture:
|
|
174
|
+
# comments` attaches comment-shaped trivia (the rules the
|
|
175
|
+
# declaration references, identified by leading literal)
|
|
176
|
+
# to the next successful capture under `comments:`.
|
|
177
|
+
if peek&.type == :ident && peek.value == "capture"
|
|
178
|
+
advance
|
|
179
|
+
punct(":")
|
|
180
|
+
document.skip_capture_key = ident.value.to_sym
|
|
181
|
+
end
|
|
173
182
|
document.skip_declaration = validate_skip_node(node)
|
|
174
183
|
document.skip_source = skip_source_string(node)
|
|
175
184
|
skip_newlines
|
|
@@ -260,7 +269,12 @@ module Parsanol
|
|
|
260
269
|
|
|
261
270
|
def stop_element?
|
|
262
271
|
peek.nil? || peek.type == :newline ||
|
|
263
|
-
(peek.type == :punct && ["/", ")", "]", "}"].include?(peek.value))
|
|
272
|
+
(peek.type == :punct && ["/", ")", "]", "}"].include?(peek.value)) ||
|
|
273
|
+
# `capture:` suffix terminates the skip declaration's RHS
|
|
274
|
+
# (parsanol-ruby#152); everywhere else parse_element's guard
|
|
275
|
+
# rejects it.
|
|
276
|
+
(peek&.type == :ident && peek.value == "capture" &&
|
|
277
|
+
@tokens[@pos + 1]&.type == :punct && @tokens[@pos + 1]&.value == ":")
|
|
264
278
|
end
|
|
265
279
|
|
|
266
280
|
def parse_element
|
|
@@ -269,6 +283,13 @@ module Parsanol
|
|
|
269
283
|
raise ParseError, "unexpected end of input inside sequence"
|
|
270
284
|
end
|
|
271
285
|
|
|
286
|
+
# `capture:` is a skip-declaration suffix, never an expression
|
|
287
|
+
# element (reserved keyword; parsanol-ruby#152).
|
|
288
|
+
if token.type == :ident && token.value == "capture" &&
|
|
289
|
+
@tokens[@pos + 1]&.type == :punct && @tokens[@pos + 1]&.value == ":"
|
|
290
|
+
raise ParseError, "capture: only modifies the skip declaration"
|
|
291
|
+
end
|
|
292
|
+
|
|
272
293
|
if token.type == :num
|
|
273
294
|
advance
|
|
274
295
|
min = token.value.to_i
|
data/lib/parsanol/version.rb
CHANGED
data/lib/parsanol/vm.rb
CHANGED
|
@@ -649,6 +649,12 @@ module Parsanol
|
|
|
649
649
|
compile_entity(atom, consume_all)
|
|
650
650
|
when Parsanol::Atoms::Lookahead
|
|
651
651
|
compile_lookahead(atom, consume_all)
|
|
652
|
+
when Parsanol::Atoms::TriviaCapture
|
|
653
|
+
# Captured trivia records into the context channel at match
|
|
654
|
+
# time (parsanol-ruby#152); the bytecode program has no
|
|
655
|
+
# channel, so the interpreter (which does) must own the
|
|
656
|
+
# grammar. Declining here routes program_for to :fallback.
|
|
657
|
+
nil
|
|
652
658
|
when Parsanol::Atoms::Ignored
|
|
653
659
|
inner = atom.wrapped_atom
|
|
654
660
|
return nil if inner.nil?
|