parsanol 1.3.81-arm-linux → 1.3.83-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/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/sequence.rb +22 -11
- data/lib/parsanol/atoms/trivia.rb +13 -9
- data/lib/parsanol/native/libparsanol.so +0 -0
- data/lib/parsanol/native/serializer.rb +9 -5
- data/lib/parsanol/parser.rb +10 -2
- data/lib/parsanol/skip.rb +78 -45
- 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: 7f0e6c8c662ef00d3cf9b455a90f086e2dd6ee46639b9272eaa2be08b380abee
|
|
4
|
+
data.tar.gz: 4cb4b482bdb061e18de9d6e78445916a749ea926879c4cacf7fad7663acc90d5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cf4bb4cf4dca692026c4f90999de2d9cf79fab5a4135400099108954dcc9847d65c1ea05ac04c17ef74afb55732cb046fe8b98565251200fbe1aa5c60e3c69f9
|
|
7
|
+
data.tar.gz: 61d8a00dc1e15e1128c0ef624fac1073f6dfc23c774069eb661a6b0db6f828e4d447a38e112bcff9104526e19b7405c8b85711d2b228ebcd1b414574e19d77bf
|
|
@@ -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: 34008548 bytes
|
|
4
|
+
sha256: 3d9692b966fef81325ab09a430d755a70669b1bde6ec1e13ab8b15e6eb92dde9
|
|
@@ -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: 34193832 bytes
|
|
4
|
+
sha256: 316cbf3f2520113134750bc699742979580a901177be3ffcf74a736afc5f20d0
|
|
@@ -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: 34187972 bytes
|
|
4
|
+
sha256: 7f0d1e2437b36ffac4e98c7bc65b2b8b159758bc18101e7ef5cb340028287993
|
|
@@ -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: 34197704 bytes
|
|
4
|
+
sha256: 65f68a0f5e165622e51b676edefc6d404ed9cf1dce150e3e0d6fac152c7a9581
|
|
@@ -18,14 +18,25 @@ module Parsanol
|
|
|
18
18
|
def initialize(*components)
|
|
19
19
|
super()
|
|
20
20
|
@parslets = components
|
|
21
|
-
|
|
22
|
-
#
|
|
23
|
-
|
|
21
|
+
# The failure message renders LAZILY (error_msgs): constructing
|
|
22
|
+
# sequences is hot-path work for the builder/injector, and
|
|
23
|
+
# stringifying the whole subtree eagerly is exponential on
|
|
24
|
+
# shared cross-referencing grammars (parsanol-ruby#180 side
|
|
25
|
+
# observation: a 25-rule Fibonacci-shaped grammar took 6s).
|
|
26
|
+
@fail_msg = nil
|
|
24
27
|
end
|
|
25
28
|
|
|
26
29
|
# Error messages hash (for compatibility)
|
|
27
30
|
def error_msgs
|
|
28
|
-
{ failed:
|
|
31
|
+
{ failed: fail_msg }
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Rendered lazily (see initialize); construction is hot-path
|
|
35
|
+
# builder/injector work and stringifying the whole subtree
|
|
36
|
+
# eagerly is exponential on shared cross-referencing grammars
|
|
37
|
+
# (parsanol-ruby#180 side observation).
|
|
38
|
+
def fail_msg
|
|
39
|
+
@fail_msg ||= "Failed to match sequence (#{inspect})"
|
|
29
40
|
end
|
|
30
41
|
|
|
31
42
|
# Appends a parser to this sequence with flattening.
|
|
@@ -104,7 +115,7 @@ module Parsanol
|
|
|
104
115
|
# Single element sequence
|
|
105
116
|
def match_single(parser, source, context, consume_all)
|
|
106
117
|
success, value = parser.apply(source, context, consume_all)
|
|
107
|
-
return context.err(self, source,
|
|
118
|
+
return context.err(self, source, fail_msg, [value]) unless success
|
|
108
119
|
|
|
109
120
|
ok([:sequence, value])
|
|
110
121
|
end
|
|
@@ -112,10 +123,10 @@ module Parsanol
|
|
|
112
123
|
# Two-element sequence
|
|
113
124
|
def match_pair(p1, p2, source, context, consume_all)
|
|
114
125
|
success, v1 = p1.apply(source, context, false)
|
|
115
|
-
return context.err(self, source,
|
|
126
|
+
return context.err(self, source, fail_msg, [v1]) unless success
|
|
116
127
|
|
|
117
128
|
success, v2 = p2.apply(source, context, consume_all)
|
|
118
|
-
return context.err(self, source,
|
|
129
|
+
return context.err(self, source, fail_msg, [v2]) unless success
|
|
119
130
|
|
|
120
131
|
ok([:sequence, v1, v2])
|
|
121
132
|
end
|
|
@@ -123,13 +134,13 @@ module Parsanol
|
|
|
123
134
|
# Three-element sequence
|
|
124
135
|
def match_triple(p1, p2, p3, source, context, consume_all)
|
|
125
136
|
success, v1 = p1.apply(source, context, false)
|
|
126
|
-
return context.err(self, source,
|
|
137
|
+
return context.err(self, source, fail_msg, [v1]) unless success
|
|
127
138
|
|
|
128
139
|
success, v2 = p2.apply(source, context, false)
|
|
129
|
-
return context.err(self, source,
|
|
140
|
+
return context.err(self, source, fail_msg, [v2]) unless success
|
|
130
141
|
|
|
131
142
|
success, v3 = p3.apply(source, context, consume_all)
|
|
132
|
-
return context.err(self, source,
|
|
143
|
+
return context.err(self, source, fail_msg, [v3]) unless success
|
|
133
144
|
|
|
134
145
|
ok([:sequence, v1, v2, v3])
|
|
135
146
|
end
|
|
@@ -148,7 +159,7 @@ module Parsanol
|
|
|
148
159
|
success, value = components[idx].apply(source, context, must_consume)
|
|
149
160
|
|
|
150
161
|
unless success
|
|
151
|
-
return context.err(self, source,
|
|
162
|
+
return context.err(self, source, fail_msg, [value])
|
|
152
163
|
end
|
|
153
164
|
|
|
154
165
|
result[idx + 1] = value
|
|
@@ -28,12 +28,16 @@ module Parsanol
|
|
|
28
28
|
# +capturers+ maps leading-literal marker -> kind label (the
|
|
29
29
|
# compiler derives markers from each capturer rule's first Str
|
|
30
30
|
# atom, e.g. "//" => :line_comment); units not matching any
|
|
31
|
-
# marker are whitespace-shaped and stay unrecorded
|
|
32
|
-
|
|
31
|
+
# marker are whitespace-shaped and stay unrecorded — unless
|
|
32
|
+
# +whitespace_kind+ is declared (parsanol-ruby#180): every
|
|
33
|
+
# unit then records under that label, giving source-preserving
|
|
34
|
+
# grammars the full ordered trivia stream.
|
|
35
|
+
attr_reader :capturers, :whitespace_kind
|
|
33
36
|
|
|
34
|
-
def initialize(atom, capturers)
|
|
37
|
+
def initialize(atom, capturers, whitespace_kind: nil)
|
|
35
38
|
super(atom)
|
|
36
39
|
@capturers = capturers
|
|
40
|
+
@whitespace_kind = whitespace_kind
|
|
37
41
|
end
|
|
38
42
|
|
|
39
43
|
def apply(source, context, consume_all)
|
|
@@ -55,16 +59,16 @@ module Parsanol
|
|
|
55
59
|
private
|
|
56
60
|
|
|
57
61
|
def record(source, context, start_pos, end_pos)
|
|
58
|
-
return unless @capturers
|
|
59
|
-
|
|
60
62
|
text = source.input[start_pos...end_pos]
|
|
61
63
|
# A trivia unit may lead with whitespace before the comment
|
|
62
64
|
# shape; markers test the comment head.
|
|
63
65
|
stripped = text.lstrip
|
|
64
|
-
marker, label = @capturers
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
marker, label = @capturers&.find { |m, _label| stripped.start_with?(m) }
|
|
67
|
+
if marker
|
|
68
|
+
context.push_captured_trivia(label, stripped.strip)
|
|
69
|
+
elsif @whitespace_kind
|
|
70
|
+
context.push_captured_trivia(@whitespace_kind, text)
|
|
71
|
+
end
|
|
68
72
|
end
|
|
69
73
|
end
|
|
70
74
|
end
|
|
Binary file
|
|
@@ -332,12 +332,16 @@ module Parsanol
|
|
|
332
332
|
|
|
333
333
|
def serialize_trivia_capture(atom)
|
|
334
334
|
inner_id = serialize_atom(atom.wrapped_atom)
|
|
335
|
-
{
|
|
336
|
-
"
|
|
337
|
-
|
|
338
|
-
"rules" => atom.capturers.map { |marker, label| [marker, label.to_s] },
|
|
339
|
-
},
|
|
335
|
+
payload = {
|
|
336
|
+
"atom" => inner_id,
|
|
337
|
+
"rules" => atom.capturers.map { |marker, label| [marker, label.to_s] },
|
|
340
338
|
}
|
|
339
|
+
# parsanol-ruby#180: the optional whitespace kind — units that
|
|
340
|
+
# match no marker record under it (source-preserving grammars).
|
|
341
|
+
# Optional on the wire: engines predating it deserialize and
|
|
342
|
+
# simply don't record whitespace units (documented caveat).
|
|
343
|
+
payload["whitespace"] = atom.whitespace_kind.to_s if atom.whitespace_kind
|
|
344
|
+
{ "TriviaCapture" => payload }
|
|
341
345
|
end
|
|
342
346
|
|
|
343
347
|
def serialize_trivia(atom)
|
data/lib/parsanol/parser.rb
CHANGED
|
@@ -54,7 +54,8 @@ module Parsanol
|
|
|
54
54
|
skip_name = self.class.skip_rule_name
|
|
55
55
|
if skip_name
|
|
56
56
|
Parsanol::Skip.inject(self, atom, skip_name,
|
|
57
|
-
captures: self.class.skip_captures
|
|
57
|
+
captures: self.class.skip_captures,
|
|
58
|
+
whitespace: self.class.skip_whitespace)[0]
|
|
58
59
|
else
|
|
59
60
|
atom
|
|
60
61
|
end
|
|
@@ -89,9 +90,10 @@ module Parsanol
|
|
|
89
90
|
# rule(:line_comment) { str("//") >> match(/[^\n]/).repeat }
|
|
90
91
|
# skip :trivia, capture: { line_comment: :line_comment }
|
|
91
92
|
#
|
|
92
|
-
def skip(rule_name, capture: nil)
|
|
93
|
+
def skip(rule_name, capture: nil, whitespace: nil)
|
|
93
94
|
@skip_rule_name = rule_name
|
|
94
95
|
@skip_captures = capture
|
|
96
|
+
@skip_whitespace = whitespace
|
|
95
97
|
nil
|
|
96
98
|
end
|
|
97
99
|
|
|
@@ -106,6 +108,12 @@ module Parsanol
|
|
|
106
108
|
def skip_captures
|
|
107
109
|
@skip_captures
|
|
108
110
|
end
|
|
111
|
+
|
|
112
|
+
# The declared whitespace kind (units matching no capturer
|
|
113
|
+
# record under it), or nil — see {.skip}.
|
|
114
|
+
def skip_whitespace
|
|
115
|
+
@skip_whitespace
|
|
116
|
+
end
|
|
109
117
|
end
|
|
110
118
|
|
|
111
119
|
# Delegates matching to the root rule.
|
data/lib/parsanol/skip.rb
CHANGED
|
@@ -20,7 +20,8 @@ module Parsanol
|
|
|
20
20
|
# capturer's leading literal attach to the next Named capture
|
|
21
21
|
# under `comments:` — the PARG `skip = trivia capture: comments`
|
|
22
22
|
# shape. Whitespace-shaped units never record.
|
|
23
|
-
def self.inject(parser_instance, root_atom, skip_rule_name, captures: nil
|
|
23
|
+
def self.inject(parser_instance, root_atom, skip_rule_name, captures: nil,
|
|
24
|
+
whitespace: nil)
|
|
24
25
|
skip_atom = parser_instance.__send__(skip_rule_name)
|
|
25
26
|
skip_atom = skip_atom.parslet while skip_atom.is_a?(Atoms::Entity)
|
|
26
27
|
|
|
@@ -31,7 +32,8 @@ module Parsanol
|
|
|
31
32
|
end
|
|
32
33
|
|
|
33
34
|
markers = capturer_markers(parser_instance, captures)
|
|
34
|
-
|
|
35
|
+
whitespace_kind = whitespace&.to_sym
|
|
36
|
+
injector = Injector.new(skip_atom, markers, whitespace_kind)
|
|
35
37
|
[injector.inject(root_atom, entry: true), skip_atom]
|
|
36
38
|
end
|
|
37
39
|
|
|
@@ -92,15 +94,28 @@ module Parsanol
|
|
|
92
94
|
# clean — the wrapper is Trivia: Ignored + diagnostics
|
|
93
95
|
# transparency), bare terminals gain a leading wrapper, and the
|
|
94
96
|
# entry root takes leading and trailing wrappers.
|
|
97
|
+
# The walk is a pure function of the atom subtree, so results are
|
|
98
|
+
# memoized: dense cross-referencing grammars (expressir's ~250
|
|
99
|
+
# rules) revisit shared subtrees once per referencing path, which
|
|
100
|
+
# made the path-scoped visited-set exponential — a 25-rule
|
|
101
|
+
# Fibonacci-shaped grammar took 6.2s to build (parsanol-ruby#180
|
|
102
|
+
# side observation). In-progress atoms mark a cycle re-entry and
|
|
103
|
+
# return raw, exactly as the path-scoped set did.
|
|
95
104
|
class Injector
|
|
96
|
-
def initialize(skip_atom, markers = nil)
|
|
105
|
+
def initialize(skip_atom, markers = nil, whitespace_kind = nil)
|
|
97
106
|
@skip_atom = skip_atom
|
|
98
107
|
@markers = markers
|
|
108
|
+
@whitespace_kind = whitespace_kind
|
|
99
109
|
@wrapper_ids = {}.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 }
|
|
100
115
|
end
|
|
101
116
|
|
|
102
117
|
def inject(atom, entry: false)
|
|
103
|
-
injected = walk(atom,
|
|
118
|
+
injected = walk(atom, false)
|
|
104
119
|
return injected unless entry
|
|
105
120
|
|
|
106
121
|
Atoms::Sequence.new(maybe, injected, maybe)
|
|
@@ -112,8 +127,9 @@ module Parsanol
|
|
|
112
127
|
@maybe ||= begin
|
|
113
128
|
inner = Atoms::Repetition.new(@skip_atom, 0, 1)
|
|
114
129
|
wrapper =
|
|
115
|
-
if @markers
|
|
116
|
-
Atoms::TriviaCapture.new(inner, @markers
|
|
130
|
+
if @markers || @whitespace_kind
|
|
131
|
+
Atoms::TriviaCapture.new(inner, @markers,
|
|
132
|
+
whitespace_kind: @whitespace_kind)
|
|
117
133
|
else
|
|
118
134
|
Atoms::Trivia.new(inner)
|
|
119
135
|
end
|
|
@@ -126,50 +142,67 @@ module Parsanol
|
|
|
126
142
|
@wrapper_ids.key?(atom)
|
|
127
143
|
end
|
|
128
144
|
|
|
129
|
-
|
|
130
|
-
|
|
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]
|
|
154
|
+
return cached if cached
|
|
155
|
+
return atom if @in_progress[rep_interior].key?(atom)
|
|
131
156
|
return atom if atom.equal?(@skip_atom)
|
|
132
157
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
atom
|
|
158
|
+
@in_progress[rep_interior][atom] = true
|
|
159
|
+
injected =
|
|
160
|
+
case atom
|
|
161
|
+
when Atoms::Sequence
|
|
162
|
+
out = []
|
|
163
|
+
atom.parslets.each do |child|
|
|
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
|
|
169
|
+
end
|
|
170
|
+
out.length == 1 ? out.first : Atoms::Sequence.new(*out)
|
|
171
|
+
when Atoms::Alternative
|
|
172
|
+
Atoms::Alternative.new(*atom.alternatives.map { |a| walk(a, rep_interior) })
|
|
173
|
+
when Atoms::Repetition
|
|
174
|
+
if wrapper?(atom)
|
|
175
|
+
atom
|
|
176
|
+
else
|
|
177
|
+
Atoms::Repetition.new(walk(atom.parslet, true), atom.min, atom.max,
|
|
178
|
+
atom.result_tag)
|
|
179
|
+
end
|
|
180
|
+
when Atoms::Named
|
|
181
|
+
Atoms::Named.new(walk(atom.parslet, rep_interior), atom.name)
|
|
182
|
+
when Atoms::Lookahead
|
|
183
|
+
Atoms::Lookahead.new(walk(atom.bound_parslet, rep_interior), atom.positive)
|
|
184
|
+
when Atoms::Ignored
|
|
185
|
+
Atoms::Ignored.new(walk(atom.wrapped_atom, rep_interior))
|
|
186
|
+
when Atoms::Entity
|
|
187
|
+
# Rule bodies own their injection when the grammar declares
|
|
188
|
+
# skip on every rule (PARG); in the DSL surface the root tree
|
|
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.
|
|
193
|
+
begin
|
|
194
|
+
walk(atom.parslet, false)
|
|
195
|
+
rescue StandardError
|
|
196
|
+
atom
|
|
197
|
+
end
|
|
198
|
+
when Atoms::Str, Atoms::Re
|
|
199
|
+
rep_interior ? atom : Atoms::Sequence.new(maybe, atom)
|
|
148
200
|
else
|
|
149
|
-
Atoms::Repetition.new(walk(atom.parslet, visited), atom.min, atom.max,
|
|
150
|
-
atom.result_tag)
|
|
151
|
-
end
|
|
152
|
-
when Atoms::Named
|
|
153
|
-
Atoms::Named.new(walk(atom.parslet, visited), atom.name)
|
|
154
|
-
when Atoms::Lookahead
|
|
155
|
-
Atoms::Lookahead.new(walk(atom.bound_parslet, visited), atom.positive)
|
|
156
|
-
when Atoms::Ignored
|
|
157
|
-
Atoms::Ignored.new(walk(atom.wrapped_atom, visited))
|
|
158
|
-
when Atoms::Entity
|
|
159
|
-
# Rule bodies own their injection when the grammar declares
|
|
160
|
-
# skip on every rule (PARG); in the DSL surface the root tree
|
|
161
|
-
# is walked once, so descend through resolved bodies with the
|
|
162
|
-
# identity visited-set guarding recursion.
|
|
163
|
-
begin
|
|
164
|
-
walk(atom.parslet, visited)
|
|
165
|
-
rescue StandardError
|
|
166
201
|
atom
|
|
167
202
|
end
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
atom
|
|
172
|
-
end
|
|
203
|
+
@in_progress[rep_interior].delete(atom)
|
|
204
|
+
@memo[rep_interior][atom] = injected
|
|
205
|
+
injected
|
|
173
206
|
end
|
|
174
207
|
end
|
|
175
208
|
end
|
data/lib/parsanol/version.rb
CHANGED