@gabrielbryk/jq-ts 1.2.0 → 1.3.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/dist/index.cjs +682 -303
- package/dist/index.mjs +682 -303
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -863,8 +863,27 @@ var Parser = class {
|
|
|
863
863
|
if (!this.match("RBrace")) {
|
|
864
864
|
do {
|
|
865
865
|
const key = this.parseObjectKey();
|
|
866
|
-
|
|
867
|
-
|
|
866
|
+
let value;
|
|
867
|
+
if (this.match("Colon")) value = this.parseDef(false);
|
|
868
|
+
else if (key.kind === "KeyIdentifier") value = {
|
|
869
|
+
kind: "FieldAccess",
|
|
870
|
+
target: {
|
|
871
|
+
kind: "Identity",
|
|
872
|
+
span: key.span
|
|
873
|
+
},
|
|
874
|
+
field: key.name,
|
|
875
|
+
span: key.span
|
|
876
|
+
};
|
|
877
|
+
else if (key.kind === "KeyString") value = {
|
|
878
|
+
kind: "FieldAccess",
|
|
879
|
+
target: {
|
|
880
|
+
kind: "Identity",
|
|
881
|
+
span: key.span
|
|
882
|
+
},
|
|
883
|
+
field: key.value,
|
|
884
|
+
span: key.span
|
|
885
|
+
};
|
|
886
|
+
else throw this.error(this.peek(), "Expected \":\" after object key");
|
|
868
887
|
entries.push({
|
|
869
888
|
key,
|
|
870
889
|
value
|
|
@@ -1346,6 +1365,51 @@ const stdBuiltins = [
|
|
|
1346
1365
|
name: "empty",
|
|
1347
1366
|
arity: 0,
|
|
1348
1367
|
apply: function* () {}
|
|
1368
|
+
},
|
|
1369
|
+
{
|
|
1370
|
+
name: "toboolean",
|
|
1371
|
+
arity: 0,
|
|
1372
|
+
apply: function* (input, _args, _env, tracker, _eval, span) {
|
|
1373
|
+
yield emit$1(isTruthy(input), span, tracker);
|
|
1374
|
+
}
|
|
1375
|
+
},
|
|
1376
|
+
{
|
|
1377
|
+
name: "walk",
|
|
1378
|
+
arity: 1,
|
|
1379
|
+
apply: function* (input, args, env, tracker, evaluate$1, span) {
|
|
1380
|
+
const f = args[0];
|
|
1381
|
+
const walkRec = function* (curr) {
|
|
1382
|
+
tracker.step(span);
|
|
1383
|
+
let newStruct = curr;
|
|
1384
|
+
if (Array.isArray(curr)) {
|
|
1385
|
+
const newArr = [];
|
|
1386
|
+
for (const item of curr) for (const walkedItem of walkRec(item)) newArr.push(walkedItem);
|
|
1387
|
+
newStruct = newArr;
|
|
1388
|
+
} else if (isPlainObject(curr)) {
|
|
1389
|
+
const newObj = {};
|
|
1390
|
+
const keys = Object.keys(curr).sort();
|
|
1391
|
+
let objValid = true;
|
|
1392
|
+
for (const key of keys) {
|
|
1393
|
+
const val = curr[key];
|
|
1394
|
+
let lastVal;
|
|
1395
|
+
let found = false;
|
|
1396
|
+
for (const walkedVal of walkRec(val)) {
|
|
1397
|
+
lastVal = walkedVal;
|
|
1398
|
+
found = true;
|
|
1399
|
+
}
|
|
1400
|
+
if (found) newObj[key] = lastVal;
|
|
1401
|
+
else {
|
|
1402
|
+
objValid = false;
|
|
1403
|
+
break;
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
if (!objValid) return;
|
|
1407
|
+
newStruct = newObj;
|
|
1408
|
+
}
|
|
1409
|
+
yield* evaluate$1(f, newStruct, env, tracker);
|
|
1410
|
+
};
|
|
1411
|
+
yield* walkRec(input);
|
|
1412
|
+
}
|
|
1349
1413
|
}
|
|
1350
1414
|
];
|
|
1351
1415
|
|
|
@@ -1359,6 +1423,232 @@ const errorBuiltins = [{
|
|
|
1359
1423
|
}
|
|
1360
1424
|
}];
|
|
1361
1425
|
|
|
1426
|
+
//#endregion
|
|
1427
|
+
//#region src/builtins/strings.ts
|
|
1428
|
+
const checkContains = (a, b) => {
|
|
1429
|
+
if (a === b) return true;
|
|
1430
|
+
if (typeof a !== typeof b) return false;
|
|
1431
|
+
if (typeof a === "string" && typeof b === "string") return a.includes(b);
|
|
1432
|
+
if (Array.isArray(a) && Array.isArray(b)) return b.every((bItem) => a.some((aItem) => checkContains(aItem, bItem)));
|
|
1433
|
+
if (isPlainObject(a) && isPlainObject(b)) {
|
|
1434
|
+
const keys = Object.keys(b);
|
|
1435
|
+
for (const key of keys) {
|
|
1436
|
+
if (!Object.prototype.hasOwnProperty.call(a, key)) return false;
|
|
1437
|
+
const valA = a[key];
|
|
1438
|
+
const valB = b[key];
|
|
1439
|
+
if (!checkContains(valA, valB)) return false;
|
|
1440
|
+
}
|
|
1441
|
+
return true;
|
|
1442
|
+
}
|
|
1443
|
+
return valueEquals(a, b);
|
|
1444
|
+
};
|
|
1445
|
+
const stringBuiltins = [
|
|
1446
|
+
{
|
|
1447
|
+
name: "split",
|
|
1448
|
+
arity: 1,
|
|
1449
|
+
apply: function* (input, args, env, tracker, evaluate$1, span) {
|
|
1450
|
+
if (typeof input !== "string") throw new RuntimeError("split input must be a string", span);
|
|
1451
|
+
const sepGen = evaluate$1(args[0], input, env, tracker);
|
|
1452
|
+
for (const sep of sepGen) {
|
|
1453
|
+
if (typeof sep !== "string") throw new RuntimeError("split separator must be a string", span);
|
|
1454
|
+
yield emit$1(input.split(sep), span, tracker);
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
},
|
|
1458
|
+
{
|
|
1459
|
+
name: "join",
|
|
1460
|
+
arity: 1,
|
|
1461
|
+
apply: function* (input, args, env, tracker, evaluate$1, span) {
|
|
1462
|
+
if (!Array.isArray(input)) throw new RuntimeError("join input must be an array", span);
|
|
1463
|
+
const sepGen = evaluate$1(args[0], input, env, tracker);
|
|
1464
|
+
for (const sep of sepGen) {
|
|
1465
|
+
if (typeof sep !== "string") throw new RuntimeError("join separator must be a string", span);
|
|
1466
|
+
const parts = [];
|
|
1467
|
+
for (const item of input) {
|
|
1468
|
+
if (typeof item !== "string") throw new RuntimeError(`join expects strings, but got ${describeType(item)}`, span);
|
|
1469
|
+
parts.push(item);
|
|
1470
|
+
}
|
|
1471
|
+
yield emit$1(parts.join(sep), span, tracker);
|
|
1472
|
+
}
|
|
1473
|
+
}
|
|
1474
|
+
},
|
|
1475
|
+
{
|
|
1476
|
+
name: "startswith",
|
|
1477
|
+
arity: 1,
|
|
1478
|
+
apply: function* (input, args, env, tracker, evaluate$1, span) {
|
|
1479
|
+
if (typeof input !== "string") throw new RuntimeError("startswith input must be a string", span);
|
|
1480
|
+
const prefixGen = evaluate$1(args[0], input, env, tracker);
|
|
1481
|
+
for (const prefix of prefixGen) {
|
|
1482
|
+
if (typeof prefix !== "string") throw new RuntimeError("startswith prefix must be a string", span);
|
|
1483
|
+
yield emit$1(input.startsWith(prefix), span, tracker);
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
},
|
|
1487
|
+
{
|
|
1488
|
+
name: "endswith",
|
|
1489
|
+
arity: 1,
|
|
1490
|
+
apply: function* (input, args, env, tracker, evaluate$1, span) {
|
|
1491
|
+
if (typeof input !== "string") throw new RuntimeError("endswith input must be a string", span);
|
|
1492
|
+
const suffixGen = evaluate$1(args[0], input, env, tracker);
|
|
1493
|
+
for (const suffix of suffixGen) {
|
|
1494
|
+
if (typeof suffix !== "string") throw new RuntimeError("endswith suffix must be a string", span);
|
|
1495
|
+
yield emit$1(input.endsWith(suffix), span, tracker);
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
},
|
|
1499
|
+
{
|
|
1500
|
+
name: "contains",
|
|
1501
|
+
arity: 1,
|
|
1502
|
+
apply: function* (input, args, env, tracker, evaluate$1, span) {
|
|
1503
|
+
const bGen = evaluate$1(args[0], input, env, tracker);
|
|
1504
|
+
for (const b of bGen) yield emit$1(checkContains(input, b), span, tracker);
|
|
1505
|
+
}
|
|
1506
|
+
},
|
|
1507
|
+
{
|
|
1508
|
+
name: "index",
|
|
1509
|
+
arity: 1,
|
|
1510
|
+
apply: function* (input, args, env, tracker, evaluate$1, span) {
|
|
1511
|
+
const searchGen = evaluate$1(args[0], input, env, tracker);
|
|
1512
|
+
for (const search of searchGen) if (Array.isArray(input)) {
|
|
1513
|
+
let foundIndex = null;
|
|
1514
|
+
for (let i = 0; i < input.length; i++) {
|
|
1515
|
+
const val = input[i];
|
|
1516
|
+
if (val !== void 0 && valueEquals(val, search)) {
|
|
1517
|
+
foundIndex = i;
|
|
1518
|
+
break;
|
|
1519
|
+
}
|
|
1520
|
+
}
|
|
1521
|
+
yield emit$1(foundIndex, span, tracker);
|
|
1522
|
+
} else if (typeof input === "string") {
|
|
1523
|
+
if (typeof search !== "string") throw new RuntimeError("index expects string search when input is string", span);
|
|
1524
|
+
const idx = input.indexOf(search);
|
|
1525
|
+
yield emit$1(idx === -1 ? null : idx, span, tracker);
|
|
1526
|
+
} else if (input === null) yield emit$1(null, span, tracker);
|
|
1527
|
+
else throw new RuntimeError("index expects string or array", span);
|
|
1528
|
+
}
|
|
1529
|
+
},
|
|
1530
|
+
{
|
|
1531
|
+
name: "rindex",
|
|
1532
|
+
arity: 1,
|
|
1533
|
+
apply: function* (input, args, env, tracker, evaluate$1, span) {
|
|
1534
|
+
const searchGen = evaluate$1(args[0], input, env, tracker);
|
|
1535
|
+
for (const search of searchGen) if (Array.isArray(input)) {
|
|
1536
|
+
let foundIndex = null;
|
|
1537
|
+
for (let i = input.length - 1; i >= 0; i--) {
|
|
1538
|
+
const val = input[i];
|
|
1539
|
+
if (val !== void 0 && valueEquals(val, search)) {
|
|
1540
|
+
foundIndex = i;
|
|
1541
|
+
break;
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1544
|
+
yield emit$1(foundIndex, span, tracker);
|
|
1545
|
+
} else if (typeof input === "string") {
|
|
1546
|
+
if (typeof search !== "string") throw new RuntimeError("rindex expects string search when input is string", span);
|
|
1547
|
+
const idx = input.lastIndexOf(search);
|
|
1548
|
+
yield emit$1(idx === -1 ? null : idx, span, tracker);
|
|
1549
|
+
} else if (input === null) yield emit$1(null, span, tracker);
|
|
1550
|
+
else throw new RuntimeError("rindex expects string or array", span);
|
|
1551
|
+
}
|
|
1552
|
+
},
|
|
1553
|
+
{
|
|
1554
|
+
name: "indices",
|
|
1555
|
+
arity: 1,
|
|
1556
|
+
apply: function* (input, args, env, tracker, evaluate$1, span) {
|
|
1557
|
+
const searchGen = evaluate$1(args[0], input, env, tracker);
|
|
1558
|
+
for (const search of searchGen) {
|
|
1559
|
+
const indices = [];
|
|
1560
|
+
if (Array.isArray(input)) for (let i = 0; i < input.length; i++) {
|
|
1561
|
+
const val = input[i];
|
|
1562
|
+
if (val !== void 0 && valueEquals(val, search)) indices.push(i);
|
|
1563
|
+
}
|
|
1564
|
+
else if (typeof input === "string") {
|
|
1565
|
+
if (typeof search !== "string") throw new RuntimeError("indices expects string", span);
|
|
1566
|
+
if (search.length === 0) {} else {
|
|
1567
|
+
let pos = 0;
|
|
1568
|
+
while (pos < input.length) {
|
|
1569
|
+
const idx = input.indexOf(search, pos);
|
|
1570
|
+
if (idx === -1) break;
|
|
1571
|
+
indices.push(idx);
|
|
1572
|
+
pos = idx + 1;
|
|
1573
|
+
pos = idx + search.length;
|
|
1574
|
+
}
|
|
1575
|
+
}
|
|
1576
|
+
} else {
|
|
1577
|
+
if (input === null) {
|
|
1578
|
+
yield emit$1(null, span, tracker);
|
|
1579
|
+
continue;
|
|
1580
|
+
}
|
|
1581
|
+
throw new RuntimeError("indices expects string or array", span);
|
|
1582
|
+
}
|
|
1583
|
+
yield emit$1(indices, span, tracker);
|
|
1584
|
+
}
|
|
1585
|
+
}
|
|
1586
|
+
},
|
|
1587
|
+
{
|
|
1588
|
+
name: "explode",
|
|
1589
|
+
arity: 0,
|
|
1590
|
+
apply: function* (input, _args, _env, tracker, _eval, span) {
|
|
1591
|
+
if (typeof input !== "string") throw new RuntimeError("explode expects string", span);
|
|
1592
|
+
yield emit$1(Array.from(input).map((c) => c.codePointAt(0)), span, tracker);
|
|
1593
|
+
}
|
|
1594
|
+
},
|
|
1595
|
+
{
|
|
1596
|
+
name: "implode",
|
|
1597
|
+
arity: 0,
|
|
1598
|
+
apply: function* (input, _args, _env, tracker, _eval, span) {
|
|
1599
|
+
if (!Array.isArray(input)) throw new RuntimeError("implode expects array", span);
|
|
1600
|
+
const chars = [];
|
|
1601
|
+
for (const item of input) {
|
|
1602
|
+
if (typeof item !== "number") throw new RuntimeError("implode item must be number", span);
|
|
1603
|
+
chars.push(String.fromCodePoint(item));
|
|
1604
|
+
}
|
|
1605
|
+
yield emit$1(chars.join(""), span, tracker);
|
|
1606
|
+
}
|
|
1607
|
+
},
|
|
1608
|
+
{
|
|
1609
|
+
name: "ltrimstr",
|
|
1610
|
+
arity: 1,
|
|
1611
|
+
apply: function* (input, args, env, tracker, evaluate$1, span) {
|
|
1612
|
+
if (typeof input !== "string") throw new RuntimeError("ltrimstr expects string", span);
|
|
1613
|
+
const prefixGen = evaluate$1(args[0], input, env, tracker);
|
|
1614
|
+
for (const prefix of prefixGen) {
|
|
1615
|
+
if (typeof prefix !== "string") throw new RuntimeError("ltrimstr prefix must be a string", span);
|
|
1616
|
+
if (input.startsWith(prefix)) yield emit$1(input.slice(prefix.length), span, tracker);
|
|
1617
|
+
else yield emit$1(input, span, tracker);
|
|
1618
|
+
}
|
|
1619
|
+
}
|
|
1620
|
+
},
|
|
1621
|
+
{
|
|
1622
|
+
name: "rtrimstr",
|
|
1623
|
+
arity: 1,
|
|
1624
|
+
apply: function* (input, args, env, tracker, evaluate$1, span) {
|
|
1625
|
+
if (typeof input !== "string") throw new RuntimeError("rtrimstr expects string", span);
|
|
1626
|
+
const suffixGen = evaluate$1(args[0], input, env, tracker);
|
|
1627
|
+
for (const suffix of suffixGen) {
|
|
1628
|
+
if (typeof suffix !== "string") throw new RuntimeError("rtrimstr suffix must be a string", span);
|
|
1629
|
+
if (input.endsWith(suffix)) yield emit$1(input.slice(0, input.length - suffix.length), span, tracker);
|
|
1630
|
+
else yield emit$1(input, span, tracker);
|
|
1631
|
+
}
|
|
1632
|
+
}
|
|
1633
|
+
},
|
|
1634
|
+
{
|
|
1635
|
+
name: "ascii_downcase",
|
|
1636
|
+
arity: 0,
|
|
1637
|
+
apply: function* (input, _args, _env, tracker, _eval, span) {
|
|
1638
|
+
if (typeof input !== "string") throw new RuntimeError("ascii_downcase expects string", span);
|
|
1639
|
+
yield emit$1(input.toLowerCase(), span, tracker);
|
|
1640
|
+
}
|
|
1641
|
+
},
|
|
1642
|
+
{
|
|
1643
|
+
name: "ascii_upcase",
|
|
1644
|
+
arity: 0,
|
|
1645
|
+
apply: function* (input, _args, _env, tracker, _eval, span) {
|
|
1646
|
+
if (typeof input !== "string") throw new RuntimeError("ascii_upcase expects string", span);
|
|
1647
|
+
yield emit$1(input.toUpperCase(), span, tracker);
|
|
1648
|
+
}
|
|
1649
|
+
}
|
|
1650
|
+
];
|
|
1651
|
+
|
|
1362
1652
|
//#endregion
|
|
1363
1653
|
//#region src/builtins/collections.ts
|
|
1364
1654
|
function sortStable(arr, compare$1) {
|
|
@@ -1553,189 +1843,207 @@ const collectionBuiltins = [
|
|
|
1553
1843
|
}
|
|
1554
1844
|
yield emit$1(result, span, tracker);
|
|
1555
1845
|
}
|
|
1556
|
-
}
|
|
1557
|
-
];
|
|
1558
|
-
|
|
1559
|
-
//#endregion
|
|
1560
|
-
//#region src/builtins/strings.ts
|
|
1561
|
-
const checkContains = (a, b) => {
|
|
1562
|
-
if (a === b) return true;
|
|
1563
|
-
if (typeof a !== typeof b) return false;
|
|
1564
|
-
if (typeof a === "string" && typeof b === "string") return a.includes(b);
|
|
1565
|
-
if (Array.isArray(a) && Array.isArray(b)) return b.every((bItem) => a.some((aItem) => checkContains(aItem, bItem)));
|
|
1566
|
-
if (isPlainObject(a) && isPlainObject(b)) {
|
|
1567
|
-
const keys = Object.keys(b);
|
|
1568
|
-
for (const key of keys) {
|
|
1569
|
-
if (!Object.prototype.hasOwnProperty.call(a, key)) return false;
|
|
1570
|
-
const valA = a[key];
|
|
1571
|
-
const valB = b[key];
|
|
1572
|
-
if (!checkContains(valA, valB)) return false;
|
|
1573
|
-
}
|
|
1574
|
-
return true;
|
|
1575
|
-
}
|
|
1576
|
-
return valueEquals(a, b);
|
|
1577
|
-
};
|
|
1578
|
-
const stringBuiltins = [
|
|
1846
|
+
},
|
|
1579
1847
|
{
|
|
1580
|
-
name: "
|
|
1848
|
+
name: "group_by",
|
|
1581
1849
|
arity: 1,
|
|
1582
1850
|
apply: function* (input, args, env, tracker, evaluate$1, span) {
|
|
1583
|
-
if (
|
|
1584
|
-
const
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1851
|
+
if (!Array.isArray(input)) throw new RuntimeError("group_by expects an array", span);
|
|
1852
|
+
const pairs = [];
|
|
1853
|
+
const filter = args[0];
|
|
1854
|
+
for (const item of input) {
|
|
1855
|
+
tracker.step(span);
|
|
1856
|
+
const keys = Array.from(evaluate$1(filter, item, env, tracker));
|
|
1857
|
+
if (keys.length !== 1) throw new RuntimeError("group_by key expression must return exactly one value", span);
|
|
1858
|
+
pairs.push({
|
|
1859
|
+
val: item,
|
|
1860
|
+
key: keys[0]
|
|
1861
|
+
});
|
|
1862
|
+
}
|
|
1863
|
+
const sorted = sortStable(pairs, (a, b) => compareValues(a.key, b.key));
|
|
1864
|
+
const groups = [];
|
|
1865
|
+
if (sorted.length > 0) {
|
|
1866
|
+
let currentGroup = [sorted[0].val];
|
|
1867
|
+
let currentKey = sorted[0].key;
|
|
1868
|
+
for (let i = 1; i < sorted.length; i++) {
|
|
1869
|
+
const pair = sorted[i];
|
|
1870
|
+
if (compareValues(pair.key, currentKey) === 0) currentGroup.push(pair.val);
|
|
1871
|
+
else {
|
|
1872
|
+
groups.push(currentGroup);
|
|
1873
|
+
currentGroup = [pair.val];
|
|
1874
|
+
currentKey = pair.key;
|
|
1875
|
+
}
|
|
1876
|
+
}
|
|
1877
|
+
groups.push(currentGroup);
|
|
1588
1878
|
}
|
|
1879
|
+
yield emit$1(groups, span, tracker);
|
|
1589
1880
|
}
|
|
1590
1881
|
},
|
|
1591
1882
|
{
|
|
1592
|
-
name: "
|
|
1593
|
-
arity:
|
|
1594
|
-
apply: function* (input,
|
|
1595
|
-
if (!Array.isArray(input)) throw new RuntimeError("
|
|
1596
|
-
|
|
1597
|
-
for (const sep of sepGen) {
|
|
1598
|
-
if (typeof sep !== "string") throw new RuntimeError("join separator must be a string", span);
|
|
1599
|
-
const parts = [];
|
|
1600
|
-
for (const item of input) {
|
|
1601
|
-
if (typeof item !== "string") throw new RuntimeError(`join expects strings, but got ${describeType(item)}`, span);
|
|
1602
|
-
parts.push(item);
|
|
1603
|
-
}
|
|
1604
|
-
yield emit$1(parts.join(sep), span, tracker);
|
|
1605
|
-
}
|
|
1883
|
+
name: "reverse",
|
|
1884
|
+
arity: 0,
|
|
1885
|
+
apply: function* (input, _args, _env, tracker, _eval, span) {
|
|
1886
|
+
if (!Array.isArray(input)) throw new RuntimeError("reverse expects an array", span);
|
|
1887
|
+
yield emit$1([...input].reverse(), span, tracker);
|
|
1606
1888
|
}
|
|
1607
1889
|
},
|
|
1608
1890
|
{
|
|
1609
|
-
name: "
|
|
1610
|
-
arity:
|
|
1611
|
-
apply: function* (input,
|
|
1612
|
-
if (
|
|
1613
|
-
const
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1891
|
+
name: "flatten",
|
|
1892
|
+
arity: 0,
|
|
1893
|
+
apply: function* (input, _args, _env, tracker, _eval, span) {
|
|
1894
|
+
if (!Array.isArray(input)) throw new RuntimeError("flatten expects an array", span);
|
|
1895
|
+
const flattenRec = (arr) => {
|
|
1896
|
+
let res = [];
|
|
1897
|
+
for (const item of arr) if (Array.isArray(item)) res = res.concat(flattenRec(item));
|
|
1898
|
+
else res.push(item);
|
|
1899
|
+
return res;
|
|
1900
|
+
};
|
|
1901
|
+
yield emit$1(flattenRec(input), span, tracker);
|
|
1618
1902
|
}
|
|
1619
1903
|
},
|
|
1620
1904
|
{
|
|
1621
|
-
name: "
|
|
1905
|
+
name: "flatten",
|
|
1622
1906
|
arity: 1,
|
|
1623
1907
|
apply: function* (input, args, env, tracker, evaluate$1, span) {
|
|
1624
|
-
if (
|
|
1625
|
-
const
|
|
1626
|
-
for (const
|
|
1627
|
-
if (typeof
|
|
1628
|
-
|
|
1908
|
+
if (!Array.isArray(input)) throw new RuntimeError("flatten expects an array", span);
|
|
1909
|
+
const depths = evaluate$1(args[0], input, env, tracker);
|
|
1910
|
+
for (const depthVal of depths) {
|
|
1911
|
+
if (typeof depthVal !== "number") throw new RuntimeError("flatten depth must be a number", span);
|
|
1912
|
+
const flattenDepth = (arr, d) => {
|
|
1913
|
+
if (d <= 0) return arr;
|
|
1914
|
+
let res = [];
|
|
1915
|
+
for (const item of arr) if (Array.isArray(item)) res = res.concat(flattenDepth(item, d - 1));
|
|
1916
|
+
else res.push(item);
|
|
1917
|
+
return res;
|
|
1918
|
+
};
|
|
1919
|
+
yield emit$1(flattenDepth(input, depthVal), span, tracker);
|
|
1629
1920
|
}
|
|
1630
1921
|
}
|
|
1631
1922
|
},
|
|
1632
1923
|
{
|
|
1633
|
-
name: "
|
|
1634
|
-
arity:
|
|
1635
|
-
apply: function* (input,
|
|
1636
|
-
|
|
1637
|
-
|
|
1924
|
+
name: "keys_unsorted",
|
|
1925
|
+
arity: 0,
|
|
1926
|
+
apply: function* (input, _args, _env, tracker, _eval, span) {
|
|
1927
|
+
if (Array.isArray(input)) yield emit$1(Array.from({ length: input.length }, (_, i) => i), span, tracker);
|
|
1928
|
+
else if (input !== null && typeof input === "object") yield emit$1(Object.keys(input), span, tracker);
|
|
1929
|
+
else throw new RuntimeError(`keys_unsorted expects an array or object`, span);
|
|
1638
1930
|
}
|
|
1639
1931
|
},
|
|
1640
1932
|
{
|
|
1641
|
-
name: "
|
|
1642
|
-
arity:
|
|
1643
|
-
apply: function* (input,
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1933
|
+
name: "transpose",
|
|
1934
|
+
arity: 0,
|
|
1935
|
+
apply: function* (input, _args, _env, tracker, _eval, span) {
|
|
1936
|
+
if (!Array.isArray(input)) throw new RuntimeError("transpose expects an array", span);
|
|
1937
|
+
const arr = input;
|
|
1938
|
+
if (arr.length === 0) {
|
|
1939
|
+
yield emit$1([], span, tracker);
|
|
1940
|
+
return;
|
|
1941
|
+
}
|
|
1942
|
+
let maxLen = 0;
|
|
1943
|
+
for (const row of arr) {
|
|
1944
|
+
if (!Array.isArray(row)) throw new RuntimeError("transpose input must be array of arrays", span);
|
|
1945
|
+
if (row.length > maxLen) maxLen = row.length;
|
|
1946
|
+
}
|
|
1947
|
+
const result = [];
|
|
1948
|
+
for (let j = 0; j < maxLen; j++) {
|
|
1949
|
+
const newRow = [];
|
|
1950
|
+
for (let i = 0; i < arr.length; i++) {
|
|
1951
|
+
const row = arr[i];
|
|
1952
|
+
const val = j < row.length ? row[j] : null;
|
|
1953
|
+
newRow.push(val);
|
|
1653
1954
|
}
|
|
1654
|
-
|
|
1655
|
-
}
|
|
1656
|
-
|
|
1657
|
-
const idx = input.indexOf(search);
|
|
1658
|
-
yield emit$1(idx === -1 ? null : idx, span, tracker);
|
|
1659
|
-
} else if (input === null) yield emit$1(null, span, tracker);
|
|
1660
|
-
else throw new RuntimeError("index expects string or array", span);
|
|
1955
|
+
result.push(newRow);
|
|
1956
|
+
}
|
|
1957
|
+
yield emit$1(result, span, tracker);
|
|
1661
1958
|
}
|
|
1662
1959
|
},
|
|
1663
1960
|
{
|
|
1664
|
-
name: "
|
|
1961
|
+
name: "bsearch",
|
|
1665
1962
|
arity: 1,
|
|
1666
1963
|
apply: function* (input, args, env, tracker, evaluate$1, span) {
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1964
|
+
if (!Array.isArray(input)) throw new RuntimeError("bsearch expects an array", span);
|
|
1965
|
+
const targetGen = evaluate$1(args[0], input, env, tracker);
|
|
1966
|
+
for (const target of targetGen) {
|
|
1967
|
+
let low = 0;
|
|
1968
|
+
let high = input.length - 1;
|
|
1969
|
+
let idx = -1;
|
|
1970
|
+
while (low <= high) {
|
|
1971
|
+
const mid = Math.floor((low + high) / 2);
|
|
1972
|
+
const cmp = compareValues(input[mid], target);
|
|
1973
|
+
if (cmp === 0) {
|
|
1974
|
+
idx = mid;
|
|
1674
1975
|
break;
|
|
1675
|
-
}
|
|
1976
|
+
} else if (cmp < 0) low = mid + 1;
|
|
1977
|
+
else high = mid - 1;
|
|
1676
1978
|
}
|
|
1677
|
-
yield emit$1(
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
const idx = input.lastIndexOf(search);
|
|
1681
|
-
yield emit$1(idx === -1 ? null : idx, span, tracker);
|
|
1682
|
-
} else if (input === null) yield emit$1(null, span, tracker);
|
|
1683
|
-
else throw new RuntimeError("rindex expects string or array", span);
|
|
1979
|
+
if (idx !== -1) yield emit$1(idx, span, tracker);
|
|
1980
|
+
else yield emit$1(-low - 1, span, tracker);
|
|
1981
|
+
}
|
|
1684
1982
|
}
|
|
1685
1983
|
},
|
|
1686
1984
|
{
|
|
1687
|
-
name: "
|
|
1985
|
+
name: "combinations",
|
|
1986
|
+
arity: 0,
|
|
1987
|
+
apply: function* (input, _args, _env, tracker, _eval, span) {
|
|
1988
|
+
if (!Array.isArray(input)) throw new RuntimeError("combinations expects an array", span);
|
|
1989
|
+
if (input.some((x) => !Array.isArray(x))) throw new RuntimeError("combinations input must be array of arrays", span);
|
|
1990
|
+
const arrays = input;
|
|
1991
|
+
if (arrays.length === 0) {
|
|
1992
|
+
yield emit$1([], span, tracker);
|
|
1993
|
+
return;
|
|
1994
|
+
}
|
|
1995
|
+
const helper = function* (idx, current) {
|
|
1996
|
+
if (idx === arrays.length) {
|
|
1997
|
+
yield [...current];
|
|
1998
|
+
return;
|
|
1999
|
+
}
|
|
2000
|
+
const arr = arrays[idx];
|
|
2001
|
+
if (arr.length === 0) return;
|
|
2002
|
+
for (const item of arr) {
|
|
2003
|
+
current.push(item);
|
|
2004
|
+
yield* helper(idx + 1, current);
|
|
2005
|
+
current.pop();
|
|
2006
|
+
}
|
|
2007
|
+
};
|
|
2008
|
+
for (const combo of helper(0, [])) yield emit$1(combo, span, tracker);
|
|
2009
|
+
}
|
|
2010
|
+
},
|
|
2011
|
+
{
|
|
2012
|
+
name: "combinations",
|
|
1688
2013
|
arity: 1,
|
|
1689
2014
|
apply: function* (input, args, env, tracker, evaluate$1, span) {
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
if (
|
|
1694
|
-
|
|
1695
|
-
|
|
2015
|
+
if (!Array.isArray(input)) throw new RuntimeError("combinations expects an array", span);
|
|
2016
|
+
const nGen = evaluate$1(args[0], input, env, tracker);
|
|
2017
|
+
for (const nVal of nGen) {
|
|
2018
|
+
if (typeof nVal !== "number") throw new RuntimeError("combinations(n) expects n to be number", span);
|
|
2019
|
+
if (nVal === 0) {
|
|
2020
|
+
yield emit$1([], span, tracker);
|
|
2021
|
+
continue;
|
|
1696
2022
|
}
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
if (idx === -1) break;
|
|
1704
|
-
indices.push(idx);
|
|
1705
|
-
pos = idx + 1;
|
|
1706
|
-
pos = idx + search.length;
|
|
1707
|
-
}
|
|
2023
|
+
const arrays = [];
|
|
2024
|
+
for (let i = 0; i < nVal; i++) arrays.push(input);
|
|
2025
|
+
const helper = function* (idx, current) {
|
|
2026
|
+
if (idx === arrays.length) {
|
|
2027
|
+
yield [...current];
|
|
2028
|
+
return;
|
|
1708
2029
|
}
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
2030
|
+
const arr = arrays[idx];
|
|
2031
|
+
for (const item of arr) {
|
|
2032
|
+
current.push(item);
|
|
2033
|
+
yield* helper(idx + 1, current);
|
|
2034
|
+
current.pop();
|
|
1713
2035
|
}
|
|
1714
|
-
|
|
1715
|
-
}
|
|
1716
|
-
yield emit$1(indices, span, tracker);
|
|
2036
|
+
};
|
|
2037
|
+
if (input.length === 0 && nVal > 0) {} else for (const combo of helper(0, [])) yield emit$1(combo, span, tracker);
|
|
1717
2038
|
}
|
|
1718
2039
|
}
|
|
1719
2040
|
},
|
|
1720
2041
|
{
|
|
1721
|
-
name: "
|
|
1722
|
-
arity:
|
|
1723
|
-
apply: function* (input,
|
|
1724
|
-
|
|
1725
|
-
yield emit$1(
|
|
1726
|
-
}
|
|
1727
|
-
},
|
|
1728
|
-
{
|
|
1729
|
-
name: "implode",
|
|
1730
|
-
arity: 0,
|
|
1731
|
-
apply: function* (input, _args, _env, tracker, _eval, span) {
|
|
1732
|
-
if (!Array.isArray(input)) throw new RuntimeError("implode expects array", span);
|
|
1733
|
-
const chars = [];
|
|
1734
|
-
for (const item of input) {
|
|
1735
|
-
if (typeof item !== "number") throw new RuntimeError("implode item must be number", span);
|
|
1736
|
-
chars.push(String.fromCodePoint(item));
|
|
1737
|
-
}
|
|
1738
|
-
yield emit$1(chars.join(""), span, tracker);
|
|
2042
|
+
name: "inside",
|
|
2043
|
+
arity: 1,
|
|
2044
|
+
apply: function* (input, args, env, tracker, evaluate$1, span) {
|
|
2045
|
+
const bGen = evaluate$1(args[0], input, env, tracker);
|
|
2046
|
+
for (const b of bGen) yield emit$1(checkContains(b, input), span, tracker);
|
|
1739
2047
|
}
|
|
1740
2048
|
}
|
|
1741
2049
|
];
|
|
@@ -2109,8 +2417,216 @@ const iteratorBuiltins = [
|
|
|
2109
2417
|
};
|
|
2110
2418
|
yield* rec(input);
|
|
2111
2419
|
}
|
|
2420
|
+
},
|
|
2421
|
+
{
|
|
2422
|
+
name: "while",
|
|
2423
|
+
arity: 2,
|
|
2424
|
+
apply: function* (input, args, env, tracker, evaluate$1, span) {
|
|
2425
|
+
const condExpr = args[0];
|
|
2426
|
+
const updateExpr = args[1];
|
|
2427
|
+
const rec = function* (curr) {
|
|
2428
|
+
tracker.step(span);
|
|
2429
|
+
let condMatches = false;
|
|
2430
|
+
for (const c of evaluate$1(condExpr, curr, env, tracker)) if (isTruthy(c)) {
|
|
2431
|
+
condMatches = true;
|
|
2432
|
+
break;
|
|
2433
|
+
}
|
|
2434
|
+
if (condMatches) {
|
|
2435
|
+
yield emit$1(curr, span, tracker);
|
|
2436
|
+
for (const next of evaluate$1(updateExpr, curr, env, tracker)) yield* rec(next);
|
|
2437
|
+
}
|
|
2438
|
+
};
|
|
2439
|
+
yield* rec(input);
|
|
2440
|
+
}
|
|
2441
|
+
},
|
|
2442
|
+
{
|
|
2443
|
+
name: "until",
|
|
2444
|
+
arity: 2,
|
|
2445
|
+
apply: function* (input, args, env, tracker, evaluate$1, span) {
|
|
2446
|
+
const condExpr = args[0];
|
|
2447
|
+
const updateExpr = args[1];
|
|
2448
|
+
const rec = function* (curr) {
|
|
2449
|
+
tracker.step(span);
|
|
2450
|
+
let condMatches = false;
|
|
2451
|
+
for (const c of evaluate$1(condExpr, curr, env, tracker)) if (isTruthy(c)) {
|
|
2452
|
+
condMatches = true;
|
|
2453
|
+
break;
|
|
2454
|
+
}
|
|
2455
|
+
if (condMatches) yield emit$1(curr, span, tracker);
|
|
2456
|
+
else for (const next of evaluate$1(updateExpr, curr, env, tracker)) yield* rec(next);
|
|
2457
|
+
};
|
|
2458
|
+
yield* rec(input);
|
|
2459
|
+
}
|
|
2460
|
+
},
|
|
2461
|
+
{
|
|
2462
|
+
name: "repeat",
|
|
2463
|
+
arity: 1,
|
|
2464
|
+
apply: function* (input, args, env, tracker, evaluate$1, span) {
|
|
2465
|
+
while (true) {
|
|
2466
|
+
tracker.step(span);
|
|
2467
|
+
yield* evaluate$1(args[0], input, env, tracker);
|
|
2468
|
+
}
|
|
2469
|
+
}
|
|
2470
|
+
}
|
|
2471
|
+
];
|
|
2472
|
+
|
|
2473
|
+
//#endregion
|
|
2474
|
+
//#region src/eval/ops.ts
|
|
2475
|
+
/**
|
|
2476
|
+
* Applies a unary negation (`-`).
|
|
2477
|
+
*
|
|
2478
|
+
* @param value - The value to negate.
|
|
2479
|
+
* @param span - Source span for errors.
|
|
2480
|
+
* @returns The negated value.
|
|
2481
|
+
*/
|
|
2482
|
+
const applyUnaryNeg = (value, span) => {
|
|
2483
|
+
if (typeof value === "number") return -value;
|
|
2484
|
+
throw new RuntimeError(`Invalid operand for unary -: ${describeType(value)}`, span);
|
|
2485
|
+
};
|
|
2486
|
+
/**
|
|
2487
|
+
* Applies a binary operator.
|
|
2488
|
+
*
|
|
2489
|
+
* Supports arithmetic (`+`, `-`, `*`, `/`, `%`) and comparators.
|
|
2490
|
+
*
|
|
2491
|
+
* @param op - The operator string.
|
|
2492
|
+
* @param left - The left operand.
|
|
2493
|
+
* @param right - The right operand.
|
|
2494
|
+
* @param span - Source span for errors.
|
|
2495
|
+
* @returns The result of the operation.
|
|
2496
|
+
*/
|
|
2497
|
+
const applyBinaryOp = (op, left, right, span) => {
|
|
2498
|
+
switch (op) {
|
|
2499
|
+
case "+": return add(left, right, span);
|
|
2500
|
+
case "-": return sub(left, right, span);
|
|
2501
|
+
case "*": return mul(left, right, span);
|
|
2502
|
+
case "/": return div(left, right, span);
|
|
2503
|
+
case "%": return mod(left, right, span);
|
|
2504
|
+
case "Eq": return isEqual(left, right);
|
|
2505
|
+
case "Neq": return !isEqual(left, right);
|
|
2506
|
+
case "Lt": return compare(left, right) < 0;
|
|
2507
|
+
case "Lte": return compare(left, right) <= 0;
|
|
2508
|
+
case "Gt": return compare(left, right) > 0;
|
|
2509
|
+
case "Gte": return compare(left, right) >= 0;
|
|
2510
|
+
default: throw new RuntimeError(`Unknown binary operator: ${op}`, span);
|
|
2511
|
+
}
|
|
2512
|
+
};
|
|
2513
|
+
function isEqual(a, b) {
|
|
2514
|
+
if (a === b) return true;
|
|
2515
|
+
if (a === null || b === null) return false;
|
|
2516
|
+
if (typeof a !== typeof b) return false;
|
|
2517
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
2518
|
+
if (a.length !== b.length) return false;
|
|
2519
|
+
return a.every((v, i) => isEqual(v, b[i]));
|
|
2520
|
+
}
|
|
2521
|
+
if (isPlainObject$1(a) && isPlainObject$1(b)) {
|
|
2522
|
+
const ka = Object.keys(a).sort();
|
|
2523
|
+
const kb = Object.keys(b).sort();
|
|
2524
|
+
if (ka.length !== kb.length) return false;
|
|
2525
|
+
if (!ka.every((k, i) => k === kb[i])) return false;
|
|
2526
|
+
return ka.every((k) => isEqual(a[k], b[k]));
|
|
2527
|
+
}
|
|
2528
|
+
return false;
|
|
2529
|
+
}
|
|
2530
|
+
function compare(a, b) {
|
|
2531
|
+
if (a === b) return 0;
|
|
2532
|
+
const typeOrder = (v) => {
|
|
2533
|
+
if (v === null) return 0;
|
|
2534
|
+
if (typeof v === "boolean") return 1;
|
|
2535
|
+
if (typeof v === "number") return 2;
|
|
2536
|
+
if (typeof v === "string") return 3;
|
|
2537
|
+
if (Array.isArray(v)) return 4;
|
|
2538
|
+
if (isPlainObject$1(v)) return 5;
|
|
2539
|
+
return 6;
|
|
2540
|
+
};
|
|
2541
|
+
const ta = typeOrder(a);
|
|
2542
|
+
const tb = typeOrder(b);
|
|
2543
|
+
if (ta !== tb) return ta - tb;
|
|
2544
|
+
if (typeof a === "boolean" && typeof b === "boolean") return (a ? 1 : 0) - (b ? 1 : 0);
|
|
2545
|
+
if (typeof a === "number" && typeof b === "number") return a - b;
|
|
2546
|
+
if (typeof a === "string" && typeof b === "string") return a < b ? -1 : 1;
|
|
2547
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
2548
|
+
for (let i = 0; i < Math.min(a.length, b.length); i++) {
|
|
2549
|
+
const c = compare(a[i], b[i]);
|
|
2550
|
+
if (c !== 0) return c;
|
|
2551
|
+
}
|
|
2552
|
+
return a.length - b.length;
|
|
2112
2553
|
}
|
|
2113
|
-
|
|
2554
|
+
if (isPlainObject$1(a) && isPlainObject$1(b)) {
|
|
2555
|
+
const keysA = Object.keys(a).sort();
|
|
2556
|
+
const keysB = Object.keys(b).sort();
|
|
2557
|
+
for (let i = 0; i < Math.min(keysA.length, keysB.length); i++) {
|
|
2558
|
+
const kA = keysA[i];
|
|
2559
|
+
const kB = keysB[i];
|
|
2560
|
+
if (kA !== kB) return kA < kB ? -1 : 1;
|
|
2561
|
+
const c = compare(a[kA], b[kB]);
|
|
2562
|
+
if (c !== 0) return c;
|
|
2563
|
+
}
|
|
2564
|
+
return keysA.length - keysB.length;
|
|
2565
|
+
}
|
|
2566
|
+
return 0;
|
|
2567
|
+
}
|
|
2568
|
+
function add(left, right, span) {
|
|
2569
|
+
if (left === null && right === null) return null;
|
|
2570
|
+
if (left === null && typeof right === "number") return right;
|
|
2571
|
+
if (typeof left === "number" && right === null) return left;
|
|
2572
|
+
if (typeof left === "number" && typeof right === "number") return left + right;
|
|
2573
|
+
if (typeof left === "string" && typeof right === "string") return left + right;
|
|
2574
|
+
if (Array.isArray(left) && Array.isArray(right)) return [...left, ...right];
|
|
2575
|
+
if (isPlainObject$1(left) && isPlainObject$1(right)) return {
|
|
2576
|
+
...left,
|
|
2577
|
+
...right
|
|
2578
|
+
};
|
|
2579
|
+
throw new RuntimeError(`Cannot add ${describeType(left)} and ${describeType(right)}`, span);
|
|
2580
|
+
}
|
|
2581
|
+
function sub(left, right, span) {
|
|
2582
|
+
if (typeof left === "number" && typeof right === "number") return left - right;
|
|
2583
|
+
if (Array.isArray(left) && Array.isArray(right)) {
|
|
2584
|
+
const toRemove = new Set(right.map(stableStringify));
|
|
2585
|
+
return left.filter((x) => !toRemove.has(stableStringify(x)));
|
|
2586
|
+
}
|
|
2587
|
+
throw new RuntimeError(`Cannot subtract ${describeType(right)} from ${describeType(left)}`, span);
|
|
2588
|
+
}
|
|
2589
|
+
function mul(left, right, span) {
|
|
2590
|
+
if (typeof left === "number" && typeof right === "number") return left * right;
|
|
2591
|
+
if (typeof left === "string" && typeof right === "number") return repeatString(left, right);
|
|
2592
|
+
if (typeof left === "number" && typeof right === "string") return repeatString(right, left);
|
|
2593
|
+
if (isPlainObject$1(left) && isPlainObject$1(right)) return mergeDeep(left, right);
|
|
2594
|
+
throw new RuntimeError(`Cannot multiply ${describeType(left)} by ${describeType(right)}`, span);
|
|
2595
|
+
}
|
|
2596
|
+
function div(left, right, span) {
|
|
2597
|
+
if (typeof left === "number" && typeof right === "number") {
|
|
2598
|
+
if (right === 0) throw new RuntimeError("Division by zero", span);
|
|
2599
|
+
return left / right;
|
|
2600
|
+
}
|
|
2601
|
+
if (typeof left === "string" && typeof right === "string") return left.split(right);
|
|
2602
|
+
throw new RuntimeError(`Cannot divide ${describeType(left)} by ${describeType(right)}`, span);
|
|
2603
|
+
}
|
|
2604
|
+
function mod(left, right, span) {
|
|
2605
|
+
if (typeof left === "number" && typeof right === "number") {
|
|
2606
|
+
if (right === 0) throw new RuntimeError("Modulo by zero", span);
|
|
2607
|
+
return left % right;
|
|
2608
|
+
}
|
|
2609
|
+
throw new RuntimeError(`Cannot modulo ${describeType(left)} by ${describeType(right)}`, span);
|
|
2610
|
+
}
|
|
2611
|
+
function repeatString(str, count) {
|
|
2612
|
+
if (count <= 0) return null;
|
|
2613
|
+
const n = Math.floor(count);
|
|
2614
|
+
if (n <= 0) return null;
|
|
2615
|
+
return str.repeat(n);
|
|
2616
|
+
}
|
|
2617
|
+
function mergeDeep(target, source) {
|
|
2618
|
+
const result = { ...target };
|
|
2619
|
+
for (const key of Object.keys(source)) {
|
|
2620
|
+
const sVal = source[key];
|
|
2621
|
+
const tVal = result[key];
|
|
2622
|
+
if (isPlainObject$1(sVal) && tVal !== void 0 && isPlainObject$1(tVal)) result[key] = mergeDeep(tVal, sVal);
|
|
2623
|
+
else result[key] = sVal;
|
|
2624
|
+
}
|
|
2625
|
+
return result;
|
|
2626
|
+
}
|
|
2627
|
+
function isPlainObject$1(v) {
|
|
2628
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
2629
|
+
}
|
|
2114
2630
|
|
|
2115
2631
|
//#endregion
|
|
2116
2632
|
//#region src/builtins/math.ts
|
|
@@ -2295,6 +2811,23 @@ const mathBuiltins = [
|
|
|
2295
2811
|
}
|
|
2296
2812
|
yield emit$1(maxItem, span, tracker);
|
|
2297
2813
|
}
|
|
2814
|
+
},
|
|
2815
|
+
{
|
|
2816
|
+
name: "add",
|
|
2817
|
+
arity: 0,
|
|
2818
|
+
apply: function* (input, _args, _env, tracker, _eval, span) {
|
|
2819
|
+
if (!Array.isArray(input)) throw new RuntimeError("add expects an array", span);
|
|
2820
|
+
if (input.length === 0) {
|
|
2821
|
+
yield emit$1(null, span, tracker);
|
|
2822
|
+
return;
|
|
2823
|
+
}
|
|
2824
|
+
let acc = input[0];
|
|
2825
|
+
for (let i = 1; i < input.length; i++) {
|
|
2826
|
+
tracker.step(span);
|
|
2827
|
+
acc = add(acc, input[i], span);
|
|
2828
|
+
}
|
|
2829
|
+
yield emit$1(acc, span, tracker);
|
|
2830
|
+
}
|
|
2298
2831
|
}
|
|
2299
2832
|
];
|
|
2300
2833
|
|
|
@@ -2503,164 +3036,6 @@ var LimitTracker = class {
|
|
|
2503
3036
|
}
|
|
2504
3037
|
};
|
|
2505
3038
|
|
|
2506
|
-
//#endregion
|
|
2507
|
-
//#region src/eval/ops.ts
|
|
2508
|
-
/**
|
|
2509
|
-
* Applies a unary negation (`-`).
|
|
2510
|
-
*
|
|
2511
|
-
* @param value - The value to negate.
|
|
2512
|
-
* @param span - Source span for errors.
|
|
2513
|
-
* @returns The negated value.
|
|
2514
|
-
*/
|
|
2515
|
-
const applyUnaryNeg = (value, span) => {
|
|
2516
|
-
if (typeof value === "number") return -value;
|
|
2517
|
-
throw new RuntimeError(`Invalid operand for unary -: ${describeType(value)}`, span);
|
|
2518
|
-
};
|
|
2519
|
-
/**
|
|
2520
|
-
* Applies a binary operator.
|
|
2521
|
-
*
|
|
2522
|
-
* Supports arithmetic (`+`, `-`, `*`, `/`, `%`) and comparators.
|
|
2523
|
-
*
|
|
2524
|
-
* @param op - The operator string.
|
|
2525
|
-
* @param left - The left operand.
|
|
2526
|
-
* @param right - The right operand.
|
|
2527
|
-
* @param span - Source span for errors.
|
|
2528
|
-
* @returns The result of the operation.
|
|
2529
|
-
*/
|
|
2530
|
-
const applyBinaryOp = (op, left, right, span) => {
|
|
2531
|
-
switch (op) {
|
|
2532
|
-
case "+": return add(left, right, span);
|
|
2533
|
-
case "-": return sub(left, right, span);
|
|
2534
|
-
case "*": return mul(left, right, span);
|
|
2535
|
-
case "/": return div(left, right, span);
|
|
2536
|
-
case "%": return mod(left, right, span);
|
|
2537
|
-
case "Eq": return isEqual(left, right);
|
|
2538
|
-
case "Neq": return !isEqual(left, right);
|
|
2539
|
-
case "Lt": return compare(left, right) < 0;
|
|
2540
|
-
case "Lte": return compare(left, right) <= 0;
|
|
2541
|
-
case "Gt": return compare(left, right) > 0;
|
|
2542
|
-
case "Gte": return compare(left, right) >= 0;
|
|
2543
|
-
default: throw new RuntimeError(`Unknown binary operator: ${op}`, span);
|
|
2544
|
-
}
|
|
2545
|
-
};
|
|
2546
|
-
function isEqual(a, b) {
|
|
2547
|
-
if (a === b) return true;
|
|
2548
|
-
if (a === null || b === null) return false;
|
|
2549
|
-
if (typeof a !== typeof b) return false;
|
|
2550
|
-
if (Array.isArray(a) && Array.isArray(b)) {
|
|
2551
|
-
if (a.length !== b.length) return false;
|
|
2552
|
-
return a.every((v, i) => isEqual(v, b[i]));
|
|
2553
|
-
}
|
|
2554
|
-
if (isPlainObject$1(a) && isPlainObject$1(b)) {
|
|
2555
|
-
const ka = Object.keys(a).sort();
|
|
2556
|
-
const kb = Object.keys(b).sort();
|
|
2557
|
-
if (ka.length !== kb.length) return false;
|
|
2558
|
-
if (!ka.every((k, i) => k === kb[i])) return false;
|
|
2559
|
-
return ka.every((k) => isEqual(a[k], b[k]));
|
|
2560
|
-
}
|
|
2561
|
-
return false;
|
|
2562
|
-
}
|
|
2563
|
-
function compare(a, b) {
|
|
2564
|
-
if (a === b) return 0;
|
|
2565
|
-
const typeOrder = (v) => {
|
|
2566
|
-
if (v === null) return 0;
|
|
2567
|
-
if (typeof v === "boolean") return 1;
|
|
2568
|
-
if (typeof v === "number") return 2;
|
|
2569
|
-
if (typeof v === "string") return 3;
|
|
2570
|
-
if (Array.isArray(v)) return 4;
|
|
2571
|
-
if (isPlainObject$1(v)) return 5;
|
|
2572
|
-
return 6;
|
|
2573
|
-
};
|
|
2574
|
-
const ta = typeOrder(a);
|
|
2575
|
-
const tb = typeOrder(b);
|
|
2576
|
-
if (ta !== tb) return ta - tb;
|
|
2577
|
-
if (typeof a === "boolean" && typeof b === "boolean") return (a ? 1 : 0) - (b ? 1 : 0);
|
|
2578
|
-
if (typeof a === "number" && typeof b === "number") return a - b;
|
|
2579
|
-
if (typeof a === "string" && typeof b === "string") return a < b ? -1 : 1;
|
|
2580
|
-
if (Array.isArray(a) && Array.isArray(b)) {
|
|
2581
|
-
for (let i = 0; i < Math.min(a.length, b.length); i++) {
|
|
2582
|
-
const c = compare(a[i], b[i]);
|
|
2583
|
-
if (c !== 0) return c;
|
|
2584
|
-
}
|
|
2585
|
-
return a.length - b.length;
|
|
2586
|
-
}
|
|
2587
|
-
if (isPlainObject$1(a) && isPlainObject$1(b)) {
|
|
2588
|
-
const keysA = Object.keys(a).sort();
|
|
2589
|
-
const keysB = Object.keys(b).sort();
|
|
2590
|
-
for (let i = 0; i < Math.min(keysA.length, keysB.length); i++) {
|
|
2591
|
-
const kA = keysA[i];
|
|
2592
|
-
const kB = keysB[i];
|
|
2593
|
-
if (kA !== kB) return kA < kB ? -1 : 1;
|
|
2594
|
-
const c = compare(a[kA], b[kB]);
|
|
2595
|
-
if (c !== 0) return c;
|
|
2596
|
-
}
|
|
2597
|
-
return keysA.length - keysB.length;
|
|
2598
|
-
}
|
|
2599
|
-
return 0;
|
|
2600
|
-
}
|
|
2601
|
-
function add(left, right, span) {
|
|
2602
|
-
if (left === null && right === null) return null;
|
|
2603
|
-
if (left === null && typeof right === "number") return right;
|
|
2604
|
-
if (typeof left === "number" && right === null) return left;
|
|
2605
|
-
if (typeof left === "number" && typeof right === "number") return left + right;
|
|
2606
|
-
if (typeof left === "string" && typeof right === "string") return left + right;
|
|
2607
|
-
if (Array.isArray(left) && Array.isArray(right)) return [...left, ...right];
|
|
2608
|
-
if (isPlainObject$1(left) && isPlainObject$1(right)) return {
|
|
2609
|
-
...left,
|
|
2610
|
-
...right
|
|
2611
|
-
};
|
|
2612
|
-
throw new RuntimeError(`Cannot add ${describeType(left)} and ${describeType(right)}`, span);
|
|
2613
|
-
}
|
|
2614
|
-
function sub(left, right, span) {
|
|
2615
|
-
if (typeof left === "number" && typeof right === "number") return left - right;
|
|
2616
|
-
if (Array.isArray(left) && Array.isArray(right)) {
|
|
2617
|
-
const toRemove = new Set(right.map(stableStringify));
|
|
2618
|
-
return left.filter((x) => !toRemove.has(stableStringify(x)));
|
|
2619
|
-
}
|
|
2620
|
-
throw new RuntimeError(`Cannot subtract ${describeType(right)} from ${describeType(left)}`, span);
|
|
2621
|
-
}
|
|
2622
|
-
function mul(left, right, span) {
|
|
2623
|
-
if (typeof left === "number" && typeof right === "number") return left * right;
|
|
2624
|
-
if (typeof left === "string" && typeof right === "number") return repeatString(left, right);
|
|
2625
|
-
if (typeof left === "number" && typeof right === "string") return repeatString(right, left);
|
|
2626
|
-
if (isPlainObject$1(left) && isPlainObject$1(right)) return mergeDeep(left, right);
|
|
2627
|
-
throw new RuntimeError(`Cannot multiply ${describeType(left)} by ${describeType(right)}`, span);
|
|
2628
|
-
}
|
|
2629
|
-
function div(left, right, span) {
|
|
2630
|
-
if (typeof left === "number" && typeof right === "number") {
|
|
2631
|
-
if (right === 0) throw new RuntimeError("Division by zero", span);
|
|
2632
|
-
return left / right;
|
|
2633
|
-
}
|
|
2634
|
-
if (typeof left === "string" && typeof right === "string") return left.split(right);
|
|
2635
|
-
throw new RuntimeError(`Cannot divide ${describeType(left)} by ${describeType(right)}`, span);
|
|
2636
|
-
}
|
|
2637
|
-
function mod(left, right, span) {
|
|
2638
|
-
if (typeof left === "number" && typeof right === "number") {
|
|
2639
|
-
if (right === 0) throw new RuntimeError("Modulo by zero", span);
|
|
2640
|
-
return left % right;
|
|
2641
|
-
}
|
|
2642
|
-
throw new RuntimeError(`Cannot modulo ${describeType(left)} by ${describeType(right)}`, span);
|
|
2643
|
-
}
|
|
2644
|
-
function repeatString(str, count) {
|
|
2645
|
-
if (count <= 0) return null;
|
|
2646
|
-
const n = Math.floor(count);
|
|
2647
|
-
if (n <= 0) return null;
|
|
2648
|
-
return str.repeat(n);
|
|
2649
|
-
}
|
|
2650
|
-
function mergeDeep(target, source) {
|
|
2651
|
-
const result = { ...target };
|
|
2652
|
-
for (const key of Object.keys(source)) {
|
|
2653
|
-
const sVal = source[key];
|
|
2654
|
-
const tVal = result[key];
|
|
2655
|
-
if (isPlainObject$1(sVal) && tVal !== void 0 && isPlainObject$1(tVal)) result[key] = mergeDeep(tVal, sVal);
|
|
2656
|
-
else result[key] = sVal;
|
|
2657
|
-
}
|
|
2658
|
-
return result;
|
|
2659
|
-
}
|
|
2660
|
-
function isPlainObject$1(v) {
|
|
2661
|
-
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
2662
|
-
}
|
|
2663
|
-
|
|
2664
3039
|
//#endregion
|
|
2665
3040
|
//#region src/eval/env.ts
|
|
2666
3041
|
/**
|
|
@@ -2726,6 +3101,7 @@ const ensureInteger = (value, span) => {
|
|
|
2726
3101
|
*/
|
|
2727
3102
|
const evalAssignment = function* (node, input, env, tracker, evaluate$1) {
|
|
2728
3103
|
const paths = Array.from(evaluatePath(node.left, input, env, tracker, evaluate$1));
|
|
3104
|
+
paths.sort((a, b) => compareValues(a, b) * -1);
|
|
2729
3105
|
if (paths.length === 0) {
|
|
2730
3106
|
yield emit(input, node.span, tracker);
|
|
2731
3107
|
return;
|
|
@@ -2779,7 +3155,10 @@ function* applyUpdates(current, paths, index, op, rhsNode, contextInput, env, tr
|
|
|
2779
3155
|
newValues.push(res);
|
|
2780
3156
|
}
|
|
2781
3157
|
}
|
|
2782
|
-
if (newValues.length === 0)
|
|
3158
|
+
if (newValues.length === 0) {
|
|
3159
|
+
yield* applyUpdates(deletePaths(current, [path], rhsNode.span), paths, index + 1, op, rhsNode, contextInput, env, tracker, evaluate$1);
|
|
3160
|
+
return;
|
|
3161
|
+
}
|
|
2783
3162
|
for (const val of newValues) yield* applyUpdates(updatePath(current, path, () => val, rhsNode.span) ?? current, paths, index + 1, op, rhsNode, contextInput, env, tracker, evaluate$1);
|
|
2784
3163
|
}
|
|
2785
3164
|
|