typesea 0.1.0 → 0.3.0
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/CHANGELOG.md +85 -6
- package/README.md +143 -28
- package/dist/adapters/index.d.ts +50 -8
- package/dist/adapters/index.d.ts.map +1 -1
- package/dist/adapters/index.js +169 -48
- package/dist/aot/index.d.ts +19 -3
- package/dist/aot/index.d.ts.map +1 -1
- package/dist/aot/index.js +115 -17
- package/dist/async/index.d.ts +28 -56
- package/dist/async/index.d.ts.map +1 -1
- package/dist/async/index.js +94 -37
- package/dist/builders/composite.d.ts +43 -9
- package/dist/builders/composite.d.ts.map +1 -1
- package/dist/builders/composite.js +100 -17
- package/dist/builders/index.d.ts +8 -5
- package/dist/builders/index.d.ts.map +1 -1
- package/dist/builders/index.js +7 -4
- package/dist/builders/modifier.d.ts +36 -5
- package/dist/builders/modifier.d.ts.map +1 -1
- package/dist/builders/modifier.js +52 -5
- package/dist/builders/object/guard.d.ts +72 -24
- package/dist/builders/object/guard.d.ts.map +1 -1
- package/dist/builders/object/guard.js +139 -29
- package/dist/builders/object/index.d.ts +4 -2
- package/dist/builders/object/index.d.ts.map +1 -1
- package/dist/builders/object/index.js +3 -1
- package/dist/builders/object/schema.d.ts +88 -11
- package/dist/builders/object/schema.d.ts.map +1 -1
- package/dist/builders/object/schema.js +290 -23
- package/dist/builders/object/types.d.ts +20 -31
- package/dist/builders/object/types.d.ts.map +1 -1
- package/dist/builders/object/types.js +2 -0
- package/dist/builders/runtime.d.ts +40 -0
- package/dist/builders/runtime.d.ts.map +1 -0
- package/dist/builders/runtime.js +150 -0
- package/dist/builders/scalar.d.ts +49 -9
- package/dist/builders/scalar.d.ts.map +1 -1
- package/dist/builders/scalar.js +87 -9
- package/dist/builders/table.d.ts +35 -5
- package/dist/builders/table.d.ts.map +1 -1
- package/dist/builders/table.js +35 -5
- package/dist/builders/types.d.ts +20 -4
- package/dist/builders/types.d.ts.map +1 -1
- package/dist/builders/types.js +2 -0
- package/dist/compile/check-composite.d.ts +25 -2
- package/dist/compile/check-composite.d.ts.map +1 -1
- package/dist/compile/check-composite.js +699 -27
- package/dist/compile/check-scalar.d.ts +88 -0
- package/dist/compile/check-scalar.d.ts.map +1 -1
- package/dist/compile/check-scalar.js +570 -3
- package/dist/compile/check.d.ts +12 -0
- package/dist/compile/check.d.ts.map +1 -1
- package/dist/compile/check.js +62 -3
- package/dist/compile/context.d.ts +47 -9
- package/dist/compile/context.d.ts.map +1 -1
- package/dist/compile/context.js +53 -8
- package/dist/compile/first.d.ts +26 -0
- package/dist/compile/first.d.ts.map +1 -0
- package/dist/compile/first.js +850 -0
- package/dist/compile/graph-predicate.d.ts +4 -2
- package/dist/compile/graph-predicate.d.ts.map +1 -1
- package/dist/compile/graph-predicate.js +2272 -165
- package/dist/compile/guard.d.ts +16 -24
- package/dist/compile/guard.d.ts.map +1 -1
- package/dist/compile/guard.js +202 -72
- package/dist/compile/index.d.ts +3 -1
- package/dist/compile/index.d.ts.map +1 -1
- package/dist/compile/index.js +2 -0
- package/dist/compile/issue.d.ts +110 -0
- package/dist/compile/issue.d.ts.map +1 -1
- package/dist/compile/issue.js +184 -1
- package/dist/compile/names.d.ts +12 -2
- package/dist/compile/names.d.ts.map +1 -1
- package/dist/compile/names.js +19 -3
- package/dist/compile/predicate.d.ts +24 -0
- package/dist/compile/predicate.d.ts.map +1 -1
- package/dist/compile/predicate.js +287 -10
- package/dist/compile/runtime.d.ts +100 -13
- package/dist/compile/runtime.d.ts.map +1 -1
- package/dist/compile/runtime.js +56 -6
- package/dist/compile/source.d.ts +10 -2
- package/dist/compile/source.d.ts.map +1 -1
- package/dist/compile/source.js +385 -26
- package/dist/compile/types.d.ts +22 -0
- package/dist/compile/types.d.ts.map +1 -1
- package/dist/compile/types.js +2 -0
- package/dist/decoder/index.d.ts +92 -46
- package/dist/decoder/index.d.ts.map +1 -1
- package/dist/decoder/index.js +266 -39
- package/dist/evaluate/check-composite.d.ts +111 -2
- package/dist/evaluate/check-composite.d.ts.map +1 -1
- package/dist/evaluate/check-composite.js +343 -8
- package/dist/evaluate/check-scalar.d.ts +25 -0
- package/dist/evaluate/check-scalar.d.ts.map +1 -1
- package/dist/evaluate/check-scalar.js +124 -3
- package/dist/evaluate/check.d.ts +7 -0
- package/dist/evaluate/check.d.ts.map +1 -1
- package/dist/evaluate/check.js +62 -4
- package/dist/evaluate/index.d.ts +2 -0
- package/dist/evaluate/index.d.ts.map +1 -1
- package/dist/evaluate/index.js +2 -0
- package/dist/evaluate/issue.d.ts +11 -1
- package/dist/evaluate/issue.d.ts.map +1 -1
- package/dist/evaluate/issue.js +15 -1
- package/dist/evaluate/predicate.d.ts +16 -5
- package/dist/evaluate/predicate.d.ts.map +1 -1
- package/dist/evaluate/predicate.js +20 -5
- package/dist/evaluate/shared.d.ts +78 -13
- package/dist/evaluate/shared.d.ts.map +1 -1
- package/dist/evaluate/shared.js +101 -8
- package/dist/evaluate/state.d.ts +35 -13
- package/dist/evaluate/state.d.ts.map +1 -1
- package/dist/evaluate/state.js +35 -2
- package/dist/guard/array.d.ts +48 -0
- package/dist/guard/array.d.ts.map +1 -0
- package/dist/guard/array.js +84 -0
- package/dist/guard/base.d.ts +111 -31
- package/dist/guard/base.d.ts.map +1 -1
- package/dist/guard/base.js +165 -32
- package/dist/guard/date.d.ts +34 -0
- package/dist/guard/date.d.ts.map +1 -0
- package/dist/guard/date.js +60 -0
- package/dist/guard/error.d.ts +10 -5
- package/dist/guard/error.d.ts.map +1 -1
- package/dist/guard/error.js +10 -5
- package/dist/guard/index.d.ts +4 -0
- package/dist/guard/index.d.ts.map +1 -1
- package/dist/guard/index.js +4 -0
- package/dist/guard/number.d.ts +86 -11
- package/dist/guard/number.d.ts.map +1 -1
- package/dist/guard/number.js +159 -11
- package/dist/guard/props.d.ts +27 -3
- package/dist/guard/props.d.ts.map +1 -1
- package/dist/guard/props.js +27 -3
- package/dist/guard/read.d.ts +115 -10
- package/dist/guard/read.d.ts.map +1 -1
- package/dist/guard/read.js +185 -10
- package/dist/guard/registry.d.ts +12 -2
- package/dist/guard/registry.d.ts.map +1 -1
- package/dist/guard/registry.js +15 -3
- package/dist/guard/string.d.ts +115 -13
- package/dist/guard/string.d.ts.map +1 -1
- package/dist/guard/string.js +250 -13
- package/dist/guard/types.d.ts +110 -40
- package/dist/guard/types.d.ts.map +1 -1
- package/dist/guard/types.js +2 -0
- package/dist/index.d.ts +5 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/internal/index.d.ts +42 -6
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +51 -8
- package/dist/ir/builder.d.ts +17 -127
- package/dist/ir/builder.d.ts.map +1 -1
- package/dist/ir/builder.js +80 -137
- package/dist/ir/freeze.d.ts +4 -0
- package/dist/ir/freeze.d.ts.map +1 -1
- package/dist/ir/freeze.js +66 -0
- package/dist/ir/index.d.ts +3 -1
- package/dist/ir/index.d.ts.map +1 -1
- package/dist/ir/index.js +2 -0
- package/dist/ir/regexp.d.ts +2 -0
- package/dist/ir/regexp.d.ts.map +1 -1
- package/dist/ir/regexp.js +2 -0
- package/dist/ir/types.d.ts +94 -56
- package/dist/ir/types.d.ts.map +1 -1
- package/dist/ir/types.js +2 -0
- package/dist/ir/validate.d.ts +8 -1
- package/dist/ir/validate.d.ts.map +1 -1
- package/dist/ir/validate.js +511 -61
- package/dist/issue/index.d.ts +42 -10
- package/dist/issue/index.d.ts.map +1 -1
- package/dist/issue/index.js +65 -11
- package/dist/json-schema/emit-combinator.d.ts +44 -4
- package/dist/json-schema/emit-combinator.d.ts.map +1 -1
- package/dist/json-schema/emit-combinator.js +44 -4
- package/dist/json-schema/emit-composite.d.ts +16 -2
- package/dist/json-schema/emit-composite.d.ts.map +1 -1
- package/dist/json-schema/emit-composite.js +81 -13
- package/dist/json-schema/emit-scalar.d.ts +26 -3
- package/dist/json-schema/emit-scalar.d.ts.map +1 -1
- package/dist/json-schema/emit-scalar.js +124 -10
- package/dist/json-schema/emit-types.d.ts +11 -1
- package/dist/json-schema/emit-types.d.ts.map +1 -1
- package/dist/json-schema/emit-types.js +2 -0
- package/dist/json-schema/emit.d.ts +12 -1
- package/dist/json-schema/emit.d.ts.map +1 -1
- package/dist/json-schema/emit.js +23 -3
- package/dist/json-schema/freeze.d.ts +13 -2
- package/dist/json-schema/freeze.d.ts.map +1 -1
- package/dist/json-schema/freeze.js +41 -8
- package/dist/json-schema/index.d.ts +16 -2
- package/dist/json-schema/index.d.ts.map +1 -1
- package/dist/json-schema/index.js +23 -3
- package/dist/json-schema/issue.d.ts +4 -1
- package/dist/json-schema/issue.d.ts.map +1 -1
- package/dist/json-schema/issue.js +4 -1
- package/dist/json-schema/read.d.ts +24 -3
- package/dist/json-schema/read.d.ts.map +1 -1
- package/dist/json-schema/read.js +59 -12
- package/dist/json-schema/types.d.ts +45 -16
- package/dist/json-schema/types.d.ts.map +1 -1
- package/dist/json-schema/types.js +2 -0
- package/dist/kind/index.d.ts +40 -28
- package/dist/kind/index.d.ts.map +1 -1
- package/dist/kind/index.js +41 -13
- package/dist/lower/index.d.ts +6 -1
- package/dist/lower/index.d.ts.map +1 -1
- package/dist/lower/index.js +462 -46
- package/dist/message/index.d.ts +64 -10
- package/dist/message/index.d.ts.map +1 -1
- package/dist/message/index.js +155 -17
- package/dist/optimize/algebraic.d.ts +54 -0
- package/dist/optimize/algebraic.d.ts.map +1 -0
- package/dist/optimize/algebraic.js +314 -0
- package/dist/optimize/compact.d.ts +8 -1
- package/dist/optimize/compact.d.ts.map +1 -1
- package/dist/optimize/compact.js +13 -2
- package/dist/optimize/domain.d.ts +16 -0
- package/dist/optimize/domain.d.ts.map +1 -0
- package/dist/optimize/domain.js +619 -0
- package/dist/optimize/fold-boolean.d.ts +17 -2
- package/dist/optimize/fold-boolean.d.ts.map +1 -1
- package/dist/optimize/fold-boolean.js +59 -14
- package/dist/optimize/fold-common.d.ts +43 -8
- package/dist/optimize/fold-common.d.ts.map +1 -1
- package/dist/optimize/fold-common.js +37 -6
- package/dist/optimize/fold-constraints.d.ts +33 -0
- package/dist/optimize/fold-constraints.d.ts.map +1 -0
- package/dist/optimize/fold-constraints.js +484 -0
- package/dist/optimize/fold-scalar.d.ts +98 -13
- package/dist/optimize/fold-scalar.d.ts.map +1 -1
- package/dist/optimize/fold-scalar.js +98 -13
- package/dist/optimize/fold.d.ts +8 -1
- package/dist/optimize/fold.d.ts.map +1 -1
- package/dist/optimize/fold.js +22 -2
- package/dist/optimize/index.d.ts +9 -1
- package/dist/optimize/index.d.ts.map +1 -1
- package/dist/optimize/index.js +18 -3
- package/dist/optimize/map-node.d.ts +3 -1
- package/dist/optimize/map-node.d.ts.map +1 -1
- package/dist/optimize/map-node.js +48 -3
- package/dist/optimize/peephole.d.ts +16 -0
- package/dist/optimize/peephole.d.ts.map +1 -0
- package/dist/optimize/peephole.js +254 -0
- package/dist/optimize/remap.d.ts +2 -0
- package/dist/optimize/remap.d.ts.map +1 -1
- package/dist/optimize/remap.js +2 -0
- package/dist/optimize/rewrite.d.ts +13 -8
- package/dist/optimize/rewrite.d.ts.map +1 -1
- package/dist/optimize/rewrite.js +13 -8
- package/dist/plan/cache.d.ts +9 -3
- package/dist/plan/cache.d.ts.map +1 -1
- package/dist/plan/cache.js +34 -6
- package/dist/plan/index.d.ts +2 -0
- package/dist/plan/index.d.ts.map +1 -1
- package/dist/plan/index.js +2 -0
- package/dist/plan/predicate.d.ts +2 -0
- package/dist/plan/predicate.d.ts.map +1 -1
- package/dist/plan/predicate.js +298 -29
- package/dist/plan/schema-predicate.d.ts +6 -0
- package/dist/plan/schema-predicate.d.ts.map +1 -1
- package/dist/plan/schema-predicate.js +382 -19
- package/dist/plan/types.d.ts +2 -0
- package/dist/plan/types.d.ts.map +1 -1
- package/dist/plan/types.js +2 -0
- package/dist/result/index.d.ts +19 -5
- package/dist/result/index.d.ts.map +1 -1
- package/dist/result/index.js +10 -2
- package/dist/schema/common.d.ts +69 -6
- package/dist/schema/common.d.ts.map +1 -1
- package/dist/schema/common.js +104 -10
- package/dist/schema/freeze.d.ts +4 -0
- package/dist/schema/freeze.d.ts.map +1 -1
- package/dist/schema/freeze.js +40 -0
- package/dist/schema/index.d.ts +5 -2
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js +4 -1
- package/dist/schema/lazy.d.ts +4 -0
- package/dist/schema/lazy.d.ts.map +1 -1
- package/dist/schema/lazy.js +4 -0
- package/dist/schema/literal.d.ts +7 -1
- package/dist/schema/literal.d.ts.map +1 -1
- package/dist/schema/literal.js +7 -1
- package/dist/schema/types.d.ts +109 -100
- package/dist/schema/types.d.ts.map +1 -1
- package/dist/schema/types.js +13 -2
- package/dist/schema/undefined.d.ts +17 -0
- package/dist/schema/undefined.d.ts.map +1 -0
- package/dist/schema/undefined.js +77 -0
- package/dist/schema/validate.d.ts +8 -1
- package/dist/schema/validate.d.ts.map +1 -1
- package/dist/schema/validate.js +255 -57
- package/docs/api.md +128 -8
- package/docs/assets/benchmark-headline.svg +163 -0
- package/docs/engine-notes.md +62 -15
- package/docs/index.html +1340 -702
- package/docs/ko/api.md +375 -0
- package/docs/ko/engine-notes.md +156 -0
- package/docs/ko/readme.md +378 -0
- package/package.json +66 -65
package/dist/ir/validate.js
CHANGED
|
@@ -1,53 +1,117 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @file validate.ts
|
|
3
3
|
* @brief Runtime validation for graph objects.
|
|
4
|
+
* @details Graph validation protects optimizer and compiler passes before they assume dense
|
|
5
|
+
* node ids and valid dependency edges.
|
|
4
6
|
*/
|
|
5
|
-
import { NodeTag } from "../kind/index.js";
|
|
7
|
+
import { ArrayCheckTag, NodeTag, ObjectModeTag, PresenceTag } from "../kind/index.js";
|
|
6
8
|
import { isLiteralValue, isSchemaValue } from "../schema/index.js";
|
|
7
9
|
import { isPlainRegExp } from "./regexp.js";
|
|
8
10
|
/**
|
|
9
|
-
* @brief
|
|
11
|
+
* @brief Validate an unknown value as a frozen-style Sea-of-Nodes graph.
|
|
12
|
+
* @param value Candidate graph object supplied to graph consumers.
|
|
13
|
+
* @returns True when the full graph has a dense arena and well-formed nodes.
|
|
14
|
+
* @details Graph objects can cross public introspection boundaries. Validation
|
|
15
|
+
* therefore rejects accessors, sparse arrays, and prototype-backed fields before
|
|
16
|
+
* optimization or freezing reads graph metadata.
|
|
10
17
|
*/
|
|
11
18
|
export function isGraphValue(value) {
|
|
19
|
+
return isGraphValueInner(value, makeGraphValidationState());
|
|
20
|
+
}
|
|
21
|
+
const missingDataProperty = Symbol("typesea.ir.missingDataProperty");
|
|
22
|
+
/**
|
|
23
|
+
* @brief Allocate traversal state for one root graph validation.
|
|
24
|
+
* @details Graph validation protects optimizer and compiler passes before they assume dense
|
|
25
|
+
* node ids and valid dependency edges.
|
|
26
|
+
* @returns Empty active and completed graph sets.
|
|
27
|
+
*/
|
|
28
|
+
function makeGraphValidationState() {
|
|
29
|
+
return {
|
|
30
|
+
active: new WeakSet(),
|
|
31
|
+
done: new WeakSet()
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* @brief Validate one graph object and its nested child graphs.
|
|
36
|
+
* @details Graph validation protects optimizer and compiler passes before they assume dense
|
|
37
|
+
* node ids and valid dependency edges.
|
|
38
|
+
* @param value Candidate graph object.
|
|
39
|
+
* @param state Shared recursion state.
|
|
40
|
+
* @returns True when entry/result ids and every arena node are valid.
|
|
41
|
+
*/
|
|
42
|
+
function isGraphValueInner(value, state) {
|
|
12
43
|
if (!isRecord(value)) {
|
|
13
44
|
return false;
|
|
14
45
|
}
|
|
15
|
-
|
|
46
|
+
if (state.done.has(value)) {
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
if (state.active.has(value)) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
state.active.add(value);
|
|
53
|
+
/*
|
|
54
|
+
* `nodes`, `entry`, and `result` must be own data slots. Optimizer callers
|
|
55
|
+
* may pass graph-like values, and bracket reads would otherwise consult a
|
|
56
|
+
* hostile prototype before the shape is trusted.
|
|
57
|
+
*/
|
|
58
|
+
const nodes = readOwnDataProperty(value, "nodes");
|
|
16
59
|
if (!isUnknownArray(nodes)) {
|
|
17
60
|
return false;
|
|
18
61
|
}
|
|
19
|
-
|
|
20
|
-
|
|
62
|
+
const entryId = readOwnDataProperty(value, "entry");
|
|
63
|
+
const resultId = readOwnDataProperty(value, "result");
|
|
64
|
+
if (!isNodeId(entryId, nodes.length) ||
|
|
65
|
+
!isNodeId(resultId, nodes.length)) {
|
|
21
66
|
return false;
|
|
22
67
|
}
|
|
23
68
|
for (let index = 0; index < nodes.length; index += 1) {
|
|
24
|
-
if (!isGraphNodeValue(nodes[index], index, nodes.length)) {
|
|
69
|
+
if (!isGraphNodeValue(nodes[index], index, nodes.length, state)) {
|
|
25
70
|
return false;
|
|
26
71
|
}
|
|
27
72
|
}
|
|
28
|
-
const entry = nodes[
|
|
29
|
-
const result = nodes[
|
|
30
|
-
|
|
31
|
-
|
|
73
|
+
const entry = nodes[entryId];
|
|
74
|
+
const result = nodes[resultId];
|
|
75
|
+
const valid = isRecord(entry) &&
|
|
76
|
+
readOwnDataProperty(entry, "tag") === NodeTag.Start &&
|
|
77
|
+
isRecord(result) &&
|
|
78
|
+
readOwnDataProperty(result, "tag") === NodeTag.Return;
|
|
79
|
+
state.active.delete(value);
|
|
80
|
+
if (valid) {
|
|
81
|
+
state.done.add(value);
|
|
82
|
+
}
|
|
83
|
+
return valid;
|
|
32
84
|
}
|
|
33
85
|
/**
|
|
34
|
-
* @brief
|
|
86
|
+
* @brief Validate one arena node at its expected id.
|
|
87
|
+
* @param value Candidate node object.
|
|
88
|
+
* @param index Arena slot the node occupies.
|
|
89
|
+
* @param nodeCount Total arena size for dependency bounds.
|
|
90
|
+
* @param state Shared recursion state for child graphs.
|
|
91
|
+
* @returns True when the node tag and payload agree with its dependency vector.
|
|
92
|
+
* @details Every node stores both `deps` and named edge fields. The redundant
|
|
93
|
+
* representation is checked here so later passes can trust either view.
|
|
35
94
|
*/
|
|
36
|
-
function isGraphNodeValue(value, index, nodeCount) {
|
|
37
|
-
if (!isRecord(value) || value
|
|
95
|
+
function isGraphNodeValue(value, index, nodeCount, state) {
|
|
96
|
+
if (!isRecord(value) || readOwnDataProperty(value, "id") !== index) {
|
|
38
97
|
return false;
|
|
39
98
|
}
|
|
40
|
-
const deps = value
|
|
99
|
+
const deps = readOwnDataProperty(value, "deps");
|
|
41
100
|
if (!isNodeIdArray(deps, nodeCount)) {
|
|
42
101
|
return false;
|
|
43
102
|
}
|
|
44
|
-
|
|
103
|
+
const tag = readOwnDataProperty(value, "tag");
|
|
104
|
+
/*
|
|
105
|
+
* The tag switch is deliberately closed. Unknown node tags are rejected at
|
|
106
|
+
* the boundary so optimizer passes can stay exhaustive over NodeTag.
|
|
107
|
+
*/
|
|
108
|
+
switch (tag) {
|
|
45
109
|
case NodeTag.Start:
|
|
46
110
|
case NodeTag.Param:
|
|
47
111
|
case NodeTag.Const:
|
|
48
112
|
return isLeafNodeValue(value, deps);
|
|
49
113
|
case NodeTag.GetProp:
|
|
50
|
-
return typeof value
|
|
114
|
+
return typeof readOwnDataProperty(value, "key") === "string" &&
|
|
51
115
|
isSingleDepNode(value, deps, "object", nodeCount);
|
|
52
116
|
case NodeTag.IsString:
|
|
53
117
|
case NodeTag.IsNumber:
|
|
@@ -66,45 +130,57 @@ function isGraphNodeValue(value, index, nodeCount) {
|
|
|
66
130
|
case NodeTag.Lte:
|
|
67
131
|
return isTwoDepNode(value, deps, "left", "right", nodeCount);
|
|
68
132
|
case NodeTag.StringMin:
|
|
69
|
-
case NodeTag.StringMax:
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
133
|
+
case NodeTag.StringMax: {
|
|
134
|
+
const bound = readOwnDataProperty(value, "bound");
|
|
135
|
+
return typeof bound === "number" &&
|
|
136
|
+
Number.isInteger(bound) &&
|
|
137
|
+
bound >= 0 &&
|
|
73
138
|
isSingleDepNode(value, deps, "value", nodeCount);
|
|
139
|
+
}
|
|
74
140
|
case NodeTag.Regex:
|
|
75
|
-
return isPlainRegExp(value
|
|
76
|
-
typeof value
|
|
141
|
+
return isPlainRegExp(readOwnDataProperty(value, "regex")) &&
|
|
142
|
+
typeof readOwnDataProperty(value, "name") === "string" &&
|
|
77
143
|
isSingleDepNode(value, deps, "value", nodeCount);
|
|
78
144
|
case NodeTag.HasOwn:
|
|
79
145
|
case NodeTag.HasOwnData:
|
|
80
|
-
return typeof value
|
|
146
|
+
return typeof readOwnDataProperty(value, "key") === "string" &&
|
|
81
147
|
isSingleDepNode(value, deps, "object", nodeCount);
|
|
82
148
|
case NodeTag.StrictKeys:
|
|
83
|
-
return isStringArray(value
|
|
149
|
+
return isStringArray(readOwnDataProperty(value, "keys")) &&
|
|
84
150
|
isSingleDepNode(value, deps, "object", nodeCount);
|
|
85
151
|
case NodeTag.ArrayEvery:
|
|
86
|
-
return isSchemaValue(value
|
|
152
|
+
return isSchemaValue(readOwnDataProperty(value, "item")) &&
|
|
153
|
+
isArrayChecks(readOwnDataProperty(value, "checks")) &&
|
|
154
|
+
isGraphValueInner(readOwnDataProperty(value, "itemGraph"), state) &&
|
|
87
155
|
isSingleDepNode(value, deps, "value", nodeCount);
|
|
88
156
|
case NodeTag.TupleItems:
|
|
89
|
-
return
|
|
157
|
+
return isTupleItemGraphsAligned(value, state) &&
|
|
90
158
|
isSingleDepNode(value, deps, "value", nodeCount);
|
|
91
159
|
case NodeTag.RecordEvery:
|
|
92
|
-
return isSchemaValue(value
|
|
160
|
+
return isSchemaValue(readOwnDataProperty(value, "item")) &&
|
|
161
|
+
isGraphValueInner(readOwnDataProperty(value, "itemGraph"), state) &&
|
|
93
162
|
isSingleDepNode(value, deps, "value", nodeCount);
|
|
94
163
|
case NodeTag.DiscriminantDispatch:
|
|
95
|
-
return
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
value
|
|
164
|
+
return isDiscriminantDispatchNode(value, state) &&
|
|
165
|
+
isSingleDepNode(value, deps, "value", nodeCount);
|
|
166
|
+
case NodeTag.ObjectShape:
|
|
167
|
+
return isObjectShapePayload(value, state) &&
|
|
168
|
+
isSingleDepNode(value, deps, "value", nodeCount);
|
|
169
|
+
case NodeTag.UnionDispatch:
|
|
170
|
+
return isUnionDispatchNode(value, state) &&
|
|
171
|
+
isSingleDepNode(value, deps, "value", nodeCount);
|
|
172
|
+
case NodeTag.PrimitiveUnion:
|
|
173
|
+
return isPrimitiveUnionNode(value, state) &&
|
|
100
174
|
isSingleDepNode(value, deps, "value", nodeCount);
|
|
101
175
|
case NodeTag.SchemaCheck:
|
|
102
|
-
return isSchemaValue(value
|
|
176
|
+
return isSchemaValue(readOwnDataProperty(value, "schema")) &&
|
|
103
177
|
isSingleDepNode(value, deps, "value", nodeCount);
|
|
104
178
|
case NodeTag.And:
|
|
105
|
-
case NodeTag.Or:
|
|
106
|
-
|
|
107
|
-
|
|
179
|
+
case NodeTag.Or: {
|
|
180
|
+
const values = readOwnDataProperty(value, "values");
|
|
181
|
+
return isNodeIdArray(values, nodeCount) &&
|
|
182
|
+
sameNodeIds(deps, values);
|
|
183
|
+
}
|
|
108
184
|
case NodeTag.Return:
|
|
109
185
|
return isTwoDepNode(value, deps, "control", "value", nodeCount);
|
|
110
186
|
default:
|
|
@@ -112,43 +188,102 @@ function isGraphNodeValue(value, index, nodeCount) {
|
|
|
112
188
|
}
|
|
113
189
|
}
|
|
114
190
|
/**
|
|
115
|
-
* @brief
|
|
191
|
+
* @brief Validate array length metadata carried by ArrayEvery nodes.
|
|
192
|
+
* @param value Candidate check vector.
|
|
193
|
+
* @returns True when every entry is a supported non-negative integer bound.
|
|
194
|
+
*/
|
|
195
|
+
function isArrayChecks(value) {
|
|
196
|
+
if (!isUnknownArray(value)) {
|
|
197
|
+
return false;
|
|
198
|
+
}
|
|
199
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
200
|
+
const check = value[index];
|
|
201
|
+
if (!isRecord(check)) {
|
|
202
|
+
return false;
|
|
203
|
+
}
|
|
204
|
+
switch (readOwnDataProperty(check, "tag")) {
|
|
205
|
+
case ArrayCheckTag.Min:
|
|
206
|
+
case ArrayCheckTag.Max: {
|
|
207
|
+
const bound = readOwnDataProperty(check, "value");
|
|
208
|
+
if (typeof bound !== "number" || !Number.isInteger(bound) || bound < 0) {
|
|
209
|
+
return false;
|
|
210
|
+
}
|
|
211
|
+
break;
|
|
212
|
+
}
|
|
213
|
+
default:
|
|
214
|
+
return false;
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return true;
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* @brief Validate payloads for dependency-free nodes.
|
|
221
|
+
* @details Graph validation protects optimizer and compiler passes before they assume dense
|
|
222
|
+
* node ids and valid dependency edges.
|
|
223
|
+
* @param value Candidate node record.
|
|
224
|
+
* @param deps Dependency vector already read from the node.
|
|
225
|
+
* @returns True when the leaf payload matches Start, Param, or Const.
|
|
116
226
|
*/
|
|
117
227
|
function isLeafNodeValue(value, deps) {
|
|
118
228
|
if (deps.length !== 0) {
|
|
119
229
|
return false;
|
|
120
230
|
}
|
|
121
|
-
switch (value
|
|
231
|
+
switch (readOwnDataProperty(value, "tag")) {
|
|
122
232
|
case NodeTag.Start:
|
|
123
233
|
return true;
|
|
124
234
|
case NodeTag.Param:
|
|
125
|
-
return typeof value
|
|
126
|
-
case NodeTag.Const:
|
|
127
|
-
|
|
235
|
+
return typeof readOwnDataProperty(value, "name") === "string";
|
|
236
|
+
case NodeTag.Const: {
|
|
237
|
+
const literal = readOwnDataProperty(value, "value");
|
|
238
|
+
return !isMissingDataProperty(literal) && isLiteralValue(literal);
|
|
239
|
+
}
|
|
128
240
|
default:
|
|
129
241
|
return false;
|
|
130
242
|
}
|
|
131
243
|
}
|
|
132
244
|
/**
|
|
133
|
-
* @brief
|
|
245
|
+
* @brief Validate a node whose named edge mirrors one dependency.
|
|
246
|
+
* @details Graph validation protects optimizer and compiler passes before they assume dense
|
|
247
|
+
* node ids and valid dependency edges.
|
|
248
|
+
* @param value Candidate node record.
|
|
249
|
+
* @param deps Dependency vector from the same node.
|
|
250
|
+
* @param field Named edge field that must equal deps[0].
|
|
251
|
+
* @param nodeCount Total arena size for bounds.
|
|
252
|
+
* @returns True when the edge is in range and exactly mirrors the dependency.
|
|
134
253
|
*/
|
|
135
254
|
function isSingleDepNode(value, deps, field, nodeCount) {
|
|
255
|
+
const fieldValue = readOwnDataProperty(value, field);
|
|
136
256
|
return deps.length === 1 &&
|
|
137
|
-
isNodeId(
|
|
138
|
-
deps[0] ===
|
|
257
|
+
isNodeId(fieldValue, nodeCount) &&
|
|
258
|
+
deps[0] === fieldValue;
|
|
139
259
|
}
|
|
140
260
|
/**
|
|
141
|
-
* @brief
|
|
261
|
+
* @brief Validate a node whose named edges mirror two dependencies.
|
|
262
|
+
* @details Graph validation protects optimizer and compiler passes before they assume dense
|
|
263
|
+
* node ids and valid dependency edges.
|
|
264
|
+
* @param value Candidate node record.
|
|
265
|
+
* @param deps Dependency vector from the same node.
|
|
266
|
+
* @param leftField First named edge field.
|
|
267
|
+
* @param rightField Second named edge field.
|
|
268
|
+
* @param nodeCount Total arena size for bounds.
|
|
269
|
+
* @returns True when both named edges are in range and mirror `deps`.
|
|
142
270
|
*/
|
|
143
271
|
function isTwoDepNode(value, deps, leftField, rightField, nodeCount) {
|
|
272
|
+
const left = readOwnDataProperty(value, leftField);
|
|
273
|
+
const right = readOwnDataProperty(value, rightField);
|
|
144
274
|
return deps.length === 2 &&
|
|
145
|
-
isNodeId(
|
|
146
|
-
isNodeId(
|
|
147
|
-
deps[0] ===
|
|
148
|
-
deps[1] ===
|
|
275
|
+
isNodeId(left, nodeCount) &&
|
|
276
|
+
isNodeId(right, nodeCount) &&
|
|
277
|
+
deps[0] === left &&
|
|
278
|
+
deps[1] === right;
|
|
149
279
|
}
|
|
150
280
|
/**
|
|
151
|
-
* @brief
|
|
281
|
+
* @brief Validate a graph-local arena index.
|
|
282
|
+
* @details Graph validation protects optimizer and compiler passes before they assume dense
|
|
283
|
+
* node ids and valid dependency edges.
|
|
284
|
+
* @param value Candidate node id.
|
|
285
|
+
* @param nodeCount Total arena size.
|
|
286
|
+
* @returns True when the id is an integer inside the arena.
|
|
152
287
|
*/
|
|
153
288
|
function isNodeId(value, nodeCount) {
|
|
154
289
|
return typeof value === "number" &&
|
|
@@ -157,7 +292,12 @@ function isNodeId(value, nodeCount) {
|
|
|
157
292
|
value < nodeCount;
|
|
158
293
|
}
|
|
159
294
|
/**
|
|
160
|
-
* @brief
|
|
295
|
+
* @brief Validate a dense dependency vector.
|
|
296
|
+
* @details Graph validation protects optimizer and compiler passes before they assume dense
|
|
297
|
+
* node ids and valid dependency edges.
|
|
298
|
+
* @param value Candidate dependency list.
|
|
299
|
+
* @param nodeCount Total arena size for every dependency.
|
|
300
|
+
* @returns True when every dependency points inside the arena.
|
|
161
301
|
*/
|
|
162
302
|
function isNodeIdArray(value, nodeCount) {
|
|
163
303
|
if (!isUnknownArray(value)) {
|
|
@@ -171,7 +311,12 @@ function isNodeIdArray(value, nodeCount) {
|
|
|
171
311
|
return true;
|
|
172
312
|
}
|
|
173
313
|
/**
|
|
174
|
-
* @brief
|
|
314
|
+
* @brief Compare two dependency vectors without allocating.
|
|
315
|
+
* @details Graph validation protects optimizer and compiler passes before they assume dense
|
|
316
|
+
* node ids and valid dependency edges.
|
|
317
|
+
* @param left First dependency vector.
|
|
318
|
+
* @param right Second dependency vector.
|
|
319
|
+
* @returns True when both vectors contain the same node ids in the same order.
|
|
175
320
|
*/
|
|
176
321
|
function sameNodeIds(left, right) {
|
|
177
322
|
if (left.length !== right.length) {
|
|
@@ -185,7 +330,11 @@ function sameNodeIds(left, right) {
|
|
|
185
330
|
return true;
|
|
186
331
|
}
|
|
187
332
|
/**
|
|
188
|
-
* @brief
|
|
333
|
+
* @brief Validate a dense vector of graph-owned strings.
|
|
334
|
+
* @details Graph validation protects optimizer and compiler passes before they assume dense
|
|
335
|
+
* node ids and valid dependency edges.
|
|
336
|
+
* @param value Candidate string vector.
|
|
337
|
+
* @returns True when every slot is a string.
|
|
189
338
|
*/
|
|
190
339
|
function isStringArray(value) {
|
|
191
340
|
if (!isUnknownArray(value)) {
|
|
@@ -199,7 +348,11 @@ function isStringArray(value) {
|
|
|
199
348
|
return true;
|
|
200
349
|
}
|
|
201
350
|
/**
|
|
202
|
-
* @brief
|
|
351
|
+
* @brief Validate a dense vector of embedded schema payloads.
|
|
352
|
+
* @details Graph validation protects optimizer and compiler passes before they assume dense
|
|
353
|
+
* node ids and valid dependency edges.
|
|
354
|
+
* @param value Candidate schema vector.
|
|
355
|
+
* @returns True when every slot is accepted by schema validation.
|
|
203
356
|
*/
|
|
204
357
|
function isSchemaArray(value) {
|
|
205
358
|
if (!isUnknownArray(value)) {
|
|
@@ -213,7 +366,249 @@ function isSchemaArray(value) {
|
|
|
213
366
|
return true;
|
|
214
367
|
}
|
|
215
368
|
/**
|
|
216
|
-
* @brief
|
|
369
|
+
* @brief Validate tuple item schemas and lowered child graphs as parallel arrays.
|
|
370
|
+
* @details IR helpers preserve Sea-of-Nodes invariants before graphs cross optimizer,
|
|
371
|
+
* compiler, or public introspection boundaries.
|
|
372
|
+
* @param value Candidate TupleItems node.
|
|
373
|
+
* @param state Shared recursion state for child graphs.
|
|
374
|
+
* @returns True when item schemas and item graphs have the same arity.
|
|
375
|
+
*/
|
|
376
|
+
function isTupleItemGraphsAligned(value, state) {
|
|
377
|
+
const items = readOwnDataProperty(value, "items");
|
|
378
|
+
const itemGraphs = readOwnDataProperty(value, "itemGraphs");
|
|
379
|
+
return isSchemaArray(items) &&
|
|
380
|
+
isGraphArray(itemGraphs, state) &&
|
|
381
|
+
items.length === itemGraphs.length;
|
|
382
|
+
}
|
|
383
|
+
/**
|
|
384
|
+
* @brief Validate the dispatch table for discriminated-union graph nodes.
|
|
385
|
+
* @details IR helpers preserve Sea-of-Nodes invariants before graphs cross optimizer,
|
|
386
|
+
* compiler, or public introspection boundaries.
|
|
387
|
+
* @param value Candidate DiscriminantDispatch node.
|
|
388
|
+
* @param state Shared recursion state for child graphs.
|
|
389
|
+
* @returns True when literal, schema, graph, and lookup vectors agree.
|
|
390
|
+
*/
|
|
391
|
+
function isDiscriminantDispatchNode(value, state) {
|
|
392
|
+
const key = readOwnDataProperty(value, "key");
|
|
393
|
+
const literals = readOwnDataProperty(value, "literals");
|
|
394
|
+
const schemas = readOwnDataProperty(value, "schemas");
|
|
395
|
+
const graphs = readOwnDataProperty(value, "graphs");
|
|
396
|
+
const lookup = readOwnDataProperty(value, "lookup");
|
|
397
|
+
return typeof key === "string" &&
|
|
398
|
+
isStringArray(literals) &&
|
|
399
|
+
isSchemaArray(schemas) &&
|
|
400
|
+
isGraphArray(graphs, state) &&
|
|
401
|
+
isDiscriminantLookup(lookup, literals) &&
|
|
402
|
+
literals.length === schemas.length &&
|
|
403
|
+
literals.length === graphs.length;
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* @brief Validate object-shape payload redundancy.
|
|
407
|
+
* @details Graph validation protects optimizer and compiler passes before they assume dense
|
|
408
|
+
* node ids and valid dependency edges.
|
|
409
|
+
* @param value Candidate ObjectShape node.
|
|
410
|
+
* @param state Shared recursion state for property graphs.
|
|
411
|
+
* @returns True when entries, keys, mode, and all-required metadata agree.
|
|
412
|
+
*/
|
|
413
|
+
function isObjectShapePayload(value, state) {
|
|
414
|
+
const entries = readOwnDataProperty(value, "entries");
|
|
415
|
+
const keys = readOwnDataProperty(value, "keys");
|
|
416
|
+
const mode = readOwnDataProperty(value, "mode");
|
|
417
|
+
const catchall = readOwnDataProperty(value, "catchall");
|
|
418
|
+
const catchallGraph = readOwnDataProperty(value, "catchallGraph");
|
|
419
|
+
const allRequired = readOwnDataProperty(value, "allRequired");
|
|
420
|
+
return isObjectShapeEntries(entries, state) &&
|
|
421
|
+
isStringArray(keys) &&
|
|
422
|
+
objectShapeEntriesMatchKeys(entries, keys) &&
|
|
423
|
+
isObjectModeTag(mode) &&
|
|
424
|
+
((catchall === undefined && catchallGraph === undefined) ||
|
|
425
|
+
(isSchemaValue(catchall) && isGraphValueInner(catchallGraph, state))) &&
|
|
426
|
+
typeof allRequired === "boolean" &&
|
|
427
|
+
allRequired === objectShapeAllRequired(entries);
|
|
428
|
+
}
|
|
429
|
+
/**
|
|
430
|
+
* @brief Validate general union-dispatch payload vectors.
|
|
431
|
+
* @details Graph validation protects optimizer and compiler passes before they assume dense
|
|
432
|
+
* node ids and valid dependency edges.
|
|
433
|
+
* @param value Candidate UnionDispatch node.
|
|
434
|
+
* @param state Shared recursion state for option graphs.
|
|
435
|
+
* @returns True when options, graphs, and masks have matching lengths.
|
|
436
|
+
*/
|
|
437
|
+
function isUnionDispatchNode(value, state) {
|
|
438
|
+
const options = readOwnDataProperty(value, "options");
|
|
439
|
+
const graphs = readOwnDataProperty(value, "graphs");
|
|
440
|
+
const masks = readOwnDataProperty(value, "masks");
|
|
441
|
+
return isSchemaArray(options) &&
|
|
442
|
+
isGraphArray(graphs, state) &&
|
|
443
|
+
isUnionMaskArray(masks) &&
|
|
444
|
+
options.length === graphs.length &&
|
|
445
|
+
options.length === masks.length;
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* @brief Validate primitive-only union dispatch metadata.
|
|
449
|
+
* @details Graph validation protects optimizer and compiler passes before they assume dense
|
|
450
|
+
* node ids and valid dependency edges.
|
|
451
|
+
* @param value Candidate PrimitiveUnion node.
|
|
452
|
+
* @param state Shared recursion state for option graphs.
|
|
453
|
+
* @returns True when primitive masks line up with option graphs.
|
|
454
|
+
*/
|
|
455
|
+
function isPrimitiveUnionNode(value, state) {
|
|
456
|
+
const graphs = readOwnDataProperty(value, "graphs");
|
|
457
|
+
const masks = readOwnDataProperty(value, "masks");
|
|
458
|
+
return isGraphArray(graphs, state) &&
|
|
459
|
+
isPrimitiveUnionMaskArray(masks) &&
|
|
460
|
+
graphs.length === masks.length;
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* @brief Validate object property entries carried by an ObjectShape node.
|
|
464
|
+
* @details IR helpers preserve Sea-of-Nodes invariants before graphs cross optimizer,
|
|
465
|
+
* compiler, or public introspection boundaries.
|
|
466
|
+
* @param value Candidate entry vector.
|
|
467
|
+
* @param state Shared recursion state for entry graphs.
|
|
468
|
+
* @returns True when each entry owns key, schema, graph, and presence metadata.
|
|
469
|
+
*/
|
|
470
|
+
function isObjectShapeEntries(value, state) {
|
|
471
|
+
if (!isUnknownArray(value)) {
|
|
472
|
+
return false;
|
|
473
|
+
}
|
|
474
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
475
|
+
const entry = value[index];
|
|
476
|
+
if (!isRecord(entry)) {
|
|
477
|
+
return false;
|
|
478
|
+
}
|
|
479
|
+
if (typeof readOwnDataProperty(entry, "key") !== "string" ||
|
|
480
|
+
!isSchemaValue(readOwnDataProperty(entry, "schema")) ||
|
|
481
|
+
!isGraphValueInner(readOwnDataProperty(entry, "graph"), state) ||
|
|
482
|
+
!isPresenceTag(readOwnDataProperty(entry, "presence"))) {
|
|
483
|
+
return false;
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
return true;
|
|
487
|
+
}
|
|
488
|
+
/**
|
|
489
|
+
* @brief Validate a dense vector of child graphs.
|
|
490
|
+
* @details Graph validation protects optimizer and compiler passes before they assume dense
|
|
491
|
+
* node ids and valid dependency edges.
|
|
492
|
+
* @param value Candidate child graph vector.
|
|
493
|
+
* @param state Shared recursion state.
|
|
494
|
+
* @returns True when every slot is a valid graph.
|
|
495
|
+
*/
|
|
496
|
+
function isGraphArray(value, state) {
|
|
497
|
+
if (!isUnknownArray(value)) {
|
|
498
|
+
return false;
|
|
499
|
+
}
|
|
500
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
501
|
+
if (!isGraphValueInner(value[index], state)) {
|
|
502
|
+
return false;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
return true;
|
|
506
|
+
}
|
|
507
|
+
/**
|
|
508
|
+
* @brief Check that object-shape entries preserve key vector order.
|
|
509
|
+
* @details Graph validation protects optimizer and compiler passes before they assume dense
|
|
510
|
+
* node ids and valid dependency edges.
|
|
511
|
+
* @param entries ObjectShape entries.
|
|
512
|
+
* @param keys Parallel key vector emitted by lowering.
|
|
513
|
+
* @returns True when each entry key matches the same index in `keys`.
|
|
514
|
+
*/
|
|
515
|
+
function objectShapeEntriesMatchKeys(entries, keys) {
|
|
516
|
+
if (entries.length !== keys.length) {
|
|
517
|
+
return false;
|
|
518
|
+
}
|
|
519
|
+
for (let index = 0; index < entries.length; index += 1) {
|
|
520
|
+
const entry = entries[index];
|
|
521
|
+
if (!isRecord(entry) || readOwnDataProperty(entry, "key") !== keys[index]) {
|
|
522
|
+
return false;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
return true;
|
|
526
|
+
}
|
|
527
|
+
/**
|
|
528
|
+
* @brief Recompute the all-required flag from object-shape entries.
|
|
529
|
+
* @param entries ObjectShape entries.
|
|
530
|
+
* @returns True when every property is required.
|
|
531
|
+
* @details The stored flag enables generated fast paths. Recomputing it during
|
|
532
|
+
* graph admission prevents a forged graph from lying about optionality.
|
|
533
|
+
*/
|
|
534
|
+
function objectShapeAllRequired(entries) {
|
|
535
|
+
for (let index = 0; index < entries.length; index += 1) {
|
|
536
|
+
const entry = entries[index];
|
|
537
|
+
if (!isRecord(entry) ||
|
|
538
|
+
readOwnDataProperty(entry, "presence") !== PresenceTag.Required) {
|
|
539
|
+
return false;
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
return true;
|
|
543
|
+
}
|
|
544
|
+
/**
|
|
545
|
+
* @brief Validate the closed presence tag set used by object entries.
|
|
546
|
+
* @details IR helpers preserve Sea-of-Nodes invariants before graphs cross optimizer,
|
|
547
|
+
* compiler, or public introspection boundaries.
|
|
548
|
+
* @param value Candidate presence marker.
|
|
549
|
+
* @returns True for required or optional.
|
|
550
|
+
*/
|
|
551
|
+
function isPresenceTag(value) {
|
|
552
|
+
return value === PresenceTag.Required || value === PresenceTag.Optional;
|
|
553
|
+
}
|
|
554
|
+
/**
|
|
555
|
+
* @brief Validate the closed object-mode tag set.
|
|
556
|
+
* @details Graph validation protects optimizer and compiler passes before they assume dense
|
|
557
|
+
* node ids and valid dependency edges.
|
|
558
|
+
* @param value Candidate object mode.
|
|
559
|
+
* @returns True for passthrough or strict mode.
|
|
560
|
+
*/
|
|
561
|
+
function isObjectModeTag(value) {
|
|
562
|
+
return value === ObjectModeTag.Passthrough || value === ObjectModeTag.Strict;
|
|
563
|
+
}
|
|
564
|
+
/**
|
|
565
|
+
* @brief Validate root-kind bit masks for union dispatch.
|
|
566
|
+
* @param value Candidate mask vector.
|
|
567
|
+
* @returns True when every mask is a small safe integer.
|
|
568
|
+
* @details The upper bound is intentionally tied to the current root-kind mask
|
|
569
|
+
* width so invalid high bits cannot steer optimizer logic.
|
|
570
|
+
*/
|
|
571
|
+
function isUnionMaskArray(value) {
|
|
572
|
+
if (!isUnknownArray(value)) {
|
|
573
|
+
return false;
|
|
574
|
+
}
|
|
575
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
576
|
+
const mask = value[index];
|
|
577
|
+
if (typeof mask !== "number" ||
|
|
578
|
+
!Number.isSafeInteger(mask) ||
|
|
579
|
+
mask < 0 ||
|
|
580
|
+
mask > 1023) {
|
|
581
|
+
return false;
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
return true;
|
|
585
|
+
}
|
|
586
|
+
/**
|
|
587
|
+
* @brief Validate masks restricted to primitive root kinds.
|
|
588
|
+
* @details Graph validation protects optimizer and compiler passes before they assume dense
|
|
589
|
+
* node ids and valid dependency edges.
|
|
590
|
+
* @param value Candidate mask vector.
|
|
591
|
+
* @returns True when no object/function bits are present.
|
|
592
|
+
*/
|
|
593
|
+
function isPrimitiveUnionMaskArray(value) {
|
|
594
|
+
if (!isUnionMaskArray(value)) {
|
|
595
|
+
return false;
|
|
596
|
+
}
|
|
597
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
598
|
+
const mask = value[index];
|
|
599
|
+
if (typeof mask !== "number" || (mask & ~127) !== 0) {
|
|
600
|
+
return false;
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
return true;
|
|
604
|
+
}
|
|
605
|
+
/**
|
|
606
|
+
* @brief Validate literal-to-case-index lookup metadata.
|
|
607
|
+
* @details Graph validation protects optimizer and compiler passes before they assume dense
|
|
608
|
+
* node ids and valid dependency edges.
|
|
609
|
+
* @param value Candidate lookup table.
|
|
610
|
+
* @param literals Parallel literal vector.
|
|
611
|
+
* @returns True when the table maps each literal to its vector index.
|
|
217
612
|
*/
|
|
218
613
|
function isDiscriminantLookup(value, literals) {
|
|
219
614
|
if (!isRecord(value)) {
|
|
@@ -226,14 +621,18 @@ function isDiscriminantLookup(value, literals) {
|
|
|
226
621
|
for (let index = 0; index < literals.length; index += 1) {
|
|
227
622
|
const literal = literals[index];
|
|
228
623
|
if (typeof literal !== "string" ||
|
|
229
|
-
value
|
|
624
|
+
readOwnDataProperty(value, literal) !== index) {
|
|
230
625
|
return false;
|
|
231
626
|
}
|
|
232
627
|
}
|
|
233
628
|
return true;
|
|
234
629
|
}
|
|
235
630
|
/**
|
|
236
|
-
* @brief
|
|
631
|
+
* @brief Accept a graph metadata record with data-only own fields.
|
|
632
|
+
* @details Graph validation protects optimizer and compiler passes before they assume dense
|
|
633
|
+
* node ids and valid dependency edges.
|
|
634
|
+
* @param value Candidate record.
|
|
635
|
+
* @returns True when no accessor fields or arrays are present.
|
|
237
636
|
*/
|
|
238
637
|
function isRecord(value) {
|
|
239
638
|
return typeof value === "object" &&
|
|
@@ -242,14 +641,22 @@ function isRecord(value) {
|
|
|
242
641
|
hasOnlyDataProperties(value);
|
|
243
642
|
}
|
|
244
643
|
/**
|
|
245
|
-
* @brief
|
|
644
|
+
* @brief Accept a dense graph metadata vector.
|
|
645
|
+
* @details Graph validation protects optimizer and compiler passes before they assume dense
|
|
646
|
+
* node ids and valid dependency edges.
|
|
647
|
+
* @param value Candidate vector.
|
|
648
|
+
* @returns True when it has no accessors, inherited slots, or holes.
|
|
246
649
|
*/
|
|
247
650
|
function isUnknownArray(value) {
|
|
248
|
-
return Array.isArray(value) &&
|
|
651
|
+
return Array.isArray(value) &&
|
|
652
|
+
hasOnlyDataProperties(value) &&
|
|
653
|
+
hasDenseDataSlots(value);
|
|
249
654
|
}
|
|
250
655
|
/**
|
|
251
|
-
* @brief
|
|
252
|
-
* @details
|
|
656
|
+
* @brief Reject accessor descriptors before graph internals read fields.
|
|
657
|
+
* @details IR helpers preserve Sea-of-Nodes invariants before graphs cross optimizer,
|
|
658
|
+
* compiler, or public introspection boundaries.
|
|
659
|
+
* @param value Object whose own descriptor table is inspected.
|
|
253
660
|
* @returns True when every own property is backed by a data slot.
|
|
254
661
|
*/
|
|
255
662
|
function hasOnlyDataProperties(value) {
|
|
@@ -269,3 +676,46 @@ function hasOnlyDataProperties(value) {
|
|
|
269
676
|
}
|
|
270
677
|
return true;
|
|
271
678
|
}
|
|
679
|
+
/**
|
|
680
|
+
* @brief Require all array indexes to be own data slots.
|
|
681
|
+
* @details Graph validation protects optimizer and compiler passes before they assume dense
|
|
682
|
+
* node ids and valid dependency edges.
|
|
683
|
+
* @param value Candidate graph vector.
|
|
684
|
+
* @returns True when each index from 0 to length - 1 exists as data.
|
|
685
|
+
*/
|
|
686
|
+
function hasDenseDataSlots(value) {
|
|
687
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
688
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
|
|
689
|
+
if (descriptor === undefined ||
|
|
690
|
+
!Object.prototype.hasOwnProperty.call(descriptor, "value")) {
|
|
691
|
+
return false;
|
|
692
|
+
}
|
|
693
|
+
}
|
|
694
|
+
return true;
|
|
695
|
+
}
|
|
696
|
+
/**
|
|
697
|
+
* @brief Read one own data slot from graph metadata.
|
|
698
|
+
* @details Graph validation protects optimizer and compiler passes before they assume dense
|
|
699
|
+
* node ids and valid dependency edges.
|
|
700
|
+
* @param value Object being validated.
|
|
701
|
+
* @param key Field name or symbol to read.
|
|
702
|
+
* @returns Stored value or the missing-data sentinel.
|
|
703
|
+
*/
|
|
704
|
+
function readOwnDataProperty(value, key) {
|
|
705
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
706
|
+
if (descriptor === undefined ||
|
|
707
|
+
!Object.prototype.hasOwnProperty.call(descriptor, "value")) {
|
|
708
|
+
return missingDataProperty;
|
|
709
|
+
}
|
|
710
|
+
return descriptor.value;
|
|
711
|
+
}
|
|
712
|
+
/**
|
|
713
|
+
* @brief Test for the graph metadata missing-data sentinel.
|
|
714
|
+
* @details Graph validation protects optimizer and compiler passes before they assume dense
|
|
715
|
+
* node ids and valid dependency edges.
|
|
716
|
+
* @param value Candidate value returned by readOwnDataProperty.
|
|
717
|
+
* @returns True when the field was absent or not a data descriptor.
|
|
718
|
+
*/
|
|
719
|
+
function isMissingDataProperty(value) {
|
|
720
|
+
return value === missingDataProperty;
|
|
721
|
+
}
|