parsanol 1.3.123 → 1.3.125
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/parg/artifact.rb +15 -0
- data/lib/parsanol/parg/document.rb +2 -2
- data/lib/parsanol/version.rb +1 -1
- data/lib/parsanol/vm.rb +15 -6
- 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: 9300ad7831ee208e1424f8a65c035db1db73f335bedfa2e3cb77027e7ae048ba
|
|
4
|
+
data.tar.gz: ec7e0cc9a73e967e957eba039f52b66e80c63cf53ca4048e69c6303b2d09f23b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c57b6923afc7be098b06844fd17fc42957c84ca7829363b8ce90fc04947c64ff7d30d16acef7aa8352f15c2b0b6f406095b6c97acd4aed4806057d4e96c31bf7
|
|
7
|
+
data.tar.gz: 200c2f64e60befe15181fbb92735d65428f02e3c01245fc66732da1e38083dfdc5143968d5b86f8d3957d4572c42a74af114eea7e0ce9917abe9379885a43aa9
|
|
@@ -241,6 +241,7 @@ module Parsanol
|
|
|
241
241
|
end
|
|
242
242
|
"test #{hash['input'].inspect}: expected captures " \
|
|
243
243
|
"#{mismatched.transform_values(&:inspect).inspect}, got #{actuals.inspect}"
|
|
244
|
+
when "bind" then bind_mismatch(entry_name, shape, hash)
|
|
244
245
|
end
|
|
245
246
|
rescue Parsanol::ParseFailed
|
|
246
247
|
unless hash["kind"] == "reject"
|
|
@@ -250,6 +251,20 @@ module Parsanol
|
|
|
250
251
|
end
|
|
251
252
|
end
|
|
252
253
|
|
|
254
|
+
# parsanol-ruby#414: the whole bound map must equal the expectation
|
|
255
|
+
# exactly (not the partial `example` match) — the grammar author
|
|
256
|
+
# pins what the bindings produce, including absent keys and
|
|
257
|
+
# phantom rows.
|
|
258
|
+
def bind_mismatch(entry_name, shape, hash)
|
|
259
|
+
bound = apply_bindings(entry_name, shape)
|
|
260
|
+
actual = Bindings.canonical(bound)
|
|
261
|
+
expected = Bindings.canonical(hash["expect"])
|
|
262
|
+
return nil if actual == expected
|
|
263
|
+
|
|
264
|
+
"test #{hash['input'].inspect}: expected bound #{expected.inspect}, " \
|
|
265
|
+
"got #{actual.inspect}"
|
|
266
|
+
end
|
|
267
|
+
|
|
253
268
|
# Best-effort recovery (TODO.sota/1, R1): on success returns
|
|
254
269
|
# {"ok": true, "shape": tree}; on ParseFailed returns
|
|
255
270
|
# {"ok": false, "error": {"offset", "message"}, "captures":
|
|
@@ -11,9 +11,9 @@ module Parsanol
|
|
|
11
11
|
# `capture` = phase 1 (grammar layer): asserts the raw capture tree,
|
|
12
12
|
# no bindings section needed. `example` = phase 2 (bindings layer):
|
|
13
13
|
# asserts the bound, preprocessed attribute hash.
|
|
14
|
-
TEST_KINDS = %i[accept reject example capture shape].freeze
|
|
14
|
+
TEST_KINDS = %i[accept reject example capture shape bind].freeze
|
|
15
15
|
# Test kinds whose expectations are `{ key: value }` pairs.
|
|
16
|
-
PAIR_KINDS = %w[example capture].freeze
|
|
16
|
+
PAIR_KINDS = %w[example capture bind].freeze
|
|
17
17
|
|
|
18
18
|
Test = Struct.new(:entry, :kind, :input, :expect)
|
|
19
19
|
|
data/lib/parsanol/version.rb
CHANGED
data/lib/parsanol/vm.rb
CHANGED
|
@@ -990,8 +990,12 @@ module Parsanol
|
|
|
990
990
|
@memoize = memoize
|
|
991
991
|
end
|
|
992
992
|
|
|
993
|
-
# The RE match's [
|
|
994
|
-
#
|
|
993
|
+
# The RE match's [span length, byte advance], both in BYTES: the
|
|
994
|
+
# interpreter's packed value spans are byte-based (STR packs the
|
|
995
|
+
# literal's byte length; ANY and the RUN ops pack the char's
|
|
996
|
+
# UTF-8 byte width; materialize byteslices the span), so the RE
|
|
997
|
+
# span must count bytes too. Single-class patterns match one
|
|
998
|
+
# character (its byte width); multi-character patterns (%i
|
|
995
999
|
# literals reach RE with no byte table) consume their full
|
|
996
1000
|
# length (ruby#357: advancing one character skipped the
|
|
997
1001
|
# pattern's remainder and let the parse re-match inside it).
|
|
@@ -1002,12 +1006,17 @@ module Parsanol
|
|
|
1002
1006
|
[w, w]
|
|
1003
1007
|
else
|
|
1004
1008
|
len = scanner.skip(pattern)
|
|
1005
|
-
[
|
|
1009
|
+
[len, len]
|
|
1006
1010
|
end
|
|
1007
1011
|
end
|
|
1008
1012
|
|
|
1009
|
-
# An RE instruction's match at pos: [matched?,
|
|
1010
|
-
# advance]
|
|
1013
|
+
# An RE instruction's match at pos: [matched?, span length, byte
|
|
1014
|
+
# advance], both lengths in BYTES (see #re_match_width: the
|
|
1015
|
+
# interpreter's spans are byte-based; a character count here
|
|
1016
|
+
# truncated every slice containing a multibyte character —
|
|
1017
|
+
# ruby#407: "Class[éin]" lost é's second continuation byte
|
|
1018
|
+
# because the span stored the run's char count and materialize
|
|
1019
|
+
# bytesliced it). Single-class patterns match one character;
|
|
1011
1020
|
# multi-character patterns (%i literals reach RE with no byte
|
|
1012
1021
|
# table) consume their FULL length (ruby#357: advancing one
|
|
1013
1022
|
# character skipped the pattern's remainder and let the parse
|
|
@@ -1030,7 +1039,7 @@ module Parsanol
|
|
|
1030
1039
|
[true, w, w]
|
|
1031
1040
|
else
|
|
1032
1041
|
len = scanner.skip(pattern)
|
|
1033
|
-
[true,
|
|
1042
|
+
[true, len, len]
|
|
1034
1043
|
end
|
|
1035
1044
|
end
|
|
1036
1045
|
|