yeptris 0.6.18.2-arm-linux-eabihf
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 +7 -0
- data/README.adoc +141 -0
- data/ext/build_windows_native.rb +41 -0
- data/ext/libyeptris/extconf.rb +57 -0
- data/ext/yeptris_native/cbor_ruby.c +193 -0
- data/ext/yeptris_native/extconf.rb +47 -0
- data/ext/yeptris_native/json_ruby.c +354 -0
- data/ext/yeptris_native/yeptris_native.c +497 -0
- data/lib/yeptris/cbor.rb +130 -0
- data/lib/yeptris/document.rb +255 -0
- data/lib/yeptris/ffi.rb +426 -0
- data/lib/yeptris/json/descriptor.rb +266 -0
- data/lib/yeptris/json.rb +394 -0
- data/lib/yeptris/materializer.rb +354 -0
- data/lib/yeptris/native-3.4.so +0 -0
- data/lib/yeptris/node.rb +453 -0
- data/lib/yeptris/psych/class_loader.rb +24 -0
- data/lib/yeptris/psych/coder_shim.rb +55 -0
- data/lib/yeptris/psych/drop_in.rb +63 -0
- data/lib/yeptris/psych/encodable.rb +14 -0
- data/lib/yeptris/psych/handler.rb +90 -0
- data/lib/yeptris/psych/parser.rb +105 -0
- data/lib/yeptris/psych/scalar_scanner.rb +149 -0
- data/lib/yeptris/psych/visitors.rb +545 -0
- data/lib/yeptris/psych.rb +622 -0
- data/lib/yeptris/schema.rb +253 -0
- data/lib/yeptris/valueml.rb +455 -0
- data/lib/yeptris/yaml/descriptor.rb +56 -0
- data/lib/yeptris/yaml.rb +422 -0
- data/lib/yeptris.rb +113 -0
- data/libyeptris.so +0 -0
- data/vendor/libyeptris/CMakeLists.txt +254 -0
- data/vendor/libyeptris/cmake/yeptris-config.cmake.in +5 -0
- data/vendor/libyeptris/cmake/yeptris.pc.in +11 -0
- data/vendor/libyeptris/src/CMakeLists.txt +167 -0
- data/vendor/libyeptris/src/include/yeptris/api.h +32 -0
- data/vendor/libyeptris/src/include/yeptris/cbor.h +101 -0
- data/vendor/libyeptris/src/include/yeptris/dom.h +190 -0
- data/vendor/libyeptris/src/include/yeptris/emit.h +81 -0
- data/vendor/libyeptris/src/include/yeptris/error.h +41 -0
- data/vendor/libyeptris/src/include/yeptris/events.h +157 -0
- data/vendor/libyeptris/src/include/yeptris/json.h +45 -0
- data/vendor/libyeptris/src/include/yeptris/json.hpp +258 -0
- data/vendor/libyeptris/src/include/yeptris/jsonc_compat.h +115 -0
- data/vendor/libyeptris/src/include/yeptris/marshal.h +52 -0
- data/vendor/libyeptris/src/include/yeptris/parse.h +48 -0
- data/vendor/libyeptris/src/include/yeptris/plan.h +100 -0
- data/vendor/libyeptris/src/include/yeptris/resolve.h +71 -0
- data/vendor/libyeptris/src/include/yeptris/schema.h +121 -0
- data/vendor/libyeptris/src/include/yeptris/tape.h +123 -0
- data/vendor/libyeptris/src/include/yeptris/types.h +38 -0
- data/vendor/libyeptris/src/include/yeptris/values.h +102 -0
- data/vendor/libyeptris/src/include/yeptris/version.h.in +29 -0
- data/vendor/libyeptris/src/include/yeptris/visit.h +77 -0
- data/vendor/libyeptris/src/include/yeptris/yajl_compat.h +135 -0
- data/vendor/libyeptris/src/include/yeptris.h +23 -0
- data/vendor/libyeptris/src/yeptris/build.c +376 -0
- data/vendor/libyeptris/src/yeptris/cbor/cbor.h +25 -0
- data/vendor/libyeptris/src/yeptris/cbor/decode.c +981 -0
- data/vendor/libyeptris/src/yeptris/cbor/encode.c +835 -0
- data/vendor/libyeptris/src/yeptris/cbor/sink.h +58 -0
- data/vendor/libyeptris/src/yeptris/common/chartype.c +41 -0
- data/vendor/libyeptris/src/yeptris/common/chartype.h +77 -0
- data/vendor/libyeptris/src/yeptris/common/cpu.c +81 -0
- data/vendor/libyeptris/src/yeptris/common/cpu.h +40 -0
- data/vendor/libyeptris/src/yeptris/common/error.c +65 -0
- data/vendor/libyeptris/src/yeptris/common/error.h +79 -0
- data/vendor/libyeptris/src/yeptris/common/mutex.h +45 -0
- data/vendor/libyeptris/src/yeptris/common/nametab.c +275 -0
- data/vendor/libyeptris/src/yeptris/common/nametab.h +68 -0
- data/vendor/libyeptris/src/yeptris/common/port.h +74 -0
- data/vendor/libyeptris/src/yeptris/common/simd_text.c +49 -0
- data/vendor/libyeptris/src/yeptris/common/simd_text.h +295 -0
- data/vendor/libyeptris/src/yeptris/common/simd_text_avx2.c +534 -0
- data/vendor/libyeptris/src/yeptris/common/simd_text_neon.c +662 -0
- data/vendor/libyeptris/src/yeptris/common/simd_text_scalar.c +298 -0
- data/vendor/libyeptris/src/yeptris/common/string_view.c +34 -0
- data/vendor/libyeptris/src/yeptris/common/string_view.h +93 -0
- data/vendor/libyeptris/src/yeptris/doc.h +56 -0
- data/vendor/libyeptris/src/yeptris/dom/dom.c +1192 -0
- data/vendor/libyeptris/src/yeptris/dom/dom.h +312 -0
- data/vendor/libyeptris/src/yeptris/dom/hpool.c +107 -0
- data/vendor/libyeptris/src/yeptris/dom/mapindex.c +173 -0
- data/vendor/libyeptris/src/yeptris/dom/mapindex.h +61 -0
- data/vendor/libyeptris/src/yeptris/dom/mutate.c +431 -0
- data/vendor/libyeptris/src/yeptris/emit/emit.c +434 -0
- data/vendor/libyeptris/src/yeptris/emit/float/api.h +38 -0
- data/vendor/libyeptris/src/yeptris/emit/float/dragon.c +405 -0
- data/vendor/libyeptris/src/yeptris/emit/float/floatint.h +231 -0
- data/vendor/libyeptris/src/yeptris/emit/float/print.c +396 -0
- data/vendor/libyeptris/src/yeptris/emit/style.c +81 -0
- data/vendor/libyeptris/src/yeptris/emit/style.h +24 -0
- data/vendor/libyeptris/src/yeptris/emit/writer.c +816 -0
- data/vendor/libyeptris/src/yeptris/emit/writer.h +76 -0
- data/vendor/libyeptris/src/yeptris/encoding/bom.c +31 -0
- data/vendor/libyeptris/src/yeptris/encoding/encoding.h +63 -0
- data/vendor/libyeptris/src/yeptris/encoding/transcode.c +148 -0
- data/vendor/libyeptris/src/yeptris/encoding/utf8_validate.c +178 -0
- data/vendor/libyeptris/src/yeptris/events/capture.c +150 -0
- data/vendor/libyeptris/src/yeptris/events/capture.h +39 -0
- data/vendor/libyeptris/src/yeptris/events/iterparse.c +208 -0
- data/vendor/libyeptris/src/yeptris/events/pull.c +97 -0
- data/vendor/libyeptris/src/yeptris/events/push.c +104 -0
- data/vendor/libyeptris/src/yeptris/events/recorder.c +107 -0
- data/vendor/libyeptris/src/yeptris/events/values.c +527 -0
- data/vendor/libyeptris/src/yeptris/events/values_priv.h +51 -0
- data/vendor/libyeptris/src/yeptris/events/yaml_compat.c +86 -0
- data/vendor/libyeptris/src/yeptris/events/yaml_compat.h +90 -0
- data/vendor/libyeptris/src/yeptris/jsonapi/jsonc_compat.c +687 -0
- data/vendor/libyeptris/src/yeptris/jsonapi/yajl_compat.c +728 -0
- data/vendor/libyeptris/src/yeptris/marshal.c +782 -0
- data/vendor/libyeptris/src/yeptris/memory/allocator.c +20 -0
- data/vendor/libyeptris/src/yeptris/memory/allocator.h +43 -0
- data/vendor/libyeptris/src/yeptris/memory/arena.c +134 -0
- data/vendor/libyeptris/src/yeptris/memory/arena.h +52 -0
- data/vendor/libyeptris/src/yeptris/memory/pool.c +122 -0
- data/vendor/libyeptris/src/yeptris/memory/pool.h +36 -0
- data/vendor/libyeptris/src/yeptris/parse/engine.c +3698 -0
- data/vendor/libyeptris/src/yeptris/parse/engine.h +65 -0
- data/vendor/libyeptris/src/yeptris/parse/events.h +124 -0
- data/vendor/libyeptris/src/yeptris/parse/numbers.c +349 -0
- data/vendor/libyeptris/src/yeptris/parse/numbers.h +33 -0
- data/vendor/libyeptris/src/yeptris/parse/scalars.c +416 -0
- data/vendor/libyeptris/src/yeptris/parse/scalars.h +75 -0
- data/vendor/libyeptris/src/yeptris/parse.c +737 -0
- data/vendor/libyeptris/src/yeptris/plan.c +824 -0
- data/vendor/libyeptris/src/yeptris/resolve/compat11.c +334 -0
- data/vendor/libyeptris/src/yeptris/resolve/core12.c +143 -0
- data/vendor/libyeptris/src/yeptris/resolve/resolver.h +56 -0
- data/vendor/libyeptris/src/yeptris/resolve/tags.c +58 -0
- data/vendor/libyeptris/src/yeptris/scan/json.c +792 -0
- data/vendor/libyeptris/src/yeptris/scan/json.h +109 -0
- data/vendor/libyeptris/src/yeptris/scan/scan.c +463 -0
- data/vendor/libyeptris/src/yeptris/scan/scan.h +150 -0
- data/vendor/libyeptris/src/yeptris/schema.c +308 -0
- data/vendor/libyeptris/src/yeptris/tape.c +1308 -0
- data/vendor/libyeptris/src/yeptris/tape_in.h +19 -0
- data/vendor/libyeptris/src/yeptris/version.c +7 -0
- data/vendor/libyeptris/src/yeptris/visit/dom_visit.c +115 -0
- data/vendor/libyeptris/src/yeptris/visit/json_visit.c +293 -0
- data/vendor/libyeptris/src/yeptris/visit/yaml_visit.c +127 -0
- metadata +199 -0
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "date"
|
|
4
|
+
require "time"
|
|
5
|
+
|
|
6
|
+
module Yeptris
|
|
7
|
+
# Recorder-driven Ruby materialization (TODO.impl/15 phase B).
|
|
8
|
+
#
|
|
9
|
+
# One bulk drain: the record array and string arena are read in two
|
|
10
|
+
# calls, then a pure-Ruby stack machine walks fixed-layout records —
|
|
11
|
+
# the FFI tax is O(chunks), never O(events). The DOM-walk
|
|
12
|
+
# materializer (Node#to_ruby) stays for node-based use; this is the
|
|
13
|
+
# Yeptris::YAML fast path.
|
|
14
|
+
class Materializer
|
|
15
|
+
RECORD_SIZE = 36 # YeptrisEventRecord layout (events.h, ABI-pinned)
|
|
16
|
+
FIELDS = 12 # unpacked values per record
|
|
17
|
+
RECORD_UNPACK = "C4V8" # type/style/flags/tag_id, line..tag_len
|
|
18
|
+
|
|
19
|
+
STREAM_START = 1
|
|
20
|
+
STREAM_END = 2
|
|
21
|
+
DOCUMENT_START = 3
|
|
22
|
+
DOCUMENT_END = 4
|
|
23
|
+
SEQUENCE_START = 5
|
|
24
|
+
SEQUENCE_END = 6
|
|
25
|
+
MAPPING_START = 7
|
|
26
|
+
MAPPING_END = 8
|
|
27
|
+
SCALAR = 9
|
|
28
|
+
ALIAS = 10
|
|
29
|
+
|
|
30
|
+
EF_IMPLICIT = 1 << 2
|
|
31
|
+
STYLE_PLAIN = 1
|
|
32
|
+
|
|
33
|
+
# YeptrisTagId values (resolve.h; FFI mirrors them)
|
|
34
|
+
TAG_STR = Yeptris::FFI::TAG_STR
|
|
35
|
+
TAG_INT = Yeptris::FFI::TAG_INT
|
|
36
|
+
TAG_FLOAT = Yeptris::FFI::TAG_FLOAT
|
|
37
|
+
TAG_BOOL = Yeptris::FFI::TAG_BOOL
|
|
38
|
+
TAG_NULL = Yeptris::FFI::TAG_NULL
|
|
39
|
+
TAG_TIMESTAMP = Yeptris::FFI::TAG_TIMESTAMP
|
|
40
|
+
TAG_BINARY = Yeptris::FFI::TAG_BINARY
|
|
41
|
+
TAG_MERGE = 9 # YEPTRIS_TAG_MERGE (resolve.h): a plain '<<' key
|
|
42
|
+
|
|
43
|
+
INF_WORDS = {
|
|
44
|
+
".inf" => Float::INFINITY, ".Inf" => Float::INFINITY, ".INF" => Float::INFINITY,
|
|
45
|
+
"+.inf" => Float::INFINITY, "+.Inf" => Float::INFINITY, "+.INF" => Float::INFINITY,
|
|
46
|
+
"-.inf" => -Float::INFINITY, "-.Inf" => -Float::INFINITY, "-.INF" => -Float::INFINITY,
|
|
47
|
+
".nan" => Float::NAN, ".NaN" => Float::NAN, ".NAN" => Float::NAN,
|
|
48
|
+
}.freeze
|
|
49
|
+
SEXAGESIMAL_INT = /\A[-+]?[1-9][0-9_]*(:[0-5]?[0-9])+\z/
|
|
50
|
+
SEXAGESIMAL_FLOAT = /\A[-+]?[0-9][0-9_]*(:[0-5]?[0-9])+:[0-5]?[0-9]\.[0-9_]*\z/
|
|
51
|
+
|
|
52
|
+
class << self
|
|
53
|
+
# First document of the stream, or nil when the stream is empty.
|
|
54
|
+
def load(yaml, schema: :compat_11)
|
|
55
|
+
docs = load_stream(yaml, schema: schema)
|
|
56
|
+
docs.empty? ? nil : docs.first
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Every document in the stream, in order.
|
|
60
|
+
def load_stream(yaml, schema: :compat_11)
|
|
61
|
+
new(schema: schema).materialize(yaml)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# The shared drain seam: one parse, records + arena read once,
|
|
65
|
+
# ONE unpack into a flat Integer array (12 fields per record:
|
|
66
|
+
# type style flags tag_id line col v_off v_len a_off a_len
|
|
67
|
+
# t_off t_len). Both consumers ride it — the stack machine
|
|
68
|
+
# (materialize) and the Psych::Parser dispatch loop.
|
|
69
|
+
def drain(yaml, schema: :compat_11)
|
|
70
|
+
rec = Yeptris::FFI.yeptris_recorder_new_ex(
|
|
71
|
+
schema == :compat_11 ? Yeptris::FFI::SCHEMA_11_COMPAT : Yeptris::FFI::SCHEMA_12_CORE
|
|
72
|
+
)
|
|
73
|
+
begin
|
|
74
|
+
status = Yeptris::FFI.yeptris_recorder_feed(rec, yaml, yaml.bytesize, 1)
|
|
75
|
+
if status != Yeptris::FFI::OK
|
|
76
|
+
raise Yeptris::ParseError,
|
|
77
|
+
"parse failed: #{Yeptris::FFI.last_error_message}"
|
|
78
|
+
end
|
|
79
|
+
count_p = ::FFI::MemoryPointer.new(:size_t)
|
|
80
|
+
records = Yeptris::FFI.yeptris_recorder_records(rec, count_p)
|
|
81
|
+
count = Yeptris::FFI.read_c_size_t(count_p)
|
|
82
|
+
arena_len = ::FFI::MemoryPointer.new(:size_t)
|
|
83
|
+
arena_ptr = Yeptris::FFI.yeptris_recorder_arena(rec, arena_len)
|
|
84
|
+
arena_len_v = Yeptris::FFI.read_c_size_t(arena_len)
|
|
85
|
+
arena = arena_ptr.null? || arena_len_v.zero? ? +"" : arena_ptr.read_bytes(arena_len_v)
|
|
86
|
+
flat = records.read_bytes(count * RECORD_SIZE)
|
|
87
|
+
.unpack(RECORD_UNPACK * count)
|
|
88
|
+
[flat, arena]
|
|
89
|
+
ensure
|
|
90
|
+
Yeptris::FFI.yeptris_recorder_free(rec)
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# The Ruby value of a scalar per schema — the ScalarScanner rule
|
|
95
|
+
# set, spec-verified against Psych case by case. Only implicit
|
|
96
|
+
# PLAIN scalars scan; quoting is the escape hatch.
|
|
97
|
+
# The record's tag_id IS the resolver's verdict (the typing
|
|
98
|
+
# SSOT): conversion by tag, Kernel#Integer/Float for the bytes —
|
|
99
|
+
# no host-side grammar. Two Psych-quirk overrides where Psych's
|
|
100
|
+
# scanner disagrees with the 1.1 resolver: single-char y/Y/n/N
|
|
101
|
+
# are STRINGS in Psych (libyaml says bool), and values the
|
|
102
|
+
# resolver tagged INT but Kernel rejects (mixed forms) fall back
|
|
103
|
+
# through sexagesimal to String.
|
|
104
|
+
PSYCH_TRUE = %w[y yes true on].freeze
|
|
105
|
+
|
|
106
|
+
# '<<' merge: existing keys win; sequences merge in order.
|
|
107
|
+
# Shared by the record walk and the value-stream walk.
|
|
108
|
+
def merge_into(map, obj)
|
|
109
|
+
case obj
|
|
110
|
+
when Hash
|
|
111
|
+
obj.each { |k, v| map[k] = v unless map.key?(k) }
|
|
112
|
+
when Array
|
|
113
|
+
obj.each { |e| merge_into(map, e) if e.is_a?(Hash) }
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def parse_timestamp(v)
|
|
118
|
+
# stdlib scalar_scanner: date-only strings parse with
|
|
119
|
+
# strptime('%F', Date::GREGORIAN) — the PROLEPTIC calendar —
|
|
120
|
+
# not Date.parse's default ITALY reform (a 1582 cycle fails
|
|
121
|
+
# the ported test_julian_date otherwise)
|
|
122
|
+
return ::Date.strptime(v, "%F", ::Date::GREGORIAN) unless v.match?(/[Tt ]\d/)
|
|
123
|
+
|
|
124
|
+
# normalize the YAML 1.1 space forms onto iso8601 for
|
|
125
|
+
# xmlschema: "2001-12-14 21:59:43.10 -05:00" ->
|
|
126
|
+
# "2001-12-14T21:59:43.10-05:00" (Psych's scanner does the
|
|
127
|
+
# same dance)
|
|
128
|
+
ts = v.sub(/ (\d)/, 'T\1').sub(/ ([+-]\d)/, '\1').sub(/ +Z\z/i, 'Z')
|
|
129
|
+
# Psych reads a NAIVE timestamp (no zone, no Z) as a UTC
|
|
130
|
+
# instant expressed in the local zone — one wall-clock hour
|
|
131
|
+
# off from reading it as local time (pinned by spec against
|
|
132
|
+
# Psych.unsafe_load across tz shapes)
|
|
133
|
+
if ts.match?(/(Z|[+-]\d\d:?\d\d)\z/i)
|
|
134
|
+
Time.xmlschema(ts)
|
|
135
|
+
else
|
|
136
|
+
Time.xmlschema(ts + "Z").getlocal
|
|
137
|
+
end
|
|
138
|
+
rescue ArgumentError
|
|
139
|
+
v
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def scan_by_tag(value, tag_id, implicit)
|
|
143
|
+
case tag_id
|
|
144
|
+
when TAG_STR
|
|
145
|
+
return value unless implicit
|
|
146
|
+
|
|
147
|
+
value.start_with?(":") && !value.start_with?("::") &&
|
|
148
|
+
value.length > 1 ? value[1..].to_sym : value
|
|
149
|
+
when TAG_NULL then nil
|
|
150
|
+
when TAG_BOOL
|
|
151
|
+
return value if value.length == 1 # Psych: "y"/"n" stay Strings
|
|
152
|
+
|
|
153
|
+
PSYCH_TRUE.include?(value.downcase)
|
|
154
|
+
when TAG_INT
|
|
155
|
+
int_or_string(value)
|
|
156
|
+
when TAG_FLOAT
|
|
157
|
+
float_or_string(value)
|
|
158
|
+
when TAG_TIMESTAMP
|
|
159
|
+
parse_timestamp(value)
|
|
160
|
+
when TAG_BINARY
|
|
161
|
+
value.unpack1("m") # psych to_ruby: !binary -> decode64, ASCII-8BIT (#168)
|
|
162
|
+
else
|
|
163
|
+
value
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def int_or_string(value)
|
|
168
|
+
Integer(value.tr("_", ""))
|
|
169
|
+
rescue ArgumentError
|
|
170
|
+
# the resolver said INT but Kernel disagrees (mixed form):
|
|
171
|
+
# sexagesimal or back to String
|
|
172
|
+
return sexagesimal(value) if SEXAGESIMAL_INT.match?(value) ||
|
|
173
|
+
SEXAGESIMAL_FLOAT.match?(value)
|
|
174
|
+
|
|
175
|
+
value
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def float_or_string(value)
|
|
179
|
+
return INF_WORDS[value] if INF_WORDS.key?(value)
|
|
180
|
+
return value unless value.include?(".")
|
|
181
|
+
|
|
182
|
+
# Psych's FLOAT: the exponent carries a mandatory sign —
|
|
183
|
+
# "1e3" and "1.5e3" are Strings (resolver quirk override)
|
|
184
|
+
return value if /[eE][^+-]/.match?(value)
|
|
185
|
+
|
|
186
|
+
Float(value.tr("_", ""))
|
|
187
|
+
rescue ArgumentError
|
|
188
|
+
return sexagesimal(value) if SEXAGESIMAL_FLOAT.match?(value)
|
|
189
|
+
|
|
190
|
+
value
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
private
|
|
194
|
+
|
|
195
|
+
# Psych's scanner IS Kernel#Integer on the plain digits: Ruby
|
|
196
|
+
# reads leading-zero strings as octal, rejects "018", takes
|
|
197
|
+
# 0x/0b/bases — verified case by case against Psych.
|
|
198
|
+
def sexagesimal(v)
|
|
199
|
+
is_float = v.include?(".")
|
|
200
|
+
total = 0
|
|
201
|
+
v.split(":").each_with_index do |n, e|
|
|
202
|
+
total += (is_float ? n.to_f : n.to_i) * (60**(e - 2).abs)
|
|
203
|
+
end
|
|
204
|
+
total
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
def initialize(schema: :compat_11)
|
|
211
|
+
@schema = schema
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def materialize(yaml)
|
|
215
|
+
yaml = Yeptris.read_input(yaml)
|
|
216
|
+
yaml = yaml.to_s
|
|
217
|
+
flat, arena = Materializer.drain(yaml, schema: @schema)
|
|
218
|
+
walk(flat, arena)
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
private
|
|
222
|
+
|
|
223
|
+
# The stack machine: containers on a stack, a pending-key slot per
|
|
224
|
+
# open mapping, anchors by name (first definition wins; an alias
|
|
225
|
+
# yields the SAME Ruby object — identity preserved). Merge keys
|
|
226
|
+
# (<<) resolve inline: existing keys win, sequences merge in
|
|
227
|
+
# order — Psych load-time semantics.
|
|
228
|
+
#
|
|
229
|
+
# flat: one Integer per unpack field, 12 per record:
|
|
230
|
+
# 0 type, 1 style, 2 flags, 3 tag_id, 4 line, 5 col, 6 value_off,
|
|
231
|
+
# 7 value_len, 8 anchor_off, 9 anchor_len, 10 tag_off, 11 tag_len.
|
|
232
|
+
def walk(flat, arena)
|
|
233
|
+
docs = []
|
|
234
|
+
stack = []
|
|
235
|
+
anchors = {}
|
|
236
|
+
pending_key = []
|
|
237
|
+
pending_key_merge = []
|
|
238
|
+
# per open container: the map to merge into when this container
|
|
239
|
+
# closes (inline `<<:` values), nil otherwise
|
|
240
|
+
merge_target = []
|
|
241
|
+
|
|
242
|
+
# the arena is UTF-8 by construction (validated at parse), so
|
|
243
|
+
# forcing its encoding ONCE makes every slice UTF-8 for free —
|
|
244
|
+
# no per-scalar force_encoding
|
|
245
|
+
arena.force_encoding(Encoding::UTF_8)
|
|
246
|
+
# (each_slice DESTRUCTURING measured SLOWER than plain indexing
|
|
247
|
+
# here: it allocates a 12-slot Array per record. Index away.)
|
|
248
|
+
i = 0
|
|
249
|
+
n = flat.length
|
|
250
|
+
while i < n
|
|
251
|
+
type = flat[i]
|
|
252
|
+
case type
|
|
253
|
+
when SCALAR
|
|
254
|
+
# a plain, resolver-tagged '<<' (TAG_MERGE) merges; a
|
|
255
|
+
# QUOTED '<<' is a literal key — Psych merges on the tag,
|
|
256
|
+
# not the text
|
|
257
|
+
tag_id = flat[i + 3]
|
|
258
|
+
v = Materializer.scan_by_tag(
|
|
259
|
+
arena[flat[i + 6], flat[i + 7]], tag_id, (flat[i + 2] & EF_IMPLICIT) != 0
|
|
260
|
+
)
|
|
261
|
+
l = flat[i + 9]
|
|
262
|
+
anchors[arena[flat[i + 8], l]] = v if l != 0
|
|
263
|
+
# place(): the scalar fast path inlined — the overwhelming
|
|
264
|
+
# majority of events land here
|
|
265
|
+
if stack.empty?
|
|
266
|
+
docs[-1] = v
|
|
267
|
+
else
|
|
268
|
+
parent = stack.last
|
|
269
|
+
if parent.is_a?(Hash)
|
|
270
|
+
if (key = pending_key[-1]).nil?
|
|
271
|
+
pending_key[-1] = v
|
|
272
|
+
pending_key_merge[-1] = flat[i + 3] == TAG_MERGE
|
|
273
|
+
else
|
|
274
|
+
pending_key[-1] = nil
|
|
275
|
+
if pending_key_merge[-1]
|
|
276
|
+
merge_into(parent, v)
|
|
277
|
+
else
|
|
278
|
+
parent[key] = v
|
|
279
|
+
end
|
|
280
|
+
end
|
|
281
|
+
else
|
|
282
|
+
parent.push(v)
|
|
283
|
+
end
|
|
284
|
+
end
|
|
285
|
+
when MAPPING_START
|
|
286
|
+
h = {}
|
|
287
|
+
l = flat[i + 9]
|
|
288
|
+
anchors[arena[flat[i + 8], l]] = h if l != 0
|
|
289
|
+
merge_target.push(place(docs, stack, pending_key, pending_key_merge, h))
|
|
290
|
+
stack.push(h)
|
|
291
|
+
pending_key.push(nil)
|
|
292
|
+
pending_key_merge.push(nil)
|
|
293
|
+
when SEQUENCE_START
|
|
294
|
+
a = []
|
|
295
|
+
l = flat[i + 9]
|
|
296
|
+
anchors[arena[flat[i + 8], l]] = a if l != 0
|
|
297
|
+
merge_target.push(place(docs, stack, pending_key, pending_key_merge, a))
|
|
298
|
+
stack.push(a)
|
|
299
|
+
pending_key.push(nil)
|
|
300
|
+
pending_key_merge.push(nil)
|
|
301
|
+
when ALIAS
|
|
302
|
+
name = arena[flat[i + 6], flat[i + 7]]
|
|
303
|
+
raise Yeptris::ParseError, "unknown anchor: #{name.inspect}" unless anchors.key?(name)
|
|
304
|
+
|
|
305
|
+
place(docs, stack, pending_key, pending_key_merge, anchors[name])
|
|
306
|
+
when MAPPING_END, SEQUENCE_END
|
|
307
|
+
done = stack.pop
|
|
308
|
+
pending_key.pop
|
|
309
|
+
pending_key_merge.pop
|
|
310
|
+
target = merge_target.pop
|
|
311
|
+
merge_into(target, done) if target
|
|
312
|
+
when DOCUMENT_START
|
|
313
|
+
docs.push(nil)
|
|
314
|
+
end
|
|
315
|
+
i += FIELDS
|
|
316
|
+
end
|
|
317
|
+
docs
|
|
318
|
+
end
|
|
319
|
+
|
|
320
|
+
# Attaches obj: as the current document's root when nothing is
|
|
321
|
+
# open, as a sequence entry, or as the pending mapping key/value.
|
|
322
|
+
# Returns the merge TARGET when obj is a container placed under a
|
|
323
|
+
# "<<" key — the caller defers the merge to the container's END
|
|
324
|
+
# (an inline map's contents arrive after its start event); scalar
|
|
325
|
+
# and alias merges apply immediately.
|
|
326
|
+
def place(docs, stack, pending_key, pending_key_merge, obj)
|
|
327
|
+
if stack.empty?
|
|
328
|
+
docs[-1] = obj
|
|
329
|
+
return nil
|
|
330
|
+
end
|
|
331
|
+
parent = stack.last
|
|
332
|
+
if parent.is_a?(Hash)
|
|
333
|
+
if pending_key.last.nil?
|
|
334
|
+
pending_key[-1] = obj
|
|
335
|
+
pending_key_merge[-1] = false
|
|
336
|
+
return nil
|
|
337
|
+
end
|
|
338
|
+
key = pending_key.last
|
|
339
|
+
pending_key[-1] = nil
|
|
340
|
+
if pending_key_merge[-1]
|
|
341
|
+
merge_into(parent, obj)
|
|
342
|
+
parent
|
|
343
|
+
else
|
|
344
|
+
parent[key] = obj
|
|
345
|
+
nil
|
|
346
|
+
end
|
|
347
|
+
else # Array
|
|
348
|
+
parent.push(obj)
|
|
349
|
+
nil
|
|
350
|
+
end
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
end
|
|
354
|
+
end
|
|
Binary file
|