@codai/axiom-mcp 2.0.0 → 2.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/README.md +57 -6
- package/dist/axm-lazy-CR-FmFVd.js +6255 -0
- package/dist/axm-lazy.js +81 -2
- package/dist/cli-main.js +2315 -264
- package/dist/dist-FFqnyzCe.js +6141 -0
- package/dist/gate-lazy.js +77 -1
- package/dist/http-lazy.js +15154 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +411 -21
- package/dist/lib-CqHwM4m_.js +3884 -0
- package/dist/migrate-lazy.js +6472 -0
- package/package.json +9 -7
- package/spec/codai-tools.json +65 -2
- package/spec/tools.json +324 -2
|
@@ -0,0 +1,3884 @@
|
|
|
1
|
+
var CelError = class extends Error {
|
|
2
|
+
#node;
|
|
3
|
+
#code;
|
|
4
|
+
#range;
|
|
5
|
+
#summary;
|
|
6
|
+
constructor({ name, code, message, node, cause, range }) {
|
|
7
|
+
super(message, cause ? { cause } : void 0);
|
|
8
|
+
this.name = name;
|
|
9
|
+
this.#code = code;
|
|
10
|
+
this.#summary = message;
|
|
11
|
+
this.#node = node;
|
|
12
|
+
this.#range = range && normalizeRange(range) || normalizeRange(node);
|
|
13
|
+
if (!node?.input) return;
|
|
14
|
+
this.message = formatErrorWithHighlight(this.#summary, node, this.#range);
|
|
15
|
+
}
|
|
16
|
+
get node() {
|
|
17
|
+
return this.#node;
|
|
18
|
+
}
|
|
19
|
+
get code() {
|
|
20
|
+
return this.#code;
|
|
21
|
+
}
|
|
22
|
+
get range() {
|
|
23
|
+
return this.#range;
|
|
24
|
+
}
|
|
25
|
+
get summary() {
|
|
26
|
+
return this.#summary;
|
|
27
|
+
}
|
|
28
|
+
withAst(node) {
|
|
29
|
+
if (this.#node || !node?.input) return this;
|
|
30
|
+
this.#node = node;
|
|
31
|
+
this.#range ??= normalizeRange(node);
|
|
32
|
+
this.message = formatErrorWithHighlight(this.#summary, node, this.#range);
|
|
33
|
+
return this;
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
function normalizeArgs(name, defaultCode, message, node, cause) {
|
|
37
|
+
if (typeof message === "string") return {
|
|
38
|
+
name,
|
|
39
|
+
code: defaultCode,
|
|
40
|
+
message,
|
|
41
|
+
node,
|
|
42
|
+
cause
|
|
43
|
+
};
|
|
44
|
+
const opts = message;
|
|
45
|
+
if (typeof opts !== "object") throw new Error("First param to error must be a string or object");
|
|
46
|
+
return {
|
|
47
|
+
name,
|
|
48
|
+
code: opts.code || defaultCode,
|
|
49
|
+
message: opts.message,
|
|
50
|
+
node: opts.node,
|
|
51
|
+
cause: opts.cause,
|
|
52
|
+
range: opts.range
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
var ParseError = class extends CelError {
|
|
56
|
+
constructor(message, node, cause) {
|
|
57
|
+
super(normalizeArgs("ParseError", "parse_error", message, node, cause));
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
var EvaluationError = class extends CelError {
|
|
61
|
+
constructor(message, node, cause) {
|
|
62
|
+
super(normalizeArgs("EvaluationError", "evaluation_error", message, node, cause));
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
var TypeError$1 = class extends CelError {
|
|
66
|
+
constructor(message, node, cause) {
|
|
67
|
+
super(normalizeArgs("TypeError", "type_error", message, node, cause));
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
function parseError(code, message, node) {
|
|
71
|
+
if (typeof code === "object") return new ParseError(code);
|
|
72
|
+
return new ParseError({
|
|
73
|
+
code,
|
|
74
|
+
message,
|
|
75
|
+
node
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
function evaluationError(code, message, node) {
|
|
79
|
+
if (typeof code === "object") return new EvaluationError(code);
|
|
80
|
+
return new EvaluationError({
|
|
81
|
+
code,
|
|
82
|
+
message,
|
|
83
|
+
node
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
function typeError(code, message, node) {
|
|
87
|
+
if (typeof code === "object") return new TypeError$1(code);
|
|
88
|
+
return new TypeError$1({
|
|
89
|
+
code,
|
|
90
|
+
message,
|
|
91
|
+
node
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
function normalizeRange(node) {
|
|
95
|
+
const start = node?.pos ?? node?.start;
|
|
96
|
+
if (typeof start !== "number") return;
|
|
97
|
+
return {
|
|
98
|
+
start,
|
|
99
|
+
end: typeof node.end === "number" ? node.end : start
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
function formatErrorWithHighlight(message, node, range) {
|
|
103
|
+
const pos = node.pos ?? range?.start;
|
|
104
|
+
if (typeof pos !== "number") return message;
|
|
105
|
+
const input = node.input;
|
|
106
|
+
let lineNum = 1;
|
|
107
|
+
let currentPos = 0;
|
|
108
|
+
let columnNum = 0;
|
|
109
|
+
while (currentPos < pos) {
|
|
110
|
+
if (input[currentPos] === "\n") {
|
|
111
|
+
lineNum++;
|
|
112
|
+
columnNum = 0;
|
|
113
|
+
} else columnNum++;
|
|
114
|
+
currentPos++;
|
|
115
|
+
}
|
|
116
|
+
let contextStart = pos;
|
|
117
|
+
let contextEnd = pos;
|
|
118
|
+
while (contextStart > 0 && input[contextStart - 1] !== "\n") contextStart--;
|
|
119
|
+
while (contextEnd < input.length && input[contextEnd] !== "\n") contextEnd++;
|
|
120
|
+
const line = input.slice(contextStart, contextEnd);
|
|
121
|
+
return `${message}\n\n${`> ${`${lineNum}`.padStart(4, " ")} | ${line}\n${" ".repeat(9 + columnNum)}^`}`;
|
|
122
|
+
}
|
|
123
|
+
function attachErrorAst(error, node) {
|
|
124
|
+
if (error instanceof CelError) return error.withAst(node);
|
|
125
|
+
return error;
|
|
126
|
+
}
|
|
127
|
+
var Optional = class Optional {
|
|
128
|
+
#value;
|
|
129
|
+
constructor(value) {
|
|
130
|
+
this.#value = value;
|
|
131
|
+
}
|
|
132
|
+
static of(value) {
|
|
133
|
+
if (value === void 0) return OPTIONAL_NONE;
|
|
134
|
+
return new Optional(value);
|
|
135
|
+
}
|
|
136
|
+
static none() {
|
|
137
|
+
return OPTIONAL_NONE;
|
|
138
|
+
}
|
|
139
|
+
hasValue() {
|
|
140
|
+
return this.#value !== void 0;
|
|
141
|
+
}
|
|
142
|
+
value() {
|
|
143
|
+
if (this.#value === void 0) throw evaluationError("optional_value_missing", "Optional value is not present");
|
|
144
|
+
return this.#value;
|
|
145
|
+
}
|
|
146
|
+
or(optional) {
|
|
147
|
+
if (this.#value !== void 0) return this;
|
|
148
|
+
if (optional instanceof Optional) return optional;
|
|
149
|
+
throw evaluationError("invalid_optional_argument", "Optional.or must be called with an Optional argument");
|
|
150
|
+
}
|
|
151
|
+
orValue(defaultValue) {
|
|
152
|
+
return this.#value === void 0 ? defaultValue : this.#value;
|
|
153
|
+
}
|
|
154
|
+
get [Symbol.toStringTag]() {
|
|
155
|
+
return "optional";
|
|
156
|
+
}
|
|
157
|
+
[Symbol.for("nodejs.util.inspect.custom")]() {
|
|
158
|
+
return this.#value === void 0 ? `Optional { none }` : `Optional { value: ${JSON.stringify(this.#value)} }`;
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
const OPTIONAL_NONE = Object.freeze(new Optional());
|
|
162
|
+
var OptionalNamespace = class {};
|
|
163
|
+
const optionalNamespace = new OptionalNamespace();
|
|
164
|
+
function toggleOptionalTypes(registry, enable) {
|
|
165
|
+
const optionalConstant = enable ? optionalNamespace : void 0;
|
|
166
|
+
registry.deleteVariable("optional");
|
|
167
|
+
registry.registerConstant("optional", "OptionalNamespace", optionalConstant);
|
|
168
|
+
}
|
|
169
|
+
function register(registry) {
|
|
170
|
+
const sync = { async: false };
|
|
171
|
+
const functionOverload = (sig, handler) => registry.registerFunctionOverload(sig, handler, sync);
|
|
172
|
+
const optionalConstant = registry.enableOptionalTypes ? optionalNamespace : void 0;
|
|
173
|
+
registry.registerType("OptionalNamespace", OptionalNamespace);
|
|
174
|
+
registry.registerConstant("optional", "OptionalNamespace", optionalConstant);
|
|
175
|
+
functionOverload("optional.hasValue(): bool", (v) => v.hasValue());
|
|
176
|
+
functionOverload("optional<A>.value(): A", (v) => v.value());
|
|
177
|
+
registry.registerFunctionOverload("OptionalNamespace.none(): optional<T>", () => Optional.none());
|
|
178
|
+
functionOverload("OptionalNamespace.of(A): optional<A>", (_, value) => Optional.of(value));
|
|
179
|
+
function ensureOptional(value, ast, description) {
|
|
180
|
+
if (value instanceof Optional) return value;
|
|
181
|
+
throw evaluationError("optional_expected", `${description} must be optional`, ast);
|
|
182
|
+
}
|
|
183
|
+
function evaluateOptional(ev, macro, ctx) {
|
|
184
|
+
const v = ev.run(macro.receiver, ctx);
|
|
185
|
+
if (v instanceof Promise) return v.then((_v) => handleOptionalResolved(_v, ev, macro, ctx));
|
|
186
|
+
return handleOptionalResolved(v, ev, macro, ctx);
|
|
187
|
+
}
|
|
188
|
+
function handleOptionalResolved(value, ev, macro, ctx) {
|
|
189
|
+
const optional = ensureOptional(value, macro.receiver, `${macro.functionDesc} receiver`);
|
|
190
|
+
if (optional.hasValue()) return macro.onHasValue(optional);
|
|
191
|
+
return macro.onEmpty(ev, macro, ctx);
|
|
192
|
+
}
|
|
193
|
+
function ensureOptionalType(checker, node, ctx, description) {
|
|
194
|
+
const type = checker.check(node, ctx);
|
|
195
|
+
if (type.kind === "optional") return type;
|
|
196
|
+
if (type.kind === "dyn") return checker.getType("optional");
|
|
197
|
+
throw checker.createError("optional_expected", `${description} must be optional, got '${type}'`, node);
|
|
198
|
+
}
|
|
199
|
+
function createOptionalMacro({ functionDesc, evaluate, typeCheck, onHasValue, onEmpty }) {
|
|
200
|
+
return ({ ast, args, receiver }) => ({
|
|
201
|
+
ast,
|
|
202
|
+
functionDesc,
|
|
203
|
+
receiver,
|
|
204
|
+
arg: args[0],
|
|
205
|
+
evaluate,
|
|
206
|
+
typeCheck,
|
|
207
|
+
onHasValue,
|
|
208
|
+
onEmpty
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
const invalidOrValueReceiver = "optional.orValue() receiver";
|
|
212
|
+
const invalidOrReceiver = "optional.or(optional) receiver";
|
|
213
|
+
const invalidOrArg = "optional.or(optional) argument";
|
|
214
|
+
registry.registerFunctionOverload("optional.or(ast): optional<dyn>", createOptionalMacro({
|
|
215
|
+
functionDesc: "optional.or(optional)",
|
|
216
|
+
evaluate: evaluateOptional,
|
|
217
|
+
typeCheck(check, macro, ctx) {
|
|
218
|
+
const l = ensureOptionalType(check, macro.receiver, ctx, invalidOrReceiver);
|
|
219
|
+
const r = ensureOptionalType(check, macro.arg, ctx, invalidOrArg);
|
|
220
|
+
if (!(macro.receiver.maybeAsync || macro.arg.maybeAsync)) macro.ast.setMeta("async", false);
|
|
221
|
+
const unified = l.unify(check.registry, r);
|
|
222
|
+
if (unified) return unified;
|
|
223
|
+
throw check.createError("incompatible_argument_type", `${macro.functionDesc} argument must be compatible type, got '${l}' and '${r}'`, macro.arg);
|
|
224
|
+
},
|
|
225
|
+
onHasValue: (optional) => optional,
|
|
226
|
+
onEmpty(ev, macro, ctx) {
|
|
227
|
+
const ast = macro.arg;
|
|
228
|
+
const v = ev.run(ast, ctx);
|
|
229
|
+
if (v instanceof Promise) return v.then((_v) => ensureOptional(_v, ast, invalidOrArg));
|
|
230
|
+
return ensureOptional(v, ast, invalidOrArg);
|
|
231
|
+
}
|
|
232
|
+
}));
|
|
233
|
+
registry.registerFunctionOverload("optional.orValue(ast): dyn", createOptionalMacro({
|
|
234
|
+
functionDesc: "optional.orValue(value)",
|
|
235
|
+
onHasValue: (optionalValue) => optionalValue.value(),
|
|
236
|
+
onEmpty(ev, macro, ctx) {
|
|
237
|
+
return ev.run(macro.arg, ctx);
|
|
238
|
+
},
|
|
239
|
+
evaluate: evaluateOptional,
|
|
240
|
+
typeCheck(check, macro, ctx) {
|
|
241
|
+
const l = ensureOptionalType(check, macro.receiver, ctx, invalidOrValueReceiver).valueType;
|
|
242
|
+
const r = check.check(macro.arg, ctx);
|
|
243
|
+
if (!(macro.receiver.maybeAsync || macro.arg.maybeAsync)) macro.ast.setMeta("async", false);
|
|
244
|
+
const unified = l.unify(check.registry, r);
|
|
245
|
+
if (unified) return unified;
|
|
246
|
+
throw check.createError("incompatible_argument_type", `${macro.functionDesc} argument must be compatible type, got '${l}' and '${r}'`, macro.arg);
|
|
247
|
+
}
|
|
248
|
+
}));
|
|
249
|
+
}
|
|
250
|
+
const hasOwn = Object.hasOwn;
|
|
251
|
+
const objKeys = Object.keys;
|
|
252
|
+
const objFreeze = Object.freeze;
|
|
253
|
+
const objEntries = Object.entries;
|
|
254
|
+
const isArray = Array.isArray;
|
|
255
|
+
const arrayFrom = Array.from;
|
|
256
|
+
function isAsync(fn, fallback) {
|
|
257
|
+
if (fn?.[Symbol.toStringTag] === "AsyncFunction") return true;
|
|
258
|
+
return typeof fallback === "boolean" ? fallback : true;
|
|
259
|
+
}
|
|
260
|
+
const RESERVED = /* @__PURE__ */ new Set([
|
|
261
|
+
"as",
|
|
262
|
+
"break",
|
|
263
|
+
"const",
|
|
264
|
+
"continue",
|
|
265
|
+
"else",
|
|
266
|
+
"for",
|
|
267
|
+
"function",
|
|
268
|
+
"if",
|
|
269
|
+
"import",
|
|
270
|
+
"let",
|
|
271
|
+
"loop",
|
|
272
|
+
"package",
|
|
273
|
+
"namespace",
|
|
274
|
+
"return",
|
|
275
|
+
"var",
|
|
276
|
+
"void",
|
|
277
|
+
"while",
|
|
278
|
+
"__proto__",
|
|
279
|
+
"prototype"
|
|
280
|
+
]);
|
|
281
|
+
var UnsignedInt = class {
|
|
282
|
+
#value;
|
|
283
|
+
constructor(value) {
|
|
284
|
+
this.verify(typeof value === "bigint" ? value : BigInt(value));
|
|
285
|
+
}
|
|
286
|
+
get value() {
|
|
287
|
+
return this.#value;
|
|
288
|
+
}
|
|
289
|
+
valueOf() {
|
|
290
|
+
return this.#value;
|
|
291
|
+
}
|
|
292
|
+
toString() {
|
|
293
|
+
return `${this.#value}`;
|
|
294
|
+
}
|
|
295
|
+
verify(v) {
|
|
296
|
+
if (v < 0n || v > 18446744073709551615n) throw evaluationError("numeric_overflow", "Unsigned integer overflow");
|
|
297
|
+
this.#value = v;
|
|
298
|
+
}
|
|
299
|
+
get [Symbol.toStringTag]() {
|
|
300
|
+
return `value = ${this.#value}`;
|
|
301
|
+
}
|
|
302
|
+
[Symbol.for("nodejs.util.inspect.custom")]() {
|
|
303
|
+
return `UnsignedInteger { value: ${this.#value} }`;
|
|
304
|
+
}
|
|
305
|
+
};
|
|
306
|
+
const billion = 1e9;
|
|
307
|
+
const billionBigInt = 1000000000n;
|
|
308
|
+
const UNIT_NANOSECONDS = {
|
|
309
|
+
h: 3600000000000n,
|
|
310
|
+
m: 60000000000n,
|
|
311
|
+
s: billionBigInt,
|
|
312
|
+
ms: 1000000n,
|
|
313
|
+
us: 1000n,
|
|
314
|
+
µs: 1000n,
|
|
315
|
+
ns: 1n
|
|
316
|
+
};
|
|
317
|
+
var Duration = class Duration {
|
|
318
|
+
#seconds;
|
|
319
|
+
#nanos;
|
|
320
|
+
constructor(seconds, nanos = 0) {
|
|
321
|
+
this.#seconds = BigInt(seconds);
|
|
322
|
+
this.#nanos = nanos;
|
|
323
|
+
}
|
|
324
|
+
get seconds() {
|
|
325
|
+
return this.#seconds;
|
|
326
|
+
}
|
|
327
|
+
get nanos() {
|
|
328
|
+
return this.#nanos;
|
|
329
|
+
}
|
|
330
|
+
valueOf() {
|
|
331
|
+
return Number(this.#seconds) * 1e3 + this.#nanos / 1e6;
|
|
332
|
+
}
|
|
333
|
+
static fromMilliseconds(ms) {
|
|
334
|
+
const totalNanos = BigInt(Math.trunc(ms * 1e6));
|
|
335
|
+
const seconds = totalNanos / billionBigInt;
|
|
336
|
+
const nanos = Number(totalNanos % billionBigInt);
|
|
337
|
+
return new Duration(seconds, nanos);
|
|
338
|
+
}
|
|
339
|
+
addDuration(other) {
|
|
340
|
+
const nanos = this.#nanos + other.nanos;
|
|
341
|
+
return new Duration(this.#seconds + other.seconds + BigInt(Math.floor(nanos / billion)), nanos % billion);
|
|
342
|
+
}
|
|
343
|
+
subtractDuration(other) {
|
|
344
|
+
const nanos = this.#nanos - other.nanos;
|
|
345
|
+
return new Duration(this.#seconds - other.seconds + BigInt(Math.floor(nanos / billion)), (nanos + billion) % billion);
|
|
346
|
+
}
|
|
347
|
+
extendTimestamp(ts) {
|
|
348
|
+
return new Date(ts.getTime() + Number(this.#seconds) * 1e3 + Math.floor(this.#nanos / 1e6));
|
|
349
|
+
}
|
|
350
|
+
subtractTimestamp(ts) {
|
|
351
|
+
return /* @__PURE__ */ new Date(ts.getTime() - Number(this.#seconds) * 1e3 - Math.floor(this.#nanos / 1e6));
|
|
352
|
+
}
|
|
353
|
+
toString() {
|
|
354
|
+
const nanos = this.#nanos ? (this.#nanos / billion).toLocaleString("en-US", {
|
|
355
|
+
useGrouping: false,
|
|
356
|
+
maximumFractionDigits: 9
|
|
357
|
+
}).slice(1) : "";
|
|
358
|
+
return `${this.#seconds}${nanos}s`;
|
|
359
|
+
}
|
|
360
|
+
getHours() {
|
|
361
|
+
return this.#seconds / 3600n;
|
|
362
|
+
}
|
|
363
|
+
getMinutes() {
|
|
364
|
+
return this.#seconds / 60n;
|
|
365
|
+
}
|
|
366
|
+
getSeconds() {
|
|
367
|
+
return this.#seconds;
|
|
368
|
+
}
|
|
369
|
+
getMilliseconds() {
|
|
370
|
+
return this.#seconds * 1000n + BigInt(Math.floor(this.#nanos / 1e6));
|
|
371
|
+
}
|
|
372
|
+
get [Symbol.toStringTag]() {
|
|
373
|
+
return "google.protobuf.Duration";
|
|
374
|
+
}
|
|
375
|
+
[Symbol.for("nodejs.util.inspect.custom")]() {
|
|
376
|
+
return `google.protobuf.Duration { seconds: ${this.#seconds}, nanos: ${this.#nanos} }`;
|
|
377
|
+
}
|
|
378
|
+
};
|
|
379
|
+
function registerFunctions(registry) {
|
|
380
|
+
const sync = { async: false };
|
|
381
|
+
const functionOverload = (sig, handler) => registry.registerFunctionOverload(sig, handler, sync);
|
|
382
|
+
const identity = (v) => v;
|
|
383
|
+
functionOverload("dyn(dyn): dyn", identity);
|
|
384
|
+
for (const _t in TYPES) {
|
|
385
|
+
const type = TYPES[_t];
|
|
386
|
+
if (!(type instanceof Type)) continue;
|
|
387
|
+
functionOverload(`type(${type.name}): type`, () => type);
|
|
388
|
+
}
|
|
389
|
+
functionOverload("bool(bool): bool", identity);
|
|
390
|
+
functionOverload("bool(string): bool", (v) => {
|
|
391
|
+
switch (v) {
|
|
392
|
+
case "1":
|
|
393
|
+
case "t":
|
|
394
|
+
case "true":
|
|
395
|
+
case "TRUE":
|
|
396
|
+
case "True": return true;
|
|
397
|
+
case "0":
|
|
398
|
+
case "f":
|
|
399
|
+
case "false":
|
|
400
|
+
case "FALSE":
|
|
401
|
+
case "False": return false;
|
|
402
|
+
default: throw evaluationError("bool_conversion_error", `bool() conversion error: invalid string value "${v}"`);
|
|
403
|
+
}
|
|
404
|
+
});
|
|
405
|
+
functionOverload("size(string): int", (v) => BigInt(stringSize(v)));
|
|
406
|
+
functionOverload("size(bytes): int", (v) => BigInt(v.length));
|
|
407
|
+
functionOverload("size(list): int", (v) => BigInt(v.length ?? v.size));
|
|
408
|
+
functionOverload("size(map): int", (v) => BigInt(v instanceof Map ? v.size : objKeys(v).length));
|
|
409
|
+
functionOverload("string.size(): int", (v) => BigInt(stringSize(v)));
|
|
410
|
+
functionOverload("bytes.size(): int", (v) => BigInt(v.length));
|
|
411
|
+
functionOverload("list.size(): int", (v) => BigInt(v.length ?? v.size));
|
|
412
|
+
functionOverload("map.size(): int", (v) => BigInt(v instanceof Map ? v.size : objKeys(v).length));
|
|
413
|
+
functionOverload("bytes(string): bytes", (v) => ByteOpts.fromString(v));
|
|
414
|
+
functionOverload("bytes(bytes): bytes", identity);
|
|
415
|
+
functionOverload("double(double): double", identity);
|
|
416
|
+
functionOverload("double(int): double", (v) => Number(v));
|
|
417
|
+
functionOverload("double(uint): double", (v) => Number(v));
|
|
418
|
+
functionOverload("double(string): double", (v) => {
|
|
419
|
+
if (!v || v !== v.trim()) throw evaluationError("double_conversion_error", "double() type error: cannot convert to double");
|
|
420
|
+
switch (v.toLowerCase()) {
|
|
421
|
+
case "inf":
|
|
422
|
+
case "+inf":
|
|
423
|
+
case "infinity":
|
|
424
|
+
case "+infinity": return Number.POSITIVE_INFINITY;
|
|
425
|
+
case "-inf":
|
|
426
|
+
case "-infinity": return Number.NEGATIVE_INFINITY;
|
|
427
|
+
case "nan": return NaN;
|
|
428
|
+
default: {
|
|
429
|
+
const parsed = Number(v);
|
|
430
|
+
if (!Number.isNaN(parsed)) return parsed;
|
|
431
|
+
throw evaluationError("double_conversion_error", "double() type error: cannot convert to double");
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
});
|
|
435
|
+
functionOverload("int(int): int", identity);
|
|
436
|
+
functionOverload("int(double): int", (v) => {
|
|
437
|
+
if (Number.isFinite(v)) return BigInt(Math.trunc(v));
|
|
438
|
+
throw evaluationError("numeric_overflow", "int() type error: integer overflow");
|
|
439
|
+
});
|
|
440
|
+
functionOverload("int(string): int", (v) => {
|
|
441
|
+
if (v !== v.trim() || v.length > 20 || v.includes("0x")) throw evaluationError("int_conversion_error", "int() type error: cannot convert to int");
|
|
442
|
+
try {
|
|
443
|
+
const num = BigInt(v);
|
|
444
|
+
if (num <= 9223372036854775807n && num >= -9223372036854775808n) return num;
|
|
445
|
+
} catch (_e) {}
|
|
446
|
+
throw evaluationError("int_conversion_error", "int() type error: cannot convert to int");
|
|
447
|
+
});
|
|
448
|
+
functionOverload("uint(uint): uint", identity);
|
|
449
|
+
functionOverload("uint(int): uint", (v) => {
|
|
450
|
+
try {
|
|
451
|
+
return new UnsignedInt(v);
|
|
452
|
+
} catch (e) {
|
|
453
|
+
throw evaluationError("uint_conversion_error", "uint() type error: cannot convert to uint");
|
|
454
|
+
}
|
|
455
|
+
});
|
|
456
|
+
functionOverload("uint(double): uint", (v) => {
|
|
457
|
+
try {
|
|
458
|
+
return new UnsignedInt(Math.trunc(v));
|
|
459
|
+
} catch (e) {
|
|
460
|
+
throw evaluationError("numeric_overflow", "uint() type error: unsigned integer overflow");
|
|
461
|
+
}
|
|
462
|
+
});
|
|
463
|
+
functionOverload("uint(string): uint", (v) => {
|
|
464
|
+
if (v !== v.trim() || v.length > 20 || v.includes("0x")) throw evaluationError("uint_conversion_error", "uint() type error: cannot convert to uint");
|
|
465
|
+
try {
|
|
466
|
+
return new UnsignedInt(v);
|
|
467
|
+
} catch (e) {
|
|
468
|
+
throw evaluationError("uint_conversion_error", "uint() type error: cannot convert to uint");
|
|
469
|
+
}
|
|
470
|
+
});
|
|
471
|
+
functionOverload("string(string): string", identity);
|
|
472
|
+
functionOverload("string(bool): string", (v) => `${v}`);
|
|
473
|
+
functionOverload("string(int): string", (v) => `${v}`);
|
|
474
|
+
functionOverload("string(uint): string", (v) => `${v}`);
|
|
475
|
+
functionOverload("string(bytes): string", (v) => ByteOpts.toUtf8(v));
|
|
476
|
+
functionOverload("string(double): string", (v) => {
|
|
477
|
+
if (v === Infinity) return "+Inf";
|
|
478
|
+
if (v === -Infinity) return "-Inf";
|
|
479
|
+
return `${v}`;
|
|
480
|
+
});
|
|
481
|
+
functionOverload("string.startsWith(string): bool", (a, b) => a.startsWith(b));
|
|
482
|
+
functionOverload("string.endsWith(string): bool", (a, b) => a.endsWith(b));
|
|
483
|
+
functionOverload("string.contains(string): bool", (a, b) => a.includes(b));
|
|
484
|
+
functionOverload("string.lowerAscii(): string", (a) => a.toLowerCase());
|
|
485
|
+
functionOverload("string.upperAscii(): string", (a) => a.toUpperCase());
|
|
486
|
+
functionOverload("string.trim(): string", (a) => a.trim());
|
|
487
|
+
functionOverload("string.indexOf(string): int", (string, search) => BigInt(string.indexOf(search)));
|
|
488
|
+
functionOverload("string.indexOf(string, int): int", (string, search, fromIndex) => {
|
|
489
|
+
if (search === "") return fromIndex;
|
|
490
|
+
fromIndex = Number(fromIndex);
|
|
491
|
+
if (fromIndex < 0 || fromIndex >= string.length) throw evaluationError("index_out_of_range", "string.indexOf(search, fromIndex): fromIndex out of range");
|
|
492
|
+
return BigInt(string.indexOf(search, fromIndex));
|
|
493
|
+
});
|
|
494
|
+
functionOverload("string.lastIndexOf(string): int", (string, search) => BigInt(string.lastIndexOf(search)));
|
|
495
|
+
functionOverload("string.lastIndexOf(string, int): int", (string, search, fromIndex) => {
|
|
496
|
+
if (search === "") return fromIndex;
|
|
497
|
+
fromIndex = Number(fromIndex);
|
|
498
|
+
if (fromIndex < 0 || fromIndex >= string.length) throw evaluationError("index_out_of_range", "string.lastIndexOf(search, fromIndex): fromIndex out of range");
|
|
499
|
+
return BigInt(string.lastIndexOf(search, fromIndex));
|
|
500
|
+
});
|
|
501
|
+
functionOverload("string.substring(int): string", (string, start) => {
|
|
502
|
+
start = Number(start);
|
|
503
|
+
if (start < 0 || start > string.length) throw evaluationError("index_out_of_range", "string.substring(start, end): start index out of range");
|
|
504
|
+
return string.substring(start);
|
|
505
|
+
});
|
|
506
|
+
functionOverload("string.substring(int, int): string", (string, start, end) => {
|
|
507
|
+
start = Number(start);
|
|
508
|
+
if (start < 0 || start > string.length) throw evaluationError("index_out_of_range", "string.substring(start, end): start index out of range");
|
|
509
|
+
end = Number(end);
|
|
510
|
+
if (end < start || end > string.length) throw evaluationError("index_out_of_range", "string.substring(start, end): end index out of range");
|
|
511
|
+
return string.substring(start, end);
|
|
512
|
+
});
|
|
513
|
+
functionOverload("string.matches(string): bool", (a, b) => {
|
|
514
|
+
try {
|
|
515
|
+
return new RegExp(b).test(a);
|
|
516
|
+
} catch (_err) {
|
|
517
|
+
throw evaluationError("invalid_regular_expression", `Invalid regular expression: ${b}`);
|
|
518
|
+
}
|
|
519
|
+
});
|
|
520
|
+
functionOverload("string.split(string): list<string>", (s, sep) => s.split(sep));
|
|
521
|
+
functionOverload("string.split(string, int): list<string>", (s, sep, l) => {
|
|
522
|
+
l = Number(l);
|
|
523
|
+
if (l === 0) return [];
|
|
524
|
+
const parts = s.split(sep);
|
|
525
|
+
if (l < 0 || parts.length <= l) return parts;
|
|
526
|
+
const limited = parts.slice(0, l - 1);
|
|
527
|
+
limited.push(parts.slice(l - 1).join(sep));
|
|
528
|
+
return limited;
|
|
529
|
+
});
|
|
530
|
+
functionOverload("list<string>.join(): string", (v) => {
|
|
531
|
+
for (let i = 0; i < v.length; i++) if (typeof v[i] !== "string") throw evaluationError("invalid_list_element_type", "string.join(): list must contain only strings");
|
|
532
|
+
return v.join("");
|
|
533
|
+
});
|
|
534
|
+
functionOverload("list<string>.join(string): string", (v, sep) => {
|
|
535
|
+
for (let i = 0; i < v.length; i++) if (typeof v[i] !== "string") throw evaluationError("invalid_list_element_type", "string.join(separator): list must contain only strings");
|
|
536
|
+
return v.join(sep);
|
|
537
|
+
});
|
|
538
|
+
const textEncoder = new TextEncoder("utf8");
|
|
539
|
+
const textDecoder = new TextDecoder("utf8");
|
|
540
|
+
const ByteOpts = typeof Buffer !== "undefined" ? {
|
|
541
|
+
byteLength: (v) => Buffer.byteLength(v),
|
|
542
|
+
fromString: (str) => Buffer.from(str, "utf8"),
|
|
543
|
+
toHex: (b) => Buffer.prototype.hexSlice.call(b, 0, b.length),
|
|
544
|
+
toBase64: (b) => Buffer.prototype.base64Slice.call(b, 0, b.length),
|
|
545
|
+
toUtf8: (b) => Buffer.prototype.utf8Slice.call(b, 0, b.length),
|
|
546
|
+
jsonParse: (b) => JSON.parse(b)
|
|
547
|
+
} : {
|
|
548
|
+
textEncoder: new TextEncoder("utf8"),
|
|
549
|
+
byteLength: (v) => textEncoder.encode(v).length,
|
|
550
|
+
fromString: (str) => textEncoder.encode(str),
|
|
551
|
+
toHex: Uint8Array.prototype.toHex ? (b) => b.toHex() : (b) => arrayFrom(b, (i) => i.toString(16).padStart(2, "0")).join(""),
|
|
552
|
+
toBase64: Uint8Array.prototype.toBase64 ? (b) => b.toBase64() : (b) => btoa(arrayFrom(b, (i) => String.fromCodePoint(i)).join("")),
|
|
553
|
+
toUtf8: (b) => textDecoder.decode(b),
|
|
554
|
+
jsonParse: (b) => JSON.parse(textEncoder.decode(b))
|
|
555
|
+
};
|
|
556
|
+
functionOverload("bytes.json(): map", ByteOpts.jsonParse);
|
|
557
|
+
functionOverload("bytes.hex(): string", ByteOpts.toHex);
|
|
558
|
+
functionOverload("bytes.string(): string", ByteOpts.toUtf8);
|
|
559
|
+
functionOverload("bytes.base64(): string", ByteOpts.toBase64);
|
|
560
|
+
functionOverload("bytes.at(int): int", (b, index) => {
|
|
561
|
+
if (index < 0 || index >= b.length) throw evaluationError("index_out_of_range", "Bytes index out of range");
|
|
562
|
+
return BigInt(b[index]);
|
|
563
|
+
});
|
|
564
|
+
const TS = "google.protobuf.Timestamp";
|
|
565
|
+
const GPD = "google.protobuf.Duration";
|
|
566
|
+
const TimestampType = registry.registerType(TS, Date).typeType;
|
|
567
|
+
const DurationType = registry.registerType(GPD, Duration).typeType;
|
|
568
|
+
registry.registerConstant("google", "map<string, map<string, type>>", { protobuf: {
|
|
569
|
+
Duration: DurationType,
|
|
570
|
+
Timestamp: TimestampType
|
|
571
|
+
} });
|
|
572
|
+
function tzDate(d, timeZone) {
|
|
573
|
+
return new Date(d.toLocaleString("en-US", { timeZone }));
|
|
574
|
+
}
|
|
575
|
+
function getDayOfYear(d, tz) {
|
|
576
|
+
const workingDate = tz ? tzDate(d, tz) : new Date(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate());
|
|
577
|
+
const start = new Date(workingDate.getFullYear(), 0, 0);
|
|
578
|
+
return BigInt(Math.floor((workingDate - start) / 864e5) - 1);
|
|
579
|
+
}
|
|
580
|
+
functionOverload(`timestamp(string): ${TS}`, (v) => {
|
|
581
|
+
if (v.length < 20 || v.length > 30) throw evaluationError("invalid_timestamp", "timestamp() requires a string in ISO 8601 format");
|
|
582
|
+
const d = new Date(v);
|
|
583
|
+
if (d <= 0xe677d21fdbff && d >= -621355968e5) return d;
|
|
584
|
+
throw evaluationError("invalid_timestamp", "timestamp() requires a string in ISO 8601 format");
|
|
585
|
+
});
|
|
586
|
+
functionOverload(`timestamp(int): ${TS}`, (i) => {
|
|
587
|
+
i = Number(i) * 1e3;
|
|
588
|
+
if (i <= 0xe677d21fdbff && i >= -621355968e5) return new Date(i);
|
|
589
|
+
throw evaluationError("invalid_timestamp", "timestamp() requires a valid integer unix timestamp");
|
|
590
|
+
});
|
|
591
|
+
functionOverload(`${TS}.getDate(): int`, (d) => BigInt(d.getUTCDate()));
|
|
592
|
+
functionOverload(`${TS}.getDate(string): int`, (d, tz) => BigInt(tzDate(d, tz).getDate()));
|
|
593
|
+
functionOverload(`${TS}.getDayOfMonth(): int`, (d) => BigInt(d.getUTCDate() - 1));
|
|
594
|
+
functionOverload(`${TS}.getDayOfMonth(string): int`, (d, tz) => BigInt(tzDate(d, tz).getDate() - 1));
|
|
595
|
+
functionOverload(`${TS}.getDayOfWeek(): int`, (d) => BigInt(d.getUTCDay()));
|
|
596
|
+
functionOverload(`${TS}.getDayOfWeek(string): int`, (d, tz) => BigInt(tzDate(d, tz).getDay()));
|
|
597
|
+
functionOverload(`${TS}.getDayOfYear(): int`, getDayOfYear);
|
|
598
|
+
functionOverload(`${TS}.getDayOfYear(string): int`, getDayOfYear);
|
|
599
|
+
functionOverload(`${TS}.getFullYear(): int`, (d) => BigInt(d.getUTCFullYear()));
|
|
600
|
+
functionOverload(`${TS}.getFullYear(string): int`, (d, tz) => BigInt(tzDate(d, tz).getFullYear()));
|
|
601
|
+
functionOverload(`${TS}.getHours(): int`, (d) => BigInt(d.getUTCHours()));
|
|
602
|
+
functionOverload(`${TS}.getHours(string): int`, (d, tz) => BigInt(tzDate(d, tz).getHours()));
|
|
603
|
+
functionOverload(`${TS}.getMilliseconds(): int`, (d) => BigInt(d.getUTCMilliseconds()));
|
|
604
|
+
functionOverload(`${TS}.getMilliseconds(string): int`, (d) => BigInt(d.getUTCMilliseconds()));
|
|
605
|
+
functionOverload(`${TS}.getMinutes(): int`, (d) => BigInt(d.getUTCMinutes()));
|
|
606
|
+
functionOverload(`${TS}.getMinutes(string): int`, (d, tz) => BigInt(tzDate(d, tz).getMinutes()));
|
|
607
|
+
functionOverload(`${TS}.getMonth(): int`, (d) => BigInt(d.getUTCMonth()));
|
|
608
|
+
functionOverload(`${TS}.getMonth(string): int`, (d, tz) => BigInt(tzDate(d, tz).getMonth()));
|
|
609
|
+
functionOverload(`${TS}.getSeconds(): int`, (d) => BigInt(d.getUTCSeconds()));
|
|
610
|
+
functionOverload(`${TS}.getSeconds(string): int`, (d, tz) => BigInt(tzDate(d, tz).getSeconds()));
|
|
611
|
+
const parseDurationPattern = /(\d*\.?\d*)(ns|us|µs|ms|s|m|h)/;
|
|
612
|
+
function parseDuration(string) {
|
|
613
|
+
if (!string) throw evaluationError("invalid_duration", `Invalid duration string: ''`);
|
|
614
|
+
const isNegative = string[0] === "-";
|
|
615
|
+
if (string[0] === "-" || string[0] === "+") string = string.slice(1);
|
|
616
|
+
let nanoseconds = BigInt(0);
|
|
617
|
+
while (true) {
|
|
618
|
+
const match = parseDurationPattern.exec(string);
|
|
619
|
+
if (!match) throw evaluationError("invalid_duration", `Invalid duration string: ${string}`);
|
|
620
|
+
if (match.index !== 0) throw evaluationError("invalid_duration", `Invalid duration string: ${string}`);
|
|
621
|
+
string = string.slice(match[0].length);
|
|
622
|
+
const unitNanos = UNIT_NANOSECONDS[match[2]];
|
|
623
|
+
const [intPart = "0", fracPart = ""] = match[1].split(".");
|
|
624
|
+
const intVal = BigInt(intPart) * unitNanos;
|
|
625
|
+
const fracNanos = fracPart ? BigInt(fracPart.slice(0, 13).padEnd(13, "0")) * unitNanos / 10000000000000n : 0n;
|
|
626
|
+
nanoseconds += intVal + fracNanos;
|
|
627
|
+
if (string === "") break;
|
|
628
|
+
}
|
|
629
|
+
const seconds = nanoseconds >= billionBigInt ? nanoseconds / billionBigInt : 0n;
|
|
630
|
+
const nanos = Number(nanoseconds % billionBigInt);
|
|
631
|
+
if (isNegative) return new Duration(-seconds, -nanos);
|
|
632
|
+
return new Duration(seconds, nanos);
|
|
633
|
+
}
|
|
634
|
+
functionOverload(`duration(string): google.protobuf.Duration`, (s) => parseDuration(s));
|
|
635
|
+
functionOverload(`google.protobuf.Duration.getHours(): int`, (d) => d.getHours());
|
|
636
|
+
functionOverload(`google.protobuf.Duration.getMinutes(): int`, (d) => d.getMinutes());
|
|
637
|
+
functionOverload(`google.protobuf.Duration.getSeconds(): int`, (d) => d.getSeconds());
|
|
638
|
+
functionOverload(`google.protobuf.Duration.getMilliseconds(): int`, (d) => d.getMilliseconds());
|
|
639
|
+
register(registry);
|
|
640
|
+
}
|
|
641
|
+
function stringSize(str) {
|
|
642
|
+
let count = 0;
|
|
643
|
+
for (const c of str) count++;
|
|
644
|
+
return count;
|
|
645
|
+
}
|
|
646
|
+
var Type = class {
|
|
647
|
+
#name;
|
|
648
|
+
constructor(name) {
|
|
649
|
+
this.#name = name;
|
|
650
|
+
objFreeze(this);
|
|
651
|
+
}
|
|
652
|
+
get name() {
|
|
653
|
+
return this.#name;
|
|
654
|
+
}
|
|
655
|
+
get [Symbol.toStringTag]() {
|
|
656
|
+
return `Type<${this.#name}>`;
|
|
657
|
+
}
|
|
658
|
+
toString() {
|
|
659
|
+
return `Type<${this.#name}>`;
|
|
660
|
+
}
|
|
661
|
+
};
|
|
662
|
+
const TYPES = {
|
|
663
|
+
string: new Type("string"),
|
|
664
|
+
bool: new Type("bool"),
|
|
665
|
+
int: new Type("int"),
|
|
666
|
+
uint: new Type("uint"),
|
|
667
|
+
double: new Type("double"),
|
|
668
|
+
map: new Type("map"),
|
|
669
|
+
list: new Type("list"),
|
|
670
|
+
bytes: new Type("bytes"),
|
|
671
|
+
null_type: new Type("null"),
|
|
672
|
+
type: new Type("type")
|
|
673
|
+
};
|
|
674
|
+
const optionalType = new Type("optional");
|
|
675
|
+
const valueTypeMatchers = {
|
|
676
|
+
dyn(v, ev) {
|
|
677
|
+
switch (typeof v) {
|
|
678
|
+
case "string":
|
|
679
|
+
case "bigint":
|
|
680
|
+
case "number":
|
|
681
|
+
case "boolean": return true;
|
|
682
|
+
case "object": switch (v ? v.constructor : v) {
|
|
683
|
+
case null:
|
|
684
|
+
case void 0:
|
|
685
|
+
case Object:
|
|
686
|
+
case Map:
|
|
687
|
+
case Array:
|
|
688
|
+
case Set: return true;
|
|
689
|
+
default: if (ev.objectTypesByConstructor.get(v.constructor)) return true;
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
return !!ev.debugType(v);
|
|
693
|
+
},
|
|
694
|
+
string(v) {
|
|
695
|
+
return typeof v === "string";
|
|
696
|
+
},
|
|
697
|
+
int(v) {
|
|
698
|
+
return typeof v === "bigint";
|
|
699
|
+
},
|
|
700
|
+
double(v) {
|
|
701
|
+
return typeof v === "number";
|
|
702
|
+
},
|
|
703
|
+
bool(v) {
|
|
704
|
+
return typeof v === "boolean";
|
|
705
|
+
},
|
|
706
|
+
null(v) {
|
|
707
|
+
return v === null;
|
|
708
|
+
},
|
|
709
|
+
bytes(v) {
|
|
710
|
+
return v instanceof Uint8Array;
|
|
711
|
+
},
|
|
712
|
+
uint(v) {
|
|
713
|
+
return v instanceof UnsignedInt;
|
|
714
|
+
},
|
|
715
|
+
type(v) {
|
|
716
|
+
return v instanceof Type;
|
|
717
|
+
},
|
|
718
|
+
list(v) {
|
|
719
|
+
switch (v?.constructor) {
|
|
720
|
+
case Array:
|
|
721
|
+
case Set: return true;
|
|
722
|
+
default: return false;
|
|
723
|
+
}
|
|
724
|
+
},
|
|
725
|
+
map(v) {
|
|
726
|
+
switch (typeof v === "object" && v ? v.constructor : null) {
|
|
727
|
+
case void 0:
|
|
728
|
+
case Object:
|
|
729
|
+
case Map: return true;
|
|
730
|
+
default: return false;
|
|
731
|
+
}
|
|
732
|
+
},
|
|
733
|
+
optional(v) {
|
|
734
|
+
return v instanceof Optional;
|
|
735
|
+
},
|
|
736
|
+
message(v, ev) {
|
|
737
|
+
return this === ev.debugType(v);
|
|
738
|
+
}
|
|
739
|
+
};
|
|
740
|
+
valueTypeMatchers.param = valueTypeMatchers.dyn;
|
|
741
|
+
var TypeDeclaration = class {
|
|
742
|
+
#matchesCache = /* @__PURE__ */ new WeakMap();
|
|
743
|
+
constructor({ kind, type, name, keyType, valueType }) {
|
|
744
|
+
this.kind = kind;
|
|
745
|
+
this.type = type;
|
|
746
|
+
this.name = name;
|
|
747
|
+
this.keyType = keyType;
|
|
748
|
+
this.valueType = valueType;
|
|
749
|
+
this.unwrappedType = kind === "dyn" && valueType ? valueType.unwrappedType : this;
|
|
750
|
+
this.wrappedType = kind === "dyn" ? this : _createDynType(this.unwrappedType);
|
|
751
|
+
this.hasDynType = this.kind === "dyn" || this.valueType?.hasDynType || this.keyType?.hasDynType || false;
|
|
752
|
+
this.hasPlaceholderType = this.kind === "param" || this.keyType?.hasPlaceholderType || this.valueType?.hasPlaceholderType || false;
|
|
753
|
+
if (kind === "list") this.fieldLazy = this.#getListField;
|
|
754
|
+
else if (kind === "map") this.fieldLazy = this.#getMapField;
|
|
755
|
+
else if (kind === "message") this.fieldLazy = this.#getMessageField;
|
|
756
|
+
else if (kind === "optional") this.fieldLazy = this.#getOptionalField;
|
|
757
|
+
this.matchesValueType = valueTypeMatchers[name] || valueTypeMatchers[kind];
|
|
758
|
+
objFreeze(this);
|
|
759
|
+
}
|
|
760
|
+
isDynOrBool() {
|
|
761
|
+
return this.type === "bool" || this.kind === "dyn";
|
|
762
|
+
}
|
|
763
|
+
isEmpty() {
|
|
764
|
+
return this.valueType && this.valueType.kind === "param";
|
|
765
|
+
}
|
|
766
|
+
unify(r, t2) {
|
|
767
|
+
const t1 = this;
|
|
768
|
+
if (t1 === t2 || t1.kind === "dyn" || t2.kind === "param") return t1;
|
|
769
|
+
if (t2.kind === "dyn" || t1.kind === "param") return t2;
|
|
770
|
+
if (t1.kind !== t2.kind) return null;
|
|
771
|
+
if (!(t1.hasPlaceholderType || t2.hasPlaceholderType || t1.hasDynType || t2.hasDynType)) return null;
|
|
772
|
+
const valueType = t1.valueType.unify(r, t2.valueType);
|
|
773
|
+
if (!valueType) return null;
|
|
774
|
+
switch (t1.kind) {
|
|
775
|
+
case "optional": return r.getOptionalType(valueType);
|
|
776
|
+
case "list": return r.getListType(valueType);
|
|
777
|
+
case "map":
|
|
778
|
+
const keyType = t1.keyType.unify(r, t2.keyType);
|
|
779
|
+
return keyType ? r.getMapType(keyType, valueType) : null;
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
templated(r, bind) {
|
|
783
|
+
if (!this.hasPlaceholderType) return this;
|
|
784
|
+
switch (this.kind) {
|
|
785
|
+
case "dyn": return this.valueType.templated(r, bind);
|
|
786
|
+
case "param": return bind?.get(this.name) || this;
|
|
787
|
+
case "map": return r.getMapType(this.keyType.templated(r, bind), this.valueType.templated(r, bind));
|
|
788
|
+
case "list": return r.getListType(this.valueType.templated(r, bind));
|
|
789
|
+
case "optional": return r.getOptionalType(this.valueType.templated(r, bind));
|
|
790
|
+
default: return this;
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
toString() {
|
|
794
|
+
return this.name;
|
|
795
|
+
}
|
|
796
|
+
#getOptionalField(obj, key, ast, ev) {
|
|
797
|
+
obj = obj instanceof Optional ? obj.orValue() : obj;
|
|
798
|
+
if (obj === void 0) return OPTIONAL_NONE;
|
|
799
|
+
const type = ev.debugType(obj);
|
|
800
|
+
try {
|
|
801
|
+
return Optional.of(type.fieldLazy(obj, key, ast, ev));
|
|
802
|
+
} catch (e) {
|
|
803
|
+
if (e instanceof EvaluationError) return OPTIONAL_NONE;
|
|
804
|
+
throw e;
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
#getMessageField(obj, key, ast, ev) {
|
|
808
|
+
const message = obj ? ev.objectTypesByConstructor.get(obj.constructor) : void 0;
|
|
809
|
+
if (!message) return;
|
|
810
|
+
const type = message.fields ? message.fields[key] : dynType$1;
|
|
811
|
+
if (!type) return void 0;
|
|
812
|
+
const value = obj instanceof Map ? obj.get(key) : obj[key];
|
|
813
|
+
if (value === void 0) return;
|
|
814
|
+
if (type.matchesValueType(value, ev)) return value;
|
|
815
|
+
throw evaluationError("field_type_mismatch", `Field '${key}' is not of type '${type}', got '${ev.debugType(value)}'`, ast);
|
|
816
|
+
}
|
|
817
|
+
#getMapField(obj, key, ast, ev) {
|
|
818
|
+
const value = obj instanceof Map ? obj.get(key) : obj && hasOwn(obj, key) ? obj[key] : void 0;
|
|
819
|
+
if (value === void 0) return;
|
|
820
|
+
if (this.valueType.matchesValueType(value, ev)) return value;
|
|
821
|
+
throw evaluationError("field_type_mismatch", `Field '${key}' is not of type '${this.valueType}', got '${ev.debugType(value)}'`, ast);
|
|
822
|
+
}
|
|
823
|
+
#getListElementAtIndex(list, pos) {
|
|
824
|
+
switch (list?.constructor) {
|
|
825
|
+
case Array: return list[pos];
|
|
826
|
+
case Set: {
|
|
827
|
+
let i = 0;
|
|
828
|
+
for (const item of list) {
|
|
829
|
+
if (i++ !== pos) continue;
|
|
830
|
+
return item;
|
|
831
|
+
}
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
#getListField(obj, key, ast, ev) {
|
|
836
|
+
if (typeof key === "bigint") key = Number(key);
|
|
837
|
+
else if (typeof key !== "number") return;
|
|
838
|
+
const value = this.#getListElementAtIndex(obj, key);
|
|
839
|
+
if (value === void 0) {
|
|
840
|
+
if (!obj) return;
|
|
841
|
+
throw evaluationError("index_out_of_bounds", `No such key: index out of bounds, index ${key} ${key < 0 ? "< 0" : `>= size ${obj.length || obj.size}`}`, ast);
|
|
842
|
+
}
|
|
843
|
+
if (this.valueType.matchesValueType(value, ev)) return value;
|
|
844
|
+
throw evaluationError("list_item_type_mismatch", `List item with index '${key}' is not of type '${this.valueType}', got '${ev.debugType(value)}'`, ast);
|
|
845
|
+
}
|
|
846
|
+
fieldLazy() {}
|
|
847
|
+
field(obj, key, ast, ev) {
|
|
848
|
+
const v = this.fieldLazy(obj, key, ast, ev);
|
|
849
|
+
if (v !== void 0) return v;
|
|
850
|
+
throw evaluationError("no_such_key", `No such key: ${key}`, ast);
|
|
851
|
+
}
|
|
852
|
+
matchesBoth(other) {
|
|
853
|
+
return this.matches(other) && other.matches(this);
|
|
854
|
+
}
|
|
855
|
+
matches(o) {
|
|
856
|
+
const s = this.unwrappedType;
|
|
857
|
+
o = o.unwrappedType;
|
|
858
|
+
if (s === o || s.kind === "dyn" || o.kind === "dyn" || o.kind === "param") return true;
|
|
859
|
+
return this.#matchesCache.get(o) ?? this.#matchesCache.set(o, this.#matches(s, o)).get(o);
|
|
860
|
+
}
|
|
861
|
+
#matches(s, o) {
|
|
862
|
+
switch (s.kind) {
|
|
863
|
+
case "dyn":
|
|
864
|
+
case "param": return true;
|
|
865
|
+
case "list": return o.kind === "list" && s.valueType.matches(o.valueType);
|
|
866
|
+
case "map": return o.kind === "map" && s.keyType.matches(o.keyType) && s.valueType.matches(o.valueType);
|
|
867
|
+
case "optional": return o.kind === "optional" && s.valueType.matches(o.valueType);
|
|
868
|
+
default: return s.name === o.name;
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
};
|
|
872
|
+
const macroEvaluateErr = `have a .callAst property or .evaluate(checker, macro, ctx) method.`;
|
|
873
|
+
const macroTypeCheckErr = `have a .callAst property or .typeCheck(checker, macro, ctx) method.`;
|
|
874
|
+
function wrapMacroExpander(name, handler) {
|
|
875
|
+
const p = `Macro '${name}' must`;
|
|
876
|
+
return function macroExpander(opts) {
|
|
877
|
+
const macro = handler(opts);
|
|
878
|
+
if (!macro || typeof macro !== "object") throw new Error(`${p} return an object.`);
|
|
879
|
+
if (macro.callAst) return macro;
|
|
880
|
+
if (!macro.evaluate) throw new Error(`${p} ${macroEvaluateErr}`);
|
|
881
|
+
if (!macro.typeCheck) throw new Error(`${p} ${macroTypeCheckErr}`);
|
|
882
|
+
return macro;
|
|
883
|
+
};
|
|
884
|
+
}
|
|
885
|
+
var VariableDeclaration = class {
|
|
886
|
+
constructor(name, type, description, value) {
|
|
887
|
+
this.name = name;
|
|
888
|
+
this.type = type;
|
|
889
|
+
this.description = description ?? null;
|
|
890
|
+
this.constant = value !== void 0;
|
|
891
|
+
this.value = value;
|
|
892
|
+
objFreeze(this);
|
|
893
|
+
}
|
|
894
|
+
};
|
|
895
|
+
var FunctionDeclaration = class {
|
|
896
|
+
constructor({ name, receiverType, returnType, handler, description, params, async }) {
|
|
897
|
+
if (typeof name !== "string") throw new Error("name must be a string");
|
|
898
|
+
if (typeof handler !== "function") throw new Error("handler must be a function");
|
|
899
|
+
this.name = name;
|
|
900
|
+
this.async = isAsync(handler, async);
|
|
901
|
+
this.receiverType = receiverType ?? null;
|
|
902
|
+
this.returnType = returnType;
|
|
903
|
+
this.description = description ?? null;
|
|
904
|
+
this.params = params;
|
|
905
|
+
this.argTypes = params.map((p) => p.type);
|
|
906
|
+
this.macro = this.argTypes.includes(astType);
|
|
907
|
+
const receiverString = receiverType ? `${receiverType}.` : "";
|
|
908
|
+
this.signature = `${receiverString}${name}(${this.argTypes.join(", ")}): ${returnType}`;
|
|
909
|
+
this.handler = this.macro ? wrapMacroExpander(this.signature, handler) : handler;
|
|
910
|
+
this.partitionKey = `${receiverType ? "rcall" : "call"}:${name}:${params.length}`;
|
|
911
|
+
this.hasPlaceholderType = this.returnType.hasPlaceholderType || this.receiverType?.hasPlaceholderType || this.argTypes.some((t) => t.hasPlaceholderType) || false;
|
|
912
|
+
objFreeze(this);
|
|
913
|
+
}
|
|
914
|
+
matchesArgs(argTypes) {
|
|
915
|
+
return argTypes.length === this.argTypes.length && this.argTypes.every((t, i) => t.matches(argTypes[i])) ? this : null;
|
|
916
|
+
}
|
|
917
|
+
};
|
|
918
|
+
var OperatorDeclaration = class {
|
|
919
|
+
constructor({ op, leftType, rightType, handler, returnType, async }) {
|
|
920
|
+
this.operator = op;
|
|
921
|
+
this.leftType = leftType;
|
|
922
|
+
this.rightType = rightType || null;
|
|
923
|
+
this.handler = handler;
|
|
924
|
+
this.async = isAsync(handler, async);
|
|
925
|
+
this.returnType = returnType;
|
|
926
|
+
if (rightType) this.signature = `${leftType} ${op} ${rightType}: ${returnType}`;
|
|
927
|
+
else this.signature = `${op}${leftType}: ${returnType}`;
|
|
928
|
+
this.hasPlaceholderType = this.leftType.hasPlaceholderType || this.rightType?.hasPlaceholderType || false;
|
|
929
|
+
objFreeze(this);
|
|
930
|
+
}
|
|
931
|
+
equals(other) {
|
|
932
|
+
return this.operator === other.operator && this.leftType === other.leftType && this.rightType === other.rightType;
|
|
933
|
+
}
|
|
934
|
+
};
|
|
935
|
+
function _createListType(valueType) {
|
|
936
|
+
return new TypeDeclaration({
|
|
937
|
+
kind: "list",
|
|
938
|
+
name: `list<${valueType}>`,
|
|
939
|
+
type: "list",
|
|
940
|
+
valueType
|
|
941
|
+
});
|
|
942
|
+
}
|
|
943
|
+
function _createPrimitiveType(name) {
|
|
944
|
+
return new TypeDeclaration({
|
|
945
|
+
kind: "primitive",
|
|
946
|
+
name,
|
|
947
|
+
type: name
|
|
948
|
+
});
|
|
949
|
+
}
|
|
950
|
+
function _createMessageType(name) {
|
|
951
|
+
return new TypeDeclaration({
|
|
952
|
+
kind: "message",
|
|
953
|
+
name,
|
|
954
|
+
type: name
|
|
955
|
+
});
|
|
956
|
+
}
|
|
957
|
+
function _createDynType(valueType) {
|
|
958
|
+
const name = valueType ? `dyn<${valueType}>` : "dyn";
|
|
959
|
+
return new TypeDeclaration({
|
|
960
|
+
kind: "dyn",
|
|
961
|
+
name,
|
|
962
|
+
type: name,
|
|
963
|
+
valueType
|
|
964
|
+
});
|
|
965
|
+
}
|
|
966
|
+
function _createOptionalType(valueType) {
|
|
967
|
+
return new TypeDeclaration({
|
|
968
|
+
kind: "optional",
|
|
969
|
+
name: `optional<${valueType}>`,
|
|
970
|
+
type: "optional",
|
|
971
|
+
valueType
|
|
972
|
+
});
|
|
973
|
+
}
|
|
974
|
+
function _createMapType(keyType, valueType) {
|
|
975
|
+
return new TypeDeclaration({
|
|
976
|
+
kind: "map",
|
|
977
|
+
name: `map<${keyType}, ${valueType}>`,
|
|
978
|
+
type: "map",
|
|
979
|
+
keyType,
|
|
980
|
+
valueType
|
|
981
|
+
});
|
|
982
|
+
}
|
|
983
|
+
function _createPlaceholderType(name) {
|
|
984
|
+
return new TypeDeclaration({
|
|
985
|
+
kind: "param",
|
|
986
|
+
name,
|
|
987
|
+
type: name
|
|
988
|
+
});
|
|
989
|
+
}
|
|
990
|
+
const dynType$1 = _createDynType();
|
|
991
|
+
const astType = _createPrimitiveType("ast");
|
|
992
|
+
const listType = _createListType(dynType$1);
|
|
993
|
+
const mapType = _createMapType(dynType$1, dynType$1);
|
|
994
|
+
const celTypes = {
|
|
995
|
+
string: _createPrimitiveType("string"),
|
|
996
|
+
bool: _createPrimitiveType("bool"),
|
|
997
|
+
int: _createPrimitiveType("int"),
|
|
998
|
+
uint: _createPrimitiveType("uint"),
|
|
999
|
+
double: _createPrimitiveType("double"),
|
|
1000
|
+
bytes: _createPrimitiveType("bytes"),
|
|
1001
|
+
dyn: dynType$1,
|
|
1002
|
+
null: _createPrimitiveType("null"),
|
|
1003
|
+
type: _createPrimitiveType("type"),
|
|
1004
|
+
optional: _createOptionalType(dynType$1),
|
|
1005
|
+
list: listType,
|
|
1006
|
+
"list<dyn>": listType,
|
|
1007
|
+
map: mapType,
|
|
1008
|
+
"map<dyn, dyn>": mapType
|
|
1009
|
+
};
|
|
1010
|
+
for (const t of [
|
|
1011
|
+
celTypes.string,
|
|
1012
|
+
celTypes.double,
|
|
1013
|
+
celTypes.int
|
|
1014
|
+
]) {
|
|
1015
|
+
const list = _createListType(t);
|
|
1016
|
+
const map = _createMapType(celTypes.string, t);
|
|
1017
|
+
celTypes[list.name] = list;
|
|
1018
|
+
celTypes[map.name] = map;
|
|
1019
|
+
}
|
|
1020
|
+
Object.freeze(celTypes);
|
|
1021
|
+
var Candidates = class {
|
|
1022
|
+
returnType = null;
|
|
1023
|
+
async = false;
|
|
1024
|
+
macro = false;
|
|
1025
|
+
#matchCache = null;
|
|
1026
|
+
#checkCache = null;
|
|
1027
|
+
declarations = [];
|
|
1028
|
+
constructor(registry) {
|
|
1029
|
+
this.registry = registry;
|
|
1030
|
+
}
|
|
1031
|
+
[Symbol.iterator]() {
|
|
1032
|
+
return this.declarations[Symbol.iterator]();
|
|
1033
|
+
}
|
|
1034
|
+
add(decl) {
|
|
1035
|
+
this.returnType = (this.returnType || decl.returnType).unify(this.registry, decl.returnType) || dynType$1;
|
|
1036
|
+
if (decl.macro) this.macro = decl;
|
|
1037
|
+
if (decl.async && !this.async) this.async = true;
|
|
1038
|
+
this.declarations.push(decl);
|
|
1039
|
+
this.#matchCache?.clear();
|
|
1040
|
+
this.#checkCache?.clear();
|
|
1041
|
+
}
|
|
1042
|
+
findFunction(argTypes, receiverType = null) {
|
|
1043
|
+
for (let i = 0; i < this.declarations.length; i++) {
|
|
1044
|
+
const match = this.#matchesFunction(this.declarations[i], argTypes, receiverType);
|
|
1045
|
+
if (match) return match;
|
|
1046
|
+
}
|
|
1047
|
+
return null;
|
|
1048
|
+
}
|
|
1049
|
+
findUnaryOverload(left) {
|
|
1050
|
+
const cached = (this.#matchCache ??= /* @__PURE__ */ new Map()).get(left);
|
|
1051
|
+
if (cached !== void 0) return cached;
|
|
1052
|
+
let value = false;
|
|
1053
|
+
for (const decl of this.declarations) {
|
|
1054
|
+
if (decl.leftType !== left) continue;
|
|
1055
|
+
value = decl;
|
|
1056
|
+
break;
|
|
1057
|
+
}
|
|
1058
|
+
this.#matchCache.set(left, value);
|
|
1059
|
+
return value;
|
|
1060
|
+
}
|
|
1061
|
+
findBinaryOverload(left, right) {
|
|
1062
|
+
if (left.kind === "dyn" && left.valueType) right = right.wrappedType;
|
|
1063
|
+
else if (right.kind === "dyn" && right.valueType) left = left.wrappedType;
|
|
1064
|
+
return (this.#matchCache ??= /* @__PURE__ */ new Map()).get(left)?.get(right) ?? this.#cacheBinary(this.#matchCache, left, right, this.#findBinaryUncached(left, right));
|
|
1065
|
+
}
|
|
1066
|
+
checkBinaryOverload(left, right) {
|
|
1067
|
+
return (this.#checkCache ??= /* @__PURE__ */ new Map()).get(left)?.get(right) ?? this.#cacheBinary(this.#checkCache, left, right, this.#checkBinaryUncached(left, right));
|
|
1068
|
+
}
|
|
1069
|
+
#cacheBinary(c, l, r, v) {
|
|
1070
|
+
return (c.get(l) || c.set(l, /* @__PURE__ */ new Map()).get(l)).set(r, v), v;
|
|
1071
|
+
}
|
|
1072
|
+
#findBinaryUncached(left, right) {
|
|
1073
|
+
const ops = this.#findBinaryOverloads(left, right);
|
|
1074
|
+
if (ops.length === 0) return false;
|
|
1075
|
+
if (ops.length === 1) return ops[0];
|
|
1076
|
+
throw new Error(`Operator overload '${ops[0].signature}' overlaps with '${ops[1].signature}'.`);
|
|
1077
|
+
}
|
|
1078
|
+
#checkBinaryUncached(left, right) {
|
|
1079
|
+
const ops = this.#findBinaryOverloads(left, right);
|
|
1080
|
+
if (ops.length === 0) return false;
|
|
1081
|
+
let rt = ops[0].returnType;
|
|
1082
|
+
for (let i = 1; i < ops.length; i++) rt = rt.unify(this.registry, ops[i].returnType) || dynType$1;
|
|
1083
|
+
return rt;
|
|
1084
|
+
}
|
|
1085
|
+
#findBinaryOverloads(leftType, rightType) {
|
|
1086
|
+
const nonexactMatches = [];
|
|
1087
|
+
for (const decl of this.declarations) {
|
|
1088
|
+
if (decl.leftType === leftType && decl.rightType === rightType) return [decl];
|
|
1089
|
+
const secondary = this.#matchBinaryOverload(decl, leftType, rightType);
|
|
1090
|
+
if (secondary) nonexactMatches.push(secondary);
|
|
1091
|
+
}
|
|
1092
|
+
if (nonexactMatches.length === 0) {
|
|
1093
|
+
const op = this.declarations[0]?.operator;
|
|
1094
|
+
if ((op === "==" || op === "!=") && leftType.kind === "dyn") return fallbackDynEqualityMatchers[op];
|
|
1095
|
+
}
|
|
1096
|
+
return nonexactMatches;
|
|
1097
|
+
}
|
|
1098
|
+
#matchBinaryOverload(decl, actualLeft, actualRight) {
|
|
1099
|
+
const bindings = decl.hasPlaceholderType ? /* @__PURE__ */ new Map() : null;
|
|
1100
|
+
const leftType = this.#matchTypeWithPlaceholders(decl.leftType, actualLeft, bindings);
|
|
1101
|
+
if (!leftType) return;
|
|
1102
|
+
const rightType = this.#matchTypeWithPlaceholders(decl.rightType, actualRight, bindings);
|
|
1103
|
+
if (!rightType) return;
|
|
1104
|
+
if ((decl.operator === "==" || decl.operator === "!=") && decl.leftType.kind === "dyn" && decl.leftType.valueType && actualLeft.kind !== "dyn" && actualRight.kind !== "dyn") return false;
|
|
1105
|
+
return decl.hasPlaceholderType ? {
|
|
1106
|
+
async: decl.async,
|
|
1107
|
+
signature: decl.signature,
|
|
1108
|
+
handler: decl.handler,
|
|
1109
|
+
leftType,
|
|
1110
|
+
rightType,
|
|
1111
|
+
returnType: decl.returnType.templated(this.registry, bindings)
|
|
1112
|
+
} : decl;
|
|
1113
|
+
}
|
|
1114
|
+
#matchesFunction(fn, argTypes, receiverType) {
|
|
1115
|
+
if (fn.hasPlaceholderType) return this.#matchWithPlaceholders(fn, argTypes, receiverType);
|
|
1116
|
+
if (receiverType && fn.receiverType && !receiverType.matches(fn.receiverType)) return;
|
|
1117
|
+
return fn.matchesArgs(argTypes);
|
|
1118
|
+
}
|
|
1119
|
+
#matchWithPlaceholders(fn, argTypes, receiverType) {
|
|
1120
|
+
const bindings = /* @__PURE__ */ new Map();
|
|
1121
|
+
if (receiverType && fn.receiverType) {
|
|
1122
|
+
if (!this.#matchTypeWithPlaceholders(fn.receiverType, receiverType, bindings)) return null;
|
|
1123
|
+
}
|
|
1124
|
+
for (let i = 0; i < argTypes.length; i++) if (!this.#matchTypeWithPlaceholders(fn.argTypes[i], argTypes[i], bindings)) return null;
|
|
1125
|
+
return {
|
|
1126
|
+
async: fn.async,
|
|
1127
|
+
handler: fn.handler,
|
|
1128
|
+
signature: fn.signature,
|
|
1129
|
+
returnType: fn.returnType.templated(this.registry, bindings)
|
|
1130
|
+
};
|
|
1131
|
+
}
|
|
1132
|
+
#matchTypeWithPlaceholders(declared, actual, bindings) {
|
|
1133
|
+
if (!declared.hasPlaceholderType) return actual.matches(declared) ? actual : null;
|
|
1134
|
+
const treatAsDyn = actual.kind === "dyn";
|
|
1135
|
+
if (!this.#collectPlaceholderBindings(declared, actual, bindings, treatAsDyn)) return null;
|
|
1136
|
+
if (treatAsDyn) return actual;
|
|
1137
|
+
return actual.matches(declared.templated(this.registry, bindings)) ? actual : null;
|
|
1138
|
+
}
|
|
1139
|
+
#collectPlaceholderBindings(dec, act, bind, fromDyn = false) {
|
|
1140
|
+
if (!dec.hasPlaceholderType) return true;
|
|
1141
|
+
if (!act) return false;
|
|
1142
|
+
const asDyn = fromDyn || act.kind === "dyn";
|
|
1143
|
+
act = act.unwrappedType;
|
|
1144
|
+
switch (dec.kind) {
|
|
1145
|
+
case "param": {
|
|
1146
|
+
const type = asDyn ? dynType$1 : act;
|
|
1147
|
+
const existing = bind.get(dec.name);
|
|
1148
|
+
if (!existing) return bind.set(dec.name, type) && true;
|
|
1149
|
+
return existing.kind === "dyn" || type.kind === "dyn" ? true : existing.matchesBoth(type);
|
|
1150
|
+
}
|
|
1151
|
+
case "list":
|
|
1152
|
+
if (act.name === "dyn") act = dec;
|
|
1153
|
+
if (act.kind !== "list") return false;
|
|
1154
|
+
return this.#collectPlaceholderBindings(dec.valueType, act.valueType, bind, asDyn);
|
|
1155
|
+
case "map":
|
|
1156
|
+
if (act.name === "dyn") act = dec;
|
|
1157
|
+
if (act.kind !== "map") return false;
|
|
1158
|
+
return this.#collectPlaceholderBindings(dec.keyType, act.keyType, bind, asDyn) && this.#collectPlaceholderBindings(dec.valueType, act.valueType, bind, asDyn);
|
|
1159
|
+
case "optional":
|
|
1160
|
+
if (act.name === "dyn") act = dec;
|
|
1161
|
+
if (act.kind !== "optional") return false;
|
|
1162
|
+
return this.#collectPlaceholderBindings(dec.valueType, act.valueType, bind, asDyn);
|
|
1163
|
+
}
|
|
1164
|
+
return true;
|
|
1165
|
+
}
|
|
1166
|
+
};
|
|
1167
|
+
function splitByComma(str) {
|
|
1168
|
+
const parts = [];
|
|
1169
|
+
let current = "";
|
|
1170
|
+
let depth = 0;
|
|
1171
|
+
for (const char of str) {
|
|
1172
|
+
if (char === "<") depth++;
|
|
1173
|
+
else if (char === ">") depth--;
|
|
1174
|
+
else if (char === "," && depth === 0) {
|
|
1175
|
+
parts.push(current.trim());
|
|
1176
|
+
current = "";
|
|
1177
|
+
continue;
|
|
1178
|
+
}
|
|
1179
|
+
current += char;
|
|
1180
|
+
}
|
|
1181
|
+
if (current) parts.push(current.trim());
|
|
1182
|
+
return parts;
|
|
1183
|
+
}
|
|
1184
|
+
const objTypesDecls = [
|
|
1185
|
+
[
|
|
1186
|
+
UnsignedInt,
|
|
1187
|
+
"uint",
|
|
1188
|
+
TYPES.uint,
|
|
1189
|
+
celTypes.uint
|
|
1190
|
+
],
|
|
1191
|
+
[
|
|
1192
|
+
Type,
|
|
1193
|
+
"type",
|
|
1194
|
+
TYPES.type,
|
|
1195
|
+
celTypes.type
|
|
1196
|
+
],
|
|
1197
|
+
[
|
|
1198
|
+
Optional,
|
|
1199
|
+
"optional",
|
|
1200
|
+
optionalType,
|
|
1201
|
+
celTypes.optional
|
|
1202
|
+
],
|
|
1203
|
+
[
|
|
1204
|
+
Uint8Array,
|
|
1205
|
+
"bytes",
|
|
1206
|
+
TYPES.bytes,
|
|
1207
|
+
celTypes.bytes
|
|
1208
|
+
],
|
|
1209
|
+
...typeof Buffer !== "undefined" ? [[
|
|
1210
|
+
Buffer,
|
|
1211
|
+
"bytes",
|
|
1212
|
+
TYPES.bytes,
|
|
1213
|
+
celTypes.bytes
|
|
1214
|
+
]] : []
|
|
1215
|
+
].map(([ctor, name, typeType, type]) => Object.freeze({
|
|
1216
|
+
name,
|
|
1217
|
+
typeType,
|
|
1218
|
+
type,
|
|
1219
|
+
ctor
|
|
1220
|
+
}));
|
|
1221
|
+
const objTypes = objTypesDecls.map((t) => [t.name, t]);
|
|
1222
|
+
const objTypesCtor = objTypesDecls.map((t) => [t.ctor, t]);
|
|
1223
|
+
const invalidVar = (postfix) => /* @__PURE__ */ new Error(`Invalid variable declaration: ${postfix}`);
|
|
1224
|
+
const invalidType = (postfix) => /* @__PURE__ */ new Error(`Invalid type declaration: ${postfix}`);
|
|
1225
|
+
const fallbackDynEqualityMatchers = {
|
|
1226
|
+
"==": [{
|
|
1227
|
+
handler: (a, b) => a === b,
|
|
1228
|
+
returnType: celTypes.bool
|
|
1229
|
+
}],
|
|
1230
|
+
"!=": [{
|
|
1231
|
+
handler: (a, b) => a !== b,
|
|
1232
|
+
returnType: celTypes.bool
|
|
1233
|
+
}]
|
|
1234
|
+
};
|
|
1235
|
+
var Registry = class Registry {
|
|
1236
|
+
#parent = null;
|
|
1237
|
+
#typeDeclarations;
|
|
1238
|
+
#ownsVariables = true;
|
|
1239
|
+
#operators = null;
|
|
1240
|
+
#functions = null;
|
|
1241
|
+
#operatorsByOp = null;
|
|
1242
|
+
#functionsByKey = null;
|
|
1243
|
+
#listTypes = null;
|
|
1244
|
+
#mapTypes = null;
|
|
1245
|
+
#optionalTypes = null;
|
|
1246
|
+
#others = null;
|
|
1247
|
+
#locked = false;
|
|
1248
|
+
constructor(opts = {}) {
|
|
1249
|
+
this.enableOptionalTypes = opts.enableOptionalTypes ?? false;
|
|
1250
|
+
this.unlistedVariablesAreDyn = opts.unlistedVariablesAreDyn ?? false;
|
|
1251
|
+
const parent = opts.parent instanceof Registry ? opts.parent : null;
|
|
1252
|
+
if (parent) {
|
|
1253
|
+
this.#parent = parent;
|
|
1254
|
+
let opParent = parent;
|
|
1255
|
+
while (opParent && !opParent.#operators) opParent = opParent.#parent;
|
|
1256
|
+
let fnParent = parent;
|
|
1257
|
+
while (fnParent && !fnParent.#functions) fnParent = fnParent.#parent;
|
|
1258
|
+
this.#operatorsByOp = parent.#operatorsByOp;
|
|
1259
|
+
this.#functionsByKey = parent.#functionsByKey;
|
|
1260
|
+
this.#others = {
|
|
1261
|
+
operators: opParent.#operators,
|
|
1262
|
+
functions: fnParent.#functions
|
|
1263
|
+
};
|
|
1264
|
+
this.objectTypes = new Map(parent.objectTypes);
|
|
1265
|
+
this.objectTypesByConstructor = new Map(parent.objectTypesByConstructor);
|
|
1266
|
+
this.variables = parent.variables;
|
|
1267
|
+
this.#ownsVariables = false;
|
|
1268
|
+
this.#typeDeclarations = parent.#typeDeclarations;
|
|
1269
|
+
this.#listTypes = parent.#listTypes;
|
|
1270
|
+
this.#mapTypes = parent.#mapTypes;
|
|
1271
|
+
this.#optionalTypes = parent.#optionalTypes;
|
|
1272
|
+
if (this.enableOptionalTypes !== parent.enableOptionalTypes || this.unlistedVariablesAreDyn !== parent.unlistedVariablesAreDyn) toggleOptionalTypes(this, this.enableOptionalTypes);
|
|
1273
|
+
} else {
|
|
1274
|
+
this.#operators = [];
|
|
1275
|
+
this.#functions = [];
|
|
1276
|
+
this.objectTypes = new Map(objTypes);
|
|
1277
|
+
this.objectTypesByConstructor = new Map(objTypesCtor);
|
|
1278
|
+
this.#typeDeclarations = new Map(objEntries(celTypes));
|
|
1279
|
+
this.#listTypes = /* @__PURE__ */ new Map();
|
|
1280
|
+
this.#mapTypes = /* @__PURE__ */ new Map();
|
|
1281
|
+
this.#optionalTypes = /* @__PURE__ */ new Map();
|
|
1282
|
+
this.variables = /* @__PURE__ */ new Map();
|
|
1283
|
+
this.variables.dyn = this.unlistedVariablesAreDyn;
|
|
1284
|
+
for (const n in TYPES) this.registerConstant(n, "type", TYPES[n]);
|
|
1285
|
+
}
|
|
1286
|
+
}
|
|
1287
|
+
#ensureOwnVariables() {
|
|
1288
|
+
if (this.#ownsVariables) return;
|
|
1289
|
+
this.variables = new Map(this.variables);
|
|
1290
|
+
this.variables.dyn = this.unlistedVariablesAreDyn;
|
|
1291
|
+
this.#ownsVariables = true;
|
|
1292
|
+
}
|
|
1293
|
+
deleteVariable(name) {
|
|
1294
|
+
this.#ensureOwnVariables();
|
|
1295
|
+
this.variables.delete(name);
|
|
1296
|
+
}
|
|
1297
|
+
#pushOperator(decl) {
|
|
1298
|
+
if (!this.#operators) this.#operatorsByOp = null;
|
|
1299
|
+
this.operatorCandidates(decl.operator).add(decl);
|
|
1300
|
+
this.#operators.push(decl);
|
|
1301
|
+
}
|
|
1302
|
+
#pushFunction(decl) {
|
|
1303
|
+
if (!this.#functions) this.#functionsByKey = null;
|
|
1304
|
+
this.#functionCandidates(decl.partitionKey).add(decl);
|
|
1305
|
+
this.#functions.push(decl);
|
|
1306
|
+
}
|
|
1307
|
+
#ensureCandiate(c, key) {
|
|
1308
|
+
return c.get(key) || c.set(key, new Candidates(this)).get(key);
|
|
1309
|
+
}
|
|
1310
|
+
#getOperators() {
|
|
1311
|
+
if (this.#operators) return this.#operators;
|
|
1312
|
+
return this.#operators = [...this.#others.operators];
|
|
1313
|
+
}
|
|
1314
|
+
#getFunctions() {
|
|
1315
|
+
if (this.#functions) return this.#functions;
|
|
1316
|
+
return this.#functions = [...this.#others.functions];
|
|
1317
|
+
}
|
|
1318
|
+
operatorCandidates(op) {
|
|
1319
|
+
if (this.#operatorsByOp) return this.#ensureCandiate(this.#operatorsByOp, op);
|
|
1320
|
+
const c = this.#operatorsByOp = /* @__PURE__ */ new Map();
|
|
1321
|
+
for (const decl of this.#getOperators()) this.#ensureCandiate(c, decl.operator).add(decl);
|
|
1322
|
+
return this.#ensureCandiate(c, op);
|
|
1323
|
+
}
|
|
1324
|
+
functionCandidates(rec, name, argLen) {
|
|
1325
|
+
return this.#functionCandidates(`${rec ? "rcall" : "call"}:${name}:${argLen}`);
|
|
1326
|
+
}
|
|
1327
|
+
#functionCandidates(key) {
|
|
1328
|
+
if (this.#functionsByKey) return this.#ensureCandiate(this.#functionsByKey, key);
|
|
1329
|
+
const c = this.#functionsByKey = /* @__PURE__ */ new Map();
|
|
1330
|
+
for (const decl of this.#getFunctions()) this.#ensureCandiate(c, decl.partitionKey).add(decl);
|
|
1331
|
+
return this.#ensureCandiate(c, key);
|
|
1332
|
+
}
|
|
1333
|
+
registerVariable(name, type, opts) {
|
|
1334
|
+
if (this.#locked) throw new Error("Cannot modify frozen registry");
|
|
1335
|
+
let description = opts?.description;
|
|
1336
|
+
let value;
|
|
1337
|
+
if (typeof name === "string" && typeof type === "object" && !(type instanceof TypeDeclaration)) {
|
|
1338
|
+
description = type.description;
|
|
1339
|
+
value = type.value;
|
|
1340
|
+
if (type.schema) type = this.registerType({
|
|
1341
|
+
name: `$${name}`,
|
|
1342
|
+
schema: type.schema
|
|
1343
|
+
}).type;
|
|
1344
|
+
else type = type.type;
|
|
1345
|
+
} else if (typeof name === "object") {
|
|
1346
|
+
if (name.schema) type = this.registerType({
|
|
1347
|
+
name: `$${name.name}`,
|
|
1348
|
+
schema: name.schema
|
|
1349
|
+
}).type;
|
|
1350
|
+
else type = name.type;
|
|
1351
|
+
description = name.description;
|
|
1352
|
+
value = name.value;
|
|
1353
|
+
name = name.name;
|
|
1354
|
+
}
|
|
1355
|
+
if (typeof name !== "string" || !name) throw invalidVar(`name must be a string`);
|
|
1356
|
+
if (RESERVED.has(name)) throw invalidVar(`'${name}' is a reserved name`);
|
|
1357
|
+
if (this.variables.get(name) !== void 0) throw invalidVar(`'${name}' is already registered`);
|
|
1358
|
+
if (typeof type === "string") type = this.getType(type);
|
|
1359
|
+
else if (!(type instanceof TypeDeclaration)) throw invalidVar(`type is required`);
|
|
1360
|
+
this.#ensureOwnVariables();
|
|
1361
|
+
this.variables.set(name, new VariableDeclaration(name, type, description, value));
|
|
1362
|
+
return this;
|
|
1363
|
+
}
|
|
1364
|
+
#registerSchemaAsType(name, schema) {
|
|
1365
|
+
const fields = Object.create(null);
|
|
1366
|
+
for (const key of objKeys(schema)) {
|
|
1367
|
+
const def = schema[key];
|
|
1368
|
+
if (typeof def === "object" && def) fields[key] = this.registerType({
|
|
1369
|
+
name: `${name}.${key}`,
|
|
1370
|
+
schema: def
|
|
1371
|
+
}).type.name;
|
|
1372
|
+
else if (typeof def === "string") fields[key] = def;
|
|
1373
|
+
else throw new Error(`Invalid field definition for '${name}.${key}'`);
|
|
1374
|
+
}
|
|
1375
|
+
return fields;
|
|
1376
|
+
}
|
|
1377
|
+
registerConstant(name, type, value) {
|
|
1378
|
+
if (typeof name === "object") this.registerVariable(name);
|
|
1379
|
+
else this.registerVariable({
|
|
1380
|
+
name,
|
|
1381
|
+
type,
|
|
1382
|
+
value
|
|
1383
|
+
});
|
|
1384
|
+
return this;
|
|
1385
|
+
}
|
|
1386
|
+
getType(typename) {
|
|
1387
|
+
return this.#parseTypeString(typename, true);
|
|
1388
|
+
}
|
|
1389
|
+
getListType(type) {
|
|
1390
|
+
return this.#listTypes.get(type) || this.#listTypes.set(type, this.#parseTypeString(`list<${type}>`, true)).get(type);
|
|
1391
|
+
}
|
|
1392
|
+
getMapType(a, b) {
|
|
1393
|
+
return this.#mapTypes.get(a)?.get(b) || (this.#mapTypes.get(a) || this.#mapTypes.set(a, /* @__PURE__ */ new Map()).get(a)).set(b, this.#parseTypeString(`map<${a}, ${b}>`, true)).get(b);
|
|
1394
|
+
}
|
|
1395
|
+
getOptionalType(type) {
|
|
1396
|
+
return this.#optionalTypes.get(type) || this.#optionalTypes.set(type, this.#parseTypeString(`optional<${type}>`, true)).get(type);
|
|
1397
|
+
}
|
|
1398
|
+
assertType(typename, type, signature) {
|
|
1399
|
+
try {
|
|
1400
|
+
return this.#parseTypeString(typename, true);
|
|
1401
|
+
} catch (e) {
|
|
1402
|
+
e.message = `Invalid ${type} '${e.unknownType || typename}' in '${signature}'`;
|
|
1403
|
+
throw e;
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
getFunctionType(typename) {
|
|
1407
|
+
if (typename === "ast") return astType;
|
|
1408
|
+
const t = this.#parseTypeString(typename, true);
|
|
1409
|
+
if (t.kind === "dyn" && t.valueType) throw new Error(`type '${t.name}' is not supported`);
|
|
1410
|
+
return t;
|
|
1411
|
+
}
|
|
1412
|
+
registerType(name, _d) {
|
|
1413
|
+
if (this.#locked) throw new Error("Cannot modify frozen registry");
|
|
1414
|
+
if (typeof name === "object") _d = name, name = _d.fullName || _d.name || _d.ctor?.name;
|
|
1415
|
+
if (typeof name === "string" && name[0] === ".") name = name.slice(1);
|
|
1416
|
+
if (typeof name !== "string" || name.length < 2 || RESERVED.has(name)) throw invalidType(`name '${name}' is not valid`);
|
|
1417
|
+
if (this.objectTypes.has(name)) throw invalidType(`type '${name}' already registered`);
|
|
1418
|
+
const type = this.#parseTypeString(name, false);
|
|
1419
|
+
if (type.kind !== "message") throw invalidType(`type '${name}' is not valid`);
|
|
1420
|
+
const decl = {
|
|
1421
|
+
name,
|
|
1422
|
+
typeType: new Type(name),
|
|
1423
|
+
type,
|
|
1424
|
+
ctor: typeof _d === "function" ? _d : _d?.ctor,
|
|
1425
|
+
convert: typeof _d === "function" ? void 0 : _d?.convert,
|
|
1426
|
+
fields: typeof _d?.schema === "object" ? this.#normalizeFields(name, this.#registerSchemaAsType(name, _d.schema)) : this.#normalizeFields(name, typeof _d === "function" ? void 0 : _d?.fields)
|
|
1427
|
+
};
|
|
1428
|
+
if (typeof decl.ctor !== "function") {
|
|
1429
|
+
if (!decl.fields) throw invalidType(`type '${name}' requires a constructor or fields`);
|
|
1430
|
+
Object.assign(decl, this.#createDefaultConvert(name, decl.fields));
|
|
1431
|
+
}
|
|
1432
|
+
this.objectTypes.set(name, Object.freeze(decl));
|
|
1433
|
+
this.objectTypesByConstructor.set(decl.ctor, decl);
|
|
1434
|
+
this.registerFunctionOverload(`type(${name}): type`, () => decl.typeType, { async: false });
|
|
1435
|
+
return decl;
|
|
1436
|
+
}
|
|
1437
|
+
#parseTypeString(typeStr, requireKnownTypes = true) {
|
|
1438
|
+
let match = this.#typeDeclarations.get(typeStr);
|
|
1439
|
+
if (match) return match;
|
|
1440
|
+
if (typeof typeStr !== "string" || !typeStr.length) throw new Error(`Invalid type: must be a string`);
|
|
1441
|
+
match = typeStr.match(/^[A-Z]$/);
|
|
1442
|
+
if (match) return this.#createDeclaration(_createPlaceholderType, typeStr, typeStr);
|
|
1443
|
+
match = typeStr.match(/^(dyn|list|map|optional)<(.+)>$/);
|
|
1444
|
+
if (!match) {
|
|
1445
|
+
if (requireKnownTypes) {
|
|
1446
|
+
const err = /* @__PURE__ */ new Error(`Unknown type: ${typeStr}`);
|
|
1447
|
+
err.unknownType = typeStr;
|
|
1448
|
+
throw err;
|
|
1449
|
+
}
|
|
1450
|
+
return this.#createDeclaration(_createMessageType, typeStr, typeStr);
|
|
1451
|
+
}
|
|
1452
|
+
const kind = match[1];
|
|
1453
|
+
const inner = match[2].trim();
|
|
1454
|
+
switch (kind) {
|
|
1455
|
+
case "dyn": {
|
|
1456
|
+
const type = this.#parseTypeString(inner, requireKnownTypes).wrappedType;
|
|
1457
|
+
this.#typeDeclarations.set(type.name, type);
|
|
1458
|
+
return type;
|
|
1459
|
+
}
|
|
1460
|
+
case "list": {
|
|
1461
|
+
const vType = this.#parseTypeString(inner, requireKnownTypes);
|
|
1462
|
+
return this.#createDeclaration(_createListType, `list<${vType}>`, vType);
|
|
1463
|
+
}
|
|
1464
|
+
case "map": {
|
|
1465
|
+
const parts = splitByComma(inner);
|
|
1466
|
+
if (parts.length !== 2) throw new Error(`Invalid map type: ${typeStr}`);
|
|
1467
|
+
const kType = this.#parseTypeString(parts[0], requireKnownTypes);
|
|
1468
|
+
const vType = this.#parseTypeString(parts[1], requireKnownTypes);
|
|
1469
|
+
return this.#createDeclaration(_createMapType, `map<${kType}, ${vType}>`, kType, vType);
|
|
1470
|
+
}
|
|
1471
|
+
case "optional": {
|
|
1472
|
+
const vType = this.#parseTypeString(inner, requireKnownTypes);
|
|
1473
|
+
return this.#createDeclaration(_createOptionalType, `optional<${vType}>`, vType);
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
}
|
|
1477
|
+
#createDeclaration(creator, key, ...args) {
|
|
1478
|
+
return this.#typeDeclarations.get(key) || this.#typeDeclarations.set(key, creator(...args)).get(key);
|
|
1479
|
+
}
|
|
1480
|
+
findMacro(name, hasReceiver, argLen) {
|
|
1481
|
+
return this.functionCandidates(hasReceiver, name, argLen).macro;
|
|
1482
|
+
}
|
|
1483
|
+
findUnaryOverload(op, left) {
|
|
1484
|
+
return this.operatorCandidates(op).findUnaryOverload(left);
|
|
1485
|
+
}
|
|
1486
|
+
findBinaryOverload(op, left, right) {
|
|
1487
|
+
return this.operatorCandidates(op).findBinaryOverload(left, right);
|
|
1488
|
+
}
|
|
1489
|
+
#toCelFieldType(field) {
|
|
1490
|
+
if (typeof field === "string") return { type: field };
|
|
1491
|
+
if (field.id) return protobufjsFieldToCelType(field);
|
|
1492
|
+
return field;
|
|
1493
|
+
}
|
|
1494
|
+
#toCelFieldDeclaration(typename, fields, k, requireKnownTypes = false) {
|
|
1495
|
+
try {
|
|
1496
|
+
const field = this.#toCelFieldType(fields[k]);
|
|
1497
|
+
if (typeof field?.type !== "string") throw new Error(`unsupported declaration`);
|
|
1498
|
+
return this.#parseTypeString(field.type, requireKnownTypes);
|
|
1499
|
+
} catch (e) {
|
|
1500
|
+
e.message = `Field '${k}' in type '${typename}' has unsupported declaration: ${JSON.stringify(fields[k])}`;
|
|
1501
|
+
throw e;
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
#normalizeFields(typename, fields) {
|
|
1505
|
+
if (!fields) return;
|
|
1506
|
+
const all = Object.create(null);
|
|
1507
|
+
for (const k of objKeys(fields)) all[k] = this.#toCelFieldDeclaration(typename, fields, k);
|
|
1508
|
+
return all;
|
|
1509
|
+
}
|
|
1510
|
+
#createDefaultConvert(name, fields) {
|
|
1511
|
+
const keys = objKeys(fields);
|
|
1512
|
+
const conversions = Object.create(null);
|
|
1513
|
+
for (const k of keys) {
|
|
1514
|
+
const type = fields[k];
|
|
1515
|
+
const decl = type.kind === "message" && this.objectTypes.get(type.name);
|
|
1516
|
+
if (decl === false) conversions[k] = false;
|
|
1517
|
+
else conversions[k] = decl.convert ? decl : false;
|
|
1518
|
+
}
|
|
1519
|
+
const Ctor = { [name]: class extends Map {
|
|
1520
|
+
#raw;
|
|
1521
|
+
constructor(v) {
|
|
1522
|
+
super();
|
|
1523
|
+
this.#raw = v;
|
|
1524
|
+
}
|
|
1525
|
+
[Symbol.iterator]() {
|
|
1526
|
+
if (this.size !== keys.length) for (const k of keys) this.get(k);
|
|
1527
|
+
return super[Symbol.iterator]();
|
|
1528
|
+
}
|
|
1529
|
+
get(field) {
|
|
1530
|
+
let v = super.get(field);
|
|
1531
|
+
if (v !== void 0 || this.has(field)) return v;
|
|
1532
|
+
const dec = conversions[field];
|
|
1533
|
+
if (dec === void 0) return;
|
|
1534
|
+
v = this.#raw instanceof Map ? this.#raw.get(field) : this.#raw?.[field];
|
|
1535
|
+
if (dec && v && typeof v === "object") switch (v.constructor) {
|
|
1536
|
+
case void 0:
|
|
1537
|
+
case Object:
|
|
1538
|
+
case Map: v = dec.convert(v);
|
|
1539
|
+
}
|
|
1540
|
+
return super.set(field, v), v;
|
|
1541
|
+
}
|
|
1542
|
+
} }[name];
|
|
1543
|
+
return {
|
|
1544
|
+
ctor: Ctor,
|
|
1545
|
+
convert(v) {
|
|
1546
|
+
if (!v) return;
|
|
1547
|
+
if (v.constructor === Ctor) return v;
|
|
1548
|
+
return new Ctor(v);
|
|
1549
|
+
}
|
|
1550
|
+
};
|
|
1551
|
+
}
|
|
1552
|
+
clone(opts) {
|
|
1553
|
+
this.#locked = true;
|
|
1554
|
+
return new Registry({
|
|
1555
|
+
parent: this,
|
|
1556
|
+
unlistedVariablesAreDyn: opts.unlistedVariablesAreDyn,
|
|
1557
|
+
enableOptionalTypes: opts.enableOptionalTypes
|
|
1558
|
+
});
|
|
1559
|
+
}
|
|
1560
|
+
getDefinitions() {
|
|
1561
|
+
const variables = [];
|
|
1562
|
+
const functions = [];
|
|
1563
|
+
for (const [, varDecl] of this.variables) {
|
|
1564
|
+
if (!varDecl) continue;
|
|
1565
|
+
variables.push({
|
|
1566
|
+
name: varDecl.name,
|
|
1567
|
+
description: varDecl.description || null,
|
|
1568
|
+
type: varDecl.type.name
|
|
1569
|
+
});
|
|
1570
|
+
}
|
|
1571
|
+
for (const decl of this.#getFunctions()) functions.push({
|
|
1572
|
+
signature: decl.signature,
|
|
1573
|
+
name: decl.name,
|
|
1574
|
+
description: decl.description,
|
|
1575
|
+
receiverType: decl.receiverType ? decl.receiverType.name : null,
|
|
1576
|
+
returnType: decl.returnType.name,
|
|
1577
|
+
params: decl.params.map((p) => ({
|
|
1578
|
+
name: p.name,
|
|
1579
|
+
type: p.type.name,
|
|
1580
|
+
description: p.description
|
|
1581
|
+
}))
|
|
1582
|
+
});
|
|
1583
|
+
return {
|
|
1584
|
+
variables,
|
|
1585
|
+
functions
|
|
1586
|
+
};
|
|
1587
|
+
}
|
|
1588
|
+
#parseSignature(signature) {
|
|
1589
|
+
if (typeof signature !== "string") throw new Error("Invalid signature: must be a string");
|
|
1590
|
+
const match = signature.match(/^(?:([a-zA-Z0-9.<>]+)\.)?(\w+)\(([^)]*)\):(.*)$/);
|
|
1591
|
+
if (!match) throw new Error(`Invalid signature: ${signature}`);
|
|
1592
|
+
const returnType = match[4].trim();
|
|
1593
|
+
if (!returnType) throw new Error(`Invalid signature: ${signature}`);
|
|
1594
|
+
return {
|
|
1595
|
+
receiverType: match[1] || null,
|
|
1596
|
+
name: match[2],
|
|
1597
|
+
argTypes: splitByComma(match[3]),
|
|
1598
|
+
returnType
|
|
1599
|
+
};
|
|
1600
|
+
}
|
|
1601
|
+
#functionSignatureOverlaps(a, b) {
|
|
1602
|
+
if (a.name !== b.name) return false;
|
|
1603
|
+
if (a.argTypes.length !== b.argTypes.length) return false;
|
|
1604
|
+
if ((a.receiverType || b.receiverType) && (!a.receiverType || !b.receiverType)) return false;
|
|
1605
|
+
return !(a.receiverType !== b.receiverType && a.receiverType !== dynType$1 && b.receiverType !== dynType$1) && (b.macro || a.macro || b.argTypes.every((t, i) => {
|
|
1606
|
+
const o = a.argTypes[i];
|
|
1607
|
+
return t === o || t === dynType$1 || o === dynType$1;
|
|
1608
|
+
}));
|
|
1609
|
+
}
|
|
1610
|
+
#checkOverlappingSignatures(newDec) {
|
|
1611
|
+
for (const decl of this.#functionCandidates(newDec.partitionKey)) {
|
|
1612
|
+
if (!this.#functionSignatureOverlaps(decl, newDec)) continue;
|
|
1613
|
+
throw new Error(`Function signature '${newDec.signature}' overlaps with existing overload '${decl.signature}'.`);
|
|
1614
|
+
}
|
|
1615
|
+
}
|
|
1616
|
+
#normalizeParam(i, aType, param) {
|
|
1617
|
+
if (!param) return {
|
|
1618
|
+
type: this.getFunctionType(aType),
|
|
1619
|
+
name: `arg${i}`,
|
|
1620
|
+
description: null
|
|
1621
|
+
};
|
|
1622
|
+
const type = param.type || aType;
|
|
1623
|
+
if (!type) throw new Error(`params[${i}].type is required`);
|
|
1624
|
+
if (aType && type !== aType) throw new Error(`params[${i}].type not equal to signature type`);
|
|
1625
|
+
return {
|
|
1626
|
+
name: param.name || `arg${i}`,
|
|
1627
|
+
type: this.getFunctionType(type),
|
|
1628
|
+
description: param.description ?? null
|
|
1629
|
+
};
|
|
1630
|
+
}
|
|
1631
|
+
registerFunctionOverload(s, handler, opts) {
|
|
1632
|
+
if (this.#locked) throw new Error("Cannot modify frozen registry");
|
|
1633
|
+
if (typeof s === "object") opts = s;
|
|
1634
|
+
else if (typeof handler === "object") opts = handler;
|
|
1635
|
+
else if (!opts) opts = {};
|
|
1636
|
+
const sig = typeof s === "string" ? s : opts.signature ?? void 0;
|
|
1637
|
+
const parsed = sig !== void 0 ? this.#parseSignature(sig) : void 0;
|
|
1638
|
+
const name = parsed?.name || opts.name;
|
|
1639
|
+
const receiverType = parsed?.receiverType || opts.receiverType;
|
|
1640
|
+
const argTypes = parsed?.argTypes;
|
|
1641
|
+
const returnType = parsed?.returnType || opts.returnType;
|
|
1642
|
+
const params = opts.params;
|
|
1643
|
+
handler = typeof handler === "function" ? handler : opts.handler;
|
|
1644
|
+
let dec;
|
|
1645
|
+
try {
|
|
1646
|
+
if (!name) throw new Error(`signature or name are required`);
|
|
1647
|
+
if (!returnType) throw new Error(`must have a returnType`);
|
|
1648
|
+
if (params) {
|
|
1649
|
+
if (argTypes && params.length !== argTypes.length) throw new Error(`mismatched length in params and args in signature`);
|
|
1650
|
+
} else if (!argTypes) throw new Error(`signature or params are required`);
|
|
1651
|
+
dec = new FunctionDeclaration({
|
|
1652
|
+
name,
|
|
1653
|
+
async: opts?.async,
|
|
1654
|
+
receiverType: receiverType ? this.getType(receiverType) : null,
|
|
1655
|
+
returnType: this.getType(returnType),
|
|
1656
|
+
handler,
|
|
1657
|
+
description: opts.description,
|
|
1658
|
+
params: (argTypes || params).map((_, i) => this.#normalizeParam(i, argTypes?.[i], params?.[i]))
|
|
1659
|
+
});
|
|
1660
|
+
} catch (e) {
|
|
1661
|
+
if (typeof sig === "string") e.message = `Invalid function declaration '${sig}': ${e.message}`;
|
|
1662
|
+
else if (name) e.message = `Invalid function declaration '${name}': ${e.message}`;
|
|
1663
|
+
else e.message = `Invalid function declaration: ${e.message}`;
|
|
1664
|
+
throw e;
|
|
1665
|
+
}
|
|
1666
|
+
this.#checkOverlappingSignatures(dec);
|
|
1667
|
+
this.#pushFunction(dec);
|
|
1668
|
+
}
|
|
1669
|
+
registerOperatorOverload(string, handler, opts) {
|
|
1670
|
+
const unaryParts = string.match(/^([-!])([\w.<>]+)(?::\s*([\w.<>]+))?$/);
|
|
1671
|
+
if (unaryParts) {
|
|
1672
|
+
const [, op, operandType, returnType] = unaryParts;
|
|
1673
|
+
return this.unaryOverload(op, operandType, handler, returnType, opts?.async);
|
|
1674
|
+
}
|
|
1675
|
+
const parts = string.match(/^([\w.<>]+) ([-+*%/]|==|!=|<|<=|>|>=|in) ([\w.<>]+)(?::\s*([\w.<>]+))?$/);
|
|
1676
|
+
if (!parts) throw new Error(`Operator overload invalid: ${string}`);
|
|
1677
|
+
const [, leftType, op, rightType, returnType] = parts;
|
|
1678
|
+
return this.binaryOverload(leftType, op, rightType, handler, returnType);
|
|
1679
|
+
}
|
|
1680
|
+
unaryOverload(op, typeStr, handler, returnTypeStr, async) {
|
|
1681
|
+
if (this.#locked) throw new Error("Cannot modify frozen registry");
|
|
1682
|
+
const leftType = this.assertType(typeStr, "type", `${op}${typeStr}`);
|
|
1683
|
+
const returnType = this.assertType(returnTypeStr || typeStr, "return type", `${op}${typeStr}: ${returnTypeStr || typeStr}`);
|
|
1684
|
+
const d = new OperatorDeclaration({
|
|
1685
|
+
op: `${op}_`,
|
|
1686
|
+
leftType,
|
|
1687
|
+
returnType,
|
|
1688
|
+
handler,
|
|
1689
|
+
async
|
|
1690
|
+
});
|
|
1691
|
+
this.#pushOperator(this.#assertOverload(d));
|
|
1692
|
+
}
|
|
1693
|
+
#hasOverload(d) {
|
|
1694
|
+
for (const o of this.operatorCandidates(d.operator)) if (d.equals(o)) return true;
|
|
1695
|
+
return false;
|
|
1696
|
+
}
|
|
1697
|
+
#assertOverload(decl) {
|
|
1698
|
+
if (!this.#hasOverload(decl)) return decl;
|
|
1699
|
+
throw new Error(`Operator overload already registered: ${decl.signature}`);
|
|
1700
|
+
}
|
|
1701
|
+
binaryOverload(leftTypeStr, op, rightTypeStr, handler, returnTypeStr, async) {
|
|
1702
|
+
if (this.#locked) throw new Error("Cannot modify frozen registry");
|
|
1703
|
+
returnTypeStr ??= isRelational.has(op) ? "bool" : leftTypeStr;
|
|
1704
|
+
const sig = `${leftTypeStr} ${op} ${rightTypeStr}: ${returnTypeStr}`;
|
|
1705
|
+
let leftType = this.assertType(leftTypeStr, "left type", sig);
|
|
1706
|
+
let rightType = this.assertType(rightTypeStr, "right type", sig);
|
|
1707
|
+
const returnType = this.assertType(returnTypeStr, "return type", sig);
|
|
1708
|
+
if (leftType.kind === "dyn" && leftType.valueType) rightType = rightType.wrappedType;
|
|
1709
|
+
else if (rightType.kind === "dyn" && rightType.valueType) leftType = leftType.wrappedType;
|
|
1710
|
+
if (isRelational.has(op) && returnType.type !== "bool") throw new Error(`Comparison operator '${op}' must return 'bool', got '${returnType.type}'`);
|
|
1711
|
+
const dec = new OperatorDeclaration({
|
|
1712
|
+
op,
|
|
1713
|
+
leftType,
|
|
1714
|
+
rightType,
|
|
1715
|
+
returnType,
|
|
1716
|
+
handler,
|
|
1717
|
+
async
|
|
1718
|
+
});
|
|
1719
|
+
if (dec.hasPlaceholderType && !(rightType.hasPlaceholderType && leftType.hasPlaceholderType)) throw new Error(`Operator overload with placeholders must use them in both left and right types: ${sig}`);
|
|
1720
|
+
this.#assertOverload(dec);
|
|
1721
|
+
if (op === "==") {
|
|
1722
|
+
const declarations = [new OperatorDeclaration({
|
|
1723
|
+
op: "!=",
|
|
1724
|
+
leftType,
|
|
1725
|
+
rightType,
|
|
1726
|
+
handler(a, b, ast, ev) {
|
|
1727
|
+
return !handler(a, b, ast, ev);
|
|
1728
|
+
},
|
|
1729
|
+
returnType,
|
|
1730
|
+
async
|
|
1731
|
+
})];
|
|
1732
|
+
if (leftType !== rightType) declarations.push(new OperatorDeclaration({
|
|
1733
|
+
op: "==",
|
|
1734
|
+
leftType: rightType,
|
|
1735
|
+
rightType: leftType,
|
|
1736
|
+
handler(a, b, ast, ev) {
|
|
1737
|
+
return handler(b, a, ast, ev);
|
|
1738
|
+
},
|
|
1739
|
+
returnType,
|
|
1740
|
+
async
|
|
1741
|
+
}), new OperatorDeclaration({
|
|
1742
|
+
op: "!=",
|
|
1743
|
+
leftType: rightType,
|
|
1744
|
+
rightType: leftType,
|
|
1745
|
+
handler(a, b, ast, ev) {
|
|
1746
|
+
return !handler(b, a, ast, ev);
|
|
1747
|
+
},
|
|
1748
|
+
returnType,
|
|
1749
|
+
async
|
|
1750
|
+
}));
|
|
1751
|
+
for (const decl of declarations) this.#assertOverload(decl);
|
|
1752
|
+
for (const decl of declarations) this.#pushOperator(decl);
|
|
1753
|
+
}
|
|
1754
|
+
this.#pushOperator(dec);
|
|
1755
|
+
}
|
|
1756
|
+
};
|
|
1757
|
+
const isRelational = /* @__PURE__ */ new Set([
|
|
1758
|
+
"<",
|
|
1759
|
+
"<=",
|
|
1760
|
+
">",
|
|
1761
|
+
">=",
|
|
1762
|
+
"==",
|
|
1763
|
+
"!=",
|
|
1764
|
+
"in"
|
|
1765
|
+
]);
|
|
1766
|
+
function createRegistry(opts) {
|
|
1767
|
+
return new Registry(opts);
|
|
1768
|
+
}
|
|
1769
|
+
var RootContext = class {
|
|
1770
|
+
#vars;
|
|
1771
|
+
#contextObj;
|
|
1772
|
+
#contextMap;
|
|
1773
|
+
#convertCache;
|
|
1774
|
+
constructor(registry, context) {
|
|
1775
|
+
this.#vars = registry.variables;
|
|
1776
|
+
if (context === void 0 || context === null) return;
|
|
1777
|
+
if (typeof context !== "object") throw evaluationError("invalid_context", "Context must be an object");
|
|
1778
|
+
if (context instanceof Map) this.#contextMap = context;
|
|
1779
|
+
else this.#contextObj = context;
|
|
1780
|
+
}
|
|
1781
|
+
getValue(key) {
|
|
1782
|
+
return this.#convertCache?.get(key) || (this.#contextObj ? this.#contextObj[key] : this.#contextMap?.get(key));
|
|
1783
|
+
}
|
|
1784
|
+
getVariable(name) {
|
|
1785
|
+
return this.#vars.get(name) ?? (this.#vars.dyn && !RESERVED.has(name) ? new VariableDeclaration(name, dynType$1) : void 0);
|
|
1786
|
+
}
|
|
1787
|
+
getCheckedValue(ev, ast) {
|
|
1788
|
+
const v = this.getValue(ast.args);
|
|
1789
|
+
if (v === void 0) throw ev.createError("unknown_variable", `Unknown variable: ${ast.args}`, ast);
|
|
1790
|
+
if (ast.checkedType.matchesValueType(v, ev)) return v;
|
|
1791
|
+
const type = ast.checkedType;
|
|
1792
|
+
const valueType = ev.debugType(v);
|
|
1793
|
+
if (type.kind === "message" && valueType.kind === "map") {
|
|
1794
|
+
const c = ev.objectTypes.get(type.name)?.convert?.(v);
|
|
1795
|
+
if (c) return (this.#convertCache ??= /* @__PURE__ */ new Map()).set(ast.args, c), c;
|
|
1796
|
+
}
|
|
1797
|
+
throw ev.createError("variable_type_mismatch", `Variable '${ast.args}' is not of type '${type}', got '${valueType}'`, ast);
|
|
1798
|
+
}
|
|
1799
|
+
forkWithVariable(iterVar, iterType) {
|
|
1800
|
+
return new OverlayContext(this, iterVar, iterType);
|
|
1801
|
+
}
|
|
1802
|
+
};
|
|
1803
|
+
var OverlayContext = class OverlayContext {
|
|
1804
|
+
#parent;
|
|
1805
|
+
accuType;
|
|
1806
|
+
accuValue;
|
|
1807
|
+
iterValue;
|
|
1808
|
+
constructor(parent, iterVar, iterType) {
|
|
1809
|
+
this.#parent = parent;
|
|
1810
|
+
this.iterVar = iterVar;
|
|
1811
|
+
this.iterType = iterType;
|
|
1812
|
+
}
|
|
1813
|
+
forkWithVariable(iterVar, iterType) {
|
|
1814
|
+
return new OverlayContext(this, iterVar, iterType);
|
|
1815
|
+
}
|
|
1816
|
+
reuse(parent) {
|
|
1817
|
+
if (!this.async) return this.#parent = parent, this;
|
|
1818
|
+
const ctx = new OverlayContext(parent, this.iterVar, this.iterType);
|
|
1819
|
+
ctx.accuType = this.accuType;
|
|
1820
|
+
return ctx;
|
|
1821
|
+
}
|
|
1822
|
+
setIterValue(v, ev) {
|
|
1823
|
+
if (this.iterType.matchesValueType(v, ev)) return this.iterValue = v, this;
|
|
1824
|
+
const type = this.iterType;
|
|
1825
|
+
const valueType = ev.debugType(v);
|
|
1826
|
+
if (type.kind === "message" && valueType.kind === "map") {
|
|
1827
|
+
const c = ev.objectTypes.get(type.name)?.convert?.(v);
|
|
1828
|
+
if (c) return this.iterValue = c, this;
|
|
1829
|
+
}
|
|
1830
|
+
throw ev.createError("variable_type_mismatch", `Variable '${this.iterVar}' is not of type '${type}', got '${valueType}'`);
|
|
1831
|
+
}
|
|
1832
|
+
setAccuType(type) {
|
|
1833
|
+
return this.accuType = type, this;
|
|
1834
|
+
}
|
|
1835
|
+
setAccuValue(v) {
|
|
1836
|
+
return this.accuValue = v, this;
|
|
1837
|
+
}
|
|
1838
|
+
getValue(key) {
|
|
1839
|
+
return this.iterVar === key ? this.iterValue : this.#parent.getValue(key);
|
|
1840
|
+
}
|
|
1841
|
+
getCheckedValue(ev, ast) {
|
|
1842
|
+
if (this.iterVar === ast.args) return this.iterValue;
|
|
1843
|
+
return this.#parent.getCheckedValue(ev, ast);
|
|
1844
|
+
}
|
|
1845
|
+
getVariable(name) {
|
|
1846
|
+
if (this.iterVar === name) return new VariableDeclaration(name, this.iterType);
|
|
1847
|
+
return this.#parent.getVariable(name);
|
|
1848
|
+
}
|
|
1849
|
+
};
|
|
1850
|
+
function protobufjsFieldToCelType(field) {
|
|
1851
|
+
let fieldType;
|
|
1852
|
+
if (field.map) fieldType = `map<${protobufjsTypeToCelType(field.keyType, field.resolvedKeyType)}, ${protobufjsTypeToCelType(field.type, field.resolvedType)}>`;
|
|
1853
|
+
else fieldType = protobufjsTypeToCelType(field.type, field.resolvedType);
|
|
1854
|
+
return { type: field.repeated ? `list<${fieldType}>` : fieldType };
|
|
1855
|
+
}
|
|
1856
|
+
function protobufjsTypeToCelType(protoType, resolvedType) {
|
|
1857
|
+
switch (protoType) {
|
|
1858
|
+
case "string": return "string";
|
|
1859
|
+
case "bytes": return "bytes";
|
|
1860
|
+
case "bool": return "bool";
|
|
1861
|
+
case "double":
|
|
1862
|
+
case "float":
|
|
1863
|
+
case "int32":
|
|
1864
|
+
case "int64":
|
|
1865
|
+
case "sint32":
|
|
1866
|
+
case "sint64":
|
|
1867
|
+
case "sfixed32":
|
|
1868
|
+
case "sfixed64":
|
|
1869
|
+
case "uint32":
|
|
1870
|
+
case "uint64":
|
|
1871
|
+
case "fixed32":
|
|
1872
|
+
case "fixed64": return "double";
|
|
1873
|
+
default:
|
|
1874
|
+
switch (resolvedType?.constructor.name) {
|
|
1875
|
+
case "Type": return resolvedType.fullName.slice(1);
|
|
1876
|
+
case "Enum": return "int";
|
|
1877
|
+
}
|
|
1878
|
+
if (protoType?.includes(".")) return protoType;
|
|
1879
|
+
return "dyn";
|
|
1880
|
+
}
|
|
1881
|
+
}
|
|
1882
|
+
const dynType = celTypes.dyn;
|
|
1883
|
+
var Base = class {
|
|
1884
|
+
dynType = celTypes.dyn;
|
|
1885
|
+
optionalType = celTypes.optional;
|
|
1886
|
+
stringType = celTypes.string;
|
|
1887
|
+
intType = celTypes.int;
|
|
1888
|
+
doubleType = celTypes.double;
|
|
1889
|
+
boolType = celTypes.bool;
|
|
1890
|
+
nullType = celTypes.null;
|
|
1891
|
+
listType = celTypes.list;
|
|
1892
|
+
mapType = celTypes.map;
|
|
1893
|
+
constructor(opts) {
|
|
1894
|
+
this.opts = opts.opts;
|
|
1895
|
+
this.registry = opts.registry;
|
|
1896
|
+
this.objectTypes = this.registry.objectTypes;
|
|
1897
|
+
this.objectTypesByConstructor = this.registry.objectTypesByConstructor;
|
|
1898
|
+
}
|
|
1899
|
+
getType(typeName) {
|
|
1900
|
+
return this.registry.getType(typeName);
|
|
1901
|
+
}
|
|
1902
|
+
debugType(v) {
|
|
1903
|
+
switch (typeof v) {
|
|
1904
|
+
case "string": return this.stringType;
|
|
1905
|
+
case "bigint": return this.intType;
|
|
1906
|
+
case "number": return this.doubleType;
|
|
1907
|
+
case "boolean": return this.boolType;
|
|
1908
|
+
case "object":
|
|
1909
|
+
if (v === null) return this.nullType;
|
|
1910
|
+
switch (v.constructor) {
|
|
1911
|
+
case void 0:
|
|
1912
|
+
case Object:
|
|
1913
|
+
case Map: return this.mapType;
|
|
1914
|
+
case Array:
|
|
1915
|
+
case Set: return this.listType;
|
|
1916
|
+
default: return this.objectTypesByConstructor.get(v.constructor)?.type || unsupportedType(this, v.constructor?.name || typeof v);
|
|
1917
|
+
}
|
|
1918
|
+
default: unsupportedType(this, typeof v);
|
|
1919
|
+
}
|
|
1920
|
+
}
|
|
1921
|
+
};
|
|
1922
|
+
function unsupportedType(self, type) {
|
|
1923
|
+
throw self.createError("unsupported_type", `Unsupported type: ${type}`);
|
|
1924
|
+
}
|
|
1925
|
+
const maybeAsyncArray = (a) => Array.isArray(a) ? a.some((n) => n.maybeAsync) : false;
|
|
1926
|
+
function maybeAsync(l, r, h) {
|
|
1927
|
+
if (r === true || r && (r?.maybeAsync || maybeAsyncArray(r))) return maybeAsyncBoth(h);
|
|
1928
|
+
if (l === true || l && (l?.maybeAsync || maybeAsyncArray(l))) return maybeAsyncFirst(h);
|
|
1929
|
+
return h;
|
|
1930
|
+
}
|
|
1931
|
+
function maybeAsyncBoth(handler) {
|
|
1932
|
+
return handler.__asyncBoth ??= function handle(a, b, c, d) {
|
|
1933
|
+
if (!(a instanceof Promise || b instanceof Promise)) return handler(a, b, c, d);
|
|
1934
|
+
if (!(b instanceof Promise)) return a.then((_a) => handler(_a, b, c, d));
|
|
1935
|
+
if (!(a instanceof Promise)) return b.then((_b) => handler(a, _b, c, d));
|
|
1936
|
+
return Promise.all([a, b]).then((p) => handler(p[0], p[1], c, d));
|
|
1937
|
+
};
|
|
1938
|
+
}
|
|
1939
|
+
function maybeAsyncFirst(handler) {
|
|
1940
|
+
return handler.__asyncFirst ??= function handle(a, b, c, d) {
|
|
1941
|
+
if (a instanceof Promise) return a.then((_a) => handler(_a, b, c, d));
|
|
1942
|
+
return handler(a, b, c, d);
|
|
1943
|
+
};
|
|
1944
|
+
}
|
|
1945
|
+
function checkAccessNode(chk, ast, ctx) {
|
|
1946
|
+
ast.right = ast.args[1];
|
|
1947
|
+
const leftType = chk.check(ast.left = ast.args[0], ctx);
|
|
1948
|
+
if (ast.op === "[]") chk.check(ast.right, ctx);
|
|
1949
|
+
ast.handle = maybeAsync(ast.left, ast.op === "[]" ? ast.right : false, leftType !== dynType ? fieldAccessStatic : fieldAccess);
|
|
1950
|
+
if (leftType.kind !== "optional") return chk.checkAccessOnType(ast, ctx, leftType);
|
|
1951
|
+
return chk.registry.getOptionalType(chk.checkAccessOnType(ast, ctx, leftType.valueType, true));
|
|
1952
|
+
}
|
|
1953
|
+
function checkOptionalAccessNode(chk, ast, ctx) {
|
|
1954
|
+
ast.right = ast.args[1];
|
|
1955
|
+
const leftType = chk.check(ast.left = ast.args[0], ctx);
|
|
1956
|
+
if (ast.op === "[?]") chk.check(ast.right, ctx);
|
|
1957
|
+
ast.handle = maybeAsync(ast.left, ast.op === "[?]" ? ast.right : false, oFieldAccess);
|
|
1958
|
+
const actualType = leftType.kind === "optional" ? leftType.valueType : leftType;
|
|
1959
|
+
return chk.registry.getOptionalType(chk.checkAccessOnType(ast, ctx, actualType, true));
|
|
1960
|
+
}
|
|
1961
|
+
const HOMOGENEOUS_PREFIX = {
|
|
1962
|
+
heterogeneous_list_element: "List elements must have the same type,",
|
|
1963
|
+
heterogeneous_map_key: "Map key uses wrong type,",
|
|
1964
|
+
heterogeneous_map_value: "Map value uses wrong type,"
|
|
1965
|
+
};
|
|
1966
|
+
function checkElementHomogenous(chk, ctx, expected, el, code) {
|
|
1967
|
+
const type = chk.check(el, ctx);
|
|
1968
|
+
if (type === expected || expected.isEmpty()) return type;
|
|
1969
|
+
if (type.isEmpty()) return expected;
|
|
1970
|
+
throw chk.createError(code, `${HOMOGENEOUS_PREFIX[code]} expected type '${chk.formatType(expected)}' but found '${chk.formatType(type)}'`, el);
|
|
1971
|
+
}
|
|
1972
|
+
function checkElement(chk, ctx, expected, el) {
|
|
1973
|
+
return expected.unify(chk.registry, chk.check(el, ctx)) || dynType;
|
|
1974
|
+
}
|
|
1975
|
+
function ternaryConditionError(ev, value, node) {
|
|
1976
|
+
const type = ev.debugRuntimeType(value);
|
|
1977
|
+
return ev.createError("invalid_condition_type", `${node.meta.label || "Ternary condition must be bool"}, got '${type}'`, node);
|
|
1978
|
+
}
|
|
1979
|
+
function handleTernary(c, ev, ast, ctx) {
|
|
1980
|
+
if (c === true) return ev.run(ast.left, ctx);
|
|
1981
|
+
if (c === false) return ev.run(ast.right, ctx);
|
|
1982
|
+
throw ternaryConditionError(ev, c, ast.condition);
|
|
1983
|
+
}
|
|
1984
|
+
function logicalOperandError(ev, value, node) {
|
|
1985
|
+
const type = ev.debugRuntimeType(value);
|
|
1986
|
+
return ev.createError("invalid_logical_operand", `Logical operator requires bool operands, got '${type}'`, node);
|
|
1987
|
+
}
|
|
1988
|
+
function logicalValueOrErr(ev, v, node) {
|
|
1989
|
+
if (v instanceof Error) return v;
|
|
1990
|
+
return logicalOperandError(ev, v, node);
|
|
1991
|
+
}
|
|
1992
|
+
function _logicalOp(exp, ev, ast, left, right) {
|
|
1993
|
+
if (right === exp) return exp;
|
|
1994
|
+
if (right === !exp) {
|
|
1995
|
+
if (left === right) return right;
|
|
1996
|
+
throw logicalValueOrErr(ev, left, ast.left);
|
|
1997
|
+
}
|
|
1998
|
+
if (right instanceof Promise) return right.then((r) => _logicalOpAsync(exp, ev, ast, left, r));
|
|
1999
|
+
throw logicalOperandError(ev, right, ast.left);
|
|
2000
|
+
}
|
|
2001
|
+
function _logicalOpAsync(exp, ev, ast, left, right) {
|
|
2002
|
+
if (right === exp) return exp;
|
|
2003
|
+
if (typeof right !== "boolean") throw logicalOperandError(ev, right, ast.right);
|
|
2004
|
+
if (typeof left !== "boolean") throw logicalValueOrErr(ev, left, ast.left);
|
|
2005
|
+
return !exp;
|
|
2006
|
+
}
|
|
2007
|
+
function checkLogicalOp(chk, ast, ctx) {
|
|
2008
|
+
const leftType = chk.check(ast.left = ast.args[0], ctx);
|
|
2009
|
+
const rightType = chk.check(ast.right = ast.args[1], ctx);
|
|
2010
|
+
if (!leftType.isDynOrBool()) throw chk.createError("invalid_logical_operand", `Logical operator requires bool operands, got '${chk.formatType(leftType)}'`, ast);
|
|
2011
|
+
if (!rightType.isDynOrBool()) throw chk.createError("invalid_logical_operand", `Logical operator requires bool operands, got '${chk.formatType(rightType)}'`, ast);
|
|
2012
|
+
return chk.boolType;
|
|
2013
|
+
}
|
|
2014
|
+
function checkUnary(chk, ast, ctx) {
|
|
2015
|
+
const op = ast.op;
|
|
2016
|
+
const right = chk.check(ast.args, ctx);
|
|
2017
|
+
ast.candidates = chk.registry.operatorCandidates(op);
|
|
2018
|
+
if (right.kind === "dyn") {
|
|
2019
|
+
ast.handle = maybeAsync(ast.args, false, handleUnary);
|
|
2020
|
+
return ast.candidates.returnType;
|
|
2021
|
+
}
|
|
2022
|
+
const overload = ast.candidates.findUnaryOverload(right);
|
|
2023
|
+
if (!overload) throw chk.createError("no_such_overload", `no such overload: ${op[0]}${chk.formatType(right)}`, ast);
|
|
2024
|
+
ast.handle = maybeAsync(ast.args, false, overload.handler);
|
|
2025
|
+
return overload.returnType;
|
|
2026
|
+
}
|
|
2027
|
+
function handleUnary(left, ast, ev) {
|
|
2028
|
+
const leftType = ev.debugRuntimeType(left, ast.args.checkedType);
|
|
2029
|
+
const overload = ast.candidates.findUnaryOverload(leftType);
|
|
2030
|
+
if (overload) return overload.handler(left);
|
|
2031
|
+
throw ev.createError("no_such_overload", `no such overload: ${ast.op[0]}${leftType}`, ast);
|
|
2032
|
+
}
|
|
2033
|
+
function evaluateUnary(ev, ast, ctx) {
|
|
2034
|
+
return ast.handle(ev.run(ast.args, ctx), ast, ev);
|
|
2035
|
+
}
|
|
2036
|
+
function checkBinary(chk, ast, ctx) {
|
|
2037
|
+
const op = ast.op;
|
|
2038
|
+
const left = chk.check(ast.left = ast.args[0], ctx);
|
|
2039
|
+
const right = chk.check(ast.right = ast.args[1], ctx);
|
|
2040
|
+
ast.candidates = chk.registry.operatorCandidates(op);
|
|
2041
|
+
const overload = left.hasDynType || right.hasDynType ? void 0 : ast.candidates.findBinaryOverload(left, right);
|
|
2042
|
+
ast.handle = maybeAsync(ast.left, ast.right, overload?.handler || handleBinary);
|
|
2043
|
+
if (overload) return overload.returnType;
|
|
2044
|
+
const type = ast.candidates.checkBinaryOverload(left, right);
|
|
2045
|
+
if (!left.hasDynType) ast.leftStaticType = left;
|
|
2046
|
+
if (!right.hasDynType) ast.rightStaticType = right;
|
|
2047
|
+
if (type) return type;
|
|
2048
|
+
throw chk.createError("no_such_overload", `no such overload: ${chk.formatType(left)} ${op} ${chk.formatType(right)}`, ast);
|
|
2049
|
+
}
|
|
2050
|
+
function evaluateBinary(ev, ast, ctx) {
|
|
2051
|
+
return ast.handle(ev.run(ast.left, ctx), ev.run(ast.right, ctx), ast, ev);
|
|
2052
|
+
}
|
|
2053
|
+
function evaluateBinaryFirst(ev, ast, ctx) {
|
|
2054
|
+
return ast.handle(ev.run(ast.left, ctx), ast.right, ast, ev);
|
|
2055
|
+
}
|
|
2056
|
+
function handleBinary(left, right, ast, ev) {
|
|
2057
|
+
const leftType = ast.leftStaticType || ev.debugTypeDeep(left).wrappedType;
|
|
2058
|
+
const rightType = ast.rightStaticType || ev.debugTypeDeep(right).wrappedType;
|
|
2059
|
+
const overload = ast.candidates.findBinaryOverload(leftType, rightType);
|
|
2060
|
+
if (overload) return overload.handler(left, right, ast, ev);
|
|
2061
|
+
throw ev.createError("no_such_overload", `no such overload: ${leftType} ${ast.op} ${rightType}`, ast);
|
|
2062
|
+
}
|
|
2063
|
+
function callFunctionHandler(handler, ev, args, ast) {
|
|
2064
|
+
try {
|
|
2065
|
+
const result = handler.apply(ev, args);
|
|
2066
|
+
if (result instanceof Promise) return result.catch((error) => {
|
|
2067
|
+
throw attachErrorAst(error, ast);
|
|
2068
|
+
});
|
|
2069
|
+
return result;
|
|
2070
|
+
} catch (error) {
|
|
2071
|
+
throw attachErrorAst(error, ast);
|
|
2072
|
+
}
|
|
2073
|
+
}
|
|
2074
|
+
function callFn(args, ast, ev) {
|
|
2075
|
+
const argAst = ast.args[1];
|
|
2076
|
+
const types = ast.argTypes;
|
|
2077
|
+
let i = argAst.length;
|
|
2078
|
+
while (i--) types[i] = ev.debugRuntimeType(args[i], argAst[i].checkedType);
|
|
2079
|
+
const decl = ast.candidates.findFunction(types);
|
|
2080
|
+
if (decl) return callFunctionHandler(decl.handler, ev, args, ast);
|
|
2081
|
+
throw ev.createError("no_matching_overload", `found no matching overload for '${ast.args[0]}(${types.map((t) => t.unwrappedType).join(", ")})'`, ast);
|
|
2082
|
+
}
|
|
2083
|
+
function callRecFn(args, ev, ast) {
|
|
2084
|
+
const [, receiverAst, argAst] = ast.args;
|
|
2085
|
+
const types = ast.argTypes;
|
|
2086
|
+
for (let i = 0; i < types.length; i++) types[i] = ev.debugRuntimeType(args[i + 1], argAst[i].checkedType);
|
|
2087
|
+
const receiverType = ev.debugRuntimeType(args[0], receiverAst.checkedType);
|
|
2088
|
+
const decl = ast.candidates.findFunction(types, receiverType);
|
|
2089
|
+
if (decl) return callFunctionHandler(decl.handler, ev, args, ast);
|
|
2090
|
+
throw ev.createError("no_matching_overload", `found no matching overload for '${receiverType.type}.${ast.args[0]}(${types.map((t) => t.unwrappedType).join(", ")})'`, ast);
|
|
2091
|
+
}
|
|
2092
|
+
function resolveAstArray(ev, astArray, ctx, i = astArray.length) {
|
|
2093
|
+
if (i === 0) return [];
|
|
2094
|
+
let async;
|
|
2095
|
+
const results = new Array(i);
|
|
2096
|
+
while (i--) if ((results[i] = ev.run(astArray[i], ctx)) instanceof Promise) async ??= true;
|
|
2097
|
+
return async ? Promise.all(results) : results;
|
|
2098
|
+
}
|
|
2099
|
+
function safeFromEntries(entries) {
|
|
2100
|
+
const obj = {};
|
|
2101
|
+
for (let i = 0; i < entries.length; i++) {
|
|
2102
|
+
const [k, v] = entries[i];
|
|
2103
|
+
if (k === "__proto__" || k === "constructor" || k === "prototype") continue;
|
|
2104
|
+
obj[k] = v;
|
|
2105
|
+
}
|
|
2106
|
+
return obj;
|
|
2107
|
+
}
|
|
2108
|
+
function comprehensionElementType(chk, iterable, ctx) {
|
|
2109
|
+
const iterType = chk.check(iterable, ctx);
|
|
2110
|
+
if (iterType.kind === "dyn") return iterType;
|
|
2111
|
+
if (iterType.kind === "list") return iterType.valueType;
|
|
2112
|
+
if (iterType.kind === "map") return iterType.keyType;
|
|
2113
|
+
throw chk.createError("invalid_comprehension_range", `Expression of type '${chk.formatType(iterType)}' cannot be range of a comprehension (must be list, map, or dynamic).`, iterable);
|
|
2114
|
+
}
|
|
2115
|
+
function toIterable(ev, args, coll) {
|
|
2116
|
+
if (coll instanceof Set) return [...coll];
|
|
2117
|
+
if (coll instanceof Map) return [...coll.keys()];
|
|
2118
|
+
if (coll && typeof coll === "object") return objKeys(coll);
|
|
2119
|
+
throw ev.createError("invalid_comprehension_range", `Expression of type '${ev.debugType(coll)}' cannot be range of a comprehension (must be list, map, or dynamic).`, args.iterable);
|
|
2120
|
+
}
|
|
2121
|
+
function runQualifier(items, args, ev, ctx) {
|
|
2122
|
+
if (!isArray(items)) items = toIterable(ev, args, items);
|
|
2123
|
+
const accu = ev.run(args.init, ctx = args.iterCtx.reuse(ctx));
|
|
2124
|
+
ctx.accuValue = accu;
|
|
2125
|
+
if (ctx === args.iterCtx) return iterateQuantifier(ev, ctx, args, items, accu, 0);
|
|
2126
|
+
return continueQuantifier(ev, ctx, args, items, accu, 0);
|
|
2127
|
+
}
|
|
2128
|
+
function runComprehension(items, args, ev, ctx) {
|
|
2129
|
+
if (!isArray(items)) items = toIterable(ev, args, items);
|
|
2130
|
+
const accu = ev.run(args.init, ctx = args.iterCtx.reuse(ctx));
|
|
2131
|
+
ctx.accuValue = accu;
|
|
2132
|
+
if (ctx === args.iterCtx) return iterateLoop(ev, ctx, args, items, accu, 0);
|
|
2133
|
+
return continueLoop(ev, ctx, args, items, accu, 0);
|
|
2134
|
+
}
|
|
2135
|
+
function iterateLoop(ev, ctx, args, items, accu, i) {
|
|
2136
|
+
const condition = args.condition;
|
|
2137
|
+
const step = args.step;
|
|
2138
|
+
const len = items.length;
|
|
2139
|
+
while (i < len) {
|
|
2140
|
+
if (condition && !condition(accu)) break;
|
|
2141
|
+
accu = ev.run(step, ctx.setIterValue(items[i++], ev));
|
|
2142
|
+
if (accu instanceof Promise) return continueLoop(ev, ctx, args, items, accu, i);
|
|
2143
|
+
}
|
|
2144
|
+
return args.result(accu);
|
|
2145
|
+
}
|
|
2146
|
+
async function continueLoop(ev, ctx, args, items, accu, i) {
|
|
2147
|
+
if (ctx === args.iterCtx) ctx.async = true;
|
|
2148
|
+
const condition = args.condition;
|
|
2149
|
+
const step = args.step;
|
|
2150
|
+
const len = items.length;
|
|
2151
|
+
accu = await accu;
|
|
2152
|
+
while (i < len) {
|
|
2153
|
+
if (condition && !condition(accu)) return args.result(accu);
|
|
2154
|
+
accu = ev.run(step, ctx.setIterValue(items[i++], ev));
|
|
2155
|
+
if (accu instanceof Promise) accu = await accu;
|
|
2156
|
+
}
|
|
2157
|
+
return args.result(accu);
|
|
2158
|
+
}
|
|
2159
|
+
function iterateQuantifier(ev, ctx, args, items, accu, i, error, stp) {
|
|
2160
|
+
const condition = args.condition;
|
|
2161
|
+
const step = args.step;
|
|
2162
|
+
const len = items.length;
|
|
2163
|
+
while (i < len) {
|
|
2164
|
+
if (!condition(accu)) return args.result(accu);
|
|
2165
|
+
stp = ev.tryEval(step, ctx.setIterValue(items[i++], ev));
|
|
2166
|
+
if (stp instanceof Promise) return continueQuantifier(ev, ctx, args, items, accu, i, error, stp);
|
|
2167
|
+
if (stp instanceof Error && (error ??= stp)) continue;
|
|
2168
|
+
accu = stp;
|
|
2169
|
+
}
|
|
2170
|
+
if (error && condition(accu)) throw error;
|
|
2171
|
+
return args.result(accu);
|
|
2172
|
+
}
|
|
2173
|
+
async function continueQuantifier(ev, ctx, args, items, accu, i, error, stp) {
|
|
2174
|
+
if (ctx === args.iterCtx) ctx.async = true;
|
|
2175
|
+
const condition = args.condition;
|
|
2176
|
+
const step = args.step;
|
|
2177
|
+
const len = items.length;
|
|
2178
|
+
stp = await stp;
|
|
2179
|
+
if (stp instanceof Error) error ??= stp;
|
|
2180
|
+
else accu = stp;
|
|
2181
|
+
while (i < len) {
|
|
2182
|
+
if (!condition(accu)) return args.result(accu);
|
|
2183
|
+
stp = ev.tryEval(step, ctx.setIterValue(items[i++], ev));
|
|
2184
|
+
if (stp instanceof Promise) stp = await stp;
|
|
2185
|
+
if (stp instanceof Error && (error ??= stp)) continue;
|
|
2186
|
+
accu = stp;
|
|
2187
|
+
}
|
|
2188
|
+
if (error && condition(accu)) throw error;
|
|
2189
|
+
return args.result(accu);
|
|
2190
|
+
}
|
|
2191
|
+
function oFieldAccess(left, right, ast, ev) {
|
|
2192
|
+
return ev.optionalType.field(left, right, ast, ev);
|
|
2193
|
+
}
|
|
2194
|
+
function fieldAccessStatic(left, right, ast, ev) {
|
|
2195
|
+
return ast.left.checkedType.field(left, right, ast, ev);
|
|
2196
|
+
}
|
|
2197
|
+
const empty = Object.create(null);
|
|
2198
|
+
function fieldAccess(left, right, ast, ev) {
|
|
2199
|
+
switch (left?.constructor) {
|
|
2200
|
+
case void 0:
|
|
2201
|
+
case Object: {
|
|
2202
|
+
const v = hasOwn(left || empty, right) ? left[right] : void 0;
|
|
2203
|
+
if (v !== void 0) return ev.debugType(v), v;
|
|
2204
|
+
break;
|
|
2205
|
+
}
|
|
2206
|
+
case Map: {
|
|
2207
|
+
const v = left.get(right);
|
|
2208
|
+
if (v !== void 0) return ev.debugType(v), v;
|
|
2209
|
+
break;
|
|
2210
|
+
}
|
|
2211
|
+
case Array:
|
|
2212
|
+
case Set: return ev.listType.field(left, right, ast, ev);
|
|
2213
|
+
default:
|
|
2214
|
+
const t = ev.objectTypesByConstructor.get(left.constructor);
|
|
2215
|
+
if (t) return t.type.field(left, right, ast, ev);
|
|
2216
|
+
else if (typeof left === "object") unsupportedType(ev, left.constructor.name);
|
|
2217
|
+
}
|
|
2218
|
+
throw ev.createError("no_such_key", `No such key: ${right}`, ast);
|
|
2219
|
+
}
|
|
2220
|
+
const emptyList = () => [];
|
|
2221
|
+
const emptyMap = () => ({});
|
|
2222
|
+
const OPERATORS = {
|
|
2223
|
+
value: {
|
|
2224
|
+
check(chk, ast) {
|
|
2225
|
+
return chk.debugType(ast.args);
|
|
2226
|
+
},
|
|
2227
|
+
evaluate(_ev, ast) {
|
|
2228
|
+
return ast.args;
|
|
2229
|
+
}
|
|
2230
|
+
},
|
|
2231
|
+
id: {
|
|
2232
|
+
check(chk, ast, ctx) {
|
|
2233
|
+
const variable = ctx.getVariable(ast.args);
|
|
2234
|
+
if (!variable) throw chk.createError("unknown_variable", `Unknown variable: ${ast.args}`, ast);
|
|
2235
|
+
if (variable.constant) {
|
|
2236
|
+
const alternate = ast.clone(OPERATORS.value, variable.value);
|
|
2237
|
+
ast.setMeta("alternate", alternate);
|
|
2238
|
+
return chk.check(alternate, ctx);
|
|
2239
|
+
}
|
|
2240
|
+
return variable.type;
|
|
2241
|
+
},
|
|
2242
|
+
evaluate(ev, ast, ctx) {
|
|
2243
|
+
return ctx.getCheckedValue(ev, ast);
|
|
2244
|
+
}
|
|
2245
|
+
},
|
|
2246
|
+
".": {
|
|
2247
|
+
alias: "fieldAccess",
|
|
2248
|
+
check: checkAccessNode,
|
|
2249
|
+
evaluate: evaluateBinaryFirst
|
|
2250
|
+
},
|
|
2251
|
+
".?": {
|
|
2252
|
+
alias: "optionalFieldAccess",
|
|
2253
|
+
check: checkOptionalAccessNode,
|
|
2254
|
+
evaluate: evaluateBinaryFirst
|
|
2255
|
+
},
|
|
2256
|
+
"[]": {
|
|
2257
|
+
alias: "bracketAccess",
|
|
2258
|
+
check: checkAccessNode,
|
|
2259
|
+
evaluate: evaluateBinary
|
|
2260
|
+
},
|
|
2261
|
+
"[?]": {
|
|
2262
|
+
alias: "optionalBracketAccess",
|
|
2263
|
+
check: checkOptionalAccessNode,
|
|
2264
|
+
evaluate: evaluateBinary
|
|
2265
|
+
},
|
|
2266
|
+
call: {
|
|
2267
|
+
check(chk, ast, ctx) {
|
|
2268
|
+
const [functionName, args] = ast.args;
|
|
2269
|
+
const candidates = ast.candidates = chk.registry.functionCandidates(false, functionName, args.length);
|
|
2270
|
+
const argTypes = ast.argTypes = args.map((a) => chk.check(a, ctx));
|
|
2271
|
+
const decl = candidates.findFunction(argTypes);
|
|
2272
|
+
if (!decl) throw chk.createError("no_matching_overload", `found no matching overload for '${functionName}(${chk.formatTypeList(argTypes)})'`, ast);
|
|
2273
|
+
ast.handle = maybeAsync(args, false, argTypes.some((t) => t.hasDynType) ? callFn : decl.handler.__handle ??= (l, _ast, e) => callFunctionHandler(decl.handler, e, l, _ast));
|
|
2274
|
+
return decl.returnType;
|
|
2275
|
+
},
|
|
2276
|
+
evaluate(ev, ast, ctx) {
|
|
2277
|
+
return ast.handle(resolveAstArray(ev, ast.args[1], ctx), ast, ev);
|
|
2278
|
+
}
|
|
2279
|
+
},
|
|
2280
|
+
rcall: {
|
|
2281
|
+
check(chk, ast, ctx) {
|
|
2282
|
+
const [methodName, receiver, args] = ast.args;
|
|
2283
|
+
const receiverType = chk.check(receiver, ctx);
|
|
2284
|
+
const candidates = ast.candidates = chk.registry.functionCandidates(true, methodName, args.length);
|
|
2285
|
+
const argTypes = ast.argTypes = args.map((a) => chk.check(a, ctx));
|
|
2286
|
+
ast.receiverWithArgs = [receiver, ...args];
|
|
2287
|
+
ast.handle = maybeAsync(ast.receiverWithArgs, false, callRecFn);
|
|
2288
|
+
if (receiverType.kind === "dyn" && candidates.returnType) return candidates.returnType;
|
|
2289
|
+
const decl = candidates.findFunction(argTypes, receiverType);
|
|
2290
|
+
if (!decl) throw chk.createError("no_matching_overload", `found no matching overload for '${receiverType.type}.${methodName}(${chk.formatTypeList(argTypes)})'`, ast);
|
|
2291
|
+
if (!receiverType.hasPlaceholderType && !argTypes.some((t) => t.hasDynType)) {
|
|
2292
|
+
const fn = decl.handler;
|
|
2293
|
+
const handle = fn.__handle ??= (a, ev, _ast) => callFunctionHandler(fn, ev, a, _ast);
|
|
2294
|
+
ast.handle = maybeAsync(ast.receiverWithArgs, false, handle);
|
|
2295
|
+
}
|
|
2296
|
+
return decl.returnType;
|
|
2297
|
+
},
|
|
2298
|
+
evaluate(ev, ast, ctx) {
|
|
2299
|
+
return ast.handle(resolveAstArray(ev, ast.receiverWithArgs, ctx), ev, ast);
|
|
2300
|
+
}
|
|
2301
|
+
},
|
|
2302
|
+
list: {
|
|
2303
|
+
check(chk, ast, ctx) {
|
|
2304
|
+
const arr = ast.args;
|
|
2305
|
+
const arrLen = arr.length;
|
|
2306
|
+
if (arrLen === 0) return ast.setMeta("evaluate", emptyList) && chk.getType("list<T>");
|
|
2307
|
+
let valueType = chk.check(arr[0], ctx);
|
|
2308
|
+
const check = chk.opts.homogeneousAggregateLiterals ? checkElementHomogenous : checkElement;
|
|
2309
|
+
for (let i = 1; i < arrLen; i++) valueType = check(chk, ctx, valueType, arr[i], "heterogeneous_list_element");
|
|
2310
|
+
return chk.registry.getListType(valueType);
|
|
2311
|
+
},
|
|
2312
|
+
evaluate(ev, ast, ctx) {
|
|
2313
|
+
return resolveAstArray(ev, ast.args, ctx);
|
|
2314
|
+
}
|
|
2315
|
+
},
|
|
2316
|
+
map: {
|
|
2317
|
+
check(chk, ast, ctx) {
|
|
2318
|
+
const arr = ast.args;
|
|
2319
|
+
const arrLen = arr.length;
|
|
2320
|
+
if (arrLen === 0) return ast.setMeta("evaluate", emptyMap) && chk.getType("map<K, V>");
|
|
2321
|
+
const check = chk.opts.homogeneousAggregateLiterals ? checkElementHomogenous : checkElement;
|
|
2322
|
+
let keyType = chk.check(arr[0][0], ctx);
|
|
2323
|
+
let valueType = chk.check(arr[0][1], ctx);
|
|
2324
|
+
for (let i = 1; i < arrLen; i++) {
|
|
2325
|
+
const e = arr[i];
|
|
2326
|
+
keyType = check(chk, ctx, keyType, e[0], "heterogeneous_map_key");
|
|
2327
|
+
valueType = check(chk, ctx, valueType, e[1], "heterogeneous_map_value");
|
|
2328
|
+
}
|
|
2329
|
+
return chk.registry.getMapType(keyType, valueType);
|
|
2330
|
+
},
|
|
2331
|
+
evaluate(ev, ast, ctx) {
|
|
2332
|
+
const astEntries = ast.args;
|
|
2333
|
+
const len = astEntries.length;
|
|
2334
|
+
const results = new Array(len);
|
|
2335
|
+
let async;
|
|
2336
|
+
for (let i = 0; i < len; i++) {
|
|
2337
|
+
const e = astEntries[i];
|
|
2338
|
+
const k = ev.run(e[0], ctx);
|
|
2339
|
+
const v = ev.run(e[1], ctx);
|
|
2340
|
+
if (k instanceof Promise || v instanceof Promise) {
|
|
2341
|
+
results[i] = Promise.all([k, v]);
|
|
2342
|
+
async ??= true;
|
|
2343
|
+
} else results[i] = [k, v];
|
|
2344
|
+
}
|
|
2345
|
+
if (async) return Promise.all(results).then(safeFromEntries);
|
|
2346
|
+
return safeFromEntries(results);
|
|
2347
|
+
}
|
|
2348
|
+
},
|
|
2349
|
+
comprehension: {
|
|
2350
|
+
check(chk, ast, ctx) {
|
|
2351
|
+
const args = ast.args;
|
|
2352
|
+
args.iterCtx = ctx.forkWithVariable(args.iterVarName, comprehensionElementType(chk, args.iterable, ctx)).setAccuType(chk.check(args.init, ctx));
|
|
2353
|
+
const stepType = chk.check(args.step, args.iterCtx);
|
|
2354
|
+
const handler = args.errorsAreFatal ? runComprehension : runQualifier;
|
|
2355
|
+
ast.handle = maybeAsync(args.iterable, false, handler);
|
|
2356
|
+
if (args.kind === "quantifier") return chk.boolType;
|
|
2357
|
+
return stepType;
|
|
2358
|
+
},
|
|
2359
|
+
evaluate(ev, ast, ctx) {
|
|
2360
|
+
return ast.handle(ev.run(ast.args.iterable, ctx), ast.args, ev, ctx);
|
|
2361
|
+
}
|
|
2362
|
+
},
|
|
2363
|
+
accuValue: {
|
|
2364
|
+
check(_chk, _ast, ctx) {
|
|
2365
|
+
return ctx.accuType;
|
|
2366
|
+
},
|
|
2367
|
+
evaluate(_ev, _ast, ctx) {
|
|
2368
|
+
return ctx.accuValue;
|
|
2369
|
+
}
|
|
2370
|
+
},
|
|
2371
|
+
accuInc: {
|
|
2372
|
+
check(_chk, _ast, ctx) {
|
|
2373
|
+
return ctx.accuType;
|
|
2374
|
+
},
|
|
2375
|
+
evaluate(_ev, _ast, ctx) {
|
|
2376
|
+
return ctx.accuValue += 1;
|
|
2377
|
+
}
|
|
2378
|
+
},
|
|
2379
|
+
accuPush: {
|
|
2380
|
+
check(chk, ast, ctx) {
|
|
2381
|
+
const listType = ctx.accuType;
|
|
2382
|
+
const itemType = chk.check(ast.args, ctx);
|
|
2383
|
+
if (!ast.args.maybeAsync) ast.setMeta("evaluate", OPERATORS.accuPush.evaluateSync);
|
|
2384
|
+
if (listType.kind === "list" && listType.valueType.kind !== "param") return listType;
|
|
2385
|
+
return chk.registry.getListType(itemType);
|
|
2386
|
+
},
|
|
2387
|
+
evaluateSync(ev, ast, ctx) {
|
|
2388
|
+
return ctx.accuValue.push(ev.run(ast.args, ctx)), ctx.accuValue;
|
|
2389
|
+
},
|
|
2390
|
+
evaluate(ev, ast, ctx) {
|
|
2391
|
+
const arr = ctx.accuValue;
|
|
2392
|
+
const el = ev.run(ast.args, ctx);
|
|
2393
|
+
if (el instanceof Promise) return el.then((_e) => arr.push(_e) && arr);
|
|
2394
|
+
arr.push(el);
|
|
2395
|
+
return arr;
|
|
2396
|
+
}
|
|
2397
|
+
},
|
|
2398
|
+
"?:": {
|
|
2399
|
+
alias: "ternary",
|
|
2400
|
+
check(chk, ast, ctx) {
|
|
2401
|
+
const condast = ast.condition = ast.args[0];
|
|
2402
|
+
const leftast = ast.left = ast.args[1];
|
|
2403
|
+
const rightast = ast.right = ast.args[2];
|
|
2404
|
+
const condType = chk.check(condast, ctx);
|
|
2405
|
+
if (!condType.isDynOrBool()) throw chk.createError("invalid_condition_type", `${condast.meta.label || "Ternary condition must be bool"}, got '${chk.formatType(condType)}'`, condast);
|
|
2406
|
+
const leftType = chk.check(leftast, ctx);
|
|
2407
|
+
const rightType = chk.check(rightast, ctx);
|
|
2408
|
+
const unified = leftType.unify(chk.registry, rightType);
|
|
2409
|
+
ast.handle = maybeAsync(condast, false, handleTernary);
|
|
2410
|
+
if (unified) return unified;
|
|
2411
|
+
throw chk.createError("incompatible_ternary_branches", `Ternary branches must have the same type, got '${chk.formatType(leftType)}' and '${chk.formatType(rightType)}'`, ast);
|
|
2412
|
+
},
|
|
2413
|
+
evaluate(ev, ast, ctx) {
|
|
2414
|
+
return ast.handle(ev.run(ast.condition, ctx), ev, ast, ctx);
|
|
2415
|
+
}
|
|
2416
|
+
},
|
|
2417
|
+
"||": {
|
|
2418
|
+
check: checkLogicalOp,
|
|
2419
|
+
evaluate(ev, ast, ctx) {
|
|
2420
|
+
const l = ev.tryEval(ast.left, ctx);
|
|
2421
|
+
if (l === true) return true;
|
|
2422
|
+
if (l === false) {
|
|
2423
|
+
const right = ev.run(ast.right, ctx);
|
|
2424
|
+
if (typeof right === "boolean") return right;
|
|
2425
|
+
return _logicalOp(true, ev, ast, l, right);
|
|
2426
|
+
}
|
|
2427
|
+
if (l instanceof Promise) return l.then((_l) => _l === true ? _l : _logicalOp(true, ev, ast, _l, ev.run(ast.right, ctx)));
|
|
2428
|
+
return _logicalOp(true, ev, ast, l, ev.run(ast.right, ctx));
|
|
2429
|
+
}
|
|
2430
|
+
},
|
|
2431
|
+
"&&": {
|
|
2432
|
+
check: checkLogicalOp,
|
|
2433
|
+
evaluate(ev, ast, ctx) {
|
|
2434
|
+
const l = ev.tryEval(ast.left, ctx);
|
|
2435
|
+
if (l === false) return false;
|
|
2436
|
+
if (l === true) {
|
|
2437
|
+
const right = ev.run(ast.right, ctx);
|
|
2438
|
+
if (typeof right === "boolean") return right;
|
|
2439
|
+
return _logicalOp(false, ev, ast, l, right);
|
|
2440
|
+
}
|
|
2441
|
+
if (l instanceof Promise) return l.then((_l) => _l === false ? _l : _logicalOp(false, ev, ast, _l, ev.run(ast.right, ctx)));
|
|
2442
|
+
return _logicalOp(false, ev, ast, l, ev.run(ast.right, ctx));
|
|
2443
|
+
}
|
|
2444
|
+
},
|
|
2445
|
+
"!_": {
|
|
2446
|
+
alias: "unaryNot",
|
|
2447
|
+
check: checkUnary,
|
|
2448
|
+
evaluate: evaluateUnary
|
|
2449
|
+
},
|
|
2450
|
+
"-_": {
|
|
2451
|
+
alias: "unaryMinus",
|
|
2452
|
+
check: checkUnary,
|
|
2453
|
+
evaluate: evaluateUnary
|
|
2454
|
+
}
|
|
2455
|
+
};
|
|
2456
|
+
for (const op of [
|
|
2457
|
+
"!=",
|
|
2458
|
+
"==",
|
|
2459
|
+
"in",
|
|
2460
|
+
"+",
|
|
2461
|
+
"-",
|
|
2462
|
+
"*",
|
|
2463
|
+
"/",
|
|
2464
|
+
"%",
|
|
2465
|
+
"<",
|
|
2466
|
+
"<=",
|
|
2467
|
+
">",
|
|
2468
|
+
">="
|
|
2469
|
+
]) OPERATORS[op] = {
|
|
2470
|
+
check: checkBinary,
|
|
2471
|
+
evaluate: evaluateBinary
|
|
2472
|
+
};
|
|
2473
|
+
for (const op of objKeys(OPERATORS)) {
|
|
2474
|
+
const obj = OPERATORS[op];
|
|
2475
|
+
obj.name = op;
|
|
2476
|
+
if (obj.alias) OPERATORS[obj.alias] = obj;
|
|
2477
|
+
}
|
|
2478
|
+
const identity = (x) => x;
|
|
2479
|
+
function assertIdentifier(node, message) {
|
|
2480
|
+
if (node.op === "id") return node.args;
|
|
2481
|
+
throw parseError("invalid_macro_argument", message, node);
|
|
2482
|
+
}
|
|
2483
|
+
function createMapExpander(hasFilter) {
|
|
2484
|
+
const functionDesc = hasFilter ? "map(var, filter, transform)" : "map(var, transform)";
|
|
2485
|
+
const invalidMsg = `${functionDesc} invalid predicate iteration variable`;
|
|
2486
|
+
const label = `${functionDesc} filter predicate must return bool`;
|
|
2487
|
+
return ({ args, receiver, ast: callAst }) => {
|
|
2488
|
+
const [iterVar, predicate, transform] = hasFilter ? args : [
|
|
2489
|
+
args[0],
|
|
2490
|
+
null,
|
|
2491
|
+
args[1]
|
|
2492
|
+
];
|
|
2493
|
+
let step = transform.clone(OPERATORS.accuPush, transform);
|
|
2494
|
+
if (predicate) {
|
|
2495
|
+
const accuValue = predicate.clone(OPERATORS.accuValue);
|
|
2496
|
+
step = predicate.clone(OPERATORS.ternary, [
|
|
2497
|
+
predicate.setMeta("label", label),
|
|
2498
|
+
step,
|
|
2499
|
+
accuValue
|
|
2500
|
+
]);
|
|
2501
|
+
}
|
|
2502
|
+
return { callAst: callAst.clone(OPERATORS.comprehension, {
|
|
2503
|
+
errorsAreFatal: true,
|
|
2504
|
+
iterable: receiver,
|
|
2505
|
+
iterVarName: assertIdentifier(iterVar, invalidMsg),
|
|
2506
|
+
init: callAst.clone(OPERATORS.list, []),
|
|
2507
|
+
step,
|
|
2508
|
+
result: identity
|
|
2509
|
+
}) };
|
|
2510
|
+
};
|
|
2511
|
+
}
|
|
2512
|
+
function createFilterExpander() {
|
|
2513
|
+
const functionDesc = "filter(var, predicate)";
|
|
2514
|
+
const invalidMsg = `${functionDesc} invalid predicate iteration variable`;
|
|
2515
|
+
const label = `${functionDesc} predicate must return bool`;
|
|
2516
|
+
return ({ args, receiver, ast: callAst }) => {
|
|
2517
|
+
const iterVarName = assertIdentifier(args[0], invalidMsg);
|
|
2518
|
+
const accuValue = callAst.clone(OPERATORS.accuValue);
|
|
2519
|
+
const predicate = args[1].setMeta("label", label);
|
|
2520
|
+
const appendItem = callAst.clone(OPERATORS.accuPush, callAst.clone(OPERATORS.id, iterVarName));
|
|
2521
|
+
const step = predicate.clone(OPERATORS.ternary, [
|
|
2522
|
+
predicate,
|
|
2523
|
+
appendItem,
|
|
2524
|
+
accuValue
|
|
2525
|
+
]);
|
|
2526
|
+
return { callAst: callAst.clone(OPERATORS.comprehension, {
|
|
2527
|
+
errorsAreFatal: true,
|
|
2528
|
+
iterable: receiver,
|
|
2529
|
+
iterVarName,
|
|
2530
|
+
init: callAst.clone(OPERATORS.list, []),
|
|
2531
|
+
step,
|
|
2532
|
+
result: identity
|
|
2533
|
+
}) };
|
|
2534
|
+
};
|
|
2535
|
+
}
|
|
2536
|
+
function createQuantifierExpander(opts) {
|
|
2537
|
+
const invalidMsg = `${opts.name}(var, predicate) invalid predicate iteration variable`;
|
|
2538
|
+
const label = `${opts.name}(var, predicate) predicate must return bool`;
|
|
2539
|
+
return ({ args, receiver, ast: callAst }) => {
|
|
2540
|
+
const predicate = args[1].setMeta("label", label);
|
|
2541
|
+
const transform = opts.transform({
|
|
2542
|
+
args,
|
|
2543
|
+
ast: callAst,
|
|
2544
|
+
predicate,
|
|
2545
|
+
opts
|
|
2546
|
+
});
|
|
2547
|
+
return { callAst: callAst.clone(OPERATORS.comprehension, {
|
|
2548
|
+
kind: "quantifier",
|
|
2549
|
+
errorsAreFatal: opts.errorsAreFatal || false,
|
|
2550
|
+
iterable: receiver,
|
|
2551
|
+
iterVarName: assertIdentifier(args[0], invalidMsg),
|
|
2552
|
+
init: transform.init,
|
|
2553
|
+
condition: transform.condition,
|
|
2554
|
+
step: transform.step,
|
|
2555
|
+
result: transform.result || identity
|
|
2556
|
+
}) };
|
|
2557
|
+
};
|
|
2558
|
+
}
|
|
2559
|
+
function createHasExpander() {
|
|
2560
|
+
const invalidHasArgument = "has() invalid argument";
|
|
2561
|
+
function evaluate(ev, macro, ctx) {
|
|
2562
|
+
const nodes = macro.macroHasProps;
|
|
2563
|
+
let i = nodes.length;
|
|
2564
|
+
let obj = ev.run(nodes[--i], ctx);
|
|
2565
|
+
let inOptionalContext;
|
|
2566
|
+
while (i--) {
|
|
2567
|
+
const node = nodes[i];
|
|
2568
|
+
if (node.op === ".?") inOptionalContext ??= true;
|
|
2569
|
+
obj = ev.debugType(obj).fieldLazy(obj, node.args[1], node, ev);
|
|
2570
|
+
if (obj !== void 0) continue;
|
|
2571
|
+
if (!(!inOptionalContext && i && node.op === ".")) break;
|
|
2572
|
+
throw evaluationError("no_such_key", `No such key: ${node.args[1]}`, node);
|
|
2573
|
+
}
|
|
2574
|
+
return obj !== void 0;
|
|
2575
|
+
}
|
|
2576
|
+
function typeCheck(checker, macro, ctx) {
|
|
2577
|
+
let node = macro.args[0];
|
|
2578
|
+
if (node.op !== ".") throw checker.createError("invalid_macro_argument", invalidHasArgument, node);
|
|
2579
|
+
if (!macro.macroHasProps) {
|
|
2580
|
+
const props = [];
|
|
2581
|
+
while (node.op === "." || node.op === ".?") node = props.push(node) && node.args[0];
|
|
2582
|
+
if (node.op !== "id") throw checker.createError("invalid_macro_argument", invalidHasArgument, node);
|
|
2583
|
+
checker.check(node, ctx);
|
|
2584
|
+
props.push(node);
|
|
2585
|
+
macro.macroHasProps = props;
|
|
2586
|
+
}
|
|
2587
|
+
return checker.getType("bool");
|
|
2588
|
+
}
|
|
2589
|
+
return function({ args }) {
|
|
2590
|
+
return {
|
|
2591
|
+
args,
|
|
2592
|
+
evaluate,
|
|
2593
|
+
typeCheck,
|
|
2594
|
+
async: false
|
|
2595
|
+
};
|
|
2596
|
+
};
|
|
2597
|
+
}
|
|
2598
|
+
function registerMacros(registry) {
|
|
2599
|
+
const functionOverload = (sig, handler) => registry.registerFunctionOverload(sig, handler);
|
|
2600
|
+
functionOverload("has(ast): bool", createHasExpander());
|
|
2601
|
+
functionOverload("list.all(ast, ast): bool", createQuantifierExpander({
|
|
2602
|
+
name: "all",
|
|
2603
|
+
transform({ ast: callAst, predicate, opts }) {
|
|
2604
|
+
return {
|
|
2605
|
+
init: callAst.clone(OPERATORS.value, true),
|
|
2606
|
+
condition: identity,
|
|
2607
|
+
step: predicate.clone(OPERATORS.ternary, [
|
|
2608
|
+
predicate,
|
|
2609
|
+
predicate.clone(OPERATORS.value, true),
|
|
2610
|
+
predicate.clone(OPERATORS.value, false)
|
|
2611
|
+
])
|
|
2612
|
+
};
|
|
2613
|
+
}
|
|
2614
|
+
}));
|
|
2615
|
+
functionOverload("list.exists(ast, ast): bool", createQuantifierExpander({
|
|
2616
|
+
name: "exists",
|
|
2617
|
+
condition(accu) {
|
|
2618
|
+
return !accu;
|
|
2619
|
+
},
|
|
2620
|
+
transform({ ast: callAst, predicate, opts }) {
|
|
2621
|
+
return {
|
|
2622
|
+
init: callAst.clone(OPERATORS.value, false),
|
|
2623
|
+
condition: opts.condition,
|
|
2624
|
+
step: predicate.clone(OPERATORS.ternary, [
|
|
2625
|
+
predicate,
|
|
2626
|
+
predicate.clone(OPERATORS.value, true),
|
|
2627
|
+
predicate.clone(OPERATORS.value, false)
|
|
2628
|
+
])
|
|
2629
|
+
};
|
|
2630
|
+
}
|
|
2631
|
+
}));
|
|
2632
|
+
functionOverload("list.exists_one(ast, ast): bool", createQuantifierExpander({
|
|
2633
|
+
name: "exists_one",
|
|
2634
|
+
errorsAreFatal: true,
|
|
2635
|
+
result(accu) {
|
|
2636
|
+
return accu === 1;
|
|
2637
|
+
},
|
|
2638
|
+
transform({ ast: callAst, predicate, opts }) {
|
|
2639
|
+
const accuValue = callAst.clone(OPERATORS.accuValue);
|
|
2640
|
+
return {
|
|
2641
|
+
init: callAst.clone(OPERATORS.value, 0),
|
|
2642
|
+
step: predicate.clone(OPERATORS.ternary, [
|
|
2643
|
+
predicate,
|
|
2644
|
+
callAst.clone(OPERATORS.accuInc),
|
|
2645
|
+
accuValue
|
|
2646
|
+
]),
|
|
2647
|
+
result: opts.result
|
|
2648
|
+
};
|
|
2649
|
+
}
|
|
2650
|
+
}));
|
|
2651
|
+
functionOverload("list.map(ast, ast): list<dyn>", createMapExpander(false));
|
|
2652
|
+
functionOverload("list.map(ast, ast, ast): list<dyn>", createMapExpander(true));
|
|
2653
|
+
functionOverload("list.filter(ast, ast): list<dyn>", createFilterExpander());
|
|
2654
|
+
class CelNamespace {}
|
|
2655
|
+
const celNamespace = new CelNamespace();
|
|
2656
|
+
registry.registerType("CelNamespace", CelNamespace);
|
|
2657
|
+
registry.registerConstant("cel", "CelNamespace", celNamespace);
|
|
2658
|
+
function bindTypeCheck(checker, m, ctx) {
|
|
2659
|
+
m.bindCtx = ctx.forkWithVariable(m.var, checker.check(m.val, ctx));
|
|
2660
|
+
const type = checker.check(m.exp, m.bindCtx);
|
|
2661
|
+
if (m.val.maybeAsync || m.exp.maybeAsync) return type;
|
|
2662
|
+
m.ast.setMeta("async", false);
|
|
2663
|
+
m.evaluate = bindEvaluateSync;
|
|
2664
|
+
return type;
|
|
2665
|
+
}
|
|
2666
|
+
function bindOptionalEvaluate(ev, exp, bindCtx, ctx, boundValue) {
|
|
2667
|
+
const res = ev.run(exp, ctx = bindCtx.reuse(ctx).setIterValue(boundValue, ev));
|
|
2668
|
+
if (res instanceof Promise && ctx === bindCtx) ctx.async = true;
|
|
2669
|
+
return res;
|
|
2670
|
+
}
|
|
2671
|
+
function bindEvaluate(ev, { val, exp, bindCtx }, ctx) {
|
|
2672
|
+
const v = ev.run(val, ctx);
|
|
2673
|
+
if (v instanceof Promise) return v.then((_v) => bindOptionalEvaluate(ev, exp, bindCtx, ctx, _v));
|
|
2674
|
+
return bindOptionalEvaluate(ev, exp, bindCtx, ctx, v);
|
|
2675
|
+
}
|
|
2676
|
+
function bindEvaluateSync(ev, { val, exp, bindCtx }, ctx) {
|
|
2677
|
+
return ev.run(exp, bindCtx.reuse(ctx).setIterValue(ev.run(val, ctx), ev));
|
|
2678
|
+
}
|
|
2679
|
+
functionOverload("CelNamespace.bind(ast, dyn, ast): dyn", ({ ast, args }) => {
|
|
2680
|
+
return {
|
|
2681
|
+
ast,
|
|
2682
|
+
var: assertIdentifier(args[0], "invalid variable argument"),
|
|
2683
|
+
val: args[1],
|
|
2684
|
+
exp: args[2],
|
|
2685
|
+
bindCtx: void 0,
|
|
2686
|
+
typeCheck: bindTypeCheck,
|
|
2687
|
+
evaluate: bindEvaluate
|
|
2688
|
+
};
|
|
2689
|
+
});
|
|
2690
|
+
}
|
|
2691
|
+
function registerOverloads(registry) {
|
|
2692
|
+
const unaryOverload = (op, t, h, ret) => registry.unaryOverload(op, t, h, ret, false);
|
|
2693
|
+
const binaryOverload = (l, op, r, h, ret) => registry.binaryOverload(l, op, r, h, ret, false);
|
|
2694
|
+
function verifyInteger(v, ast) {
|
|
2695
|
+
if (v <= 9223372036854775807n && v >= -9223372036854775808n) return v;
|
|
2696
|
+
throw evaluationError("numeric_overflow", `integer overflow: ${v}`, ast);
|
|
2697
|
+
}
|
|
2698
|
+
function throwDivisionByZero(ast) {
|
|
2699
|
+
throw evaluationError("division_by_zero", "division by zero", ast);
|
|
2700
|
+
}
|
|
2701
|
+
function throwModuloByZero(ast) {
|
|
2702
|
+
throw evaluationError("modulo_by_zero", "modulo by zero", ast);
|
|
2703
|
+
}
|
|
2704
|
+
unaryOverload("!", "bool", (a) => !a);
|
|
2705
|
+
unaryOverload("-", "int", (a) => -a);
|
|
2706
|
+
binaryOverload("dyn<int>", `==`, `double`, (a, b) => a == b);
|
|
2707
|
+
binaryOverload("dyn<int>", `==`, `uint`, (a, b) => a == b.valueOf());
|
|
2708
|
+
binaryOverload("int", "*", "int", (a, b, ast) => verifyInteger(a * b, ast));
|
|
2709
|
+
binaryOverload("int", "+", "int", (a, b, ast) => verifyInteger(a + b, ast));
|
|
2710
|
+
binaryOverload("int", "-", "int", (a, b, ast) => verifyInteger(a - b, ast));
|
|
2711
|
+
binaryOverload("int", "/", "int", (a, b, ast) => {
|
|
2712
|
+
if (b === 0n) return throwDivisionByZero(ast);
|
|
2713
|
+
return a / b;
|
|
2714
|
+
});
|
|
2715
|
+
binaryOverload("int", "%", "int", (a, b, ast) => {
|
|
2716
|
+
if (b === 0n) return throwModuloByZero(ast);
|
|
2717
|
+
return a % b;
|
|
2718
|
+
});
|
|
2719
|
+
unaryOverload("-", "double", (a) => -a);
|
|
2720
|
+
binaryOverload("double", "*", "double", (a, b) => a * b);
|
|
2721
|
+
binaryOverload("double", "+", "double", (a, b) => a + b);
|
|
2722
|
+
binaryOverload("double", "-", "double", (a, b) => a - b);
|
|
2723
|
+
binaryOverload("double", "/", "double", (a, b) => a / b);
|
|
2724
|
+
binaryOverload("string", "+", "string", (a, b) => a + b);
|
|
2725
|
+
binaryOverload("list<V>", "+", "list<V>", (a, b) => [...a, ...b]);
|
|
2726
|
+
binaryOverload("bytes", "+", "bytes", (a, b) => {
|
|
2727
|
+
if (!a.length) return b;
|
|
2728
|
+
if (!b.length) return a;
|
|
2729
|
+
const result = new Uint8Array(a.length + b.length);
|
|
2730
|
+
result.set(a, 0);
|
|
2731
|
+
result.set(b, a.length);
|
|
2732
|
+
return result;
|
|
2733
|
+
});
|
|
2734
|
+
const GPD = "google.protobuf.Duration";
|
|
2735
|
+
binaryOverload(GPD, "+", GPD, (a, b) => a.addDuration(b));
|
|
2736
|
+
binaryOverload(GPD, "-", GPD, (a, b) => a.subtractDuration(b));
|
|
2737
|
+
binaryOverload(GPD, "==", GPD, (a, b) => a.seconds === b.seconds && a.nanos === b.nanos);
|
|
2738
|
+
const GPT = "google.protobuf.Timestamp";
|
|
2739
|
+
binaryOverload(GPT, "==", GPT, (a, b) => a.getTime() === b.getTime());
|
|
2740
|
+
binaryOverload(GPT, "-", GPT, (a, b) => Duration.fromMilliseconds(a.getTime() - b.getTime()), GPD);
|
|
2741
|
+
binaryOverload(GPT, "-", GPD, (a, b) => b.subtractTimestamp(a));
|
|
2742
|
+
binaryOverload(GPT, "+", GPD, (a, b) => b.extendTimestamp(a));
|
|
2743
|
+
binaryOverload(GPD, "+", GPT, (a, b) => a.extendTimestamp(b));
|
|
2744
|
+
function listIncludes(value, list, ast, ev) {
|
|
2745
|
+
if (list instanceof Set && list.has(value)) return true;
|
|
2746
|
+
for (const v of list) if (isEqual(value, v, ast, ev)) return true;
|
|
2747
|
+
return false;
|
|
2748
|
+
}
|
|
2749
|
+
function mapIncludes(a, b) {
|
|
2750
|
+
if (b instanceof Map) return b.get(a) !== void 0;
|
|
2751
|
+
return hasOwn(b, a) ? b[a] !== void 0 : false;
|
|
2752
|
+
}
|
|
2753
|
+
function listMembership(value, list, ast, ev) {
|
|
2754
|
+
return listIncludes(value, list, ast, ev);
|
|
2755
|
+
}
|
|
2756
|
+
binaryOverload("V", "in", "list<V>", listMembership);
|
|
2757
|
+
binaryOverload("K", "in", "map<K, V>", mapIncludes);
|
|
2758
|
+
for (const t of [
|
|
2759
|
+
"type",
|
|
2760
|
+
"null",
|
|
2761
|
+
"bool",
|
|
2762
|
+
"string",
|
|
2763
|
+
"int",
|
|
2764
|
+
"double"
|
|
2765
|
+
]) binaryOverload(t, "==", t, (a, b) => a === b);
|
|
2766
|
+
binaryOverload("bytes", `==`, "bytes", (a, b) => {
|
|
2767
|
+
if (a === b) return true;
|
|
2768
|
+
let i = a.length;
|
|
2769
|
+
if (i !== b.length) return false;
|
|
2770
|
+
while (i--) if (a[i] !== b[i]) return false;
|
|
2771
|
+
return true;
|
|
2772
|
+
});
|
|
2773
|
+
binaryOverload("list<V>", `==`, "list<V>", (a, b, ast, ev) => {
|
|
2774
|
+
if (a === b) return true;
|
|
2775
|
+
if (isArray(a) && isArray(b)) {
|
|
2776
|
+
const length = a.length;
|
|
2777
|
+
if (length !== b.length) return false;
|
|
2778
|
+
for (let i = 0; i < length; i++) if (!isEqual(a[i], b[i], ast, ev)) return false;
|
|
2779
|
+
return true;
|
|
2780
|
+
}
|
|
2781
|
+
if (a instanceof Set && b instanceof Set) {
|
|
2782
|
+
if (a.size !== b.size) return false;
|
|
2783
|
+
for (const value of a) if (!b.has(value)) return false;
|
|
2784
|
+
return true;
|
|
2785
|
+
}
|
|
2786
|
+
const arr = a instanceof Set ? b : a;
|
|
2787
|
+
const set = a instanceof Set ? a : b;
|
|
2788
|
+
if (!isArray(arr)) return false;
|
|
2789
|
+
if (arr.length !== set?.size) return false;
|
|
2790
|
+
for (let i = 0; i < arr.length; i++) if (!set.has(arr[i])) return false;
|
|
2791
|
+
return true;
|
|
2792
|
+
});
|
|
2793
|
+
binaryOverload("map<K, V>", `==`, "map<K, V>", (a, b, ast, ev) => {
|
|
2794
|
+
if (a === b) return true;
|
|
2795
|
+
if (a instanceof Map && b instanceof Map) {
|
|
2796
|
+
if (a.size !== b.size) return false;
|
|
2797
|
+
for (const [key, value] of a) if (!(b.has(key) && isEqual(value, b.get(key), ast, ev))) return false;
|
|
2798
|
+
return true;
|
|
2799
|
+
}
|
|
2800
|
+
if (a instanceof Map || b instanceof Map) {
|
|
2801
|
+
const obj = a instanceof Map ? b : a;
|
|
2802
|
+
const map = a instanceof Map ? a : b;
|
|
2803
|
+
const keysObj = objKeys(obj);
|
|
2804
|
+
if (map.size !== keysObj.length) return false;
|
|
2805
|
+
for (const [key, value] of map) if (!(key in obj && isEqual(value, obj[key], ast, ev))) return false;
|
|
2806
|
+
return true;
|
|
2807
|
+
}
|
|
2808
|
+
const keysA = objKeys(a);
|
|
2809
|
+
const keysB = objKeys(b);
|
|
2810
|
+
if (keysA.length !== keysB.length) return false;
|
|
2811
|
+
for (let i = 0; i < keysA.length; i++) {
|
|
2812
|
+
const key = keysA[i];
|
|
2813
|
+
if (!(key in b && isEqual(a[key], b[key], ast, ev))) return false;
|
|
2814
|
+
}
|
|
2815
|
+
return true;
|
|
2816
|
+
});
|
|
2817
|
+
binaryOverload("uint", "==", "uint", (a, b) => a.valueOf() === b.valueOf());
|
|
2818
|
+
binaryOverload("dyn<uint>", `==`, `double`, (a, b) => a.valueOf() == b);
|
|
2819
|
+
binaryOverload("uint", "+", "uint", (a, b) => new UnsignedInt(a.valueOf() + b.valueOf()));
|
|
2820
|
+
binaryOverload("uint", "-", "uint", (a, b) => new UnsignedInt(a.valueOf() - b.valueOf()));
|
|
2821
|
+
binaryOverload("uint", "*", "uint", (a, b) => new UnsignedInt(a.valueOf() * b.valueOf()));
|
|
2822
|
+
binaryOverload("uint", "/", "uint", (a, b, ast) => {
|
|
2823
|
+
if (b.valueOf() === 0n) return throwDivisionByZero(ast);
|
|
2824
|
+
return new UnsignedInt(a.valueOf() / b.valueOf());
|
|
2825
|
+
});
|
|
2826
|
+
binaryOverload("uint", "%", "uint", (a, b, ast) => {
|
|
2827
|
+
if (b.valueOf() === 0n) return throwModuloByZero(ast);
|
|
2828
|
+
return new UnsignedInt(a.valueOf() % b.valueOf());
|
|
2829
|
+
});
|
|
2830
|
+
for (const [left, right] of [
|
|
2831
|
+
["bool", "bool"],
|
|
2832
|
+
["int", "int"],
|
|
2833
|
+
["uint", "uint"],
|
|
2834
|
+
["double", "double"],
|
|
2835
|
+
["string", "string"],
|
|
2836
|
+
["google.protobuf.Timestamp", "google.protobuf.Timestamp"],
|
|
2837
|
+
["google.protobuf.Duration", "google.protobuf.Duration"],
|
|
2838
|
+
["int", "uint"],
|
|
2839
|
+
["int", "double"],
|
|
2840
|
+
["double", "int"],
|
|
2841
|
+
["double", "uint"],
|
|
2842
|
+
["uint", "int"],
|
|
2843
|
+
["uint", "double"]
|
|
2844
|
+
]) {
|
|
2845
|
+
binaryOverload(left, "<", right, (a, b) => a < b);
|
|
2846
|
+
binaryOverload(left, "<=", right, (a, b) => a <= b);
|
|
2847
|
+
binaryOverload(left, ">", right, (a, b) => a > b);
|
|
2848
|
+
binaryOverload(left, ">=", right, (a, b) => a >= b);
|
|
2849
|
+
}
|
|
2850
|
+
}
|
|
2851
|
+
function isEqual(a, b, ast, ev) {
|
|
2852
|
+
if (a === b) return true;
|
|
2853
|
+
switch (typeof a) {
|
|
2854
|
+
case "undefined":
|
|
2855
|
+
case "string":
|
|
2856
|
+
case "boolean": return false;
|
|
2857
|
+
case "bigint":
|
|
2858
|
+
if (typeof b === "number") return a == b;
|
|
2859
|
+
return false;
|
|
2860
|
+
case "number":
|
|
2861
|
+
if (typeof b === "bigint") return a == b;
|
|
2862
|
+
return false;
|
|
2863
|
+
case "object":
|
|
2864
|
+
if (typeof b !== "object") return false;
|
|
2865
|
+
const leftType = ev.debugType(a);
|
|
2866
|
+
const rightType = ev.debugType(b);
|
|
2867
|
+
if (leftType !== rightType) return false;
|
|
2868
|
+
const overload = ev.registry.findBinaryOverload("==", leftType, rightType);
|
|
2869
|
+
if (!overload) return false;
|
|
2870
|
+
return overload.handler(a, b, ast, ev);
|
|
2871
|
+
}
|
|
2872
|
+
throw evaluationError("invalid_comparison_type", `Cannot compare values of type ${typeof a}`, ast);
|
|
2873
|
+
}
|
|
2874
|
+
const toDynTypeBinding = (/* @__PURE__ */ new Map()).set("A", "dyn").set("T", "dyn").set("K", "dyn").set("V", "dyn");
|
|
2875
|
+
var TypeChecker = class extends Base {
|
|
2876
|
+
constructor(opts, isEvaluating) {
|
|
2877
|
+
super(opts);
|
|
2878
|
+
this.createError = isEvaluating ? evaluationError : typeError;
|
|
2879
|
+
}
|
|
2880
|
+
check(ast, ctx) {
|
|
2881
|
+
try {
|
|
2882
|
+
return ast.checkedType ??= ast.check(this, ast, ctx);
|
|
2883
|
+
} catch (error) {
|
|
2884
|
+
throw attachErrorAst(error, ast);
|
|
2885
|
+
}
|
|
2886
|
+
}
|
|
2887
|
+
checkAccessOnType(ast, ctx, leftType, allowMissingField = false) {
|
|
2888
|
+
if (leftType === this.dynType) return leftType;
|
|
2889
|
+
const indexTypeName = (ast.op === "[]" || ast.op === "[?]" ? this.check(ast.args[1], ctx) : this.stringType).type;
|
|
2890
|
+
if (leftType.kind === "list") {
|
|
2891
|
+
if (indexTypeName === "int" || indexTypeName === "dyn") return leftType.valueType;
|
|
2892
|
+
throw this.createError("invalid_index_type", `List index must be int, got '${indexTypeName}'`, ast);
|
|
2893
|
+
}
|
|
2894
|
+
if (leftType.kind === "map") return leftType.valueType;
|
|
2895
|
+
const customType = this.objectTypes.get(leftType.name);
|
|
2896
|
+
if (customType) {
|
|
2897
|
+
if (!(indexTypeName === "string" || indexTypeName === "dyn")) throw this.createError("invalid_index_type", `Cannot index type '${leftType.name}' with type '${indexTypeName}'`, ast);
|
|
2898
|
+
if (customType.fields) {
|
|
2899
|
+
let keyName;
|
|
2900
|
+
if (ast.op === "." || ast.op === ".?") keyName = ast.args[1];
|
|
2901
|
+
else if (ast.args[1].op === "value") keyName = ast.args[1].args;
|
|
2902
|
+
if (typeof keyName === "string") {
|
|
2903
|
+
const fieldType = customType.fields[keyName];
|
|
2904
|
+
if (fieldType) return fieldType;
|
|
2905
|
+
if (allowMissingField) return this.dynType;
|
|
2906
|
+
throw this.createError("no_such_key", `No such key: ${keyName}`, ast);
|
|
2907
|
+
}
|
|
2908
|
+
}
|
|
2909
|
+
return this.dynType;
|
|
2910
|
+
}
|
|
2911
|
+
throw this.createError("cannot_index_type", `Cannot index type '${this.formatType(leftType)}'`, ast);
|
|
2912
|
+
}
|
|
2913
|
+
formatType(type) {
|
|
2914
|
+
if (!type.hasPlaceholderType) return type.name;
|
|
2915
|
+
return type.templated(this.registry, toDynTypeBinding).name;
|
|
2916
|
+
}
|
|
2917
|
+
formatTypeList(types) {
|
|
2918
|
+
return types.map((t) => this.formatType(t)).join(", ");
|
|
2919
|
+
}
|
|
2920
|
+
};
|
|
2921
|
+
const TOKEN = {
|
|
2922
|
+
EOF: 0,
|
|
2923
|
+
NUMBER: 1,
|
|
2924
|
+
STRING: 2,
|
|
2925
|
+
BOOLEAN: 3,
|
|
2926
|
+
NULL: 4,
|
|
2927
|
+
IDENTIFIER: 5,
|
|
2928
|
+
PLUS: 6,
|
|
2929
|
+
MINUS: 7,
|
|
2930
|
+
MULTIPLY: 8,
|
|
2931
|
+
DIVIDE: 9,
|
|
2932
|
+
MODULO: 10,
|
|
2933
|
+
EQ: 11,
|
|
2934
|
+
NE: 12,
|
|
2935
|
+
LT: 13,
|
|
2936
|
+
LE: 14,
|
|
2937
|
+
GT: 15,
|
|
2938
|
+
GE: 16,
|
|
2939
|
+
AND: 17,
|
|
2940
|
+
OR: 18,
|
|
2941
|
+
NOT: 19,
|
|
2942
|
+
IN: 20,
|
|
2943
|
+
LPAREN: 21,
|
|
2944
|
+
RPAREN: 22,
|
|
2945
|
+
LBRACKET: 23,
|
|
2946
|
+
RBRACKET: 24,
|
|
2947
|
+
LBRACE: 25,
|
|
2948
|
+
RBRACE: 26,
|
|
2949
|
+
DOT: 27,
|
|
2950
|
+
COMMA: 28,
|
|
2951
|
+
COLON: 29,
|
|
2952
|
+
QUESTION: 30,
|
|
2953
|
+
BYTES: 31
|
|
2954
|
+
};
|
|
2955
|
+
const OP_FOR_TOKEN = {
|
|
2956
|
+
[TOKEN.EQ]: OPERATORS["=="],
|
|
2957
|
+
[TOKEN.PLUS]: OPERATORS["+"],
|
|
2958
|
+
[TOKEN.MINUS]: OPERATORS["-"],
|
|
2959
|
+
[TOKEN.MULTIPLY]: OPERATORS["*"],
|
|
2960
|
+
[TOKEN.DIVIDE]: OPERATORS["/"],
|
|
2961
|
+
[TOKEN.MODULO]: OPERATORS["%"],
|
|
2962
|
+
[TOKEN.LE]: OPERATORS["<="],
|
|
2963
|
+
[TOKEN.LT]: OPERATORS["<"],
|
|
2964
|
+
[TOKEN.GE]: OPERATORS[">="],
|
|
2965
|
+
[TOKEN.GT]: OPERATORS[">"],
|
|
2966
|
+
[TOKEN.NE]: OPERATORS["!="],
|
|
2967
|
+
[TOKEN.IN]: OPERATORS["in"]
|
|
2968
|
+
};
|
|
2969
|
+
const TOKEN_BY_NUMBER = {};
|
|
2970
|
+
for (const key in TOKEN) TOKEN_BY_NUMBER[TOKEN[key]] = key;
|
|
2971
|
+
const HEX_CODES = /* @__PURE__ */ new Uint8Array(128);
|
|
2972
|
+
for (const ch of "0123456789abcdefABCDEF") HEX_CODES[ch.charCodeAt(0)] = 1;
|
|
2973
|
+
const ESCAPE_ERRORS = {
|
|
2974
|
+
bytes_unicode_escape: (e) => `\\${e} not allowed in bytes literals`,
|
|
2975
|
+
invalid_unicode_escape: (e) => `Invalid Unicode escape: \\${e}`,
|
|
2976
|
+
invalid_unicode_surrogate: (e) => `Invalid Unicode surrogate: \\${e}`,
|
|
2977
|
+
invalid_hex_escape: (e) => `Invalid hex escape: \\${e}`,
|
|
2978
|
+
invalid_octal_escape: () => "Octal escape must be 3 digits",
|
|
2979
|
+
octal_escape_out_of_range: (e) => `Octal escape out of range: \\${e}`,
|
|
2980
|
+
invalid_escape_sequence: (e) => `Invalid escape sequence: \\${e}`
|
|
2981
|
+
};
|
|
2982
|
+
const STRING_ESCAPES = {
|
|
2983
|
+
"\\": "\\",
|
|
2984
|
+
"?": "?",
|
|
2985
|
+
"\"": "\"",
|
|
2986
|
+
"'": "'",
|
|
2987
|
+
"`": "`",
|
|
2988
|
+
a: "\x07",
|
|
2989
|
+
b: "\b",
|
|
2990
|
+
f: "\f",
|
|
2991
|
+
n: "\n",
|
|
2992
|
+
r: "\r",
|
|
2993
|
+
t: " ",
|
|
2994
|
+
v: "\v"
|
|
2995
|
+
};
|
|
2996
|
+
var ASTNode = class ASTNode {
|
|
2997
|
+
#meta;
|
|
2998
|
+
#input;
|
|
2999
|
+
constructor(input, pos, start, end, op, args) {
|
|
3000
|
+
this.#meta = {
|
|
3001
|
+
check: op.check,
|
|
3002
|
+
evaluate: op.evaluate
|
|
3003
|
+
};
|
|
3004
|
+
this.#input = input;
|
|
3005
|
+
this.op = op.name;
|
|
3006
|
+
this.args = args;
|
|
3007
|
+
this.pos = pos;
|
|
3008
|
+
this.start = start;
|
|
3009
|
+
this.end = end;
|
|
3010
|
+
}
|
|
3011
|
+
clone(op, args) {
|
|
3012
|
+
return new ASTNode(this.#input, this.pos, this.start, this.end, op, args);
|
|
3013
|
+
}
|
|
3014
|
+
get meta() {
|
|
3015
|
+
return this.#meta;
|
|
3016
|
+
}
|
|
3017
|
+
get input() {
|
|
3018
|
+
return this.#input;
|
|
3019
|
+
}
|
|
3020
|
+
#computeIsAsync() {
|
|
3021
|
+
const ast = this.#meta.alternate ?? this;
|
|
3022
|
+
switch (ast.op) {
|
|
3023
|
+
case "value":
|
|
3024
|
+
case "id":
|
|
3025
|
+
case "accuValue":
|
|
3026
|
+
case "accuInc": return false;
|
|
3027
|
+
case "accuPush": return ast.args.maybeAsync;
|
|
3028
|
+
case "!_":
|
|
3029
|
+
case "-_":
|
|
3030
|
+
if (ast.candidates?.async !== false) return true;
|
|
3031
|
+
return ast.args.maybeAsync;
|
|
3032
|
+
case "!=":
|
|
3033
|
+
case "==":
|
|
3034
|
+
case "in":
|
|
3035
|
+
case "+":
|
|
3036
|
+
case "-":
|
|
3037
|
+
case "*":
|
|
3038
|
+
case "/":
|
|
3039
|
+
case "%":
|
|
3040
|
+
case "<":
|
|
3041
|
+
case "<=":
|
|
3042
|
+
case ">":
|
|
3043
|
+
case ">=":
|
|
3044
|
+
if (ast.candidates?.async !== false) return true;
|
|
3045
|
+
return ast.args.some((a) => a.maybeAsync);
|
|
3046
|
+
case "call":
|
|
3047
|
+
case "rcall":
|
|
3048
|
+
if (ast.candidates?.async !== false) return true;
|
|
3049
|
+
return (ast.receiverWithArgs || ast.args[1]).some((a) => a.maybeAsync);
|
|
3050
|
+
case "comprehension": return ast.args.iterable.maybeAsync || ast.args.step.maybeAsync;
|
|
3051
|
+
case ".":
|
|
3052
|
+
case ".?": return ast.args[0].maybeAsync;
|
|
3053
|
+
case "?:":
|
|
3054
|
+
case "list":
|
|
3055
|
+
case "[]":
|
|
3056
|
+
case "[?]": return ast.args.some((a) => a.maybeAsync);
|
|
3057
|
+
case "||":
|
|
3058
|
+
case "&&": return ast.args.some((a) => a.maybeAsync);
|
|
3059
|
+
case "map": return ast.args.some((a) => a[0].maybeAsync || a[1].maybeAsync);
|
|
3060
|
+
default: return true;
|
|
3061
|
+
}
|
|
3062
|
+
}
|
|
3063
|
+
get maybeAsync() {
|
|
3064
|
+
return this.#meta.async ??= this.#computeIsAsync();
|
|
3065
|
+
}
|
|
3066
|
+
check(chk, ast, ctx) {
|
|
3067
|
+
const meta = this.#meta;
|
|
3068
|
+
if (meta.alternate) return chk.check(meta.alternate, ctx);
|
|
3069
|
+
else if (meta.macro) return meta.macro.typeCheck(chk, meta.macro, ctx);
|
|
3070
|
+
return meta.check(chk, ast, ctx);
|
|
3071
|
+
}
|
|
3072
|
+
evaluate(ev, ast, ctx) {
|
|
3073
|
+
const meta = this.#meta;
|
|
3074
|
+
if (meta.alternate) this.evaluate = this.#evaluateAlternate;
|
|
3075
|
+
else if (meta.macro) this.evaluate = this.#evaluateMacro;
|
|
3076
|
+
else this.evaluate = meta.evaluate;
|
|
3077
|
+
return this.evaluate(ev, ast, ctx);
|
|
3078
|
+
}
|
|
3079
|
+
#evaluateAlternate(ev, ast, ctx) {
|
|
3080
|
+
return (ast = this.#meta.alternate).evaluate(ev, ast, ctx);
|
|
3081
|
+
}
|
|
3082
|
+
#evaluateMacro(ev, ast, ctx) {
|
|
3083
|
+
return (ast = this.#meta.macro).evaluate(ev, ast, ctx);
|
|
3084
|
+
}
|
|
3085
|
+
setMeta(key, value) {
|
|
3086
|
+
return this.#meta[key] = value, this;
|
|
3087
|
+
}
|
|
3088
|
+
get range() {
|
|
3089
|
+
return {
|
|
3090
|
+
start: this.start,
|
|
3091
|
+
end: this.end
|
|
3092
|
+
};
|
|
3093
|
+
}
|
|
3094
|
+
toOldStructure() {
|
|
3095
|
+
const args = Array.isArray(this.args) ? this.args : [this.args];
|
|
3096
|
+
return [this.op, ...args.map((a) => a instanceof ASTNode ? a.toOldStructure() : a)];
|
|
3097
|
+
}
|
|
3098
|
+
};
|
|
3099
|
+
var Lexer = class {
|
|
3100
|
+
input;
|
|
3101
|
+
pos;
|
|
3102
|
+
length;
|
|
3103
|
+
tokenPos;
|
|
3104
|
+
tokenType;
|
|
3105
|
+
tokenValue;
|
|
3106
|
+
reset(input) {
|
|
3107
|
+
this.pos = 0;
|
|
3108
|
+
this.input = input;
|
|
3109
|
+
this.length = input.length;
|
|
3110
|
+
return input;
|
|
3111
|
+
}
|
|
3112
|
+
token(pos, type, value) {
|
|
3113
|
+
this.tokenPos = pos;
|
|
3114
|
+
this.tokenType = type;
|
|
3115
|
+
this.tokenValue = value;
|
|
3116
|
+
return this;
|
|
3117
|
+
}
|
|
3118
|
+
nextToken() {
|
|
3119
|
+
while (true) {
|
|
3120
|
+
const { pos, input, length } = this;
|
|
3121
|
+
if (pos >= length) return this.token(pos, TOKEN.EOF);
|
|
3122
|
+
const ch = input[pos];
|
|
3123
|
+
switch (ch) {
|
|
3124
|
+
case " ":
|
|
3125
|
+
case " ":
|
|
3126
|
+
case "\n":
|
|
3127
|
+
case "\r":
|
|
3128
|
+
this.pos++;
|
|
3129
|
+
continue;
|
|
3130
|
+
case "=":
|
|
3131
|
+
if (input[pos + 1] !== "=") break;
|
|
3132
|
+
return this.token((this.pos += 2) - 2, TOKEN.EQ);
|
|
3133
|
+
case "&":
|
|
3134
|
+
if (input[pos + 1] !== "&") break;
|
|
3135
|
+
return this.token((this.pos += 2) - 2, TOKEN.AND);
|
|
3136
|
+
case "|":
|
|
3137
|
+
if (input[pos + 1] !== "|") break;
|
|
3138
|
+
return this.token((this.pos += 2) - 2, TOKEN.OR);
|
|
3139
|
+
case "+": return this.token(this.pos++, TOKEN.PLUS);
|
|
3140
|
+
case "-": return this.token(this.pos++, TOKEN.MINUS);
|
|
3141
|
+
case "*": return this.token(this.pos++, TOKEN.MULTIPLY);
|
|
3142
|
+
case "/":
|
|
3143
|
+
if (input[pos + 1] === "/") {
|
|
3144
|
+
while (this.pos < length && this.input[this.pos] !== "\n") this.pos++;
|
|
3145
|
+
continue;
|
|
3146
|
+
}
|
|
3147
|
+
return this.token(this.pos++, TOKEN.DIVIDE);
|
|
3148
|
+
case "%": return this.token(this.pos++, TOKEN.MODULO);
|
|
3149
|
+
case "<":
|
|
3150
|
+
if (input[pos + 1] === "=") return this.token((this.pos += 2) - 2, TOKEN.LE);
|
|
3151
|
+
return this.token(this.pos++, TOKEN.LT);
|
|
3152
|
+
case ">":
|
|
3153
|
+
if (input[pos + 1] === "=") return this.token((this.pos += 2) - 2, TOKEN.GE);
|
|
3154
|
+
return this.token(this.pos++, TOKEN.GT);
|
|
3155
|
+
case "!":
|
|
3156
|
+
if (input[pos + 1] === "=") return this.token((this.pos += 2) - 2, TOKEN.NE);
|
|
3157
|
+
return this.token(this.pos++, TOKEN.NOT);
|
|
3158
|
+
case "(": return this.token(this.pos++, TOKEN.LPAREN);
|
|
3159
|
+
case ")": return this.token(this.pos++, TOKEN.RPAREN);
|
|
3160
|
+
case "[": return this.token(this.pos++, TOKEN.LBRACKET);
|
|
3161
|
+
case "]": return this.token(this.pos++, TOKEN.RBRACKET);
|
|
3162
|
+
case "{": return this.token(this.pos++, TOKEN.LBRACE);
|
|
3163
|
+
case "}": return this.token(this.pos++, TOKEN.RBRACE);
|
|
3164
|
+
case ".": return this.token(this.pos++, TOKEN.DOT);
|
|
3165
|
+
case ",": return this.token(this.pos++, TOKEN.COMMA);
|
|
3166
|
+
case ":": return this.token(this.pos++, TOKEN.COLON);
|
|
3167
|
+
case "?": return this.token(this.pos++, TOKEN.QUESTION);
|
|
3168
|
+
case `"`:
|
|
3169
|
+
case `'`: return this.readString(ch);
|
|
3170
|
+
case "b":
|
|
3171
|
+
case "B":
|
|
3172
|
+
case "r":
|
|
3173
|
+
case "R": {
|
|
3174
|
+
const next = input[pos + 1];
|
|
3175
|
+
if (next === "\"" || next === "'") return ++this.pos && this.readString(next, ch);
|
|
3176
|
+
return this.readIdentifier();
|
|
3177
|
+
}
|
|
3178
|
+
default: {
|
|
3179
|
+
const code = ch.charCodeAt(0);
|
|
3180
|
+
if (code <= 57 && code >= 48) return this.readNumber();
|
|
3181
|
+
if (this._isIdentifierCharCode(code)) return this.readIdentifier();
|
|
3182
|
+
}
|
|
3183
|
+
}
|
|
3184
|
+
throw parseError("unexpected_character", `Unexpected character: ${ch}`, {
|
|
3185
|
+
pos,
|
|
3186
|
+
start: pos,
|
|
3187
|
+
end: pos + 1,
|
|
3188
|
+
input
|
|
3189
|
+
});
|
|
3190
|
+
}
|
|
3191
|
+
}
|
|
3192
|
+
_isIdentifierCharCode(c) {
|
|
3193
|
+
if (c < 48 || c > 122) return false;
|
|
3194
|
+
return c >= 97 || c >= 65 && c <= 90 || c <= 57 || c === 95;
|
|
3195
|
+
}
|
|
3196
|
+
_parseAsDouble(start, end) {
|
|
3197
|
+
const value = Number(this.input.substring(start, end));
|
|
3198
|
+
if (Number.isFinite(value)) return this.token(start, TOKEN.NUMBER, value);
|
|
3199
|
+
throw parseError("invalid_number", `Invalid number: ${value}`, {
|
|
3200
|
+
pos: start,
|
|
3201
|
+
start,
|
|
3202
|
+
end,
|
|
3203
|
+
input: this.input
|
|
3204
|
+
});
|
|
3205
|
+
}
|
|
3206
|
+
_parseAsBigInt(start, end, isHex, unsigned) {
|
|
3207
|
+
const string = this.input.substring(start, end);
|
|
3208
|
+
if (unsigned === "u" || unsigned === "U") {
|
|
3209
|
+
this.pos++;
|
|
3210
|
+
try {
|
|
3211
|
+
return this.token(start, TOKEN.NUMBER, new UnsignedInt(string));
|
|
3212
|
+
} catch (_err) {}
|
|
3213
|
+
} else try {
|
|
3214
|
+
return this.token(start, TOKEN.NUMBER, BigInt(string));
|
|
3215
|
+
} catch (_err) {}
|
|
3216
|
+
throw parseError(isHex ? "invalid_hex_integer" : "invalid_integer", isHex ? `Invalid hex integer: ${string}` : `Invalid integer: ${string}`, {
|
|
3217
|
+
pos: start,
|
|
3218
|
+
start,
|
|
3219
|
+
end: this.pos,
|
|
3220
|
+
input: this.input
|
|
3221
|
+
});
|
|
3222
|
+
}
|
|
3223
|
+
_readDigits(input, length, pos, code) {
|
|
3224
|
+
while (pos < length && (code = input.charCodeAt(pos)) && !(code > 57 || code < 48)) pos++;
|
|
3225
|
+
return pos;
|
|
3226
|
+
}
|
|
3227
|
+
_readExponent(input, length, pos) {
|
|
3228
|
+
let ch = pos < length && input[pos];
|
|
3229
|
+
if (ch === "e" || ch === "E") {
|
|
3230
|
+
ch = ++pos < length && input[pos];
|
|
3231
|
+
if (ch === "-" || ch === "+") pos++;
|
|
3232
|
+
const start = pos;
|
|
3233
|
+
pos = this._readDigits(input, length, pos);
|
|
3234
|
+
if (start === pos) throw parseError("invalid_exponent", "Invalid exponent", {
|
|
3235
|
+
pos,
|
|
3236
|
+
start: pos,
|
|
3237
|
+
end: Math.min(pos + 1, input.length),
|
|
3238
|
+
input
|
|
3239
|
+
});
|
|
3240
|
+
}
|
|
3241
|
+
return pos;
|
|
3242
|
+
}
|
|
3243
|
+
readNumber() {
|
|
3244
|
+
const { input, length, pos: start } = this;
|
|
3245
|
+
let pos = start;
|
|
3246
|
+
if (input[pos] === "0" && (input[pos + 1] === "x" || input[pos + 1] === "X")) {
|
|
3247
|
+
pos += 2;
|
|
3248
|
+
while (pos < length && HEX_CODES[input[pos].charCodeAt(0)]) pos++;
|
|
3249
|
+
return this._parseAsBigInt(start, this.pos = pos, true, input[pos]);
|
|
3250
|
+
}
|
|
3251
|
+
pos = this._readDigits(input, length, pos);
|
|
3252
|
+
if (pos + 1 < length) {
|
|
3253
|
+
let isDouble = false;
|
|
3254
|
+
let afterpos = input[pos] === "." ? this._readDigits(input, length, pos + 1) : pos + 1;
|
|
3255
|
+
if (afterpos !== pos + 1) (isDouble = true) && (pos = afterpos);
|
|
3256
|
+
afterpos = this._readExponent(input, length, pos);
|
|
3257
|
+
if (afterpos !== pos) (isDouble = true) && (pos = afterpos);
|
|
3258
|
+
if (isDouble) return this._parseAsDouble(start, this.pos = pos);
|
|
3259
|
+
}
|
|
3260
|
+
return this._parseAsBigInt(start, this.pos = pos, false, input[pos]);
|
|
3261
|
+
}
|
|
3262
|
+
readString(del, prefix) {
|
|
3263
|
+
const { input: i, pos: s } = this;
|
|
3264
|
+
if (i[s + 1] === del && i[s + 2] === del) return this.readTripleQuotedString(del, prefix);
|
|
3265
|
+
return this.readSingleQuotedString(del, prefix);
|
|
3266
|
+
}
|
|
3267
|
+
_closeQuotedString(rawStart, rawValue, prefix, pos) {
|
|
3268
|
+
switch (prefix) {
|
|
3269
|
+
case "b":
|
|
3270
|
+
case "B": {
|
|
3271
|
+
const processed = this.processEscapes(rawStart, rawValue, true);
|
|
3272
|
+
const bytes = new Uint8Array(processed.length);
|
|
3273
|
+
for (let i = 0; i < processed.length; i++) bytes[i] = processed.charCodeAt(i) & 255;
|
|
3274
|
+
return this.token(pos - 1, TOKEN.BYTES, bytes);
|
|
3275
|
+
}
|
|
3276
|
+
case "r":
|
|
3277
|
+
case "R": return this.token(pos - 1, TOKEN.STRING, rawValue);
|
|
3278
|
+
default: {
|
|
3279
|
+
const value = this.processEscapes(rawStart, rawValue, false);
|
|
3280
|
+
return this.token(pos, TOKEN.STRING, value);
|
|
3281
|
+
}
|
|
3282
|
+
}
|
|
3283
|
+
}
|
|
3284
|
+
readSingleQuotedString(delimiter, prefix) {
|
|
3285
|
+
const { input, length, pos: start } = this;
|
|
3286
|
+
let ch;
|
|
3287
|
+
let pos = this.pos + 1;
|
|
3288
|
+
while (pos < length && (ch = input[pos])) {
|
|
3289
|
+
switch (ch) {
|
|
3290
|
+
case delimiter:
|
|
3291
|
+
const rawStart = start + 1;
|
|
3292
|
+
const rawValue = input.slice(rawStart, pos);
|
|
3293
|
+
this.pos = ++pos;
|
|
3294
|
+
return this._closeQuotedString(rawStart, rawValue, prefix, start);
|
|
3295
|
+
case "\n":
|
|
3296
|
+
case "\r": throw parseError("newline_in_string", "Newlines not allowed in single-quoted strings", {
|
|
3297
|
+
pos,
|
|
3298
|
+
start: pos,
|
|
3299
|
+
end: pos + 1,
|
|
3300
|
+
input
|
|
3301
|
+
});
|
|
3302
|
+
case "\\": pos++;
|
|
3303
|
+
}
|
|
3304
|
+
pos++;
|
|
3305
|
+
}
|
|
3306
|
+
throw parseError("unterminated_string", "Unterminated string", {
|
|
3307
|
+
pos: start,
|
|
3308
|
+
start,
|
|
3309
|
+
end: input.length,
|
|
3310
|
+
input
|
|
3311
|
+
});
|
|
3312
|
+
}
|
|
3313
|
+
readTripleQuotedString(delimiter, prefix) {
|
|
3314
|
+
const { input, length, pos: start } = this;
|
|
3315
|
+
let ch;
|
|
3316
|
+
let pos = this.pos + 3;
|
|
3317
|
+
while (pos < length && (ch = input[pos])) {
|
|
3318
|
+
switch (ch) {
|
|
3319
|
+
case delimiter:
|
|
3320
|
+
if (input[pos + 1] === delimiter && input[pos + 2] === delimiter) {
|
|
3321
|
+
const rawStart = start + 3;
|
|
3322
|
+
const rawValue = input.slice(rawStart, pos);
|
|
3323
|
+
this.pos = pos + 3;
|
|
3324
|
+
return this._closeQuotedString(rawStart, rawValue, prefix, start);
|
|
3325
|
+
}
|
|
3326
|
+
break;
|
|
3327
|
+
case "\\": pos++;
|
|
3328
|
+
}
|
|
3329
|
+
pos++;
|
|
3330
|
+
}
|
|
3331
|
+
throw parseError("unterminated_triple_quoted_string", "Unterminated triple-quoted string", {
|
|
3332
|
+
pos: start,
|
|
3333
|
+
start,
|
|
3334
|
+
end: input.length,
|
|
3335
|
+
input
|
|
3336
|
+
});
|
|
3337
|
+
}
|
|
3338
|
+
#escapeErr(code, offset, len, i, chars, extra) {
|
|
3339
|
+
const start = offset + i;
|
|
3340
|
+
return parseError(code, ESCAPE_ERRORS[code](extra), {
|
|
3341
|
+
input: this.input,
|
|
3342
|
+
pos: start,
|
|
3343
|
+
start,
|
|
3344
|
+
end: Math.min(start + chars, offset + len)
|
|
3345
|
+
});
|
|
3346
|
+
}
|
|
3347
|
+
processEscapes(offset, str, isBytes) {
|
|
3348
|
+
if (!str.includes("\\")) return str;
|
|
3349
|
+
const len = str.length;
|
|
3350
|
+
let result = "";
|
|
3351
|
+
let i = 0;
|
|
3352
|
+
while (i < len) {
|
|
3353
|
+
if (str[i] !== "\\" || i + 1 >= len) {
|
|
3354
|
+
result += str[i++];
|
|
3355
|
+
continue;
|
|
3356
|
+
}
|
|
3357
|
+
const next = str[i + 1];
|
|
3358
|
+
if (STRING_ESCAPES[next]) {
|
|
3359
|
+
result += STRING_ESCAPES[next];
|
|
3360
|
+
i += 2;
|
|
3361
|
+
} else if (next === "u" || next === "U") {
|
|
3362
|
+
if (isBytes) throw this.#escapeErr("bytes_unicode_escape", offset, len, i, 2, next);
|
|
3363
|
+
const hexLen = next === "u" ? 4 : 8;
|
|
3364
|
+
const hex = str.substring(i + 2, i + 2 + hexLen);
|
|
3365
|
+
const c = Number.parseInt(hex, 16);
|
|
3366
|
+
if (hex.length !== hexLen || !/^[0-9a-fA-F]+$/.test(hex) || c > 1114111) throw this.#escapeErr("invalid_unicode_escape", offset, len, i, 2 + hexLen, next + hex);
|
|
3367
|
+
if (c >= 55296 && c <= 57343) throw this.#escapeErr("invalid_unicode_surrogate", offset, len, i, 2 + hexLen, next + hex);
|
|
3368
|
+
result += String.fromCodePoint(c);
|
|
3369
|
+
i += 2 + hexLen;
|
|
3370
|
+
} else if (next === "x" || next === "X") {
|
|
3371
|
+
const h = str.substring(i + 2, i + 4);
|
|
3372
|
+
if (!/^[0-9a-fA-F]{2}$/.test(h)) throw this.#escapeErr("invalid_hex_escape", offset, len, i, 4, next + h);
|
|
3373
|
+
result += String.fromCharCode(Number.parseInt(h, 16));
|
|
3374
|
+
i += 4;
|
|
3375
|
+
} else if (next >= "0" && next <= "7") {
|
|
3376
|
+
const o = str.substring(i + 1, i + 4);
|
|
3377
|
+
if (!/^[0-7]{3}$/.test(o)) throw this.#escapeErr("invalid_octal_escape", offset, len, i, 4);
|
|
3378
|
+
const value = Number.parseInt(o, 8);
|
|
3379
|
+
if (value > 255) throw this.#escapeErr("octal_escape_out_of_range", offset, len, i, 4, o);
|
|
3380
|
+
result += String.fromCharCode(value);
|
|
3381
|
+
i += 4;
|
|
3382
|
+
} else throw this.#escapeErr("invalid_escape_sequence", offset, len, i, 2, next);
|
|
3383
|
+
}
|
|
3384
|
+
return result;
|
|
3385
|
+
}
|
|
3386
|
+
readIdentifier() {
|
|
3387
|
+
const { pos, input, length } = this;
|
|
3388
|
+
let p = pos;
|
|
3389
|
+
while (p < length && this._isIdentifierCharCode(input[p].charCodeAt(0))) p++;
|
|
3390
|
+
const value = input.substring(pos, this.pos = p);
|
|
3391
|
+
switch (value) {
|
|
3392
|
+
case "true": return this.token(pos, TOKEN.BOOLEAN, true);
|
|
3393
|
+
case "false": return this.token(pos, TOKEN.BOOLEAN, false);
|
|
3394
|
+
case "null": return this.token(pos, TOKEN.NULL, null);
|
|
3395
|
+
case "in": return this.token(pos, TOKEN.IN);
|
|
3396
|
+
default: return this.token(pos, TOKEN.IDENTIFIER, value);
|
|
3397
|
+
}
|
|
3398
|
+
}
|
|
3399
|
+
};
|
|
3400
|
+
const globalLexer = new Lexer();
|
|
3401
|
+
var Parser = class {
|
|
3402
|
+
lexer = globalLexer;
|
|
3403
|
+
input = null;
|
|
3404
|
+
maxDepthRemaining = null;
|
|
3405
|
+
astNodesRemaining = null;
|
|
3406
|
+
type = null;
|
|
3407
|
+
pos = null;
|
|
3408
|
+
constructor(limits, registry) {
|
|
3409
|
+
this.limits = limits;
|
|
3410
|
+
this.registry = registry;
|
|
3411
|
+
}
|
|
3412
|
+
#limitExceeded(limitKey, pos = this.pos) {
|
|
3413
|
+
throw parseError("limit_exceeded", `Exceeded ${limitKey} (${this.limits[limitKey]})`, {
|
|
3414
|
+
pos,
|
|
3415
|
+
start: pos,
|
|
3416
|
+
end: pos,
|
|
3417
|
+
input: this.input
|
|
3418
|
+
});
|
|
3419
|
+
}
|
|
3420
|
+
#node(start, end, op, args, pos = start) {
|
|
3421
|
+
const node = new ASTNode(this.input, pos, start, end, op, args);
|
|
3422
|
+
if (!this.astNodesRemaining--) this.#limitExceeded("maxAstNodes", pos);
|
|
3423
|
+
return node;
|
|
3424
|
+
}
|
|
3425
|
+
#infixNode(op, left, right) {
|
|
3426
|
+
return this.#node(left.start, right.end, op, [left, right]);
|
|
3427
|
+
}
|
|
3428
|
+
#ternaryNode(expression, consequent, alternate) {
|
|
3429
|
+
return this.#node(expression.start, alternate.end, OPERATORS.ternary, [
|
|
3430
|
+
expression,
|
|
3431
|
+
consequent,
|
|
3432
|
+
alternate
|
|
3433
|
+
]);
|
|
3434
|
+
}
|
|
3435
|
+
#unaryNode(pos, op, arg) {
|
|
3436
|
+
return this.#node(pos, arg.end, op, arg);
|
|
3437
|
+
}
|
|
3438
|
+
#accessNode(op, left, right, end, pos = left.start) {
|
|
3439
|
+
return this.#node(left.start, end, op, [left, right], pos);
|
|
3440
|
+
}
|
|
3441
|
+
#advanceToken(returnValue = this.pos) {
|
|
3442
|
+
const l = this.lexer.nextToken();
|
|
3443
|
+
this.pos = l.tokenPos;
|
|
3444
|
+
this.type = l.tokenType;
|
|
3445
|
+
return returnValue;
|
|
3446
|
+
}
|
|
3447
|
+
get value() {
|
|
3448
|
+
return this.lexer.tokenValue;
|
|
3449
|
+
}
|
|
3450
|
+
consume(expectedType) {
|
|
3451
|
+
if (this.type === expectedType) return this.#advanceToken();
|
|
3452
|
+
throw parseError("expected_token", `Expected ${TOKEN_BY_NUMBER[expectedType]}, got ${TOKEN_BY_NUMBER[this.type]}`, {
|
|
3453
|
+
pos: this.pos,
|
|
3454
|
+
start: this.pos,
|
|
3455
|
+
end: this.lexer.pos,
|
|
3456
|
+
input: this.input
|
|
3457
|
+
});
|
|
3458
|
+
}
|
|
3459
|
+
match(type) {
|
|
3460
|
+
return this.type === type;
|
|
3461
|
+
}
|
|
3462
|
+
parse(input) {
|
|
3463
|
+
if (typeof input !== "string") throw parseError("expression_must_be_string", "Expression must be a string");
|
|
3464
|
+
this.input = this.lexer.reset(input);
|
|
3465
|
+
this.#advanceToken();
|
|
3466
|
+
this.maxDepthRemaining = this.limits.maxDepth;
|
|
3467
|
+
this.astNodesRemaining = this.limits.maxAstNodes;
|
|
3468
|
+
const result = this.parseExpression();
|
|
3469
|
+
if (this.match(TOKEN.EOF)) return result;
|
|
3470
|
+
throw parseError("unexpected_character", `Unexpected character: '${this.input[this.lexer.pos - 1]}'`, {
|
|
3471
|
+
pos: this.pos,
|
|
3472
|
+
start: this.pos,
|
|
3473
|
+
end: this.lexer.pos,
|
|
3474
|
+
input: this.input
|
|
3475
|
+
});
|
|
3476
|
+
}
|
|
3477
|
+
#expandMacro(start, end, op, args) {
|
|
3478
|
+
const methodName = args[0];
|
|
3479
|
+
const receiver = op === OPERATORS.rcall ? args[1] : null;
|
|
3480
|
+
const fnArgs = op === OPERATORS.rcall ? args[2] : args[1];
|
|
3481
|
+
const decl = this.registry.findMacro(methodName, !!receiver, fnArgs.length);
|
|
3482
|
+
const ast = this.#node(start, end, op, args);
|
|
3483
|
+
if (!decl) return ast;
|
|
3484
|
+
const macro = decl.handler({
|
|
3485
|
+
ast,
|
|
3486
|
+
args: fnArgs,
|
|
3487
|
+
receiver,
|
|
3488
|
+
methodName,
|
|
3489
|
+
parser: this
|
|
3490
|
+
});
|
|
3491
|
+
if (macro.callAst) return ast.setMeta("alternate", macro.callAst);
|
|
3492
|
+
return ast.setMeta("macro", macro).setMeta("async", isAsync(macro.evaluate, macro.async));
|
|
3493
|
+
}
|
|
3494
|
+
parseExpression() {
|
|
3495
|
+
if (!this.maxDepthRemaining--) this.#limitExceeded("maxDepth");
|
|
3496
|
+
const expr = this.parseLogicalOr();
|
|
3497
|
+
if (!this.match(TOKEN.QUESTION)) return ++this.maxDepthRemaining && expr;
|
|
3498
|
+
this.#advanceToken();
|
|
3499
|
+
const consequent = this.parseExpression();
|
|
3500
|
+
this.consume(TOKEN.COLON);
|
|
3501
|
+
const alternate = this.parseExpression();
|
|
3502
|
+
this.maxDepthRemaining++;
|
|
3503
|
+
return this.#ternaryNode(expr, consequent, alternate);
|
|
3504
|
+
}
|
|
3505
|
+
parseLogicalOr() {
|
|
3506
|
+
let expr = this.parseLogicalAnd();
|
|
3507
|
+
while (this.match(TOKEN.OR)) {
|
|
3508
|
+
this.#advanceToken();
|
|
3509
|
+
expr = this.#infixNode(OPERATORS["||"], expr, this.parseLogicalAnd());
|
|
3510
|
+
}
|
|
3511
|
+
return expr;
|
|
3512
|
+
}
|
|
3513
|
+
parseLogicalAnd() {
|
|
3514
|
+
let expr = this.parseEquality();
|
|
3515
|
+
while (this.match(TOKEN.AND)) {
|
|
3516
|
+
this.#advanceToken();
|
|
3517
|
+
expr = this.#infixNode(OPERATORS["&&"], expr, this.parseEquality());
|
|
3518
|
+
}
|
|
3519
|
+
return expr;
|
|
3520
|
+
}
|
|
3521
|
+
parseEquality() {
|
|
3522
|
+
let expr = this.parseRelational();
|
|
3523
|
+
while (this.match(TOKEN.EQ) || this.match(TOKEN.NE)) {
|
|
3524
|
+
const op = OP_FOR_TOKEN[this.type];
|
|
3525
|
+
this.#advanceToken();
|
|
3526
|
+
expr = this.#infixNode(op, expr, this.parseRelational());
|
|
3527
|
+
}
|
|
3528
|
+
return expr;
|
|
3529
|
+
}
|
|
3530
|
+
parseRelational() {
|
|
3531
|
+
let expr = this.parseAdditive();
|
|
3532
|
+
while (this.match(TOKEN.LT) || this.match(TOKEN.LE) || this.match(TOKEN.GT) || this.match(TOKEN.GE) || this.match(TOKEN.IN)) {
|
|
3533
|
+
const op = OP_FOR_TOKEN[this.type];
|
|
3534
|
+
this.#advanceToken();
|
|
3535
|
+
expr = this.#infixNode(op, expr, this.parseAdditive());
|
|
3536
|
+
}
|
|
3537
|
+
return expr;
|
|
3538
|
+
}
|
|
3539
|
+
parseAdditive() {
|
|
3540
|
+
let expr = this.parseMultiplicative();
|
|
3541
|
+
while (this.match(TOKEN.PLUS) || this.match(TOKEN.MINUS)) {
|
|
3542
|
+
const op = OP_FOR_TOKEN[this.type];
|
|
3543
|
+
this.#advanceToken();
|
|
3544
|
+
expr = this.#infixNode(op, expr, this.parseMultiplicative());
|
|
3545
|
+
}
|
|
3546
|
+
return expr;
|
|
3547
|
+
}
|
|
3548
|
+
parseMultiplicative() {
|
|
3549
|
+
let expr = this.parseUnary();
|
|
3550
|
+
while (this.match(TOKEN.MULTIPLY) || this.match(TOKEN.DIVIDE) || this.match(TOKEN.MODULO)) {
|
|
3551
|
+
const op = OP_FOR_TOKEN[this.type];
|
|
3552
|
+
this.#advanceToken();
|
|
3553
|
+
expr = this.#infixNode(op, expr, this.parseUnary());
|
|
3554
|
+
}
|
|
3555
|
+
return expr;
|
|
3556
|
+
}
|
|
3557
|
+
parseUnary() {
|
|
3558
|
+
if (this.type === TOKEN.NOT) return this.#unaryNode(this.#advanceToken(), OPERATORS.unaryNot, this.parseUnary());
|
|
3559
|
+
if (this.type === TOKEN.MINUS) return this.#unaryNode(this.#advanceToken(), OPERATORS.unaryMinus, this.parseUnary());
|
|
3560
|
+
return this.parsePostfix();
|
|
3561
|
+
}
|
|
3562
|
+
parsePostfix() {
|
|
3563
|
+
let expr = this.parsePrimary();
|
|
3564
|
+
const depth = this.maxDepthRemaining;
|
|
3565
|
+
while (true) {
|
|
3566
|
+
if (this.match(TOKEN.DOT)) {
|
|
3567
|
+
const dot = this.#advanceToken();
|
|
3568
|
+
if (!this.maxDepthRemaining--) this.#limitExceeded("maxDepth", dot);
|
|
3569
|
+
const op = this.match(TOKEN.QUESTION) && this.registry.enableOptionalTypes && this.#advanceToken() ? OPERATORS.optionalFieldAccess : OPERATORS.fieldAccess;
|
|
3570
|
+
const propertyValue = this.value;
|
|
3571
|
+
const start = this.pos;
|
|
3572
|
+
const end = this.lexer.pos;
|
|
3573
|
+
this.consume(TOKEN.IDENTIFIER);
|
|
3574
|
+
if (op === OPERATORS.fieldAccess && this.match(TOKEN.LPAREN) && this.#advanceToken()) {
|
|
3575
|
+
const args = this.parseArgumentList();
|
|
3576
|
+
const closeEnd = this.lexer.pos;
|
|
3577
|
+
this.consume(TOKEN.RPAREN);
|
|
3578
|
+
expr = this.#expandMacro(expr.start, closeEnd, OPERATORS.rcall, [
|
|
3579
|
+
propertyValue,
|
|
3580
|
+
expr,
|
|
3581
|
+
args
|
|
3582
|
+
]);
|
|
3583
|
+
} else expr = this.#accessNode(op, expr, propertyValue, end, start);
|
|
3584
|
+
continue;
|
|
3585
|
+
}
|
|
3586
|
+
if (this.match(TOKEN.LBRACKET)) {
|
|
3587
|
+
const bracket = this.#advanceToken();
|
|
3588
|
+
if (!this.maxDepthRemaining--) this.#limitExceeded("maxDepth", bracket);
|
|
3589
|
+
const op = this.match(TOKEN.QUESTION) && this.registry.enableOptionalTypes && this.#advanceToken() ? OPERATORS.optionalBracketAccess : OPERATORS.bracketAccess;
|
|
3590
|
+
const index = this.parseExpression();
|
|
3591
|
+
const closeEnd = this.lexer.pos;
|
|
3592
|
+
this.consume(TOKEN.RBRACKET);
|
|
3593
|
+
expr = this.#accessNode(op, expr, index, closeEnd);
|
|
3594
|
+
continue;
|
|
3595
|
+
}
|
|
3596
|
+
break;
|
|
3597
|
+
}
|
|
3598
|
+
this.maxDepthRemaining = depth;
|
|
3599
|
+
return expr;
|
|
3600
|
+
}
|
|
3601
|
+
parsePrimary() {
|
|
3602
|
+
switch (this.type) {
|
|
3603
|
+
case TOKEN.NUMBER:
|
|
3604
|
+
case TOKEN.STRING:
|
|
3605
|
+
case TOKEN.BYTES:
|
|
3606
|
+
case TOKEN.BOOLEAN:
|
|
3607
|
+
case TOKEN.NULL: return this.#consumeLiteral();
|
|
3608
|
+
case TOKEN.IDENTIFIER: return this.#parseIdentifierPrimary();
|
|
3609
|
+
case TOKEN.LPAREN: return this.#parseParenthesizedExpression();
|
|
3610
|
+
case TOKEN.LBRACKET: return this.parseList();
|
|
3611
|
+
case TOKEN.LBRACE: return this.parseMap();
|
|
3612
|
+
}
|
|
3613
|
+
throw parseError("unexpected_token", `Unexpected token: ${TOKEN_BY_NUMBER[this.type]}`, {
|
|
3614
|
+
pos: this.pos,
|
|
3615
|
+
start: this.pos,
|
|
3616
|
+
end: this.lexer.pos,
|
|
3617
|
+
input: this.input
|
|
3618
|
+
});
|
|
3619
|
+
}
|
|
3620
|
+
#consumeLiteral() {
|
|
3621
|
+
return this.#advanceToken(this.#node(this.pos, this.lexer.pos, OPERATORS.value, this.value));
|
|
3622
|
+
}
|
|
3623
|
+
#parseIdentifierPrimary() {
|
|
3624
|
+
const value = this.value;
|
|
3625
|
+
const end = this.lexer.pos;
|
|
3626
|
+
const start = this.consume(TOKEN.IDENTIFIER);
|
|
3627
|
+
if (RESERVED.has(value)) throw parseError("reserved_identifier", `Reserved identifier: ${value}`, {
|
|
3628
|
+
pos: start,
|
|
3629
|
+
start,
|
|
3630
|
+
end,
|
|
3631
|
+
input: this.input
|
|
3632
|
+
});
|
|
3633
|
+
if (!this.match(TOKEN.LPAREN)) return this.#node(start, end, OPERATORS.id, value);
|
|
3634
|
+
this.#advanceToken();
|
|
3635
|
+
const args = this.parseArgumentList();
|
|
3636
|
+
const closeEnd = this.lexer.pos;
|
|
3637
|
+
this.consume(TOKEN.RPAREN);
|
|
3638
|
+
return this.#expandMacro(start, closeEnd, OPERATORS.call, [value, args]);
|
|
3639
|
+
}
|
|
3640
|
+
#parseParenthesizedExpression() {
|
|
3641
|
+
this.consume(TOKEN.LPAREN);
|
|
3642
|
+
const expr = this.parseExpression();
|
|
3643
|
+
this.consume(TOKEN.RPAREN);
|
|
3644
|
+
return expr;
|
|
3645
|
+
}
|
|
3646
|
+
parseList() {
|
|
3647
|
+
const start = this.consume(TOKEN.LBRACKET);
|
|
3648
|
+
const elements = [];
|
|
3649
|
+
let remainingElements = this.limits.maxListElements;
|
|
3650
|
+
if (!this.match(TOKEN.RBRACKET)) {
|
|
3651
|
+
elements.push(this.parseExpression());
|
|
3652
|
+
if (!remainingElements--) this.#limitExceeded("maxListElements", elements.at(-1).pos);
|
|
3653
|
+
while (this.match(TOKEN.COMMA)) {
|
|
3654
|
+
this.#advanceToken();
|
|
3655
|
+
if (this.match(TOKEN.RBRACKET)) break;
|
|
3656
|
+
elements.push(this.parseExpression());
|
|
3657
|
+
if (!remainingElements--) this.#limitExceeded("maxListElements", elements.at(-1).pos);
|
|
3658
|
+
}
|
|
3659
|
+
}
|
|
3660
|
+
const closeEnd = this.lexer.pos;
|
|
3661
|
+
this.consume(TOKEN.RBRACKET);
|
|
3662
|
+
return this.#node(start, closeEnd, OPERATORS.list, elements);
|
|
3663
|
+
}
|
|
3664
|
+
parseMap() {
|
|
3665
|
+
const start = this.consume(TOKEN.LBRACE);
|
|
3666
|
+
const props = [];
|
|
3667
|
+
let remainingEntries = this.limits.maxMapEntries;
|
|
3668
|
+
if (!this.match(TOKEN.RBRACE)) {
|
|
3669
|
+
props.push(this.parseProperty());
|
|
3670
|
+
if (!remainingEntries--) this.#limitExceeded("maxMapEntries", props.at(-1)[0].pos);
|
|
3671
|
+
while (this.match(TOKEN.COMMA)) {
|
|
3672
|
+
this.#advanceToken();
|
|
3673
|
+
if (this.match(TOKEN.RBRACE)) break;
|
|
3674
|
+
props.push(this.parseProperty());
|
|
3675
|
+
if (!remainingEntries--) this.#limitExceeded("maxMapEntries", props.at(-1)[0].pos);
|
|
3676
|
+
}
|
|
3677
|
+
}
|
|
3678
|
+
const closeEnd = this.lexer.pos;
|
|
3679
|
+
this.consume(TOKEN.RBRACE);
|
|
3680
|
+
return this.#node(start, closeEnd, OPERATORS.map, props);
|
|
3681
|
+
}
|
|
3682
|
+
parseProperty() {
|
|
3683
|
+
return [this.parseExpression(), (this.consume(TOKEN.COLON), this.parseExpression())];
|
|
3684
|
+
}
|
|
3685
|
+
parseArgumentList() {
|
|
3686
|
+
const args = [];
|
|
3687
|
+
let remainingArgs = this.limits.maxCallArguments;
|
|
3688
|
+
if (!this.match(TOKEN.RPAREN)) {
|
|
3689
|
+
args.push(this.parseExpression());
|
|
3690
|
+
if (!remainingArgs--) this.#limitExceeded("maxCallArguments", args.at(-1).pos);
|
|
3691
|
+
while (this.match(TOKEN.COMMA)) {
|
|
3692
|
+
this.#advanceToken();
|
|
3693
|
+
if (this.match(TOKEN.RPAREN)) break;
|
|
3694
|
+
args.push(this.parseExpression());
|
|
3695
|
+
if (!remainingArgs--) this.#limitExceeded("maxCallArguments", args.at(-1).pos);
|
|
3696
|
+
}
|
|
3697
|
+
}
|
|
3698
|
+
return args;
|
|
3699
|
+
}
|
|
3700
|
+
};
|
|
3701
|
+
const DEFAULT_LIMITS = objFreeze({
|
|
3702
|
+
maxAstNodes: 1e5,
|
|
3703
|
+
maxDepth: 250,
|
|
3704
|
+
maxListElements: 1e3,
|
|
3705
|
+
maxMapEntries: 1e3,
|
|
3706
|
+
maxCallArguments: 32
|
|
3707
|
+
});
|
|
3708
|
+
const LIMIT_KEYS = new Set(objKeys(DEFAULT_LIMITS));
|
|
3709
|
+
function createLimits(overrides, base = DEFAULT_LIMITS) {
|
|
3710
|
+
const keys = overrides ? objKeys(overrides) : void 0;
|
|
3711
|
+
if (!keys?.length) return base;
|
|
3712
|
+
const merged = { ...base };
|
|
3713
|
+
for (const key of keys) {
|
|
3714
|
+
if (!LIMIT_KEYS.has(key)) throw new TypeError(`Unknown limits option: ${key}`);
|
|
3715
|
+
const value = overrides[key];
|
|
3716
|
+
if (typeof value !== "number") continue;
|
|
3717
|
+
merged[key] = value;
|
|
3718
|
+
}
|
|
3719
|
+
return objFreeze(merged);
|
|
3720
|
+
}
|
|
3721
|
+
const DEFAULT_OPTIONS = objFreeze({
|
|
3722
|
+
unlistedVariablesAreDyn: false,
|
|
3723
|
+
homogeneousAggregateLiterals: true,
|
|
3724
|
+
enableOptionalTypes: false,
|
|
3725
|
+
limits: DEFAULT_LIMITS
|
|
3726
|
+
});
|
|
3727
|
+
function bool(a, b, key) {
|
|
3728
|
+
const value = a?.[key] ?? b?.[key];
|
|
3729
|
+
if (typeof value !== "boolean") throw new TypeError(`Invalid option: ${key}`);
|
|
3730
|
+
return value;
|
|
3731
|
+
}
|
|
3732
|
+
function createOptions(opts, base = DEFAULT_OPTIONS) {
|
|
3733
|
+
if (!opts) return base;
|
|
3734
|
+
return objFreeze({
|
|
3735
|
+
unlistedVariablesAreDyn: bool(opts, base, "unlistedVariablesAreDyn"),
|
|
3736
|
+
homogeneousAggregateLiterals: bool(opts, base, "homogeneousAggregateLiterals"),
|
|
3737
|
+
enableOptionalTypes: bool(opts, base, "enableOptionalTypes"),
|
|
3738
|
+
limits: createLimits(opts.limits, base.limits)
|
|
3739
|
+
});
|
|
3740
|
+
}
|
|
3741
|
+
const globalRegistry = createRegistry({ enableOptionalTypes: false });
|
|
3742
|
+
registerFunctions(globalRegistry);
|
|
3743
|
+
registerOverloads(globalRegistry);
|
|
3744
|
+
registerMacros(globalRegistry);
|
|
3745
|
+
var Environment = class Environment {
|
|
3746
|
+
#registry;
|
|
3747
|
+
#evaluator;
|
|
3748
|
+
#typeChecker;
|
|
3749
|
+
#evalTypeChecker;
|
|
3750
|
+
#parser;
|
|
3751
|
+
constructor(opts, inherited) {
|
|
3752
|
+
this.opts = createOptions(opts, inherited?.opts);
|
|
3753
|
+
this.#registry = (inherited instanceof Environment ? inherited.#registry : globalRegistry).clone(this.opts);
|
|
3754
|
+
const childOpts = {
|
|
3755
|
+
registry: this.#registry,
|
|
3756
|
+
opts: this.opts
|
|
3757
|
+
};
|
|
3758
|
+
this.#typeChecker = new TypeChecker(childOpts);
|
|
3759
|
+
this.#evalTypeChecker = new TypeChecker(childOpts, true);
|
|
3760
|
+
this.#evaluator = new Evaluator(childOpts);
|
|
3761
|
+
this.#parser = new Parser(this.opts.limits, this.#registry);
|
|
3762
|
+
Object.freeze(this);
|
|
3763
|
+
}
|
|
3764
|
+
clone(opts) {
|
|
3765
|
+
return new Environment(opts, this);
|
|
3766
|
+
}
|
|
3767
|
+
registerFunction(signature, handler, opts) {
|
|
3768
|
+
this.#registry.registerFunctionOverload(signature, handler, opts);
|
|
3769
|
+
return this;
|
|
3770
|
+
}
|
|
3771
|
+
registerOperator(string, handler, opts) {
|
|
3772
|
+
this.#registry.registerOperatorOverload(string, handler, opts);
|
|
3773
|
+
return this;
|
|
3774
|
+
}
|
|
3775
|
+
registerType(typename, constructor) {
|
|
3776
|
+
this.#registry.registerType(typename, constructor);
|
|
3777
|
+
return this;
|
|
3778
|
+
}
|
|
3779
|
+
registerVariable(name, type, opts) {
|
|
3780
|
+
this.#registry.registerVariable(name, type, opts);
|
|
3781
|
+
return this;
|
|
3782
|
+
}
|
|
3783
|
+
registerConstant(name, type, value) {
|
|
3784
|
+
this.#registry.registerConstant(name, type, value);
|
|
3785
|
+
return this;
|
|
3786
|
+
}
|
|
3787
|
+
hasVariable(name) {
|
|
3788
|
+
return this.#registry.variables.has(name);
|
|
3789
|
+
}
|
|
3790
|
+
getDefinitions() {
|
|
3791
|
+
return this.#registry.getDefinitions();
|
|
3792
|
+
}
|
|
3793
|
+
check(expression) {
|
|
3794
|
+
try {
|
|
3795
|
+
return this.#checkAST(this.#parser.parse(expression));
|
|
3796
|
+
} catch (error) {
|
|
3797
|
+
return {
|
|
3798
|
+
valid: false,
|
|
3799
|
+
error
|
|
3800
|
+
};
|
|
3801
|
+
}
|
|
3802
|
+
}
|
|
3803
|
+
#checkAST(ast) {
|
|
3804
|
+
try {
|
|
3805
|
+
const typeDecl = this.#typeChecker.check(ast, new RootContext(this.#registry));
|
|
3806
|
+
return {
|
|
3807
|
+
valid: true,
|
|
3808
|
+
type: this.#formatTypeForCheck(typeDecl)
|
|
3809
|
+
};
|
|
3810
|
+
} catch (error) {
|
|
3811
|
+
return {
|
|
3812
|
+
valid: false,
|
|
3813
|
+
error
|
|
3814
|
+
};
|
|
3815
|
+
}
|
|
3816
|
+
}
|
|
3817
|
+
#formatTypeForCheck(typeDecl) {
|
|
3818
|
+
if (typeDecl.name === `list<dyn>`) return "list";
|
|
3819
|
+
if (typeDecl.name === `map<dyn, dyn>`) return "map";
|
|
3820
|
+
return typeDecl.name;
|
|
3821
|
+
}
|
|
3822
|
+
parse(expression) {
|
|
3823
|
+
const ast = this.#parser.parse(expression);
|
|
3824
|
+
const evaluateParsed = this.#evaluateAST.bind(this, ast);
|
|
3825
|
+
evaluateParsed.check = this.#checkAST.bind(this, ast);
|
|
3826
|
+
evaluateParsed.ast = ast;
|
|
3827
|
+
return evaluateParsed;
|
|
3828
|
+
}
|
|
3829
|
+
evaluate(expression, context) {
|
|
3830
|
+
return this.#evaluateAST(this.#parser.parse(expression), context);
|
|
3831
|
+
}
|
|
3832
|
+
#evaluateAST(ast, ctx) {
|
|
3833
|
+
if (ast.checkedType) return ast.evaluate(this.#evaluator, ast, new RootContext(this.#registry, ctx));
|
|
3834
|
+
else {
|
|
3835
|
+
this.#evalTypeChecker.check(ast, ctx = new RootContext(this.#registry, ctx));
|
|
3836
|
+
return ast.evaluate(this.#evaluator, ast, ctx);
|
|
3837
|
+
}
|
|
3838
|
+
}
|
|
3839
|
+
};
|
|
3840
|
+
var Evaluator = class extends Base {
|
|
3841
|
+
constructor(opts) {
|
|
3842
|
+
super(opts);
|
|
3843
|
+
this.createError = evaluationError;
|
|
3844
|
+
}
|
|
3845
|
+
#firstMapElement(coll) {
|
|
3846
|
+
if (coll instanceof Map) return coll.entries().next().value;
|
|
3847
|
+
for (const key in coll) return [key, coll[key]];
|
|
3848
|
+
}
|
|
3849
|
+
debugRuntimeType(value, checkedType) {
|
|
3850
|
+
return checkedType?.hasDynType === false ? checkedType : this.debugTypeDeep(value);
|
|
3851
|
+
}
|
|
3852
|
+
debugTypeDeep(value) {
|
|
3853
|
+
const runtimeType = this.debugType(value);
|
|
3854
|
+
switch (runtimeType.kind) {
|
|
3855
|
+
case "list": {
|
|
3856
|
+
const first = value instanceof Array ? value[0] : value.values().next().value;
|
|
3857
|
+
if (first === void 0) return runtimeType;
|
|
3858
|
+
return this.registry.getListType(this.debugTypeDeep(first));
|
|
3859
|
+
}
|
|
3860
|
+
case "map": {
|
|
3861
|
+
const first = this.#firstMapElement(value);
|
|
3862
|
+
if (!first) return runtimeType;
|
|
3863
|
+
return this.registry.getMapType(runtimeType.keyType.hasDynType ? this.debugTypeDeep(first[0]) : runtimeType.keyType, runtimeType.valueType.hasDynType ? this.debugTypeDeep(first[1]) : runtimeType.valueType);
|
|
3864
|
+
}
|
|
3865
|
+
default: return runtimeType;
|
|
3866
|
+
}
|
|
3867
|
+
}
|
|
3868
|
+
tryEval(ast, ctx) {
|
|
3869
|
+
try {
|
|
3870
|
+
const res = this.run(ast, ctx);
|
|
3871
|
+
if (res instanceof Promise) return res.catch((err) => err);
|
|
3872
|
+
return res;
|
|
3873
|
+
} catch (err) {
|
|
3874
|
+
return err;
|
|
3875
|
+
}
|
|
3876
|
+
}
|
|
3877
|
+
run(ast, ctx) {
|
|
3878
|
+
return ast.evaluate(this, ast, ctx);
|
|
3879
|
+
}
|
|
3880
|
+
};
|
|
3881
|
+
new Environment({ unlistedVariablesAreDyn: true });
|
|
3882
|
+
export { Environment };
|
|
3883
|
+
|
|
3884
|
+
//# sourceMappingURL=lib-CqHwM4m_.js.map
|