@creationix/rex 0.3.0 → 0.4.1
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/package.json +3 -2
- package/rex-cli.js +730 -285
- package/rex-cli.ts +34 -13
- package/rex-repl.js +695 -270
- package/rex-repl.ts +39 -5
- package/rex.js +370 -188
- package/rex.ohm +73 -25
- package/rex.ohm-bundle.cjs +1 -1
- package/rex.ohm-bundle.d.ts +31 -8
- package/rex.ohm-bundle.js +1 -1
- package/rex.ts +390 -206
- package/rexc-interpreter.ts +277 -90
package/rex.js
CHANGED
|
@@ -10,31 +10,32 @@ function byteLength(value) {
|
|
|
10
10
|
return Buffer.byteLength(value, "utf8");
|
|
11
11
|
}
|
|
12
12
|
var OPCODE_IDS = {
|
|
13
|
-
do:
|
|
14
|
-
add:
|
|
15
|
-
sub:
|
|
16
|
-
mul:
|
|
17
|
-
div:
|
|
18
|
-
eq:
|
|
19
|
-
neq:
|
|
20
|
-
lt:
|
|
21
|
-
lte:
|
|
22
|
-
gt:
|
|
23
|
-
gte:
|
|
24
|
-
and:
|
|
25
|
-
or:
|
|
26
|
-
xor:
|
|
27
|
-
not:
|
|
28
|
-
boolean:
|
|
29
|
-
number:
|
|
30
|
-
string:
|
|
31
|
-
array:
|
|
32
|
-
object:
|
|
33
|
-
mod:
|
|
34
|
-
neg:
|
|
13
|
+
do: "",
|
|
14
|
+
add: "ad",
|
|
15
|
+
sub: "sb",
|
|
16
|
+
mul: "ml",
|
|
17
|
+
div: "dv",
|
|
18
|
+
eq: "eq",
|
|
19
|
+
neq: "nq",
|
|
20
|
+
lt: "lt",
|
|
21
|
+
lte: "le",
|
|
22
|
+
gt: "gt",
|
|
23
|
+
gte: "ge",
|
|
24
|
+
and: "an",
|
|
25
|
+
or: "or",
|
|
26
|
+
xor: "xr",
|
|
27
|
+
not: "nt",
|
|
28
|
+
boolean: "bt",
|
|
29
|
+
number: "nm",
|
|
30
|
+
string: "st",
|
|
31
|
+
array: "ar",
|
|
32
|
+
object: "ob",
|
|
33
|
+
mod: "md",
|
|
34
|
+
neg: "ng",
|
|
35
|
+
range: "rn",
|
|
36
|
+
size: "sz"
|
|
35
37
|
};
|
|
36
|
-
var
|
|
37
|
-
var DOMAIN_DIGIT_INDEX = new Map(Array.from(DIGITS).map((char, index) => [char, index]));
|
|
38
|
+
var KEYWORD_OPCODES = new Set(["boolean", "number", "string", "array", "object", "size"]);
|
|
38
39
|
var BINARY_TO_OPCODE = {
|
|
39
40
|
add: "add",
|
|
40
41
|
sub: "sub",
|
|
@@ -147,12 +148,33 @@ function encodeBareOrLengthString(value) {
|
|
|
147
148
|
return `${value}:`;
|
|
148
149
|
return `${encodeUint(byteLength(value))},${value}`;
|
|
149
150
|
}
|
|
151
|
+
var DEC_PARTS = /^(-?\d)(?:\.(\d+))?e([+-]\d+)$/;
|
|
152
|
+
function splitDecimal(num) {
|
|
153
|
+
const match = num.toExponential().match(DEC_PARTS);
|
|
154
|
+
if (!match)
|
|
155
|
+
throw new Error(`Failed to split decimal for ${num}`);
|
|
156
|
+
const [, b1, b2 = "", e1] = match;
|
|
157
|
+
const base = Number.parseInt(b1 + b2, 10);
|
|
158
|
+
const exp = Number.parseInt(e1, 10) - b2.length;
|
|
159
|
+
return { base, exp };
|
|
160
|
+
}
|
|
161
|
+
function encodeDecimal(significand, power) {
|
|
162
|
+
return `${encodeZigzag(power)}*${encodeInt(significand)}`;
|
|
163
|
+
}
|
|
150
164
|
function encodeNumberNode(node) {
|
|
151
165
|
const numberValue = node.value;
|
|
152
|
-
if (
|
|
153
|
-
|
|
154
|
-
if (
|
|
155
|
-
return
|
|
166
|
+
if (Number.isNaN(numberValue))
|
|
167
|
+
return "nan'";
|
|
168
|
+
if (numberValue === Infinity)
|
|
169
|
+
return "inf'";
|
|
170
|
+
if (numberValue === -Infinity)
|
|
171
|
+
return "nif'";
|
|
172
|
+
if (Number.isInteger(numberValue)) {
|
|
173
|
+
const { base, exp } = splitDecimal(numberValue);
|
|
174
|
+
if (exp >= 0 && exp <= 4)
|
|
175
|
+
return encodeInt(numberValue);
|
|
176
|
+
return encodeDecimal(base, exp);
|
|
177
|
+
}
|
|
156
178
|
const raw = node.raw.toLowerCase();
|
|
157
179
|
const sign = raw.startsWith("-") ? -1 : 1;
|
|
158
180
|
const unsigned = sign < 0 ? raw.slice(1) : raw;
|
|
@@ -175,10 +197,10 @@ function encodeNumberNode(node) {
|
|
|
175
197
|
significand /= 10;
|
|
176
198
|
power += 1;
|
|
177
199
|
}
|
|
178
|
-
return
|
|
200
|
+
return encodeDecimal(significand, power);
|
|
179
201
|
}
|
|
180
202
|
function encodeOpcode(opcode) {
|
|
181
|
-
return `${
|
|
203
|
+
return `${OPCODE_IDS[opcode]}%`;
|
|
182
204
|
}
|
|
183
205
|
function encodeCallParts(parts) {
|
|
184
206
|
return `(${parts.join("")})`;
|
|
@@ -195,7 +217,7 @@ function addOptionalPrefix(encoded) {
|
|
|
195
217
|
let payload = encoded;
|
|
196
218
|
if (encoded.startsWith("?(") || encoded.startsWith("!(") || encoded.startsWith("|(") || encoded.startsWith("&(") || encoded.startsWith(">(") || encoded.startsWith("<(") || encoded.startsWith("#(")) {
|
|
197
219
|
payload = encoded.slice(2, -1);
|
|
198
|
-
} else if (encoded.startsWith(">[") || encoded.startsWith(">{")) {
|
|
220
|
+
} else if (encoded.startsWith(">[") || encoded.startsWith(">{") || encoded.startsWith("<[") || encoded.startsWith("<{") || encoded.startsWith("#[") || encoded.startsWith("#{")) {
|
|
199
221
|
payload = encoded.slice(2, -1);
|
|
200
222
|
} else if (encoded.startsWith("[") || encoded.startsWith("{") || encoded.startsWith("(")) {
|
|
201
223
|
payload = encoded.slice(1, -1);
|
|
@@ -206,7 +228,7 @@ function addOptionalPrefix(encoded) {
|
|
|
206
228
|
}
|
|
207
229
|
function encodeBlockExpression(block) {
|
|
208
230
|
if (block.length === 0)
|
|
209
|
-
return "
|
|
231
|
+
return "un'";
|
|
210
232
|
if (block.length === 1)
|
|
211
233
|
return encodeNode(block[0]);
|
|
212
234
|
return encodeCallParts([encodeOpcode("do"), ...block.map((node) => encodeNode(node))]);
|
|
@@ -223,9 +245,13 @@ function encodeConditionalElse(elseBranch) {
|
|
|
223
245
|
};
|
|
224
246
|
return encodeNode(nested);
|
|
225
247
|
}
|
|
248
|
+
function encodeDomainLookup(shortCode, tag) {
|
|
249
|
+
return `${shortCode}${tag}`;
|
|
250
|
+
}
|
|
226
251
|
function encodeNavigation(node) {
|
|
227
252
|
const domainRefs = activeEncodeOptions?.domainRefs;
|
|
228
|
-
|
|
253
|
+
const domainOpcodes = activeEncodeOptions?.domainOpcodes;
|
|
254
|
+
if ((domainRefs || domainOpcodes) && node.target.type === "identifier") {
|
|
229
255
|
const staticPath = [node.target.name];
|
|
230
256
|
for (const segment of node.segments) {
|
|
231
257
|
if (segment.type !== "static")
|
|
@@ -234,14 +260,17 @@ function encodeNavigation(node) {
|
|
|
234
260
|
}
|
|
235
261
|
for (let pathLength = staticPath.length;pathLength >= 1; pathLength -= 1) {
|
|
236
262
|
const dottedName = staticPath.slice(0, pathLength).join(".");
|
|
237
|
-
const
|
|
238
|
-
|
|
263
|
+
const refCode = domainRefs?.[dottedName];
|
|
264
|
+
const opcodeCode = domainOpcodes?.[dottedName];
|
|
265
|
+
const shortCode = refCode ?? opcodeCode;
|
|
266
|
+
if (shortCode === undefined)
|
|
239
267
|
continue;
|
|
268
|
+
const tag = refCode !== undefined ? "'" : "%";
|
|
240
269
|
const consumedStaticSegments = pathLength - 1;
|
|
241
270
|
if (consumedStaticSegments === node.segments.length) {
|
|
242
|
-
return
|
|
271
|
+
return encodeDomainLookup(shortCode, tag);
|
|
243
272
|
}
|
|
244
|
-
const parts2 = [
|
|
273
|
+
const parts2 = [encodeDomainLookup(shortCode, tag)];
|
|
245
274
|
for (const segment of node.segments.slice(consumedStaticSegments)) {
|
|
246
275
|
if (segment.type === "static")
|
|
247
276
|
parts2.push(encodeBareOrLengthString(segment.key));
|
|
@@ -267,9 +296,12 @@ function encodeWhile(node) {
|
|
|
267
296
|
}
|
|
268
297
|
function encodeFor(node) {
|
|
269
298
|
const body = addOptionalPrefix(encodeBlockExpression(node.body));
|
|
270
|
-
if (node.binding.type === "binding:
|
|
299
|
+
if (node.binding.type === "binding:bareIn") {
|
|
271
300
|
return `>(${encodeNode(node.binding.source)}${body})`;
|
|
272
301
|
}
|
|
302
|
+
if (node.binding.type === "binding:bareOf") {
|
|
303
|
+
return `<(${encodeNode(node.binding.source)}${body})`;
|
|
304
|
+
}
|
|
273
305
|
if (node.binding.type === "binding:valueIn") {
|
|
274
306
|
return `>(${encodeNode(node.binding.source)}${node.binding.value}$${body})`;
|
|
275
307
|
}
|
|
@@ -280,30 +312,47 @@ function encodeFor(node) {
|
|
|
280
312
|
}
|
|
281
313
|
function encodeArrayComprehension(node) {
|
|
282
314
|
const body = addOptionalPrefix(encodeNode(node.body));
|
|
283
|
-
if (node.binding.type === "binding:
|
|
315
|
+
if (node.binding.type === "binding:bareIn") {
|
|
284
316
|
return `>[${encodeNode(node.binding.source)}${body}]`;
|
|
285
317
|
}
|
|
318
|
+
if (node.binding.type === "binding:bareOf") {
|
|
319
|
+
return `<[${encodeNode(node.binding.source)}${body}]`;
|
|
320
|
+
}
|
|
286
321
|
if (node.binding.type === "binding:valueIn") {
|
|
287
322
|
return `>[${encodeNode(node.binding.source)}${node.binding.value}$${body}]`;
|
|
288
323
|
}
|
|
289
324
|
if (node.binding.type === "binding:keyValueIn") {
|
|
290
325
|
return `>[${encodeNode(node.binding.source)}${node.binding.key}$${node.binding.value}$${body}]`;
|
|
291
326
|
}
|
|
292
|
-
return
|
|
327
|
+
return `<[${encodeNode(node.binding.source)}${node.binding.key}$${body}]`;
|
|
293
328
|
}
|
|
294
329
|
function encodeObjectComprehension(node) {
|
|
295
330
|
const key = addOptionalPrefix(encodeNode(node.key));
|
|
296
331
|
const value = addOptionalPrefix(encodeNode(node.value));
|
|
297
|
-
if (node.binding.type === "binding:
|
|
332
|
+
if (node.binding.type === "binding:bareIn") {
|
|
298
333
|
return `>{${encodeNode(node.binding.source)}${key}${value}}`;
|
|
299
334
|
}
|
|
335
|
+
if (node.binding.type === "binding:bareOf") {
|
|
336
|
+
return `<{${encodeNode(node.binding.source)}${key}${value}}`;
|
|
337
|
+
}
|
|
300
338
|
if (node.binding.type === "binding:valueIn") {
|
|
301
339
|
return `>{${encodeNode(node.binding.source)}${node.binding.value}$${key}${value}}`;
|
|
302
340
|
}
|
|
303
341
|
if (node.binding.type === "binding:keyValueIn") {
|
|
304
342
|
return `>{${encodeNode(node.binding.source)}${node.binding.key}$${node.binding.value}$${key}${value}}`;
|
|
305
343
|
}
|
|
306
|
-
return
|
|
344
|
+
return `<{${encodeNode(node.binding.source)}${node.binding.key}$${key}${value}}`;
|
|
345
|
+
}
|
|
346
|
+
function encodeWhileArrayComprehension(node) {
|
|
347
|
+
const cond = encodeNode(node.condition);
|
|
348
|
+
const body = addOptionalPrefix(encodeNode(node.body));
|
|
349
|
+
return `#[${cond}${body}]`;
|
|
350
|
+
}
|
|
351
|
+
function encodeWhileObjectComprehension(node) {
|
|
352
|
+
const cond = encodeNode(node.condition);
|
|
353
|
+
const key = addOptionalPrefix(encodeNode(node.key));
|
|
354
|
+
const value = addOptionalPrefix(encodeNode(node.value));
|
|
355
|
+
return `#{${cond}${key}${value}}`;
|
|
307
356
|
}
|
|
308
357
|
var activeEncodeOptions;
|
|
309
358
|
function encodeNode(node) {
|
|
@@ -313,7 +362,10 @@ function encodeNode(node) {
|
|
|
313
362
|
case "identifier": {
|
|
314
363
|
const domainRef = activeEncodeOptions?.domainRefs?.[node.name];
|
|
315
364
|
if (domainRef !== undefined)
|
|
316
|
-
return `${
|
|
365
|
+
return `${domainRef}'`;
|
|
366
|
+
const domainOpcode = activeEncodeOptions?.domainOpcodes?.[node.name];
|
|
367
|
+
if (domainOpcode !== undefined)
|
|
368
|
+
return `${domainOpcode}%`;
|
|
317
369
|
return `${node.name}$`;
|
|
318
370
|
}
|
|
319
371
|
case "self":
|
|
@@ -326,11 +378,11 @@ function encodeNode(node) {
|
|
|
326
378
|
return `${encodeUint(node.depth - 1)}@`;
|
|
327
379
|
}
|
|
328
380
|
case "boolean":
|
|
329
|
-
return node.value ? "
|
|
381
|
+
return node.value ? "tr'" : "fl'";
|
|
330
382
|
case "null":
|
|
331
|
-
return "
|
|
383
|
+
return "nl'";
|
|
332
384
|
case "undefined":
|
|
333
|
-
return "
|
|
385
|
+
return "un'";
|
|
334
386
|
case "number":
|
|
335
387
|
return encodeNumberNode(node);
|
|
336
388
|
case "string":
|
|
@@ -341,12 +393,16 @@ function encodeNode(node) {
|
|
|
341
393
|
}
|
|
342
394
|
case "arrayComprehension":
|
|
343
395
|
return encodeArrayComprehension(node);
|
|
396
|
+
case "whileArrayComprehension":
|
|
397
|
+
return encodeWhileArrayComprehension(node);
|
|
344
398
|
case "object": {
|
|
345
399
|
const body = node.entries.map(({ key, value }) => `${encodeNode(key)}${addOptionalPrefix(encodeNode(value))}`).join("");
|
|
346
400
|
return `{${body}}`;
|
|
347
401
|
}
|
|
348
402
|
case "objectComprehension":
|
|
349
403
|
return encodeObjectComprehension(node);
|
|
404
|
+
case "whileObjectComprehension":
|
|
405
|
+
return encodeWhileObjectComprehension(node);
|
|
350
406
|
case "key":
|
|
351
407
|
return encodeBareOrLengthString(node.name);
|
|
352
408
|
case "group":
|
|
@@ -356,6 +412,10 @@ function encodeNode(node) {
|
|
|
356
412
|
return `~${encodeNode(node.value)}`;
|
|
357
413
|
if (node.op === "neg")
|
|
358
414
|
return encodeCallParts([encodeOpcode("neg"), encodeNode(node.value)]);
|
|
415
|
+
if (node.op === "logicalNot") {
|
|
416
|
+
const val = encodeNode(node.value);
|
|
417
|
+
return `!(${val}tr')`;
|
|
418
|
+
}
|
|
359
419
|
return encodeCallParts([encodeOpcode("not"), encodeNode(node.value)]);
|
|
360
420
|
case "binary":
|
|
361
421
|
if (node.op === "and") {
|
|
@@ -374,12 +434,19 @@ function encodeNode(node) {
|
|
|
374
434
|
}).join("");
|
|
375
435
|
return `|(${body})`;
|
|
376
436
|
}
|
|
437
|
+
if (node.op === "nor") {
|
|
438
|
+
const left = encodeNode(node.left);
|
|
439
|
+
const right = addOptionalPrefix(encodeNode(node.right));
|
|
440
|
+
return `!(${left}${right})`;
|
|
441
|
+
}
|
|
377
442
|
return encodeCallParts([
|
|
378
443
|
encodeOpcode(BINARY_TO_OPCODE[node.op]),
|
|
379
444
|
encodeNode(node.left),
|
|
380
445
|
encodeNode(node.right)
|
|
381
446
|
]);
|
|
382
447
|
case "assign": {
|
|
448
|
+
if (node.op === ":=")
|
|
449
|
+
return `/${encodeNode(node.place)}${addOptionalPrefix(encodeNode(node.value))}`;
|
|
383
450
|
if (node.op === "=")
|
|
384
451
|
return `=${encodeNode(node.place)}${addOptionalPrefix(encodeNode(node.value))}`;
|
|
385
452
|
const opcode = ASSIGN_COMPOUND_TO_OPCODE[node.op];
|
|
@@ -390,8 +457,12 @@ function encodeNode(node) {
|
|
|
390
457
|
}
|
|
391
458
|
case "navigation":
|
|
392
459
|
return encodeNavigation(node);
|
|
393
|
-
case "call":
|
|
460
|
+
case "call": {
|
|
461
|
+
if (node.callee.type === "identifier" && KEYWORD_OPCODES.has(node.callee.name)) {
|
|
462
|
+
return encodeCallParts([encodeOpcode(node.callee.name), ...node.args.map((arg) => encodeNode(arg))]);
|
|
463
|
+
}
|
|
394
464
|
return encodeCallParts([encodeNode(node.callee), ...node.args.map((arg) => encodeNode(arg))]);
|
|
465
|
+
}
|
|
395
466
|
case "conditional": {
|
|
396
467
|
const opener = node.head === "when" ? "?(" : "!(";
|
|
397
468
|
const cond = encodeNode(node.condition);
|
|
@@ -399,6 +470,8 @@ function encodeNode(node) {
|
|
|
399
470
|
const elseExpr = node.elseBranch ? addOptionalPrefix(encodeConditionalElse(node.elseBranch)) : "";
|
|
400
471
|
return `${opener}${cond}${thenExpr}${elseExpr})`;
|
|
401
472
|
}
|
|
473
|
+
case "range":
|
|
474
|
+
return encodeCallParts([encodeOpcode("range"), encodeNode(node.from), encodeNode(node.to)]);
|
|
402
475
|
case "for":
|
|
403
476
|
return encodeFor(node);
|
|
404
477
|
case "while":
|
|
@@ -477,6 +550,18 @@ function isPlainObject(value) {
|
|
|
477
550
|
function isBareKeyName(key) {
|
|
478
551
|
return /^[A-Za-z_][A-Za-z0-9_-]*$/.test(key);
|
|
479
552
|
}
|
|
553
|
+
function isNumericKey(key) {
|
|
554
|
+
if (key === "")
|
|
555
|
+
return false;
|
|
556
|
+
return String(Number(key)) === key && Number.isFinite(Number(key));
|
|
557
|
+
}
|
|
558
|
+
function stringifyKey(key) {
|
|
559
|
+
if (isBareKeyName(key))
|
|
560
|
+
return key;
|
|
561
|
+
if (isNumericKey(key))
|
|
562
|
+
return key;
|
|
563
|
+
return stringifyString(key);
|
|
564
|
+
}
|
|
480
565
|
function stringifyString(value) {
|
|
481
566
|
return JSON.stringify(value);
|
|
482
567
|
}
|
|
@@ -488,8 +573,12 @@ function stringifyInline(value) {
|
|
|
488
573
|
if (typeof value === "boolean")
|
|
489
574
|
return value ? "true" : "false";
|
|
490
575
|
if (typeof value === "number") {
|
|
491
|
-
if (
|
|
492
|
-
|
|
576
|
+
if (Number.isNaN(value))
|
|
577
|
+
return "nan";
|
|
578
|
+
if (value === Infinity)
|
|
579
|
+
return "inf";
|
|
580
|
+
if (value === -Infinity)
|
|
581
|
+
return "-inf";
|
|
493
582
|
return String(value);
|
|
494
583
|
}
|
|
495
584
|
if (typeof value === "string")
|
|
@@ -503,7 +592,7 @@ function stringifyInline(value) {
|
|
|
503
592
|
const entries = Object.entries(value);
|
|
504
593
|
if (entries.length === 0)
|
|
505
594
|
return "{}";
|
|
506
|
-
const body = entries.map(([key, item]) => `${
|
|
595
|
+
const body = entries.map(([key, item]) => `${stringifyKey(key)}: ${stringifyInline(item)}`).join(" ");
|
|
507
596
|
return `{${body}}`;
|
|
508
597
|
}
|
|
509
598
|
throw new Error(`Rex stringify() cannot encode value of type ${typeof value}`);
|
|
@@ -540,7 +629,7 @@ ${indent}]`;
|
|
|
540
629
|
if (entries.length === 0)
|
|
541
630
|
return "{}";
|
|
542
631
|
const lines = entries.map(([key, item]) => {
|
|
543
|
-
const keyText =
|
|
632
|
+
const keyText = stringifyKey(key);
|
|
544
633
|
const rendered = stringifyPretty(item, depth + 1, indentSize, maxWidth);
|
|
545
634
|
return `${childIndent}${keyText}: ${rendered}`;
|
|
546
635
|
});
|
|
@@ -558,78 +647,55 @@ function domainRefsFromConfig(config) {
|
|
|
558
647
|
if (!config || typeof config !== "object" || Array.isArray(config)) {
|
|
559
648
|
throw new Error("Domain config must be an object");
|
|
560
649
|
}
|
|
561
|
-
const
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
return refs;
|
|
568
|
-
}
|
|
569
|
-
function decodeDomainRefKey(refText) {
|
|
570
|
-
if (!refText)
|
|
571
|
-
throw new Error("Domain ref key cannot be empty");
|
|
572
|
-
if (!/^[0-9A-Za-z_-]+$/.test(refText)) {
|
|
573
|
-
throw new Error(`Invalid domain ref key '${refText}' (must use base64 alphabet 0-9a-zA-Z-_)`);
|
|
574
|
-
}
|
|
575
|
-
if (refText.length > 1 && refText[0] === "0") {
|
|
576
|
-
throw new Error(`Invalid domain ref key '${refText}' (leading zeroes are not allowed)`);
|
|
577
|
-
}
|
|
578
|
-
if (/^[1-9]$/.test(refText)) {
|
|
579
|
-
throw new Error(`Invalid domain ref key '${refText}' (reserved by core language)`);
|
|
580
|
-
}
|
|
581
|
-
let value = 0;
|
|
582
|
-
for (const char of refText) {
|
|
583
|
-
const digit = DOMAIN_DIGIT_INDEX.get(char);
|
|
584
|
-
if (digit === undefined)
|
|
585
|
-
throw new Error(`Invalid domain ref key '${refText}'`);
|
|
586
|
-
value = value * 64 + digit;
|
|
587
|
-
if (value > Number.MAX_SAFE_INTEGER) {
|
|
588
|
-
throw new Error(`Invalid domain ref key '${refText}' (must fit in 53 bits)`);
|
|
589
|
-
}
|
|
650
|
+
const configObj = config;
|
|
651
|
+
const domainRefs = {};
|
|
652
|
+
const domainOpcodes = {};
|
|
653
|
+
const dataSection = configObj.data;
|
|
654
|
+
if (dataSection && typeof dataSection === "object" && !Array.isArray(dataSection)) {
|
|
655
|
+
mapConfigEntries(dataSection, domainRefs);
|
|
590
656
|
}
|
|
591
|
-
|
|
592
|
-
|
|
657
|
+
const functionsSection = configObj.functions;
|
|
658
|
+
if (functionsSection && typeof functionsSection === "object" && !Array.isArray(functionsSection)) {
|
|
659
|
+
mapConfigEntries(functionsSection, domainOpcodes);
|
|
593
660
|
}
|
|
594
|
-
return
|
|
661
|
+
return { domainRefs, domainOpcodes };
|
|
595
662
|
}
|
|
596
663
|
function mapConfigEntries(entries, refs) {
|
|
597
664
|
const sourceKindByRoot = new Map;
|
|
598
665
|
for (const root of Object.keys(refs)) {
|
|
599
666
|
sourceKindByRoot.set(root, "explicit");
|
|
600
667
|
}
|
|
601
|
-
for (const [
|
|
668
|
+
for (const [shortCode, rawEntry] of Object.entries(entries)) {
|
|
602
669
|
const entry = rawEntry;
|
|
603
670
|
if (!entry || typeof entry !== "object")
|
|
604
671
|
continue;
|
|
605
672
|
if (!Array.isArray(entry.names))
|
|
606
673
|
continue;
|
|
607
|
-
const refId = decodeDomainRefKey(refText);
|
|
608
674
|
for (const rawName of entry.names) {
|
|
609
675
|
if (typeof rawName !== "string")
|
|
610
676
|
continue;
|
|
611
|
-
const
|
|
612
|
-
if (
|
|
613
|
-
throw new Error(`Conflicting refs for '${rawName}': ${
|
|
677
|
+
const existingRef = refs[rawName];
|
|
678
|
+
if (existingRef !== undefined && existingRef !== shortCode) {
|
|
679
|
+
throw new Error(`Conflicting refs for '${rawName}': ${existingRef} vs ${shortCode}`);
|
|
614
680
|
}
|
|
615
|
-
refs[rawName] =
|
|
681
|
+
refs[rawName] = shortCode;
|
|
616
682
|
const root = rawName.split(".")[0];
|
|
617
683
|
if (!root)
|
|
618
684
|
continue;
|
|
619
685
|
const currentKind = rawName.includes(".") ? "implicit" : "explicit";
|
|
620
686
|
const existing = refs[root];
|
|
621
687
|
if (existing !== undefined) {
|
|
622
|
-
if (existing ===
|
|
688
|
+
if (existing === shortCode)
|
|
623
689
|
continue;
|
|
624
690
|
const existingKind = sourceKindByRoot.get(root) ?? "explicit";
|
|
625
691
|
if (currentKind === "explicit") {
|
|
626
|
-
throw new Error(`Conflicting refs for '${root}': ${existing} vs ${
|
|
692
|
+
throw new Error(`Conflicting refs for '${root}': ${existing} vs ${shortCode}`);
|
|
627
693
|
}
|
|
628
694
|
if (existingKind === "explicit")
|
|
629
695
|
continue;
|
|
630
696
|
continue;
|
|
631
697
|
}
|
|
632
|
-
refs[root] =
|
|
698
|
+
refs[root] = shortCode;
|
|
633
699
|
sourceKindByRoot.set(root, currentKind);
|
|
634
700
|
}
|
|
635
701
|
}
|
|
@@ -913,6 +979,21 @@ function dropBindingNames(env, binding) {
|
|
|
913
979
|
clearBinding(env, binding.key);
|
|
914
980
|
}
|
|
915
981
|
}
|
|
982
|
+
function optimizeBinding(binding, sourceEnv, currentDepth) {
|
|
983
|
+
const source = optimizeNode(binding.source, sourceEnv, currentDepth);
|
|
984
|
+
switch (binding.type) {
|
|
985
|
+
case "binding:bareIn":
|
|
986
|
+
return { type: "binding:bareIn", source };
|
|
987
|
+
case "binding:bareOf":
|
|
988
|
+
return { type: "binding:bareOf", source };
|
|
989
|
+
case "binding:valueIn":
|
|
990
|
+
return { type: "binding:valueIn", value: binding.value, source };
|
|
991
|
+
case "binding:keyValueIn":
|
|
992
|
+
return { type: "binding:keyValueIn", key: binding.key, value: binding.value, source };
|
|
993
|
+
case "binding:keyOf":
|
|
994
|
+
return { type: "binding:keyOf", key: binding.key, source };
|
|
995
|
+
}
|
|
996
|
+
}
|
|
916
997
|
function collectReads(node, out) {
|
|
917
998
|
switch (node.type) {
|
|
918
999
|
case "identifier":
|
|
@@ -935,11 +1016,20 @@ function collectReads(node, out) {
|
|
|
935
1016
|
collectReads(node.binding.source, out);
|
|
936
1017
|
collectReads(node.body, out);
|
|
937
1018
|
return;
|
|
1019
|
+
case "whileArrayComprehension":
|
|
1020
|
+
collectReads(node.condition, out);
|
|
1021
|
+
collectReads(node.body, out);
|
|
1022
|
+
return;
|
|
938
1023
|
case "objectComprehension":
|
|
939
1024
|
collectReads(node.binding.source, out);
|
|
940
1025
|
collectReads(node.key, out);
|
|
941
1026
|
collectReads(node.value, out);
|
|
942
1027
|
return;
|
|
1028
|
+
case "whileObjectComprehension":
|
|
1029
|
+
collectReads(node.condition, out);
|
|
1030
|
+
collectReads(node.key, out);
|
|
1031
|
+
collectReads(node.value, out);
|
|
1032
|
+
return;
|
|
943
1033
|
case "unary":
|
|
944
1034
|
collectReads(node.value, out);
|
|
945
1035
|
return;
|
|
@@ -976,6 +1066,10 @@ function collectReads(node, out) {
|
|
|
976
1066
|
for (const part of node.body)
|
|
977
1067
|
collectReads(part, out);
|
|
978
1068
|
return;
|
|
1069
|
+
case "range":
|
|
1070
|
+
collectReads(node.from, out);
|
|
1071
|
+
collectReads(node.to, out);
|
|
1072
|
+
return;
|
|
979
1073
|
case "program":
|
|
980
1074
|
for (const part of node.body)
|
|
981
1075
|
collectReads(part, out);
|
|
@@ -1020,6 +1114,8 @@ function isPureNode(node) {
|
|
|
1020
1114
|
return node.op !== "delete" && isPureNode(node.value);
|
|
1021
1115
|
case "binary":
|
|
1022
1116
|
return isPureNode(node.left) && isPureNode(node.right);
|
|
1117
|
+
case "range":
|
|
1118
|
+
return isPureNode(node.from) && isPureNode(node.to);
|
|
1023
1119
|
default:
|
|
1024
1120
|
return false;
|
|
1025
1121
|
}
|
|
@@ -1084,6 +1180,8 @@ function hasIdentifierRead(node, name, asPlace = false) {
|
|
|
1084
1180
|
return hasIdentifierRead(node.value, name, node.op === "delete");
|
|
1085
1181
|
case "binary":
|
|
1086
1182
|
return hasIdentifierRead(node.left, name) || hasIdentifierRead(node.right, name);
|
|
1183
|
+
case "range":
|
|
1184
|
+
return hasIdentifierRead(node.from, name) || hasIdentifierRead(node.to, name);
|
|
1087
1185
|
case "assign":
|
|
1088
1186
|
return hasIdentifierRead(node.place, name, true) || hasIdentifierRead(node.value, name);
|
|
1089
1187
|
default:
|
|
@@ -1106,6 +1204,8 @@ function countIdentifierReads(node, name, asPlace = false) {
|
|
|
1106
1204
|
return countIdentifierReads(node.value, name, node.op === "delete");
|
|
1107
1205
|
case "binary":
|
|
1108
1206
|
return countIdentifierReads(node.left, name) + countIdentifierReads(node.right, name);
|
|
1207
|
+
case "range":
|
|
1208
|
+
return countIdentifierReads(node.from, name) + countIdentifierReads(node.to, name);
|
|
1109
1209
|
case "assign":
|
|
1110
1210
|
return countIdentifierReads(node.place, name, true) + countIdentifierReads(node.value, name);
|
|
1111
1211
|
default:
|
|
@@ -1160,6 +1260,12 @@ function replaceIdentifier(node, name, replacement, asPlace = false) {
|
|
|
1160
1260
|
place: replaceIdentifier(node.place, name, replacement, true),
|
|
1161
1261
|
value: replaceIdentifier(node.value, name, replacement)
|
|
1162
1262
|
};
|
|
1263
|
+
case "range":
|
|
1264
|
+
return {
|
|
1265
|
+
type: "range",
|
|
1266
|
+
from: replaceIdentifier(node.from, name, replacement),
|
|
1267
|
+
to: replaceIdentifier(node.to, name, replacement)
|
|
1268
|
+
};
|
|
1163
1269
|
default:
|
|
1164
1270
|
return node;
|
|
1165
1271
|
}
|
|
@@ -1200,7 +1306,16 @@ function inlineAdjacentPureAssignments(block) {
|
|
|
1200
1306
|
return out;
|
|
1201
1307
|
}
|
|
1202
1308
|
function toNumberNode(value) {
|
|
1203
|
-
|
|
1309
|
+
let raw;
|
|
1310
|
+
if (Number.isNaN(value))
|
|
1311
|
+
raw = "nan";
|
|
1312
|
+
else if (value === Infinity)
|
|
1313
|
+
raw = "inf";
|
|
1314
|
+
else if (value === -Infinity)
|
|
1315
|
+
raw = "-inf";
|
|
1316
|
+
else
|
|
1317
|
+
raw = String(value);
|
|
1318
|
+
return { type: "number", raw, value };
|
|
1204
1319
|
}
|
|
1205
1320
|
function toStringNode(value) {
|
|
1206
1321
|
return { type: "string", raw: JSON.stringify(value) };
|
|
@@ -1212,7 +1327,7 @@ function toLiteralNode(value) {
|
|
|
1212
1327
|
return { type: "null" };
|
|
1213
1328
|
if (typeof value === "boolean")
|
|
1214
1329
|
return { type: "boolean", value };
|
|
1215
|
-
if (typeof value === "number"
|
|
1330
|
+
if (typeof value === "number")
|
|
1216
1331
|
return toNumberNode(value);
|
|
1217
1332
|
if (typeof value === "string")
|
|
1218
1333
|
return toStringNode(value);
|
|
@@ -1295,6 +1410,9 @@ function foldUnary(op, value) {
|
|
|
1295
1410
|
return ~value;
|
|
1296
1411
|
return;
|
|
1297
1412
|
}
|
|
1413
|
+
if (op === "logicalNot") {
|
|
1414
|
+
return value === undefined ? true : undefined;
|
|
1415
|
+
}
|
|
1298
1416
|
return;
|
|
1299
1417
|
}
|
|
1300
1418
|
function foldBinary(op, left, right) {
|
|
@@ -1465,6 +1583,12 @@ function optimizeNode(node, env, currentDepth, asPlace = false) {
|
|
|
1465
1583
|
}
|
|
1466
1584
|
return { type: "binary", op: node.op, left, right };
|
|
1467
1585
|
}
|
|
1586
|
+
case "range":
|
|
1587
|
+
return {
|
|
1588
|
+
type: "range",
|
|
1589
|
+
from: optimizeNode(node.from, env, currentDepth),
|
|
1590
|
+
to: optimizeNode(node.to, env, currentDepth)
|
|
1591
|
+
};
|
|
1468
1592
|
case "navigation": {
|
|
1469
1593
|
const target = optimizeNode(node.target, env, currentDepth);
|
|
1470
1594
|
const segments = node.segments.map((segment) => segment.type === "static" ? segment : { type: "dynamic", key: optimizeNode(segment.key, env, currentDepth) });
|
|
@@ -1575,31 +1699,7 @@ function optimizeNode(node, env, currentDepth, asPlace = false) {
|
|
|
1575
1699
|
}
|
|
1576
1700
|
case "for": {
|
|
1577
1701
|
const sourceEnv = cloneOptimizeEnv(env);
|
|
1578
|
-
const binding = (
|
|
1579
|
-
if (node.binding.type === "binding:expr") {
|
|
1580
|
-
return { type: "binding:expr", source: optimizeNode(node.binding.source, sourceEnv, currentDepth) };
|
|
1581
|
-
}
|
|
1582
|
-
if (node.binding.type === "binding:valueIn") {
|
|
1583
|
-
return {
|
|
1584
|
-
type: "binding:valueIn",
|
|
1585
|
-
value: node.binding.value,
|
|
1586
|
-
source: optimizeNode(node.binding.source, sourceEnv, currentDepth)
|
|
1587
|
-
};
|
|
1588
|
-
}
|
|
1589
|
-
if (node.binding.type === "binding:keyValueIn") {
|
|
1590
|
-
return {
|
|
1591
|
-
type: "binding:keyValueIn",
|
|
1592
|
-
key: node.binding.key,
|
|
1593
|
-
value: node.binding.value,
|
|
1594
|
-
source: optimizeNode(node.binding.source, sourceEnv, currentDepth)
|
|
1595
|
-
};
|
|
1596
|
-
}
|
|
1597
|
-
return {
|
|
1598
|
-
type: "binding:keyOf",
|
|
1599
|
-
key: node.binding.key,
|
|
1600
|
-
source: optimizeNode(node.binding.source, sourceEnv, currentDepth)
|
|
1601
|
-
};
|
|
1602
|
-
})();
|
|
1702
|
+
const binding = optimizeBinding(node.binding, sourceEnv, currentDepth);
|
|
1603
1703
|
const bodyEnv = cloneOptimizeEnv(env);
|
|
1604
1704
|
dropBindingNames(bodyEnv, binding);
|
|
1605
1705
|
return {
|
|
@@ -1610,20 +1710,7 @@ function optimizeNode(node, env, currentDepth, asPlace = false) {
|
|
|
1610
1710
|
}
|
|
1611
1711
|
case "arrayComprehension": {
|
|
1612
1712
|
const sourceEnv = cloneOptimizeEnv(env);
|
|
1613
|
-
const binding =
|
|
1614
|
-
type: "binding:valueIn",
|
|
1615
|
-
value: node.binding.value,
|
|
1616
|
-
source: optimizeNode(node.binding.source, sourceEnv, currentDepth)
|
|
1617
|
-
} : node.binding.type === "binding:keyValueIn" ? {
|
|
1618
|
-
type: "binding:keyValueIn",
|
|
1619
|
-
key: node.binding.key,
|
|
1620
|
-
value: node.binding.value,
|
|
1621
|
-
source: optimizeNode(node.binding.source, sourceEnv, currentDepth)
|
|
1622
|
-
} : {
|
|
1623
|
-
type: "binding:keyOf",
|
|
1624
|
-
key: node.binding.key,
|
|
1625
|
-
source: optimizeNode(node.binding.source, sourceEnv, currentDepth)
|
|
1626
|
-
};
|
|
1713
|
+
const binding = optimizeBinding(node.binding, sourceEnv, currentDepth);
|
|
1627
1714
|
const bodyEnv = cloneOptimizeEnv(env);
|
|
1628
1715
|
dropBindingNames(bodyEnv, binding);
|
|
1629
1716
|
return {
|
|
@@ -1632,22 +1719,15 @@ function optimizeNode(node, env, currentDepth, asPlace = false) {
|
|
|
1632
1719
|
body: optimizeNode(node.body, bodyEnv, currentDepth + 1)
|
|
1633
1720
|
};
|
|
1634
1721
|
}
|
|
1722
|
+
case "whileArrayComprehension":
|
|
1723
|
+
return {
|
|
1724
|
+
type: "whileArrayComprehension",
|
|
1725
|
+
condition: optimizeNode(node.condition, env, currentDepth),
|
|
1726
|
+
body: optimizeNode(node.body, env, currentDepth + 1)
|
|
1727
|
+
};
|
|
1635
1728
|
case "objectComprehension": {
|
|
1636
1729
|
const sourceEnv = cloneOptimizeEnv(env);
|
|
1637
|
-
const binding =
|
|
1638
|
-
type: "binding:valueIn",
|
|
1639
|
-
value: node.binding.value,
|
|
1640
|
-
source: optimizeNode(node.binding.source, sourceEnv, currentDepth)
|
|
1641
|
-
} : node.binding.type === "binding:keyValueIn" ? {
|
|
1642
|
-
type: "binding:keyValueIn",
|
|
1643
|
-
key: node.binding.key,
|
|
1644
|
-
value: node.binding.value,
|
|
1645
|
-
source: optimizeNode(node.binding.source, sourceEnv, currentDepth)
|
|
1646
|
-
} : {
|
|
1647
|
-
type: "binding:keyOf",
|
|
1648
|
-
key: node.binding.key,
|
|
1649
|
-
source: optimizeNode(node.binding.source, sourceEnv, currentDepth)
|
|
1650
|
-
};
|
|
1730
|
+
const binding = optimizeBinding(node.binding, sourceEnv, currentDepth);
|
|
1651
1731
|
const bodyEnv = cloneOptimizeEnv(env);
|
|
1652
1732
|
dropBindingNames(bodyEnv, binding);
|
|
1653
1733
|
return {
|
|
@@ -1657,6 +1737,13 @@ function optimizeNode(node, env, currentDepth, asPlace = false) {
|
|
|
1657
1737
|
value: optimizeNode(node.value, bodyEnv, currentDepth + 1)
|
|
1658
1738
|
};
|
|
1659
1739
|
}
|
|
1740
|
+
case "whileObjectComprehension":
|
|
1741
|
+
return {
|
|
1742
|
+
type: "whileObjectComprehension",
|
|
1743
|
+
condition: optimizeNode(node.condition, env, currentDepth),
|
|
1744
|
+
key: optimizeNode(node.key, env, currentDepth + 1),
|
|
1745
|
+
value: optimizeNode(node.value, env, currentDepth + 1)
|
|
1746
|
+
};
|
|
1660
1747
|
default:
|
|
1661
1748
|
return node;
|
|
1662
1749
|
}
|
|
@@ -1708,6 +1795,10 @@ function collectLocalBindings(node, locals) {
|
|
|
1708
1795
|
collectLocalBindings(node.left, locals);
|
|
1709
1796
|
collectLocalBindings(node.right, locals);
|
|
1710
1797
|
return;
|
|
1798
|
+
case "range":
|
|
1799
|
+
collectLocalBindings(node.from, locals);
|
|
1800
|
+
collectLocalBindings(node.to, locals);
|
|
1801
|
+
return;
|
|
1711
1802
|
case "conditional":
|
|
1712
1803
|
collectLocalBindings(node.condition, locals);
|
|
1713
1804
|
for (const part of node.thenBlock)
|
|
@@ -1724,11 +1815,20 @@ function collectLocalBindings(node, locals) {
|
|
|
1724
1815
|
collectLocalBindingFromBinding(node.binding, locals);
|
|
1725
1816
|
collectLocalBindings(node.body, locals);
|
|
1726
1817
|
return;
|
|
1818
|
+
case "whileArrayComprehension":
|
|
1819
|
+
collectLocalBindings(node.condition, locals);
|
|
1820
|
+
collectLocalBindings(node.body, locals);
|
|
1821
|
+
return;
|
|
1727
1822
|
case "objectComprehension":
|
|
1728
1823
|
collectLocalBindingFromBinding(node.binding, locals);
|
|
1729
1824
|
collectLocalBindings(node.key, locals);
|
|
1730
1825
|
collectLocalBindings(node.value, locals);
|
|
1731
1826
|
return;
|
|
1827
|
+
case "whileObjectComprehension":
|
|
1828
|
+
collectLocalBindings(node.condition, locals);
|
|
1829
|
+
collectLocalBindings(node.key, locals);
|
|
1830
|
+
collectLocalBindings(node.value, locals);
|
|
1831
|
+
return;
|
|
1732
1832
|
default:
|
|
1733
1833
|
return;
|
|
1734
1834
|
}
|
|
@@ -1820,6 +1920,10 @@ function collectNameFrequencies(node, locals, frequencies, order, nextOrder) {
|
|
|
1820
1920
|
collectNameFrequencies(node.left, locals, frequencies, order, nextOrder);
|
|
1821
1921
|
collectNameFrequencies(node.right, locals, frequencies, order, nextOrder);
|
|
1822
1922
|
return;
|
|
1923
|
+
case "range":
|
|
1924
|
+
collectNameFrequencies(node.from, locals, frequencies, order, nextOrder);
|
|
1925
|
+
collectNameFrequencies(node.to, locals, frequencies, order, nextOrder);
|
|
1926
|
+
return;
|
|
1823
1927
|
case "conditional":
|
|
1824
1928
|
collectNameFrequencies(node.condition, locals, frequencies, order, nextOrder);
|
|
1825
1929
|
for (const part of node.thenBlock)
|
|
@@ -1836,11 +1940,20 @@ function collectNameFrequencies(node, locals, frequencies, order, nextOrder) {
|
|
|
1836
1940
|
collectNameFrequenciesBinding(node.binding, locals, frequencies, order, nextOrder);
|
|
1837
1941
|
collectNameFrequencies(node.body, locals, frequencies, order, nextOrder);
|
|
1838
1942
|
return;
|
|
1943
|
+
case "whileArrayComprehension":
|
|
1944
|
+
collectNameFrequencies(node.condition, locals, frequencies, order, nextOrder);
|
|
1945
|
+
collectNameFrequencies(node.body, locals, frequencies, order, nextOrder);
|
|
1946
|
+
return;
|
|
1839
1947
|
case "objectComprehension":
|
|
1840
1948
|
collectNameFrequenciesBinding(node.binding, locals, frequencies, order, nextOrder);
|
|
1841
1949
|
collectNameFrequencies(node.key, locals, frequencies, order, nextOrder);
|
|
1842
1950
|
collectNameFrequencies(node.value, locals, frequencies, order, nextOrder);
|
|
1843
1951
|
return;
|
|
1952
|
+
case "whileObjectComprehension":
|
|
1953
|
+
collectNameFrequencies(node.condition, locals, frequencies, order, nextOrder);
|
|
1954
|
+
collectNameFrequencies(node.key, locals, frequencies, order, nextOrder);
|
|
1955
|
+
collectNameFrequencies(node.value, locals, frequencies, order, nextOrder);
|
|
1956
|
+
return;
|
|
1844
1957
|
default:
|
|
1845
1958
|
return;
|
|
1846
1959
|
}
|
|
@@ -1915,6 +2028,12 @@ function renameLocalNames(node, map) {
|
|
|
1915
2028
|
left: renameLocalNames(node.left, map),
|
|
1916
2029
|
right: renameLocalNames(node.right, map)
|
|
1917
2030
|
};
|
|
2031
|
+
case "range":
|
|
2032
|
+
return {
|
|
2033
|
+
type: "range",
|
|
2034
|
+
from: renameLocalNames(node.from, map),
|
|
2035
|
+
to: renameLocalNames(node.to, map)
|
|
2036
|
+
};
|
|
1918
2037
|
case "assign": {
|
|
1919
2038
|
const place = node.place.type === "identifier" && map.has(node.place.name) ? { type: "identifier", name: map.get(node.place.name) } : renameLocalNames(node.place, map);
|
|
1920
2039
|
return {
|
|
@@ -1944,6 +2063,12 @@ function renameLocalNames(node, map) {
|
|
|
1944
2063
|
binding: renameLocalNamesBinding(node.binding, map),
|
|
1945
2064
|
body: renameLocalNames(node.body, map)
|
|
1946
2065
|
};
|
|
2066
|
+
case "whileArrayComprehension":
|
|
2067
|
+
return {
|
|
2068
|
+
type: "whileArrayComprehension",
|
|
2069
|
+
condition: renameLocalNames(node.condition, map),
|
|
2070
|
+
body: renameLocalNames(node.body, map)
|
|
2071
|
+
};
|
|
1947
2072
|
case "objectComprehension":
|
|
1948
2073
|
return {
|
|
1949
2074
|
type: "objectComprehension",
|
|
@@ -1951,34 +2076,31 @@ function renameLocalNames(node, map) {
|
|
|
1951
2076
|
key: renameLocalNames(node.key, map),
|
|
1952
2077
|
value: renameLocalNames(node.value, map)
|
|
1953
2078
|
};
|
|
2079
|
+
case "whileObjectComprehension":
|
|
2080
|
+
return {
|
|
2081
|
+
type: "whileObjectComprehension",
|
|
2082
|
+
condition: renameLocalNames(node.condition, map),
|
|
2083
|
+
key: renameLocalNames(node.key, map),
|
|
2084
|
+
value: renameLocalNames(node.value, map)
|
|
2085
|
+
};
|
|
1954
2086
|
default:
|
|
1955
2087
|
return node;
|
|
1956
2088
|
}
|
|
1957
2089
|
}
|
|
1958
2090
|
function renameLocalNamesBinding(binding, map) {
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
type: "binding:
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
2091
|
+
const source = renameLocalNames(binding.source, map);
|
|
2092
|
+
switch (binding.type) {
|
|
2093
|
+
case "binding:bareIn":
|
|
2094
|
+
return { type: "binding:bareIn", source };
|
|
2095
|
+
case "binding:bareOf":
|
|
2096
|
+
return { type: "binding:bareOf", source };
|
|
2097
|
+
case "binding:valueIn":
|
|
2098
|
+
return { type: "binding:valueIn", value: map.get(binding.value) ?? binding.value, source };
|
|
2099
|
+
case "binding:keyValueIn":
|
|
2100
|
+
return { type: "binding:keyValueIn", key: map.get(binding.key) ?? binding.key, value: map.get(binding.value) ?? binding.value, source };
|
|
2101
|
+
case "binding:keyOf":
|
|
2102
|
+
return { type: "binding:keyOf", key: map.get(binding.key) ?? binding.key, source };
|
|
1968
2103
|
}
|
|
1969
|
-
if (binding.type === "binding:keyValueIn") {
|
|
1970
|
-
return {
|
|
1971
|
-
type: "binding:keyValueIn",
|
|
1972
|
-
key: map.get(binding.key) ?? binding.key,
|
|
1973
|
-
value: map.get(binding.value) ?? binding.value,
|
|
1974
|
-
source: renameLocalNames(binding.source, map)
|
|
1975
|
-
};
|
|
1976
|
-
}
|
|
1977
|
-
return {
|
|
1978
|
-
type: "binding:keyOf",
|
|
1979
|
-
key: map.get(binding.key) ?? binding.key,
|
|
1980
|
-
source: renameLocalNames(binding.source, map)
|
|
1981
|
-
};
|
|
1982
2104
|
}
|
|
1983
2105
|
function renameLocalNamesElse(elseBranch, map) {
|
|
1984
2106
|
if (elseBranch.type === "else") {
|
|
@@ -2025,14 +2147,20 @@ function compile(source, options) {
|
|
|
2025
2147
|
let lowered = options?.optimize ? optimizeIR(ir) : ir;
|
|
2026
2148
|
if (options?.minifyNames)
|
|
2027
2149
|
lowered = minifyLocalNamesIR(lowered);
|
|
2028
|
-
const
|
|
2150
|
+
const domainMaps = options?.domainConfig ? domainRefsFromConfig(options.domainConfig) : undefined;
|
|
2029
2151
|
return encodeIR(lowered, {
|
|
2030
|
-
|
|
2152
|
+
...domainMaps,
|
|
2031
2153
|
dedupeValues: options?.dedupeValues,
|
|
2032
2154
|
dedupeMinBytes: options?.dedupeMinBytes
|
|
2033
2155
|
});
|
|
2034
2156
|
}
|
|
2035
2157
|
function parseNumber(raw) {
|
|
2158
|
+
if (raw === "nan")
|
|
2159
|
+
return NaN;
|
|
2160
|
+
if (raw === "inf")
|
|
2161
|
+
return Infinity;
|
|
2162
|
+
if (raw === "-inf")
|
|
2163
|
+
return -Infinity;
|
|
2036
2164
|
if (/^-?0x/i.test(raw))
|
|
2037
2165
|
return parseInt(raw, 16);
|
|
2038
2166
|
if (/^-?0b/i.test(raw)) {
|
|
@@ -2147,6 +2275,9 @@ semantics.addOperation("toIR", {
|
|
|
2147
2275
|
ExistenceExpr_or(left, _or, right) {
|
|
2148
2276
|
return { type: "binary", op: "or", left: left.toIR(), right: right.toIR() };
|
|
2149
2277
|
},
|
|
2278
|
+
ExistenceExpr_nor(left, _nor, right) {
|
|
2279
|
+
return { type: "binary", op: "nor", left: left.toIR(), right: right.toIR() };
|
|
2280
|
+
},
|
|
2150
2281
|
BitExpr_and(left, _op, right) {
|
|
2151
2282
|
return { type: "binary", op: "bitAnd", left: left.toIR(), right: right.toIR() };
|
|
2152
2283
|
},
|
|
@@ -2156,6 +2287,9 @@ semantics.addOperation("toIR", {
|
|
|
2156
2287
|
BitExpr_or(left, _op, right) {
|
|
2157
2288
|
return { type: "binary", op: "bitOr", left: left.toIR(), right: right.toIR() };
|
|
2158
2289
|
},
|
|
2290
|
+
RangeExpr_range(left, _op, right) {
|
|
2291
|
+
return { type: "range", from: left.toIR(), to: right.toIR() };
|
|
2292
|
+
},
|
|
2159
2293
|
CompareExpr_binary(left, op, right) {
|
|
2160
2294
|
const map = {
|
|
2161
2295
|
"==": "eq",
|
|
@@ -2196,6 +2330,9 @@ semantics.addOperation("toIR", {
|
|
|
2196
2330
|
UnaryExpr_not(_op, value) {
|
|
2197
2331
|
return { type: "unary", op: "not", value: value.toIR() };
|
|
2198
2332
|
},
|
|
2333
|
+
UnaryExpr_logicalNot(_not, value) {
|
|
2334
|
+
return { type: "unary", op: "logicalNot", value: value.toIR() };
|
|
2335
|
+
},
|
|
2199
2336
|
UnaryExpr_delete(_del, place) {
|
|
2200
2337
|
return { type: "unary", op: "delete", value: place.toIR() };
|
|
2201
2338
|
},
|
|
@@ -2249,14 +2386,6 @@ semantics.addOperation("toIR", {
|
|
|
2249
2386
|
ConditionalElse_else(_else, block) {
|
|
2250
2387
|
return { type: "else", block: block.toIR() };
|
|
2251
2388
|
},
|
|
2252
|
-
DoExpr(_do, block, _end) {
|
|
2253
|
-
const body = block.toIR();
|
|
2254
|
-
if (body.length === 0)
|
|
2255
|
-
return { type: "undefined" };
|
|
2256
|
-
if (body.length === 1)
|
|
2257
|
-
return body[0];
|
|
2258
|
-
return { type: "program", body };
|
|
2259
|
-
},
|
|
2260
2389
|
WhileExpr(_while, condition, _do, block, _end) {
|
|
2261
2390
|
return {
|
|
2262
2391
|
type: "while",
|
|
@@ -2271,30 +2400,44 @@ semantics.addOperation("toIR", {
|
|
|
2271
2400
|
body: block.toIR()
|
|
2272
2401
|
};
|
|
2273
2402
|
},
|
|
2274
|
-
BindingExpr(iterOrExpr) {
|
|
2275
|
-
const node = iterOrExpr.toIR();
|
|
2276
|
-
if (typeof node === "object" && node && "type" in node && String(node.type).startsWith("binding:")) {
|
|
2277
|
-
return node;
|
|
2278
|
-
}
|
|
2279
|
-
return { type: "binding:expr", source: node };
|
|
2280
|
-
},
|
|
2281
2403
|
Array_empty(_open, _close) {
|
|
2282
2404
|
return { type: "array", items: [] };
|
|
2283
2405
|
},
|
|
2284
|
-
|
|
2406
|
+
Array_forComprehension(_open, body, _for, binding, _close) {
|
|
2285
2407
|
return {
|
|
2286
2408
|
type: "arrayComprehension",
|
|
2287
2409
|
binding: binding.toIR(),
|
|
2288
2410
|
body: body.toIR()
|
|
2289
2411
|
};
|
|
2290
2412
|
},
|
|
2413
|
+
Array_whileComprehension(_open, body, _while, condition, _close) {
|
|
2414
|
+
return {
|
|
2415
|
+
type: "whileArrayComprehension",
|
|
2416
|
+
condition: condition.toIR(),
|
|
2417
|
+
body: body.toIR()
|
|
2418
|
+
};
|
|
2419
|
+
},
|
|
2420
|
+
Array_inComprehension(_open, body, _in, source, _close) {
|
|
2421
|
+
return {
|
|
2422
|
+
type: "arrayComprehension",
|
|
2423
|
+
binding: { type: "binding:bareIn", source: source.toIR() },
|
|
2424
|
+
body: body.toIR()
|
|
2425
|
+
};
|
|
2426
|
+
},
|
|
2427
|
+
Array_ofComprehension(_open, body, _of, source, _close) {
|
|
2428
|
+
return {
|
|
2429
|
+
type: "arrayComprehension",
|
|
2430
|
+
binding: { type: "binding:bareOf", source: source.toIR() },
|
|
2431
|
+
body: body.toIR()
|
|
2432
|
+
};
|
|
2433
|
+
},
|
|
2291
2434
|
Array_values(_open, items, _close) {
|
|
2292
2435
|
return { type: "array", items: normalizeList(items.toIR()) };
|
|
2293
2436
|
},
|
|
2294
2437
|
Object_empty(_open, _close) {
|
|
2295
2438
|
return { type: "object", entries: [] };
|
|
2296
2439
|
},
|
|
2297
|
-
|
|
2440
|
+
Object_forComprehension(_open, key, _colon, value, _for, binding, _close) {
|
|
2298
2441
|
return {
|
|
2299
2442
|
type: "objectComprehension",
|
|
2300
2443
|
binding: binding.toIR(),
|
|
@@ -2302,6 +2445,30 @@ semantics.addOperation("toIR", {
|
|
|
2302
2445
|
value: value.toIR()
|
|
2303
2446
|
};
|
|
2304
2447
|
},
|
|
2448
|
+
Object_whileComprehension(_open, key, _colon, value, _while, condition, _close) {
|
|
2449
|
+
return {
|
|
2450
|
+
type: "whileObjectComprehension",
|
|
2451
|
+
condition: condition.toIR(),
|
|
2452
|
+
key: key.toIR(),
|
|
2453
|
+
value: value.toIR()
|
|
2454
|
+
};
|
|
2455
|
+
},
|
|
2456
|
+
Object_inComprehension(_open, key, _colon, value, _in, source, _close) {
|
|
2457
|
+
return {
|
|
2458
|
+
type: "objectComprehension",
|
|
2459
|
+
binding: { type: "binding:bareIn", source: source.toIR() },
|
|
2460
|
+
key: key.toIR(),
|
|
2461
|
+
value: value.toIR()
|
|
2462
|
+
};
|
|
2463
|
+
},
|
|
2464
|
+
Object_ofComprehension(_open, key, _colon, value, _of, source, _close) {
|
|
2465
|
+
return {
|
|
2466
|
+
type: "objectComprehension",
|
|
2467
|
+
binding: { type: "binding:bareOf", source: source.toIR() },
|
|
2468
|
+
key: key.toIR(),
|
|
2469
|
+
value: value.toIR()
|
|
2470
|
+
};
|
|
2471
|
+
},
|
|
2305
2472
|
Object_pairs(_open, pairs, _close) {
|
|
2306
2473
|
return {
|
|
2307
2474
|
type: "object",
|
|
@@ -2330,6 +2497,18 @@ semantics.addOperation("toIR", {
|
|
|
2330
2497
|
source: source.toIR()
|
|
2331
2498
|
};
|
|
2332
2499
|
},
|
|
2500
|
+
IterBinding_bareIn(_in, source) {
|
|
2501
|
+
return {
|
|
2502
|
+
type: "binding:bareIn",
|
|
2503
|
+
source: source.toIR()
|
|
2504
|
+
};
|
|
2505
|
+
},
|
|
2506
|
+
IterBinding_bareOf(_of, source) {
|
|
2507
|
+
return {
|
|
2508
|
+
type: "binding:bareOf",
|
|
2509
|
+
source: source.toIR()
|
|
2510
|
+
};
|
|
2511
|
+
},
|
|
2333
2512
|
Pair(key, _colon, value) {
|
|
2334
2513
|
return { key: key.toIR(), value: value.toIR() };
|
|
2335
2514
|
},
|
|
@@ -2393,6 +2572,9 @@ semantics.addOperation("toIR", {
|
|
|
2393
2572
|
BooleanKw(_kw) {
|
|
2394
2573
|
return { type: "identifier", name: "boolean" };
|
|
2395
2574
|
},
|
|
2575
|
+
SizeKw(_kw) {
|
|
2576
|
+
return { type: "identifier", name: "size" };
|
|
2577
|
+
},
|
|
2396
2578
|
identifier(_a, _b) {
|
|
2397
2579
|
return { type: "identifier", name: this.sourceString };
|
|
2398
2580
|
},
|