squint-cljs 0.12.192 → 0.13.194
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/README.md +11 -56
- package/lib/cli.js +117 -45
- package/lib/cljs.pprint.js +265 -265
- package/lib/compiler.js +1356 -1324
- package/lib/compiler.node.js +39 -32
- package/lib/compiler.sci.js +1312 -1167
- package/lib/node.nrepl_server.js +29 -21
- package/lib/squint.core.umd.js +1 -1
- package/package.json +3 -1
- package/src/squint/core.js +647 -416
- package/src/squint/multi.js +10 -10
- package/src/squint/set.js +3 -3
- package/src/squint/string.js +20 -3
- package/src/squint/test.js +42 -42
- package/src/squint/walk.js +103 -0
- package/vite.js +34 -3
package/src/squint/core.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/*eslint no-unused-vars: ["error", { "varsIgnorePattern": "^_", "argsIgnorePattern": "^_", "destructuredArrayIgnorePattern": "^_"}]*/
|
|
2
2
|
|
|
3
|
-
// __toFn is not public API
|
|
3
|
+
// __toFn is not public API - the leading underscores mark it as an
|
|
4
4
|
// implementation helper shared with other squint runtime modules
|
|
5
5
|
// (e.g. multi.js). Signature and semantics may change without notice.
|
|
6
6
|
export function __toFn(x) {
|
|
@@ -24,6 +24,8 @@ function dequal(foo, bar) {
|
|
|
24
24
|
// supports primitives, Array, Set, Map and plain objects
|
|
25
25
|
// like CLJS: does not support NaN
|
|
26
26
|
if (foo === bar) return true;
|
|
27
|
+
// null and undefined are both nil in CLJS, so they compare equal
|
|
28
|
+
if (foo == null) return bar == null;
|
|
27
29
|
var ctor, len, tmp;
|
|
28
30
|
|
|
29
31
|
if (foo && bar && (ctor = foo.constructor) === bar.constructor) {
|
|
@@ -66,7 +68,9 @@ function dequal(foo, bar) {
|
|
|
66
68
|
return true;
|
|
67
69
|
}
|
|
68
70
|
|
|
69
|
-
|
|
71
|
+
// LazyIterable falls through to the sequential-equality path below; it is an
|
|
72
|
+
// object but must compare element-wise, not by enumerable properties
|
|
73
|
+
if ((!ctor || typeof foo === 'object') && !(foo instanceof LazyIterable)) {
|
|
70
74
|
len = 0;
|
|
71
75
|
for (const k in foo) {
|
|
72
76
|
if (has.call(foo, k) && ++len && !has.call(bar, k)) return false;
|
|
@@ -75,6 +79,26 @@ function dequal(foo, bar) {
|
|
|
75
79
|
return Object.keys(bar).length === len;
|
|
76
80
|
}
|
|
77
81
|
}
|
|
82
|
+
|
|
83
|
+
// Cross-type sequential equality, like CLJS `(= '(1 2) [1 2])`: vectors,
|
|
84
|
+
// lists and lazy seqs compare element-wise regardless of concrete type. Only
|
|
85
|
+
// reached when the same-constructor paths above did not apply, so equal-typed
|
|
86
|
+
// collections keep their fast paths.
|
|
87
|
+
if (
|
|
88
|
+
foo && bar &&
|
|
89
|
+
(Array.isArray(foo) || foo instanceof LazyIterable) &&
|
|
90
|
+
(Array.isArray(bar) || bar instanceof LazyIterable)
|
|
91
|
+
) {
|
|
92
|
+
const fi = foo[Symbol.iterator]();
|
|
93
|
+
const bi = bar[Symbol.iterator]();
|
|
94
|
+
while (true) {
|
|
95
|
+
const a = fi.next();
|
|
96
|
+
const b = bi.next();
|
|
97
|
+
if (a.done || b.done) return !!(a.done && b.done);
|
|
98
|
+
if (!dequal(a.value, b.value)) return false;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
78
102
|
return false;
|
|
79
103
|
}
|
|
80
104
|
// end inlined version of dequals
|
|
@@ -179,16 +203,31 @@ export function assoc_BANG_(m, k, v, ...kvs) {
|
|
|
179
203
|
return m;
|
|
180
204
|
}
|
|
181
205
|
|
|
206
|
+
const _metaSym = Symbol('meta');
|
|
207
|
+
|
|
208
|
+
// Copies metadata from `from` onto `to` (when present) and returns `to`. Used
|
|
209
|
+
// to make value-producing operations (copy, empty, conj, into) carry metadata
|
|
210
|
+
// like Clojure does, instead of dropping it on the freshly built structure.
|
|
211
|
+
// Kept branch-light for the hot path: reads an absent symbol property (cheap,
|
|
212
|
+
// no hidden-class change) and only writes when metadata is actually present.
|
|
213
|
+
function copyMeta(from, to) {
|
|
214
|
+
const m = from?.[_metaSym];
|
|
215
|
+
if (m !== undefined) to[_metaSym] = m;
|
|
216
|
+
return to;
|
|
217
|
+
}
|
|
218
|
+
|
|
182
219
|
function copy(o) {
|
|
183
220
|
switch (typeConst(o)) {
|
|
184
221
|
case MAP_TYPE:
|
|
185
|
-
return new Map(o);
|
|
222
|
+
return copyMeta(o, new Map(o));
|
|
186
223
|
case SET_TYPE:
|
|
187
|
-
return new o.constructor(o);
|
|
224
|
+
return copyMeta(o, new o.constructor(o));
|
|
188
225
|
case ARRAY_TYPE:
|
|
189
|
-
return [...o];
|
|
226
|
+
return copyMeta(o, [...o]);
|
|
190
227
|
case OBJECT_TYPE:
|
|
191
|
-
return { ...o };
|
|
228
|
+
return copyMeta(o, { ...o });
|
|
229
|
+
case LIST_TYPE:
|
|
230
|
+
return copyMeta(o, new List(...o));
|
|
192
231
|
default:
|
|
193
232
|
throw new Error(`Don't know how to copy object of type ${typeof o}.`);
|
|
194
233
|
}
|
|
@@ -399,14 +438,14 @@ export function conj(...xs) {
|
|
|
399
438
|
case SET_TYPE:
|
|
400
439
|
if (o instanceof SortedSet) {
|
|
401
440
|
// prevent re-sorting of collection
|
|
402
|
-
return conj_BANG_set(new o.constructor(o), rest);
|
|
441
|
+
return copyMeta(o, conj_BANG_set(new o.constructor(o), rest));
|
|
403
442
|
} else {
|
|
404
|
-
return new o.constructor([...o, ...rest]);
|
|
443
|
+
return copyMeta(o, new o.constructor([...o, ...rest]));
|
|
405
444
|
}
|
|
406
445
|
case LIST_TYPE:
|
|
407
|
-
return new List(...rest.reverse(), ...o);
|
|
446
|
+
return copyMeta(o, new List(...rest.reverse(), ...o));
|
|
408
447
|
case ARRAY_TYPE:
|
|
409
|
-
return [...o, ...rest];
|
|
448
|
+
return copyMeta(o, [...o, ...rest]);
|
|
410
449
|
case MAP_TYPE:
|
|
411
450
|
m = new Map(o);
|
|
412
451
|
for (const x of rest) {
|
|
@@ -417,7 +456,7 @@ export function conj(...xs) {
|
|
|
417
456
|
else m.set(x[0], x[1]);
|
|
418
457
|
}
|
|
419
458
|
|
|
420
|
-
return m;
|
|
459
|
+
return copyMeta(o, m);
|
|
421
460
|
case LAZY_ITERABLE_TYPE:
|
|
422
461
|
return lazy(function* () {
|
|
423
462
|
yield* rest;
|
|
@@ -431,7 +470,7 @@ export function conj(...xs) {
|
|
|
431
470
|
else o2[x[0]] = x[1];
|
|
432
471
|
}
|
|
433
472
|
|
|
434
|
-
return o2;
|
|
473
|
+
return copyMeta(o, o2);
|
|
435
474
|
default:
|
|
436
475
|
throw new Error(
|
|
437
476
|
'Illegal argument: conj expects a Set, Array, List, Map, or Object as the first argument.'
|
|
@@ -447,6 +486,7 @@ export function disj_BANG_(s, ...xs) {
|
|
|
447
486
|
}
|
|
448
487
|
|
|
449
488
|
export function disj(s, ...xs) {
|
|
489
|
+
if (s == null) return s;
|
|
450
490
|
const s1 = new s.constructor([...s]);
|
|
451
491
|
return disj_BANG_(s1, ...xs);
|
|
452
492
|
}
|
|
@@ -503,25 +543,29 @@ export function println(...args) {
|
|
|
503
543
|
}
|
|
504
544
|
|
|
505
545
|
export function nth(coll, idx, orElse) {
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
if (i++ == idx) {
|
|
515
|
-
elt = value;
|
|
516
|
-
break;
|
|
517
|
-
}
|
|
518
|
-
}
|
|
546
|
+
const hasDefault = arguments.length > 2;
|
|
547
|
+
// nil coll puns to nil, like Clojure
|
|
548
|
+
if (coll == null) return hasDefault ? orElse : null;
|
|
549
|
+
// "found" is decided by the index bound, not the value. An in-bounds element
|
|
550
|
+
// that happens to be undefined is still found.
|
|
551
|
+
if (Array.isArray(coll)) {
|
|
552
|
+
if (idx >= 0 && idx < coll.length) {
|
|
553
|
+
return coll[idx];
|
|
519
554
|
}
|
|
520
|
-
|
|
521
|
-
|
|
555
|
+
} else if (idx >= 0) {
|
|
556
|
+
// non-array: skip whole chunks instead of counting elements (handles
|
|
557
|
+
// infinite seqs since it stops once idx is reached)
|
|
558
|
+
const next = chunkCursor(coll);
|
|
559
|
+
let base = 0;
|
|
560
|
+
let ch;
|
|
561
|
+
while ((ch = next()) !== null) {
|
|
562
|
+
if (idx < base + ch.length) return ch[idx - base];
|
|
563
|
+
base += ch.length;
|
|
522
564
|
}
|
|
523
565
|
}
|
|
524
|
-
return
|
|
566
|
+
// out of bounds. With a default return it, otherwise throw like Clojure
|
|
567
|
+
if (hasDefault) return orElse;
|
|
568
|
+
throw new Error('Index out of bounds: ' + idx);
|
|
525
569
|
}
|
|
526
570
|
|
|
527
571
|
export function get(coll, key, otherwise = undefined) {
|
|
@@ -576,21 +620,42 @@ export function seqable_QMARK_(x) {
|
|
|
576
620
|
return (
|
|
577
621
|
x === null ||
|
|
578
622
|
x === undefined ||
|
|
623
|
+
// plain objects (squint maps) are seqable via Object.entries in `iterable`,
|
|
624
|
+
// even though they lack Symbol.iterator.
|
|
625
|
+
object_QMARK_(x) ||
|
|
579
626
|
// we used to check instanceof Object but this returns false for TC39 Records
|
|
580
627
|
// also we used to write `Symbol.iterator in` but this does not work for strings and some other types
|
|
581
628
|
!!x[Symbol.iterator]
|
|
582
629
|
);
|
|
583
630
|
}
|
|
584
631
|
|
|
632
|
+
// squint has no distinct MapEntry type (map entries are plain 2-element
|
|
633
|
+
// arrays). We tag entries produced from a map with this marker symbol so
|
|
634
|
+
// map-entry? can tell them apart from ordinary vectors. Symbol-keyed props are
|
|
635
|
+
// invisible to =, into, iteration and JSON, so the effect is contained.
|
|
636
|
+
const MAP_ENTRY = Symbol('squint.lang.map-entry');
|
|
637
|
+
|
|
638
|
+
function tagMapEntry(e) {
|
|
639
|
+
e[MAP_ENTRY] = true;
|
|
640
|
+
return e;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
export function map_entry_QMARK_(x) {
|
|
644
|
+
return Array.isArray(x) && x[MAP_ENTRY] === true;
|
|
645
|
+
}
|
|
646
|
+
|
|
585
647
|
export function iterable(x) {
|
|
586
648
|
// nil puns to empty iterable, support passing nil to first/rest/reduce, etc.
|
|
587
649
|
if (x === null || x === undefined) {
|
|
588
650
|
return [];
|
|
589
651
|
}
|
|
590
|
-
|
|
652
|
+
// fast path: anything with Symbol.iterator (arrays, strings, sets, maps,
|
|
653
|
+
// lazy seqs). Inlined rather than calling seqable?, which also reports plain
|
|
654
|
+
// objects as seqable; those are handled by the Object.entries branch below.
|
|
655
|
+
if (x[Symbol.iterator]) {
|
|
591
656
|
return x;
|
|
592
657
|
}
|
|
593
|
-
if (x instanceof Object) return Object.entries(x);
|
|
658
|
+
if (x instanceof Object) return Object.entries(x).map(tagMapEntry);
|
|
594
659
|
throw new TypeError(`${x} is not iterable`);
|
|
595
660
|
}
|
|
596
661
|
|
|
@@ -617,12 +682,24 @@ export function seq(x) {
|
|
|
617
682
|
}
|
|
618
683
|
|
|
619
684
|
export function first(coll) {
|
|
685
|
+
if (coll == null) return undefined;
|
|
686
|
+
if (Array.isArray(coll)) return coll[0];
|
|
687
|
+
if (coll instanceof LazyIterable) {
|
|
688
|
+
coll.force();
|
|
689
|
+
return coll.chunk === null ? undefined : coll.chunk[0];
|
|
690
|
+
}
|
|
620
691
|
// destructuring uses iterable protocol
|
|
621
692
|
const [first] = iterable(coll);
|
|
622
693
|
return first;
|
|
623
694
|
}
|
|
624
695
|
|
|
625
696
|
export function second(coll) {
|
|
697
|
+
if (coll instanceof LazyIterable) {
|
|
698
|
+
coll.force();
|
|
699
|
+
const ch = coll.chunk;
|
|
700
|
+
if (ch === null) return undefined;
|
|
701
|
+
return ch.length > 1 ? ch[1] : first(coll._rest);
|
|
702
|
+
}
|
|
626
703
|
const [_, v] = iterable(coll);
|
|
627
704
|
return v;
|
|
628
705
|
}
|
|
@@ -632,13 +709,20 @@ export function ffirst(coll) {
|
|
|
632
709
|
}
|
|
633
710
|
|
|
634
711
|
export function rest(coll) {
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
712
|
+
// chunk-aware: drop the first element of the first chunk, keep the rest of
|
|
713
|
+
// the chain chunked (preserves chunkedness, unlike re-iterating element-wise)
|
|
714
|
+
const cell = chunkCells(coll);
|
|
715
|
+
cell.force();
|
|
716
|
+
const ch = cell.chunk;
|
|
717
|
+
if (ch === null) return cell; // (rest ()) is ()
|
|
718
|
+
if (ch.length > 1) {
|
|
719
|
+
const c = new LazyIterable(null);
|
|
720
|
+
c.realized = true;
|
|
721
|
+
c.chunk = ch.slice(1);
|
|
722
|
+
c._rest = cell._rest;
|
|
723
|
+
return c;
|
|
724
|
+
}
|
|
725
|
+
return cell._rest; // first chunk had one element; the next cell is the rest
|
|
642
726
|
}
|
|
643
727
|
|
|
644
728
|
class Reduced {
|
|
@@ -653,16 +737,15 @@ class Reduced {
|
|
|
653
737
|
|
|
654
738
|
export function last(coll) {
|
|
655
739
|
coll = iterable(coll);
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
case ARRAY_TYPE:
|
|
659
|
-
return coll[coll.length - 1];
|
|
660
|
-
default:
|
|
661
|
-
for (const x of coll) {
|
|
662
|
-
lastEl = x;
|
|
663
|
-
}
|
|
664
|
-
return lastEl;
|
|
740
|
+
if (Array.isArray(coll)) {
|
|
741
|
+
return coll[coll.length - 1];
|
|
665
742
|
}
|
|
743
|
+
// non-array: walk chunks, keep the last chunk's last element
|
|
744
|
+
const next = chunkCursor(coll);
|
|
745
|
+
let lastEl;
|
|
746
|
+
let ch;
|
|
747
|
+
while ((ch = next()) !== null) lastEl = ch[ch.length - 1];
|
|
748
|
+
return lastEl;
|
|
666
749
|
}
|
|
667
750
|
|
|
668
751
|
export function reduced(x) {
|
|
@@ -675,31 +758,43 @@ export function reduced_QMARK_(x) {
|
|
|
675
758
|
|
|
676
759
|
export function reduce(f, arg1, arg2) {
|
|
677
760
|
f = __toFn(f);
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
761
|
+
const hasInit = arguments.length !== 2;
|
|
762
|
+
const coll = hasInit ? arg2 : arg1;
|
|
763
|
+
let val = hasInit ? arg1 : undefined;
|
|
764
|
+
|
|
765
|
+
// fast path: index loop over an array
|
|
766
|
+
if (Array.isArray(coll)) {
|
|
767
|
+
let i = 0;
|
|
768
|
+
if (!hasInit) {
|
|
769
|
+
if (coll.length === 0) return f();
|
|
770
|
+
val = coll[0];
|
|
771
|
+
i = 1;
|
|
687
772
|
}
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
773
|
+
if (val instanceof Reduced) return val.value;
|
|
774
|
+
for (; i < coll.length; i++) {
|
|
775
|
+
val = f(val, coll[i]);
|
|
776
|
+
if (val instanceof Reduced) return val.value;
|
|
777
|
+
}
|
|
778
|
+
return val;
|
|
693
779
|
}
|
|
694
|
-
|
|
695
|
-
|
|
780
|
+
|
|
781
|
+
// non-array: walk chunks (chunked cell or any other seqable)
|
|
782
|
+
const next = chunkCursor(coll);
|
|
783
|
+
let ch = next();
|
|
784
|
+
let i = 0;
|
|
785
|
+
if (!hasInit) {
|
|
786
|
+
if (ch === null) return f();
|
|
787
|
+
val = ch[0];
|
|
788
|
+
i = 1;
|
|
696
789
|
}
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
val = val
|
|
701
|
-
|
|
790
|
+
if (val instanceof Reduced) return val.value;
|
|
791
|
+
while (ch !== null) {
|
|
792
|
+
for (; i < ch.length; i++) {
|
|
793
|
+
val = f(val, ch[i]);
|
|
794
|
+
if (val instanceof Reduced) return val.value;
|
|
702
795
|
}
|
|
796
|
+
ch = next();
|
|
797
|
+
i = 0;
|
|
703
798
|
}
|
|
704
799
|
return val;
|
|
705
800
|
}
|
|
@@ -732,42 +827,152 @@ function* _reductions3(f, init, coll) {
|
|
|
732
827
|
export function reductions(f, arg1, arg2) {
|
|
733
828
|
f = __toFn(f);
|
|
734
829
|
if (arguments.length === 2) {
|
|
830
|
+
const it = es6_iterator(iterable(arg1));
|
|
735
831
|
return lazy(function* () {
|
|
736
|
-
yield* _reductions2(f,
|
|
832
|
+
yield* _reductions2(f, it);
|
|
737
833
|
});
|
|
738
834
|
}
|
|
835
|
+
const it = es6_iterator(iterable(arg2));
|
|
739
836
|
return lazy(function* () {
|
|
740
|
-
yield* _reductions3(f, arg1,
|
|
837
|
+
yield* _reductions3(f, arg1, it);
|
|
741
838
|
});
|
|
742
839
|
}
|
|
743
840
|
|
|
744
|
-
|
|
841
|
+
// Deprecated: lazy values are now cached, so reuse no longer recomputes. Kept
|
|
842
|
+
// for API compatibility; remove in a future release.
|
|
745
843
|
export function warn_on_lazy_reusage_BANG_() {
|
|
746
|
-
|
|
844
|
+
console.warn(
|
|
845
|
+
'warn-on-lazy-reusage! is deprecated and does nothing: lazy values are now cached.',
|
|
846
|
+
);
|
|
747
847
|
}
|
|
748
848
|
|
|
849
|
+
const CHUNK_SIZE = 32;
|
|
850
|
+
|
|
851
|
+
// One cell of a self-caching chunked seq. `step` is a thunk returning
|
|
852
|
+
// [nonEmptyChunkArray, nextStep] or null at the end. See doc/dev/lazy-seqs.md.
|
|
749
853
|
class LazyIterable {
|
|
750
|
-
constructor(
|
|
751
|
-
this.
|
|
752
|
-
this.
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
854
|
+
constructor(step) {
|
|
855
|
+
this.step = step;
|
|
856
|
+
this.realized = false;
|
|
857
|
+
this.chunk = null; // array, or null when this is the terminal (empty) cell
|
|
858
|
+
this._rest = null;
|
|
859
|
+
}
|
|
860
|
+
force() {
|
|
861
|
+
if (!this.realized) {
|
|
862
|
+
this.realized = true;
|
|
863
|
+
const r = this.step();
|
|
864
|
+
this.step = null;
|
|
865
|
+
if (r !== null && r !== undefined) {
|
|
866
|
+
this.chunk = r[0];
|
|
867
|
+
this._rest = new LazyIterable(r[1]);
|
|
761
868
|
}
|
|
762
869
|
}
|
|
763
|
-
return this
|
|
870
|
+
return this;
|
|
871
|
+
}
|
|
872
|
+
[Symbol.iterator]() {
|
|
873
|
+
let cell = this;
|
|
874
|
+
let i = 0;
|
|
875
|
+
return {
|
|
876
|
+
next() {
|
|
877
|
+
for (;;) {
|
|
878
|
+
cell.force();
|
|
879
|
+
const ch = cell.chunk;
|
|
880
|
+
if (ch === null) return { value: undefined, done: true };
|
|
881
|
+
if (i < ch.length) return { value: ch[i++], done: false };
|
|
882
|
+
cell = cell._rest;
|
|
883
|
+
i = 0;
|
|
884
|
+
}
|
|
885
|
+
},
|
|
886
|
+
[Symbol.iterator]() {
|
|
887
|
+
return this;
|
|
888
|
+
},
|
|
889
|
+
};
|
|
764
890
|
}
|
|
765
891
|
}
|
|
766
892
|
|
|
767
893
|
LazyIterable.prototype[IIterable] = true; // Closure compatibility
|
|
768
894
|
|
|
895
|
+
// One-element chunks: an unchunked seq, realized one element at a time.
|
|
896
|
+
function unchunkedSteps(iter) {
|
|
897
|
+
const step = () => {
|
|
898
|
+
const r = iter.next();
|
|
899
|
+
return r.done ? null : [[r.value], step];
|
|
900
|
+
};
|
|
901
|
+
return step;
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
// f is a zero-arg generator function; its result is an unchunked lazy seq.
|
|
769
905
|
export function lazy(f) {
|
|
770
|
-
return new LazyIterable(f);
|
|
906
|
+
return new LazyIterable(unchunkedSteps(f()));
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
// gen(it) over a hoisted iterator: keeps the input head unpinned (streaming)
|
|
910
|
+
function lazyIter(coll, gen) {
|
|
911
|
+
const it = es6_iterator(iterable(coll));
|
|
912
|
+
return lazy(() => gen(it));
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
// A chunked view of any seqable for chunk-aware ops, preserving chunkedness:
|
|
916
|
+
// cells pass through, arrays slice into CHUNK_SIZE batches, others stay unchunked.
|
|
917
|
+
function chunkCells(coll) {
|
|
918
|
+
if (coll instanceof LazyIterable) return coll;
|
|
919
|
+
if (Array.isArray(coll)) {
|
|
920
|
+
const step = (pos) => () => {
|
|
921
|
+
if (pos >= coll.length) return null;
|
|
922
|
+
const end = Math.min(pos + CHUNK_SIZE, coll.length);
|
|
923
|
+
return [coll.slice(pos, end), step(end)];
|
|
924
|
+
};
|
|
925
|
+
return new LazyIterable(step(0));
|
|
926
|
+
}
|
|
927
|
+
return new LazyIterable(unchunkedSteps(es6_iterator(iterable(coll))));
|
|
928
|
+
}
|
|
929
|
+
|
|
930
|
+
// A cursor over a seq's chunks for realizers: returns a function yielding the
|
|
931
|
+
// next chunk array or null. Drive it with an inline loop (keeps an accumulator a
|
|
932
|
+
// plain local, unlike a callback). Callers keep their own array shortcut.
|
|
933
|
+
function chunkCursor(coll) {
|
|
934
|
+
if (coll instanceof LazyIterable) {
|
|
935
|
+
let cell = coll;
|
|
936
|
+
return () => {
|
|
937
|
+
if (cell === null) return null;
|
|
938
|
+
cell.force();
|
|
939
|
+
const ch = cell.chunk;
|
|
940
|
+
cell = ch === null ? null : cell._rest;
|
|
941
|
+
return ch;
|
|
942
|
+
};
|
|
943
|
+
}
|
|
944
|
+
const it = es6_iterator(iterable(coll));
|
|
945
|
+
return () => {
|
|
946
|
+
const b = [];
|
|
947
|
+
for (let i = 0; i < CHUNK_SIZE; i++) {
|
|
948
|
+
const r = it.next();
|
|
949
|
+
if (r.done) break;
|
|
950
|
+
b.push(r.value);
|
|
951
|
+
}
|
|
952
|
+
return b.length === 0 ? null : b;
|
|
953
|
+
};
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
// Build a lazy seq transforming each input chunk via xf(chunk, baseIndex) -> new
|
|
957
|
+
// chunk array, preserving chunkedness. Empty results are skipped (e.g. filter).
|
|
958
|
+
// baseIndex is the input element count before the chunk, for indexed ops.
|
|
959
|
+
function mapChunks(coll, xf) {
|
|
960
|
+
const src = chunkCells(coll);
|
|
961
|
+
const step = (cell, base) => () => {
|
|
962
|
+
let c = cell;
|
|
963
|
+
let b = base;
|
|
964
|
+
for (;;) {
|
|
965
|
+
c.force();
|
|
966
|
+
const ch = c.chunk;
|
|
967
|
+
if (ch === null) return null;
|
|
968
|
+
const out = xf(ch, b);
|
|
969
|
+
const rest = c._rest;
|
|
970
|
+
b += ch.length;
|
|
971
|
+
if (out.length !== 0) return [out, step(rest, b)];
|
|
972
|
+
c = rest;
|
|
973
|
+
}
|
|
974
|
+
};
|
|
975
|
+
return new LazyIterable(step(src, 0));
|
|
771
976
|
}
|
|
772
977
|
|
|
773
978
|
export class Cons {
|
|
@@ -775,24 +980,35 @@ export class Cons {
|
|
|
775
980
|
this.x = x;
|
|
776
981
|
this.coll = coll;
|
|
777
982
|
}
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
983
|
+
[Symbol.iterator]() {
|
|
984
|
+
const x = this.x;
|
|
985
|
+
let coll = this.coll;
|
|
986
|
+
let started = false;
|
|
987
|
+
let it = null;
|
|
988
|
+
return {
|
|
989
|
+
next() {
|
|
990
|
+
if (!started) {
|
|
991
|
+
started = true;
|
|
992
|
+
return { value: x, done: false };
|
|
993
|
+
}
|
|
994
|
+
if (!it) {
|
|
995
|
+
it = es6_iterator(iterable(coll));
|
|
996
|
+
coll = null; // release the tail head so a single pass streams
|
|
997
|
+
}
|
|
998
|
+
return it.next();
|
|
999
|
+
},
|
|
1000
|
+
[Symbol.iterator]() {
|
|
1001
|
+
return this;
|
|
1002
|
+
},
|
|
1003
|
+
};
|
|
781
1004
|
}
|
|
782
1005
|
}
|
|
783
1006
|
|
|
784
1007
|
export function cons(x, coll) {
|
|
785
1008
|
return new Cons(x, coll);
|
|
786
|
-
// return lazy(function* () {
|
|
787
|
-
// yield x;
|
|
788
|
-
// yield* iterable(coll);
|
|
789
|
-
// });
|
|
790
1009
|
}
|
|
791
1010
|
|
|
792
1011
|
export function map(f, ...colls) {
|
|
793
|
-
// if (! (f instanceof Function)) {
|
|
794
|
-
// throw new Error(`Argument f must be a function but is ${typeof(f)}`);
|
|
795
|
-
// }
|
|
796
1012
|
f = __toFn(f);
|
|
797
1013
|
switch (colls.length) {
|
|
798
1014
|
case 0:
|
|
@@ -815,14 +1031,14 @@ export function map(f, ...colls) {
|
|
|
815
1031
|
};
|
|
816
1032
|
};
|
|
817
1033
|
case 1:
|
|
818
|
-
return
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
1034
|
+
return mapChunks(colls[0], (ch) => {
|
|
1035
|
+
const out = new Array(ch.length);
|
|
1036
|
+
for (let i = 0; i < ch.length; i++) out[i] = f(ch[i]);
|
|
1037
|
+
return out;
|
|
822
1038
|
});
|
|
823
|
-
default:
|
|
1039
|
+
default: {
|
|
1040
|
+
const iters = colls.map((coll) => es6_iterator(iterable(coll)));
|
|
824
1041
|
return lazy(function* () {
|
|
825
|
-
const iters = colls.map((coll) => es6_iterator(iterable(coll)));
|
|
826
1042
|
while (true) {
|
|
827
1043
|
const args = [];
|
|
828
1044
|
for (const i of iters) {
|
|
@@ -835,45 +1051,41 @@ export function map(f, ...colls) {
|
|
|
835
1051
|
yield f(...args);
|
|
836
1052
|
}
|
|
837
1053
|
});
|
|
1054
|
+
}
|
|
838
1055
|
}
|
|
839
1056
|
}
|
|
840
1057
|
|
|
841
|
-
|
|
1058
|
+
// 0/1 arities pass through to rf; step(rf) is the 2-arity reducer
|
|
1059
|
+
function transducer(step) {
|
|
842
1060
|
return (rf) => {
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
return rf();
|
|
847
|
-
case 1:
|
|
848
|
-
return rf(args[0]);
|
|
849
|
-
case 2: {
|
|
850
|
-
const result = args[0];
|
|
851
|
-
const input = args[1];
|
|
852
|
-
if (truth_(pred(input))) {
|
|
853
|
-
return rf(result, input);
|
|
854
|
-
} else return result;
|
|
855
|
-
}
|
|
856
|
-
}
|
|
857
|
-
};
|
|
1061
|
+
const s = step(rf);
|
|
1062
|
+
return (...args) =>
|
|
1063
|
+
args.length === 0 ? rf() : args.length === 1 ? rf(args[0]) : s(args[0], args[1]);
|
|
858
1064
|
};
|
|
859
1065
|
}
|
|
860
1066
|
|
|
1067
|
+
function filter1(pred) {
|
|
1068
|
+
return transducer((rf) => (r, x) => (truth_(pred(x)) ? rf(r, x) : r));
|
|
1069
|
+
}
|
|
1070
|
+
|
|
861
1071
|
export function filter(pred, coll) {
|
|
862
1072
|
if (arguments.length === 1) {
|
|
863
1073
|
return filter1(pred);
|
|
864
1074
|
}
|
|
865
1075
|
pred = __toFn(pred);
|
|
866
|
-
return
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
1076
|
+
return mapChunks(coll, (ch) => {
|
|
1077
|
+
const out = [];
|
|
1078
|
+
for (let i = 0; i < ch.length; i++) {
|
|
1079
|
+
const x = ch[i];
|
|
1080
|
+
if (truth_(pred(x))) out.push(x);
|
|
871
1081
|
}
|
|
1082
|
+
return out;
|
|
872
1083
|
});
|
|
873
1084
|
}
|
|
874
1085
|
|
|
875
1086
|
export function filterv(pred, coll) {
|
|
876
|
-
|
|
1087
|
+
// filter is chunked; vec bulk-appends its chunks
|
|
1088
|
+
return pushAll([], filter(pred, coll));
|
|
877
1089
|
}
|
|
878
1090
|
|
|
879
1091
|
export function remove(pred, coll) {
|
|
@@ -884,19 +1096,10 @@ export function remove(pred, coll) {
|
|
|
884
1096
|
}
|
|
885
1097
|
|
|
886
1098
|
function map_indexed1(f) {
|
|
887
|
-
return (rf) => {
|
|
1099
|
+
return transducer((rf) => {
|
|
888
1100
|
let i = -1;
|
|
889
|
-
return (
|
|
890
|
-
|
|
891
|
-
case 0:
|
|
892
|
-
return rf();
|
|
893
|
-
case 1:
|
|
894
|
-
return rf(args[0]);
|
|
895
|
-
case 2:
|
|
896
|
-
return rf(args[0], f(((i = i + 1), i), args[1]));
|
|
897
|
-
}
|
|
898
|
-
};
|
|
899
|
-
};
|
|
1101
|
+
return (r, x) => rf(r, f(++i, x));
|
|
1102
|
+
});
|
|
900
1103
|
}
|
|
901
1104
|
|
|
902
1105
|
export function map_indexed(f, coll) {
|
|
@@ -904,50 +1107,33 @@ export function map_indexed(f, coll) {
|
|
|
904
1107
|
if (arguments.length === 1) {
|
|
905
1108
|
return map_indexed1(f);
|
|
906
1109
|
}
|
|
907
|
-
return
|
|
908
|
-
|
|
909
|
-
for (
|
|
910
|
-
|
|
911
|
-
idx++;
|
|
912
|
-
}
|
|
1110
|
+
return mapChunks(coll, (ch, base) => {
|
|
1111
|
+
const out = new Array(ch.length);
|
|
1112
|
+
for (let i = 0; i < ch.length; i++) out[i] = f(base + i, ch[i]);
|
|
1113
|
+
return out;
|
|
913
1114
|
});
|
|
914
1115
|
}
|
|
915
1116
|
|
|
916
1117
|
function keep_indexed2(f, coll) {
|
|
917
1118
|
f = __toFn(f);
|
|
918
|
-
return
|
|
919
|
-
|
|
920
|
-
for (
|
|
921
|
-
const v = f(
|
|
922
|
-
if (truth_(v))
|
|
923
|
-
idx++;
|
|
1119
|
+
return mapChunks(coll, (ch, base) => {
|
|
1120
|
+
const out = [];
|
|
1121
|
+
for (let i = 0; i < ch.length; i++) {
|
|
1122
|
+
const v = f(base + i, ch[i]);
|
|
1123
|
+
if (truth_(v)) out.push(v);
|
|
924
1124
|
}
|
|
1125
|
+
return out;
|
|
925
1126
|
});
|
|
926
1127
|
}
|
|
927
1128
|
|
|
928
1129
|
function keep_indexed1(f) {
|
|
929
|
-
return (rf) => {
|
|
1130
|
+
return transducer((rf) => {
|
|
930
1131
|
let ia = -1;
|
|
931
|
-
return (
|
|
932
|
-
const
|
|
933
|
-
|
|
934
|
-
return rf();
|
|
935
|
-
}
|
|
936
|
-
if (al === 1) {
|
|
937
|
-
return rf(args[0]);
|
|
938
|
-
}
|
|
939
|
-
if (al === 2) {
|
|
940
|
-
const result = args[0];
|
|
941
|
-
const input = args[1];
|
|
942
|
-
ia++;
|
|
943
|
-
const v = f(ia, input);
|
|
944
|
-
if (v == null) {
|
|
945
|
-
return result;
|
|
946
|
-
}
|
|
947
|
-
return rf(result, v);
|
|
948
|
-
}
|
|
1132
|
+
return (r, x) => {
|
|
1133
|
+
const v = f(++ia, x);
|
|
1134
|
+
return v == null ? r : rf(r, v);
|
|
949
1135
|
};
|
|
950
|
-
};
|
|
1136
|
+
});
|
|
951
1137
|
}
|
|
952
1138
|
|
|
953
1139
|
export function keep_indexed(f, coll) {
|
|
@@ -963,7 +1149,12 @@ export function str(...xs) {
|
|
|
963
1149
|
}
|
|
964
1150
|
|
|
965
1151
|
export function name(x) {
|
|
966
|
-
if (typeof x === 'string')
|
|
1152
|
+
if (typeof x === 'string') {
|
|
1153
|
+
// keywords/symbols are strings in squint; name is the part after the "/"
|
|
1154
|
+
// ns separator (consistent with `namespace`, which returns the part before)
|
|
1155
|
+
const i = x.indexOf('/');
|
|
1156
|
+
return i >= 1 ? x.slice(i + 1) : x;
|
|
1157
|
+
}
|
|
967
1158
|
throw new Error("Doesn't support name: " + typeof x);
|
|
968
1159
|
}
|
|
969
1160
|
|
|
@@ -1048,22 +1239,29 @@ export function compare_and_set_BANG_(atm, oldv, newv) {
|
|
|
1048
1239
|
}
|
|
1049
1240
|
|
|
1050
1241
|
export function range(begin, end, step) {
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1242
|
+
// range is a chunked source: it realizes CHUNK_SIZE values at a time
|
|
1243
|
+
let b = begin,
|
|
1244
|
+
e = end,
|
|
1245
|
+
s = step;
|
|
1246
|
+
if (end === undefined) {
|
|
1247
|
+
b = 0;
|
|
1248
|
+
e = begin;
|
|
1249
|
+
}
|
|
1250
|
+
const start = b || 0;
|
|
1251
|
+
s = step ?? 1;
|
|
1252
|
+
const ascending = s >= 0;
|
|
1253
|
+
const more = (i) => e === undefined || (ascending && i < e) || (!ascending && e < i);
|
|
1254
|
+
const mkStep = (from) => () => {
|
|
1255
|
+
if (!more(from)) return null;
|
|
1256
|
+
const out = [];
|
|
1257
|
+
let i = from;
|
|
1258
|
+
while (out.length < CHUNK_SIZE && more(i)) {
|
|
1259
|
+
out.push(i);
|
|
1064
1260
|
i += s;
|
|
1065
1261
|
}
|
|
1066
|
-
|
|
1262
|
+
return [out, mkStep(i)];
|
|
1263
|
+
};
|
|
1264
|
+
return new LazyIterable(mkStep(start));
|
|
1067
1265
|
}
|
|
1068
1266
|
|
|
1069
1267
|
export function re_matches(re, s) {
|
|
@@ -1136,9 +1334,12 @@ export function mapv(...args) {
|
|
|
1136
1334
|
}
|
|
1137
1335
|
return ret;
|
|
1138
1336
|
} else {
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1337
|
+
// non-array: map whole chunks straight into the result array
|
|
1338
|
+
const ret = [];
|
|
1339
|
+
const next = chunkCursor(iter);
|
|
1340
|
+
let ch;
|
|
1341
|
+
while ((ch = next()) !== null) {
|
|
1342
|
+
for (let i = 0; i < ch.length; i++) ret.push(f(ch[i]));
|
|
1142
1343
|
}
|
|
1143
1344
|
return ret;
|
|
1144
1345
|
}
|
|
@@ -1146,12 +1347,32 @@ export function mapv(...args) {
|
|
|
1146
1347
|
return [...map(...args)];
|
|
1147
1348
|
}
|
|
1148
1349
|
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1350
|
+
// Append every element of `from` to array `out`, bulk-appending whole chunks
|
|
1351
|
+
// for a chunked seq. Returns out.
|
|
1352
|
+
function pushAll(out, from) {
|
|
1353
|
+
if (from instanceof LazyIterable) {
|
|
1354
|
+
let cell = from;
|
|
1355
|
+
for (;;) {
|
|
1356
|
+
cell.force();
|
|
1357
|
+
const ch = cell.chunk;
|
|
1358
|
+
if (ch === null) return out;
|
|
1359
|
+
Array.prototype.push.apply(out, ch);
|
|
1360
|
+
cell = cell._rest;
|
|
1361
|
+
}
|
|
1153
1362
|
}
|
|
1154
|
-
|
|
1363
|
+
for (const x of iterable(from)) out.push(x);
|
|
1364
|
+
return out;
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1367
|
+
// Materialize a seq into a fresh, mutable array (bulk-copies chunked seqs).
|
|
1368
|
+
function toArray(coll) {
|
|
1369
|
+
if (coll instanceof LazyIterable) return pushAll([], coll);
|
|
1370
|
+
return [...iterable(coll)];
|
|
1371
|
+
}
|
|
1372
|
+
|
|
1373
|
+
export function vec(x) {
|
|
1374
|
+
if (array_QMARK_(x)) return x;
|
|
1375
|
+
return pushAll([], x);
|
|
1155
1376
|
}
|
|
1156
1377
|
|
|
1157
1378
|
export function set(coll) {
|
|
@@ -1216,12 +1437,54 @@ export function array_QMARK_(x) {
|
|
|
1216
1437
|
return Array.isArray(x);
|
|
1217
1438
|
}
|
|
1218
1439
|
|
|
1440
|
+
const CONCAT_DONE = Symbol('concat-done');
|
|
1441
|
+
|
|
1219
1442
|
function concat1(colls) {
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1443
|
+
// chunk-aware: pass each coll's chunks through, preserving chunkedness. Each
|
|
1444
|
+
// coll head is released once consumed so a single pass streams.
|
|
1445
|
+
const isArr = Array.isArray(colls);
|
|
1446
|
+
const arr = isArr ? colls.slice() : null;
|
|
1447
|
+
const collIter = isArr ? null : es6_iterator(iterable(colls));
|
|
1448
|
+
let idx = 0;
|
|
1449
|
+
const nextColl = () => {
|
|
1450
|
+
if (isArr) {
|
|
1451
|
+
if (idx >= arr.length) return CONCAT_DONE;
|
|
1452
|
+
const c = arr[idx];
|
|
1453
|
+
arr[idx] = null;
|
|
1454
|
+
idx++;
|
|
1455
|
+
return c;
|
|
1223
1456
|
}
|
|
1224
|
-
|
|
1457
|
+
const r = collIter.next();
|
|
1458
|
+
return r.done ? CONCAT_DONE : r.value;
|
|
1459
|
+
};
|
|
1460
|
+
// src is null, a chunked cell, or {a, pos} for an array (raw-array fast path:
|
|
1461
|
+
// no per-coll wrapper). Continuations carry immutable state, so a single pass
|
|
1462
|
+
// streams.
|
|
1463
|
+
const step = (src) => () => {
|
|
1464
|
+
for (;;) {
|
|
1465
|
+
if (src !== null) {
|
|
1466
|
+
if (src instanceof LazyIterable) {
|
|
1467
|
+
src.force();
|
|
1468
|
+
if (src.chunk !== null) return [src.chunk, step(src._rest)];
|
|
1469
|
+
src = null;
|
|
1470
|
+
} else {
|
|
1471
|
+
const a = src.a;
|
|
1472
|
+
const pos = src.pos;
|
|
1473
|
+
if (pos < a.length) {
|
|
1474
|
+
const end = Math.min(pos + CHUNK_SIZE, a.length);
|
|
1475
|
+
// slice (copy) so a cached chunk never aliases the caller's array
|
|
1476
|
+
return [a.slice(pos, end), step({ a, pos: end })];
|
|
1477
|
+
}
|
|
1478
|
+
src = null;
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
const nc = nextColl();
|
|
1482
|
+
if (nc === CONCAT_DONE) return null;
|
|
1483
|
+
src =
|
|
1484
|
+
nc instanceof LazyIterable ? nc : Array.isArray(nc) ? { a: nc, pos: 0 } : chunkCells(nc);
|
|
1485
|
+
}
|
|
1486
|
+
};
|
|
1487
|
+
return new LazyIterable(step(null));
|
|
1225
1488
|
}
|
|
1226
1489
|
|
|
1227
1490
|
export function concat(...colls) {
|
|
@@ -1236,10 +1499,8 @@ concat[IApply__apply] = (colls) => {
|
|
|
1236
1499
|
export function mapcat(f, ...colls) {
|
|
1237
1500
|
if (colls.length === 0) {
|
|
1238
1501
|
return comp(map(f), cat);
|
|
1239
|
-
} else {
|
|
1240
|
-
const mapped = map(f, ...colls);
|
|
1241
|
-
return concat1(mapped);
|
|
1242
1502
|
}
|
|
1503
|
+
return concat1(map(f, ...colls));
|
|
1243
1504
|
}
|
|
1244
1505
|
|
|
1245
1506
|
export function identity(x) {
|
|
@@ -1247,8 +1508,8 @@ export function identity(x) {
|
|
|
1247
1508
|
}
|
|
1248
1509
|
|
|
1249
1510
|
export function interleave(...colls) {
|
|
1511
|
+
const iters = colls.map((coll) => es6_iterator(iterable(coll)));
|
|
1250
1512
|
return lazy(function* () {
|
|
1251
|
-
const iters = colls.map((coll) => es6_iterator(iterable(coll)));
|
|
1252
1513
|
while (true) {
|
|
1253
1514
|
const res = [];
|
|
1254
1515
|
for (const i of iters) {
|
|
@@ -1264,30 +1525,17 @@ export function interleave(...colls) {
|
|
|
1264
1525
|
}
|
|
1265
1526
|
|
|
1266
1527
|
function interpose1(sep) {
|
|
1267
|
-
return (rf) => {
|
|
1528
|
+
return transducer((rf) => {
|
|
1268
1529
|
let started = false;
|
|
1269
|
-
return (
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
case 1:
|
|
1274
|
-
return rf(args[0]);
|
|
1275
|
-
case 2: {
|
|
1276
|
-
if (started) {
|
|
1277
|
-
const sepr = rf(args[0], sep);
|
|
1278
|
-
if (reduced_QMARK_(sepr)) {
|
|
1279
|
-
return sepr;
|
|
1280
|
-
} else {
|
|
1281
|
-
return rf(sepr, args[1]);
|
|
1282
|
-
}
|
|
1283
|
-
} else {
|
|
1284
|
-
started = true;
|
|
1285
|
-
return rf(args[0], args[1]);
|
|
1286
|
-
}
|
|
1287
|
-
}
|
|
1530
|
+
return (r, x) => {
|
|
1531
|
+
if (!started) {
|
|
1532
|
+
started = true;
|
|
1533
|
+
return rf(r, x);
|
|
1288
1534
|
}
|
|
1535
|
+
const sepr = rf(r, sep);
|
|
1536
|
+
return reduced_QMARK_(sepr) ? sepr : rf(sepr, x);
|
|
1289
1537
|
};
|
|
1290
|
-
};
|
|
1538
|
+
});
|
|
1291
1539
|
}
|
|
1292
1540
|
|
|
1293
1541
|
export function interpose(sep, coll) {
|
|
@@ -1301,7 +1549,7 @@ export function select_keys(o, ks) {
|
|
|
1301
1549
|
const ret = emptyOfType(type) || {};
|
|
1302
1550
|
for (const k of ks) {
|
|
1303
1551
|
const v = get(o, k);
|
|
1304
|
-
if (v
|
|
1552
|
+
if (v !== undefined) {
|
|
1305
1553
|
assoc_BANG_(ret, k, v);
|
|
1306
1554
|
}
|
|
1307
1555
|
}
|
|
@@ -1379,10 +1627,10 @@ export const partitionv = partition; // partition already returns a lazy of arra
|
|
|
1379
1627
|
export const partitionv_all = partition_all;
|
|
1380
1628
|
|
|
1381
1629
|
function partitionInternal(n, step, pad, coll, all) {
|
|
1382
|
-
return
|
|
1630
|
+
return lazyIter(coll, function* (it) {
|
|
1383
1631
|
let p = [];
|
|
1384
1632
|
let i = 0;
|
|
1385
|
-
for (const x of
|
|
1633
|
+
for (const x of it) {
|
|
1386
1634
|
if (i < n) {
|
|
1387
1635
|
p.push(x);
|
|
1388
1636
|
if (p.length === n) {
|
|
@@ -1454,8 +1702,8 @@ export function partition_by(f, coll) {
|
|
|
1454
1702
|
if (arguments.length === 1) {
|
|
1455
1703
|
return partition_by1(f);
|
|
1456
1704
|
}
|
|
1705
|
+
const iter = es6_iterator(coll);
|
|
1457
1706
|
return lazy(function* () {
|
|
1458
|
-
const iter = es6_iterator(coll);
|
|
1459
1707
|
const _fst = iter.next();
|
|
1460
1708
|
if (_fst.done) {
|
|
1461
1709
|
yield* null;
|
|
@@ -1488,7 +1736,7 @@ export function partition_by(f, coll) {
|
|
|
1488
1736
|
export function empty(coll) {
|
|
1489
1737
|
const type = typeConst(coll);
|
|
1490
1738
|
if (type != null) {
|
|
1491
|
-
return emptyOfType(type);
|
|
1739
|
+
return copyMeta(coll, emptyOfType(type));
|
|
1492
1740
|
} else {
|
|
1493
1741
|
throw new Error(`Can't create empty of ${typeof coll}`);
|
|
1494
1742
|
}
|
|
@@ -1554,7 +1802,13 @@ export function into(...args) {
|
|
|
1554
1802
|
case 1:
|
|
1555
1803
|
return args[0];
|
|
1556
1804
|
case 2:
|
|
1557
|
-
|
|
1805
|
+
// vector target bulk-appends chunks (copy preserves metadata); lists conj
|
|
1806
|
+
// at the head, other targets need conj!
|
|
1807
|
+
to = args[0] ?? [];
|
|
1808
|
+
if (Array.isArray(to) && !(to instanceof List)) {
|
|
1809
|
+
return pushAll(copy(to), args[1]);
|
|
1810
|
+
}
|
|
1811
|
+
return reduce(conj_BANG_, copy(to), args[1]);
|
|
1558
1812
|
case 3:
|
|
1559
1813
|
to = args[0];
|
|
1560
1814
|
xform = args[1];
|
|
@@ -1605,42 +1859,23 @@ export function ensure_reduced(x) {
|
|
|
1605
1859
|
}
|
|
1606
1860
|
|
|
1607
1861
|
function take1(n) {
|
|
1608
|
-
return (rf) => {
|
|
1862
|
+
return transducer((rf) => {
|
|
1609
1863
|
let na = n;
|
|
1610
|
-
return (
|
|
1611
|
-
const
|
|
1612
|
-
if (
|
|
1613
|
-
|
|
1614
|
-
}
|
|
1615
|
-
if (al === 1) {
|
|
1616
|
-
const result = args[0];
|
|
1617
|
-
return rf(result);
|
|
1618
|
-
}
|
|
1619
|
-
if (al === 2) {
|
|
1620
|
-
let result = args[0];
|
|
1621
|
-
const input = args[1];
|
|
1622
|
-
const n = na;
|
|
1623
|
-
const nn = ((na = na - 1), na);
|
|
1624
|
-
if (n > 0) {
|
|
1625
|
-
result = rf(result, input);
|
|
1626
|
-
}
|
|
1627
|
-
if (!(nn > 0)) {
|
|
1628
|
-
return ensure_reduced(result);
|
|
1629
|
-
} else {
|
|
1630
|
-
return result;
|
|
1631
|
-
}
|
|
1632
|
-
}
|
|
1864
|
+
return (r, x) => {
|
|
1865
|
+
const nn = --na + 1;
|
|
1866
|
+
if (nn > 0) r = rf(r, x);
|
|
1867
|
+
return nn > 1 ? r : ensure_reduced(r);
|
|
1633
1868
|
};
|
|
1634
|
-
};
|
|
1869
|
+
});
|
|
1635
1870
|
}
|
|
1636
1871
|
|
|
1637
1872
|
export function take(n, coll) {
|
|
1638
1873
|
if (arguments.length === 1) {
|
|
1639
1874
|
return take1(n);
|
|
1640
1875
|
}
|
|
1641
|
-
return
|
|
1876
|
+
return lazyIter(coll, function* (it) {
|
|
1642
1877
|
let i = n - 1;
|
|
1643
|
-
for (const x of
|
|
1878
|
+
for (const x of it) {
|
|
1644
1879
|
if (i-- >= 0) {
|
|
1645
1880
|
yield x;
|
|
1646
1881
|
}
|
|
@@ -1674,22 +1909,7 @@ export function take_last(n, coll) {
|
|
|
1674
1909
|
}
|
|
1675
1910
|
|
|
1676
1911
|
function take_while1(pred) {
|
|
1677
|
-
return (rf) =>
|
|
1678
|
-
return (...args) => {
|
|
1679
|
-
const al = args.length;
|
|
1680
|
-
if (al === 0) return rf();
|
|
1681
|
-
if (al === 1) return rf(args[0]);
|
|
1682
|
-
if (al === 2) {
|
|
1683
|
-
const result = args[0];
|
|
1684
|
-
const input = args[1];
|
|
1685
|
-
if (truth_(pred(input))) {
|
|
1686
|
-
return rf(result, input);
|
|
1687
|
-
} else {
|
|
1688
|
-
return reduced(result);
|
|
1689
|
-
}
|
|
1690
|
-
}
|
|
1691
|
-
};
|
|
1692
|
-
};
|
|
1912
|
+
return transducer((rf) => (r, x) => (truth_(pred(x)) ? rf(r, x) : reduced(r)));
|
|
1693
1913
|
}
|
|
1694
1914
|
|
|
1695
1915
|
export function take_while(pred, coll) {
|
|
@@ -1697,8 +1917,8 @@ export function take_while(pred, coll) {
|
|
|
1697
1917
|
if (arguments.length === 1) {
|
|
1698
1918
|
return take_while1(pred);
|
|
1699
1919
|
}
|
|
1700
|
-
return
|
|
1701
|
-
for (const o of
|
|
1920
|
+
return lazyIter(coll, function* (it) {
|
|
1921
|
+
for (const o of it) {
|
|
1702
1922
|
if (truth_(pred(o))) yield o;
|
|
1703
1923
|
else return;
|
|
1704
1924
|
}
|
|
@@ -1706,23 +1926,10 @@ export function take_while(pred, coll) {
|
|
|
1706
1926
|
}
|
|
1707
1927
|
|
|
1708
1928
|
function take_nth1(n) {
|
|
1709
|
-
return (rf) => {
|
|
1929
|
+
return transducer((rf) => {
|
|
1710
1930
|
let ia = -1;
|
|
1711
|
-
return (
|
|
1712
|
-
|
|
1713
|
-
if (al === 0) return rf();
|
|
1714
|
-
if (al === 1) return rf(args[0]);
|
|
1715
|
-
if (al === 2) {
|
|
1716
|
-
const result = args[0];
|
|
1717
|
-
const input = args[1];
|
|
1718
|
-
ia++;
|
|
1719
|
-
const i = ia;
|
|
1720
|
-
if (rem(i, n) === 0) {
|
|
1721
|
-
return rf(result, input);
|
|
1722
|
-
} else return result;
|
|
1723
|
-
}
|
|
1724
|
-
};
|
|
1725
|
-
};
|
|
1931
|
+
return (r, x) => (rem(++ia, n) === 0 ? rf(r, x) : r);
|
|
1932
|
+
});
|
|
1726
1933
|
}
|
|
1727
1934
|
|
|
1728
1935
|
export function take_nth(n, coll) {
|
|
@@ -1731,9 +1938,9 @@ export function take_nth(n, coll) {
|
|
|
1731
1938
|
return repeat(first(coll));
|
|
1732
1939
|
}
|
|
1733
1940
|
|
|
1734
|
-
return
|
|
1941
|
+
return lazyIter(coll, function* (it) {
|
|
1735
1942
|
let i = 0;
|
|
1736
|
-
for (const x of
|
|
1943
|
+
for (const x of it) {
|
|
1737
1944
|
if (i % n === 0) {
|
|
1738
1945
|
yield x;
|
|
1739
1946
|
}
|
|
@@ -1756,33 +1963,15 @@ export function cycle(coll) {
|
|
|
1756
1963
|
}
|
|
1757
1964
|
|
|
1758
1965
|
function drop1(n) {
|
|
1759
|
-
return (rf) => {
|
|
1966
|
+
return transducer((rf) => {
|
|
1760
1967
|
let na = n;
|
|
1761
|
-
return (
|
|
1762
|
-
|
|
1763
|
-
if (al === 0) {
|
|
1764
|
-
return rf();
|
|
1765
|
-
}
|
|
1766
|
-
if (al === 1) {
|
|
1767
|
-
return rf(args[0]);
|
|
1768
|
-
}
|
|
1769
|
-
if (al === 2) {
|
|
1770
|
-
const result = args[0];
|
|
1771
|
-
const input = args[1];
|
|
1772
|
-
const n = na;
|
|
1773
|
-
na--;
|
|
1774
|
-
if (n > 0) {
|
|
1775
|
-
return result;
|
|
1776
|
-
} else return rf(result, input);
|
|
1777
|
-
}
|
|
1778
|
-
};
|
|
1779
|
-
};
|
|
1968
|
+
return (r, x) => (na-- > 0 ? r : rf(r, x));
|
|
1969
|
+
});
|
|
1780
1970
|
}
|
|
1781
1971
|
|
|
1782
1972
|
export function drop(n, xs) {
|
|
1783
1973
|
if (arguments.length === 1) return drop1(n);
|
|
1784
|
-
return
|
|
1785
|
-
const iter = _iterator(iterable(xs));
|
|
1974
|
+
return lazyIter(xs, function* (iter) {
|
|
1786
1975
|
for (let x = 0; x < n; x++) {
|
|
1787
1976
|
iter.next();
|
|
1788
1977
|
}
|
|
@@ -1791,36 +1980,20 @@ export function drop(n, xs) {
|
|
|
1791
1980
|
}
|
|
1792
1981
|
|
|
1793
1982
|
function drop_while1(pred) {
|
|
1794
|
-
return (rf) => {
|
|
1983
|
+
return transducer((rf) => {
|
|
1795
1984
|
let da = true;
|
|
1796
|
-
return (
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
}
|
|
1801
|
-
if (al === 1) {
|
|
1802
|
-
return rf(args[0]);
|
|
1803
|
-
}
|
|
1804
|
-
if (al === 2) {
|
|
1805
|
-
const isDrop = da;
|
|
1806
|
-
const result = args[0];
|
|
1807
|
-
const input = args[1];
|
|
1808
|
-
if (isDrop && truth_(pred(input))) {
|
|
1809
|
-
return result;
|
|
1810
|
-
} else {
|
|
1811
|
-
da = null;
|
|
1812
|
-
return rf(result, input);
|
|
1813
|
-
}
|
|
1814
|
-
}
|
|
1985
|
+
return (r, x) => {
|
|
1986
|
+
if (da && truth_(pred(x))) return r;
|
|
1987
|
+
da = false;
|
|
1988
|
+
return rf(r, x);
|
|
1815
1989
|
};
|
|
1816
|
-
};
|
|
1990
|
+
});
|
|
1817
1991
|
}
|
|
1818
1992
|
|
|
1819
1993
|
export function drop_while(pred, xs) {
|
|
1820
1994
|
pred = __toFn(pred);
|
|
1821
1995
|
if (arguments.length === 1) return drop_while1(pred);
|
|
1822
|
-
return
|
|
1823
|
-
const iter = _iterator(iterable(xs));
|
|
1996
|
+
return lazyIter(xs, function* (iter) {
|
|
1824
1997
|
while (true) {
|
|
1825
1998
|
const nextItem = iter.next();
|
|
1826
1999
|
if (nextItem.done) {
|
|
@@ -1837,28 +2010,21 @@ export function drop_while(pred, xs) {
|
|
|
1837
2010
|
}
|
|
1838
2011
|
|
|
1839
2012
|
function distinct1() {
|
|
1840
|
-
return (rf) => {
|
|
2013
|
+
return transducer((rf) => {
|
|
1841
2014
|
const seen = new Set();
|
|
1842
|
-
return (
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
if (al === 2) {
|
|
1847
|
-
const result = args[0];
|
|
1848
|
-
const input = args[1];
|
|
1849
|
-
if (seen.has(input)) return result;
|
|
1850
|
-
seen.add(input);
|
|
1851
|
-
return rf(result, input);
|
|
1852
|
-
}
|
|
2015
|
+
return (r, x) => {
|
|
2016
|
+
if (seen.has(x)) return r;
|
|
2017
|
+
seen.add(x);
|
|
2018
|
+
return rf(r, x);
|
|
1853
2019
|
};
|
|
1854
|
-
};
|
|
2020
|
+
});
|
|
1855
2021
|
}
|
|
1856
2022
|
|
|
1857
2023
|
export function distinct(coll) {
|
|
1858
2024
|
if (arguments.length === 0) return distinct1();
|
|
1859
|
-
return
|
|
2025
|
+
return lazyIter(coll, function* (it) {
|
|
1860
2026
|
const seen = new Set();
|
|
1861
|
-
for (const x of
|
|
2027
|
+
for (const x of it) {
|
|
1862
2028
|
if (!seen.has(x)) yield x;
|
|
1863
2029
|
seen.add(x);
|
|
1864
2030
|
}
|
|
@@ -1869,28 +2035,21 @@ export function distinct(coll) {
|
|
|
1869
2035
|
const DEDUPE_NONE = Symbol('dedupe-none');
|
|
1870
2036
|
|
|
1871
2037
|
function dedupe1() {
|
|
1872
|
-
return (rf) => {
|
|
2038
|
+
return transducer((rf) => {
|
|
1873
2039
|
let prev = DEDUPE_NONE;
|
|
1874
|
-
return (
|
|
1875
|
-
const
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
if (al === 2) {
|
|
1879
|
-
const result = args[0];
|
|
1880
|
-
const input = args[1];
|
|
1881
|
-
const skip = prev !== DEDUPE_NONE && truth_(_EQ_(prev, input));
|
|
1882
|
-
prev = input;
|
|
1883
|
-
return skip ? result : rf(result, input);
|
|
1884
|
-
}
|
|
2040
|
+
return (r, x) => {
|
|
2041
|
+
const skip = prev !== DEDUPE_NONE && truth_(_EQ_(prev, x));
|
|
2042
|
+
prev = x;
|
|
2043
|
+
return skip ? r : rf(r, x);
|
|
1885
2044
|
};
|
|
1886
|
-
};
|
|
2045
|
+
});
|
|
1887
2046
|
}
|
|
1888
2047
|
|
|
1889
2048
|
export function dedupe(coll) {
|
|
1890
2049
|
if (arguments.length === 0) return dedupe1();
|
|
1891
|
-
return
|
|
2050
|
+
return lazyIter(coll, function* (it) {
|
|
1892
2051
|
let prev = DEDUPE_NONE;
|
|
1893
|
-
for (const x of
|
|
2052
|
+
for (const x of it) {
|
|
1894
2053
|
if (prev === DEDUPE_NONE || !truth_(_EQ_(prev, x))) yield x;
|
|
1895
2054
|
prev = x;
|
|
1896
2055
|
}
|
|
@@ -1930,8 +2089,14 @@ export function fnil(f, x, ...xs) {
|
|
|
1930
2089
|
|
|
1931
2090
|
export function every_QMARK_(pred, coll) {
|
|
1932
2091
|
pred = __toFn(pred);
|
|
1933
|
-
|
|
1934
|
-
if (!pred(
|
|
2092
|
+
if (Array.isArray(coll)) {
|
|
2093
|
+
for (let i = 0; i < coll.length; i++) if (!pred(coll[i])) return false;
|
|
2094
|
+
return true;
|
|
2095
|
+
}
|
|
2096
|
+
const next = chunkCursor(coll);
|
|
2097
|
+
let ch;
|
|
2098
|
+
while ((ch = next()) !== null) {
|
|
2099
|
+
for (let i = 0; i < ch.length; i++) if (!pred(ch[i])) return false;
|
|
1935
2100
|
}
|
|
1936
2101
|
return true;
|
|
1937
2102
|
}
|
|
@@ -1941,36 +2106,27 @@ export function not_every_QMARK_(pred, coll) {
|
|
|
1941
2106
|
}
|
|
1942
2107
|
|
|
1943
2108
|
function keep1(pred) {
|
|
1944
|
-
return (rf) => {
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
if (al === 1) return rf(args[0]);
|
|
1949
|
-
if (al === 2) {
|
|
1950
|
-
const result = args[0];
|
|
1951
|
-
const input = args[1];
|
|
1952
|
-
const v = pred(input);
|
|
1953
|
-
if (v == null) return result;
|
|
1954
|
-
return rf(result, v);
|
|
1955
|
-
}
|
|
1956
|
-
};
|
|
1957
|
-
};
|
|
2109
|
+
return transducer((rf) => (r, x) => {
|
|
2110
|
+
const v = pred(x);
|
|
2111
|
+
return v == null ? r : rf(r, v);
|
|
2112
|
+
});
|
|
1958
2113
|
}
|
|
1959
2114
|
|
|
1960
2115
|
export function keep(pred, coll) {
|
|
1961
2116
|
pred = __toFn(pred);
|
|
1962
2117
|
if (arguments.length === 1) return keep1(pred);
|
|
1963
|
-
return
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
2118
|
+
return mapChunks(coll, (ch) => {
|
|
2119
|
+
const out = [];
|
|
2120
|
+
for (let i = 0; i < ch.length; i++) {
|
|
2121
|
+
const res = pred(ch[i]);
|
|
2122
|
+
if (truth_(res)) out.push(res);
|
|
1967
2123
|
}
|
|
2124
|
+
return out;
|
|
1968
2125
|
});
|
|
1969
2126
|
}
|
|
1970
2127
|
|
|
1971
2128
|
export function reverse(coll) {
|
|
1972
|
-
|
|
1973
|
-
return [...coll].reverse();
|
|
2129
|
+
return toArray(coll).reverse();
|
|
1974
2130
|
}
|
|
1975
2131
|
|
|
1976
2132
|
export function sort(f, coll) {
|
|
@@ -1979,9 +2135,8 @@ export function sort(f, coll) {
|
|
|
1979
2135
|
f = undefined;
|
|
1980
2136
|
}
|
|
1981
2137
|
f = __toFn(f);
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
const clone = [...coll];
|
|
2138
|
+
// need a copy since .sort works in place and .toSorted isn't on Node < 20
|
|
2139
|
+
const clone = toArray(coll);
|
|
1985
2140
|
// result is guaranteed to be stable since ES2019, like CLJS
|
|
1986
2141
|
return clone.sort(f || compare);
|
|
1987
2142
|
}
|
|
@@ -2021,7 +2176,7 @@ export function sort_by(keyfn, comp, coll) {
|
|
|
2021
2176
|
}
|
|
2022
2177
|
|
|
2023
2178
|
export function shuffle(coll) {
|
|
2024
|
-
const result =
|
|
2179
|
+
const result = toArray(coll);
|
|
2025
2180
|
let remaining = result.length;
|
|
2026
2181
|
while (remaining) {
|
|
2027
2182
|
const i = Math.floor(Math.random() * remaining--);
|
|
@@ -2035,9 +2190,20 @@ export function shuffle(coll) {
|
|
|
2035
2190
|
|
|
2036
2191
|
export function some(pred, coll) {
|
|
2037
2192
|
pred = __toFn(pred);
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2193
|
+
if (Array.isArray(coll)) {
|
|
2194
|
+
for (let i = 0; i < coll.length; i++) {
|
|
2195
|
+
const res = pred(coll[i]);
|
|
2196
|
+
if (truth_(res)) return res;
|
|
2197
|
+
}
|
|
2198
|
+
return undefined;
|
|
2199
|
+
}
|
|
2200
|
+
const next = chunkCursor(coll);
|
|
2201
|
+
let ch;
|
|
2202
|
+
while ((ch = next()) !== null) {
|
|
2203
|
+
for (let i = 0; i < ch.length; i++) {
|
|
2204
|
+
const res = pred(ch[i]);
|
|
2205
|
+
if (truth_(res)) return res;
|
|
2206
|
+
}
|
|
2041
2207
|
}
|
|
2042
2208
|
return undefined;
|
|
2043
2209
|
}
|
|
@@ -2123,22 +2289,16 @@ export function frequencies(coll) {
|
|
|
2123
2289
|
return res;
|
|
2124
2290
|
}
|
|
2125
2291
|
|
|
2126
|
-
|
|
2292
|
+
// The lazy-seq macro emits `new LazySeq(() => body)`: a LazyIterable whose step
|
|
2293
|
+
// evaluates the body thunk on first force and reads it unchunked.
|
|
2294
|
+
export class LazySeq extends LazyIterable {
|
|
2127
2295
|
constructor(f) {
|
|
2128
|
-
|
|
2129
|
-
this.res = undefined;
|
|
2130
|
-
}
|
|
2131
|
-
*[Symbol.iterator]() {
|
|
2132
|
-
if (this.res === undefined) {
|
|
2133
|
-
this.res = this.f();
|
|
2134
|
-
this.f = null;
|
|
2135
|
-
}
|
|
2136
|
-
yield* iterable(this.res);
|
|
2296
|
+
super(() => unchunkedSteps(es6_iterator(iterable(f())))());
|
|
2137
2297
|
}
|
|
2138
2298
|
}
|
|
2139
2299
|
|
|
2140
2300
|
export function butlast(coll) {
|
|
2141
|
-
const x =
|
|
2301
|
+
const x = toArray(coll);
|
|
2142
2302
|
x.pop();
|
|
2143
2303
|
return x.length > 0 ? x : null;
|
|
2144
2304
|
}
|
|
@@ -2162,10 +2322,11 @@ export function count(coll) {
|
|
|
2162
2322
|
if (typeof len === 'number') {
|
|
2163
2323
|
return len;
|
|
2164
2324
|
}
|
|
2325
|
+
// sum chunk lengths instead of counting elements one by one
|
|
2326
|
+
const next = chunkCursor(coll);
|
|
2165
2327
|
let ret = 0;
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
}
|
|
2328
|
+
let ch;
|
|
2329
|
+
while ((ch = next()) !== null) ret += ch.length;
|
|
2169
2330
|
return ret;
|
|
2170
2331
|
}
|
|
2171
2332
|
|
|
@@ -2233,6 +2394,12 @@ export function aset(arr, idx, val, ...more) {
|
|
|
2233
2394
|
}
|
|
2234
2395
|
|
|
2235
2396
|
export function dorun(x) {
|
|
2397
|
+
// only a lazy seq needs forcing; realized colls are walked natively
|
|
2398
|
+
if (x instanceof LazyIterable) {
|
|
2399
|
+
const next = chunkCursor(x);
|
|
2400
|
+
while (next() !== null);
|
|
2401
|
+
return null;
|
|
2402
|
+
}
|
|
2236
2403
|
for (const _ of iterable(x)) {
|
|
2237
2404
|
// nothing here, just consume for side effects
|
|
2238
2405
|
}
|
|
@@ -2372,7 +2539,8 @@ export function compare(x, y) {
|
|
|
2372
2539
|
}
|
|
2373
2540
|
const tx = typeof x;
|
|
2374
2541
|
const ty = typeof y;
|
|
2375
|
-
if ((tx === 'number' && ty === 'number') || (tx === 'string' && ty === 'string')
|
|
2542
|
+
if ((tx === 'number' && ty === 'number') || (tx === 'string' && ty === 'string') ||
|
|
2543
|
+
(tx === 'boolean' && ty === 'boolean')) {
|
|
2376
2544
|
if (x === y) {
|
|
2377
2545
|
return 0;
|
|
2378
2546
|
}
|
|
@@ -2493,6 +2661,62 @@ export function string_QMARK_(s) {
|
|
|
2493
2661
|
return typeof s === 'string';
|
|
2494
2662
|
}
|
|
2495
2663
|
|
|
2664
|
+
export function unchecked_int(x) {
|
|
2665
|
+
return Math.trunc(x);
|
|
2666
|
+
}
|
|
2667
|
+
|
|
2668
|
+
export function unchecked_inc_int(x) {
|
|
2669
|
+
return x + 1;
|
|
2670
|
+
}
|
|
2671
|
+
|
|
2672
|
+
export function unchecked_dec_int(x) {
|
|
2673
|
+
return x - 1;
|
|
2674
|
+
}
|
|
2675
|
+
|
|
2676
|
+
export function unchecked_add_int(x, y) {
|
|
2677
|
+
return x + y;
|
|
2678
|
+
}
|
|
2679
|
+
|
|
2680
|
+
// keywords/symbols are strings in squint; namespace is the part before "/"
|
|
2681
|
+
export function namespace(x) {
|
|
2682
|
+
// keywords/symbols are strings in squint; namespace is the part before the
|
|
2683
|
+
// "/" ns separator (consistent with `name`, which returns the part after).
|
|
2684
|
+
// i >= 1 so a leading "/" yields a nil namespace rather than an empty one.
|
|
2685
|
+
const i = x.indexOf('/');
|
|
2686
|
+
return i >= 1 ? x.slice(0, i) : null;
|
|
2687
|
+
}
|
|
2688
|
+
|
|
2689
|
+
// squint has no keyword type; keywords are strings, so keyword/keyword? are
|
|
2690
|
+
// string-based. (keyword name) or (keyword ns name).
|
|
2691
|
+
export function keyword(arg1, arg2) {
|
|
2692
|
+
if (arg2 !== undefined) {
|
|
2693
|
+
return (arg1 != null ? arg1 + '/' : '') + arg2;
|
|
2694
|
+
}
|
|
2695
|
+
return arg1;
|
|
2696
|
+
}
|
|
2697
|
+
|
|
2698
|
+
export function keyword_QMARK_(x) {
|
|
2699
|
+
return typeof x === 'string';
|
|
2700
|
+
}
|
|
2701
|
+
|
|
2702
|
+
// squint has no symbol type either; symbols are strings
|
|
2703
|
+
export function symbol_QMARK_(x) {
|
|
2704
|
+
return typeof x === 'string';
|
|
2705
|
+
}
|
|
2706
|
+
|
|
2707
|
+
// squint has no first-class Var objects (#'x emits the value), so var? is false
|
|
2708
|
+
export function var_QMARK_(_x) {
|
|
2709
|
+
return false;
|
|
2710
|
+
}
|
|
2711
|
+
|
|
2712
|
+
export function simple_keyword_QMARK_(x) {
|
|
2713
|
+
return typeof x === 'string' && !x.includes('/');
|
|
2714
|
+
}
|
|
2715
|
+
|
|
2716
|
+
export function qualified_keyword_QMARK_(x) {
|
|
2717
|
+
return typeof x === 'string' && x.includes('/');
|
|
2718
|
+
}
|
|
2719
|
+
|
|
2496
2720
|
export function coll_QMARK_(coll) {
|
|
2497
2721
|
return typeConst(coll) != undefined;
|
|
2498
2722
|
}
|
|
@@ -2546,8 +2770,6 @@ export function neg_int_QMARK_(x) {
|
|
|
2546
2770
|
return int_QMARK_(x) && x < 0;
|
|
2547
2771
|
}
|
|
2548
2772
|
|
|
2549
|
-
const _metaSym = Symbol('meta');
|
|
2550
|
-
|
|
2551
2773
|
export function meta(x) {
|
|
2552
2774
|
if (x instanceof Object) {
|
|
2553
2775
|
return x[_metaSym];
|
|
@@ -2557,7 +2779,7 @@ export function meta(x) {
|
|
|
2557
2779
|
export function with_meta(x, m) {
|
|
2558
2780
|
// For functions, wrap in a new callable that forwards to the original
|
|
2559
2781
|
// so fn? stays true and the original isn't mutated. copy() can't handle
|
|
2560
|
-
// functions
|
|
2782
|
+
// functions - a {...x} spread loses the call signature.
|
|
2561
2783
|
if (typeof x === 'function') {
|
|
2562
2784
|
const wrapped = function (...args) { return x.apply(this, args); };
|
|
2563
2785
|
wrapped[_metaSym] = m;
|
|
@@ -2596,7 +2818,7 @@ export function bounded_count(n, coll) {
|
|
|
2596
2818
|
export function find(m, k) {
|
|
2597
2819
|
const v = get(m, k);
|
|
2598
2820
|
if (v !== undefined) {
|
|
2599
|
-
return [k, v];
|
|
2821
|
+
return tagMapEntry([k, v]);
|
|
2600
2822
|
}
|
|
2601
2823
|
}
|
|
2602
2824
|
|
|
@@ -2644,7 +2866,7 @@ export function parse_long(s) {
|
|
|
2644
2866
|
if (string_QMARK_(s)) {
|
|
2645
2867
|
if (/^[+-]?\d+$/.test(s)) {
|
|
2646
2868
|
const i = parseInt(s);
|
|
2647
|
-
if (Number.MIN_SAFE_INTEGER <= i <= Number.MAX_SAFE_INTEGER) {
|
|
2869
|
+
if (Number.MIN_SAFE_INTEGER <= i && i <= Number.MAX_SAFE_INTEGER) {
|
|
2648
2870
|
return i;
|
|
2649
2871
|
}
|
|
2650
2872
|
}
|
|
@@ -2655,10 +2877,10 @@ export function parse_long(s) {
|
|
|
2655
2877
|
|
|
2656
2878
|
export function parse_double(s) {
|
|
2657
2879
|
if (string_QMARK_(s)) {
|
|
2658
|
-
if (/^[
|
|
2880
|
+
if (/^[\x00-\x20]*[+-]?NaN[\x00-\x20]*$/.test(s)) {
|
|
2659
2881
|
return NaN;
|
|
2660
2882
|
} else if (
|
|
2661
|
-
/^[
|
|
2883
|
+
/^[\x00-\x20]*[+-]?(Infinity|((\d+\.?\d*|\.\d+)([eE][+-]?\d+)?)[dDfF]?)[\x00-\x20]*$/.test(
|
|
2662
2884
|
s
|
|
2663
2885
|
)
|
|
2664
2886
|
) {
|
|
@@ -2667,7 +2889,7 @@ export function parse_double(s) {
|
|
|
2667
2889
|
return null;
|
|
2668
2890
|
}
|
|
2669
2891
|
} else {
|
|
2670
|
-
|
|
2892
|
+
return parsing_err(s);
|
|
2671
2893
|
}
|
|
2672
2894
|
}
|
|
2673
2895
|
|
|
@@ -2765,7 +2987,9 @@ export function transient$(x) {
|
|
|
2765
2987
|
}
|
|
2766
2988
|
|
|
2767
2989
|
export function persistent_BANG_(x) {
|
|
2768
|
-
|
|
2990
|
+
// no Object.freeze: persistent structures stay extensible so symbol-keyed
|
|
2991
|
+
// metadata can be attached
|
|
2992
|
+
return x;
|
|
2769
2993
|
}
|
|
2770
2994
|
|
|
2771
2995
|
class SortedSet {
|
|
@@ -3052,11 +3276,18 @@ export function volatile_BANG_(x) {
|
|
|
3052
3276
|
|
|
3053
3277
|
export function vreset_BANG_(vol, v) {
|
|
3054
3278
|
vol.v = v;
|
|
3279
|
+
return v;
|
|
3055
3280
|
}
|
|
3056
3281
|
|
|
3057
3282
|
function toEDN(value, seen = new WeakSet()) {
|
|
3058
3283
|
if (value == null) return 'nil';
|
|
3059
|
-
if (typeof value === 'number'
|
|
3284
|
+
if (typeof value === 'number') {
|
|
3285
|
+
if (value === Infinity) return '##Inf';
|
|
3286
|
+
if (value === -Infinity) return '##-Inf';
|
|
3287
|
+
if (Number.isNaN(value)) return '##NaN';
|
|
3288
|
+
return String(value);
|
|
3289
|
+
}
|
|
3290
|
+
if (typeof value === 'boolean') return String(value);
|
|
3060
3291
|
if (typeof value === 'string') return JSON.stringify(value);
|
|
3061
3292
|
if (typeof value === 'bigint') return `${value}N`;
|
|
3062
3293
|
|