squint-cljs 0.14.196 → 0.14.198
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/lib/cli.js +108 -108
- package/lib/cljs.pprint.js +252 -252
- package/lib/compiler.js +1314 -1320
- package/lib/compiler.node.js +40 -40
- package/lib/compiler.sci.js +1277 -1276
- package/lib/node.nrepl_server.js +29 -29
- package/lib/squint.core.umd.js +3 -3
- package/package.json +1 -1
- package/src/squint/core.js +340 -73
- package/src/squint/string.js +4 -0
- package/src/squint/test.js +166 -197
package/src/squint/core.js
CHANGED
|
@@ -20,6 +20,28 @@ function findKey(iter, tar, key) {
|
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
function isSortedMap(m) {
|
|
24
|
+
return m != null && m[SORTED_TAG] === true && m[TYPE_TAG] === MAP_TYPE;
|
|
25
|
+
}
|
|
26
|
+
function isMapLike(m) {
|
|
27
|
+
return (
|
|
28
|
+
m != null &&
|
|
29
|
+
typeof m === 'object' &&
|
|
30
|
+
(m.constructor === Object || m instanceof Map || m[TYPE_TAG] === MAP_TYPE)
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
function mapHas(m, k) {
|
|
34
|
+
return m instanceof Map || m[TYPE_TAG] === MAP_TYPE ? m.has(k) : has.call(m, k);
|
|
35
|
+
}
|
|
36
|
+
function mapGet(m, k) {
|
|
37
|
+
return m instanceof Map || m[TYPE_TAG] === MAP_TYPE ? m.get(k) : m[k];
|
|
38
|
+
}
|
|
39
|
+
function mapCount(m) {
|
|
40
|
+
return m instanceof Map || m[TYPE_TAG] === MAP_TYPE
|
|
41
|
+
? m.size
|
|
42
|
+
: Object.keys(m).length;
|
|
43
|
+
}
|
|
44
|
+
|
|
23
45
|
function dequal(foo, bar) {
|
|
24
46
|
// supports primitives, Array, Set, Map and plain objects
|
|
25
47
|
// like CLJS: does not support NaN
|
|
@@ -28,7 +50,21 @@ function dequal(foo, bar) {
|
|
|
28
50
|
if (foo == null) return bar == null;
|
|
29
51
|
var ctor, len, tmp;
|
|
30
52
|
|
|
53
|
+
// A sorted map compares by entries against any map type (object, Map, sorted).
|
|
54
|
+
const fooSorted = isSortedMap(foo);
|
|
55
|
+
if (fooSorted || isSortedMap(bar)) {
|
|
56
|
+
const sm = fooSorted ? foo : bar;
|
|
57
|
+
const other = sm === foo ? bar : foo;
|
|
58
|
+
if (!isMapLike(other) || mapCount(sm) !== mapCount(other)) return false;
|
|
59
|
+
for (const k of sm.keys()) {
|
|
60
|
+
if (!mapHas(other, k) || !dequal(sm.get(k), mapGet(other, k))) return false;
|
|
61
|
+
}
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
|
|
31
65
|
if (foo && bar && (ctor = foo.constructor) === bar.constructor) {
|
|
66
|
+
if (ctor === Date) return foo.getTime() === bar.getTime();
|
|
67
|
+
|
|
32
68
|
if (ctor === Array) {
|
|
33
69
|
if ((len = foo.length) === bar.length) {
|
|
34
70
|
while (len-- && dequal(foo[len], bar[len]));
|
|
@@ -219,7 +255,8 @@ function copyMeta(from, to) {
|
|
|
219
255
|
function copy(o) {
|
|
220
256
|
switch (typeConst(o)) {
|
|
221
257
|
case MAP_TYPE:
|
|
222
|
-
|
|
258
|
+
// new o.constructor(o) preserves a SortedMap; for a plain Map it is new Map(o)
|
|
259
|
+
return copyMeta(o, new o.constructor(o));
|
|
223
260
|
case SET_TYPE:
|
|
224
261
|
return copyMeta(o, new o.constructor(o));
|
|
225
262
|
case ARRAY_TYPE:
|
|
@@ -242,6 +279,14 @@ export function assoc(o, k, v, ...kvs) {
|
|
|
242
279
|
return ret;
|
|
243
280
|
}
|
|
244
281
|
|
|
282
|
+
// squint has no distinct hash-map or array-map type; both build a plain object.
|
|
283
|
+
export function hash_map(...kvs) {
|
|
284
|
+
if (kvs.length === 0) return {};
|
|
285
|
+
return assoc({}, ...kvs);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
export const array_map = hash_map;
|
|
289
|
+
|
|
245
290
|
const MAP_TYPE = 1;
|
|
246
291
|
const ARRAY_TYPE = 2;
|
|
247
292
|
const OBJECT_TYPE = 3;
|
|
@@ -251,16 +296,16 @@ const LAZY_ITERABLE_TYPE = 6;
|
|
|
251
296
|
|
|
252
297
|
// type tag set in each collection ctor, read by typeConst (DCE: no instanceof).
|
|
253
298
|
const TYPE_TAG = Symbol('squint.lang.type');
|
|
299
|
+
const SORTED_TAG = Symbol('squint.lang.sorted');
|
|
254
300
|
|
|
255
|
-
// @__NO_SIDE_EFFECTS__ lets
|
|
256
|
-
// or IApply fn shakes out (neither does alone). See doc/dev/dce.md.
|
|
301
|
+
// @__NO_SIDE_EFFECTS__ lets a bundler drop unused defclass/withApply calls; see doc/dev/dce.md
|
|
257
302
|
// @__NO_SIDE_EFFECTS__
|
|
258
303
|
function defclass(c) {
|
|
259
304
|
return c;
|
|
260
305
|
}
|
|
261
306
|
// @__NO_SIDE_EFFECTS__
|
|
262
307
|
function withApply(f, applyFn) {
|
|
263
|
-
f
|
|
308
|
+
f.squint$lang$variadic = applyFn;
|
|
264
309
|
return f;
|
|
265
310
|
}
|
|
266
311
|
|
|
@@ -392,17 +437,31 @@ function conj_BANG_set(o, rest) {
|
|
|
392
437
|
}
|
|
393
438
|
|
|
394
439
|
export function conj_BANG_(...xs) {
|
|
395
|
-
|
|
440
|
+
const n = xs.length;
|
|
441
|
+
if (n === 0) {
|
|
396
442
|
return vector();
|
|
397
443
|
}
|
|
398
444
|
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
let o = _o;
|
|
445
|
+
let o = xs[0];
|
|
402
446
|
if (o === null || o === undefined) {
|
|
403
447
|
o = [];
|
|
404
448
|
}
|
|
405
449
|
|
|
450
|
+
// Fast path for the common single-element conj! onto an array or set,
|
|
451
|
+
// avoiding the rest-array allocation and spread.
|
|
452
|
+
if (n === 2) {
|
|
453
|
+
switch (typeConst(o)) {
|
|
454
|
+
case ARRAY_TYPE:
|
|
455
|
+
o.push(xs[1]);
|
|
456
|
+
return o;
|
|
457
|
+
case SET_TYPE:
|
|
458
|
+
o.add(xs[1]);
|
|
459
|
+
return o;
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
const rest = xs.slice(1);
|
|
464
|
+
|
|
406
465
|
switch (typeConst(o)) {
|
|
407
466
|
case SET_TYPE:
|
|
408
467
|
conj_BANG_set(o, rest);
|
|
@@ -443,6 +502,8 @@ export function conj(...xs) {
|
|
|
443
502
|
}
|
|
444
503
|
|
|
445
504
|
const [_o, ...rest] = xs;
|
|
505
|
+
// (conj coll) with nothing to add returns coll unchanged, including nil.
|
|
506
|
+
if (rest.length === 0) return _o;
|
|
446
507
|
|
|
447
508
|
let o = _o;
|
|
448
509
|
if (o === null || o === undefined) {
|
|
@@ -452,7 +513,8 @@ export function conj(...xs) {
|
|
|
452
513
|
|
|
453
514
|
switch (typeConst(o)) {
|
|
454
515
|
case SET_TYPE:
|
|
455
|
-
|
|
516
|
+
// brand, not instanceof, so conj does not pin SortedSet
|
|
517
|
+
if (o[SORTED_TAG]) {
|
|
456
518
|
// prevent re-sorting of collection
|
|
457
519
|
return copyMeta(o, conj_BANG_set(new o.constructor(o), rest));
|
|
458
520
|
} else {
|
|
@@ -503,11 +565,15 @@ export function disj_BANG_(s, ...xs) {
|
|
|
503
565
|
|
|
504
566
|
export function disj(s, ...xs) {
|
|
505
567
|
if (s == null) return s;
|
|
506
|
-
|
|
568
|
+
// pass s itself (not a spread) so a SortedSet keeps its comparator
|
|
569
|
+
const s1 = new s.constructor(s);
|
|
507
570
|
return disj_BANG_(s1, ...xs);
|
|
508
571
|
}
|
|
509
572
|
|
|
510
573
|
export function contains_QMARK_(coll, v) {
|
|
574
|
+
if (typeof coll === 'string') {
|
|
575
|
+
return int_QMARK_(v) && v >= 0 && v < coll.length;
|
|
576
|
+
}
|
|
511
577
|
switch (typeConst(coll)) {
|
|
512
578
|
case SET_TYPE:
|
|
513
579
|
case MAP_TYPE:
|
|
@@ -530,19 +596,19 @@ export function dissoc_BANG_(m, ...ks) {
|
|
|
530
596
|
export function dissoc(m, ...ks) {
|
|
531
597
|
if (!m) return;
|
|
532
598
|
if (ks.length === 0) return m;
|
|
599
|
+
if (typeConst(m) === MAP_TYPE) {
|
|
600
|
+
let present = false;
|
|
601
|
+
for (const k of ks) if (m.has(k)) { present = true; break; }
|
|
602
|
+
if (!present) return m;
|
|
603
|
+
const m2 = copy(m);
|
|
604
|
+
for (const k of ks) m2.delete(k);
|
|
605
|
+
return m2;
|
|
606
|
+
}
|
|
607
|
+
let present = false;
|
|
608
|
+
for (const k of ks) if (k in m) { present = true; break; }
|
|
609
|
+
if (!present) return m;
|
|
533
610
|
const m2 = copy(m);
|
|
534
|
-
|
|
535
|
-
case MAP_TYPE:
|
|
536
|
-
for (const k of ks) {
|
|
537
|
-
m2.delete(k);
|
|
538
|
-
}
|
|
539
|
-
break;
|
|
540
|
-
default:
|
|
541
|
-
for (const k of ks) {
|
|
542
|
-
delete m2[k];
|
|
543
|
-
}
|
|
544
|
-
break;
|
|
545
|
-
}
|
|
611
|
+
for (const k of ks) delete m2[k];
|
|
546
612
|
return m2;
|
|
547
613
|
}
|
|
548
614
|
|
|
@@ -643,7 +709,11 @@ export function seq_QMARK_(x) {
|
|
|
643
709
|
return x != null && !!x[Symbol.iterator];
|
|
644
710
|
}
|
|
645
711
|
|
|
646
|
-
export
|
|
712
|
+
export function sequential_QMARK_(x) {
|
|
713
|
+
// vectors and lists are arrays; lazy seqs and cons carry the lazy brand.
|
|
714
|
+
// Sets, maps and strings are iterable but not sequential.
|
|
715
|
+
return Array.isArray(x) || x?.[TYPE_TAG] === LAZY_ITERABLE_TYPE;
|
|
716
|
+
}
|
|
647
717
|
|
|
648
718
|
export function seqable_QMARK_(x) {
|
|
649
719
|
return (
|
|
@@ -700,11 +770,17 @@ export const es6_iterator = _iterator;
|
|
|
700
770
|
|
|
701
771
|
export function seq(x) {
|
|
702
772
|
if (x == null) return x;
|
|
773
|
+
// a string seqs into its characters, like CLJS.
|
|
774
|
+
if (typeof x === 'string') return x.length ? [...x] : null;
|
|
703
775
|
const iter = iterable(x);
|
|
704
776
|
// return nil for terminal checking
|
|
705
777
|
if (iter.length === 0 || iter.size === 0) {
|
|
706
778
|
return null;
|
|
707
779
|
}
|
|
780
|
+
// a set is iterable but not sequential; materialize its elements.
|
|
781
|
+
if (iter instanceof Set || iter[TYPE_TAG] === SET_TYPE) {
|
|
782
|
+
return [...iter];
|
|
783
|
+
}
|
|
708
784
|
const _i = iter[Symbol.iterator]();
|
|
709
785
|
if (_i.next().done) return null;
|
|
710
786
|
return iter;
|
|
@@ -1019,6 +1095,7 @@ function mapChunks(coll, xf) {
|
|
|
1019
1095
|
export const Cons = defclass(
|
|
1020
1096
|
class Cons {
|
|
1021
1097
|
constructor(x, coll) {
|
|
1098
|
+
this[TYPE_TAG] = LAZY_ITERABLE_TYPE;
|
|
1022
1099
|
this.x = x;
|
|
1023
1100
|
this.coll = coll;
|
|
1024
1101
|
}
|
|
@@ -1351,6 +1428,19 @@ export function re_pattern(s) {
|
|
|
1351
1428
|
}
|
|
1352
1429
|
|
|
1353
1430
|
export function subvec(arr, start, end) {
|
|
1431
|
+
if (!isVectorArray(arr)) {
|
|
1432
|
+
throw new Error('subvec: argument must be a vector');
|
|
1433
|
+
}
|
|
1434
|
+
if (end === undefined) end = arr.length;
|
|
1435
|
+
if (start == null || end == null) {
|
|
1436
|
+
throw new Error('subvec: start and end must not be nil');
|
|
1437
|
+
}
|
|
1438
|
+
// CLJS coerces the indices with (int x) before bounds-checking.
|
|
1439
|
+
start = start | 0;
|
|
1440
|
+
end = end | 0;
|
|
1441
|
+
if (start < 0 || end < start || end > arr.length) {
|
|
1442
|
+
throw new Error('subvec: index out of bounds');
|
|
1443
|
+
}
|
|
1354
1444
|
return arr.slice(start, end);
|
|
1355
1445
|
}
|
|
1356
1446
|
|
|
@@ -1426,20 +1516,39 @@ export function set_QMARK_(x) {
|
|
|
1426
1516
|
return typeConst(x) === SET_TYPE;
|
|
1427
1517
|
}
|
|
1428
1518
|
|
|
1429
|
-
const IApply__apply = Symbol('IApply__apply');
|
|
1430
|
-
|
|
1431
1519
|
export function apply(f, ...args) {
|
|
1432
1520
|
f = __toFn(f);
|
|
1433
1521
|
const xs = args.slice(0, args.length - 1);
|
|
1434
|
-
const
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1522
|
+
const last = args[args.length - 1];
|
|
1523
|
+
// variadic impl hint; see doc/adr/0001
|
|
1524
|
+
const v = f.squint$lang$variadic;
|
|
1525
|
+
if (v) {
|
|
1526
|
+
// pull maxfa fixed args (bounded, lazy-safe); more left -> variadic, else fixed
|
|
1527
|
+
const maxfa = v.length - 1;
|
|
1528
|
+
const fixed = [];
|
|
1529
|
+
let i = 0, rest;
|
|
1530
|
+
for (; i < maxfa && i < xs.length; i++) fixed.push(xs[i]);
|
|
1531
|
+
if (i < maxfa) {
|
|
1532
|
+
let s = seq(last);
|
|
1533
|
+
for (; i < maxfa && s != null; i++) {
|
|
1534
|
+
fixed.push(first(s));
|
|
1535
|
+
s = next(s);
|
|
1536
|
+
}
|
|
1537
|
+
rest = s;
|
|
1538
|
+
} else {
|
|
1539
|
+
rest = i < xs.length ? concat1([xs.slice(i), last]) : last;
|
|
1540
|
+
}
|
|
1541
|
+
rest = rest == null ? null : seq(rest);
|
|
1542
|
+
if (rest == null) return f(...fixed);
|
|
1543
|
+
return v(...fixed, rest);
|
|
1438
1544
|
}
|
|
1439
|
-
return f(...xs, ...
|
|
1545
|
+
return f(...xs, ...iterable(last));
|
|
1440
1546
|
}
|
|
1441
1547
|
|
|
1442
1548
|
export function even_QMARK_(x) {
|
|
1549
|
+
if (!Number.isInteger(x)) {
|
|
1550
|
+
throw new Error(`Argument must be an integer: ${x}`);
|
|
1551
|
+
}
|
|
1443
1552
|
return x % 2 == 0;
|
|
1444
1553
|
}
|
|
1445
1554
|
|
|
@@ -1465,7 +1574,7 @@ class List extends Array {
|
|
|
1465
1574
|
}
|
|
1466
1575
|
|
|
1467
1576
|
export function list_QMARK_(x) {
|
|
1468
|
-
return
|
|
1577
|
+
return x?.[TYPE_TAG] === LIST_TYPE;
|
|
1469
1578
|
}
|
|
1470
1579
|
|
|
1471
1580
|
export function list(...args) {
|
|
@@ -1651,8 +1760,10 @@ export function partition_all(n, ...args) {
|
|
|
1651
1760
|
}
|
|
1652
1761
|
|
|
1653
1762
|
export function partition(n, ...args) {
|
|
1763
|
+
// pad stays undefined for arity 1 and 2: only arity 4 provides a pad, which
|
|
1764
|
+
// makes the final partial partition be emitted (padded when pad has elements).
|
|
1654
1765
|
let step = n,
|
|
1655
|
-
pad
|
|
1766
|
+
pad,
|
|
1656
1767
|
coll = args[0];
|
|
1657
1768
|
|
|
1658
1769
|
if (args.length === 2) {
|
|
@@ -1687,8 +1798,10 @@ function partitionInternal(n, step, pad, coll, all) {
|
|
|
1687
1798
|
if (p.length > 0) {
|
|
1688
1799
|
if (p.length === n || all) {
|
|
1689
1800
|
yield p;
|
|
1690
|
-
} else if (pad
|
|
1691
|
-
|
|
1801
|
+
} else if (pad !== undefined) {
|
|
1802
|
+
if (pad != null) {
|
|
1803
|
+
p.push(...[...iterable(pad)].slice(0, n - p.length));
|
|
1804
|
+
}
|
|
1692
1805
|
yield p;
|
|
1693
1806
|
}
|
|
1694
1807
|
}
|
|
@@ -1783,6 +1896,8 @@ export function empty(coll) {
|
|
|
1783
1896
|
}
|
|
1784
1897
|
|
|
1785
1898
|
export function merge(...args) {
|
|
1899
|
+
// with no truthy maps, return nil like CLJS `(when (some identity maps) ...)`.
|
|
1900
|
+
if (!args.some(truth_)) return null;
|
|
1786
1901
|
// if the first arg is nil we coerce it into a map.
|
|
1787
1902
|
const firstArg = args[0];
|
|
1788
1903
|
let obj;
|
|
@@ -1874,20 +1989,16 @@ export function repeat(...args) {
|
|
|
1874
1989
|
if (args.length == 0 || args.length > 2) {
|
|
1875
1990
|
throw new Error(`Invalid arity: ${args.length}`);
|
|
1876
1991
|
}
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
const [n, x] = args;
|
|
1888
|
-
for (var i = 0; i < n; i++) yield x;
|
|
1889
|
-
},
|
|
1890
|
-
};
|
|
1992
|
+
if (args.length == 1) {
|
|
1993
|
+
const x = args[0];
|
|
1994
|
+
return lazy(function* () {
|
|
1995
|
+
while (true) yield x;
|
|
1996
|
+
});
|
|
1997
|
+
}
|
|
1998
|
+
const [n, x] = args;
|
|
1999
|
+
return lazy(function* () {
|
|
2000
|
+
for (var i = 0; i < n; i++) yield x;
|
|
2001
|
+
});
|
|
1891
2002
|
}
|
|
1892
2003
|
|
|
1893
2004
|
export function ensure_reduced(x) {
|
|
@@ -1939,6 +2050,8 @@ export function take_last(n, coll) {
|
|
|
1939
2050
|
lastN[i % n] = x;
|
|
1940
2051
|
i++;
|
|
1941
2052
|
}
|
|
2053
|
+
// an empty or nil coll has no last n elements; return nil like CLJS.
|
|
2054
|
+
if (i === 0) return null;
|
|
1942
2055
|
if (i % n !== 0 && i >= n) {
|
|
1943
2056
|
return lastN.slice(i % n).concat(lastN.slice(0, i % n));
|
|
1944
2057
|
} else {
|
|
@@ -2116,14 +2229,14 @@ export function update_in(coll, path, f, ...args) {
|
|
|
2116
2229
|
return assoc_in(coll, path, f(get_in(coll, path), ...args));
|
|
2117
2230
|
}
|
|
2118
2231
|
|
|
2119
|
-
export function fnil(f,
|
|
2232
|
+
export function fnil(f, ...defaults) {
|
|
2120
2233
|
f = __toFn(f);
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
return f(a, ...xs, ...args);
|
|
2234
|
+
const n = defaults.length;
|
|
2235
|
+
return function (...args) {
|
|
2236
|
+
for (let i = 0; i < n; i++) {
|
|
2237
|
+
if (args[i] == null) args[i] = defaults[i];
|
|
2126
2238
|
}
|
|
2239
|
+
return f(...args);
|
|
2127
2240
|
};
|
|
2128
2241
|
}
|
|
2129
2242
|
|
|
@@ -2297,7 +2410,10 @@ export function repeatedly(n, f) {
|
|
|
2297
2410
|
n = undefined;
|
|
2298
2411
|
}
|
|
2299
2412
|
const res = _repeatedly(f);
|
|
2300
|
-
if (n) {
|
|
2413
|
+
if (n !== undefined) {
|
|
2414
|
+
if (typeof n !== 'number') {
|
|
2415
|
+
throw new Error('repeatedly: count must be a number, got: ' + str(n));
|
|
2416
|
+
}
|
|
2301
2417
|
return take(n, res);
|
|
2302
2418
|
} else {
|
|
2303
2419
|
return res;
|
|
@@ -2332,6 +2448,11 @@ export function frequencies(coll) {
|
|
|
2332
2448
|
// The lazy-seq macro emits `new LazySeq(() => body)`: a LazyIterable whose step
|
|
2333
2449
|
// evaluates the body thunk on first force and reads it unchunked.
|
|
2334
2450
|
export class LazySeq extends LazyIterable {
|
|
2451
|
+
// Core fns build the base LazyIterable, not this subclass, so widen
|
|
2452
|
+
// instanceof to any lazy cell for `(instance? LazySeq x)` parity with CLJS.
|
|
2453
|
+
static [Symbol.hasInstance](x) {
|
|
2454
|
+
return x instanceof LazyIterable;
|
|
2455
|
+
}
|
|
2335
2456
|
constructor(f) {
|
|
2336
2457
|
super(() => unchunkedSteps(es6_iterator(iterable(f())))());
|
|
2337
2458
|
}
|
|
@@ -2383,7 +2504,7 @@ export function some_QMARK_(x) {
|
|
|
2383
2504
|
}
|
|
2384
2505
|
|
|
2385
2506
|
export function boolean$(x) {
|
|
2386
|
-
return
|
|
2507
|
+
return truth_(x);
|
|
2387
2508
|
}
|
|
2388
2509
|
|
|
2389
2510
|
export function zero_QMARK_(x) {
|
|
@@ -2457,11 +2578,13 @@ export function aclone(arr) {
|
|
|
2457
2578
|
}
|
|
2458
2579
|
|
|
2459
2580
|
export function add_watch(ref, key, fn) {
|
|
2460
|
-
|
|
2581
|
+
ref._add_watch(key, fn);
|
|
2582
|
+
return ref;
|
|
2461
2583
|
}
|
|
2462
2584
|
|
|
2463
2585
|
export function remove_watch(ref, key) {
|
|
2464
|
-
|
|
2586
|
+
ref._remove_watch(key);
|
|
2587
|
+
return ref;
|
|
2465
2588
|
}
|
|
2466
2589
|
|
|
2467
2590
|
export function reduce_kv(f, init, m) {
|
|
@@ -2493,6 +2616,7 @@ export function map_QMARK_(coll) {
|
|
|
2493
2616
|
if (coll == null) return false;
|
|
2494
2617
|
if (isObj(coll)) return true;
|
|
2495
2618
|
if (coll instanceof Map) return true;
|
|
2619
|
+
if (coll[TYPE_TAG] === MAP_TYPE) return true;
|
|
2496
2620
|
return false;
|
|
2497
2621
|
}
|
|
2498
2622
|
|
|
@@ -2675,25 +2799,33 @@ export function keys(obj) {
|
|
|
2675
2799
|
if (obj == null) return;
|
|
2676
2800
|
const t = typeConst(obj);
|
|
2677
2801
|
switch (t) {
|
|
2678
|
-
case OBJECT_TYPE:
|
|
2679
|
-
|
|
2802
|
+
case OBJECT_TYPE: {
|
|
2803
|
+
const ks = Object.keys(obj);
|
|
2804
|
+
if (ks.length) return ks;
|
|
2805
|
+
return;
|
|
2806
|
+
}
|
|
2680
2807
|
case MAP_TYPE:
|
|
2681
|
-
return Array.from(obj.keys());
|
|
2808
|
+
if (obj.size) return Array.from(obj.keys());
|
|
2809
|
+
return;
|
|
2682
2810
|
}
|
|
2683
2811
|
}
|
|
2684
2812
|
|
|
2685
2813
|
export function js_keys(obj) {
|
|
2686
|
-
return keys(obj);
|
|
2814
|
+
return keys(obj) ?? [];
|
|
2687
2815
|
}
|
|
2688
2816
|
|
|
2689
2817
|
export function vals(obj) {
|
|
2690
2818
|
if (obj == null) return;
|
|
2691
2819
|
const t = typeConst(obj);
|
|
2692
2820
|
switch (t) {
|
|
2693
|
-
case OBJECT_TYPE:
|
|
2694
|
-
|
|
2821
|
+
case OBJECT_TYPE: {
|
|
2822
|
+
const vs = Object.values(obj);
|
|
2823
|
+
if (vs.length) return vs;
|
|
2824
|
+
return;
|
|
2825
|
+
}
|
|
2695
2826
|
case MAP_TYPE:
|
|
2696
|
-
return Array.from(obj.values());
|
|
2827
|
+
if (obj.size) return Array.from(obj.values());
|
|
2828
|
+
return;
|
|
2697
2829
|
}
|
|
2698
2830
|
}
|
|
2699
2831
|
|
|
@@ -2836,6 +2968,13 @@ export function with_meta(x, m) {
|
|
|
2836
2968
|
wrapped[_metaSym] = m;
|
|
2837
2969
|
return wrapped;
|
|
2838
2970
|
}
|
|
2971
|
+
// A lazy seq or cons is not copied element-wise: clone the head so the new
|
|
2972
|
+
// value carries its own metadata without forcing realization.
|
|
2973
|
+
if (x?.[TYPE_TAG] === LAZY_ITERABLE_TYPE) {
|
|
2974
|
+
const ret = Object.assign(Object.create(Object.getPrototypeOf(x)), x);
|
|
2975
|
+
ret[_metaSym] = m;
|
|
2976
|
+
return ret;
|
|
2977
|
+
}
|
|
2839
2978
|
const ret = copy(x);
|
|
2840
2979
|
ret[_metaSym] = m;
|
|
2841
2980
|
return ret;
|
|
@@ -3051,11 +3190,13 @@ export function persistent_BANG_(x) {
|
|
|
3051
3190
|
|
|
3052
3191
|
const SortedSet = defclass(
|
|
3053
3192
|
class SortedSet {
|
|
3054
|
-
constructor(xs) {
|
|
3193
|
+
constructor(xs, cmp) {
|
|
3055
3194
|
this[TYPE_TAG] = SET_TYPE;
|
|
3056
|
-
|
|
3195
|
+
this[SORTED_TAG] = true;
|
|
3196
|
+
this._cmp = cmp ?? xs?._cmp;
|
|
3197
|
+
const isSorted = xs instanceof SortedSet && xs._cmp === this._cmp;
|
|
3057
3198
|
if (!isSorted) {
|
|
3058
|
-
xs = sort(xs);
|
|
3199
|
+
xs = this._cmp ? sort(this._cmp, xs) : sort(xs);
|
|
3059
3200
|
}
|
|
3060
3201
|
const s = new Set(xs);
|
|
3061
3202
|
// we don't re-use xs since xs can contain duplicates
|
|
@@ -3065,9 +3206,10 @@ class SortedSet {
|
|
|
3065
3206
|
add(x) {
|
|
3066
3207
|
if (this._set.has(x)) return this;
|
|
3067
3208
|
const xs = this._elts;
|
|
3209
|
+
const cmp = this._cmp;
|
|
3068
3210
|
let added = false;
|
|
3069
3211
|
for (let i = 0; i < xs.length; i++) {
|
|
3070
|
-
if (compare(x, xs[i]) <= 0) {
|
|
3212
|
+
if ((cmp ? cmp(x, xs[i]) : compare(x, xs[i])) <= 0) {
|
|
3071
3213
|
xs.splice(i, 0, x);
|
|
3072
3214
|
added = true;
|
|
3073
3215
|
break;
|
|
@@ -3121,6 +3263,85 @@ export function sorted_set(...xs) {
|
|
|
3121
3263
|
return new SortedSet(xs);
|
|
3122
3264
|
}
|
|
3123
3265
|
|
|
3266
|
+
export function sorted_set_by(cmp, ...xs) {
|
|
3267
|
+
return new SortedSet(xs, fnToComparator(__toFn(cmp)));
|
|
3268
|
+
}
|
|
3269
|
+
|
|
3270
|
+
// A map that keeps its keys in sorted order. Backed by a sorted key array plus
|
|
3271
|
+
// a plain Map for lookup, and branded MAP_TYPE so map ops dispatch normally.
|
|
3272
|
+
const SortedMap = defclass(
|
|
3273
|
+
class SortedMap {
|
|
3274
|
+
constructor(entries, cmp) {
|
|
3275
|
+
this[TYPE_TAG] = MAP_TYPE;
|
|
3276
|
+
this[SORTED_TAG] = true;
|
|
3277
|
+
this._cmp = cmp ?? entries?._cmp;
|
|
3278
|
+
this._map = new Map();
|
|
3279
|
+
this._keys = [];
|
|
3280
|
+
this.size = 0;
|
|
3281
|
+
if (entries) {
|
|
3282
|
+
for (const [k, v] of entries) this.set(k, v);
|
|
3283
|
+
}
|
|
3284
|
+
}
|
|
3285
|
+
set(k, v) {
|
|
3286
|
+
if (!this._map.has(k)) {
|
|
3287
|
+
const ks = this._keys;
|
|
3288
|
+
const cmp = this._cmp;
|
|
3289
|
+
let i = 0;
|
|
3290
|
+
while (i < ks.length && (cmp ? cmp(k, ks[i]) : compare(k, ks[i])) > 0) i++;
|
|
3291
|
+
ks.splice(i, 0, k);
|
|
3292
|
+
}
|
|
3293
|
+
this._map.set(k, v);
|
|
3294
|
+
this.size = this._map.size;
|
|
3295
|
+
return this;
|
|
3296
|
+
}
|
|
3297
|
+
get(k) {
|
|
3298
|
+
return this._map.get(k);
|
|
3299
|
+
}
|
|
3300
|
+
has(k) {
|
|
3301
|
+
return this._map.has(k);
|
|
3302
|
+
}
|
|
3303
|
+
delete(k) {
|
|
3304
|
+
if (this._map.delete(k)) {
|
|
3305
|
+
this._keys.splice(this._keys.indexOf(k), 1);
|
|
3306
|
+
this.size = this._map.size;
|
|
3307
|
+
}
|
|
3308
|
+
return this;
|
|
3309
|
+
}
|
|
3310
|
+
*keys() {
|
|
3311
|
+
yield* this._keys;
|
|
3312
|
+
}
|
|
3313
|
+
*values() {
|
|
3314
|
+
for (const k of this._keys) yield this._map.get(k);
|
|
3315
|
+
}
|
|
3316
|
+
*entries() {
|
|
3317
|
+
for (const k of this._keys) yield [k, this._map.get(k)];
|
|
3318
|
+
}
|
|
3319
|
+
forEach(f) {
|
|
3320
|
+
for (const k of this._keys) f(this._map.get(k), k, this);
|
|
3321
|
+
}
|
|
3322
|
+
clear() {
|
|
3323
|
+
this._map.clear();
|
|
3324
|
+
this._keys = [];
|
|
3325
|
+
this.size = 0;
|
|
3326
|
+
}
|
|
3327
|
+
[Symbol.iterator]() {
|
|
3328
|
+
return this.entries();
|
|
3329
|
+
}
|
|
3330
|
+
}
|
|
3331
|
+
);
|
|
3332
|
+
|
|
3333
|
+
export function sorted_map(...kvs) {
|
|
3334
|
+
const m = new SortedMap();
|
|
3335
|
+
for (let i = 0; i < kvs.length; i += 2) m.set(kvs[i], kvs[i + 1]);
|
|
3336
|
+
return m;
|
|
3337
|
+
}
|
|
3338
|
+
|
|
3339
|
+
export function sorted_map_by(cmp, ...kvs) {
|
|
3340
|
+
const m = new SortedMap(null, fnToComparator(__toFn(cmp)));
|
|
3341
|
+
for (let i = 0; i < kvs.length; i += 2) m.set(kvs[i], kvs[i + 1]);
|
|
3342
|
+
return m;
|
|
3343
|
+
}
|
|
3344
|
+
|
|
3124
3345
|
function mkBoundFn(_sc, test, key) {
|
|
3125
3346
|
return (e) => {
|
|
3126
3347
|
return test(compare(e, key), 0);
|
|
@@ -3186,6 +3407,14 @@ export function long$(x) {
|
|
|
3186
3407
|
return fix(x);
|
|
3187
3408
|
}
|
|
3188
3409
|
|
|
3410
|
+
export function float$(x) {
|
|
3411
|
+
return x;
|
|
3412
|
+
}
|
|
3413
|
+
|
|
3414
|
+
export function double$(x) {
|
|
3415
|
+
return x;
|
|
3416
|
+
}
|
|
3417
|
+
|
|
3189
3418
|
export function type(x) {
|
|
3190
3419
|
return x != null && x.constructor;
|
|
3191
3420
|
}
|
|
@@ -3200,7 +3429,7 @@ function preserving_reduced(rf) {
|
|
|
3200
3429
|
}
|
|
3201
3430
|
|
|
3202
3431
|
export function cat(rf) {
|
|
3203
|
-
|
|
3432
|
+
const rrf = preserving_reduced(rf);
|
|
3204
3433
|
return (...args) => {
|
|
3205
3434
|
switch (args.length) {
|
|
3206
3435
|
case 0:
|
|
@@ -3208,7 +3437,7 @@ export function cat(rf) {
|
|
|
3208
3437
|
case 1:
|
|
3209
3438
|
return rf(args[0]);
|
|
3210
3439
|
case 2:
|
|
3211
|
-
return reduce(
|
|
3440
|
+
return reduce(rrf, args[0], args[1]);
|
|
3212
3441
|
}
|
|
3213
3442
|
};
|
|
3214
3443
|
}
|
|
@@ -3232,7 +3461,11 @@ export function memoize(f) {
|
|
|
3232
3461
|
}
|
|
3233
3462
|
|
|
3234
3463
|
export function peek(vec) {
|
|
3235
|
-
|
|
3464
|
+
// A list peeks at its front; squint lists are array-backed, so check list
|
|
3465
|
+
// before array to avoid returning the last element.
|
|
3466
|
+
if (list_QMARK_(vec)) {
|
|
3467
|
+
return first(vec);
|
|
3468
|
+
} else if (array_QMARK_(vec)) {
|
|
3236
3469
|
return vec[vec.length - 1];
|
|
3237
3470
|
} else {
|
|
3238
3471
|
return first(vec);
|
|
@@ -3240,7 +3473,12 @@ export function peek(vec) {
|
|
|
3240
3473
|
}
|
|
3241
3474
|
|
|
3242
3475
|
export function pop(vec) {
|
|
3243
|
-
if (
|
|
3476
|
+
if (vec == null) return null;
|
|
3477
|
+
if (list_QMARK_(vec)) {
|
|
3478
|
+
if (vec.length === 0) throw new Error("Can't pop empty list");
|
|
3479
|
+
return rest(vec);
|
|
3480
|
+
} else if (array_QMARK_(vec)) {
|
|
3481
|
+
if (vec.length === 0) throw new Error("Can't pop empty vector");
|
|
3244
3482
|
const ret = [...vec];
|
|
3245
3483
|
ret.pop();
|
|
3246
3484
|
return ret;
|
|
@@ -3279,6 +3517,27 @@ export function random_uuid() {
|
|
|
3279
3517
|
return crypto.randomUUID();
|
|
3280
3518
|
}
|
|
3281
3519
|
|
|
3520
|
+
export class UUID {
|
|
3521
|
+
constructor(uuid) {
|
|
3522
|
+
this.uuid = uuid;
|
|
3523
|
+
}
|
|
3524
|
+
toString() {
|
|
3525
|
+
return this.uuid;
|
|
3526
|
+
}
|
|
3527
|
+
}
|
|
3528
|
+
|
|
3529
|
+
export function uuid(s) {
|
|
3530
|
+
return new UUID(s);
|
|
3531
|
+
}
|
|
3532
|
+
|
|
3533
|
+
export function uuid_QMARK_(x) {
|
|
3534
|
+
return x instanceof UUID;
|
|
3535
|
+
}
|
|
3536
|
+
|
|
3537
|
+
export function inst_QMARK_(x) {
|
|
3538
|
+
return x instanceof Date;
|
|
3539
|
+
}
|
|
3540
|
+
|
|
3282
3541
|
export class Delay {
|
|
3283
3542
|
constructor(f) {
|
|
3284
3543
|
this.f = f;
|
|
@@ -3294,6 +3553,13 @@ export class Delay {
|
|
|
3294
3553
|
}
|
|
3295
3554
|
}
|
|
3296
3555
|
|
|
3556
|
+
export function realized_QMARK_(x) {
|
|
3557
|
+
if (x instanceof Delay || x instanceof LazyIterable) {
|
|
3558
|
+
return x.realized === true;
|
|
3559
|
+
}
|
|
3560
|
+
throw new Error('realized? not supported on: ' + str(x));
|
|
3561
|
+
}
|
|
3562
|
+
|
|
3297
3563
|
function clj__GT_js_(x, seen) {
|
|
3298
3564
|
// we need to protect against circular objects
|
|
3299
3565
|
if (seen.has(x)) return x;
|
|
@@ -3353,6 +3619,7 @@ function toEDN(value, seen = new WeakSet(), readably = true) {
|
|
|
3353
3619
|
if (typeof value === 'bigint') return `${value}N`;
|
|
3354
3620
|
|
|
3355
3621
|
if (typeof value === 'object') {
|
|
3622
|
+
if (value instanceof UUID) return readably ? `#uuid "${value.uuid}"` : value.uuid;
|
|
3356
3623
|
// seen tracks the current ancestor path only. A shared reference that
|
|
3357
3624
|
// appears under sibling branches is a DAG, not a cycle, so delete on exit.
|
|
3358
3625
|
if (seen.has(value)) return '#object[circular]';
|