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.
@@ -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
- return copyMeta(o, new Map(o));
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 bundlers drop unused calls, so a computed-key class
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[IApply__apply] = applyFn;
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
- if (xs.length === 0) {
440
+ const n = xs.length;
441
+ if (n === 0) {
396
442
  return vector();
397
443
  }
398
444
 
399
- const [_o, ...rest] = xs;
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
- if (o instanceof SortedSet) {
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
- const s1 = new s.constructor([...s]);
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
- switch (typeConst(m)) {
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 const sequential_QMARK_ = seq_QMARK_;
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 coll = iterable(args[args.length - 1]);
1435
- const af = f[IApply__apply];
1436
- if (af) {
1437
- return af(...xs, coll);
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, ...coll);
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 typeConst(x) === LIST_TYPE;
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.length) {
1691
- p.push(...pad.slice(0, n - p.length));
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
- return {
1879
- [IIterable]: true,
1880
- [IIterable__iterator]:
1881
- args.length == 1
1882
- ? function* () {
1883
- const x = args[0];
1884
- while (true) yield x;
1885
- }
1886
- : function* () {
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, x, ...xs) {
2232
+ export function fnil(f, ...defaults) {
2120
2233
  f = __toFn(f);
2121
- return function (a, ...args) {
2122
- if (!a) {
2123
- return f(x, ...xs, ...args);
2124
- } else {
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 !!x;
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
- return ref._add_watch(key, fn);
2581
+ ref._add_watch(key, fn);
2582
+ return ref;
2461
2583
  }
2462
2584
 
2463
2585
  export function remove_watch(ref, key) {
2464
- return ref._remove_watch(key);
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
- return Object.keys(obj);
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
- return Object.values(obj);
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
- const isSorted = xs instanceof SortedSet;
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
- rf = preserving_reduced(rf);
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(rf, args[0], args[1]);
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
- if (array_QMARK_(vec)) {
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 (array_QMARK_(vec)) {
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]';