@creationix/rex 0.3.1 → 0.6.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/rx-cli.js ADDED
@@ -0,0 +1,2836 @@
1
+ #!/usr/bin/env node
2
+ // b64.ts
3
+ var regex = /^[0-9a-zA-Z\-_]*$/;
4
+ var chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_";
5
+ var decodeTable = new Uint8Array(256).fill(255);
6
+ var encodeTable = new Uint8Array(64);
7
+ for (let i = 0;i < 64; i++) {
8
+ const code = chars.charCodeAt(i);
9
+ decodeTable[code] = i;
10
+ encodeTable[i] = code;
11
+ }
12
+ function is(byte) {
13
+ return decodeTable[byte] !== 255;
14
+ }
15
+ function stringify(num) {
16
+ if (!Number.isSafeInteger(num) || num < 0) {
17
+ throw new Error(`Cannot stringify ${num} as base64`);
18
+ }
19
+ let result = "";
20
+ while (num > 0) {
21
+ result = chars[num % 64] + result;
22
+ num = Math.floor(num / 64);
23
+ }
24
+ return result;
25
+ }
26
+ function read(data, left, right) {
27
+ let result = 0;
28
+ for (let i = left;i < right; i++) {
29
+ const digit = decodeTable[data[i]];
30
+ if (digit === 255) {
31
+ throw new Error(`Invalid base64 character code: ${data[i]}`);
32
+ }
33
+ result = result * 64 + digit;
34
+ }
35
+ return result;
36
+ }
37
+
38
+ // rexc.ts
39
+ var BUILTIN_REFS = {
40
+ n: null,
41
+ t: true,
42
+ f: false,
43
+ u: undefined,
44
+ nan: NaN,
45
+ inf: Infinity,
46
+ nif: -Infinity
47
+ };
48
+ var ENCODE_DEFAULTS = {
49
+ chainSplit: "/",
50
+ indexes: 32,
51
+ refs: {}
52
+ };
53
+ var DECODE_DEFAULTS = {
54
+ lazy: false,
55
+ refs: {}
56
+ };
57
+ function toZigZag(num) {
58
+ if (num >= -2147483648 && num <= 2147483647) {
59
+ return num << 1 ^ num >> 31;
60
+ }
61
+ return num < 0 ? num * -2 - 1 : num * 2;
62
+ }
63
+ function writeStringPair(tag, value) {
64
+ if (!regex.test(value)) {
65
+ throw new TypeError(`String contains invalid characters for inline encoding: ${value}`);
66
+ }
67
+ return tag + value;
68
+ }
69
+ function writeUnsigned(tag, value) {
70
+ if (value < 0) {
71
+ throw new RangeError(`Value must be non-negative, got ${value}`);
72
+ }
73
+ return `${tag}${stringify(value)}`;
74
+ }
75
+ function writeSigned(tag, value) {
76
+ return `${tag}${stringify(toZigZag(value))}`;
77
+ }
78
+ function stringify2(value, options) {
79
+ const { onChunk, ...rest } = options ?? {};
80
+ if (onChunk) {
81
+ encode(value, {
82
+ ...rest,
83
+ onChunk: (chunk, offset) => onChunk(new TextDecoder().decode(chunk), offset)
84
+ });
85
+ return;
86
+ }
87
+ return new TextDecoder().decode(encode(value, rest));
88
+ }
89
+ function encode(rootValue, options) {
90
+ const opts = { ...ENCODE_DEFAULTS, ...options };
91
+ const parts = [];
92
+ let byteLength = 0;
93
+ const onChunk = opts.onChunk ?? ((chunk) => parts.push(chunk));
94
+ const chainSplit = opts.chainSplit;
95
+ const refs = Object.fromEntries(Object.entries({ ...opts.refs }).map(([key, val]) => [makeKey(val), key]));
96
+ const indexThreshold = typeof opts.indexes === "number" ? opts.indexes : Infinity;
97
+ const seenOffsets = {};
98
+ const schemaOffsets = {};
99
+ const seenCosts = {};
100
+ for (const [key, val] of Object.entries(opts.refs)) {
101
+ if (typeof val === "object" && val !== null) {
102
+ if (Array.isArray(val)) {
103
+ schemaOffsets[makeKey(val)] = key;
104
+ } else {
105
+ schemaOffsets[makeKey(Object.keys(val))] = key;
106
+ }
107
+ }
108
+ }
109
+ const duplicatePrefixes = new Set;
110
+ const seenPrefixes = new Set;
111
+ scanPrefixes(rootValue);
112
+ function scanPrefixes(value) {
113
+ if (!chainSplit)
114
+ return;
115
+ if (typeof value === "string" && value.indexOf(chainSplit) >= 0) {
116
+ let offset2 = 0;
117
+ if (!seenPrefixes.has(value)) {
118
+ while (offset2 < value.length) {
119
+ const nextDelimiter = value.indexOf(chainSplit, offset2 + 1);
120
+ if (nextDelimiter === -1)
121
+ break;
122
+ const prefix = value.slice(0, nextDelimiter);
123
+ if (seenPrefixes.has(prefix)) {
124
+ duplicatePrefixes.add(prefix);
125
+ } else {
126
+ seenPrefixes.add(prefix);
127
+ }
128
+ offset2 = nextDelimiter;
129
+ }
130
+ }
131
+ } else if (value && typeof value === "object") {
132
+ if (Array.isArray(value)) {
133
+ for (const item of value) {
134
+ scanPrefixes(item);
135
+ }
136
+ } else {
137
+ for (const [key, val] of Object.entries(value)) {
138
+ scanPrefixes(key);
139
+ scanPrefixes(val);
140
+ }
141
+ }
142
+ }
143
+ }
144
+ writeAny(rootValue);
145
+ if (opts.onChunk)
146
+ return;
147
+ const output = new Uint8Array(byteLength);
148
+ let offset = 0;
149
+ for (const chunk of parts) {
150
+ output.set(chunk, offset);
151
+ offset += chunk.byteLength;
152
+ }
153
+ return output;
154
+ function pushBytes(bytes) {
155
+ onChunk(bytes, byteLength);
156
+ return byteLength += bytes.byteLength;
157
+ }
158
+ function pushString(str) {
159
+ const bytes = new TextEncoder().encode(str);
160
+ return pushBytes(bytes);
161
+ }
162
+ function writeAny(value) {
163
+ const key = makeKey(value);
164
+ const refKey = refs[key];
165
+ if (refKey !== undefined) {
166
+ return pushString(writeStringPair("'", refKey));
167
+ }
168
+ const seenOffset = seenOffsets[key];
169
+ if (seenOffset !== undefined) {
170
+ const delta = byteLength - seenOffset;
171
+ const seenCost = seenCosts[key] ?? 0;
172
+ const pointerCost = Math.ceil(Math.log(delta + 1) / Math.log(64)) + 1;
173
+ if (pointerCost < seenCost) {
174
+ return pushString(writeUnsigned("^", delta));
175
+ }
176
+ }
177
+ const before = byteLength;
178
+ const ret = writeAnyInner(value);
179
+ seenOffsets[key] = byteLength;
180
+ seenCosts[key] = byteLength - before;
181
+ return ret;
182
+ }
183
+ function writeAnyInner(value) {
184
+ switch (typeof value) {
185
+ case "string":
186
+ return writeString(value);
187
+ case "number":
188
+ return writeNumber(value);
189
+ case "boolean":
190
+ return pushString(writeStringPair("'", value ? "t" : "f"));
191
+ case "undefined":
192
+ return pushString(writeStringPair("'", "u"));
193
+ case "object":
194
+ if (value === null)
195
+ return pushString(writeStringPair("'", "n"));
196
+ if (Array.isArray(value))
197
+ return writeArray(value);
198
+ return writeObject(value);
199
+ default:
200
+ throw new TypeError(`Unsupported value type: ${typeof value}`);
201
+ }
202
+ }
203
+ function writeString(value) {
204
+ if (chainSplit && value.indexOf(chainSplit) >= 0) {
205
+ let offset2 = value.length;
206
+ let head;
207
+ let tail;
208
+ while (offset2 > 0) {
209
+ offset2 = value.lastIndexOf(chainSplit, offset2 - 1);
210
+ if (offset2 <= 0)
211
+ break;
212
+ const prefix = value.slice(0, offset2);
213
+ if (duplicatePrefixes.has(prefix)) {
214
+ head = prefix;
215
+ tail = value.substring(offset2);
216
+ break;
217
+ }
218
+ }
219
+ if (head && tail) {
220
+ const before = byteLength;
221
+ writeAny(tail);
222
+ writeAny(head);
223
+ const size = byteLength - before;
224
+ return pushString(writeUnsigned(".", size));
225
+ }
226
+ }
227
+ const utf8 = new TextEncoder().encode(value);
228
+ pushBytes(utf8);
229
+ return pushString(writeUnsigned(",", utf8.byteLength));
230
+ }
231
+ function writeNumber(value) {
232
+ if (Number.isNaN(value)) {
233
+ return pushString(writeStringPair("'", "nan"));
234
+ }
235
+ if (value === Infinity) {
236
+ return pushString(writeStringPair("'", "inf"));
237
+ }
238
+ if (value === -Infinity) {
239
+ return pushString(writeStringPair("'", "nif"));
240
+ }
241
+ const [base, exp] = splitNumber(value);
242
+ if (exp >= 0 && exp < 5 && Number.isInteger(base) && Number.isSafeInteger(base)) {
243
+ return pushString(writeSigned("+", value));
244
+ }
245
+ pushString(writeSigned("+", base));
246
+ return pushString(writeSigned("*", exp));
247
+ }
248
+ function writeArray(value) {
249
+ const start = byteLength;
250
+ writeValues(value);
251
+ return pushString(writeUnsigned(";", byteLength - start));
252
+ }
253
+ function writeValues(values) {
254
+ const length = values.length;
255
+ const offsets = length > indexThreshold ? new Array(length) : undefined;
256
+ for (let f = length - 1, i = f;i >= 0; i--) {
257
+ writeAny(values[i]);
258
+ if (offsets) {
259
+ offsets[i] = byteLength;
260
+ }
261
+ }
262
+ if (offsets) {
263
+ const lastOffset = offsets[offsets.length - 1];
264
+ const width = Math.ceil(Math.log(byteLength - lastOffset + 1) / Math.log(64));
265
+ const pointers = offsets.map((offset2) => stringify(byteLength - offset2).padStart(width, "0")).join("");
266
+ pushString(pointers);
267
+ if (width > 8) {
268
+ throw new Error(`Index width exceeds maximum of 8 characters: ${width}`);
269
+ }
270
+ pushString(writeUnsigned("#", values.length << 3 | width - 1));
271
+ }
272
+ }
273
+ function writeObject(value) {
274
+ const keys = Object.keys(value);
275
+ const length = keys.length;
276
+ if (length === 0) {
277
+ return pushString(":");
278
+ }
279
+ const keysKey = makeKey(keys);
280
+ const schemaTarget = schemaOffsets[keysKey] ?? seenOffsets[keysKey];
281
+ if (schemaTarget !== undefined) {
282
+ return writeSchemaObject(value, schemaTarget);
283
+ }
284
+ const before = byteLength;
285
+ const offsets = length > indexThreshold ? {} : undefined;
286
+ let lastOffset;
287
+ const entries = Object.entries(value);
288
+ for (let f = entries.length - 1, i = f;i >= 0; i--) {
289
+ const [key, val] = entries[i];
290
+ writeAny(val);
291
+ writeAny(key);
292
+ if (offsets) {
293
+ offsets[key] = byteLength;
294
+ lastOffset = lastOffset ?? byteLength;
295
+ }
296
+ }
297
+ if (offsets && lastOffset !== undefined) {
298
+ const width = Math.ceil(Math.log(byteLength - lastOffset + 1) / Math.log(64));
299
+ const pointers = Object.entries(offsets).sort(([a], [b]) => utf8Sort(a, b)).map(([, offset2]) => stringify(byteLength - offset2).padStart(width, "0")).join("");
300
+ pushString(pointers);
301
+ if (width > 8) {
302
+ throw new Error(`Index width exceeds maximum of 8 characters: ${width}`);
303
+ }
304
+ pushString(writeUnsigned("#", length << 3 | width - 1));
305
+ }
306
+ const ret = pushString(writeUnsigned(":", byteLength - before));
307
+ schemaOffsets[keysKey] = byteLength;
308
+ return ret;
309
+ }
310
+ function writeSchemaObject(value, target) {
311
+ const before = byteLength;
312
+ writeValues(Object.values(value));
313
+ if (typeof target === "string") {
314
+ pushString(writeStringPair("'", target));
315
+ } else {
316
+ pushString(writeUnsigned("^", byteLength - target));
317
+ }
318
+ return pushString(writeUnsigned(":", byteLength - before));
319
+ }
320
+ }
321
+ function zigzagDecode(num) {
322
+ if (num <= 4294967295) {
323
+ return num >>> 1 ^ -(num & 1);
324
+ }
325
+ return num % 2 === 0 ? num / 2 : (num + 1) / -2;
326
+ }
327
+ function b64Skip(data, offset) {
328
+ while (is(data[--offset] ?? 0))
329
+ ;
330
+ return offset + 1;
331
+ }
332
+ function peek(data, right) {
333
+ let left = b64Skip(data, right);
334
+ if (left <= 0) {
335
+ throw new SyntaxError("Unexpected end of input seeking for non-b64 tag");
336
+ }
337
+ const tag = data[--left];
338
+ return [left, tag];
339
+ }
340
+ function unpackIndex(data, left, right) {
341
+ const b64 = read(data, left, right);
342
+ return {
343
+ width: (b64 & 7) + 1,
344
+ count: b64 >> 3
345
+ };
346
+ }
347
+ function get(data, right = data.length) {
348
+ let [left, tag] = peek(data, right);
349
+ if (tag === 39) {
350
+ const ref = new TextDecoder().decode(data.subarray(left + 1, right));
351
+ if (ref in BUILTIN_REFS) {
352
+ return {
353
+ type: "primitive",
354
+ left,
355
+ right,
356
+ value: BUILTIN_REFS[ref]
357
+ };
358
+ }
359
+ return {
360
+ type: "pointer",
361
+ left,
362
+ right,
363
+ target: ref
364
+ };
365
+ }
366
+ const b64 = read(data, left + 1, right);
367
+ switch (tag) {
368
+ case 44:
369
+ return {
370
+ type: "primitive",
371
+ left: left - b64,
372
+ right,
373
+ value: new TextDecoder().decode(data.subarray(left - b64, left))
374
+ };
375
+ case 59: {
376
+ let content = left;
377
+ left -= b64;
378
+ let index;
379
+ if (content > left) {
380
+ const [l, t] = peek(data, content);
381
+ if (t === 35) {
382
+ index = unpackIndex(data, l + 1, content);
383
+ content = l - index.width * index.count;
384
+ }
385
+ }
386
+ return {
387
+ type: "array",
388
+ left,
389
+ right,
390
+ content,
391
+ index
392
+ };
393
+ }
394
+ case 58: {
395
+ let content = left;
396
+ left -= b64;
397
+ let index;
398
+ let schema;
399
+ while (content > left) {
400
+ const [l, t] = peek(data, content);
401
+ if (t === 35 && index === undefined) {
402
+ index = unpackIndex(data, l + 1, content);
403
+ content = l - index.width * index.count;
404
+ } else if ((t === 39 || t === 94) && schema === undefined) {
405
+ const ptr = get(data, content);
406
+ if (ptr.type !== "pointer") {
407
+ break;
408
+ }
409
+ if (t === 94) {
410
+ const target = get(data, ptr.target);
411
+ if (target.type !== "array" && target.type !== "object") {
412
+ break;
413
+ }
414
+ }
415
+ schema = ptr.target;
416
+ content = l;
417
+ } else {
418
+ break;
419
+ }
420
+ }
421
+ return {
422
+ type: "object",
423
+ left,
424
+ right,
425
+ content,
426
+ schema,
427
+ index
428
+ };
429
+ }
430
+ case 94:
431
+ return {
432
+ type: "pointer",
433
+ left,
434
+ right,
435
+ target: left - b64
436
+ };
437
+ case 46: {
438
+ return {
439
+ type: "chain",
440
+ left: left - b64,
441
+ right,
442
+ content: left
443
+ };
444
+ throw new Error("TODO: implement string chain reading");
445
+ }
446
+ case 42: {
447
+ const int = get(data, left);
448
+ if (int.type === "primitive" && typeof int.value === "number") {
449
+ return {
450
+ type: "primitive",
451
+ left: int.left,
452
+ right,
453
+ value: parseFloat(`${int.value}e${zigzagDecode(b64)}`)
454
+ };
455
+ }
456
+ throw new SyntaxError("Invalid number format in decimal");
457
+ }
458
+ case 43:
459
+ return {
460
+ type: "primitive",
461
+ left,
462
+ right,
463
+ value: zigzagDecode(b64)
464
+ };
465
+ default:
466
+ throw new SyntaxError(`Unknown tag: ${String.fromCharCode(tag)}`);
467
+ }
468
+ }
469
+ function* getEntries(context, node) {
470
+ if (node.type !== "object") {
471
+ throw new TypeError("Node must be an object");
472
+ }
473
+ const { data, refs } = context;
474
+ const { schema } = node;
475
+ let right = node.content;
476
+ if (schema !== undefined) {
477
+ let keyNodes;
478
+ if (typeof schema === "string") {
479
+ if (!(schema in refs)) {
480
+ throw new ReferenceError(`Unknown schema reference: ${schema}`);
481
+ }
482
+ const ref = refs[schema];
483
+ if (typeof ref !== "object" || ref === null) {
484
+ throw new TypeError("Schema reference must point to an object or array");
485
+ }
486
+ const keyStrings = Array.isArray(ref) ? ref : Object.keys(ref);
487
+ keyNodes = keyStrings.map((k) => ({
488
+ type: "primitive",
489
+ left: -1,
490
+ right: -1,
491
+ value: k
492
+ }));
493
+ } else if (typeof schema === "number") {
494
+ let targetNode = get(data, schema);
495
+ if (targetNode.type === "array") {
496
+ keyNodes = getEach(context, targetNode);
497
+ } else if (targetNode.type === "object") {
498
+ keyNodes = getEntries(context, targetNode).map(([k]) => k);
499
+ } else {
500
+ throw new TypeError("Schema reference must point to an object or array");
501
+ }
502
+ } else {
503
+ throw new TypeError("Invalid schema reference type");
504
+ }
505
+ const values = getEach(context, node);
506
+ const keysIter = keyNodes[Symbol.iterator]();
507
+ for (const value of values) {
508
+ const key = keysIter.next();
509
+ if (key.done) {
510
+ throw new SyntaxError("Not enough keys in schema reference for object entries");
511
+ }
512
+ yield [key.value, value];
513
+ }
514
+ return;
515
+ }
516
+ while (right > node.left) {
517
+ const key = get(data, right);
518
+ right = key.left;
519
+ const value = get(data, right);
520
+ right = value.left;
521
+ yield [key, value];
522
+ }
523
+ }
524
+ function* getEach(context, node) {
525
+ if (node.type !== "array" && node.type !== "object" && node.type !== "chain") {
526
+ throw new TypeError("Node must be an array, object, or chain");
527
+ }
528
+ const { data } = context;
529
+ let right = node.content;
530
+ while (right > node.left) {
531
+ const value = get(data, right);
532
+ right = value.left;
533
+ yield value;
534
+ }
535
+ }
536
+ function makeContext(input, options) {
537
+ return {
538
+ data: input,
539
+ refs: options?.refs ?? DECODE_DEFAULTS.refs,
540
+ lazy: options?.lazy ?? DECODE_DEFAULTS.lazy,
541
+ resolveCache: options?.resolveCache ?? new Map
542
+ };
543
+ }
544
+ function decode(input, options) {
545
+ let context = makeContext(input, options);
546
+ return resolve(context, get(context.data));
547
+ }
548
+ function resolve(context, node, lazy = false) {
549
+ const { data, refs } = context;
550
+ if (node.type === "primitive") {
551
+ return node.value;
552
+ }
553
+ if (node.type === "pointer") {
554
+ const target = node.target;
555
+ if (typeof target === "string") {
556
+ if (target in refs) {
557
+ return refs[target];
558
+ }
559
+ throw new ReferenceError(`Unknown reference: ${target}`);
560
+ } else if (typeof target === "number") {
561
+ return resolve(context, get(data, target));
562
+ }
563
+ throw new TypeError(`Invalid pointer target type: ${typeof target}`);
564
+ }
565
+ if (node.type === "object") {
566
+ const obj = {};
567
+ for (const [keyNode, value] of getEntries(context, node)) {
568
+ const key = resolve(context, keyNode);
569
+ if (typeof key !== "string") {
570
+ throw new SyntaxError("Expected string key in object");
571
+ }
572
+ obj[key] = resolve(context, value);
573
+ }
574
+ return obj;
575
+ }
576
+ if (node.type === "array") {
577
+ return Array.from(getEach(context, node)).map((value) => resolve(context, value));
578
+ }
579
+ if (node.type === "chain") {
580
+ let expandChain = function(node2) {
581
+ for (const part of getEach(context, node2)) {
582
+ if (part.type === "chain") {
583
+ expandChain(part);
584
+ } else {
585
+ parts.push(resolve(context, part));
586
+ }
587
+ }
588
+ };
589
+ const parts = [];
590
+ expandChain(node);
591
+ if (parts.length === 0) {
592
+ throw new SyntaxError("Chain must have at least one part");
593
+ }
594
+ if (parts.every((part) => typeof part === "string")) {
595
+ return parts.join("");
596
+ }
597
+ if (parts.some((part) => Array.isArray(part))) {
598
+ return parts.flat();
599
+ }
600
+ throw new Error("TODO: implement complex chain resolution");
601
+ }
602
+ throw new TypeError(`Unknown node type - ${JSON.stringify(node)}`);
603
+ }
604
+ function parse(input, options) {
605
+ return decode(new TextEncoder().encode(input), options);
606
+ }
607
+ function trimZeroes(str) {
608
+ const trimmed = str.replace(/0+$/, "");
609
+ const zeroCount = str.length - trimmed.length;
610
+ return [parseInt(trimmed, 10), zeroCount];
611
+ }
612
+ function splitNumber(val) {
613
+ if (Number.isInteger(val)) {
614
+ if (Math.abs(val) < 10) {
615
+ return [val, 0];
616
+ }
617
+ if (Math.abs(val) < 999999999999999900000) {
618
+ return trimZeroes(val.toString());
619
+ }
620
+ }
621
+ const decStr = val.toPrecision(14).match(/^([-+]?\d+)(?:\.(\d+))?$/);
622
+ if (decStr) {
623
+ const b1 = parseInt((decStr[1] ?? "") + (decStr[2] ?? ""), 10);
624
+ const e1 = -(decStr[2]?.length ?? 0);
625
+ if (e1 === 0) {
626
+ return [b1, 0];
627
+ }
628
+ const [b2, e2] = splitNumber(b1);
629
+ return [b2, e1 + e2];
630
+ }
631
+ const sciStr = val.toExponential(14).match(/^([+-]?\d+)(?:\.(\d+))?(?:e([+-]?\d+))$/);
632
+ if (sciStr) {
633
+ const e1 = -(sciStr[2]?.length ?? 0);
634
+ const e2 = parseInt(sciStr[3] ?? "0", 10);
635
+ const [b1, e3] = trimZeroes(sciStr[1] + (sciStr[2] ?? ""));
636
+ return [b1, e1 + e2 + e3];
637
+ }
638
+ throw new Error(`Invalid number format: ${val}`);
639
+ }
640
+ var KeyMap = new WeakMap;
641
+ function makeKey(val) {
642
+ if (val && typeof val === "object") {
643
+ let key = KeyMap.get(val);
644
+ if (!key) {
645
+ key = JSON.stringify(val);
646
+ KeyMap.set(val, key);
647
+ }
648
+ return key;
649
+ }
650
+ return JSON.stringify(val);
651
+ }
652
+ function utf8Sort(a, b) {
653
+ const len = Math.min(a.length, b.length);
654
+ for (let i = 0;i < len; ) {
655
+ const cpA = a.codePointAt(i) ?? 0;
656
+ const cpB = b.codePointAt(i) ?? 0;
657
+ if (cpA !== cpB)
658
+ return cpA - cpB;
659
+ i += cpA > 65535 ? 2 : 1;
660
+ }
661
+ return a.length - b.length;
662
+ }
663
+
664
+ // rex.ts
665
+ import { createRequire } from "node:module";
666
+ var require2 = createRequire(import.meta.url);
667
+ var rexGrammarModule = require2("./rex.ohm-bundle.cjs");
668
+ var rexGrammar = rexGrammarModule?.default ?? rexGrammarModule;
669
+ var semantics = rexGrammar.createSemantics();
670
+ var DIGITS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_";
671
+ var KEYWORD_OPCODES = new Set(["boolean", "number", "string", "array", "object"]);
672
+ function isPlainObject(value) {
673
+ if (!value || typeof value !== "object" || Array.isArray(value))
674
+ return false;
675
+ const proto = Object.getPrototypeOf(value);
676
+ return proto === Object.prototype || proto === null;
677
+ }
678
+ function isBareKeyName(key) {
679
+ return /^[A-Za-z_][A-Za-z0-9_-]*$/.test(key);
680
+ }
681
+ function isNumericKey(key) {
682
+ if (key === "")
683
+ return false;
684
+ return String(Number(key)) === key && Number.isFinite(Number(key));
685
+ }
686
+ function stringifyKey(key) {
687
+ if (isBareKeyName(key))
688
+ return key;
689
+ if (isNumericKey(key))
690
+ return key;
691
+ return stringifyString(key);
692
+ }
693
+ function stringifyString(value) {
694
+ return JSON.stringify(value);
695
+ }
696
+ function stringifyInline(value) {
697
+ if (value === undefined)
698
+ return "undefined";
699
+ if (value === null)
700
+ return "null";
701
+ if (typeof value === "boolean")
702
+ return value ? "true" : "false";
703
+ if (typeof value === "number") {
704
+ if (Number.isNaN(value))
705
+ return "nan";
706
+ if (value === Infinity)
707
+ return "inf";
708
+ if (value === -Infinity)
709
+ return "-inf";
710
+ return String(value);
711
+ }
712
+ if (typeof value === "string")
713
+ return stringifyString(value);
714
+ if (Array.isArray(value)) {
715
+ if (value.length === 0)
716
+ return "[]";
717
+ return `[${value.map((item) => stringifyInline(item)).join(" ")}]`;
718
+ }
719
+ if (isPlainObject(value)) {
720
+ const entries = Object.entries(value);
721
+ if (entries.length === 0)
722
+ return "{}";
723
+ const body = entries.map(([key, item]) => `${stringifyKey(key)}: ${stringifyInline(item)}`).join(" ");
724
+ return `{${body}}`;
725
+ }
726
+ throw new Error(`Rex stringify() cannot encode value of type ${typeof value}`);
727
+ }
728
+ function fitsInline(rendered, depth, indentSize, maxWidth) {
729
+ if (rendered.includes(`
730
+ `))
731
+ return false;
732
+ return depth * indentSize + rendered.length <= maxWidth;
733
+ }
734
+ function stringifyPretty(value, depth, indentSize, maxWidth) {
735
+ const inline = stringifyInline(value);
736
+ if (fitsInline(inline, depth, indentSize, maxWidth))
737
+ return inline;
738
+ const indent = " ".repeat(depth * indentSize);
739
+ const childIndent = " ".repeat((depth + 1) * indentSize);
740
+ if (Array.isArray(value)) {
741
+ if (value.length === 0)
742
+ return "[]";
743
+ const lines = value.map((item) => {
744
+ const rendered = stringifyPretty(item, depth + 1, indentSize, maxWidth);
745
+ if (!rendered.includes(`
746
+ `))
747
+ return `${childIndent}${rendered}`;
748
+ return `${childIndent}${rendered}`;
749
+ });
750
+ return `[
751
+ ${lines.join(`
752
+ `)}
753
+ ${indent}]`;
754
+ }
755
+ if (isPlainObject(value)) {
756
+ const entries = Object.entries(value);
757
+ if (entries.length === 0)
758
+ return "{}";
759
+ const lines = entries.map(([key, item]) => {
760
+ const keyText = stringifyKey(key);
761
+ const rendered = stringifyPretty(item, depth + 1, indentSize, maxWidth);
762
+ return `${childIndent}${keyText}: ${rendered}`;
763
+ });
764
+ return `{
765
+ ${lines.join(`
766
+ `)}
767
+ ${indent}}`;
768
+ }
769
+ return inline;
770
+ }
771
+ function stringify3(value, options) {
772
+ const indent = options?.indent ?? 2;
773
+ const maxWidth = options?.maxWidth ?? 80;
774
+ if (!Number.isInteger(indent) || indent < 0)
775
+ throw new Error("Rex stringify() indent must be a non-negative integer");
776
+ if (!Number.isInteger(maxWidth) || maxWidth < 20)
777
+ throw new Error("Rex stringify() maxWidth must be an integer >= 20");
778
+ return stringifyPretty(value, 0, indent, maxWidth);
779
+ }
780
+ var DIGIT_SET = new Set(DIGITS.split(""));
781
+ var DIGIT_INDEX = new Map(Array.from(DIGITS).map((char, index) => [char, index]));
782
+ function parseNumber(raw) {
783
+ if (raw === "nan")
784
+ return NaN;
785
+ if (raw === "inf")
786
+ return Infinity;
787
+ if (raw === "-inf")
788
+ return -Infinity;
789
+ if (/^-?0x/i.test(raw))
790
+ return parseInt(raw, 16);
791
+ if (/^-?0b/i.test(raw)) {
792
+ const isNegative = raw.startsWith("-");
793
+ const digits = raw.replace(/^-?0b/i, "");
794
+ const value = parseInt(digits, 2);
795
+ return isNegative ? -value : value;
796
+ }
797
+ return Number(raw);
798
+ }
799
+ function collectStructured(value, out) {
800
+ if (Array.isArray(value)) {
801
+ for (const part of value)
802
+ collectStructured(part, out);
803
+ return;
804
+ }
805
+ if (!value || typeof value !== "object")
806
+ return;
807
+ if ("type" in value || "key" in value && "value" in value) {
808
+ out.push(value);
809
+ }
810
+ }
811
+ function normalizeList(value) {
812
+ const out = [];
813
+ collectStructured(value, out);
814
+ return out;
815
+ }
816
+ function collectPostfixSteps(value, out) {
817
+ if (Array.isArray(value)) {
818
+ for (const part of value)
819
+ collectPostfixSteps(part, out);
820
+ return;
821
+ }
822
+ if (!value || typeof value !== "object")
823
+ return;
824
+ if ("kind" in value)
825
+ out.push(value);
826
+ }
827
+ function normalizePostfixSteps(value) {
828
+ const out = [];
829
+ collectPostfixSteps(value, out);
830
+ return out;
831
+ }
832
+ function buildPostfix(base, steps) {
833
+ let current = base;
834
+ let pendingSegments = [];
835
+ const flushSegments = () => {
836
+ if (pendingSegments.length === 0)
837
+ return;
838
+ current = {
839
+ type: "navigation",
840
+ target: current,
841
+ segments: pendingSegments
842
+ };
843
+ pendingSegments = [];
844
+ };
845
+ for (const step of steps) {
846
+ if (step.kind === "navStatic") {
847
+ pendingSegments.push({ type: "static", key: step.key });
848
+ continue;
849
+ }
850
+ if (step.kind === "navDynamic") {
851
+ pendingSegments.push({ type: "dynamic", key: step.key });
852
+ continue;
853
+ }
854
+ flushSegments();
855
+ current = { type: "call", callee: current, args: step.args };
856
+ }
857
+ flushSegments();
858
+ return current;
859
+ }
860
+ semantics.addOperation("toIR", {
861
+ _iter(...children) {
862
+ return children.map((child) => child.toIR());
863
+ },
864
+ _terminal() {
865
+ return this.sourceString;
866
+ },
867
+ _nonterminal(...children) {
868
+ if (children.length === 1 && children[0])
869
+ return children[0].toIR();
870
+ return children.map((child) => child.toIR());
871
+ },
872
+ Program(expressions) {
873
+ const body = normalizeList(expressions.toIR());
874
+ if (body.length === 1)
875
+ return body[0];
876
+ return { type: "program", body };
877
+ },
878
+ Block(expressions) {
879
+ return normalizeList(expressions.toIR());
880
+ },
881
+ Elements(first, separatorsAndItems, maybeTrailingComma, maybeEmpty) {
882
+ return normalizeList([
883
+ first.toIR(),
884
+ separatorsAndItems.toIR(),
885
+ maybeTrailingComma.toIR(),
886
+ maybeEmpty.toIR()
887
+ ]);
888
+ },
889
+ AssignExpr_assign(place, op, value) {
890
+ return {
891
+ type: "assign",
892
+ op: op.sourceString,
893
+ place: place.toIR(),
894
+ value: value.toIR()
895
+ };
896
+ },
897
+ ExistenceExpr_and(left, _and, right) {
898
+ return { type: "binary", op: "and", left: left.toIR(), right: right.toIR() };
899
+ },
900
+ ExistenceExpr_or(left, _or, right) {
901
+ return { type: "binary", op: "or", left: left.toIR(), right: right.toIR() };
902
+ },
903
+ ExistenceExpr_nor(left, _nor, right) {
904
+ return { type: "binary", op: "nor", left: left.toIR(), right: right.toIR() };
905
+ },
906
+ BitExpr_and(left, _op, right) {
907
+ return { type: "binary", op: "bitAnd", left: left.toIR(), right: right.toIR() };
908
+ },
909
+ BitExpr_xor(left, _op, right) {
910
+ return { type: "binary", op: "bitXor", left: left.toIR(), right: right.toIR() };
911
+ },
912
+ BitExpr_or(left, _op, right) {
913
+ return { type: "binary", op: "bitOr", left: left.toIR(), right: right.toIR() };
914
+ },
915
+ RangeExpr_range(left, _op, right) {
916
+ return { type: "range", from: left.toIR(), to: right.toIR() };
917
+ },
918
+ CompareExpr_binary(left, op, right) {
919
+ const map = {
920
+ "==": "eq",
921
+ "!=": "neq",
922
+ ">": "gt",
923
+ ">=": "gte",
924
+ "<": "lt",
925
+ "<=": "lte"
926
+ };
927
+ const mapped = map[op.sourceString];
928
+ if (!mapped)
929
+ throw new Error(`Unsupported compare op: ${op.sourceString}`);
930
+ return { type: "binary", op: mapped, left: left.toIR(), right: right.toIR() };
931
+ },
932
+ AddExpr_add(left, _op, right) {
933
+ return { type: "binary", op: "add", left: left.toIR(), right: right.toIR() };
934
+ },
935
+ AddExpr_sub(left, _op, right) {
936
+ return { type: "binary", op: "sub", left: left.toIR(), right: right.toIR() };
937
+ },
938
+ MulExpr_mul(left, _op, right) {
939
+ return { type: "binary", op: "mul", left: left.toIR(), right: right.toIR() };
940
+ },
941
+ MulExpr_div(left, _op, right) {
942
+ return { type: "binary", op: "div", left: left.toIR(), right: right.toIR() };
943
+ },
944
+ MulExpr_mod(left, _op, right) {
945
+ return { type: "binary", op: "mod", left: left.toIR(), right: right.toIR() };
946
+ },
947
+ UnaryExpr_neg(_op, value) {
948
+ const lowered = value.toIR();
949
+ if (lowered.type === "number") {
950
+ const raw = lowered.raw.startsWith("-") ? lowered.raw.slice(1) : `-${lowered.raw}`;
951
+ return { type: "number", raw, value: -lowered.value };
952
+ }
953
+ return { type: "unary", op: "neg", value: lowered };
954
+ },
955
+ UnaryExpr_not(_op, value) {
956
+ return { type: "unary", op: "not", value: value.toIR() };
957
+ },
958
+ UnaryExpr_logicalNot(_not, value) {
959
+ return { type: "unary", op: "logicalNot", value: value.toIR() };
960
+ },
961
+ UnaryExpr_delete(_del, place) {
962
+ return { type: "unary", op: "delete", value: place.toIR() };
963
+ },
964
+ PostfixExpr_chain(base, tails) {
965
+ return buildPostfix(base.toIR(), normalizePostfixSteps(tails.toIR()));
966
+ },
967
+ Place(base, tails) {
968
+ return buildPostfix(base.toIR(), normalizePostfixSteps(tails.toIR()));
969
+ },
970
+ PlaceTail_navStatic(_dot, key) {
971
+ return { kind: "navStatic", key: key.sourceString };
972
+ },
973
+ PlaceTail_navDynamic(_dotOpen, key, _close) {
974
+ return { kind: "navDynamic", key: key.toIR() };
975
+ },
976
+ PostfixTail_navStatic(_dot, key) {
977
+ return { kind: "navStatic", key: key.sourceString };
978
+ },
979
+ PostfixTail_navDynamic(_dotOpen, key, _close) {
980
+ return { kind: "navDynamic", key: key.toIR() };
981
+ },
982
+ PostfixTail_callEmpty(_open, _close) {
983
+ return { kind: "call", args: [] };
984
+ },
985
+ PostfixTail_call(_open, args, _close) {
986
+ return { kind: "call", args: normalizeList(args.toIR()) };
987
+ },
988
+ ConditionalExpr(head, condition, _do, thenBlock, elseBranch, _end) {
989
+ const nextElse = elseBranch.children[0];
990
+ return {
991
+ type: "conditional",
992
+ head: head.toIR(),
993
+ condition: condition.toIR(),
994
+ thenBlock: thenBlock.toIR(),
995
+ elseBranch: nextElse ? nextElse.toIR() : undefined
996
+ };
997
+ },
998
+ ConditionalHead(_kw) {
999
+ return this.sourceString;
1000
+ },
1001
+ ConditionalElse_elseChain(_else, head, condition, _do, thenBlock, elseBranch) {
1002
+ const nextElse = elseBranch.children[0];
1003
+ return {
1004
+ type: "elseChain",
1005
+ head: head.toIR(),
1006
+ condition: condition.toIR(),
1007
+ thenBlock: thenBlock.toIR(),
1008
+ elseBranch: nextElse ? nextElse.toIR() : undefined
1009
+ };
1010
+ },
1011
+ ConditionalElse_else(_else, block) {
1012
+ return { type: "else", block: block.toIR() };
1013
+ },
1014
+ WhileExpr(_while, condition, _do, block, _end) {
1015
+ return {
1016
+ type: "while",
1017
+ condition: condition.toIR(),
1018
+ body: block.toIR()
1019
+ };
1020
+ },
1021
+ ForExpr(_for, binding, _do, block, _end) {
1022
+ return {
1023
+ type: "for",
1024
+ binding: binding.toIR(),
1025
+ body: block.toIR()
1026
+ };
1027
+ },
1028
+ Array_empty(_open, _close) {
1029
+ return { type: "array", items: [] };
1030
+ },
1031
+ Array_forComprehension(_open, body, _for, binding, _close) {
1032
+ return {
1033
+ type: "arrayComprehension",
1034
+ binding: binding.toIR(),
1035
+ body: body.toIR()
1036
+ };
1037
+ },
1038
+ Array_whileComprehension(_open, body, _while, condition, _close) {
1039
+ return {
1040
+ type: "whileArrayComprehension",
1041
+ condition: condition.toIR(),
1042
+ body: body.toIR()
1043
+ };
1044
+ },
1045
+ Array_inComprehension(_open, body, _in, source, _close) {
1046
+ return {
1047
+ type: "arrayComprehension",
1048
+ binding: { type: "binding:bareIn", source: source.toIR() },
1049
+ body: body.toIR()
1050
+ };
1051
+ },
1052
+ Array_ofComprehension(_open, body, _of, source, _close) {
1053
+ return {
1054
+ type: "arrayComprehension",
1055
+ binding: { type: "binding:bareOf", source: source.toIR() },
1056
+ body: body.toIR()
1057
+ };
1058
+ },
1059
+ Array_values(_open, items, _close) {
1060
+ return { type: "array", items: normalizeList(items.toIR()) };
1061
+ },
1062
+ Object_empty(_open, _close) {
1063
+ return { type: "object", entries: [] };
1064
+ },
1065
+ Object_forComprehension(_open, key, _colon, value, _for, binding, _close) {
1066
+ return {
1067
+ type: "objectComprehension",
1068
+ binding: binding.toIR(),
1069
+ key: key.toIR(),
1070
+ value: value.toIR()
1071
+ };
1072
+ },
1073
+ Object_whileComprehension(_open, key, _colon, value, _while, condition, _close) {
1074
+ return {
1075
+ type: "whileObjectComprehension",
1076
+ condition: condition.toIR(),
1077
+ key: key.toIR(),
1078
+ value: value.toIR()
1079
+ };
1080
+ },
1081
+ Object_inComprehension(_open, key, _colon, value, _in, source, _close) {
1082
+ return {
1083
+ type: "objectComprehension",
1084
+ binding: { type: "binding:bareIn", source: source.toIR() },
1085
+ key: key.toIR(),
1086
+ value: value.toIR()
1087
+ };
1088
+ },
1089
+ Object_ofComprehension(_open, key, _colon, value, _of, source, _close) {
1090
+ return {
1091
+ type: "objectComprehension",
1092
+ binding: { type: "binding:bareOf", source: source.toIR() },
1093
+ key: key.toIR(),
1094
+ value: value.toIR()
1095
+ };
1096
+ },
1097
+ Object_pairs(_open, pairs, _close) {
1098
+ return {
1099
+ type: "object",
1100
+ entries: normalizeList(pairs.toIR())
1101
+ };
1102
+ },
1103
+ IterBinding_keyValueIn(key, _comma, value, _in, source) {
1104
+ return {
1105
+ type: "binding:keyValueIn",
1106
+ key: key.sourceString,
1107
+ value: value.sourceString,
1108
+ source: source.toIR()
1109
+ };
1110
+ },
1111
+ IterBinding_valueIn(value, _in, source) {
1112
+ return {
1113
+ type: "binding:valueIn",
1114
+ value: value.sourceString,
1115
+ source: source.toIR()
1116
+ };
1117
+ },
1118
+ IterBinding_keyOf(key, _of, source) {
1119
+ return {
1120
+ type: "binding:keyOf",
1121
+ key: key.sourceString,
1122
+ source: source.toIR()
1123
+ };
1124
+ },
1125
+ IterBinding_bareIn(_in, source) {
1126
+ return {
1127
+ type: "binding:bareIn",
1128
+ source: source.toIR()
1129
+ };
1130
+ },
1131
+ IterBinding_bareOf(_of, source) {
1132
+ return {
1133
+ type: "binding:bareOf",
1134
+ source: source.toIR()
1135
+ };
1136
+ },
1137
+ IterBindingComprehension_keyValueIn(key, _comma, value, _in, source) {
1138
+ return {
1139
+ type: "binding:keyValueIn",
1140
+ key: key.sourceString,
1141
+ value: value.sourceString,
1142
+ source: source.toIR()
1143
+ };
1144
+ },
1145
+ IterBindingComprehension_valueIn(value, _in, source) {
1146
+ return {
1147
+ type: "binding:valueIn",
1148
+ value: value.sourceString,
1149
+ source: source.toIR()
1150
+ };
1151
+ },
1152
+ IterBindingComprehension_keyOf(key, _of, source) {
1153
+ return {
1154
+ type: "binding:keyOf",
1155
+ key: key.sourceString,
1156
+ source: source.toIR()
1157
+ };
1158
+ },
1159
+ Pair(key, _colon, value) {
1160
+ return { key: key.toIR(), value: value.toIR() };
1161
+ },
1162
+ ObjKey_bare(key) {
1163
+ return { type: "key", name: key.sourceString };
1164
+ },
1165
+ ObjKey_number(num) {
1166
+ return num.toIR();
1167
+ },
1168
+ ObjKey_string(str) {
1169
+ return str.toIR();
1170
+ },
1171
+ ObjKey_computed(_open, expr, _close) {
1172
+ return expr.toIR();
1173
+ },
1174
+ BreakKw(_kw) {
1175
+ return { type: "break" };
1176
+ },
1177
+ ContinueKw(_kw) {
1178
+ return { type: "continue" };
1179
+ },
1180
+ SelfExpr_depth(_self, _at, depth) {
1181
+ const value = depth.toIR();
1182
+ if (value.type !== "number" || !Number.isInteger(value.value) || value.value < 1) {
1183
+ throw new Error("self depth must be a positive integer literal");
1184
+ }
1185
+ if (value.value === 1)
1186
+ return { type: "self" };
1187
+ return { type: "selfDepth", depth: value.value };
1188
+ },
1189
+ SelfExpr_plain(selfKw) {
1190
+ return selfKw.toIR();
1191
+ },
1192
+ SelfKw(_kw) {
1193
+ return { type: "self" };
1194
+ },
1195
+ TrueKw(_kw) {
1196
+ return { type: "boolean", value: true };
1197
+ },
1198
+ FalseKw(_kw) {
1199
+ return { type: "boolean", value: false };
1200
+ },
1201
+ NullKw(_kw) {
1202
+ return { type: "null" };
1203
+ },
1204
+ UndefinedKw(_kw) {
1205
+ return { type: "undefined" };
1206
+ },
1207
+ StringKw(_kw) {
1208
+ return { type: "identifier", name: "string" };
1209
+ },
1210
+ NumberKw(_kw) {
1211
+ return { type: "identifier", name: "number" };
1212
+ },
1213
+ ObjectKw(_kw) {
1214
+ return { type: "identifier", name: "object" };
1215
+ },
1216
+ ArrayKw(_kw) {
1217
+ return { type: "identifier", name: "array" };
1218
+ },
1219
+ BooleanKw(_kw) {
1220
+ return { type: "identifier", name: "boolean" };
1221
+ },
1222
+ identifier(_a, _b) {
1223
+ return { type: "identifier", name: this.sourceString };
1224
+ },
1225
+ String(_value) {
1226
+ return { type: "string", raw: this.sourceString };
1227
+ },
1228
+ Number(_value) {
1229
+ return { type: "number", raw: this.sourceString, value: parseNumber(this.sourceString) };
1230
+ },
1231
+ PrimaryExpr_group(_open, expr, _close) {
1232
+ return { type: "group", expression: expr.toIR() };
1233
+ }
1234
+ });
1235
+
1236
+ // rex-repl.ts
1237
+ import { createRequire as createRequire2 } from "node:module";
1238
+ import { resolve as resolve2, dirname, basename } from "node:path";
1239
+ import { homedir } from "node:os";
1240
+
1241
+ // rexc-interpreter.ts
1242
+ var DIGITS2 = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_";
1243
+ var digitMap = new Map(Array.from(DIGITS2).map((char, index) => [char, index]));
1244
+ var OPCODES = {
1245
+ do: "",
1246
+ add: "ad",
1247
+ sub: "sb",
1248
+ mul: "ml",
1249
+ div: "dv",
1250
+ eq: "eq",
1251
+ neq: "nq",
1252
+ lt: "lt",
1253
+ lte: "le",
1254
+ gt: "gt",
1255
+ gte: "ge",
1256
+ and: "an",
1257
+ or: "or",
1258
+ xor: "xr",
1259
+ not: "nt",
1260
+ boolean: "bt",
1261
+ number: "nm",
1262
+ string: "st",
1263
+ array: "ar",
1264
+ object: "ob",
1265
+ mod: "md",
1266
+ neg: "ng",
1267
+ range: "rn"
1268
+ };
1269
+ function decodePrefix(text, start, end) {
1270
+ let value = 0;
1271
+ for (let index = start;index < end; index += 1) {
1272
+ const digit = digitMap.get(text[index] ?? "") ?? -1;
1273
+ if (digit < 0)
1274
+ throw new Error(`Invalid digit '${text[index]}'`);
1275
+ value = value * 64 + digit;
1276
+ }
1277
+ return value;
1278
+ }
1279
+ function decodeZigzag(value) {
1280
+ return value % 2 === 0 ? value / 2 : -(value + 1) / 2;
1281
+ }
1282
+ function isDefined(value) {
1283
+ return value !== undefined;
1284
+ }
1285
+
1286
+ class CursorInterpreter {
1287
+ text;
1288
+ pos = 0;
1289
+ state;
1290
+ selfStack;
1291
+ pointerCache = new Map;
1292
+ gasLimit;
1293
+ gas = 0;
1294
+ tick() {
1295
+ if (this.gasLimit && ++this.gas > this.gasLimit) {
1296
+ throw new Error("Gas limit exceeded (too many loop iterations)");
1297
+ }
1298
+ }
1299
+ constructor(text, ctx = {}) {
1300
+ const initialSelf = ctx.selfStack && ctx.selfStack.length > 0 ? ctx.selfStack[ctx.selfStack.length - 1] : ctx.self;
1301
+ this.text = text;
1302
+ this.state = {
1303
+ vars: ctx.vars ?? {},
1304
+ refs: {
1305
+ tr: true,
1306
+ fl: false,
1307
+ nl: null,
1308
+ un: undefined,
1309
+ nan: NaN,
1310
+ inf: Infinity,
1311
+ nif: -Infinity,
1312
+ ...ctx.refs
1313
+ }
1314
+ };
1315
+ this.selfStack = ctx.selfStack && ctx.selfStack.length > 0 ? [...ctx.selfStack] : [initialSelf];
1316
+ this.gasLimit = ctx.gasLimit ?? 0;
1317
+ if (ctx.opcodes) {
1318
+ for (const [key, op] of Object.entries(ctx.opcodes)) {
1319
+ if (op)
1320
+ this.customOpcodes.set(key, op);
1321
+ }
1322
+ }
1323
+ }
1324
+ customOpcodes = new Map;
1325
+ readSelf(depthPrefix) {
1326
+ const depth = depthPrefix + 1;
1327
+ const index = this.selfStack.length - depth;
1328
+ if (index < 0)
1329
+ return;
1330
+ return this.selfStack[index];
1331
+ }
1332
+ get runtimeState() {
1333
+ return this.state;
1334
+ }
1335
+ evaluateTopLevel() {
1336
+ this.skipNonCode();
1337
+ if (this.pos >= this.text.length)
1338
+ return;
1339
+ const value = this.evalValue();
1340
+ this.skipNonCode();
1341
+ if (this.pos < this.text.length)
1342
+ throw new Error(`Unexpected trailing input at ${this.pos}`);
1343
+ return value;
1344
+ }
1345
+ skipNonCode() {
1346
+ while (this.pos < this.text.length) {
1347
+ const ch = this.text[this.pos];
1348
+ if (ch === " " || ch === "\t" || ch === `
1349
+ ` || ch === "\r") {
1350
+ this.pos += 1;
1351
+ continue;
1352
+ }
1353
+ if (ch === "/" && this.text[this.pos + 1] === "/") {
1354
+ this.pos += 2;
1355
+ while (this.pos < this.text.length && this.text[this.pos] !== `
1356
+ `)
1357
+ this.pos += 1;
1358
+ continue;
1359
+ }
1360
+ if (ch === "/" && this.text[this.pos + 1] === "*") {
1361
+ this.pos += 2;
1362
+ while (this.pos < this.text.length) {
1363
+ if (this.text[this.pos] === "*" && this.text[this.pos + 1] === "/") {
1364
+ this.pos += 2;
1365
+ break;
1366
+ }
1367
+ this.pos += 1;
1368
+ }
1369
+ continue;
1370
+ }
1371
+ break;
1372
+ }
1373
+ }
1374
+ readPrefix() {
1375
+ const start = this.pos;
1376
+ while (this.pos < this.text.length && digitMap.has(this.text[this.pos] ?? ""))
1377
+ this.pos += 1;
1378
+ const end = this.pos;
1379
+ return { start, end, value: decodePrefix(this.text, start, end), raw: this.text.slice(start, end) };
1380
+ }
1381
+ advanceByBytes(start, byteCount) {
1382
+ if (byteCount <= 0)
1383
+ return start;
1384
+ let bytes = 0;
1385
+ let index = start;
1386
+ for (const char of this.text.slice(start)) {
1387
+ const charBytes = Buffer.byteLength(char);
1388
+ if (bytes + charBytes > byteCount)
1389
+ break;
1390
+ bytes += charBytes;
1391
+ index += char.length;
1392
+ if (bytes === byteCount)
1393
+ return index;
1394
+ }
1395
+ throw new Error("String container overflows input");
1396
+ }
1397
+ ensure(char) {
1398
+ if (this.text[this.pos] !== char)
1399
+ throw new Error(`Expected '${char}' at ${this.pos}`);
1400
+ this.pos += 1;
1401
+ }
1402
+ hasMoreBefore(close) {
1403
+ const save = this.pos;
1404
+ this.skipNonCode();
1405
+ const more = this.pos < this.text.length && this.text[this.pos] !== close;
1406
+ this.pos = save;
1407
+ return more;
1408
+ }
1409
+ readBindingVarIfPresent() {
1410
+ const save = this.pos;
1411
+ this.skipNonCode();
1412
+ const prefix = this.readPrefix();
1413
+ const tag = this.text[this.pos];
1414
+ if (tag === "$" && prefix.raw.length > 0) {
1415
+ this.pos += 1;
1416
+ return prefix.raw;
1417
+ }
1418
+ this.pos = save;
1419
+ return;
1420
+ }
1421
+ evalValue() {
1422
+ this.skipNonCode();
1423
+ const prefix = this.readPrefix();
1424
+ const tag = this.text[this.pos];
1425
+ if (!tag)
1426
+ throw new Error("Unexpected end of input");
1427
+ switch (tag) {
1428
+ case "+":
1429
+ this.pos += 1;
1430
+ return decodeZigzag(prefix.value);
1431
+ case "*": {
1432
+ this.pos += 1;
1433
+ const power = decodeZigzag(prefix.value);
1434
+ const significand = this.evalValue();
1435
+ if (typeof significand !== "number")
1436
+ throw new Error("Decimal significand must be numeric");
1437
+ return parseFloat(`${significand}e${power}`);
1438
+ }
1439
+ case ":":
1440
+ this.pos += 1;
1441
+ return prefix.raw;
1442
+ case "%":
1443
+ this.pos += 1;
1444
+ return { __opcode: prefix.raw };
1445
+ case "@":
1446
+ this.pos += 1;
1447
+ return this.readSelf(prefix.value);
1448
+ case "'":
1449
+ this.pos += 1;
1450
+ return this.state.refs[prefix.raw];
1451
+ case "$":
1452
+ this.pos += 1;
1453
+ return this.state.vars[prefix.raw];
1454
+ case ",": {
1455
+ this.pos += 1;
1456
+ const start = this.pos;
1457
+ const end = this.advanceByBytes(start, prefix.value);
1458
+ const value = this.text.slice(start, end);
1459
+ this.pos = end;
1460
+ return value;
1461
+ }
1462
+ case "^": {
1463
+ this.pos += 1;
1464
+ const target = this.advanceByBytes(this.pos, prefix.value);
1465
+ if (this.pointerCache.has(target))
1466
+ return this.pointerCache.get(target);
1467
+ const save = this.pos;
1468
+ this.pos = target;
1469
+ const value = this.evalValue();
1470
+ this.pos = save;
1471
+ this.pointerCache.set(target, value);
1472
+ return value;
1473
+ }
1474
+ case "=": {
1475
+ this.pos += 1;
1476
+ const place = this.readPlace();
1477
+ const value = this.evalValue();
1478
+ this.writePlace(place, value);
1479
+ return value;
1480
+ }
1481
+ case "/": {
1482
+ this.pos += 1;
1483
+ const place = this.readPlace();
1484
+ const oldValue = this.readPlaceValue(place);
1485
+ const newValue = this.evalValue();
1486
+ this.writePlace(place, newValue);
1487
+ return oldValue;
1488
+ }
1489
+ case "~": {
1490
+ this.pos += 1;
1491
+ const place = this.readPlace();
1492
+ this.deletePlace(place);
1493
+ return;
1494
+ }
1495
+ case ";": {
1496
+ this.pos += 1;
1497
+ const kind = prefix.value % 2 === 0 ? "break" : "continue";
1498
+ const depth = Math.floor(prefix.value / 2) + 1;
1499
+ return { kind, depth };
1500
+ }
1501
+ case "(":
1502
+ return this.evalCall(prefix.value);
1503
+ case "[":
1504
+ return this.evalArray(prefix.value);
1505
+ case "{":
1506
+ return this.evalObject(prefix.value);
1507
+ case "?":
1508
+ case "!":
1509
+ case "|":
1510
+ case "&":
1511
+ return this.evalFlowParen(tag);
1512
+ case ">":
1513
+ case "<":
1514
+ return this.evalLoopLike(tag);
1515
+ case "#":
1516
+ return this.evalWhileLike();
1517
+ default:
1518
+ throw new Error(`Unexpected tag '${tag}' at ${this.pos}`);
1519
+ }
1520
+ }
1521
+ evalCall(_prefix) {
1522
+ this.ensure("(");
1523
+ this.skipNonCode();
1524
+ if (this.text[this.pos] === ")") {
1525
+ this.pos += 1;
1526
+ return;
1527
+ }
1528
+ const callee = this.evalValue();
1529
+ const args = [];
1530
+ while (true) {
1531
+ this.skipNonCode();
1532
+ if (this.text[this.pos] === ")")
1533
+ break;
1534
+ args.push(this.evalValue());
1535
+ }
1536
+ this.ensure(")");
1537
+ if (typeof callee === "object" && callee && "__opcode" in callee) {
1538
+ const marker = callee;
1539
+ const opArgs = marker.__receiver !== undefined ? [marker.__receiver, ...args] : args;
1540
+ return this.applyOpcode(marker.__opcode, opArgs);
1541
+ }
1542
+ return this.navigate(callee, args);
1543
+ }
1544
+ evalArray(_prefix) {
1545
+ this.ensure("[");
1546
+ this.skipNonCode();
1547
+ this.skipIndexHeaderIfPresent();
1548
+ const out = [];
1549
+ while (true) {
1550
+ this.skipNonCode();
1551
+ if (this.text[this.pos] === "]")
1552
+ break;
1553
+ out.push(this.evalValue());
1554
+ }
1555
+ this.ensure("]");
1556
+ return out;
1557
+ }
1558
+ evalObject(_prefix) {
1559
+ this.ensure("{");
1560
+ this.skipNonCode();
1561
+ this.skipIndexHeaderIfPresent();
1562
+ const out = {};
1563
+ while (true) {
1564
+ this.skipNonCode();
1565
+ if (this.text[this.pos] === "}")
1566
+ break;
1567
+ const key = this.evalValue();
1568
+ const value = this.evalValue();
1569
+ out[String(key)] = value;
1570
+ }
1571
+ this.ensure("}");
1572
+ return out;
1573
+ }
1574
+ skipIndexHeaderIfPresent() {
1575
+ const save = this.pos;
1576
+ const countPrefix = this.readPrefix();
1577
+ if (this.text[this.pos] !== "#") {
1578
+ this.pos = save;
1579
+ return;
1580
+ }
1581
+ this.pos += 1;
1582
+ const widthChar = this.text[this.pos];
1583
+ const width = widthChar ? digitMap.get(widthChar) ?? 0 : 0;
1584
+ if (widthChar)
1585
+ this.pos += 1;
1586
+ const skipLen = countPrefix.value * width;
1587
+ this.pos += skipLen;
1588
+ }
1589
+ evalFlowParen(tag) {
1590
+ this.pos += 1;
1591
+ this.ensure("(");
1592
+ if (tag === "?") {
1593
+ const cond = this.evalValue();
1594
+ if (isDefined(cond)) {
1595
+ this.selfStack.push(cond);
1596
+ const thenValue = this.evalValue();
1597
+ this.selfStack.pop();
1598
+ if (this.hasMoreBefore(")"))
1599
+ this.skipValue();
1600
+ this.ensure(")");
1601
+ return thenValue;
1602
+ }
1603
+ this.skipValue();
1604
+ let elseValue = undefined;
1605
+ if (this.hasMoreBefore(")"))
1606
+ elseValue = this.evalValue();
1607
+ this.ensure(")");
1608
+ return elseValue;
1609
+ }
1610
+ if (tag === "!") {
1611
+ const cond = this.evalValue();
1612
+ if (!isDefined(cond)) {
1613
+ const thenValue = this.evalValue();
1614
+ if (this.hasMoreBefore(")"))
1615
+ this.skipValue();
1616
+ this.ensure(")");
1617
+ return thenValue;
1618
+ }
1619
+ this.skipValue();
1620
+ let elseValue = undefined;
1621
+ if (this.hasMoreBefore(")")) {
1622
+ this.selfStack.push(cond);
1623
+ elseValue = this.evalValue();
1624
+ this.selfStack.pop();
1625
+ }
1626
+ this.ensure(")");
1627
+ return elseValue;
1628
+ }
1629
+ if (tag === "|") {
1630
+ let result2 = undefined;
1631
+ while (this.hasMoreBefore(")")) {
1632
+ if (isDefined(result2))
1633
+ this.skipValue();
1634
+ else
1635
+ result2 = this.evalValue();
1636
+ }
1637
+ this.ensure(")");
1638
+ return result2;
1639
+ }
1640
+ let result = undefined;
1641
+ while (this.hasMoreBefore(")")) {
1642
+ if (!isDefined(result) && result !== undefined) {
1643
+ this.skipValue();
1644
+ continue;
1645
+ }
1646
+ result = this.evalValue();
1647
+ if (!isDefined(result)) {
1648
+ while (this.hasMoreBefore(")"))
1649
+ this.skipValue();
1650
+ break;
1651
+ }
1652
+ }
1653
+ this.ensure(")");
1654
+ return result;
1655
+ }
1656
+ evalLoopLike(tag) {
1657
+ this.pos += 1;
1658
+ const open = this.text[this.pos];
1659
+ if (!open || !"([{".includes(open))
1660
+ throw new Error(`Expected loop opener after '${tag}'`);
1661
+ const close = open === "(" ? ")" : open === "[" ? "]" : "}";
1662
+ this.pos += 1;
1663
+ const iterable = this.evalValue();
1664
+ const afterIterable = this.pos;
1665
+ const bodyValueCount = open === "{" ? 2 : 1;
1666
+ let varA;
1667
+ let varB;
1668
+ let bodyStart = afterIterable;
1669
+ let bodyEnd = afterIterable;
1670
+ let matched = false;
1671
+ for (const bindingCount of [2, 1, 0]) {
1672
+ this.pos = afterIterable;
1673
+ const vars = [];
1674
+ let bindingsOk = true;
1675
+ for (let index = 0;index < bindingCount; index += 1) {
1676
+ const binding = this.readBindingVarIfPresent();
1677
+ if (!binding) {
1678
+ bindingsOk = false;
1679
+ break;
1680
+ }
1681
+ vars.push(binding);
1682
+ }
1683
+ if (!bindingsOk)
1684
+ continue;
1685
+ const candidateBodyStart = this.pos;
1686
+ let cursor = candidateBodyStart;
1687
+ let bodyOk = true;
1688
+ for (let index = 0;index < bodyValueCount; index += 1) {
1689
+ const next = this.skipValueFrom(cursor);
1690
+ if (next <= cursor) {
1691
+ bodyOk = false;
1692
+ break;
1693
+ }
1694
+ cursor = next;
1695
+ }
1696
+ if (!bodyOk)
1697
+ continue;
1698
+ this.pos = cursor;
1699
+ this.skipNonCode();
1700
+ if (this.text[this.pos] !== close)
1701
+ continue;
1702
+ varA = vars[0];
1703
+ varB = vars[1];
1704
+ bodyStart = candidateBodyStart;
1705
+ bodyEnd = cursor;
1706
+ matched = true;
1707
+ break;
1708
+ }
1709
+ if (!matched)
1710
+ throw new Error(`Invalid loop/comprehension body before '${close}' at ${this.pos}`);
1711
+ this.pos = bodyEnd;
1712
+ this.ensure(close);
1713
+ if (open === "[")
1714
+ return this.evalArrayComprehension(iterable, varA, varB, bodyStart, bodyEnd, tag === "<");
1715
+ if (open === "{")
1716
+ return this.evalObjectComprehension(iterable, varA, varB, bodyStart, bodyEnd, tag === "<");
1717
+ return this.evalForLoop(iterable, varA, varB, bodyStart, bodyEnd, tag === "<");
1718
+ }
1719
+ iterate(iterable, keysOnly) {
1720
+ if (Array.isArray(iterable)) {
1721
+ if (keysOnly)
1722
+ return iterable.map((_value, index) => ({ key: index, value: index }));
1723
+ return iterable.map((value, index) => ({ key: index, value }));
1724
+ }
1725
+ if (iterable && typeof iterable === "object") {
1726
+ const entries = Object.entries(iterable);
1727
+ if (keysOnly)
1728
+ return entries.map(([key]) => ({ key, value: key }));
1729
+ return entries.map(([key, value]) => ({ key, value }));
1730
+ }
1731
+ if (typeof iterable === "string") {
1732
+ const entries = Array.from(iterable);
1733
+ if (keysOnly)
1734
+ return entries.map((_value, index) => ({ key: index, value: index }));
1735
+ return entries.map((value, index) => ({ key: index, value }));
1736
+ }
1737
+ return [];
1738
+ }
1739
+ evalBodySlice(start, end) {
1740
+ const save = this.pos;
1741
+ this.pos = start;
1742
+ const value = this.evalValue();
1743
+ this.pos = end;
1744
+ this.pos = save;
1745
+ return value;
1746
+ }
1747
+ handleLoopControl(value) {
1748
+ if (value && typeof value === "object" && "kind" in value && "depth" in value) {
1749
+ return value;
1750
+ }
1751
+ return;
1752
+ }
1753
+ evalForLoop(iterable, varA, varB, bodyStart, bodyEnd, keysOnly) {
1754
+ const items = this.iterate(iterable, keysOnly);
1755
+ let last = undefined;
1756
+ for (const item of items) {
1757
+ this.tick();
1758
+ const currentSelf = keysOnly ? item.key : item.value;
1759
+ this.selfStack.push(currentSelf);
1760
+ if (varA && varB) {
1761
+ this.state.vars[varA] = item.key;
1762
+ this.state.vars[varB] = keysOnly ? item.key : item.value;
1763
+ } else if (varA) {
1764
+ this.state.vars[varA] = keysOnly ? item.key : item.value;
1765
+ }
1766
+ last = this.evalBodySlice(bodyStart, bodyEnd);
1767
+ this.selfStack.pop();
1768
+ const control = this.handleLoopControl(last);
1769
+ if (!control)
1770
+ continue;
1771
+ if (control.depth > 1)
1772
+ return { kind: control.kind, depth: control.depth - 1 };
1773
+ if (control.kind === "break")
1774
+ return;
1775
+ last = undefined;
1776
+ continue;
1777
+ }
1778
+ return last;
1779
+ }
1780
+ evalWhileLike() {
1781
+ this.pos += 1;
1782
+ const open = this.text[this.pos];
1783
+ if (!open || !"([{".includes(open))
1784
+ throw new Error(`Expected opener after '#' at ${this.pos}`);
1785
+ const close = open === "(" ? ")" : open === "[" ? "]" : "}";
1786
+ this.pos += 1;
1787
+ const condStart = this.pos;
1788
+ const condValue = this.evalValue();
1789
+ const bodyStart = this.pos;
1790
+ const bodyValueCount = open === "{" ? 2 : 1;
1791
+ let cursor = bodyStart;
1792
+ for (let index = 0;index < bodyValueCount; index += 1) {
1793
+ cursor = this.skipValueFrom(cursor);
1794
+ }
1795
+ const bodyEnd = cursor;
1796
+ this.pos = bodyEnd;
1797
+ this.ensure(close);
1798
+ const afterClose = this.pos;
1799
+ if (open === "[")
1800
+ return this.evalWhileArrayComprehension(condStart, bodyStart, bodyEnd, afterClose, condValue);
1801
+ if (open === "{")
1802
+ return this.evalWhileObjectComprehension(condStart, bodyStart, bodyEnd, afterClose, condValue);
1803
+ return this.evalWhileLoop(condStart, bodyStart, bodyEnd, afterClose, condValue);
1804
+ }
1805
+ evalWhileLoop(condStart, bodyStart, bodyEnd, afterClose, condValue) {
1806
+ let last = undefined;
1807
+ let currentCond = condValue;
1808
+ while (isDefined(currentCond)) {
1809
+ this.tick();
1810
+ this.selfStack.push(currentCond);
1811
+ last = this.evalBodySlice(bodyStart, bodyEnd);
1812
+ this.selfStack.pop();
1813
+ const control = this.handleLoopControl(last);
1814
+ if (control) {
1815
+ if (control.depth > 1)
1816
+ return { kind: control.kind, depth: control.depth - 1 };
1817
+ if (control.kind === "break")
1818
+ return;
1819
+ last = undefined;
1820
+ }
1821
+ currentCond = this.evalBodySlice(condStart, bodyStart);
1822
+ }
1823
+ this.pos = afterClose;
1824
+ return last;
1825
+ }
1826
+ evalWhileArrayComprehension(condStart, bodyStart, bodyEnd, afterClose, condValue) {
1827
+ const out = [];
1828
+ let currentCond = condValue;
1829
+ while (isDefined(currentCond)) {
1830
+ this.tick();
1831
+ this.selfStack.push(currentCond);
1832
+ const value = this.evalBodySlice(bodyStart, bodyEnd);
1833
+ this.selfStack.pop();
1834
+ const control = this.handleLoopControl(value);
1835
+ if (control) {
1836
+ if (control.depth > 1)
1837
+ return { kind: control.kind, depth: control.depth - 1 };
1838
+ if (control.kind === "break")
1839
+ break;
1840
+ currentCond = this.evalBodySlice(condStart, bodyStart);
1841
+ continue;
1842
+ }
1843
+ if (isDefined(value))
1844
+ out.push(value);
1845
+ currentCond = this.evalBodySlice(condStart, bodyStart);
1846
+ }
1847
+ this.pos = afterClose;
1848
+ return out;
1849
+ }
1850
+ evalWhileObjectComprehension(condStart, bodyStart, bodyEnd, afterClose, condValue) {
1851
+ const result = {};
1852
+ let currentCond = condValue;
1853
+ while (isDefined(currentCond)) {
1854
+ this.tick();
1855
+ this.selfStack.push(currentCond);
1856
+ const save = this.pos;
1857
+ this.pos = bodyStart;
1858
+ const key = this.evalValue();
1859
+ const value = this.evalValue();
1860
+ this.pos = save;
1861
+ this.selfStack.pop();
1862
+ const control = this.handleLoopControl(value);
1863
+ if (control) {
1864
+ if (control.depth > 1)
1865
+ return { kind: control.kind, depth: control.depth - 1 };
1866
+ if (control.kind === "break")
1867
+ break;
1868
+ currentCond = this.evalBodySlice(condStart, bodyStart);
1869
+ continue;
1870
+ }
1871
+ if (isDefined(value))
1872
+ result[String(key)] = value;
1873
+ currentCond = this.evalBodySlice(condStart, bodyStart);
1874
+ }
1875
+ this.pos = afterClose;
1876
+ return result;
1877
+ }
1878
+ evalArrayComprehension(iterable, varA, varB, bodyStart, bodyEnd, keysOnly) {
1879
+ const items = this.iterate(iterable, keysOnly);
1880
+ const out = [];
1881
+ for (const item of items) {
1882
+ this.tick();
1883
+ const currentSelf = keysOnly ? item.key : item.value;
1884
+ this.selfStack.push(currentSelf);
1885
+ if (varA && varB) {
1886
+ this.state.vars[varA] = item.key;
1887
+ this.state.vars[varB] = keysOnly ? item.key : item.value;
1888
+ } else if (varA) {
1889
+ this.state.vars[varA] = keysOnly ? item.key : item.value;
1890
+ }
1891
+ const value = this.evalBodySlice(bodyStart, bodyEnd);
1892
+ this.selfStack.pop();
1893
+ const control = this.handleLoopControl(value);
1894
+ if (control) {
1895
+ if (control.depth > 1)
1896
+ return { kind: control.kind, depth: control.depth - 1 };
1897
+ if (control.kind === "break")
1898
+ break;
1899
+ continue;
1900
+ }
1901
+ if (isDefined(value))
1902
+ out.push(value);
1903
+ }
1904
+ return out;
1905
+ }
1906
+ evalObjectComprehension(iterable, varA, varB, bodyStart, bodyEnd, keysOnly) {
1907
+ const items = this.iterate(iterable, keysOnly);
1908
+ const out = {};
1909
+ for (const item of items) {
1910
+ this.tick();
1911
+ const currentSelf = keysOnly ? item.key : item.value;
1912
+ this.selfStack.push(currentSelf);
1913
+ if (varA && varB) {
1914
+ this.state.vars[varA] = item.key;
1915
+ this.state.vars[varB] = keysOnly ? item.key : item.value;
1916
+ } else if (varA) {
1917
+ this.state.vars[varA] = keysOnly ? item.key : item.value;
1918
+ }
1919
+ const save = this.pos;
1920
+ this.pos = bodyStart;
1921
+ const key = this.evalValue();
1922
+ const value = this.evalValue();
1923
+ this.pos = save;
1924
+ this.selfStack.pop();
1925
+ const control = this.handleLoopControl(value);
1926
+ if (control) {
1927
+ if (control.depth > 1)
1928
+ return { kind: control.kind, depth: control.depth - 1 };
1929
+ if (control.kind === "break")
1930
+ break;
1931
+ continue;
1932
+ }
1933
+ if (isDefined(value))
1934
+ out[String(key)] = value;
1935
+ }
1936
+ return out;
1937
+ }
1938
+ applyOpcode(id, args) {
1939
+ const custom = this.customOpcodes.get(id);
1940
+ if (custom)
1941
+ return custom(args, this.state);
1942
+ switch (id) {
1943
+ case OPCODES.do:
1944
+ return args.length ? args[args.length - 1] : undefined;
1945
+ case OPCODES.add:
1946
+ if (args[0] === undefined || args[1] === undefined)
1947
+ return;
1948
+ if (Array.isArray(args[0]) && Array.isArray(args[1])) {
1949
+ return [...args[0], ...args[1]];
1950
+ }
1951
+ if (args[0] && args[1] && typeof args[0] === "object" && typeof args[1] === "object" && !Array.isArray(args[0]) && !Array.isArray(args[1])) {
1952
+ return { ...args[0], ...args[1] };
1953
+ }
1954
+ if (typeof args[0] === "string" && typeof args[1] === "string") {
1955
+ return args[0] + args[1];
1956
+ }
1957
+ if (typeof args[0] === "number" && typeof args[1] === "number") {
1958
+ return args[0] + args[1];
1959
+ }
1960
+ return;
1961
+ case OPCODES.sub:
1962
+ if (args[0] === undefined || args[1] === undefined)
1963
+ return;
1964
+ return Number(args[0]) - Number(args[1]);
1965
+ case OPCODES.mul:
1966
+ if (args[0] === undefined || args[1] === undefined)
1967
+ return;
1968
+ return Number(args[0]) * Number(args[1]);
1969
+ case OPCODES.div:
1970
+ if (args[0] === undefined || args[1] === undefined)
1971
+ return;
1972
+ return Number(args[0]) / Number(args[1]);
1973
+ case OPCODES.mod:
1974
+ if (args[0] === undefined || args[1] === undefined)
1975
+ return;
1976
+ return Number(args[0]) % Number(args[1]);
1977
+ case OPCODES.neg:
1978
+ if (args[0] === undefined)
1979
+ return;
1980
+ return -Number(args[0]);
1981
+ case OPCODES.not: {
1982
+ const value = args[0];
1983
+ if (value === undefined)
1984
+ return;
1985
+ if (typeof value === "boolean")
1986
+ return !value;
1987
+ return ~Number(value);
1988
+ }
1989
+ case OPCODES.and: {
1990
+ const [a, b] = args;
1991
+ if (typeof a === "boolean" || typeof b === "boolean")
1992
+ return Boolean(a) && Boolean(b);
1993
+ return Number(a ?? 0) & Number(b ?? 0);
1994
+ }
1995
+ case OPCODES.or: {
1996
+ const [a, b] = args;
1997
+ if (typeof a === "boolean" || typeof b === "boolean")
1998
+ return Boolean(a) || Boolean(b);
1999
+ return Number(a ?? 0) | Number(b ?? 0);
2000
+ }
2001
+ case OPCODES.xor: {
2002
+ const [a, b] = args;
2003
+ if (typeof a === "boolean" || typeof b === "boolean")
2004
+ return Boolean(a) !== Boolean(b);
2005
+ return Number(a ?? 0) ^ Number(b ?? 0);
2006
+ }
2007
+ case OPCODES.eq:
2008
+ return args[0] === args[1] ? args[0] : undefined;
2009
+ case OPCODES.neq:
2010
+ return args[0] !== args[1] ? args[0] : undefined;
2011
+ case OPCODES.gt:
2012
+ return Number(args[0]) > Number(args[1]) ? args[0] : undefined;
2013
+ case OPCODES.gte:
2014
+ return Number(args[0]) >= Number(args[1]) ? args[0] : undefined;
2015
+ case OPCODES.lt:
2016
+ return Number(args[0]) < Number(args[1]) ? args[0] : undefined;
2017
+ case OPCODES.lte:
2018
+ return Number(args[0]) <= Number(args[1]) ? args[0] : undefined;
2019
+ case OPCODES.boolean:
2020
+ return typeof args[0] === "boolean" ? args[0] : undefined;
2021
+ case OPCODES.number:
2022
+ return typeof args[0] === "number" ? args[0] : undefined;
2023
+ case OPCODES.string:
2024
+ return typeof args[0] === "string" ? args[0] : undefined;
2025
+ case OPCODES.array:
2026
+ return Array.isArray(args[0]) ? args[0] : undefined;
2027
+ case OPCODES.object:
2028
+ return args[0] && typeof args[0] === "object" && !Array.isArray(args[0]) ? args[0] : undefined;
2029
+ case OPCODES.range: {
2030
+ const from = Number(args[0]);
2031
+ const to = Number(args[1]);
2032
+ const step = to >= from ? 1 : -1;
2033
+ const out = [];
2034
+ for (let v = from;step > 0 ? v <= to : v >= to; v += step)
2035
+ out.push(v);
2036
+ return out;
2037
+ }
2038
+ case "array:push": {
2039
+ const target = args[0];
2040
+ if (!Array.isArray(target))
2041
+ return;
2042
+ const next = target.slice();
2043
+ for (let i = 1;i < args.length; i += 1)
2044
+ next.push(args[i]);
2045
+ return next;
2046
+ }
2047
+ case "array:pop": {
2048
+ const target = args[0];
2049
+ if (!Array.isArray(target) || target.length === 0)
2050
+ return;
2051
+ return target[target.length - 1];
2052
+ }
2053
+ case "array:unshift": {
2054
+ const target = args[0];
2055
+ if (!Array.isArray(target))
2056
+ return;
2057
+ const next = target.slice();
2058
+ for (let i = args.length - 1;i >= 1; i -= 1)
2059
+ next.unshift(args[i]);
2060
+ return next;
2061
+ }
2062
+ case "array:shift": {
2063
+ const target = args[0];
2064
+ if (!Array.isArray(target) || target.length === 0)
2065
+ return;
2066
+ return target[0];
2067
+ }
2068
+ case "array:slice": {
2069
+ const target = args[0];
2070
+ if (!Array.isArray(target))
2071
+ return;
2072
+ const start = args.length > 1 && args[1] !== undefined ? Number(args[1]) : undefined;
2073
+ const end = args.length > 2 && args[2] !== undefined ? Number(args[2]) : undefined;
2074
+ return target.slice(start, end);
2075
+ }
2076
+ case "array:join": {
2077
+ const target = args[0];
2078
+ if (!Array.isArray(target))
2079
+ return;
2080
+ const sep = args.length > 1 && args[1] !== undefined ? String(args[1]) : ",";
2081
+ return target.map((item) => String(item)).join(sep);
2082
+ }
2083
+ case "string:split": {
2084
+ const target = args[0];
2085
+ if (typeof target !== "string")
2086
+ return;
2087
+ if (args.length < 2 || args[1] === undefined)
2088
+ return [target];
2089
+ return target.split(String(args[1]));
2090
+ }
2091
+ case "string:join": {
2092
+ const target = args[0];
2093
+ if (typeof target !== "string")
2094
+ return;
2095
+ const parts = Array.from(target);
2096
+ const sep = args.length > 1 && args[1] !== undefined ? String(args[1]) : "";
2097
+ return parts.join(sep);
2098
+ }
2099
+ case "string:slice": {
2100
+ const target = args[0];
2101
+ if (typeof target !== "string")
2102
+ return;
2103
+ const start = args.length > 1 && args[1] !== undefined ? Number(args[1]) : undefined;
2104
+ const end = args.length > 2 && args[2] !== undefined ? Number(args[2]) : undefined;
2105
+ return Array.from(target).slice(start, end).join("");
2106
+ }
2107
+ case "string:starts-with": {
2108
+ const target = args[0];
2109
+ if (typeof target !== "string")
2110
+ return;
2111
+ const prefix = args.length > 1 && args[1] !== undefined ? String(args[1]) : "";
2112
+ return target.startsWith(prefix);
2113
+ }
2114
+ case "string:ends-with": {
2115
+ const target = args[0];
2116
+ if (typeof target !== "string")
2117
+ return;
2118
+ const suffix = args.length > 1 && args[1] !== undefined ? String(args[1]) : "";
2119
+ return target.endsWith(suffix);
2120
+ }
2121
+ default:
2122
+ throw new Error(`Unknown opcode ${id}`);
2123
+ }
2124
+ }
2125
+ navigate(base, keys) {
2126
+ let current = base;
2127
+ for (const key of keys) {
2128
+ if (current === undefined || current === null)
2129
+ return;
2130
+ current = this.readProperty(current, key);
2131
+ if (current === undefined)
2132
+ return;
2133
+ }
2134
+ return current;
2135
+ }
2136
+ readProperty(target, key) {
2137
+ if (typeof key === "string" && key === "size") {
2138
+ if (Array.isArray(target))
2139
+ return target.length;
2140
+ if (typeof target === "string")
2141
+ return Array.from(target).length;
2142
+ }
2143
+ const index = this.parseIndexKey(key);
2144
+ if (Array.isArray(target)) {
2145
+ if (index !== undefined)
2146
+ return target[index];
2147
+ if (typeof key === "string")
2148
+ return this.resolveArrayMethod(target, key);
2149
+ return;
2150
+ }
2151
+ if (typeof target === "string") {
2152
+ if (index !== undefined)
2153
+ return Array.from(target)[index];
2154
+ if (typeof key === "string")
2155
+ return this.resolveStringMethod(target, key);
2156
+ return;
2157
+ }
2158
+ if (this.isPlainObject(target)) {
2159
+ const prop = String(key);
2160
+ if (!Object.prototype.hasOwnProperty.call(target, prop))
2161
+ return;
2162
+ return target[prop];
2163
+ }
2164
+ return;
2165
+ }
2166
+ resolveArrayMethod(target, key) {
2167
+ switch (key) {
2168
+ case "push":
2169
+ return { __opcode: "array:push", __receiver: target };
2170
+ case "pop":
2171
+ return { __opcode: "array:pop", __receiver: target };
2172
+ case "unshift":
2173
+ return { __opcode: "array:unshift", __receiver: target };
2174
+ case "shift":
2175
+ return { __opcode: "array:shift", __receiver: target };
2176
+ case "slice":
2177
+ return { __opcode: "array:slice", __receiver: target };
2178
+ case "join":
2179
+ return { __opcode: "array:join", __receiver: target };
2180
+ default:
2181
+ return;
2182
+ }
2183
+ }
2184
+ resolveStringMethod(target, key) {
2185
+ switch (key) {
2186
+ case "split":
2187
+ return { __opcode: "string:split", __receiver: target };
2188
+ case "join":
2189
+ return { __opcode: "string:join", __receiver: target };
2190
+ case "slice":
2191
+ return { __opcode: "string:slice", __receiver: target };
2192
+ case "starts-with":
2193
+ return { __opcode: "string:starts-with", __receiver: target };
2194
+ case "ends-with":
2195
+ return { __opcode: "string:ends-with", __receiver: target };
2196
+ default:
2197
+ return;
2198
+ }
2199
+ }
2200
+ canWriteProperty(target, key) {
2201
+ const index = this.parseIndexKey(key);
2202
+ if (Array.isArray(target)) {
2203
+ if (index === undefined)
2204
+ return;
2205
+ return { kind: "array", index };
2206
+ }
2207
+ if (this.isPlainObject(target))
2208
+ return { kind: "object" };
2209
+ return;
2210
+ }
2211
+ parseIndexKey(key) {
2212
+ if (typeof key === "number" && Number.isInteger(key) && key >= 0)
2213
+ return key;
2214
+ if (typeof key !== "string" || key.length === 0)
2215
+ return;
2216
+ if (!/^(0|[1-9]\d*)$/.test(key))
2217
+ return;
2218
+ const index = Number(key);
2219
+ return Number.isSafeInteger(index) ? index : undefined;
2220
+ }
2221
+ isPlainObject(value) {
2222
+ if (!value || typeof value !== "object")
2223
+ return false;
2224
+ const proto = Object.getPrototypeOf(value);
2225
+ return proto === Object.prototype || proto === null;
2226
+ }
2227
+ readPlace() {
2228
+ this.skipNonCode();
2229
+ const direct = this.readRootVarOrRefIfPresent();
2230
+ if (direct) {
2231
+ const keys = [];
2232
+ this.skipNonCode();
2233
+ if (this.text[this.pos] === "(") {
2234
+ this.pos += 1;
2235
+ while (true) {
2236
+ this.skipNonCode();
2237
+ if (this.text[this.pos] === ")")
2238
+ break;
2239
+ keys.push(this.evalValue());
2240
+ }
2241
+ this.pos += 1;
2242
+ }
2243
+ return {
2244
+ root: direct.root,
2245
+ keys,
2246
+ isRef: direct.isRef
2247
+ };
2248
+ }
2249
+ if (this.text[this.pos] === "(") {
2250
+ this.pos += 1;
2251
+ this.skipNonCode();
2252
+ const rootFromNav = this.readRootVarOrRefIfPresent();
2253
+ if (!rootFromNav)
2254
+ throw new Error(`Invalid place root at ${this.pos}`);
2255
+ const keys = [];
2256
+ while (true) {
2257
+ this.skipNonCode();
2258
+ if (this.text[this.pos] === ")")
2259
+ break;
2260
+ keys.push(this.evalValue());
2261
+ }
2262
+ this.pos += 1;
2263
+ return {
2264
+ root: rootFromNav.root,
2265
+ keys,
2266
+ isRef: rootFromNav.isRef
2267
+ };
2268
+ }
2269
+ throw new Error(`Invalid place at ${this.pos}`);
2270
+ }
2271
+ readRootVarOrRefIfPresent() {
2272
+ const save = this.pos;
2273
+ const prefix = this.readPrefix();
2274
+ const tag = this.text[this.pos];
2275
+ if (tag !== "$" && tag !== "'") {
2276
+ this.pos = save;
2277
+ return;
2278
+ }
2279
+ this.pos += 1;
2280
+ return {
2281
+ root: prefix.raw,
2282
+ isRef: tag === "'"
2283
+ };
2284
+ }
2285
+ writePlace(place, value) {
2286
+ const rootTable = place.isRef ? this.state.refs : this.state.vars;
2287
+ const rootKey = place.root;
2288
+ if (place.keys.length === 0) {
2289
+ rootTable[rootKey] = value;
2290
+ return;
2291
+ }
2292
+ let target = rootTable[rootKey];
2293
+ if (!target || typeof target !== "object") {
2294
+ target = {};
2295
+ rootTable[rootKey] = target;
2296
+ }
2297
+ for (let index = 0;index < place.keys.length - 1; index += 1) {
2298
+ const key = place.keys[index];
2299
+ const access2 = this.canWriteProperty(target, key);
2300
+ if (!access2)
2301
+ return;
2302
+ if (access2.kind === "array") {
2303
+ const next2 = target[access2.index];
2304
+ if (!next2 || typeof next2 !== "object")
2305
+ target[access2.index] = {};
2306
+ target = target[access2.index];
2307
+ continue;
2308
+ }
2309
+ const prop = String(key);
2310
+ const next = target[prop];
2311
+ if (!next || typeof next !== "object")
2312
+ target[prop] = {};
2313
+ target = target[prop];
2314
+ }
2315
+ const lastKey = place.keys[place.keys.length - 1];
2316
+ const access = this.canWriteProperty(target, lastKey);
2317
+ if (!access)
2318
+ return;
2319
+ if (access.kind === "array") {
2320
+ target[access.index] = value;
2321
+ return;
2322
+ }
2323
+ target[String(lastKey)] = value;
2324
+ }
2325
+ readPlaceValue(place) {
2326
+ const rootTable = place.isRef ? this.state.refs : this.state.vars;
2327
+ let current = rootTable[place.root];
2328
+ for (const key of place.keys) {
2329
+ if (current === undefined || current === null)
2330
+ return;
2331
+ current = this.readProperty(current, key);
2332
+ if (current === undefined)
2333
+ return;
2334
+ }
2335
+ return current;
2336
+ }
2337
+ deletePlace(place) {
2338
+ const rootTable = place.isRef ? this.state.refs : this.state.vars;
2339
+ const rootKey = place.root;
2340
+ if (place.keys.length === 0) {
2341
+ delete rootTable[rootKey];
2342
+ return;
2343
+ }
2344
+ let target = rootTable[rootKey];
2345
+ if (!target || typeof target !== "object")
2346
+ return;
2347
+ for (let index = 0;index < place.keys.length - 1; index += 1) {
2348
+ const key = place.keys[index];
2349
+ const access2 = this.canWriteProperty(target, key);
2350
+ if (!access2)
2351
+ return;
2352
+ if (access2.kind === "array") {
2353
+ target = target[access2.index];
2354
+ if (!target || typeof target !== "object")
2355
+ return;
2356
+ continue;
2357
+ }
2358
+ target = target[String(key)];
2359
+ if (!target || typeof target !== "object")
2360
+ return;
2361
+ }
2362
+ const lastKey = place.keys[place.keys.length - 1];
2363
+ const access = this.canWriteProperty(target, lastKey);
2364
+ if (!access)
2365
+ return;
2366
+ if (access.kind === "array") {
2367
+ delete target[access.index];
2368
+ return;
2369
+ }
2370
+ delete target[String(lastKey)];
2371
+ }
2372
+ skipValue() {
2373
+ this.pos = this.skipValueFrom(this.pos);
2374
+ }
2375
+ skipValueFrom(startPos) {
2376
+ const save = this.pos;
2377
+ this.pos = startPos;
2378
+ this.skipNonCode();
2379
+ const prefix = this.readPrefix();
2380
+ const tag = this.text[this.pos];
2381
+ if (!tag) {
2382
+ this.pos = save;
2383
+ return startPos;
2384
+ }
2385
+ if (tag === ",") {
2386
+ this.pos = this.advanceByBytes(this.pos + 1, prefix.value);
2387
+ const end2 = this.pos;
2388
+ this.pos = save;
2389
+ return end2;
2390
+ }
2391
+ if (tag === "=" || tag === "/") {
2392
+ this.pos += 1;
2393
+ this.skipValue();
2394
+ this.skipValue();
2395
+ const end2 = this.pos;
2396
+ this.pos = save;
2397
+ return end2;
2398
+ }
2399
+ if (tag === "~") {
2400
+ this.pos += 1;
2401
+ this.skipValue();
2402
+ const end2 = this.pos;
2403
+ this.pos = save;
2404
+ return end2;
2405
+ }
2406
+ if (tag === "*") {
2407
+ this.pos += 1;
2408
+ this.skipValue();
2409
+ const end2 = this.pos;
2410
+ this.pos = save;
2411
+ return end2;
2412
+ }
2413
+ if ("+:%$@'^;".includes(tag)) {
2414
+ this.pos += 1;
2415
+ const end2 = this.pos;
2416
+ this.pos = save;
2417
+ return end2;
2418
+ }
2419
+ if (tag === "?" || tag === "!" || tag === "|" || tag === "&" || tag === ">" || tag === "<" || tag === "#") {
2420
+ this.pos += 1;
2421
+ }
2422
+ const opener = this.text[this.pos];
2423
+ if (opener && "([{".includes(opener)) {
2424
+ const close = opener === "(" ? ")" : opener === "[" ? "]" : "}";
2425
+ if (prefix.value > 0) {
2426
+ const bodyEnd = this.advanceByBytes(this.pos + 1, prefix.value);
2427
+ this.pos = bodyEnd + 1;
2428
+ const end3 = this.pos;
2429
+ this.pos = save;
2430
+ return end3;
2431
+ }
2432
+ this.pos += 1;
2433
+ while (true) {
2434
+ this.skipNonCode();
2435
+ if (this.text[this.pos] === close)
2436
+ break;
2437
+ this.skipValue();
2438
+ }
2439
+ this.pos += 1;
2440
+ const end2 = this.pos;
2441
+ this.pos = save;
2442
+ return end2;
2443
+ }
2444
+ this.pos += 1;
2445
+ const end = this.pos;
2446
+ this.pos = save;
2447
+ return end;
2448
+ }
2449
+ }
2450
+
2451
+ // rex-repl.ts
2452
+ var req = createRequire2(import.meta.url);
2453
+ var { version } = req("./package.json");
2454
+ function createColors(enabled) {
2455
+ if (!enabled) {
2456
+ return {
2457
+ reset: "",
2458
+ bold: "",
2459
+ dim: "",
2460
+ red: "",
2461
+ green: "",
2462
+ yellow: "",
2463
+ blue: "",
2464
+ magenta: "",
2465
+ cyan: "",
2466
+ gray: "",
2467
+ keyword: ""
2468
+ };
2469
+ }
2470
+ return {
2471
+ reset: "\x1B[0m",
2472
+ bold: "\x1B[1m",
2473
+ dim: "\x1B[2m",
2474
+ red: "\x1B[38;5;203m",
2475
+ green: "\x1B[38;5;114m",
2476
+ yellow: "\x1B[38;5;179m",
2477
+ blue: "\x1B[38;5;75m",
2478
+ magenta: "\x1B[38;5;141m",
2479
+ cyan: "\x1B[38;5;81m",
2480
+ gray: "\x1B[38;5;245m",
2481
+ keyword: "\x1B[1;38;5;208m"
2482
+ };
2483
+ }
2484
+ var colorEnabled = process.stdout.isTTY;
2485
+ var C = createColors(colorEnabled);
2486
+ function setColorEnabled(enabled) {
2487
+ colorEnabled = enabled;
2488
+ C = createColors(enabled);
2489
+ }
2490
+ var TOKEN_RE = /(?<blockComment>\/\*[\s\S]*?(?:\*\/|$))|(?<lineComment>\/\/[^\n]*)|(?<dstring>"(?:[^"\\]|\\.)*"?)|(?<sstring>'(?:[^'\\]|\\.)*'?)|(?<objKey>\b[A-Za-z_][A-Za-z0-9_-]*\b)(?=\s*:)|(?<keyword>\b(?:when|unless|while|for|do|end|in|of|and|or|nor|else|break|continue|delete|self)(?![a-zA-Z0-9_-]))|(?<literal>\b(?:true|false|null|undefined|nan)(?![a-zA-Z0-9_-])|-?\binf\b)|(?<typePred>\b(?:string|number|object|array|boolean)(?![a-zA-Z0-9_-]))|(?<num>\b(?:0x[0-9a-fA-F]+|0b[01]+|(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?)\b)|(?<identifier>\b[A-Za-z_][A-Za-z0-9_.-]*\b)/g;
2491
+ function highlightLine(line) {
2492
+ let result = "";
2493
+ let lastIndex = 0;
2494
+ TOKEN_RE.lastIndex = 0;
2495
+ for (const m of line.matchAll(TOKEN_RE)) {
2496
+ result += line.slice(lastIndex, m.index);
2497
+ const text = m[0];
2498
+ const g = m.groups;
2499
+ if (g.blockComment || g.lineComment) {
2500
+ result += C.gray + text + C.reset;
2501
+ } else if (g.dstring || g.sstring) {
2502
+ result += C.green + text + C.reset;
2503
+ } else if (g.objKey) {
2504
+ result += C.magenta + text + C.reset;
2505
+ } else if (g.keyword) {
2506
+ result += C.keyword + text + C.reset;
2507
+ } else if (g.literal) {
2508
+ result += C.yellow + text + C.reset;
2509
+ } else if (g.typePred) {
2510
+ result += C.cyan + text + C.reset;
2511
+ } else if (g.num) {
2512
+ result += C.cyan + text + C.reset;
2513
+ } else if (g.identifier) {
2514
+ result += C.blue + text + C.reset;
2515
+ } else {
2516
+ result += text;
2517
+ }
2518
+ lastIndex = m.index + text.length;
2519
+ }
2520
+ result += line.slice(lastIndex);
2521
+ return result;
2522
+ }
2523
+ var REXC_DIGITS = new Set("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_");
2524
+ var JSON_TOKEN_RE = /(?<key>"(?:[^"\\]|\\.)*")\s*:|(?<string>"(?:[^"\\]|\\.)*")|(?<number>-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?)\b|(?<bool>true|false)|(?<null>null)|(?<brace>[{}[\]])|(?<punct>[:,])/g;
2525
+ function highlightJSON(json) {
2526
+ let result = "";
2527
+ let lastIndex = 0;
2528
+ JSON_TOKEN_RE.lastIndex = 0;
2529
+ for (const m of json.matchAll(JSON_TOKEN_RE)) {
2530
+ result += json.slice(lastIndex, m.index);
2531
+ const text = m[0];
2532
+ const g = m.groups;
2533
+ if (g.key) {
2534
+ result += C.cyan + g.key + C.reset + ":";
2535
+ } else if (g.string) {
2536
+ result += C.green + text + C.reset;
2537
+ } else if (g.number) {
2538
+ result += C.yellow + text + C.reset;
2539
+ } else if (g.bool) {
2540
+ result += C.yellow + text + C.reset;
2541
+ } else if (g.null) {
2542
+ result += C.dim + text + C.reset;
2543
+ } else {
2544
+ result += text;
2545
+ }
2546
+ lastIndex = m.index + text.length;
2547
+ }
2548
+ result += json.slice(lastIndex);
2549
+ return result;
2550
+ }
2551
+ var HISTORY_PATH = resolve2(homedir(), ".rex_history");
2552
+
2553
+ // rx-cli.ts
2554
+ import { readFile, writeFile } from "node:fs/promises";
2555
+ function parseArgs(argv) {
2556
+ const opts = {
2557
+ files: [],
2558
+ color: process.stdout.isTTY ?? false,
2559
+ colorExplicit: false,
2560
+ help: false
2561
+ };
2562
+ for (let i = 0;i < argv.length; i++) {
2563
+ const arg = argv[i];
2564
+ if (arg === "-h" || arg === "--help") {
2565
+ opts.help = true;
2566
+ continue;
2567
+ }
2568
+ if (arg === "--color") {
2569
+ opts.color = true;
2570
+ opts.colorExplicit = true;
2571
+ continue;
2572
+ }
2573
+ if (arg === "--no-color") {
2574
+ opts.color = false;
2575
+ opts.colorExplicit = true;
2576
+ continue;
2577
+ }
2578
+ if (arg === "-j" || arg === "--json") {
2579
+ opts.toFormat = "json";
2580
+ continue;
2581
+ }
2582
+ if (arg === "-r" || arg === "--rexc") {
2583
+ opts.toFormat = "rexc";
2584
+ continue;
2585
+ }
2586
+ if (arg === "-t" || arg === "--tree") {
2587
+ opts.toFormat = "tree";
2588
+ continue;
2589
+ }
2590
+ if (arg === "--from") {
2591
+ const v = argv[++i];
2592
+ if (v !== "json" && v !== "rexc")
2593
+ throw new Error("--from must be 'json' or 'rexc'");
2594
+ opts.fromFormat = v;
2595
+ continue;
2596
+ }
2597
+ if (arg === "--to") {
2598
+ const v = argv[++i];
2599
+ if (v !== "json" && v !== "rexc" && v !== "tree")
2600
+ throw new Error("--to must be 'json', 'rexc', or 'tree'");
2601
+ opts.toFormat = v;
2602
+ continue;
2603
+ }
2604
+ if (arg === "-s" || arg === "--select") {
2605
+ const v = argv[++i];
2606
+ if (!v)
2607
+ throw new Error("Missing value for --select");
2608
+ opts.select = v;
2609
+ continue;
2610
+ }
2611
+ if (arg === "-o" || arg === "--out") {
2612
+ const v = argv[++i];
2613
+ if (!v)
2614
+ throw new Error("Missing value for --out");
2615
+ opts.out = v;
2616
+ continue;
2617
+ }
2618
+ if (!arg.startsWith("-") || arg === "-") {
2619
+ opts.files.push(arg);
2620
+ continue;
2621
+ }
2622
+ throw new Error(`Unknown option: ${arg}`);
2623
+ }
2624
+ return opts;
2625
+ }
2626
+ function usage() {
2627
+ return [
2628
+ "rx — inspect, convert, and filter REXC & JSON data.",
2629
+ "",
2630
+ "Usage:",
2631
+ " rx data.rexc Pretty-print rexc as a tree",
2632
+ " rx data.rexc --to json Convert rexc to JSON",
2633
+ " rx data.json --to rexc Convert JSON to rexc",
2634
+ " cat data.rexc | rx Read from stdin (auto-detect)",
2635
+ " rx -s .routes[0].op data.rexc Select a sub-value",
2636
+ "",
2637
+ "Input:",
2638
+ " <file> Read from file (format auto-detected by extension)",
2639
+ " - Read from stdin explicitly",
2640
+ " (no args, piped) Read from stdin automatically",
2641
+ "",
2642
+ "Format control:",
2643
+ " --from json|rexc Force input format (default: auto-detect)",
2644
+ " --to json|rexc|tree Output format",
2645
+ " -j, --json Shortcut for --to json",
2646
+ " -r, --rexc Shortcut for --to rexc",
2647
+ " -t, --tree Shortcut for --to tree",
2648
+ "",
2649
+ " Default output: tree on TTY, json when piped.",
2650
+ "",
2651
+ "Filtering:",
2652
+ " -s, --select <path> Dot-path selector (e.g. .foo.bar[0].baz)",
2653
+ "",
2654
+ "Output:",
2655
+ " -o, --out <path> Write to file instead of stdout",
2656
+ " --color Force ANSI color",
2657
+ " --no-color Disable ANSI color",
2658
+ " -h, --help Show this message"
2659
+ ].join(`
2660
+ `);
2661
+ }
2662
+ function formatFromExt(path) {
2663
+ if (path.endsWith(".json"))
2664
+ return "json";
2665
+ if (path.endsWith(".rexc"))
2666
+ return "rexc";
2667
+ return;
2668
+ }
2669
+ function detectFormat(content) {
2670
+ const t = content.trimStart();
2671
+ if (/^[\[{"0-9tfn\-]/.test(t)) {
2672
+ try {
2673
+ JSON.parse(content);
2674
+ return "json";
2675
+ } catch {}
2676
+ }
2677
+ return "rexc";
2678
+ }
2679
+ async function readStdin() {
2680
+ const chunks = [];
2681
+ for await (const chunk of process.stdin) {
2682
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
2683
+ }
2684
+ return Buffer.concat(chunks).toString("utf8");
2685
+ }
2686
+ function parseRaw(raw, format) {
2687
+ if (format === "json")
2688
+ return JSON.parse(raw);
2689
+ return parse(raw.trim());
2690
+ }
2691
+ async function readInput(opts) {
2692
+ if (opts.files.length === 0) {
2693
+ if (process.stdin.isTTY)
2694
+ throw new Error("No input. Provide a file or pipe data via stdin.");
2695
+ const raw = await readStdin();
2696
+ if (!raw.trim())
2697
+ throw new Error("Empty stdin.");
2698
+ const format = opts.fromFormat ?? detectFormat(raw);
2699
+ return { value: parseRaw(raw, format) };
2700
+ }
2701
+ if (opts.files.length === 1) {
2702
+ const file = opts.files[0];
2703
+ const raw = file === "-" ? await readStdin() : await readFile(file, "utf8");
2704
+ const format = opts.fromFormat ?? (file === "-" ? detectFormat(raw) : formatFromExt(file) ?? detectFormat(raw));
2705
+ return { value: parseRaw(raw, format) };
2706
+ }
2707
+ const values = [];
2708
+ for (const file of opts.files) {
2709
+ const raw = file === "-" ? await readStdin() : await readFile(file, "utf8");
2710
+ const format = opts.fromFormat ?? (file === "-" ? detectFormat(raw) : formatFromExt(file) ?? detectFormat(raw));
2711
+ values.push(parseRaw(raw, format));
2712
+ }
2713
+ return { value: values };
2714
+ }
2715
+ function parseSelector(selector) {
2716
+ const segments = [];
2717
+ const re = /\.([a-zA-Z_][\w-]*)|(\[(\d+)\])/g;
2718
+ let s = selector;
2719
+ if (s.startsWith("."))
2720
+ s = s;
2721
+ else if (!s.startsWith("["))
2722
+ s = "." + s;
2723
+ let match;
2724
+ let lastIndex = 0;
2725
+ while ((match = re.exec(s)) !== null) {
2726
+ if (match.index !== lastIndex) {
2727
+ throw new Error(`Invalid selector at position ${lastIndex}: ${selector}`);
2728
+ }
2729
+ if (match[1] !== undefined) {
2730
+ segments.push({ type: "key", name: match[1] });
2731
+ } else if (match[3] !== undefined) {
2732
+ segments.push({ type: "index", value: parseInt(match[3], 10) });
2733
+ }
2734
+ lastIndex = re.lastIndex;
2735
+ }
2736
+ if (lastIndex !== s.length) {
2737
+ throw new Error(`Invalid selector at position ${lastIndex}: ${selector}`);
2738
+ }
2739
+ return segments;
2740
+ }
2741
+ function applySelector(value, selector) {
2742
+ if (selector === "." || selector === "")
2743
+ return value;
2744
+ const segments = parseSelector(selector);
2745
+ let current = value;
2746
+ let path = "";
2747
+ for (const seg of segments) {
2748
+ if (seg.type === "key") {
2749
+ path += `.${seg.name}`;
2750
+ if (current === null || current === undefined || typeof current !== "object" || Array.isArray(current)) {
2751
+ throw new Error(`Selector ${path}: cannot access property '${seg.name}' on ${typeLabel(current)}`);
2752
+ }
2753
+ const obj = current;
2754
+ if (!(seg.name in obj)) {
2755
+ throw new Error(`Selector ${path}: property '${seg.name}' not found`);
2756
+ }
2757
+ current = obj[seg.name];
2758
+ } else {
2759
+ path += `[${seg.value}]`;
2760
+ if (!Array.isArray(current)) {
2761
+ throw new Error(`Selector ${path}: cannot index into ${typeLabel(current)}`);
2762
+ }
2763
+ if (seg.value < 0 || seg.value >= current.length) {
2764
+ throw new Error(`Selector ${path}: index ${seg.value} out of range (length ${current.length})`);
2765
+ }
2766
+ current = current[seg.value];
2767
+ }
2768
+ }
2769
+ return current;
2770
+ }
2771
+ function typeLabel(v) {
2772
+ if (v === null)
2773
+ return "null";
2774
+ if (v === undefined)
2775
+ return "undefined";
2776
+ if (Array.isArray(v))
2777
+ return "array";
2778
+ return typeof v;
2779
+ }
2780
+ function formatTree(value, color) {
2781
+ const text = stringify3(value, { indent: 2, maxWidth: 80 });
2782
+ if (!color)
2783
+ return text;
2784
+ return text.split(`
2785
+ `).map((line) => highlightLine(line)).join(`
2786
+ `);
2787
+ }
2788
+ function normalizeForJson(value, inArray) {
2789
+ if (value === undefined)
2790
+ return inArray ? null : undefined;
2791
+ if (value === null || typeof value !== "object")
2792
+ return value;
2793
+ if (Array.isArray(value))
2794
+ return value.map((item) => normalizeForJson(item, true));
2795
+ const out = {};
2796
+ for (const [key, val] of Object.entries(value)) {
2797
+ const n = normalizeForJson(val, false);
2798
+ if (n !== undefined)
2799
+ out[key] = n;
2800
+ }
2801
+ return out;
2802
+ }
2803
+ function formatOutput(value, format, color) {
2804
+ if (format === "tree")
2805
+ return formatTree(value, color);
2806
+ if (format === "json") {
2807
+ const text = JSON.stringify(normalizeForJson(value, false), null, 2) ?? "null";
2808
+ return color ? highlightJSON(text) : text;
2809
+ }
2810
+ return stringify2(value);
2811
+ }
2812
+ async function main() {
2813
+ const opts = parseArgs(process.argv.slice(2));
2814
+ if (opts.help) {
2815
+ console.log(usage());
2816
+ return;
2817
+ }
2818
+ setColorEnabled(opts.color);
2819
+ const toFormat = opts.toFormat ?? (process.stdout.isTTY ? "tree" : "json");
2820
+ const { value: parsed } = await readInput(opts);
2821
+ const value = opts.select ? applySelector(parsed, opts.select) : parsed;
2822
+ const output = formatOutput(value, toFormat, opts.color);
2823
+ if (opts.out) {
2824
+ await writeFile(opts.out, output + `
2825
+ `, "utf8");
2826
+ } else {
2827
+ process.stdout.write(output + `
2828
+ `);
2829
+ }
2830
+ }
2831
+ await main().catch((error) => {
2832
+ const message = error instanceof Error ? error.message : String(error);
2833
+ process.stderr.write(`rx: ${message}
2834
+ `);
2835
+ process.exit(1);
2836
+ });