typesea 0.1.0 → 0.2.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 +67 -6
- package/README.md +98 -17
- 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 +18 -2
- package/dist/aot/index.d.ts.map +1 -1
- package/dist/aot/index.js +93 -14
- 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 +37 -6
- package/dist/builders/composite.d.ts.map +1 -1
- package/dist/builders/composite.js +84 -10
- package/dist/builders/index.d.ts +2 -0
- package/dist/builders/index.d.ts.map +1 -1
- package/dist/builders/index.js +2 -0
- package/dist/builders/modifier.d.ts +30 -5
- package/dist/builders/modifier.d.ts.map +1 -1
- package/dist/builders/modifier.js +38 -5
- package/dist/builders/object/guard.d.ts +18 -22
- package/dist/builders/object/guard.d.ts.map +1 -1
- package/dist/builders/object/guard.js +26 -26
- package/dist/builders/object/index.d.ts +2 -0
- package/dist/builders/object/index.d.ts.map +1 -1
- package/dist/builders/object/index.js +2 -0
- package/dist/builders/object/schema.d.ts +55 -9
- package/dist/builders/object/schema.d.ts.map +1 -1
- package/dist/builders/object/schema.js +92 -15
- package/dist/builders/object/types.d.ts +5 -31
- package/dist/builders/object/types.d.ts.map +1 -1
- package/dist/builders/object/types.js +2 -0
- package/dist/builders/scalar.d.ts +29 -8
- package/dist/builders/scalar.d.ts.map +1 -1
- package/dist/builders/scalar.js +33 -8
- package/dist/builders/table.d.ts +4 -0
- package/dist/builders/table.d.ts.map +1 -1
- package/dist/builders/table.js +4 -0
- package/dist/builders/types.d.ts +14 -4
- package/dist/builders/types.d.ts.map +1 -1
- package/dist/builders/types.js +2 -0
- package/dist/compile/check-composite.d.ts +22 -1
- package/dist/compile/check-composite.d.ts.map +1 -1
- package/dist/compile/check-composite.js +564 -24
- package/dist/compile/check-scalar.d.ts +78 -0
- package/dist/compile/check-scalar.d.ts.map +1 -1
- package/dist/compile/check-scalar.js +432 -1
- package/dist/compile/check.d.ts +12 -0
- package/dist/compile/check.d.ts.map +1 -1
- package/dist/compile/check.js +37 -0
- package/dist/compile/context.d.ts +47 -9
- package/dist/compile/context.d.ts.map +1 -1
- package/dist/compile/context.js +51 -8
- 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 +1907 -171
- package/dist/compile/guard.d.ts +15 -24
- package/dist/compile/guard.d.ts.map +1 -1
- package/dist/compile/guard.js +158 -74
- 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 +131 -5
- package/dist/compile/runtime.d.ts +80 -12
- package/dist/compile/runtime.d.ts.map +1 -1
- package/dist/compile/runtime.js +25 -6
- package/dist/compile/source.d.ts +10 -2
- package/dist/compile/source.d.ts.map +1 -1
- package/dist/compile/source.js +361 -26
- package/dist/compile/types.d.ts +20 -0
- package/dist/compile/types.d.ts.map +1 -1
- package/dist/compile/types.js +2 -0
- package/dist/decoder/index.d.ts +32 -46
- package/dist/decoder/index.d.ts.map +1 -1
- package/dist/decoder/index.js +102 -38
- package/dist/evaluate/check-composite.d.ts +59 -0
- package/dist/evaluate/check-composite.d.ts.map +1 -1
- package/dist/evaluate/check-composite.js +151 -3
- package/dist/evaluate/check-scalar.d.ts +16 -0
- package/dist/evaluate/check-scalar.d.ts.map +1 -1
- package/dist/evaluate/check-scalar.js +32 -0
- package/dist/evaluate/check.d.ts +7 -0
- package/dist/evaluate/check.d.ts.map +1 -1
- package/dist/evaluate/check.js +43 -0
- 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 +59 -13
- package/dist/evaluate/shared.d.ts.map +1 -1
- package/dist/evaluate/shared.js +66 -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/base.d.ts +79 -29
- package/dist/guard/base.d.ts.map +1 -1
- package/dist/guard/base.js +91 -29
- 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 +2 -0
- package/dist/guard/index.d.ts.map +1 -1
- package/dist/guard/index.js +2 -0
- package/dist/guard/number.d.ts +26 -11
- package/dist/guard/number.d.ts.map +1 -1
- package/dist/guard/number.js +30 -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 +62 -9
- package/dist/guard/read.d.ts.map +1 -1
- package/dist/guard/read.js +83 -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 +33 -13
- package/dist/guard/string.d.ts.map +1 -1
- package/dist/guard/string.js +37 -13
- package/dist/guard/types.d.ts +92 -40
- package/dist/guard/types.d.ts.map +1 -1
- package/dist/guard/types.js +2 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- 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 +16 -126
- package/dist/ir/builder.d.ts.map +1 -1
- package/dist/ir/builder.js +77 -137
- package/dist/ir/freeze.d.ts +4 -0
- package/dist/ir/freeze.d.ts.map +1 -1
- package/dist/ir/freeze.js +59 -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 +90 -55
- 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 +477 -61
- package/dist/issue/index.d.ts +41 -9
- package/dist/issue/index.d.ts.map +1 -1
- package/dist/issue/index.js +61 -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 +10 -0
- package/dist/json-schema/emit-composite.d.ts.map +1 -1
- package/dist/json-schema/emit-composite.js +15 -1
- 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 +70 -9
- 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 +12 -1
- 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 +38 -15
- package/dist/json-schema/types.d.ts.map +1 -1
- package/dist/json-schema/types.js +2 -0
- package/dist/kind/index.d.ts +15 -28
- package/dist/kind/index.d.ts.map +1 -1
- package/dist/kind/index.js +15 -10
- package/dist/lower/index.d.ts +6 -1
- package/dist/lower/index.d.ts.map +1 -1
- package/dist/lower/index.js +411 -44
- package/dist/message/index.d.ts +46 -10
- package/dist/message/index.d.ts.map +1 -1
- package/dist/message/index.js +88 -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 +615 -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 +45 -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 +21 -5
- 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 +268 -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 +117 -13
- 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 +18 -0
- package/dist/schema/index.d.ts +3 -0
- package/dist/schema/index.d.ts.map +1 -1
- package/dist/schema/index.js +3 -0
- 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 +20 -96
- package/dist/schema/types.d.ts.map +1 -1
- package/dist/schema/types.js +5 -1
- package/dist/schema/undefined.d.ts +17 -0
- package/dist/schema/undefined.d.ts.map +1 -0
- package/dist/schema/undefined.js +72 -0
- package/dist/schema/validate.d.ts +8 -1
- package/dist/schema/validate.d.ts.map +1 -1
- package/dist/schema/validate.js +146 -55
- package/docs/api.md +57 -0
- package/docs/assets/benchmark-headline.svg +163 -0
- package/docs/engine-notes.md +58 -15
- package/docs/index.html +130 -110
- package/package.json +65 -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 { 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,56 @@ 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
|
+
isGraphValueInner(readOwnDataProperty(value, "itemGraph"), state) &&
|
|
87
154
|
isSingleDepNode(value, deps, "value", nodeCount);
|
|
88
155
|
case NodeTag.TupleItems:
|
|
89
|
-
return
|
|
156
|
+
return isTupleItemGraphsAligned(value, state) &&
|
|
90
157
|
isSingleDepNode(value, deps, "value", nodeCount);
|
|
91
158
|
case NodeTag.RecordEvery:
|
|
92
|
-
return isSchemaValue(value
|
|
159
|
+
return isSchemaValue(readOwnDataProperty(value, "item")) &&
|
|
160
|
+
isGraphValueInner(readOwnDataProperty(value, "itemGraph"), state) &&
|
|
93
161
|
isSingleDepNode(value, deps, "value", nodeCount);
|
|
94
162
|
case NodeTag.DiscriminantDispatch:
|
|
95
|
-
return
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
value
|
|
163
|
+
return isDiscriminantDispatchNode(value, state) &&
|
|
164
|
+
isSingleDepNode(value, deps, "value", nodeCount);
|
|
165
|
+
case NodeTag.ObjectShape:
|
|
166
|
+
return isObjectShapePayload(value, state) &&
|
|
167
|
+
isSingleDepNode(value, deps, "value", nodeCount);
|
|
168
|
+
case NodeTag.UnionDispatch:
|
|
169
|
+
return isUnionDispatchNode(value, state) &&
|
|
170
|
+
isSingleDepNode(value, deps, "value", nodeCount);
|
|
171
|
+
case NodeTag.PrimitiveUnion:
|
|
172
|
+
return isPrimitiveUnionNode(value, state) &&
|
|
100
173
|
isSingleDepNode(value, deps, "value", nodeCount);
|
|
101
174
|
case NodeTag.SchemaCheck:
|
|
102
|
-
return isSchemaValue(value
|
|
175
|
+
return isSchemaValue(readOwnDataProperty(value, "schema")) &&
|
|
103
176
|
isSingleDepNode(value, deps, "value", nodeCount);
|
|
104
177
|
case NodeTag.And:
|
|
105
|
-
case NodeTag.Or:
|
|
106
|
-
|
|
107
|
-
|
|
178
|
+
case NodeTag.Or: {
|
|
179
|
+
const values = readOwnDataProperty(value, "values");
|
|
180
|
+
return isNodeIdArray(values, nodeCount) &&
|
|
181
|
+
sameNodeIds(deps, values);
|
|
182
|
+
}
|
|
108
183
|
case NodeTag.Return:
|
|
109
184
|
return isTwoDepNode(value, deps, "control", "value", nodeCount);
|
|
110
185
|
default:
|
|
@@ -112,43 +187,73 @@ function isGraphNodeValue(value, index, nodeCount) {
|
|
|
112
187
|
}
|
|
113
188
|
}
|
|
114
189
|
/**
|
|
115
|
-
* @brief
|
|
190
|
+
* @brief Validate payloads for dependency-free nodes.
|
|
191
|
+
* @details Graph validation protects optimizer and compiler passes before they assume dense
|
|
192
|
+
* node ids and valid dependency edges.
|
|
193
|
+
* @param value Candidate node record.
|
|
194
|
+
* @param deps Dependency vector already read from the node.
|
|
195
|
+
* @returns True when the leaf payload matches Start, Param, or Const.
|
|
116
196
|
*/
|
|
117
197
|
function isLeafNodeValue(value, deps) {
|
|
118
198
|
if (deps.length !== 0) {
|
|
119
199
|
return false;
|
|
120
200
|
}
|
|
121
|
-
switch (value
|
|
201
|
+
switch (readOwnDataProperty(value, "tag")) {
|
|
122
202
|
case NodeTag.Start:
|
|
123
203
|
return true;
|
|
124
204
|
case NodeTag.Param:
|
|
125
|
-
return typeof value
|
|
126
|
-
case NodeTag.Const:
|
|
127
|
-
|
|
205
|
+
return typeof readOwnDataProperty(value, "name") === "string";
|
|
206
|
+
case NodeTag.Const: {
|
|
207
|
+
const literal = readOwnDataProperty(value, "value");
|
|
208
|
+
return !isMissingDataProperty(literal) && isLiteralValue(literal);
|
|
209
|
+
}
|
|
128
210
|
default:
|
|
129
211
|
return false;
|
|
130
212
|
}
|
|
131
213
|
}
|
|
132
214
|
/**
|
|
133
|
-
* @brief
|
|
215
|
+
* @brief Validate a node whose named edge mirrors one dependency.
|
|
216
|
+
* @details Graph validation protects optimizer and compiler passes before they assume dense
|
|
217
|
+
* node ids and valid dependency edges.
|
|
218
|
+
* @param value Candidate node record.
|
|
219
|
+
* @param deps Dependency vector from the same node.
|
|
220
|
+
* @param field Named edge field that must equal deps[0].
|
|
221
|
+
* @param nodeCount Total arena size for bounds.
|
|
222
|
+
* @returns True when the edge is in range and exactly mirrors the dependency.
|
|
134
223
|
*/
|
|
135
224
|
function isSingleDepNode(value, deps, field, nodeCount) {
|
|
225
|
+
const fieldValue = readOwnDataProperty(value, field);
|
|
136
226
|
return deps.length === 1 &&
|
|
137
|
-
isNodeId(
|
|
138
|
-
deps[0] ===
|
|
227
|
+
isNodeId(fieldValue, nodeCount) &&
|
|
228
|
+
deps[0] === fieldValue;
|
|
139
229
|
}
|
|
140
230
|
/**
|
|
141
|
-
* @brief
|
|
231
|
+
* @brief Validate a node whose named edges mirror two dependencies.
|
|
232
|
+
* @details Graph validation protects optimizer and compiler passes before they assume dense
|
|
233
|
+
* node ids and valid dependency edges.
|
|
234
|
+
* @param value Candidate node record.
|
|
235
|
+
* @param deps Dependency vector from the same node.
|
|
236
|
+
* @param leftField First named edge field.
|
|
237
|
+
* @param rightField Second named edge field.
|
|
238
|
+
* @param nodeCount Total arena size for bounds.
|
|
239
|
+
* @returns True when both named edges are in range and mirror `deps`.
|
|
142
240
|
*/
|
|
143
241
|
function isTwoDepNode(value, deps, leftField, rightField, nodeCount) {
|
|
242
|
+
const left = readOwnDataProperty(value, leftField);
|
|
243
|
+
const right = readOwnDataProperty(value, rightField);
|
|
144
244
|
return deps.length === 2 &&
|
|
145
|
-
isNodeId(
|
|
146
|
-
isNodeId(
|
|
147
|
-
deps[0] ===
|
|
148
|
-
deps[1] ===
|
|
245
|
+
isNodeId(left, nodeCount) &&
|
|
246
|
+
isNodeId(right, nodeCount) &&
|
|
247
|
+
deps[0] === left &&
|
|
248
|
+
deps[1] === right;
|
|
149
249
|
}
|
|
150
250
|
/**
|
|
151
|
-
* @brief
|
|
251
|
+
* @brief Validate a graph-local arena index.
|
|
252
|
+
* @details Graph validation protects optimizer and compiler passes before they assume dense
|
|
253
|
+
* node ids and valid dependency edges.
|
|
254
|
+
* @param value Candidate node id.
|
|
255
|
+
* @param nodeCount Total arena size.
|
|
256
|
+
* @returns True when the id is an integer inside the arena.
|
|
152
257
|
*/
|
|
153
258
|
function isNodeId(value, nodeCount) {
|
|
154
259
|
return typeof value === "number" &&
|
|
@@ -157,7 +262,12 @@ function isNodeId(value, nodeCount) {
|
|
|
157
262
|
value < nodeCount;
|
|
158
263
|
}
|
|
159
264
|
/**
|
|
160
|
-
* @brief
|
|
265
|
+
* @brief Validate a dense dependency vector.
|
|
266
|
+
* @details Graph validation protects optimizer and compiler passes before they assume dense
|
|
267
|
+
* node ids and valid dependency edges.
|
|
268
|
+
* @param value Candidate dependency list.
|
|
269
|
+
* @param nodeCount Total arena size for every dependency.
|
|
270
|
+
* @returns True when every dependency points inside the arena.
|
|
161
271
|
*/
|
|
162
272
|
function isNodeIdArray(value, nodeCount) {
|
|
163
273
|
if (!isUnknownArray(value)) {
|
|
@@ -171,7 +281,12 @@ function isNodeIdArray(value, nodeCount) {
|
|
|
171
281
|
return true;
|
|
172
282
|
}
|
|
173
283
|
/**
|
|
174
|
-
* @brief
|
|
284
|
+
* @brief Compare two dependency vectors without allocating.
|
|
285
|
+
* @details Graph validation protects optimizer and compiler passes before they assume dense
|
|
286
|
+
* node ids and valid dependency edges.
|
|
287
|
+
* @param left First dependency vector.
|
|
288
|
+
* @param right Second dependency vector.
|
|
289
|
+
* @returns True when both vectors contain the same node ids in the same order.
|
|
175
290
|
*/
|
|
176
291
|
function sameNodeIds(left, right) {
|
|
177
292
|
if (left.length !== right.length) {
|
|
@@ -185,7 +300,11 @@ function sameNodeIds(left, right) {
|
|
|
185
300
|
return true;
|
|
186
301
|
}
|
|
187
302
|
/**
|
|
188
|
-
* @brief
|
|
303
|
+
* @brief Validate a dense vector of graph-owned strings.
|
|
304
|
+
* @details Graph validation protects optimizer and compiler passes before they assume dense
|
|
305
|
+
* node ids and valid dependency edges.
|
|
306
|
+
* @param value Candidate string vector.
|
|
307
|
+
* @returns True when every slot is a string.
|
|
189
308
|
*/
|
|
190
309
|
function isStringArray(value) {
|
|
191
310
|
if (!isUnknownArray(value)) {
|
|
@@ -199,7 +318,11 @@ function isStringArray(value) {
|
|
|
199
318
|
return true;
|
|
200
319
|
}
|
|
201
320
|
/**
|
|
202
|
-
* @brief
|
|
321
|
+
* @brief Validate a dense vector of embedded schema payloads.
|
|
322
|
+
* @details Graph validation protects optimizer and compiler passes before they assume dense
|
|
323
|
+
* node ids and valid dependency edges.
|
|
324
|
+
* @param value Candidate schema vector.
|
|
325
|
+
* @returns True when every slot is accepted by schema validation.
|
|
203
326
|
*/
|
|
204
327
|
function isSchemaArray(value) {
|
|
205
328
|
if (!isUnknownArray(value)) {
|
|
@@ -213,7 +336,245 @@ function isSchemaArray(value) {
|
|
|
213
336
|
return true;
|
|
214
337
|
}
|
|
215
338
|
/**
|
|
216
|
-
* @brief
|
|
339
|
+
* @brief Validate tuple item schemas and lowered child graphs as parallel arrays.
|
|
340
|
+
* @details IR helpers preserve Sea-of-Nodes invariants before graphs cross optimizer,
|
|
341
|
+
* compiler, or public introspection boundaries.
|
|
342
|
+
* @param value Candidate TupleItems node.
|
|
343
|
+
* @param state Shared recursion state for child graphs.
|
|
344
|
+
* @returns True when item schemas and item graphs have the same arity.
|
|
345
|
+
*/
|
|
346
|
+
function isTupleItemGraphsAligned(value, state) {
|
|
347
|
+
const items = readOwnDataProperty(value, "items");
|
|
348
|
+
const itemGraphs = readOwnDataProperty(value, "itemGraphs");
|
|
349
|
+
return isSchemaArray(items) &&
|
|
350
|
+
isGraphArray(itemGraphs, state) &&
|
|
351
|
+
items.length === itemGraphs.length;
|
|
352
|
+
}
|
|
353
|
+
/**
|
|
354
|
+
* @brief Validate the dispatch table for discriminated-union graph nodes.
|
|
355
|
+
* @details IR helpers preserve Sea-of-Nodes invariants before graphs cross optimizer,
|
|
356
|
+
* compiler, or public introspection boundaries.
|
|
357
|
+
* @param value Candidate DiscriminantDispatch node.
|
|
358
|
+
* @param state Shared recursion state for child graphs.
|
|
359
|
+
* @returns True when literal, schema, graph, and lookup vectors agree.
|
|
360
|
+
*/
|
|
361
|
+
function isDiscriminantDispatchNode(value, state) {
|
|
362
|
+
const key = readOwnDataProperty(value, "key");
|
|
363
|
+
const literals = readOwnDataProperty(value, "literals");
|
|
364
|
+
const schemas = readOwnDataProperty(value, "schemas");
|
|
365
|
+
const graphs = readOwnDataProperty(value, "graphs");
|
|
366
|
+
const lookup = readOwnDataProperty(value, "lookup");
|
|
367
|
+
return typeof key === "string" &&
|
|
368
|
+
isStringArray(literals) &&
|
|
369
|
+
isSchemaArray(schemas) &&
|
|
370
|
+
isGraphArray(graphs, state) &&
|
|
371
|
+
isDiscriminantLookup(lookup, literals) &&
|
|
372
|
+
literals.length === schemas.length &&
|
|
373
|
+
literals.length === graphs.length;
|
|
374
|
+
}
|
|
375
|
+
/**
|
|
376
|
+
* @brief Validate object-shape payload redundancy.
|
|
377
|
+
* @details Graph validation protects optimizer and compiler passes before they assume dense
|
|
378
|
+
* node ids and valid dependency edges.
|
|
379
|
+
* @param value Candidate ObjectShape node.
|
|
380
|
+
* @param state Shared recursion state for property graphs.
|
|
381
|
+
* @returns True when entries, keys, mode, and all-required metadata agree.
|
|
382
|
+
*/
|
|
383
|
+
function isObjectShapePayload(value, state) {
|
|
384
|
+
const entries = readOwnDataProperty(value, "entries");
|
|
385
|
+
const keys = readOwnDataProperty(value, "keys");
|
|
386
|
+
const mode = readOwnDataProperty(value, "mode");
|
|
387
|
+
const allRequired = readOwnDataProperty(value, "allRequired");
|
|
388
|
+
return isObjectShapeEntries(entries, state) &&
|
|
389
|
+
isStringArray(keys) &&
|
|
390
|
+
objectShapeEntriesMatchKeys(entries, keys) &&
|
|
391
|
+
isObjectModeTag(mode) &&
|
|
392
|
+
typeof allRequired === "boolean" &&
|
|
393
|
+
allRequired === objectShapeAllRequired(entries);
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* @brief Validate general union-dispatch payload vectors.
|
|
397
|
+
* @details Graph validation protects optimizer and compiler passes before they assume dense
|
|
398
|
+
* node ids and valid dependency edges.
|
|
399
|
+
* @param value Candidate UnionDispatch node.
|
|
400
|
+
* @param state Shared recursion state for option graphs.
|
|
401
|
+
* @returns True when options, graphs, and masks have matching lengths.
|
|
402
|
+
*/
|
|
403
|
+
function isUnionDispatchNode(value, state) {
|
|
404
|
+
const options = readOwnDataProperty(value, "options");
|
|
405
|
+
const graphs = readOwnDataProperty(value, "graphs");
|
|
406
|
+
const masks = readOwnDataProperty(value, "masks");
|
|
407
|
+
return isSchemaArray(options) &&
|
|
408
|
+
isGraphArray(graphs, state) &&
|
|
409
|
+
isUnionMaskArray(masks) &&
|
|
410
|
+
options.length === graphs.length &&
|
|
411
|
+
options.length === masks.length;
|
|
412
|
+
}
|
|
413
|
+
/**
|
|
414
|
+
* @brief Validate primitive-only union dispatch metadata.
|
|
415
|
+
* @details Graph validation protects optimizer and compiler passes before they assume dense
|
|
416
|
+
* node ids and valid dependency edges.
|
|
417
|
+
* @param value Candidate PrimitiveUnion node.
|
|
418
|
+
* @param state Shared recursion state for option graphs.
|
|
419
|
+
* @returns True when primitive masks line up with option graphs.
|
|
420
|
+
*/
|
|
421
|
+
function isPrimitiveUnionNode(value, state) {
|
|
422
|
+
const graphs = readOwnDataProperty(value, "graphs");
|
|
423
|
+
const masks = readOwnDataProperty(value, "masks");
|
|
424
|
+
return isGraphArray(graphs, state) &&
|
|
425
|
+
isPrimitiveUnionMaskArray(masks) &&
|
|
426
|
+
graphs.length === masks.length;
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* @brief Validate object property entries carried by an ObjectShape node.
|
|
430
|
+
* @details IR helpers preserve Sea-of-Nodes invariants before graphs cross optimizer,
|
|
431
|
+
* compiler, or public introspection boundaries.
|
|
432
|
+
* @param value Candidate entry vector.
|
|
433
|
+
* @param state Shared recursion state for entry graphs.
|
|
434
|
+
* @returns True when each entry owns key, schema, graph, and presence metadata.
|
|
435
|
+
*/
|
|
436
|
+
function isObjectShapeEntries(value, state) {
|
|
437
|
+
if (!isUnknownArray(value)) {
|
|
438
|
+
return false;
|
|
439
|
+
}
|
|
440
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
441
|
+
const entry = value[index];
|
|
442
|
+
if (!isRecord(entry)) {
|
|
443
|
+
return false;
|
|
444
|
+
}
|
|
445
|
+
if (typeof readOwnDataProperty(entry, "key") !== "string" ||
|
|
446
|
+
!isSchemaValue(readOwnDataProperty(entry, "schema")) ||
|
|
447
|
+
!isGraphValueInner(readOwnDataProperty(entry, "graph"), state) ||
|
|
448
|
+
!isPresenceTag(readOwnDataProperty(entry, "presence"))) {
|
|
449
|
+
return false;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
return true;
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* @brief Validate a dense vector of child graphs.
|
|
456
|
+
* @details Graph validation protects optimizer and compiler passes before they assume dense
|
|
457
|
+
* node ids and valid dependency edges.
|
|
458
|
+
* @param value Candidate child graph vector.
|
|
459
|
+
* @param state Shared recursion state.
|
|
460
|
+
* @returns True when every slot is a valid graph.
|
|
461
|
+
*/
|
|
462
|
+
function isGraphArray(value, state) {
|
|
463
|
+
if (!isUnknownArray(value)) {
|
|
464
|
+
return false;
|
|
465
|
+
}
|
|
466
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
467
|
+
if (!isGraphValueInner(value[index], state)) {
|
|
468
|
+
return false;
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
return true;
|
|
472
|
+
}
|
|
473
|
+
/**
|
|
474
|
+
* @brief Check that object-shape entries preserve key vector order.
|
|
475
|
+
* @details Graph validation protects optimizer and compiler passes before they assume dense
|
|
476
|
+
* node ids and valid dependency edges.
|
|
477
|
+
* @param entries ObjectShape entries.
|
|
478
|
+
* @param keys Parallel key vector emitted by lowering.
|
|
479
|
+
* @returns True when each entry key matches the same index in `keys`.
|
|
480
|
+
*/
|
|
481
|
+
function objectShapeEntriesMatchKeys(entries, keys) {
|
|
482
|
+
if (entries.length !== keys.length) {
|
|
483
|
+
return false;
|
|
484
|
+
}
|
|
485
|
+
for (let index = 0; index < entries.length; index += 1) {
|
|
486
|
+
const entry = entries[index];
|
|
487
|
+
if (!isRecord(entry) || readOwnDataProperty(entry, "key") !== keys[index]) {
|
|
488
|
+
return false;
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
return true;
|
|
492
|
+
}
|
|
493
|
+
/**
|
|
494
|
+
* @brief Recompute the all-required flag from object-shape entries.
|
|
495
|
+
* @param entries ObjectShape entries.
|
|
496
|
+
* @returns True when every property is required.
|
|
497
|
+
* @details The stored flag enables generated fast paths. Recomputing it during
|
|
498
|
+
* graph admission prevents a forged graph from lying about optionality.
|
|
499
|
+
*/
|
|
500
|
+
function objectShapeAllRequired(entries) {
|
|
501
|
+
for (let index = 0; index < entries.length; index += 1) {
|
|
502
|
+
const entry = entries[index];
|
|
503
|
+
if (!isRecord(entry) ||
|
|
504
|
+
readOwnDataProperty(entry, "presence") !== PresenceTag.Required) {
|
|
505
|
+
return false;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
return true;
|
|
509
|
+
}
|
|
510
|
+
/**
|
|
511
|
+
* @brief Validate the closed presence tag set used by object entries.
|
|
512
|
+
* @details IR helpers preserve Sea-of-Nodes invariants before graphs cross optimizer,
|
|
513
|
+
* compiler, or public introspection boundaries.
|
|
514
|
+
* @param value Candidate presence marker.
|
|
515
|
+
* @returns True for required or optional.
|
|
516
|
+
*/
|
|
517
|
+
function isPresenceTag(value) {
|
|
518
|
+
return value === PresenceTag.Required || value === PresenceTag.Optional;
|
|
519
|
+
}
|
|
520
|
+
/**
|
|
521
|
+
* @brief Validate the closed object-mode tag set.
|
|
522
|
+
* @details Graph validation protects optimizer and compiler passes before they assume dense
|
|
523
|
+
* node ids and valid dependency edges.
|
|
524
|
+
* @param value Candidate object mode.
|
|
525
|
+
* @returns True for passthrough or strict mode.
|
|
526
|
+
*/
|
|
527
|
+
function isObjectModeTag(value) {
|
|
528
|
+
return value === ObjectModeTag.Passthrough || value === ObjectModeTag.Strict;
|
|
529
|
+
}
|
|
530
|
+
/**
|
|
531
|
+
* @brief Validate root-kind bit masks for union dispatch.
|
|
532
|
+
* @param value Candidate mask vector.
|
|
533
|
+
* @returns True when every mask is a small safe integer.
|
|
534
|
+
* @details The upper bound is intentionally tied to the current root-kind mask
|
|
535
|
+
* width so invalid high bits cannot steer optimizer logic.
|
|
536
|
+
*/
|
|
537
|
+
function isUnionMaskArray(value) {
|
|
538
|
+
if (!isUnknownArray(value)) {
|
|
539
|
+
return false;
|
|
540
|
+
}
|
|
541
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
542
|
+
const mask = value[index];
|
|
543
|
+
if (typeof mask !== "number" ||
|
|
544
|
+
!Number.isSafeInteger(mask) ||
|
|
545
|
+
mask < 0 ||
|
|
546
|
+
mask > 1023) {
|
|
547
|
+
return false;
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
return true;
|
|
551
|
+
}
|
|
552
|
+
/**
|
|
553
|
+
* @brief Validate masks restricted to primitive root kinds.
|
|
554
|
+
* @details Graph validation protects optimizer and compiler passes before they assume dense
|
|
555
|
+
* node ids and valid dependency edges.
|
|
556
|
+
* @param value Candidate mask vector.
|
|
557
|
+
* @returns True when no object/function bits are present.
|
|
558
|
+
*/
|
|
559
|
+
function isPrimitiveUnionMaskArray(value) {
|
|
560
|
+
if (!isUnionMaskArray(value)) {
|
|
561
|
+
return false;
|
|
562
|
+
}
|
|
563
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
564
|
+
const mask = value[index];
|
|
565
|
+
if (typeof mask !== "number" || (mask & ~127) !== 0) {
|
|
566
|
+
return false;
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
return true;
|
|
570
|
+
}
|
|
571
|
+
/**
|
|
572
|
+
* @brief Validate literal-to-case-index lookup metadata.
|
|
573
|
+
* @details Graph validation protects optimizer and compiler passes before they assume dense
|
|
574
|
+
* node ids and valid dependency edges.
|
|
575
|
+
* @param value Candidate lookup table.
|
|
576
|
+
* @param literals Parallel literal vector.
|
|
577
|
+
* @returns True when the table maps each literal to its vector index.
|
|
217
578
|
*/
|
|
218
579
|
function isDiscriminantLookup(value, literals) {
|
|
219
580
|
if (!isRecord(value)) {
|
|
@@ -226,14 +587,18 @@ function isDiscriminantLookup(value, literals) {
|
|
|
226
587
|
for (let index = 0; index < literals.length; index += 1) {
|
|
227
588
|
const literal = literals[index];
|
|
228
589
|
if (typeof literal !== "string" ||
|
|
229
|
-
value
|
|
590
|
+
readOwnDataProperty(value, literal) !== index) {
|
|
230
591
|
return false;
|
|
231
592
|
}
|
|
232
593
|
}
|
|
233
594
|
return true;
|
|
234
595
|
}
|
|
235
596
|
/**
|
|
236
|
-
* @brief
|
|
597
|
+
* @brief Accept a graph metadata record with data-only own fields.
|
|
598
|
+
* @details Graph validation protects optimizer and compiler passes before they assume dense
|
|
599
|
+
* node ids and valid dependency edges.
|
|
600
|
+
* @param value Candidate record.
|
|
601
|
+
* @returns True when no accessor fields or arrays are present.
|
|
237
602
|
*/
|
|
238
603
|
function isRecord(value) {
|
|
239
604
|
return typeof value === "object" &&
|
|
@@ -242,14 +607,22 @@ function isRecord(value) {
|
|
|
242
607
|
hasOnlyDataProperties(value);
|
|
243
608
|
}
|
|
244
609
|
/**
|
|
245
|
-
* @brief
|
|
610
|
+
* @brief Accept a dense graph metadata vector.
|
|
611
|
+
* @details Graph validation protects optimizer and compiler passes before they assume dense
|
|
612
|
+
* node ids and valid dependency edges.
|
|
613
|
+
* @param value Candidate vector.
|
|
614
|
+
* @returns True when it has no accessors, inherited slots, or holes.
|
|
246
615
|
*/
|
|
247
616
|
function isUnknownArray(value) {
|
|
248
|
-
return Array.isArray(value) &&
|
|
617
|
+
return Array.isArray(value) &&
|
|
618
|
+
hasOnlyDataProperties(value) &&
|
|
619
|
+
hasDenseDataSlots(value);
|
|
249
620
|
}
|
|
250
621
|
/**
|
|
251
|
-
* @brief
|
|
252
|
-
* @details
|
|
622
|
+
* @brief Reject accessor descriptors before graph internals read fields.
|
|
623
|
+
* @details IR helpers preserve Sea-of-Nodes invariants before graphs cross optimizer,
|
|
624
|
+
* compiler, or public introspection boundaries.
|
|
625
|
+
* @param value Object whose own descriptor table is inspected.
|
|
253
626
|
* @returns True when every own property is backed by a data slot.
|
|
254
627
|
*/
|
|
255
628
|
function hasOnlyDataProperties(value) {
|
|
@@ -269,3 +642,46 @@ function hasOnlyDataProperties(value) {
|
|
|
269
642
|
}
|
|
270
643
|
return true;
|
|
271
644
|
}
|
|
645
|
+
/**
|
|
646
|
+
* @brief Require all array indexes to be own data slots.
|
|
647
|
+
* @details Graph validation protects optimizer and compiler passes before they assume dense
|
|
648
|
+
* node ids and valid dependency edges.
|
|
649
|
+
* @param value Candidate graph vector.
|
|
650
|
+
* @returns True when each index from 0 to length - 1 exists as data.
|
|
651
|
+
*/
|
|
652
|
+
function hasDenseDataSlots(value) {
|
|
653
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
654
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, String(index));
|
|
655
|
+
if (descriptor === undefined ||
|
|
656
|
+
!Object.prototype.hasOwnProperty.call(descriptor, "value")) {
|
|
657
|
+
return false;
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
return true;
|
|
661
|
+
}
|
|
662
|
+
/**
|
|
663
|
+
* @brief Read one own data slot from graph metadata.
|
|
664
|
+
* @details Graph validation protects optimizer and compiler passes before they assume dense
|
|
665
|
+
* node ids and valid dependency edges.
|
|
666
|
+
* @param value Object being validated.
|
|
667
|
+
* @param key Field name or symbol to read.
|
|
668
|
+
* @returns Stored value or the missing-data sentinel.
|
|
669
|
+
*/
|
|
670
|
+
function readOwnDataProperty(value, key) {
|
|
671
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
672
|
+
if (descriptor === undefined ||
|
|
673
|
+
!Object.prototype.hasOwnProperty.call(descriptor, "value")) {
|
|
674
|
+
return missingDataProperty;
|
|
675
|
+
}
|
|
676
|
+
return descriptor.value;
|
|
677
|
+
}
|
|
678
|
+
/**
|
|
679
|
+
* @brief Test for the graph metadata missing-data sentinel.
|
|
680
|
+
* @details Graph validation protects optimizer and compiler passes before they assume dense
|
|
681
|
+
* node ids and valid dependency edges.
|
|
682
|
+
* @param value Candidate value returned by readOwnDataProperty.
|
|
683
|
+
* @returns True when the field was absent or not a data descriptor.
|
|
684
|
+
*/
|
|
685
|
+
function isMissingDataProperty(value) {
|
|
686
|
+
return value === missingDataProperty;
|
|
687
|
+
}
|