@packet-schema/core 0.1.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/dist/collect-refs.d.ts +4 -0
- package/dist/collect-refs.d.ts.map +1 -0
- package/dist/collect-refs.js +76 -0
- package/dist/collect-refs.js.map +1 -0
- package/dist/constraint.d.ts +66 -0
- package/dist/constraint.d.ts.map +1 -0
- package/dist/constraint.js +286 -0
- package/dist/constraint.js.map +1 -0
- package/dist/expr.d.ts +32 -0
- package/dist/expr.d.ts.map +1 -0
- package/dist/expr.js +190 -0
- package/dist/expr.js.map +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -0
- package/dist/layout.d.ts +7 -0
- package/dist/layout.d.ts.map +1 -0
- package/dist/layout.js +217 -0
- package/dist/layout.js.map +1 -0
- package/dist/normalize.d.ts +37 -0
- package/dist/normalize.d.ts.map +1 -0
- package/dist/normalize.js +857 -0
- package/dist/normalize.js.map +1 -0
- package/dist/types.d.ts +538 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +27 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +3 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +4 -0
- package/dist/utils.js.map +1 -0
- package/dist/validate.d.ts +8 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +1222 -0
- package/dist/validate.js.map +1 -0
- package/dist/values.d.ts +31 -0
- package/dist/values.d.ts.map +1 -0
- package/dist/values.js +73 -0
- package/dist/values.js.map +1 -0
- package/dist/yaml.d.ts +11 -0
- package/dist/yaml.d.ts.map +1 -0
- package/dist/yaml.js +145 -0
- package/dist/yaml.js.map +1 -0
- package/package.json +35 -0
- package/schemas/psdl-0.5.yaml +1223 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collect-refs.d.ts","sourceRoot":"","sources":["../src/collect-refs.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAmB,MAAM,EAAE,MAAM,YAAY,CAAC;AAY1D,2EAA2E;AAC3E,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC,CA4C3D"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { walkExpr } from "./expr.js";
|
|
2
|
+
import { isField } from "./utils.js";
|
|
3
|
+
function isExpr(value) {
|
|
4
|
+
return typeof value === "object" && value !== null && "kind" in value &&
|
|
5
|
+
typeof value.kind === "string";
|
|
6
|
+
}
|
|
7
|
+
function isUntilCount(value) {
|
|
8
|
+
return typeof value === "object" && value !== null && "until" in value &&
|
|
9
|
+
isExpr(value.until);
|
|
10
|
+
}
|
|
11
|
+
/** All plain field-id references reachable from a packet's expressions. */
|
|
12
|
+
export function collectPsdlRefs(packet) {
|
|
13
|
+
const out = new Set();
|
|
14
|
+
const visit = (e) => {
|
|
15
|
+
walkExpr(e, (n) => {
|
|
16
|
+
if (n.kind === "ref")
|
|
17
|
+
out.add(n.field);
|
|
18
|
+
});
|
|
19
|
+
};
|
|
20
|
+
const walk = (containers) => {
|
|
21
|
+
for (const c of containers) {
|
|
22
|
+
if (isField(c)) {
|
|
23
|
+
// A delimiter-terminated bytes length (`delimiter` form, §3) carries no Expr.
|
|
24
|
+
if (c.type.kind === "bytes" && isExpr(c.type.n))
|
|
25
|
+
visit(c.type.n);
|
|
26
|
+
if (c.computedFrom)
|
|
27
|
+
visit(c.computedFrom);
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
switch (c.kind) {
|
|
31
|
+
case "virtual":
|
|
32
|
+
visit(c.expr);
|
|
33
|
+
break;
|
|
34
|
+
case "group":
|
|
35
|
+
walk(c.children);
|
|
36
|
+
break;
|
|
37
|
+
case "bounded":
|
|
38
|
+
visit(c.bytes);
|
|
39
|
+
walk(c.fields);
|
|
40
|
+
break;
|
|
41
|
+
case "switch":
|
|
42
|
+
visit(c.on);
|
|
43
|
+
for (const arm of Object.values(c.cases))
|
|
44
|
+
walk(arm.fields);
|
|
45
|
+
break;
|
|
46
|
+
case "repeat":
|
|
47
|
+
if (isExpr(c.count))
|
|
48
|
+
visit(c.count);
|
|
49
|
+
else if (isUntilCount(c.count))
|
|
50
|
+
visit(c.count.until);
|
|
51
|
+
walk(c.element.fields);
|
|
52
|
+
break;
|
|
53
|
+
case "encrypted":
|
|
54
|
+
if (c.wireBits)
|
|
55
|
+
visit(c.wireBits);
|
|
56
|
+
walk(c.plaintext.fields);
|
|
57
|
+
break;
|
|
58
|
+
case "optional":
|
|
59
|
+
visit(c.when);
|
|
60
|
+
walk([c.container]);
|
|
61
|
+
break;
|
|
62
|
+
// align, ref: no inline field-id expressions
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
walk(packet.body);
|
|
67
|
+
if (packet.defs)
|
|
68
|
+
for (const def of Object.values(packet.defs))
|
|
69
|
+
walk(def.fields);
|
|
70
|
+
for (const con of packet.constraints ?? []) {
|
|
71
|
+
visit(con.lhs);
|
|
72
|
+
visit(con.rhs);
|
|
73
|
+
}
|
|
74
|
+
return out;
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=collect-refs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collect-refs.js","sourceRoot":"","sources":["../src/collect-refs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import type { Constraint, NormativeLevel, PacketEnv } from "./types.js";
|
|
2
|
+
export type PropagateOk = {
|
|
3
|
+
ok: PacketEnv;
|
|
4
|
+
};
|
|
5
|
+
/**
|
|
6
|
+
* A hard solver conflict (§9.1). `index` identifies the conflicting constraint
|
|
7
|
+
* within the `constraints` array (so an LSP can map the conflict back to a
|
|
8
|
+
* source range) and `env` carries the partially-propagated environment at the
|
|
9
|
+
* moment the conflict was detected — re-running `validateConstraints` over it
|
|
10
|
+
* reproduces the conflict with full per-constraint diagnostics. Both fields
|
|
11
|
+
* are additive (older callers that only read `conflict` keep working).
|
|
12
|
+
*/
|
|
13
|
+
export type PropagateConflict = {
|
|
14
|
+
conflict: string;
|
|
15
|
+
index?: number;
|
|
16
|
+
env?: PacketEnv;
|
|
17
|
+
};
|
|
18
|
+
export type PropagateResult = PropagateOk | PropagateConflict;
|
|
19
|
+
export declare function propagate(constraints: Constraint[], env: PacketEnv, changedKey: string): PropagateResult;
|
|
20
|
+
/**
|
|
21
|
+
* Fixpoint back-propagation (§9): re-run the constraint list until no new
|
|
22
|
+
* field is resolved in a pass. Seeds the pass set from every key in `env`
|
|
23
|
+
* UNION every ref mentioned by a `must` (or level-less) constraint, so a
|
|
24
|
+
* constraint sharing no ref with the env — e.g. the literal-only
|
|
25
|
+
* `version == 4` — still fires and can start a resolution chain (§9
|
|
26
|
+
* "re-runs the full constraint list until no new fields are resolved").
|
|
27
|
+
*/
|
|
28
|
+
export declare function propagateFixpoint(constraints: Constraint[], env: PacketEnv): PropagateResult;
|
|
29
|
+
/**
|
|
30
|
+
* A constraint mismatch diagnostic (§9.1). EVERY failing constraint — `must`
|
|
31
|
+
* included — is reported as one of these: `should`/`may` mismatches are
|
|
32
|
+
* advisories (warning/info), while a failing `must` additionally drives the
|
|
33
|
+
* hard `conflict` (so a `must` violation appears both as the `conflict` string
|
|
34
|
+
* and as a level-tagged entry here). `index` identifies the failing constraint
|
|
35
|
+
* within the `constraints` array (so an LSP can map the diagnostic back to a
|
|
36
|
+
* source range) and `doc` copies the constraint's authored doc string when
|
|
37
|
+
* present.
|
|
38
|
+
*/
|
|
39
|
+
export type ConstraintDiagnostic = {
|
|
40
|
+
index: number;
|
|
41
|
+
level: NormativeLevel;
|
|
42
|
+
message: string;
|
|
43
|
+
doc?: string;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* Evaluate every constraint for diagnostics (§9.1). `must` (and level-less)
|
|
47
|
+
* mismatches become a hard `conflict`; `should`/`may` mismatches are collected
|
|
48
|
+
* into `diagnostics` (level-tagged) so the caller can map them to warning/info
|
|
49
|
+
* severities. `should`/`may` never produce a conflict, matching the solver's
|
|
50
|
+
* back-propagation exclusion in `propagate`. EVERY failing constraint — `must`
|
|
51
|
+
* included — also appears in `diagnostics` with its index, so an LSP can map
|
|
52
|
+
* each violation (not just the first) back to a source range; the `conflict`
|
|
53
|
+
* string is derived from the first failing `must` in declaration order.
|
|
54
|
+
* Evaluation errors (e.g. division by zero in an expression) likewise never
|
|
55
|
+
* escape as exceptions: they become a diagnostic at the constraint's level
|
|
56
|
+
* (plus the hard conflict for `must`), so a single broken advisory constraint
|
|
57
|
+
* cannot crash diagnostics generation.
|
|
58
|
+
*/
|
|
59
|
+
export declare function validateConstraints(constraints: Constraint[], env: PacketEnv): {
|
|
60
|
+
ok: true;
|
|
61
|
+
diagnostics?: ConstraintDiagnostic[];
|
|
62
|
+
} | {
|
|
63
|
+
conflict: string;
|
|
64
|
+
diagnostics: ConstraintDiagnostic[];
|
|
65
|
+
};
|
|
66
|
+
//# sourceMappingURL=constraint.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constraint.d.ts","sourceRoot":"","sources":["../src/constraint.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAQ,cAAc,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE9E,MAAM,MAAM,WAAW,GAAG;IAAE,EAAE,EAAE,SAAS,CAAA;CAAE,CAAC;AAC5C;;;;;;;GAOG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,GAAG,CAAC,EAAE,SAAS,CAAA;CAAE,CAAC;AACtF,MAAM,MAAM,eAAe,GAAG,WAAW,GAAG,iBAAiB,CAAC;AA6I9D,wBAAgB,SAAS,CACvB,WAAW,EAAE,UAAU,EAAE,EACzB,GAAG,EAAE,SAAS,EACd,UAAU,EAAE,MAAM,GACjB,eAAe,CAsCjB;AAUD;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,UAAU,EAAE,EACzB,GAAG,EAAE,SAAS,GACb,eAAe,CA2BjB;AAED;;;;;;;;;GASG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,cAAc,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd,CAAC;AAOF;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CACjC,WAAW,EAAE,UAAU,EAAE,EACzB,GAAG,EAAE,SAAS,GACb;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,WAAW,CAAC,EAAE,oBAAoB,EAAE,CAAA;CAAE,GACjD;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,oBAAoB,EAAE,CAAA;CAAE,CA0B5D"}
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
import { evalExpr, exprContains, MissingRefError, walkExpr } from "./expr.js";
|
|
2
|
+
function solveFor(expr, targetRef, known, env) {
|
|
3
|
+
if (expr.kind === "ref")
|
|
4
|
+
return expr.field === targetRef ? known : null;
|
|
5
|
+
if (expr.kind !== "op")
|
|
6
|
+
return null; // only linear op-trees are invertible
|
|
7
|
+
const aHas = containsRef(expr.a, targetRef);
|
|
8
|
+
const bHas = containsRef(expr.b, targetRef);
|
|
9
|
+
if (aHas === bHas)
|
|
10
|
+
return null;
|
|
11
|
+
if (aHas) {
|
|
12
|
+
const bVal = evalConst(expr.b, env);
|
|
13
|
+
if (bVal === null)
|
|
14
|
+
return null;
|
|
15
|
+
const peeled = invertLeft(expr.op, known, bVal);
|
|
16
|
+
if (peeled === null)
|
|
17
|
+
return null;
|
|
18
|
+
return solveFor(expr.a, targetRef, peeled, env);
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
const aVal = evalConst(expr.a, env);
|
|
22
|
+
if (aVal === null)
|
|
23
|
+
return null;
|
|
24
|
+
const peeled = invertRight(expr.op, known, aVal);
|
|
25
|
+
if (peeled === null)
|
|
26
|
+
return null;
|
|
27
|
+
return solveFor(expr.b, targetRef, peeled, env);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function containsRef(expr, target) {
|
|
31
|
+
return exprContains(expr, (e) => e.kind === "ref" && e.field === target);
|
|
32
|
+
}
|
|
33
|
+
function evalConst(expr, env) {
|
|
34
|
+
try {
|
|
35
|
+
return evalExpr(expr, env);
|
|
36
|
+
}
|
|
37
|
+
catch (e) {
|
|
38
|
+
if (e instanceof MissingRefError)
|
|
39
|
+
return null;
|
|
40
|
+
throw e;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
// Invert `a OP known = result` for `a` (the unknown on the LEFT operand).
|
|
44
|
+
// Shifts use the semantics of expr.ts (`<<` → `(a<<b)>>>0` unsigned, `>>` →
|
|
45
|
+
// arithmetic `a>>b`, §4). They are lossy and not uniquely invertible, so the
|
|
46
|
+
// candidate produced here is verified by re-evaluation in applyKnownSide
|
|
47
|
+
// before adoption.
|
|
48
|
+
function invertLeft(o, result, known) {
|
|
49
|
+
switch (o) {
|
|
50
|
+
case "+": return result - known;
|
|
51
|
+
case "-": return result + known;
|
|
52
|
+
case "*": return known === 0 ? null : Math.trunc(result / known);
|
|
53
|
+
case "/": return result * known;
|
|
54
|
+
case "%": return null;
|
|
55
|
+
case "<<": return result >>> known; // inverse of (a << known)>>>0
|
|
56
|
+
case ">>": return (result << known) | 0; // inverse of arithmetic a >> known
|
|
57
|
+
}
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
// Invert `known OP b = result` for `b` (the unknown on the RIGHT operand).
|
|
61
|
+
function invertRight(o, result, known) {
|
|
62
|
+
switch (o) {
|
|
63
|
+
case "+": return result - known;
|
|
64
|
+
case "-": return known - result;
|
|
65
|
+
case "*": return known === 0 ? null : Math.trunc(result / known);
|
|
66
|
+
case "/": return result === 0 ? null : Math.trunc(known / result);
|
|
67
|
+
case "%": return null;
|
|
68
|
+
// Shift amount as the unknown is not soundly invertible.
|
|
69
|
+
case "<<": return null;
|
|
70
|
+
case ">>": return null;
|
|
71
|
+
}
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
/** Refs in `expr` whose value is not yet known in `env`. */
|
|
75
|
+
function unknownRefs(expr, env) {
|
|
76
|
+
return uniqueRefs(expr).filter((r) => !env.has(r));
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Given that `known` is the value of one side of an equality, try to use it to
|
|
80
|
+
* resolve the other (`other`) side: solve its single unknown, or detect a
|
|
81
|
+
* conflict when it is fully determined and disagrees. `knownSide` names the
|
|
82
|
+
* side `known` came from so conflict messages keep the lhs/rhs orientation,
|
|
83
|
+
* and `c` supplies the authored doc string for the message (§9.1).
|
|
84
|
+
*/
|
|
85
|
+
function applyKnownSide(known, other, next, knownSide, c) {
|
|
86
|
+
const unknowns = unknownRefs(other, next);
|
|
87
|
+
if (unknowns.length === 0) {
|
|
88
|
+
let otherVal;
|
|
89
|
+
try {
|
|
90
|
+
otherVal = evalConst(other, next);
|
|
91
|
+
}
|
|
92
|
+
catch (e) {
|
|
93
|
+
// Mirror validateConstraints: a `must` expression that cannot be
|
|
94
|
+
// evaluated is a hard conflict, never an uncaught exception.
|
|
95
|
+
return { conflict: withDoc(`Constraint evaluation error: ${e instanceof Error ? e.message : String(e)}`, c) };
|
|
96
|
+
}
|
|
97
|
+
if (otherVal !== null && otherVal !== known) {
|
|
98
|
+
const [l, r] = knownSide === "lhs" ? [known, otherVal] : [otherVal, known];
|
|
99
|
+
return { conflict: withDoc(`Constraint failed: lhs=${l} rhs=${r}`, c) };
|
|
100
|
+
}
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
if (unknowns.length === 1) {
|
|
104
|
+
// Like the probe below, an evaluation error while inverting (e.g. a
|
|
105
|
+
// constant zero-divisor subtree next to the unknown ref) just means no
|
|
106
|
+
// candidate can be derived — not a conflict, and never an uncaught
|
|
107
|
+
// exception out of the solver. This matches validateConstraints, which
|
|
108
|
+
// skips the constraint when a side cannot be evaluated.
|
|
109
|
+
let solved;
|
|
110
|
+
try {
|
|
111
|
+
solved = solveFor(other, unknowns[0], known, next);
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
solved = null;
|
|
115
|
+
}
|
|
116
|
+
if (solved !== null) {
|
|
117
|
+
// Inversion through lossy operators (shifts, truncating division) is not
|
|
118
|
+
// guaranteed to round-trip under the unsigned evaluator. Adopt the solved
|
|
119
|
+
// value only if re-evaluating `other` actually reproduces `known`. An
|
|
120
|
+
// evaluation error on the probe (e.g. the candidate lands as a zero
|
|
121
|
+
// divisor) just means the candidate is not adoptable — not a conflict.
|
|
122
|
+
const probe = new Map(next);
|
|
123
|
+
probe.set(unknowns[0], solved);
|
|
124
|
+
let check;
|
|
125
|
+
try {
|
|
126
|
+
check = evalConst(other, probe);
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
check = null;
|
|
130
|
+
}
|
|
131
|
+
if (check === known)
|
|
132
|
+
next.set(unknowns[0], solved);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
export function propagate(constraints, env, changedKey) {
|
|
138
|
+
const next = new Map(env);
|
|
139
|
+
for (const [index, c] of constraints.entries()) {
|
|
140
|
+
// Only `must` (and level-less) constraints back-propagate (§9.1). `should`/
|
|
141
|
+
// `may` are diagnostic-only and excluded from both value derivation and the
|
|
142
|
+
// conflict detection below, so relaxing a level never changes any
|
|
143
|
+
// wire-parsed value (it can drop solver-derived values and hard-failure
|
|
144
|
+
// detection that the `must` was providing — see §9.1).
|
|
145
|
+
if (c.level !== undefined && c.level !== "must")
|
|
146
|
+
continue;
|
|
147
|
+
// A constraint with no ref node at all (literal-only, or built solely from
|
|
148
|
+
// env-backed nullaries like `remaining`) can never match the changed-key
|
|
149
|
+
// gate, yet may still be violated — always evaluate it as a pure check.
|
|
150
|
+
const refLess = uniqueRefs(c.lhs).length === 0 && uniqueRefs(c.rhs).length === 0;
|
|
151
|
+
if (!refLess && !containsRef(c.lhs, changedKey) && !containsRef(c.rhs, changedKey))
|
|
152
|
+
continue;
|
|
153
|
+
let lhsVal;
|
|
154
|
+
let rhsVal;
|
|
155
|
+
try {
|
|
156
|
+
lhsVal = evalConst(c.lhs, next);
|
|
157
|
+
rhsVal = evalConst(c.rhs, next);
|
|
158
|
+
}
|
|
159
|
+
catch (e) {
|
|
160
|
+
// Mirror validateConstraints: an evaluation error (e.g. division by zero
|
|
161
|
+
// on wire-derived values) in a `must` constraint is a hard conflict, not
|
|
162
|
+
// an uncaught exception out of the solver.
|
|
163
|
+
return { conflict: withDoc(`Constraint evaluation error: ${e instanceof Error ? e.message : String(e)}`, c), index, env: next };
|
|
164
|
+
}
|
|
165
|
+
if (lhsVal !== null && rhsVal !== null) {
|
|
166
|
+
if (lhsVal !== rhsVal)
|
|
167
|
+
return { conflict: withDoc(`Constraint failed: lhs=${lhsVal} rhs=${rhsVal}`, c), index, env: next };
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
if (lhsVal !== null) {
|
|
171
|
+
const conflict = applyKnownSide(lhsVal, c.rhs, next, "lhs", c);
|
|
172
|
+
if (conflict)
|
|
173
|
+
return { ...conflict, index, env: next };
|
|
174
|
+
}
|
|
175
|
+
else if (rhsVal !== null) {
|
|
176
|
+
const conflict = applyKnownSide(rhsVal, c.lhs, next, "rhs", c);
|
|
177
|
+
if (conflict)
|
|
178
|
+
return { ...conflict, index, env: next };
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return { ok: next };
|
|
182
|
+
}
|
|
183
|
+
function uniqueRefs(expr) {
|
|
184
|
+
const set = new Set();
|
|
185
|
+
walkExpr(expr, (e) => {
|
|
186
|
+
if (e.kind === "ref")
|
|
187
|
+
set.add(e.field);
|
|
188
|
+
});
|
|
189
|
+
return [...set];
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Fixpoint back-propagation (§9): re-run the constraint list until no new
|
|
193
|
+
* field is resolved in a pass. Seeds the pass set from every key in `env`
|
|
194
|
+
* UNION every ref mentioned by a `must` (or level-less) constraint, so a
|
|
195
|
+
* constraint sharing no ref with the env — e.g. the literal-only
|
|
196
|
+
* `version == 4` — still fires and can start a resolution chain (§9
|
|
197
|
+
* "re-runs the full constraint list until no new fields are resolved").
|
|
198
|
+
*/
|
|
199
|
+
export function propagateFixpoint(constraints, env) {
|
|
200
|
+
let current = new Map(env);
|
|
201
|
+
const seedKeys = new Set();
|
|
202
|
+
for (const c of constraints) {
|
|
203
|
+
if (c.level !== undefined && c.level !== "must")
|
|
204
|
+
continue; // §9.1
|
|
205
|
+
for (const r of uniqueRefs(c.lhs))
|
|
206
|
+
seedKeys.add(r);
|
|
207
|
+
for (const r of uniqueRefs(c.rhs))
|
|
208
|
+
seedKeys.add(r);
|
|
209
|
+
}
|
|
210
|
+
let changed = true;
|
|
211
|
+
let guard = 0;
|
|
212
|
+
const MAX_PASSES = 1000;
|
|
213
|
+
while (changed && guard++ < MAX_PASSES) {
|
|
214
|
+
changed = false;
|
|
215
|
+
const keys = new Set([...current.keys(), ...seedKeys]);
|
|
216
|
+
// Even with no keys at all (empty env, ref-less constraints only), run one
|
|
217
|
+
// pass so pure checks like `remaining == 0` still get evaluated.
|
|
218
|
+
if (keys.size === 0)
|
|
219
|
+
keys.add("");
|
|
220
|
+
for (const key of keys) {
|
|
221
|
+
const res = propagate(constraints, current, key);
|
|
222
|
+
if ("conflict" in res)
|
|
223
|
+
return res;
|
|
224
|
+
// Adopt newly resolved keys.
|
|
225
|
+
for (const [k, v] of res.ok) {
|
|
226
|
+
if (current.get(k) !== v) {
|
|
227
|
+
current = res.ok;
|
|
228
|
+
changed = true;
|
|
229
|
+
break;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return { ok: current };
|
|
235
|
+
}
|
|
236
|
+
/** Append the constraint's authored doc to a message, when present. */
|
|
237
|
+
function withDoc(message, c) {
|
|
238
|
+
return c.doc !== undefined ? `${message} (${c.doc})` : message;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Evaluate every constraint for diagnostics (§9.1). `must` (and level-less)
|
|
242
|
+
* mismatches become a hard `conflict`; `should`/`may` mismatches are collected
|
|
243
|
+
* into `diagnostics` (level-tagged) so the caller can map them to warning/info
|
|
244
|
+
* severities. `should`/`may` never produce a conflict, matching the solver's
|
|
245
|
+
* back-propagation exclusion in `propagate`. EVERY failing constraint — `must`
|
|
246
|
+
* included — also appears in `diagnostics` with its index, so an LSP can map
|
|
247
|
+
* each violation (not just the first) back to a source range; the `conflict`
|
|
248
|
+
* string is derived from the first failing `must` in declaration order.
|
|
249
|
+
* Evaluation errors (e.g. division by zero in an expression) likewise never
|
|
250
|
+
* escape as exceptions: they become a diagnostic at the constraint's level
|
|
251
|
+
* (plus the hard conflict for `must`), so a single broken advisory constraint
|
|
252
|
+
* cannot crash diagnostics generation.
|
|
253
|
+
*/
|
|
254
|
+
export function validateConstraints(constraints, env) {
|
|
255
|
+
const diagnostics = [];
|
|
256
|
+
let hardConflict = null;
|
|
257
|
+
for (const [index, c] of constraints.entries()) {
|
|
258
|
+
const level = c.level ?? "must";
|
|
259
|
+
const report = (message) => {
|
|
260
|
+
if (level === "must" && hardConflict === null)
|
|
261
|
+
hardConflict = withDoc(message, c);
|
|
262
|
+
diagnostics.push({ index, level, message, ...(c.doc !== undefined ? { doc: c.doc } : {}) });
|
|
263
|
+
};
|
|
264
|
+
let l;
|
|
265
|
+
let r;
|
|
266
|
+
try {
|
|
267
|
+
l = evalConst(c.lhs, env);
|
|
268
|
+
r = evalConst(c.rhs, env);
|
|
269
|
+
}
|
|
270
|
+
catch (e) {
|
|
271
|
+
report(`Constraint evaluation error: ${e instanceof Error ? e.message : String(e)}`);
|
|
272
|
+
continue;
|
|
273
|
+
}
|
|
274
|
+
if (l === null || r === null)
|
|
275
|
+
continue;
|
|
276
|
+
if (l !== r)
|
|
277
|
+
report(`Constraint failed: lhs=${l} rhs=${r}`);
|
|
278
|
+
}
|
|
279
|
+
// A hard conflict is only ever set by report(), which always pushes the
|
|
280
|
+
// matching `must` diagnostic first — so `diagnostics` is necessarily
|
|
281
|
+
// non-empty here and the conflict return carries it unconditionally.
|
|
282
|
+
if (hardConflict !== null)
|
|
283
|
+
return { conflict: hardConflict, diagnostics };
|
|
284
|
+
return diagnostics.length ? { ok: true, diagnostics } : { ok: true };
|
|
285
|
+
}
|
|
286
|
+
//# sourceMappingURL=constraint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constraint.js","sourceRoot":"","sources":["../src/constraint.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAe9E,SAAS,QAAQ,CACf,IAAU,EACV,SAAiB,EACjB,KAAa,EACb,GAAc;IAEd,IAAI,IAAI,CAAC,IAAI,KAAK,KAAK;QAAE,OAAO,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC;IACxE,IAAI,IAAI,CAAC,IAAI,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC,CAAC,sCAAsC;IAC3E,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;IAC5C,MAAM,IAAI,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;IAC5C,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IAC/B,IAAI,IAAI,EAAE,CAAC;QACT,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QACpC,IAAI,IAAI,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC;QAC/B,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;QAChD,IAAI,MAAM,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC;QACjC,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC;IAClD,CAAC;SAAM,CAAC;QACN,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;QACpC,IAAI,IAAI,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC;QAC/B,MAAM,MAAM,GAAG,WAAW,CAAC,IAAI,CAAC,EAAE,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;QACjD,IAAI,MAAM,KAAK,IAAI;YAAE,OAAO,IAAI,CAAC;QACjC,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC;IAClD,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAAC,IAAU,EAAE,MAAc;IAC7C,OAAO,YAAY,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM,CAAC,CAAC;AAC3E,CAAC;AAED,SAAS,SAAS,CAAC,IAAU,EAAE,GAAc;IAC3C,IAAI,CAAC;QACH,OAAO,QAAQ,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAC7B,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAI,CAAC,YAAY,eAAe;YAAE,OAAO,IAAI,CAAC;QAC9C,MAAM,CAAC,CAAC;IACV,CAAC;AACH,CAAC;AAED,0EAA0E;AAC1E,4EAA4E;AAC5E,6EAA6E;AAC7E,yEAAyE;AACzE,mBAAmB;AACnB,SAAS,UAAU,CAAC,CAAS,EAAE,MAAc,EAAE,KAAa;IAC1D,QAAQ,CAAC,EAAE,CAAC;QACV,KAAK,GAAG,CAAC,CAAC,OAAO,MAAM,GAAG,KAAK,CAAC;QAChC,KAAK,GAAG,CAAC,CAAC,OAAO,MAAM,GAAG,KAAK,CAAC;QAChC,KAAK,GAAG,CAAC,CAAC,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC;QACjE,KAAK,GAAG,CAAC,CAAC,OAAO,MAAM,GAAG,KAAK,CAAC;QAChC,KAAK,GAAG,CAAC,CAAC,OAAO,IAAI,CAAC;QACtB,KAAK,IAAI,CAAC,CAAC,OAAO,MAAM,KAAK,KAAK,CAAC,CAAQ,8BAA8B;QACzE,KAAK,IAAI,CAAC,CAAC,OAAO,CAAC,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,CAAI,mCAAmC;IACjF,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,2EAA2E;AAC3E,SAAS,WAAW,CAAC,CAAS,EAAE,MAAc,EAAE,KAAa;IAC3D,QAAQ,CAAC,EAAE,CAAC;QACV,KAAK,GAAG,CAAC,CAAC,OAAO,MAAM,GAAG,KAAK,CAAC;QAChC,KAAK,GAAG,CAAC,CAAC,OAAO,KAAK,GAAG,MAAM,CAAC;QAChC,KAAK,GAAG,CAAC,CAAC,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC;QACjE,KAAK,GAAG,CAAC,CAAC,OAAO,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,MAAM,CAAC,CAAC;QAClE,KAAK,GAAG,CAAC,CAAC,OAAO,IAAI,CAAC;QACtB,yDAAyD;QACzD,KAAK,IAAI,CAAC,CAAC,OAAO,IAAI,CAAC;QACvB,KAAK,IAAI,CAAC,CAAC,OAAO,IAAI,CAAC;IACzB,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,4DAA4D;AAC5D,SAAS,WAAW,CAAC,IAAU,EAAE,GAAc;IAC7C,OAAO,UAAU,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;AACrD,CAAC;AAED;;;;;;GAMG;AACH,SAAS,cAAc,CACrB,KAAa,EACb,KAAW,EACX,IAAe,EACf,SAAwB,EACxB,CAAa;IAEb,MAAM,QAAQ,GAAG,WAAW,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;IAC1C,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,IAAI,QAAuB,CAAC;QAC5B,IAAI,CAAC;YACH,QAAQ,GAAG,SAAS,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;QACpC,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,iEAAiE;YACjE,6DAA6D;YAC7D,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,gCAAgC,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC;QAChH,CAAC;QACD,IAAI,QAAQ,KAAK,IAAI,IAAI,QAAQ,KAAK,KAAK,EAAE,CAAC;YAC5C,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,SAAS,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;YAC3E,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,0BAA0B,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC;QAC1E,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1B,oEAAoE;QACpE,uEAAuE;QACvE,mEAAmE;QACnE,uEAAuE;QACvE,wDAAwD;QACxD,IAAI,MAAqB,CAAC;QAC1B,IAAI,CAAC;YACH,MAAM,GAAG,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAE,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC;QACtD,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,GAAG,IAAI,CAAC;QAChB,CAAC;QACD,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YACpB,yEAAyE;YACzE,0EAA0E;YAC1E,sEAAsE;YACtE,oEAAoE;YACpE,uEAAuE;YACvE,MAAM,KAAK,GAAc,IAAI,GAAG,CAAC,IAAI,CAAC,CAAC;YACvC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAE,EAAE,MAAM,CAAC,CAAC;YAChC,IAAI,KAAoB,CAAC;YACzB,IAAI,CAAC;gBACH,KAAK,GAAG,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;YAClC,CAAC;YAAC,MAAM,CAAC;gBACP,KAAK,GAAG,IAAI,CAAC;YACf,CAAC;YACD,IAAI,KAAK,KAAK,KAAK;gBAAE,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAE,EAAE,MAAM,CAAC,CAAC;QACtD,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,MAAM,UAAU,SAAS,CACvB,WAAyB,EACzB,GAAc,EACd,UAAkB;IAElB,MAAM,IAAI,GAAc,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;IACrC,KAAK,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,WAAW,CAAC,OAAO,EAAE,EAAE,CAAC;QAC/C,4EAA4E;QAC5E,4EAA4E;QAC5E,kEAAkE;QAClE,wEAAwE;QACxE,uDAAuD;QACvD,IAAI,CAAC,CAAC,KAAK,KAAK,SAAS,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM;YAAE,SAAS;QAC1D,2EAA2E;QAC3E,yEAAyE;QACzE,wEAAwE;QACxE,MAAM,OAAO,GAAG,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,KAAK,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC;QACjF,IAAI,CAAC,OAAO,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,EAAE,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,EAAE,UAAU,CAAC;YAAE,SAAS;QAC7F,IAAI,MAAqB,CAAC;QAC1B,IAAI,MAAqB,CAAC;QAC1B,IAAI,CAAC;YACH,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YAChC,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;QAClC,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,yEAAyE;YACzE,yEAAyE;YACzE,2CAA2C;YAC3C,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,gCAAgC,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;QAClI,CAAC;QACD,IAAI,MAAM,KAAK,IAAI,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YACvC,IAAI,MAAM,KAAK,MAAM;gBAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,0BAA0B,MAAM,QAAQ,MAAM,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;YAC3H,SAAS;QACX,CAAC;QACD,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YACpB,MAAM,QAAQ,GAAG,cAAc,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;YAC/D,IAAI,QAAQ;gBAAE,OAAO,EAAE,GAAG,QAAQ,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;QACzD,CAAC;aAAM,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;YAC3B,MAAM,QAAQ,GAAG,cAAc,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;YAC/D,IAAI,QAAQ;gBAAE,OAAO,EAAE,GAAG,QAAQ,EAAE,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;QACzD,CAAC;IACH,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;AACtB,CAAC;AAED,SAAS,UAAU,CAAC,IAAU;IAC5B,MAAM,GAAG,GAAG,IAAI,GAAG,EAAU,CAAC;IAC9B,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE;QACnB,IAAI,CAAC,CAAC,IAAI,KAAK,KAAK;YAAE,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IACzC,CAAC,CAAC,CAAC;IACH,OAAO,CAAC,GAAG,GAAG,CAAC,CAAC;AAClB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAC/B,WAAyB,EACzB,GAAc;IAEd,IAAI,OAAO,GAAc,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;IACtC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;IACnC,KAAK,MAAM,CAAC,IAAI,WAAW,EAAE,CAAC;QAC5B,IAAI,CAAC,CAAC,KAAK,KAAK,SAAS,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM;YAAE,SAAS,CAAC,OAAO;QAClE,KAAK,MAAM,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC;YAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACnD,KAAK,MAAM,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC;YAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACrD,CAAC;IACD,IAAI,OAAO,GAAG,IAAI,CAAC;IACnB,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,MAAM,UAAU,GAAG,IAAI,CAAC;IACxB,OAAO,OAAO,IAAI,KAAK,EAAE,GAAG,UAAU,EAAE,CAAC;QACvC,OAAO,GAAG,KAAK,CAAC;QAChB,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,EAAE,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAC;QACvD,2EAA2E;QAC3E,iEAAiE;QACjE,IAAI,IAAI,CAAC,IAAI,KAAK,CAAC;YAAE,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAClC,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,MAAM,GAAG,GAAG,SAAS,CAAC,WAAW,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;YACjD,IAAI,UAAU,IAAI,GAAG;gBAAE,OAAO,GAAG,CAAC;YAClC,6BAA6B;YAC7B,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,GAAG,CAAC,EAAE,EAAE,CAAC;gBAC5B,IAAI,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC;oBAAC,OAAO,GAAG,GAAG,CAAC,EAAE,CAAC;oBAAC,OAAO,GAAG,IAAI,CAAC;oBAAC,MAAM;gBAAC,CAAC;YACxE,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC;AACzB,CAAC;AAmBD,uEAAuE;AACvE,SAAS,OAAO,CAAC,OAAe,EAAE,CAAa;IAC7C,OAAO,CAAC,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,GAAG,OAAO,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC;AACjE,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,mBAAmB,CACjC,WAAyB,EACzB,GAAc;IAGd,MAAM,WAAW,GAA2B,EAAE,CAAC;IAC/C,IAAI,YAAY,GAAkB,IAAI,CAAC;IACvC,KAAK,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,WAAW,CAAC,OAAO,EAAE,EAAE,CAAC;QAC/C,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,IAAI,MAAM,CAAC;QAChC,MAAM,MAAM,GAAG,CAAC,OAAe,EAAQ,EAAE;YACvC,IAAI,KAAK,KAAK,MAAM,IAAI,YAAY,KAAK,IAAI;gBAAE,YAAY,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;YAClF,WAAW,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QAC9F,CAAC,CAAC;QACF,IAAI,CAAgB,CAAC;QACrB,IAAI,CAAgB,CAAC;QACrB,IAAI,CAAC;YACH,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YAC1B,CAAC,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QAC5B,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,CAAC,gCAAgC,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YACrF,SAAS;QACX,CAAC;QACD,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,KAAK,IAAI;YAAE,SAAS;QACvC,IAAI,CAAC,KAAK,CAAC;YAAE,MAAM,CAAC,0BAA0B,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC9D,CAAC;IACD,wEAAwE;IACxE,qEAAqE;IACrE,qEAAqE;IACrE,IAAI,YAAY,KAAK,IAAI;QAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,CAAC;IAC1E,OAAO,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;AACvE,CAAC"}
|
package/dist/expr.d.ts
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { BinOp, Expr, ExprWireSize, PacketEnv } from "./types.js";
|
|
2
|
+
export declare const lit: (value: number) => Expr;
|
|
3
|
+
export declare const ref: (field: string) => Expr;
|
|
4
|
+
export declare const op: (o: BinOp, a: Expr, b: Expr) => Expr;
|
|
5
|
+
export declare const cond: (test: Expr, t: Expr, f: Expr) => Expr;
|
|
6
|
+
export declare const peek: (bits: number, offset?: Expr) => Expr;
|
|
7
|
+
export declare const lookup: (key: Expr, table: Record<number, number>) => Expr;
|
|
8
|
+
export declare const wireSize: (target: string) => ExprWireSize;
|
|
9
|
+
export declare const prevIter: (field: string) => Expr;
|
|
10
|
+
export declare const remaining: () => Expr;
|
|
11
|
+
export declare const enclosingBits: () => Expr;
|
|
12
|
+
export declare const enclosingField: (field: string) => Expr;
|
|
13
|
+
export declare const peekEnvKey: (offset: number, bits: number) => string;
|
|
14
|
+
export declare const remainingEnvKey: () => string;
|
|
15
|
+
export declare const enclosingBitsEnvKey: () => string;
|
|
16
|
+
export declare const wireSizeEnvKey: (target: string) => string;
|
|
17
|
+
export declare const prevIterEnvKey: (field: string) => string;
|
|
18
|
+
export declare const enclosingFieldEnvKey: (field: string) => string;
|
|
19
|
+
export declare class MissingRefError extends Error {
|
|
20
|
+
readonly field: string;
|
|
21
|
+
constructor(field: string);
|
|
22
|
+
}
|
|
23
|
+
export declare function evalExpr(expr: Expr, env: PacketEnv): number;
|
|
24
|
+
/** Evaluate, returning `fallback` when a referenced field is missing (§10.3). */
|
|
25
|
+
export declare function evalExprOr(expr: Expr, env: PacketEnv, fallback?: number): number;
|
|
26
|
+
/** Plain field-id references (`ref`) reachable from an expression. */
|
|
27
|
+
export declare function exprRefs(expr: Expr): string[];
|
|
28
|
+
/** Visit every sub-expression node depth-first. */
|
|
29
|
+
export declare function walkExpr(expr: Expr, visit: (e: Expr) => void): void;
|
|
30
|
+
/** True if any sub-expression matches the predicate. */
|
|
31
|
+
export declare function exprContains(expr: Expr, pred: (e: Expr) => boolean): boolean;
|
|
32
|
+
//# sourceMappingURL=expr.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"expr.d.ts","sourceRoot":"","sources":["../src/expr.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAMvE,eAAO,MAAM,GAAG,GAAI,OAAO,MAAM,KAAG,IAAgC,CAAC;AACrE,eAAO,MAAM,GAAG,GAAI,OAAO,MAAM,KAAG,IAAgC,CAAC;AACrE,eAAO,MAAM,EAAE,GAAI,GAAG,KAAK,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,KAAG,IAAqC,CAAC;AACtF,eAAO,MAAM,IAAI,GAAI,MAAM,IAAI,EAAE,GAAG,IAAI,EAAE,GAAG,IAAI,KAAG,IAAsC,CAAC;AAC3F,eAAO,MAAM,IAAI,GAAI,MAAM,MAAM,EAAE,SAAS,IAAI,KAAG,IAC6B,CAAC;AACjF,eAAO,MAAM,MAAM,GAAI,KAAK,IAAI,EAAE,OAAO,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAG,IAAwC,CAAC;AAC3G,eAAO,MAAM,QAAQ,GAAI,QAAQ,MAAM,KAAG,YAA8C,CAAC;AACzF,eAAO,MAAM,QAAQ,GAAI,OAAO,MAAM,KAAG,IAAqC,CAAC;AAC/E,eAAO,MAAM,SAAS,QAAO,IAA+B,CAAC;AAC7D,eAAO,MAAM,aAAa,QAAO,IAAmC,CAAC;AACrE,eAAO,MAAM,cAAc,GAAI,OAAO,MAAM,KAAG,IAA2C,CAAC;AAO3F,eAAO,MAAM,UAAU,GAAI,QAAQ,MAAM,EAAE,MAAM,MAAM,KAAG,MAAsC,CAAC;AACjG,eAAO,MAAM,eAAe,QAAO,MAAyB,CAAC;AAC7D,eAAO,MAAM,mBAAmB,QAAO,MAA6B,CAAC;AACrE,eAAO,MAAM,cAAc,GAAI,QAAQ,MAAM,KAAG,MAAiC,CAAC;AAClF,eAAO,MAAM,cAAc,GAAI,OAAO,MAAM,KAAG,MAAgC,CAAC;AAChF,eAAO,MAAM,oBAAoB,GAAI,OAAO,MAAM,KAAG,MAAiC,CAAC;AAEvF,qBAAa,eAAgB,SAAQ,KAAK;aACZ,KAAK,EAAE,MAAM;gBAAb,KAAK,EAAE,MAAM;CAI1C;AAMD,wBAAgB,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,SAAS,GAAG,MAAM,CAsF3D;AAED,iFAAiF;AACjF,wBAAgB,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE,QAAQ,SAAI,GAAG,MAAM,CAO3E;AAMD,sEAAsE;AACtE,wBAAgB,QAAQ,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,EAAE,CAM7C;AAED,mDAAmD;AACnD,wBAAgB,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,EAAE,IAAI,KAAK,IAAI,GAAG,IAAI,CAiCnE;AAED,wDAAwD;AACxD,wBAAgB,YAAY,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,IAAI,KAAK,OAAO,GAAG,OAAO,CAM5E"}
|