@elaraai/east 1.0.76 → 1.0.78
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.
- package/dist/src/fuzz.d.ts +103 -11
- package/dist/src/fuzz.d.ts.map +1 -1
- package/dist/src/fuzz.js +226 -16
- package/dist/src/fuzz.js.map +1 -1
- package/dist/src/patch/fuzz.d.ts +26 -0
- package/dist/src/patch/fuzz.d.ts.map +1 -1
- package/dist/src/patch/fuzz.js +42 -4
- package/dist/src/patch/fuzz.js.map +1 -1
- package/dist/src/patch/type_of_patch.d.ts +14 -1
- package/dist/src/patch/type_of_patch.d.ts.map +1 -1
- package/dist/src/patch/type_of_patch.js +8 -13
- package/dist/src/patch/type_of_patch.js.map +1 -1
- package/dist/src/patch/type_of_patch.spec.d.ts +6 -0
- package/dist/src/patch/type_of_patch.spec.d.ts.map +1 -0
- package/dist/src/patch/type_of_patch.spec.js +74 -0
- package/dist/src/patch/type_of_patch.spec.js.map +1 -0
- package/dist/src/serialization/beast2/index.d.ts +22 -1
- package/dist/src/serialization/beast2/index.d.ts.map +1 -1
- package/dist/src/serialization/beast2/index.js +56 -1
- package/dist/src/serialization/beast2/index.js.map +1 -1
- package/dist/src/serialization/beast2/index.spec.js +16 -0
- package/dist/src/serialization/beast2/index.spec.js.map +1 -1
- package/dist/src/serialization/beast2/v4/container.js +10 -15
- package/dist/src/serialization/beast2/v4/container.js.map +1 -1
- package/dist/src/serialization/beast2/v4/type-table.d.ts +63 -34
- package/dist/src/serialization/beast2/v4/type-table.d.ts.map +1 -1
- package/dist/src/serialization/beast2/v4/type-table.js +353 -403
- package/dist/src/serialization/beast2/v4/type-table.js.map +1 -1
- package/dist/src/serialization/beast2/v5/deflate.d.ts.map +1 -1
- package/dist/src/serialization/beast2/v5/deflate.js +147 -50
- package/dist/src/serialization/beast2/v5/deflate.js.map +1 -1
- package/dist/src/serialization/beast2/v5/deflate.spec.d.ts +6 -0
- package/dist/src/serialization/beast2/v5/deflate.spec.d.ts.map +1 -0
- package/dist/src/serialization/beast2/v5/deflate.spec.js +237 -0
- package/dist/src/serialization/beast2/v5/deflate.spec.js.map +1 -0
- package/dist/src/serialization/beast2/v5/frame-pool.d.ts +119 -0
- package/dist/src/serialization/beast2/v5/frame-pool.d.ts.map +1 -0
- package/dist/src/serialization/beast2/v5/frame-pool.js +235 -0
- package/dist/src/serialization/beast2/v5/frame-pool.js.map +1 -0
- package/dist/src/serialization/beast2/v5/frame-pool.spec.d.ts +6 -0
- package/dist/src/serialization/beast2/v5/frame-pool.spec.d.ts.map +1 -0
- package/dist/src/serialization/beast2/v5/frame-pool.spec.js +287 -0
- package/dist/src/serialization/beast2/v5/frame-pool.spec.js.map +1 -0
- package/dist/src/serialization/beast2/v5/frame-worker.d.ts +6 -0
- package/dist/src/serialization/beast2/v5/frame-worker.d.ts.map +1 -0
- package/dist/src/serialization/beast2/v5/frame-worker.js +40 -0
- package/dist/src/serialization/beast2/v5/frame-worker.js.map +1 -0
- package/dist/src/serialization/beast2/v5/index.spec.js +292 -5
- package/dist/src/serialization/beast2/v5/index.spec.js.map +1 -1
- package/dist/src/serialization/beast2/v5/lazy.d.ts +11 -8
- package/dist/src/serialization/beast2/v5/lazy.d.ts.map +1 -1
- package/dist/src/serialization/beast2/v5/lazy.js +49 -39
- package/dist/src/serialization/beast2/v5/lazy.js.map +1 -1
- package/dist/src/serialization/beast2/v5/lazy.spec.js +98 -3
- package/dist/src/serialization/beast2/v5/lazy.spec.js.map +1 -1
- package/dist/src/serialization/beast2/v5/stream.d.ts +88 -2
- package/dist/src/serialization/beast2/v5/stream.d.ts.map +1 -1
- package/dist/src/serialization/beast2/v5/stream.js +175 -22
- package/dist/src/serialization/beast2/v5/stream.js.map +1 -1
- package/dist/src/serialization/index.d.ts +1 -1
- package/dist/src/serialization/index.d.ts.map +1 -1
- package/dist/src/serialization/index.js +1 -1
- package/dist/src/serialization/index.js.map +1 -1
- package/dist/src/type_of_type.d.ts +0 -5
- package/dist/src/type_of_type.d.ts.map +1 -1
- package/dist/src/type_of_type.js +51 -49
- package/dist/src/type_of_type.js.map +1 -1
- package/dist/src/type_of_type.to_etv.spec.js +75 -0
- package/dist/src/type_of_type.to_etv.spec.js.map +1 -1
- package/package.json +1 -1
|
@@ -3,15 +3,41 @@
|
|
|
3
3
|
* Dual-licensed under AGPL-3.0 and commercial license. See LICENSE for details.
|
|
4
4
|
*/
|
|
5
5
|
/**
|
|
6
|
-
* Beast2
|
|
6
|
+
* Beast2 flat type table — encoder and decoder.
|
|
7
7
|
*
|
|
8
|
-
* The type table is a flat array
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* The type table is a flat array in which each distinct type is one entry,
|
|
9
|
+
* referenced by varint index; tag bytes double as indices into the decoder's
|
|
10
|
+
* dispatch table. The v4 container writes it as its first section and the v5
|
|
11
|
+
* container reuses it verbatim as the structural type section.
|
|
11
12
|
*
|
|
12
|
-
*
|
|
13
|
+
* **The table is canonical** (#770): a pure function of the type, so the same
|
|
14
|
+
* type writes the same bytes in every runtime (east-c's `type_table.c` applies
|
|
15
|
+
* the same rules, and east-py encodes through it) and whether the type was
|
|
16
|
+
* built in code or read back off the wire. e3 content-addresses beast2 bytes,
|
|
17
|
+
* so anything less puts one value under several hashes. The rules, as
|
|
18
|
+
* {@link TypeTableBuilder} applies them:
|
|
19
|
+
*
|
|
20
|
+
* - Entries are committed in a post-order walk over the type in declaration
|
|
21
|
+
* order: Struct fields as declared, Variant cases as sorted, Function inputs
|
|
22
|
+
* then output, Dict key then value. A child therefore sits at a lower index
|
|
23
|
+
* than its parent, which the decoders rely on.
|
|
24
|
+
* - A Recursive wrapper takes its index before its body is walked, so the
|
|
25
|
+
* body's self-references name that index.
|
|
26
|
+
* - An entry whose bytes (tag + parameters) are already in the table is not
|
|
27
|
+
* written again. Two occurrences of one type — inside or outside a
|
|
28
|
+
* recursive wrapper's body, as an `EastType` or as an `EastTypeValue`, as
|
|
29
|
+
* one object or as many — are one entry.
|
|
30
|
+
* - Two Recursive wrappers are one entry when {@link isTypeValueEqual} says
|
|
31
|
+
* so. A wrapper's id is a runtime artefact (a type id in one process, a
|
|
32
|
+
* table index off the wire) and is not written, so wrappers compare up to
|
|
33
|
+
* their naming.
|
|
34
|
+
*
|
|
35
|
+
* Nothing here constructs an `EastType`. Type ids are serialized into IR, so
|
|
36
|
+
* an encode must not shift the ids of the types built after it.
|
|
37
|
+
*
|
|
38
|
+
* See v4/SPEC.md for the entry grammar and v5/SPEC.md for the type section.
|
|
13
39
|
*/
|
|
14
|
-
import { toEastTypeValue } from "../../../type_of_type.js";
|
|
40
|
+
import { toEastTypeValue, isTypeValueEqual } from "../../../type_of_type.js";
|
|
15
41
|
import { getTypeId } from "../../../types.js";
|
|
16
42
|
import { isVariant, variant } from "../../../containers/variant.js";
|
|
17
43
|
import { BufferWriter, BufferReader } from "../../binary-utils.js";
|
|
@@ -45,313 +71,240 @@ const TAG_FOR_TYPE = {
|
|
|
45
71
|
Function: TAG_FUNCTION, AsyncFunction: TAG_ASYNC_FUNCTION, Recursive: TAG_RECURSIVE,
|
|
46
72
|
};
|
|
47
73
|
/**
|
|
48
|
-
* Builds
|
|
49
|
-
*
|
|
50
|
-
*
|
|
74
|
+
* Builds the canonical flat type table of one or more types (see the module
|
|
75
|
+
* comment for the rules). Accepts `EastType` (converted with
|
|
76
|
+
* {@link toEastTypeValue}, which allocates no type) and `EastTypeValue`.
|
|
51
77
|
*
|
|
52
78
|
* Usage:
|
|
53
79
|
* const builder = new TypeTableBuilder();
|
|
54
80
|
* const rootIdx = builder.add(myType); // EastType or EastTypeValue
|
|
55
|
-
* builder.
|
|
81
|
+
* builder.add(someIRTypeAnnotation); // a later type shares entries
|
|
56
82
|
* writeTypeTableSection(rootIdx, builder.entries, writer);
|
|
57
83
|
*/
|
|
58
84
|
export class TypeTableBuilder {
|
|
59
85
|
entries = [];
|
|
60
|
-
/**
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
|
|
64
|
-
/** type_id →
|
|
65
|
-
|
|
66
|
-
/** Recursive wrapper
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
/** Create a
|
|
86
|
+
/** Entry bytes (tag + parameters) → index: the same bytes are the same wire node. */
|
|
87
|
+
byContent = new Map();
|
|
88
|
+
/** Type object (EastType or EastTypeValue) → index: a memo over the walk. */
|
|
89
|
+
byObject = new Map();
|
|
90
|
+
/** type_id → index, for the values `toEastTypeValue` stamps. */
|
|
91
|
+
byTid = new Map();
|
|
92
|
+
/** Recursive wrapper id → the wrapper's index, for every wrapper added. */
|
|
93
|
+
byWrapperId = new Map();
|
|
94
|
+
/** Committed wrappers, deduplicated structurally. */
|
|
95
|
+
wrappers = [];
|
|
96
|
+
/** Wrappers whose bodies are being walked, innermost last. */
|
|
97
|
+
open = [];
|
|
98
|
+
/** Create a copy with the same entries and lookups (the v4 encoder extends a
|
|
99
|
+
* cached root closure per value). */
|
|
73
100
|
clone() {
|
|
74
101
|
const c = new TypeTableBuilder();
|
|
75
102
|
for (const e of this.entries)
|
|
76
103
|
c.entries.push(e);
|
|
77
|
-
for (const [k, v] of this.
|
|
78
|
-
c.
|
|
79
|
-
for (const [k, v] of this.
|
|
80
|
-
c.
|
|
81
|
-
for (const [k, v] of this.
|
|
82
|
-
c.
|
|
83
|
-
for (const [k, v] of this.
|
|
84
|
-
c.
|
|
104
|
+
for (const [k, v] of this.byContent)
|
|
105
|
+
c.byContent.set(k, v);
|
|
106
|
+
for (const [k, v] of this.byObject)
|
|
107
|
+
c.byObject.set(k, v);
|
|
108
|
+
for (const [k, v] of this.byTid)
|
|
109
|
+
c.byTid.set(k, v);
|
|
110
|
+
for (const [k, v] of this.byWrapperId)
|
|
111
|
+
c.byWrapperId.set(k, v);
|
|
112
|
+
for (const w of this.wrappers)
|
|
113
|
+
c.wrappers.push(w);
|
|
114
|
+
for (const w of this.open)
|
|
115
|
+
c.open.push(w);
|
|
85
116
|
return c;
|
|
86
117
|
}
|
|
87
|
-
/** Add a type
|
|
118
|
+
/** Add a type and return its index; a type already in the table returns its
|
|
119
|
+
* existing index and writes nothing. Accepts both EastType and EastTypeValue. */
|
|
88
120
|
add(type) {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
121
|
+
const memo = this.byObject.get(type);
|
|
122
|
+
if (memo !== undefined)
|
|
123
|
+
return memo;
|
|
124
|
+
const etv = isVariant(type) ? type : toEastTypeValue(type);
|
|
125
|
+
const idx = this.visit(etv);
|
|
126
|
+
this.byObject.set(type, idx);
|
|
127
|
+
return idx;
|
|
93
128
|
}
|
|
94
129
|
/** Add an EastTypeValue (for IR type annotations). */
|
|
95
130
|
addETV(etv) {
|
|
96
|
-
return this.
|
|
131
|
+
return this.add(etv);
|
|
97
132
|
}
|
|
98
|
-
/** Look up
|
|
133
|
+
/** Look up a type's index without adding it: by object, by type_id, or — for
|
|
134
|
+
* a Recursive ref or wrapper — by the wrapper's id. */
|
|
99
135
|
indexOf(etv) {
|
|
100
|
-
const idx = this.
|
|
101
|
-
if (idx
|
|
102
|
-
|
|
136
|
+
const idx = this.lookup(etv);
|
|
137
|
+
if (idx === undefined)
|
|
138
|
+
throw new Error(`Type not in table: ${etv.type}`);
|
|
139
|
+
return idx;
|
|
140
|
+
}
|
|
141
|
+
/** Whether {@link indexOf} would find the type. `add` is idempotent, so a
|
|
142
|
+
* miss here is never a reason not to add. */
|
|
143
|
+
has(etv) {
|
|
144
|
+
return this.lookup(etv) !== undefined;
|
|
145
|
+
}
|
|
146
|
+
lookup(etv) {
|
|
147
|
+
const memo = this.byObject.get(etv);
|
|
148
|
+
if (memo !== undefined)
|
|
149
|
+
return memo;
|
|
103
150
|
const tid = getTypeId(etv);
|
|
104
151
|
if (tid !== undefined) {
|
|
105
|
-
const
|
|
106
|
-
if (
|
|
107
|
-
return
|
|
152
|
+
const known = this.byTid.get(tid);
|
|
153
|
+
if (known !== undefined)
|
|
154
|
+
return known;
|
|
108
155
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
const recIdx = this.recIdMap.get(refId);
|
|
113
|
-
if (recIdx !== undefined)
|
|
114
|
-
return recIdx;
|
|
156
|
+
if (etv.type === "Recursive") {
|
|
157
|
+
const id = recursiveId(etv.value);
|
|
158
|
+
return this.openWrapper(id) ?? this.byWrapperId.get(id);
|
|
115
159
|
}
|
|
116
|
-
|
|
160
|
+
return undefined;
|
|
117
161
|
}
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
162
|
+
// ── The walk ────────────────────────────────────────────────────────
|
|
163
|
+
visit(etv) {
|
|
164
|
+
const memo = this.byObject.get(etv);
|
|
165
|
+
if (memo !== undefined)
|
|
166
|
+
return memo;
|
|
122
167
|
const tid = getTypeId(etv);
|
|
123
|
-
if (tid !== undefined
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}
|
|
129
|
-
return false;
|
|
130
|
-
}
|
|
131
|
-
// ── EastType walker (handles Recursive wrappers) ────────────────────
|
|
132
|
-
visitET(type) {
|
|
133
|
-
const existing = this.etMap.get(type);
|
|
134
|
-
if (existing !== undefined)
|
|
135
|
-
return existing;
|
|
136
|
-
const t = type;
|
|
137
|
-
if (t.type === "Recursive") {
|
|
138
|
-
// Allocate index BEFORE recursing — self-references find this index
|
|
139
|
-
const idx = this.allocate();
|
|
140
|
-
this.etMap.set(type, idx);
|
|
141
|
-
// Register type_id so ETV path can find this entry via tidMap
|
|
142
|
-
const recTid = getTypeId(type);
|
|
143
|
-
if (recTid !== undefined) {
|
|
144
|
-
this.tidMap.set(recTid, idx);
|
|
145
|
-
this.recIdMap.set(BigInt(recTid), idx);
|
|
168
|
+
if (tid !== undefined) {
|
|
169
|
+
const known = this.byTid.get(tid);
|
|
170
|
+
if (known !== undefined) {
|
|
171
|
+
this.byObject.set(etv, known);
|
|
172
|
+
return known;
|
|
146
173
|
}
|
|
147
|
-
const innerIdx = this.visitET(t.node);
|
|
148
|
-
this.entries[idx] = { tag: TAG_RECURSIVE, params: varint(innerIdx) };
|
|
149
|
-
return idx;
|
|
150
|
-
}
|
|
151
|
-
// Check EastTypeValue identity cache for dedup
|
|
152
|
-
const etv = toEastTypeValue(type);
|
|
153
|
-
const etvIdx = this.etvMap.get(etv);
|
|
154
|
-
if (etvIdx !== undefined) {
|
|
155
|
-
this.etMap.set(type, etvIdx);
|
|
156
|
-
return etvIdx;
|
|
157
|
-
}
|
|
158
|
-
// Primitives
|
|
159
|
-
if (t.type === "Never" || t.type === "Null" || t.type === "Boolean" ||
|
|
160
|
-
t.type === "Integer" || t.type === "Float" || t.type === "String" ||
|
|
161
|
-
t.type === "DateTime" || t.type === "Blob") {
|
|
162
|
-
return this.emitPrimitive(type, etv, t.type);
|
|
163
|
-
}
|
|
164
|
-
// Single-parameter containers
|
|
165
|
-
if (t.type === "Array" || t.type === "Ref") {
|
|
166
|
-
const elemIdx = this.visitET(t.value);
|
|
167
|
-
return this.emit(type, etv, TAG_FOR_TYPE[t.type], varint(elemIdx));
|
|
168
174
|
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
const elemIdx = this.visitET(t.element);
|
|
175
|
-
return this.emit(type, etv, TAG_FOR_TYPE[t.type], varint(elemIdx));
|
|
176
|
-
}
|
|
177
|
-
if (t.type === "Dict") {
|
|
178
|
-
const ki = this.visitET(t.key);
|
|
179
|
-
const vi = this.visitET(t.value);
|
|
180
|
-
return this.emit(type, etv, TAG_DICT, varints(ki, vi));
|
|
181
|
-
}
|
|
182
|
-
if (t.type === "Struct") {
|
|
183
|
-
return this.emitNamedFields(type, etv, TAG_STRUCT, Object.keys(t.fields), (name) => this.visitET(t.fields[name]));
|
|
184
|
-
}
|
|
185
|
-
if (t.type === "Variant") {
|
|
186
|
-
return this.emitNamedFields(type, etv, TAG_VARIANT, Object.keys(t.cases), (name) => this.visitET(t.cases[name]));
|
|
187
|
-
}
|
|
188
|
-
if (t.type === "Function" || t.type === "AsyncFunction") {
|
|
189
|
-
return this.emitFunc(type, etv, t.type, t.inputs.map((i) => this.visitET(i)), this.visitET(t.output));
|
|
190
|
-
}
|
|
191
|
-
throw new Error(`Unknown EastType: ${t.type}`);
|
|
175
|
+
const idx = this.visitNode(etv);
|
|
176
|
+
this.byObject.set(etv, idx);
|
|
177
|
+
if (tid !== undefined)
|
|
178
|
+
this.byTid.set(tid, idx);
|
|
179
|
+
return idx;
|
|
192
180
|
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
this.
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
this.recIdMap.set(wrapperId, idx);
|
|
216
|
-
const innerIdx = this.visitETV(inner.value.inner);
|
|
217
|
-
this.entries[idx] = { tag: TAG_RECURSIVE, params: varint(innerIdx) };
|
|
218
|
-
return idx;
|
|
181
|
+
/** Commit the entry of a node after its children (post-order). */
|
|
182
|
+
visitNode(etv) {
|
|
183
|
+
switch (etv.type) {
|
|
184
|
+
case "Never":
|
|
185
|
+
case "Null":
|
|
186
|
+
case "Boolean":
|
|
187
|
+
case "Integer":
|
|
188
|
+
case "Float":
|
|
189
|
+
case "String":
|
|
190
|
+
case "DateTime":
|
|
191
|
+
case "Blob":
|
|
192
|
+
return this.commit(TAG_FOR_TYPE[etv.type], EMPTY);
|
|
193
|
+
case "Array":
|
|
194
|
+
case "Set":
|
|
195
|
+
case "Ref":
|
|
196
|
+
case "Vector":
|
|
197
|
+
case "Matrix":
|
|
198
|
+
return this.commit(TAG_FOR_TYPE[etv.type], varint(this.visit(etv.value)));
|
|
199
|
+
case "Dict": {
|
|
200
|
+
const ki = this.visit(etv.value.key);
|
|
201
|
+
const vi = this.visit(etv.value.value);
|
|
202
|
+
return this.commit(TAG_DICT, varints(ki, vi));
|
|
219
203
|
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
204
|
+
case "Struct":
|
|
205
|
+
case "Variant": {
|
|
206
|
+
const members = etv.value;
|
|
207
|
+
const indices = members.map(m => this.visit(m.type));
|
|
208
|
+
const w = new BufferWriter();
|
|
209
|
+
w.writeVarint(members.length);
|
|
210
|
+
for (let i = 0; i < members.length; i++) {
|
|
211
|
+
w.writeStringUtf8Varint(members[i].name);
|
|
212
|
+
w.writeVarint(indices[i]);
|
|
213
|
+
}
|
|
214
|
+
return this.commit(TAG_FOR_TYPE[etv.type], w.toUint8Array());
|
|
230
215
|
}
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
216
|
+
case "Function":
|
|
217
|
+
case "AsyncFunction": {
|
|
218
|
+
const inputs = etv.value.inputs.map(i => this.visit(i));
|
|
219
|
+
const output = this.visit(etv.value.output);
|
|
220
|
+
const w = new BufferWriter();
|
|
221
|
+
w.writeVarint(inputs.length);
|
|
222
|
+
for (const ii of inputs)
|
|
223
|
+
w.writeVarint(ii);
|
|
224
|
+
w.writeVarint(output);
|
|
225
|
+
return this.commit(TAG_FOR_TYPE[etv.type], w.toUint8Array());
|
|
235
226
|
}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
caseName === "Integer" || caseName === "Float" || caseName === "String" ||
|
|
241
|
-
caseName === "DateTime" || caseName === "Blob") {
|
|
242
|
-
const idx = this.allocate();
|
|
243
|
-
this.registerETV(etv, idx);
|
|
244
|
-
this.entries[idx] = { tag: TAG_FOR_TYPE[caseName], params: EMPTY };
|
|
245
|
-
return idx;
|
|
246
|
-
}
|
|
247
|
-
// Single-parameter containers
|
|
248
|
-
if (caseName === "Array" || caseName === "Set" || caseName === "Ref" ||
|
|
249
|
-
caseName === "Vector" || caseName === "Matrix") {
|
|
250
|
-
const elemIdx = this.visitETV(etv.value);
|
|
251
|
-
const idx = this.allocate();
|
|
252
|
-
this.registerETV(etv, idx);
|
|
253
|
-
this.entries[idx] = { tag: TAG_FOR_TYPE[caseName], params: varint(elemIdx) };
|
|
254
|
-
return idx;
|
|
255
|
-
}
|
|
256
|
-
if (caseName === "Dict") {
|
|
257
|
-
const ki = this.visitETV(etv.value.key);
|
|
258
|
-
const vi = this.visitETV(etv.value.value);
|
|
259
|
-
const idx = this.allocate();
|
|
260
|
-
this.registerETV(etv, idx);
|
|
261
|
-
this.entries[idx] = { tag: TAG_DICT, params: varints(ki, vi) };
|
|
262
|
-
return idx;
|
|
263
|
-
}
|
|
264
|
-
if (caseName === "Struct") {
|
|
265
|
-
const fields = etv.value;
|
|
266
|
-
const indices = fields.map(f => this.visitETV(f.type));
|
|
267
|
-
const idx = this.emitNamedFieldsETV(etv, TAG_STRUCT, fields.map(f => f.name), indices);
|
|
268
|
-
return idx;
|
|
269
|
-
}
|
|
270
|
-
if (caseName === "Variant") {
|
|
271
|
-
const cases = etv.value;
|
|
272
|
-
const indices = cases.map(c => this.visitETV(c.type));
|
|
273
|
-
const idx = this.emitNamedFieldsETV(etv, TAG_VARIANT, cases.map(c => c.name), indices);
|
|
274
|
-
return idx;
|
|
275
|
-
}
|
|
276
|
-
if (caseName === "Function" || caseName === "AsyncFunction") {
|
|
277
|
-
const inputs = etv.value.inputs;
|
|
278
|
-
const inputIndices = inputs.map(i => this.visitETV(i));
|
|
279
|
-
const outputIdx = this.visitETV(etv.value.output);
|
|
280
|
-
const idx = this.emitFuncETV(etv, caseName, inputIndices, outputIdx);
|
|
281
|
-
return idx;
|
|
227
|
+
case "Recursive":
|
|
228
|
+
return this.visitRecursive(etv.value, etv);
|
|
229
|
+
default:
|
|
230
|
+
throw new Error(`Unknown EastTypeValue case: ${etv.type}`);
|
|
282
231
|
}
|
|
283
|
-
throw new Error(`Unknown EastTypeValue case: ${caseName}`);
|
|
284
232
|
}
|
|
285
|
-
|
|
286
|
-
|
|
233
|
+
visitRecursive(payload, etv) {
|
|
234
|
+
const id = recursiveId(payload);
|
|
235
|
+
// A self-reference — a ref, or the wrapper spelled out again inside its
|
|
236
|
+
// own body — names the wrapper being walked.
|
|
237
|
+
const open = this.openWrapper(id);
|
|
238
|
+
if (open !== undefined)
|
|
239
|
+
return open;
|
|
240
|
+
if (payload.type === "ref") {
|
|
241
|
+
// A ref outside its wrapper's body stands for the whole recursive type.
|
|
242
|
+
const committed = this.byWrapperId.get(id);
|
|
243
|
+
if (committed !== undefined)
|
|
244
|
+
return committed;
|
|
245
|
+
throw new Error(`beast2 type table: Recursive ref(${id}) is bound by no wrapper`);
|
|
246
|
+
}
|
|
247
|
+
// The wrapper's entry exists only once its body does, so a repeat is found
|
|
248
|
+
// by comparing types, not bytes — up to the naming of wrappers.
|
|
249
|
+
for (const w of this.wrappers) {
|
|
250
|
+
if (isTypeValueEqual(w.etv, etv)) {
|
|
251
|
+
// Bind THIS id to the shared entry too. One recursive type reaches a
|
|
252
|
+
// table under different wrapper ids — an interned type id in this
|
|
253
|
+
// process, a table index off the wire — and the id is a runtime
|
|
254
|
+
// artefact that is never written. Binding only the first wrapper's
|
|
255
|
+
// would leave a later bare `ref` under the second id bound by no
|
|
256
|
+
// wrapper, which is an encode failure, not a naming difference.
|
|
257
|
+
this.byWrapperId.set(id, w.idx);
|
|
258
|
+
return w.idx;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
// Take the index before the body so its self-references resolve.
|
|
287
262
|
const idx = this.entries.length;
|
|
288
|
-
this.entries.push(null);
|
|
263
|
+
this.entries.push(null);
|
|
264
|
+
this.open.push({ id, idx });
|
|
265
|
+
let innerIdx;
|
|
266
|
+
try {
|
|
267
|
+
innerIdx = this.visit(payload.value.inner);
|
|
268
|
+
}
|
|
269
|
+
finally {
|
|
270
|
+
this.open.pop();
|
|
271
|
+
}
|
|
272
|
+
this.entries[idx] = { tag: TAG_RECURSIVE, params: varint(innerIdx) };
|
|
273
|
+
this.wrappers.push({ etv, idx });
|
|
274
|
+
this.byWrapperId.set(id, idx);
|
|
289
275
|
return idx;
|
|
290
276
|
}
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
if (tid !== undefined)
|
|
296
|
-
this.tidMap.set(tid, idx);
|
|
297
|
-
}
|
|
298
|
-
emitPrimitive(et, etv, typeName) {
|
|
299
|
-
const idx = this.allocate();
|
|
300
|
-
this.etMap.set(et, idx);
|
|
301
|
-
this.registerETV(etv, idx);
|
|
302
|
-
this.entries[idx] = { tag: TAG_FOR_TYPE[typeName], params: EMPTY };
|
|
303
|
-
return idx;
|
|
304
|
-
}
|
|
305
|
-
emit(et, etv, tag, params) {
|
|
306
|
-
const idx = this.allocate();
|
|
307
|
-
this.etMap.set(et, idx);
|
|
308
|
-
this.registerETV(etv, idx);
|
|
309
|
-
this.entries[idx] = { tag, params };
|
|
310
|
-
return idx;
|
|
311
|
-
}
|
|
312
|
-
emitNamedFields(et, etv, tag, names, resolve) {
|
|
313
|
-
const indices = names.map(resolve);
|
|
314
|
-
const w = new BufferWriter();
|
|
315
|
-
w.writeVarint(names.length);
|
|
316
|
-
for (let i = 0; i < names.length; i++) {
|
|
317
|
-
w.writeStringUtf8Varint(names[i]);
|
|
318
|
-
w.writeVarint(indices[i]);
|
|
277
|
+
openWrapper(id) {
|
|
278
|
+
for (let i = this.open.length - 1; i >= 0; i--) {
|
|
279
|
+
if (this.open[i].id === id)
|
|
280
|
+
return this.open[i].idx;
|
|
319
281
|
}
|
|
320
|
-
return
|
|
321
|
-
}
|
|
322
|
-
emitNamedFieldsETV(etv, tag, names, indices) {
|
|
323
|
-
const w = new BufferWriter();
|
|
324
|
-
w.writeVarint(names.length);
|
|
325
|
-
for (let i = 0; i < names.length; i++) {
|
|
326
|
-
w.writeStringUtf8Varint(names[i]);
|
|
327
|
-
w.writeVarint(indices[i]);
|
|
328
|
-
}
|
|
329
|
-
const idx = this.allocate();
|
|
330
|
-
this.registerETV(etv, idx);
|
|
331
|
-
this.entries[idx] = { tag, params: w.toUint8Array() };
|
|
332
|
-
return idx;
|
|
282
|
+
return undefined;
|
|
333
283
|
}
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
const w = new BufferWriter();
|
|
344
|
-
w.writeVarint(inputIndices.length);
|
|
345
|
-
for (const ii of inputIndices)
|
|
346
|
-
w.writeVarint(ii);
|
|
347
|
-
w.writeVarint(outputIdx);
|
|
348
|
-
const idx = this.allocate();
|
|
349
|
-
this.registerETV(etv, idx);
|
|
350
|
-
this.entries[idx] = { tag: TAG_FOR_TYPE[caseName], params: w.toUint8Array() };
|
|
284
|
+
/** Append an entry unless the same bytes are already in the table. */
|
|
285
|
+
commit(tag, params) {
|
|
286
|
+
const key = contentKey(tag, params);
|
|
287
|
+
const existing = this.byContent.get(key);
|
|
288
|
+
if (existing !== undefined)
|
|
289
|
+
return existing;
|
|
290
|
+
const idx = this.entries.length;
|
|
291
|
+
this.entries.push({ tag, params });
|
|
292
|
+
this.byContent.set(key, idx);
|
|
351
293
|
return idx;
|
|
352
294
|
}
|
|
353
295
|
}
|
|
354
296
|
const EMPTY = new Uint8Array(0);
|
|
297
|
+
/** The id a `Recursive` payload names — the wrapper's own id, or a ref's. */
|
|
298
|
+
function recursiveId(payload) {
|
|
299
|
+
return payload.type === "ref" ? payload.value : payload.value.id;
|
|
300
|
+
}
|
|
301
|
+
/** The entry's bytes as a map key (one code unit per byte). */
|
|
302
|
+
function contentKey(tag, params) {
|
|
303
|
+
let key = String.fromCharCode(tag);
|
|
304
|
+
for (let i = 0; i < params.length; i++)
|
|
305
|
+
key += String.fromCharCode(params[i]);
|
|
306
|
+
return key;
|
|
307
|
+
}
|
|
355
308
|
function varint(value) {
|
|
356
309
|
const w = new BufferWriter();
|
|
357
310
|
w.writeVarint(value);
|
|
@@ -457,13 +410,25 @@ function parseTypeTableSectionPayload(payload) {
|
|
|
457
410
|
// Phase 1: Parse raw entries
|
|
458
411
|
const parsed = new Array(entryCount);
|
|
459
412
|
for (let i = 0; i < entryCount; i++) {
|
|
460
|
-
|
|
413
|
+
const tag = reader.readUint8();
|
|
414
|
+
const parse = ENTRY_PARSERS[tag];
|
|
415
|
+
if (!parse)
|
|
416
|
+
throw new Error(`Type table entry ${i} has unknown tag 0x${tag.toString(16)}`);
|
|
417
|
+
parsed[i] = parse(reader);
|
|
418
|
+
// Every child index names an entry of this table.
|
|
419
|
+
for (const child of parsed[i].childIndices) {
|
|
420
|
+
if (child >= entryCount)
|
|
421
|
+
throw new Error(`Type table entry ${i} references entry ${child} of ${entryCount}`);
|
|
422
|
+
}
|
|
461
423
|
}
|
|
462
424
|
if (reader.offset !== payload.length) {
|
|
463
425
|
throw new Error(`Type table size mismatch: expected offset ${payload.length}, got ${reader.offset}`);
|
|
464
426
|
}
|
|
465
|
-
|
|
466
|
-
|
|
427
|
+
if (rootIdx >= entryCount) {
|
|
428
|
+
throw new Error(`Type table root index ${rootIdx} out of range (${entryCount} entries)`);
|
|
429
|
+
}
|
|
430
|
+
// Phase 2: Reconstruct EastTypeValue tree with Recursive wrapper/ref references
|
|
431
|
+
const table = reconstructTypes(parsed);
|
|
467
432
|
return { rootType: table[rootIdx], typeTable: table };
|
|
468
433
|
}
|
|
469
434
|
/**
|
|
@@ -528,7 +493,7 @@ const ENTRY_PARSERS = [
|
|
|
528
493
|
/* 0x11 */ parseFunc(TAG_ASYNC_FUNCTION),
|
|
529
494
|
/* 0x12 */ parseRecursive,
|
|
530
495
|
];
|
|
531
|
-
//
|
|
496
|
+
// ── Reconstruction: flat table → EastTypeValue with wrapper/ref recursion ──
|
|
532
497
|
const TAG_TO_CASE = [
|
|
533
498
|
"Null", "String", "Integer", "Float", "Boolean", "DateTime", "Blob", "Never",
|
|
534
499
|
"Variant", "Struct", "Array", "Dict", "Set", "Ref", "Vector", "Matrix",
|
|
@@ -547,165 +512,150 @@ const PRIMITIVE_ETV = [
|
|
|
547
512
|
/**
|
|
548
513
|
* Reconstruct EastTypeValue objects from parsed flat table entries.
|
|
549
514
|
*
|
|
550
|
-
* Recursive
|
|
551
|
-
*
|
|
552
|
-
*
|
|
515
|
+
* A Recursive entry becomes `wrapper({id, inner})` whose id is its table
|
|
516
|
+
* index; inside its body a reference back to it is `ref(id)`. The returned
|
|
517
|
+
* table holds every entry's **closed** form — built in no wrapper's scope, so
|
|
518
|
+
* it is a complete type wherever it is used (v4 value-table entries name
|
|
519
|
+
* element types by index).
|
|
553
520
|
*
|
|
554
|
-
*
|
|
555
|
-
* it
|
|
556
|
-
*
|
|
557
|
-
*
|
|
558
|
-
*
|
|
559
|
-
*
|
|
560
|
-
*
|
|
561
|
-
*
|
|
521
|
+
* The same entry can be reached from inside a wrapper's body and from outside
|
|
522
|
+
* it — a canonical table writes `Array<T>` once whether it occurs as `T`'s
|
|
523
|
+
* child or as another field's type — and the two readings are different
|
|
524
|
+
* objects: inside, references to `T` are `ref`s; outside, they are the
|
|
525
|
+
* wrapper. So an object built under a wrapper (one that holds a `ref` to it)
|
|
526
|
+
* is memoized only for that wrapper's scope, and an object that references no
|
|
527
|
+
* open wrapper is closed and memoized for good. One table index yields one
|
|
528
|
+
* closed object, shared by every reference to it, so a decoded type is a
|
|
529
|
+
* canonical input to {@link TypeTableBuilder} in turn.
|
|
530
|
+
*
|
|
531
|
+
* The walk is top-down, so the outside reading of `Array<T>` can be under
|
|
532
|
+
* construction when `T` — its child, indexed before it — opens and its body
|
|
533
|
+
* reaches `Array<T>` again. That re-entry is `T`'s own recursion, built as
|
|
534
|
+
* the inside reading in `T`'s scope; only a cycle with no wrapper in it is
|
|
535
|
+
* malformed. So entries under construction are tracked per open wrapper
|
|
536
|
+
* (#773 — east-ui's `TreeView.nodes`, an `Array<Inner>` whose `Inner` has
|
|
537
|
+
* `children: Array<self>`, under the `UIComponentType` wrapper).
|
|
562
538
|
*/
|
|
563
|
-
function reconstructTypes(parsed
|
|
564
|
-
const
|
|
565
|
-
//
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
//
|
|
570
|
-
|
|
571
|
-
//
|
|
572
|
-
//
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
//
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
// For the inner types of recursive entries, self-references (indices pointing
|
|
583
|
-
// back to a Recursive wrapper) must be replaced with Recursive(depth).
|
|
584
|
-
//
|
|
585
|
-
// We process bottom-up: entries with lower indices are built first (they
|
|
586
|
-
// have no forward references except through Recursive wrappers).
|
|
587
|
-
// recursionStack tracks which Recursive wrapper indices are "in scope"
|
|
588
|
-
// as we build types, so we can compute depth for Recursive(N) references.
|
|
589
|
-
function build(idx, depthStack) {
|
|
590
|
-
// If this index is a Recursive wrapper currently being built, emit Recursive(ref(id)).
|
|
591
|
-
// The id is the table index of the wrapper entry.
|
|
592
|
-
const stackPos = depthStack.indexOf(idx);
|
|
593
|
-
if (stackPos !== -1) {
|
|
594
|
-
if (stackPos < minRefPos)
|
|
595
|
-
minRefPos = stackPos;
|
|
539
|
+
function reconstructTypes(parsed) {
|
|
540
|
+
const closed = new Array(parsed.length);
|
|
541
|
+
// Open wrapper indices, outermost first; `scopes[i]` memoizes what was
|
|
542
|
+
// built under `stack[i]` and reaches an open wrapper.
|
|
543
|
+
const stack = [];
|
|
544
|
+
const scopes = [];
|
|
545
|
+
// Non-wrapper entries under construction since the innermost open wrapper
|
|
546
|
+
// was pushed (`building[0]` for none): a cycle through them has no wrapper
|
|
547
|
+
// to close it and is malformed. Reaching one from inside a wrapper opened
|
|
548
|
+
// later is that wrapper's recursion, so each wrapper starts a fresh set.
|
|
549
|
+
const building = [new Set()];
|
|
550
|
+
// Shallowest stack position referenced by the subtree under construction
|
|
551
|
+
// (Infinity = nothing referenced).
|
|
552
|
+
let minRef = Infinity;
|
|
553
|
+
function build(idx) {
|
|
554
|
+
const pos = stack.indexOf(idx);
|
|
555
|
+
if (pos !== -1) {
|
|
556
|
+
if (pos < minRef)
|
|
557
|
+
minRef = pos;
|
|
596
558
|
return variant("Recursive", variant("ref", BigInt(idx)));
|
|
597
559
|
}
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
if (
|
|
602
|
-
|
|
560
|
+
const done = closed[idx];
|
|
561
|
+
if (done !== undefined)
|
|
562
|
+
return done;
|
|
563
|
+
if (scopes.length > 0) {
|
|
564
|
+
const scoped = scopes[scopes.length - 1].get(idx);
|
|
565
|
+
if (scoped !== undefined) {
|
|
566
|
+
if (scoped.minRef < minRef)
|
|
567
|
+
minRef = scoped.minRef;
|
|
568
|
+
return scoped.value;
|
|
569
|
+
}
|
|
603
570
|
}
|
|
604
571
|
const entry = parsed[idx];
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
572
|
+
if (entry.tag <= TAG_NEVER) {
|
|
573
|
+
const primitive = PRIMITIVE_ETV[entry.tag];
|
|
574
|
+
closed[idx] = primitive;
|
|
575
|
+
return primitive;
|
|
576
|
+
}
|
|
577
|
+
const depth = stack.length;
|
|
578
|
+
const outerMinRef = minRef;
|
|
579
|
+
minRef = Infinity;
|
|
580
|
+
let result;
|
|
608
581
|
if (entry.tag === TAG_RECURSIVE) {
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
const wrapped = variant("Recursive", variant("wrapper", { id: BigInt(idx), inner }));
|
|
623
|
-
table[idx] = wrapped;
|
|
624
|
-
if (closed)
|
|
625
|
-
closedWrappers.add(idx);
|
|
626
|
-
return wrapped;
|
|
582
|
+
stack.push(idx);
|
|
583
|
+
scopes.push(new Map());
|
|
584
|
+
building.push(new Set());
|
|
585
|
+
let inner;
|
|
586
|
+
try {
|
|
587
|
+
inner = build(entry.childIndices[0]);
|
|
588
|
+
}
|
|
589
|
+
finally {
|
|
590
|
+
stack.pop();
|
|
591
|
+
scopes.pop();
|
|
592
|
+
building.pop();
|
|
593
|
+
}
|
|
594
|
+
result = variant("Recursive", variant("wrapper", { id: BigInt(idx), inner }));
|
|
627
595
|
}
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
596
|
+
else {
|
|
597
|
+
const open = building[building.length - 1];
|
|
598
|
+
if (open.has(idx)) {
|
|
599
|
+
throw new Error(`Type table entry ${idx} refers to itself without a Recursive wrapper`);
|
|
600
|
+
}
|
|
601
|
+
open.add(idx);
|
|
602
|
+
try {
|
|
603
|
+
result = buildCompound(entry);
|
|
604
|
+
}
|
|
605
|
+
finally {
|
|
606
|
+
open.delete(idx);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
const mine = minRef;
|
|
610
|
+
// Closed ⇔ nothing under this entry referenced a wrapper open above it
|
|
611
|
+
// (a wrapper's own self-references sit at `depth`, so it stays closed).
|
|
612
|
+
if (mine >= depth) {
|
|
613
|
+
closed[idx] = result;
|
|
632
614
|
}
|
|
633
|
-
|
|
634
|
-
|
|
615
|
+
else {
|
|
616
|
+
scopes[scopes.length - 1].set(idx, { value: result, minRef: mine });
|
|
617
|
+
}
|
|
618
|
+
minRef = Math.min(outerMinRef, mine);
|
|
635
619
|
return result;
|
|
636
620
|
}
|
|
637
|
-
|
|
638
|
-
* Build a compound type entry, pushing to the depth stack.
|
|
639
|
-
* If recursiveOwner is set, self-references to that index (the Recursive
|
|
640
|
-
* wrapper) will be found on the stack at the position where this compound
|
|
641
|
-
* type is pushed.
|
|
642
|
-
*/
|
|
643
|
-
function buildCompound(idx, depthStack, recursiveOwner) {
|
|
644
|
-
const entry = parsed[idx];
|
|
645
|
-
// Push: the index that self-references should find.
|
|
646
|
-
// If this compound is the inner type of a Recursive wrapper, push the
|
|
647
|
-
// wrapper's index so Recursive(depth) resolves to it.
|
|
648
|
-
const stackEntry = recursiveOwner ?? idx;
|
|
649
|
-
depthStack.push(stackEntry);
|
|
650
|
-
let result;
|
|
621
|
+
function buildCompound(entry) {
|
|
651
622
|
switch (entry.tag) {
|
|
652
|
-
case TAG_VARIANT:
|
|
653
|
-
const cases = entry.names.map((name, i) => ({
|
|
654
|
-
name, type: build(entry.childIndices[i], depthStack),
|
|
655
|
-
}));
|
|
656
|
-
result = variant("Variant", cases);
|
|
657
|
-
break;
|
|
658
|
-
}
|
|
623
|
+
case TAG_VARIANT:
|
|
659
624
|
case TAG_STRUCT: {
|
|
660
|
-
const
|
|
661
|
-
|
|
662
|
-
}));
|
|
663
|
-
result = variant("Struct", fields);
|
|
664
|
-
break;
|
|
625
|
+
const members = entry.names.map((name, i) => ({ name, type: build(entry.childIndices[i]) }));
|
|
626
|
+
return variant(TAG_TO_CASE[entry.tag], members);
|
|
665
627
|
}
|
|
666
628
|
case TAG_ARRAY:
|
|
667
|
-
result = variant("Array", build(entry.childIndices[0], depthStack));
|
|
668
|
-
break;
|
|
669
|
-
case TAG_DICT:
|
|
670
|
-
result = variant("Dict", {
|
|
671
|
-
key: build(entry.childIndices[0], depthStack),
|
|
672
|
-
value: build(entry.childIndices[1], depthStack),
|
|
673
|
-
});
|
|
674
|
-
break;
|
|
675
629
|
case TAG_SET:
|
|
676
|
-
result = variant("Set", build(entry.childIndices[0], depthStack));
|
|
677
|
-
break;
|
|
678
630
|
case TAG_REF:
|
|
679
|
-
result = variant("Ref", build(entry.childIndices[0], depthStack));
|
|
680
|
-
break;
|
|
681
631
|
case TAG_VECTOR:
|
|
682
|
-
result = variant("Vector", build(entry.childIndices[0], depthStack));
|
|
683
|
-
break;
|
|
684
632
|
case TAG_MATRIX:
|
|
685
|
-
|
|
686
|
-
|
|
633
|
+
return variant(TAG_TO_CASE[entry.tag], build(entry.childIndices[0]));
|
|
634
|
+
case TAG_DICT: {
|
|
635
|
+
const key = build(entry.childIndices[0]);
|
|
636
|
+
const value = build(entry.childIndices[1]);
|
|
637
|
+
return variant("Dict", { key, value });
|
|
638
|
+
}
|
|
687
639
|
case TAG_FUNCTION:
|
|
688
640
|
case TAG_ASYNC_FUNCTION: {
|
|
689
641
|
const n = entry.childIndices.length - 1;
|
|
690
642
|
const inputs = [];
|
|
691
643
|
for (let i = 0; i < n; i++)
|
|
692
|
-
inputs.push(build(entry.childIndices[i]
|
|
693
|
-
const output = build(entry.childIndices[n]
|
|
694
|
-
|
|
695
|
-
break;
|
|
644
|
+
inputs.push(build(entry.childIndices[i]));
|
|
645
|
+
const output = build(entry.childIndices[n]);
|
|
646
|
+
return variant(TAG_TO_CASE[entry.tag], { inputs, output });
|
|
696
647
|
}
|
|
697
648
|
default:
|
|
698
649
|
throw new Error(`Unexpected compound tag 0x${entry.tag.toString(16)}`);
|
|
699
650
|
}
|
|
700
|
-
depthStack.pop();
|
|
701
|
-
return result;
|
|
702
651
|
}
|
|
703
|
-
// Build ALL entries (not just root-reachable)
|
|
704
|
-
// capture types are needed for function IR type restoration
|
|
652
|
+
// Build ALL entries (not just root-reachable) in their closed form. Extra
|
|
653
|
+
// entries from IR capture types are needed for function IR type restoration
|
|
654
|
+
// during v4 decode.
|
|
705
655
|
for (let i = 0; i < parsed.length; i++) {
|
|
706
|
-
if (
|
|
707
|
-
build(i
|
|
656
|
+
if (closed[i] === undefined)
|
|
657
|
+
build(i);
|
|
708
658
|
}
|
|
709
|
-
return
|
|
659
|
+
return closed;
|
|
710
660
|
}
|
|
711
661
|
//# sourceMappingURL=type-table.js.map
|