squint-cljs 0.12.193 → 0.13.195
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 +1361 -1324
- package/lib/compiler.node.js +39 -35
- package/lib/compiler.sci.js +1313 -1164
- package/lib/node.nrepl_server.js +29 -29
- package/lib/squint.core.umd.js +1 -1
- package/package.json +3 -1
- package/src/squint/core.js +631 -410
- package/src/squint/walk.js +103 -0
- package/vite.js +9 -2
package/src/squint/core.js
CHANGED
|
@@ -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
|
}
|
|
@@ -234,6 +273,10 @@ function isObj(coll) {
|
|
|
234
273
|
return coll.constructor === Object;
|
|
235
274
|
}
|
|
236
275
|
|
|
276
|
+
function isVectorArray(x) {
|
|
277
|
+
return Array.isArray(x) && !(x instanceof List);
|
|
278
|
+
}
|
|
279
|
+
|
|
237
280
|
export function object_QMARK_(coll) {
|
|
238
281
|
return coll != null && isObj(coll);
|
|
239
282
|
}
|
|
@@ -249,7 +292,7 @@ function typeConst(obj) {
|
|
|
249
292
|
if (obj instanceof Map) return MAP_TYPE;
|
|
250
293
|
if (obj instanceof Set) return SET_TYPE;
|
|
251
294
|
if (obj instanceof List) return LIST_TYPE;
|
|
252
|
-
if (
|
|
295
|
+
if (isVectorArray(obj)) return ARRAY_TYPE;
|
|
253
296
|
if (obj instanceof LazyIterable) return LAZY_ITERABLE_TYPE;
|
|
254
297
|
if (obj instanceof SortedSet) return SET_TYPE;
|
|
255
298
|
|
|
@@ -399,14 +442,14 @@ export function conj(...xs) {
|
|
|
399
442
|
case SET_TYPE:
|
|
400
443
|
if (o instanceof SortedSet) {
|
|
401
444
|
// prevent re-sorting of collection
|
|
402
|
-
return conj_BANG_set(new o.constructor(o), rest);
|
|
445
|
+
return copyMeta(o, conj_BANG_set(new o.constructor(o), rest));
|
|
403
446
|
} else {
|
|
404
|
-
return new o.constructor([...o, ...rest]);
|
|
447
|
+
return copyMeta(o, new o.constructor([...o, ...rest]));
|
|
405
448
|
}
|
|
406
449
|
case LIST_TYPE:
|
|
407
|
-
return new List(...rest.reverse(), ...o);
|
|
450
|
+
return copyMeta(o, new List(...rest.reverse(), ...o));
|
|
408
451
|
case ARRAY_TYPE:
|
|
409
|
-
return [...o, ...rest];
|
|
452
|
+
return copyMeta(o, [...o, ...rest]);
|
|
410
453
|
case MAP_TYPE:
|
|
411
454
|
m = new Map(o);
|
|
412
455
|
for (const x of rest) {
|
|
@@ -417,7 +460,7 @@ export function conj(...xs) {
|
|
|
417
460
|
else m.set(x[0], x[1]);
|
|
418
461
|
}
|
|
419
462
|
|
|
420
|
-
return m;
|
|
463
|
+
return copyMeta(o, m);
|
|
421
464
|
case LAZY_ITERABLE_TYPE:
|
|
422
465
|
return lazy(function* () {
|
|
423
466
|
yield* rest;
|
|
@@ -431,7 +474,7 @@ export function conj(...xs) {
|
|
|
431
474
|
else o2[x[0]] = x[1];
|
|
432
475
|
}
|
|
433
476
|
|
|
434
|
-
return o2;
|
|
477
|
+
return copyMeta(o, o2);
|
|
435
478
|
default:
|
|
436
479
|
throw new Error(
|
|
437
480
|
'Illegal argument: conj expects a Set, Array, List, Map, or Object as the first argument.'
|
|
@@ -447,6 +490,7 @@ export function disj_BANG_(s, ...xs) {
|
|
|
447
490
|
}
|
|
448
491
|
|
|
449
492
|
export function disj(s, ...xs) {
|
|
493
|
+
if (s == null) return s;
|
|
450
494
|
const s1 = new s.constructor([...s]);
|
|
451
495
|
return disj_BANG_(s1, ...xs);
|
|
452
496
|
}
|
|
@@ -503,26 +547,29 @@ export function println(...args) {
|
|
|
503
547
|
}
|
|
504
548
|
|
|
505
549
|
export function nth(coll, idx, orElse) {
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
550
|
+
const hasDefault = arguments.length > 2;
|
|
551
|
+
// nil coll puns to nil, like Clojure
|
|
552
|
+
if (coll == null) return hasDefault ? orElse : null;
|
|
553
|
+
// "found" is decided by the index bound, not the value. An in-bounds element
|
|
554
|
+
// that happens to be undefined is still found.
|
|
555
|
+
if (Array.isArray(coll)) {
|
|
556
|
+
if (idx >= 0 && idx < coll.length) {
|
|
557
|
+
return coll[idx];
|
|
558
|
+
}
|
|
559
|
+
} else if (idx >= 0) {
|
|
560
|
+
// non-array: skip whole chunks instead of counting elements (handles
|
|
561
|
+
// infinite seqs since it stops once idx is reached)
|
|
562
|
+
const next = chunkCursor(coll);
|
|
563
|
+
let base = 0;
|
|
564
|
+
let ch;
|
|
565
|
+
while ((ch = next()) !== null) {
|
|
566
|
+
if (idx < base + ch.length) return ch[idx - base];
|
|
567
|
+
base += ch.length;
|
|
523
568
|
}
|
|
524
569
|
}
|
|
525
|
-
return
|
|
570
|
+
// out of bounds. With a default return it, otherwise throw like Clojure
|
|
571
|
+
if (hasDefault) return orElse;
|
|
572
|
+
throw new Error('Index out of bounds: ' + idx);
|
|
526
573
|
}
|
|
527
574
|
|
|
528
575
|
export function get(coll, key, otherwise = undefined) {
|
|
@@ -586,6 +633,21 @@ export function seqable_QMARK_(x) {
|
|
|
586
633
|
);
|
|
587
634
|
}
|
|
588
635
|
|
|
636
|
+
// squint has no distinct MapEntry type (map entries are plain 2-element
|
|
637
|
+
// arrays). We tag entries produced from a map with this marker symbol so
|
|
638
|
+
// map-entry? can tell them apart from ordinary vectors. Symbol-keyed props are
|
|
639
|
+
// invisible to =, into, iteration and JSON, so the effect is contained.
|
|
640
|
+
const MAP_ENTRY = Symbol('squint.lang.map-entry');
|
|
641
|
+
|
|
642
|
+
function tagMapEntry(e) {
|
|
643
|
+
e[MAP_ENTRY] = true;
|
|
644
|
+
return e;
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
export function map_entry_QMARK_(x) {
|
|
648
|
+
return Array.isArray(x) && x[MAP_ENTRY] === true;
|
|
649
|
+
}
|
|
650
|
+
|
|
589
651
|
export function iterable(x) {
|
|
590
652
|
// nil puns to empty iterable, support passing nil to first/rest/reduce, etc.
|
|
591
653
|
if (x === null || x === undefined) {
|
|
@@ -597,7 +659,7 @@ export function iterable(x) {
|
|
|
597
659
|
if (x[Symbol.iterator]) {
|
|
598
660
|
return x;
|
|
599
661
|
}
|
|
600
|
-
if (x instanceof Object) return Object.entries(x);
|
|
662
|
+
if (x instanceof Object) return Object.entries(x).map(tagMapEntry);
|
|
601
663
|
throw new TypeError(`${x} is not iterable`);
|
|
602
664
|
}
|
|
603
665
|
|
|
@@ -624,12 +686,24 @@ export function seq(x) {
|
|
|
624
686
|
}
|
|
625
687
|
|
|
626
688
|
export function first(coll) {
|
|
689
|
+
if (coll == null) return undefined;
|
|
690
|
+
if (Array.isArray(coll)) return coll[0];
|
|
691
|
+
if (coll instanceof LazyIterable) {
|
|
692
|
+
coll.force();
|
|
693
|
+
return coll.chunk === null ? undefined : coll.chunk[0];
|
|
694
|
+
}
|
|
627
695
|
// destructuring uses iterable protocol
|
|
628
696
|
const [first] = iterable(coll);
|
|
629
697
|
return first;
|
|
630
698
|
}
|
|
631
699
|
|
|
632
700
|
export function second(coll) {
|
|
701
|
+
if (coll instanceof LazyIterable) {
|
|
702
|
+
coll.force();
|
|
703
|
+
const ch = coll.chunk;
|
|
704
|
+
if (ch === null) return undefined;
|
|
705
|
+
return ch.length > 1 ? ch[1] : first(coll._rest);
|
|
706
|
+
}
|
|
633
707
|
const [_, v] = iterable(coll);
|
|
634
708
|
return v;
|
|
635
709
|
}
|
|
@@ -639,13 +713,20 @@ export function ffirst(coll) {
|
|
|
639
713
|
}
|
|
640
714
|
|
|
641
715
|
export function rest(coll) {
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
716
|
+
// chunk-aware: drop the first element of the first chunk, keep the rest of
|
|
717
|
+
// the chain chunked (preserves chunkedness, unlike re-iterating element-wise)
|
|
718
|
+
const cell = chunkCells(coll);
|
|
719
|
+
cell.force();
|
|
720
|
+
const ch = cell.chunk;
|
|
721
|
+
if (ch === null) return cell; // (rest ()) is ()
|
|
722
|
+
if (ch.length > 1) {
|
|
723
|
+
const c = new LazyIterable(null);
|
|
724
|
+
c.realized = true;
|
|
725
|
+
c.chunk = ch.slice(1);
|
|
726
|
+
c._rest = cell._rest;
|
|
727
|
+
return c;
|
|
728
|
+
}
|
|
729
|
+
return cell._rest; // first chunk had one element; the next cell is the rest
|
|
649
730
|
}
|
|
650
731
|
|
|
651
732
|
class Reduced {
|
|
@@ -660,16 +741,15 @@ class Reduced {
|
|
|
660
741
|
|
|
661
742
|
export function last(coll) {
|
|
662
743
|
coll = iterable(coll);
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
case ARRAY_TYPE:
|
|
666
|
-
return coll[coll.length - 1];
|
|
667
|
-
default:
|
|
668
|
-
for (const x of coll) {
|
|
669
|
-
lastEl = x;
|
|
670
|
-
}
|
|
671
|
-
return lastEl;
|
|
744
|
+
if (Array.isArray(coll)) {
|
|
745
|
+
return coll[coll.length - 1];
|
|
672
746
|
}
|
|
747
|
+
// non-array: walk chunks, keep the last chunk's last element
|
|
748
|
+
const next = chunkCursor(coll);
|
|
749
|
+
let lastEl;
|
|
750
|
+
let ch;
|
|
751
|
+
while ((ch = next()) !== null) lastEl = ch[ch.length - 1];
|
|
752
|
+
return lastEl;
|
|
673
753
|
}
|
|
674
754
|
|
|
675
755
|
export function reduced(x) {
|
|
@@ -682,31 +762,43 @@ export function reduced_QMARK_(x) {
|
|
|
682
762
|
|
|
683
763
|
export function reduce(f, arg1, arg2) {
|
|
684
764
|
f = __toFn(f);
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
765
|
+
const hasInit = arguments.length !== 2;
|
|
766
|
+
const coll = hasInit ? arg2 : arg1;
|
|
767
|
+
let val = hasInit ? arg1 : undefined;
|
|
768
|
+
|
|
769
|
+
// fast path: index loop over an array
|
|
770
|
+
if (Array.isArray(coll)) {
|
|
771
|
+
let i = 0;
|
|
772
|
+
if (!hasInit) {
|
|
773
|
+
if (coll.length === 0) return f();
|
|
774
|
+
val = coll[0];
|
|
775
|
+
i = 1;
|
|
694
776
|
}
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
777
|
+
if (val instanceof Reduced) return val.value;
|
|
778
|
+
for (; i < coll.length; i++) {
|
|
779
|
+
val = f(val, coll[i]);
|
|
780
|
+
if (val instanceof Reduced) return val.value;
|
|
781
|
+
}
|
|
782
|
+
return val;
|
|
700
783
|
}
|
|
701
|
-
|
|
702
|
-
|
|
784
|
+
|
|
785
|
+
// non-array: walk chunks (chunked cell or any other seqable)
|
|
786
|
+
const next = chunkCursor(coll);
|
|
787
|
+
let ch = next();
|
|
788
|
+
let i = 0;
|
|
789
|
+
if (!hasInit) {
|
|
790
|
+
if (ch === null) return f();
|
|
791
|
+
val = ch[0];
|
|
792
|
+
i = 1;
|
|
703
793
|
}
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
val = val
|
|
708
|
-
|
|
794
|
+
if (val instanceof Reduced) return val.value;
|
|
795
|
+
while (ch !== null) {
|
|
796
|
+
for (; i < ch.length; i++) {
|
|
797
|
+
val = f(val, ch[i]);
|
|
798
|
+
if (val instanceof Reduced) return val.value;
|
|
709
799
|
}
|
|
800
|
+
ch = next();
|
|
801
|
+
i = 0;
|
|
710
802
|
}
|
|
711
803
|
return val;
|
|
712
804
|
}
|
|
@@ -739,42 +831,152 @@ function* _reductions3(f, init, coll) {
|
|
|
739
831
|
export function reductions(f, arg1, arg2) {
|
|
740
832
|
f = __toFn(f);
|
|
741
833
|
if (arguments.length === 2) {
|
|
834
|
+
const it = es6_iterator(iterable(arg1));
|
|
742
835
|
return lazy(function* () {
|
|
743
|
-
yield* _reductions2(f,
|
|
836
|
+
yield* _reductions2(f, it);
|
|
744
837
|
});
|
|
745
838
|
}
|
|
839
|
+
const it = es6_iterator(iterable(arg2));
|
|
746
840
|
return lazy(function* () {
|
|
747
|
-
yield* _reductions3(f, arg1,
|
|
841
|
+
yield* _reductions3(f, arg1, it);
|
|
748
842
|
});
|
|
749
843
|
}
|
|
750
844
|
|
|
751
|
-
|
|
845
|
+
// Deprecated: lazy values are now cached, so reuse no longer recomputes. Kept
|
|
846
|
+
// for API compatibility; remove in a future release.
|
|
752
847
|
export function warn_on_lazy_reusage_BANG_() {
|
|
753
|
-
|
|
848
|
+
console.warn(
|
|
849
|
+
'warn-on-lazy-reusage! is deprecated and does nothing: lazy values are now cached.',
|
|
850
|
+
);
|
|
754
851
|
}
|
|
755
852
|
|
|
853
|
+
const CHUNK_SIZE = 32;
|
|
854
|
+
|
|
855
|
+
// One cell of a self-caching chunked seq. `step` is a thunk returning
|
|
856
|
+
// [nonEmptyChunkArray, nextStep] or null at the end. See doc/dev/lazy-seqs.md.
|
|
756
857
|
class LazyIterable {
|
|
757
|
-
constructor(
|
|
758
|
-
this.
|
|
759
|
-
this.
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
858
|
+
constructor(step) {
|
|
859
|
+
this.step = step;
|
|
860
|
+
this.realized = false;
|
|
861
|
+
this.chunk = null; // array, or null when this is the terminal (empty) cell
|
|
862
|
+
this._rest = null;
|
|
863
|
+
}
|
|
864
|
+
force() {
|
|
865
|
+
if (!this.realized) {
|
|
866
|
+
this.realized = true;
|
|
867
|
+
const r = this.step();
|
|
868
|
+
this.step = null;
|
|
869
|
+
if (r !== null && r !== undefined) {
|
|
870
|
+
this.chunk = r[0];
|
|
871
|
+
this._rest = new LazyIterable(r[1]);
|
|
768
872
|
}
|
|
769
873
|
}
|
|
770
|
-
return this
|
|
874
|
+
return this;
|
|
875
|
+
}
|
|
876
|
+
[Symbol.iterator]() {
|
|
877
|
+
let cell = this;
|
|
878
|
+
let i = 0;
|
|
879
|
+
return {
|
|
880
|
+
next() {
|
|
881
|
+
for (;;) {
|
|
882
|
+
cell.force();
|
|
883
|
+
const ch = cell.chunk;
|
|
884
|
+
if (ch === null) return { value: undefined, done: true };
|
|
885
|
+
if (i < ch.length) return { value: ch[i++], done: false };
|
|
886
|
+
cell = cell._rest;
|
|
887
|
+
i = 0;
|
|
888
|
+
}
|
|
889
|
+
},
|
|
890
|
+
[Symbol.iterator]() {
|
|
891
|
+
return this;
|
|
892
|
+
},
|
|
893
|
+
};
|
|
771
894
|
}
|
|
772
895
|
}
|
|
773
896
|
|
|
774
897
|
LazyIterable.prototype[IIterable] = true; // Closure compatibility
|
|
775
898
|
|
|
899
|
+
// One-element chunks: an unchunked seq, realized one element at a time.
|
|
900
|
+
function unchunkedSteps(iter) {
|
|
901
|
+
const step = () => {
|
|
902
|
+
const r = iter.next();
|
|
903
|
+
return r.done ? null : [[r.value], step];
|
|
904
|
+
};
|
|
905
|
+
return step;
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
// f is a zero-arg generator function; its result is an unchunked lazy seq.
|
|
776
909
|
export function lazy(f) {
|
|
777
|
-
return new LazyIterable(f);
|
|
910
|
+
return new LazyIterable(unchunkedSteps(f()));
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
// gen(it) over a hoisted iterator: keeps the input head unpinned (streaming)
|
|
914
|
+
function lazyIter(coll, gen) {
|
|
915
|
+
const it = es6_iterator(iterable(coll));
|
|
916
|
+
return lazy(() => gen(it));
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
// A chunked view of any seqable for chunk-aware ops, preserving chunkedness:
|
|
920
|
+
// cells pass through, arrays slice into CHUNK_SIZE batches, others stay unchunked.
|
|
921
|
+
function chunkCells(coll) {
|
|
922
|
+
if (coll instanceof LazyIterable) return coll;
|
|
923
|
+
if (Array.isArray(coll)) {
|
|
924
|
+
const step = (pos) => () => {
|
|
925
|
+
if (pos >= coll.length) return null;
|
|
926
|
+
const end = Math.min(pos + CHUNK_SIZE, coll.length);
|
|
927
|
+
return [coll.slice(pos, end), step(end)];
|
|
928
|
+
};
|
|
929
|
+
return new LazyIterable(step(0));
|
|
930
|
+
}
|
|
931
|
+
return new LazyIterable(unchunkedSteps(es6_iterator(iterable(coll))));
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
// A cursor over a seq's chunks for realizers: returns a function yielding the
|
|
935
|
+
// next chunk array or null. Drive it with an inline loop (keeps an accumulator a
|
|
936
|
+
// plain local, unlike a callback). Callers keep their own array shortcut.
|
|
937
|
+
function chunkCursor(coll) {
|
|
938
|
+
if (coll instanceof LazyIterable) {
|
|
939
|
+
let cell = coll;
|
|
940
|
+
return () => {
|
|
941
|
+
if (cell === null) return null;
|
|
942
|
+
cell.force();
|
|
943
|
+
const ch = cell.chunk;
|
|
944
|
+
cell = ch === null ? null : cell._rest;
|
|
945
|
+
return ch;
|
|
946
|
+
};
|
|
947
|
+
}
|
|
948
|
+
const it = es6_iterator(iterable(coll));
|
|
949
|
+
return () => {
|
|
950
|
+
const b = [];
|
|
951
|
+
for (let i = 0; i < CHUNK_SIZE; i++) {
|
|
952
|
+
const r = it.next();
|
|
953
|
+
if (r.done) break;
|
|
954
|
+
b.push(r.value);
|
|
955
|
+
}
|
|
956
|
+
return b.length === 0 ? null : b;
|
|
957
|
+
};
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
// Build a lazy seq transforming each input chunk via xf(chunk, baseIndex) -> new
|
|
961
|
+
// chunk array, preserving chunkedness. Empty results are skipped (e.g. filter).
|
|
962
|
+
// baseIndex is the input element count before the chunk, for indexed ops.
|
|
963
|
+
function mapChunks(coll, xf) {
|
|
964
|
+
const src = chunkCells(coll);
|
|
965
|
+
const step = (cell, base) => () => {
|
|
966
|
+
let c = cell;
|
|
967
|
+
let b = base;
|
|
968
|
+
for (;;) {
|
|
969
|
+
c.force();
|
|
970
|
+
const ch = c.chunk;
|
|
971
|
+
if (ch === null) return null;
|
|
972
|
+
const out = xf(ch, b);
|
|
973
|
+
const rest = c._rest;
|
|
974
|
+
b += ch.length;
|
|
975
|
+
if (out.length !== 0) return [out, step(rest, b)];
|
|
976
|
+
c = rest;
|
|
977
|
+
}
|
|
978
|
+
};
|
|
979
|
+
return new LazyIterable(step(src, 0));
|
|
778
980
|
}
|
|
779
981
|
|
|
780
982
|
export class Cons {
|
|
@@ -782,24 +984,35 @@ export class Cons {
|
|
|
782
984
|
this.x = x;
|
|
783
985
|
this.coll = coll;
|
|
784
986
|
}
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
987
|
+
[Symbol.iterator]() {
|
|
988
|
+
const x = this.x;
|
|
989
|
+
let coll = this.coll;
|
|
990
|
+
let started = false;
|
|
991
|
+
let it = null;
|
|
992
|
+
return {
|
|
993
|
+
next() {
|
|
994
|
+
if (!started) {
|
|
995
|
+
started = true;
|
|
996
|
+
return { value: x, done: false };
|
|
997
|
+
}
|
|
998
|
+
if (!it) {
|
|
999
|
+
it = es6_iterator(iterable(coll));
|
|
1000
|
+
coll = null; // release the tail head so a single pass streams
|
|
1001
|
+
}
|
|
1002
|
+
return it.next();
|
|
1003
|
+
},
|
|
1004
|
+
[Symbol.iterator]() {
|
|
1005
|
+
return this;
|
|
1006
|
+
},
|
|
1007
|
+
};
|
|
788
1008
|
}
|
|
789
1009
|
}
|
|
790
1010
|
|
|
791
1011
|
export function cons(x, coll) {
|
|
792
1012
|
return new Cons(x, coll);
|
|
793
|
-
// return lazy(function* () {
|
|
794
|
-
// yield x;
|
|
795
|
-
// yield* iterable(coll);
|
|
796
|
-
// });
|
|
797
1013
|
}
|
|
798
1014
|
|
|
799
1015
|
export function map(f, ...colls) {
|
|
800
|
-
// if (! (f instanceof Function)) {
|
|
801
|
-
// throw new Error(`Argument f must be a function but is ${typeof(f)}`);
|
|
802
|
-
// }
|
|
803
1016
|
f = __toFn(f);
|
|
804
1017
|
switch (colls.length) {
|
|
805
1018
|
case 0:
|
|
@@ -822,14 +1035,14 @@ export function map(f, ...colls) {
|
|
|
822
1035
|
};
|
|
823
1036
|
};
|
|
824
1037
|
case 1:
|
|
825
|
-
return
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
1038
|
+
return mapChunks(colls[0], (ch) => {
|
|
1039
|
+
const out = new Array(ch.length);
|
|
1040
|
+
for (let i = 0; i < ch.length; i++) out[i] = f(ch[i]);
|
|
1041
|
+
return out;
|
|
829
1042
|
});
|
|
830
|
-
default:
|
|
1043
|
+
default: {
|
|
1044
|
+
const iters = colls.map((coll) => es6_iterator(iterable(coll)));
|
|
831
1045
|
return lazy(function* () {
|
|
832
|
-
const iters = colls.map((coll) => es6_iterator(iterable(coll)));
|
|
833
1046
|
while (true) {
|
|
834
1047
|
const args = [];
|
|
835
1048
|
for (const i of iters) {
|
|
@@ -842,45 +1055,41 @@ export function map(f, ...colls) {
|
|
|
842
1055
|
yield f(...args);
|
|
843
1056
|
}
|
|
844
1057
|
});
|
|
1058
|
+
}
|
|
845
1059
|
}
|
|
846
1060
|
}
|
|
847
1061
|
|
|
848
|
-
|
|
1062
|
+
// 0/1 arities pass through to rf; step(rf) is the 2-arity reducer
|
|
1063
|
+
function transducer(step) {
|
|
849
1064
|
return (rf) => {
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
return rf();
|
|
854
|
-
case 1:
|
|
855
|
-
return rf(args[0]);
|
|
856
|
-
case 2: {
|
|
857
|
-
const result = args[0];
|
|
858
|
-
const input = args[1];
|
|
859
|
-
if (truth_(pred(input))) {
|
|
860
|
-
return rf(result, input);
|
|
861
|
-
} else return result;
|
|
862
|
-
}
|
|
863
|
-
}
|
|
864
|
-
};
|
|
1065
|
+
const s = step(rf);
|
|
1066
|
+
return (...args) =>
|
|
1067
|
+
args.length === 0 ? rf() : args.length === 1 ? rf(args[0]) : s(args[0], args[1]);
|
|
865
1068
|
};
|
|
866
1069
|
}
|
|
867
1070
|
|
|
1071
|
+
function filter1(pred) {
|
|
1072
|
+
return transducer((rf) => (r, x) => (truth_(pred(x)) ? rf(r, x) : r));
|
|
1073
|
+
}
|
|
1074
|
+
|
|
868
1075
|
export function filter(pred, coll) {
|
|
869
1076
|
if (arguments.length === 1) {
|
|
870
1077
|
return filter1(pred);
|
|
871
1078
|
}
|
|
872
1079
|
pred = __toFn(pred);
|
|
873
|
-
return
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
1080
|
+
return mapChunks(coll, (ch) => {
|
|
1081
|
+
const out = [];
|
|
1082
|
+
for (let i = 0; i < ch.length; i++) {
|
|
1083
|
+
const x = ch[i];
|
|
1084
|
+
if (truth_(pred(x))) out.push(x);
|
|
878
1085
|
}
|
|
1086
|
+
return out;
|
|
879
1087
|
});
|
|
880
1088
|
}
|
|
881
1089
|
|
|
882
1090
|
export function filterv(pred, coll) {
|
|
883
|
-
|
|
1091
|
+
// filter is chunked; vec bulk-appends its chunks
|
|
1092
|
+
return pushAll([], filter(pred, coll));
|
|
884
1093
|
}
|
|
885
1094
|
|
|
886
1095
|
export function remove(pred, coll) {
|
|
@@ -891,19 +1100,10 @@ export function remove(pred, coll) {
|
|
|
891
1100
|
}
|
|
892
1101
|
|
|
893
1102
|
function map_indexed1(f) {
|
|
894
|
-
return (rf) => {
|
|
1103
|
+
return transducer((rf) => {
|
|
895
1104
|
let i = -1;
|
|
896
|
-
return (
|
|
897
|
-
|
|
898
|
-
case 0:
|
|
899
|
-
return rf();
|
|
900
|
-
case 1:
|
|
901
|
-
return rf(args[0]);
|
|
902
|
-
case 2:
|
|
903
|
-
return rf(args[0], f(((i = i + 1), i), args[1]));
|
|
904
|
-
}
|
|
905
|
-
};
|
|
906
|
-
};
|
|
1105
|
+
return (r, x) => rf(r, f(++i, x));
|
|
1106
|
+
});
|
|
907
1107
|
}
|
|
908
1108
|
|
|
909
1109
|
export function map_indexed(f, coll) {
|
|
@@ -911,50 +1111,33 @@ export function map_indexed(f, coll) {
|
|
|
911
1111
|
if (arguments.length === 1) {
|
|
912
1112
|
return map_indexed1(f);
|
|
913
1113
|
}
|
|
914
|
-
return
|
|
915
|
-
|
|
916
|
-
for (
|
|
917
|
-
|
|
918
|
-
idx++;
|
|
919
|
-
}
|
|
1114
|
+
return mapChunks(coll, (ch, base) => {
|
|
1115
|
+
const out = new Array(ch.length);
|
|
1116
|
+
for (let i = 0; i < ch.length; i++) out[i] = f(base + i, ch[i]);
|
|
1117
|
+
return out;
|
|
920
1118
|
});
|
|
921
1119
|
}
|
|
922
1120
|
|
|
923
1121
|
function keep_indexed2(f, coll) {
|
|
924
1122
|
f = __toFn(f);
|
|
925
|
-
return
|
|
926
|
-
|
|
927
|
-
for (
|
|
928
|
-
const v = f(
|
|
929
|
-
if (truth_(v))
|
|
930
|
-
idx++;
|
|
1123
|
+
return mapChunks(coll, (ch, base) => {
|
|
1124
|
+
const out = [];
|
|
1125
|
+
for (let i = 0; i < ch.length; i++) {
|
|
1126
|
+
const v = f(base + i, ch[i]);
|
|
1127
|
+
if (truth_(v)) out.push(v);
|
|
931
1128
|
}
|
|
1129
|
+
return out;
|
|
932
1130
|
});
|
|
933
1131
|
}
|
|
934
1132
|
|
|
935
1133
|
function keep_indexed1(f) {
|
|
936
|
-
return (rf) => {
|
|
1134
|
+
return transducer((rf) => {
|
|
937
1135
|
let ia = -1;
|
|
938
|
-
return (
|
|
939
|
-
const
|
|
940
|
-
|
|
941
|
-
return rf();
|
|
942
|
-
}
|
|
943
|
-
if (al === 1) {
|
|
944
|
-
return rf(args[0]);
|
|
945
|
-
}
|
|
946
|
-
if (al === 2) {
|
|
947
|
-
const result = args[0];
|
|
948
|
-
const input = args[1];
|
|
949
|
-
ia++;
|
|
950
|
-
const v = f(ia, input);
|
|
951
|
-
if (v == null) {
|
|
952
|
-
return result;
|
|
953
|
-
}
|
|
954
|
-
return rf(result, v);
|
|
955
|
-
}
|
|
1136
|
+
return (r, x) => {
|
|
1137
|
+
const v = f(++ia, x);
|
|
1138
|
+
return v == null ? r : rf(r, v);
|
|
956
1139
|
};
|
|
957
|
-
};
|
|
1140
|
+
});
|
|
958
1141
|
}
|
|
959
1142
|
|
|
960
1143
|
export function keep_indexed(f, coll) {
|
|
@@ -970,7 +1153,12 @@ export function str(...xs) {
|
|
|
970
1153
|
}
|
|
971
1154
|
|
|
972
1155
|
export function name(x) {
|
|
973
|
-
if (typeof x === 'string')
|
|
1156
|
+
if (typeof x === 'string') {
|
|
1157
|
+
// keywords/symbols are strings in squint; name is the part after the "/"
|
|
1158
|
+
// ns separator (consistent with `namespace`, which returns the part before)
|
|
1159
|
+
const i = x.indexOf('/');
|
|
1160
|
+
return i >= 1 ? x.slice(i + 1) : x;
|
|
1161
|
+
}
|
|
974
1162
|
throw new Error("Doesn't support name: " + typeof x);
|
|
975
1163
|
}
|
|
976
1164
|
|
|
@@ -1055,22 +1243,29 @@ export function compare_and_set_BANG_(atm, oldv, newv) {
|
|
|
1055
1243
|
}
|
|
1056
1244
|
|
|
1057
1245
|
export function range(begin, end, step) {
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1246
|
+
// range is a chunked source: it realizes CHUNK_SIZE values at a time
|
|
1247
|
+
let b = begin,
|
|
1248
|
+
e = end,
|
|
1249
|
+
s = step;
|
|
1250
|
+
if (end === undefined) {
|
|
1251
|
+
b = 0;
|
|
1252
|
+
e = begin;
|
|
1253
|
+
}
|
|
1254
|
+
const start = b || 0;
|
|
1255
|
+
s = step ?? 1;
|
|
1256
|
+
const ascending = s >= 0;
|
|
1257
|
+
const more = (i) => e === undefined || (ascending && i < e) || (!ascending && e < i);
|
|
1258
|
+
const mkStep = (from) => () => {
|
|
1259
|
+
if (!more(from)) return null;
|
|
1260
|
+
const out = [];
|
|
1261
|
+
let i = from;
|
|
1262
|
+
while (out.length < CHUNK_SIZE && more(i)) {
|
|
1263
|
+
out.push(i);
|
|
1071
1264
|
i += s;
|
|
1072
1265
|
}
|
|
1073
|
-
|
|
1266
|
+
return [out, mkStep(i)];
|
|
1267
|
+
};
|
|
1268
|
+
return new LazyIterable(mkStep(start));
|
|
1074
1269
|
}
|
|
1075
1270
|
|
|
1076
1271
|
export function re_matches(re, s) {
|
|
@@ -1127,7 +1322,7 @@ export function vector(...args) {
|
|
|
1127
1322
|
export const array = vector;
|
|
1128
1323
|
|
|
1129
1324
|
export function vector_QMARK_(x) {
|
|
1130
|
-
return
|
|
1325
|
+
return isVectorArray(x);
|
|
1131
1326
|
}
|
|
1132
1327
|
|
|
1133
1328
|
export function mapv(...args) {
|
|
@@ -1143,9 +1338,12 @@ export function mapv(...args) {
|
|
|
1143
1338
|
}
|
|
1144
1339
|
return ret;
|
|
1145
1340
|
} else {
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1341
|
+
// non-array: map whole chunks straight into the result array
|
|
1342
|
+
const ret = [];
|
|
1343
|
+
const next = chunkCursor(iter);
|
|
1344
|
+
let ch;
|
|
1345
|
+
while ((ch = next()) !== null) {
|
|
1346
|
+
for (let i = 0; i < ch.length; i++) ret.push(f(ch[i]));
|
|
1149
1347
|
}
|
|
1150
1348
|
return ret;
|
|
1151
1349
|
}
|
|
@@ -1153,12 +1351,32 @@ export function mapv(...args) {
|
|
|
1153
1351
|
return [...map(...args)];
|
|
1154
1352
|
}
|
|
1155
1353
|
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1354
|
+
// Append every element of `from` to array `out`, bulk-appending whole chunks
|
|
1355
|
+
// for a chunked seq. Returns out.
|
|
1356
|
+
function pushAll(out, from) {
|
|
1357
|
+
if (from instanceof LazyIterable) {
|
|
1358
|
+
let cell = from;
|
|
1359
|
+
for (;;) {
|
|
1360
|
+
cell.force();
|
|
1361
|
+
const ch = cell.chunk;
|
|
1362
|
+
if (ch === null) return out;
|
|
1363
|
+
Array.prototype.push.apply(out, ch);
|
|
1364
|
+
cell = cell._rest;
|
|
1365
|
+
}
|
|
1160
1366
|
}
|
|
1161
|
-
|
|
1367
|
+
for (const x of iterable(from)) out.push(x);
|
|
1368
|
+
return out;
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
// Materialize a seq into a fresh, mutable array (bulk-copies chunked seqs).
|
|
1372
|
+
function toArray(coll) {
|
|
1373
|
+
if (coll instanceof LazyIterable) return pushAll([], coll);
|
|
1374
|
+
return [...iterable(coll)];
|
|
1375
|
+
}
|
|
1376
|
+
|
|
1377
|
+
export function vec(x) {
|
|
1378
|
+
if (isVectorArray(x)) return x;
|
|
1379
|
+
return pushAll([], x);
|
|
1162
1380
|
}
|
|
1163
1381
|
|
|
1164
1382
|
export function set(coll) {
|
|
@@ -1223,12 +1441,54 @@ export function array_QMARK_(x) {
|
|
|
1223
1441
|
return Array.isArray(x);
|
|
1224
1442
|
}
|
|
1225
1443
|
|
|
1444
|
+
const CONCAT_DONE = Symbol('concat-done');
|
|
1445
|
+
|
|
1226
1446
|
function concat1(colls) {
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1447
|
+
// chunk-aware: pass each coll's chunks through, preserving chunkedness. Each
|
|
1448
|
+
// coll head is released once consumed so a single pass streams.
|
|
1449
|
+
const isArr = Array.isArray(colls);
|
|
1450
|
+
const arr = isArr ? colls.slice() : null;
|
|
1451
|
+
const collIter = isArr ? null : es6_iterator(iterable(colls));
|
|
1452
|
+
let idx = 0;
|
|
1453
|
+
const nextColl = () => {
|
|
1454
|
+
if (isArr) {
|
|
1455
|
+
if (idx >= arr.length) return CONCAT_DONE;
|
|
1456
|
+
const c = arr[idx];
|
|
1457
|
+
arr[idx] = null;
|
|
1458
|
+
idx++;
|
|
1459
|
+
return c;
|
|
1230
1460
|
}
|
|
1231
|
-
|
|
1461
|
+
const r = collIter.next();
|
|
1462
|
+
return r.done ? CONCAT_DONE : r.value;
|
|
1463
|
+
};
|
|
1464
|
+
// src is null, a chunked cell, or {a, pos} for an array (raw-array fast path:
|
|
1465
|
+
// no per-coll wrapper). Continuations carry immutable state, so a single pass
|
|
1466
|
+
// streams.
|
|
1467
|
+
const step = (src) => () => {
|
|
1468
|
+
for (;;) {
|
|
1469
|
+
if (src !== null) {
|
|
1470
|
+
if (src instanceof LazyIterable) {
|
|
1471
|
+
src.force();
|
|
1472
|
+
if (src.chunk !== null) return [src.chunk, step(src._rest)];
|
|
1473
|
+
src = null;
|
|
1474
|
+
} else {
|
|
1475
|
+
const a = src.a;
|
|
1476
|
+
const pos = src.pos;
|
|
1477
|
+
if (pos < a.length) {
|
|
1478
|
+
const end = Math.min(pos + CHUNK_SIZE, a.length);
|
|
1479
|
+
// slice (copy) so a cached chunk never aliases the caller's array
|
|
1480
|
+
return [a.slice(pos, end), step({ a, pos: end })];
|
|
1481
|
+
}
|
|
1482
|
+
src = null;
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1485
|
+
const nc = nextColl();
|
|
1486
|
+
if (nc === CONCAT_DONE) return null;
|
|
1487
|
+
src =
|
|
1488
|
+
nc instanceof LazyIterable ? nc : Array.isArray(nc) ? { a: nc, pos: 0 } : chunkCells(nc);
|
|
1489
|
+
}
|
|
1490
|
+
};
|
|
1491
|
+
return new LazyIterable(step(null));
|
|
1232
1492
|
}
|
|
1233
1493
|
|
|
1234
1494
|
export function concat(...colls) {
|
|
@@ -1243,10 +1503,8 @@ concat[IApply__apply] = (colls) => {
|
|
|
1243
1503
|
export function mapcat(f, ...colls) {
|
|
1244
1504
|
if (colls.length === 0) {
|
|
1245
1505
|
return comp(map(f), cat);
|
|
1246
|
-
} else {
|
|
1247
|
-
const mapped = map(f, ...colls);
|
|
1248
|
-
return concat1(mapped);
|
|
1249
1506
|
}
|
|
1507
|
+
return concat1(map(f, ...colls));
|
|
1250
1508
|
}
|
|
1251
1509
|
|
|
1252
1510
|
export function identity(x) {
|
|
@@ -1254,8 +1512,8 @@ export function identity(x) {
|
|
|
1254
1512
|
}
|
|
1255
1513
|
|
|
1256
1514
|
export function interleave(...colls) {
|
|
1515
|
+
const iters = colls.map((coll) => es6_iterator(iterable(coll)));
|
|
1257
1516
|
return lazy(function* () {
|
|
1258
|
-
const iters = colls.map((coll) => es6_iterator(iterable(coll)));
|
|
1259
1517
|
while (true) {
|
|
1260
1518
|
const res = [];
|
|
1261
1519
|
for (const i of iters) {
|
|
@@ -1271,30 +1529,17 @@ export function interleave(...colls) {
|
|
|
1271
1529
|
}
|
|
1272
1530
|
|
|
1273
1531
|
function interpose1(sep) {
|
|
1274
|
-
return (rf) => {
|
|
1532
|
+
return transducer((rf) => {
|
|
1275
1533
|
let started = false;
|
|
1276
|
-
return (
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
case 1:
|
|
1281
|
-
return rf(args[0]);
|
|
1282
|
-
case 2: {
|
|
1283
|
-
if (started) {
|
|
1284
|
-
const sepr = rf(args[0], sep);
|
|
1285
|
-
if (reduced_QMARK_(sepr)) {
|
|
1286
|
-
return sepr;
|
|
1287
|
-
} else {
|
|
1288
|
-
return rf(sepr, args[1]);
|
|
1289
|
-
}
|
|
1290
|
-
} else {
|
|
1291
|
-
started = true;
|
|
1292
|
-
return rf(args[0], args[1]);
|
|
1293
|
-
}
|
|
1294
|
-
}
|
|
1534
|
+
return (r, x) => {
|
|
1535
|
+
if (!started) {
|
|
1536
|
+
started = true;
|
|
1537
|
+
return rf(r, x);
|
|
1295
1538
|
}
|
|
1539
|
+
const sepr = rf(r, sep);
|
|
1540
|
+
return reduced_QMARK_(sepr) ? sepr : rf(sepr, x);
|
|
1296
1541
|
};
|
|
1297
|
-
};
|
|
1542
|
+
});
|
|
1298
1543
|
}
|
|
1299
1544
|
|
|
1300
1545
|
export function interpose(sep, coll) {
|
|
@@ -1386,10 +1631,10 @@ export const partitionv = partition; // partition already returns a lazy of arra
|
|
|
1386
1631
|
export const partitionv_all = partition_all;
|
|
1387
1632
|
|
|
1388
1633
|
function partitionInternal(n, step, pad, coll, all) {
|
|
1389
|
-
return
|
|
1634
|
+
return lazyIter(coll, function* (it) {
|
|
1390
1635
|
let p = [];
|
|
1391
1636
|
let i = 0;
|
|
1392
|
-
for (const x of
|
|
1637
|
+
for (const x of it) {
|
|
1393
1638
|
if (i < n) {
|
|
1394
1639
|
p.push(x);
|
|
1395
1640
|
if (p.length === n) {
|
|
@@ -1461,8 +1706,8 @@ export function partition_by(f, coll) {
|
|
|
1461
1706
|
if (arguments.length === 1) {
|
|
1462
1707
|
return partition_by1(f);
|
|
1463
1708
|
}
|
|
1709
|
+
const iter = es6_iterator(coll);
|
|
1464
1710
|
return lazy(function* () {
|
|
1465
|
-
const iter = es6_iterator(coll);
|
|
1466
1711
|
const _fst = iter.next();
|
|
1467
1712
|
if (_fst.done) {
|
|
1468
1713
|
yield* null;
|
|
@@ -1495,7 +1740,7 @@ export function partition_by(f, coll) {
|
|
|
1495
1740
|
export function empty(coll) {
|
|
1496
1741
|
const type = typeConst(coll);
|
|
1497
1742
|
if (type != null) {
|
|
1498
|
-
return emptyOfType(type);
|
|
1743
|
+
return copyMeta(coll, emptyOfType(type));
|
|
1499
1744
|
} else {
|
|
1500
1745
|
throw new Error(`Can't create empty of ${typeof coll}`);
|
|
1501
1746
|
}
|
|
@@ -1561,7 +1806,13 @@ export function into(...args) {
|
|
|
1561
1806
|
case 1:
|
|
1562
1807
|
return args[0];
|
|
1563
1808
|
case 2:
|
|
1564
|
-
|
|
1809
|
+
// vector target bulk-appends chunks (copy preserves metadata); lists conj
|
|
1810
|
+
// at the head, other targets need conj!
|
|
1811
|
+
to = args[0] ?? [];
|
|
1812
|
+
if (isVectorArray(to)) {
|
|
1813
|
+
return pushAll(copy(to), args[1]);
|
|
1814
|
+
}
|
|
1815
|
+
return reduce(conj_BANG_, copy(to), args[1]);
|
|
1565
1816
|
case 3:
|
|
1566
1817
|
to = args[0];
|
|
1567
1818
|
xform = args[1];
|
|
@@ -1612,42 +1863,23 @@ export function ensure_reduced(x) {
|
|
|
1612
1863
|
}
|
|
1613
1864
|
|
|
1614
1865
|
function take1(n) {
|
|
1615
|
-
return (rf) => {
|
|
1866
|
+
return transducer((rf) => {
|
|
1616
1867
|
let na = n;
|
|
1617
|
-
return (
|
|
1618
|
-
const
|
|
1619
|
-
if (
|
|
1620
|
-
|
|
1621
|
-
}
|
|
1622
|
-
if (al === 1) {
|
|
1623
|
-
const result = args[0];
|
|
1624
|
-
return rf(result);
|
|
1625
|
-
}
|
|
1626
|
-
if (al === 2) {
|
|
1627
|
-
let result = args[0];
|
|
1628
|
-
const input = args[1];
|
|
1629
|
-
const n = na;
|
|
1630
|
-
const nn = ((na = na - 1), na);
|
|
1631
|
-
if (n > 0) {
|
|
1632
|
-
result = rf(result, input);
|
|
1633
|
-
}
|
|
1634
|
-
if (!(nn > 0)) {
|
|
1635
|
-
return ensure_reduced(result);
|
|
1636
|
-
} else {
|
|
1637
|
-
return result;
|
|
1638
|
-
}
|
|
1639
|
-
}
|
|
1868
|
+
return (r, x) => {
|
|
1869
|
+
const nn = --na + 1;
|
|
1870
|
+
if (nn > 0) r = rf(r, x);
|
|
1871
|
+
return nn > 1 ? r : ensure_reduced(r);
|
|
1640
1872
|
};
|
|
1641
|
-
};
|
|
1873
|
+
});
|
|
1642
1874
|
}
|
|
1643
1875
|
|
|
1644
1876
|
export function take(n, coll) {
|
|
1645
1877
|
if (arguments.length === 1) {
|
|
1646
1878
|
return take1(n);
|
|
1647
1879
|
}
|
|
1648
|
-
return
|
|
1880
|
+
return lazyIter(coll, function* (it) {
|
|
1649
1881
|
let i = n - 1;
|
|
1650
|
-
for (const x of
|
|
1882
|
+
for (const x of it) {
|
|
1651
1883
|
if (i-- >= 0) {
|
|
1652
1884
|
yield x;
|
|
1653
1885
|
}
|
|
@@ -1681,22 +1913,7 @@ export function take_last(n, coll) {
|
|
|
1681
1913
|
}
|
|
1682
1914
|
|
|
1683
1915
|
function take_while1(pred) {
|
|
1684
|
-
return (rf) =>
|
|
1685
|
-
return (...args) => {
|
|
1686
|
-
const al = args.length;
|
|
1687
|
-
if (al === 0) return rf();
|
|
1688
|
-
if (al === 1) return rf(args[0]);
|
|
1689
|
-
if (al === 2) {
|
|
1690
|
-
const result = args[0];
|
|
1691
|
-
const input = args[1];
|
|
1692
|
-
if (truth_(pred(input))) {
|
|
1693
|
-
return rf(result, input);
|
|
1694
|
-
} else {
|
|
1695
|
-
return reduced(result);
|
|
1696
|
-
}
|
|
1697
|
-
}
|
|
1698
|
-
};
|
|
1699
|
-
};
|
|
1916
|
+
return transducer((rf) => (r, x) => (truth_(pred(x)) ? rf(r, x) : reduced(r)));
|
|
1700
1917
|
}
|
|
1701
1918
|
|
|
1702
1919
|
export function take_while(pred, coll) {
|
|
@@ -1704,8 +1921,8 @@ export function take_while(pred, coll) {
|
|
|
1704
1921
|
if (arguments.length === 1) {
|
|
1705
1922
|
return take_while1(pred);
|
|
1706
1923
|
}
|
|
1707
|
-
return
|
|
1708
|
-
for (const o of
|
|
1924
|
+
return lazyIter(coll, function* (it) {
|
|
1925
|
+
for (const o of it) {
|
|
1709
1926
|
if (truth_(pred(o))) yield o;
|
|
1710
1927
|
else return;
|
|
1711
1928
|
}
|
|
@@ -1713,23 +1930,10 @@ export function take_while(pred, coll) {
|
|
|
1713
1930
|
}
|
|
1714
1931
|
|
|
1715
1932
|
function take_nth1(n) {
|
|
1716
|
-
return (rf) => {
|
|
1933
|
+
return transducer((rf) => {
|
|
1717
1934
|
let ia = -1;
|
|
1718
|
-
return (
|
|
1719
|
-
|
|
1720
|
-
if (al === 0) return rf();
|
|
1721
|
-
if (al === 1) return rf(args[0]);
|
|
1722
|
-
if (al === 2) {
|
|
1723
|
-
const result = args[0];
|
|
1724
|
-
const input = args[1];
|
|
1725
|
-
ia++;
|
|
1726
|
-
const i = ia;
|
|
1727
|
-
if (rem(i, n) === 0) {
|
|
1728
|
-
return rf(result, input);
|
|
1729
|
-
} else return result;
|
|
1730
|
-
}
|
|
1731
|
-
};
|
|
1732
|
-
};
|
|
1935
|
+
return (r, x) => (rem(++ia, n) === 0 ? rf(r, x) : r);
|
|
1936
|
+
});
|
|
1733
1937
|
}
|
|
1734
1938
|
|
|
1735
1939
|
export function take_nth(n, coll) {
|
|
@@ -1738,9 +1942,9 @@ export function take_nth(n, coll) {
|
|
|
1738
1942
|
return repeat(first(coll));
|
|
1739
1943
|
}
|
|
1740
1944
|
|
|
1741
|
-
return
|
|
1945
|
+
return lazyIter(coll, function* (it) {
|
|
1742
1946
|
let i = 0;
|
|
1743
|
-
for (const x of
|
|
1947
|
+
for (const x of it) {
|
|
1744
1948
|
if (i % n === 0) {
|
|
1745
1949
|
yield x;
|
|
1746
1950
|
}
|
|
@@ -1763,33 +1967,15 @@ export function cycle(coll) {
|
|
|
1763
1967
|
}
|
|
1764
1968
|
|
|
1765
1969
|
function drop1(n) {
|
|
1766
|
-
return (rf) => {
|
|
1970
|
+
return transducer((rf) => {
|
|
1767
1971
|
let na = n;
|
|
1768
|
-
return (
|
|
1769
|
-
|
|
1770
|
-
if (al === 0) {
|
|
1771
|
-
return rf();
|
|
1772
|
-
}
|
|
1773
|
-
if (al === 1) {
|
|
1774
|
-
return rf(args[0]);
|
|
1775
|
-
}
|
|
1776
|
-
if (al === 2) {
|
|
1777
|
-
const result = args[0];
|
|
1778
|
-
const input = args[1];
|
|
1779
|
-
const n = na;
|
|
1780
|
-
na--;
|
|
1781
|
-
if (n > 0) {
|
|
1782
|
-
return result;
|
|
1783
|
-
} else return rf(result, input);
|
|
1784
|
-
}
|
|
1785
|
-
};
|
|
1786
|
-
};
|
|
1972
|
+
return (r, x) => (na-- > 0 ? r : rf(r, x));
|
|
1973
|
+
});
|
|
1787
1974
|
}
|
|
1788
1975
|
|
|
1789
1976
|
export function drop(n, xs) {
|
|
1790
1977
|
if (arguments.length === 1) return drop1(n);
|
|
1791
|
-
return
|
|
1792
|
-
const iter = _iterator(iterable(xs));
|
|
1978
|
+
return lazyIter(xs, function* (iter) {
|
|
1793
1979
|
for (let x = 0; x < n; x++) {
|
|
1794
1980
|
iter.next();
|
|
1795
1981
|
}
|
|
@@ -1798,36 +1984,20 @@ export function drop(n, xs) {
|
|
|
1798
1984
|
}
|
|
1799
1985
|
|
|
1800
1986
|
function drop_while1(pred) {
|
|
1801
|
-
return (rf) => {
|
|
1987
|
+
return transducer((rf) => {
|
|
1802
1988
|
let da = true;
|
|
1803
|
-
return (
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
}
|
|
1808
|
-
if (al === 1) {
|
|
1809
|
-
return rf(args[0]);
|
|
1810
|
-
}
|
|
1811
|
-
if (al === 2) {
|
|
1812
|
-
const isDrop = da;
|
|
1813
|
-
const result = args[0];
|
|
1814
|
-
const input = args[1];
|
|
1815
|
-
if (isDrop && truth_(pred(input))) {
|
|
1816
|
-
return result;
|
|
1817
|
-
} else {
|
|
1818
|
-
da = null;
|
|
1819
|
-
return rf(result, input);
|
|
1820
|
-
}
|
|
1821
|
-
}
|
|
1989
|
+
return (r, x) => {
|
|
1990
|
+
if (da && truth_(pred(x))) return r;
|
|
1991
|
+
da = false;
|
|
1992
|
+
return rf(r, x);
|
|
1822
1993
|
};
|
|
1823
|
-
};
|
|
1994
|
+
});
|
|
1824
1995
|
}
|
|
1825
1996
|
|
|
1826
1997
|
export function drop_while(pred, xs) {
|
|
1827
1998
|
pred = __toFn(pred);
|
|
1828
1999
|
if (arguments.length === 1) return drop_while1(pred);
|
|
1829
|
-
return
|
|
1830
|
-
const iter = _iterator(iterable(xs));
|
|
2000
|
+
return lazyIter(xs, function* (iter) {
|
|
1831
2001
|
while (true) {
|
|
1832
2002
|
const nextItem = iter.next();
|
|
1833
2003
|
if (nextItem.done) {
|
|
@@ -1844,28 +2014,21 @@ export function drop_while(pred, xs) {
|
|
|
1844
2014
|
}
|
|
1845
2015
|
|
|
1846
2016
|
function distinct1() {
|
|
1847
|
-
return (rf) => {
|
|
2017
|
+
return transducer((rf) => {
|
|
1848
2018
|
const seen = new Set();
|
|
1849
|
-
return (
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
if (al === 2) {
|
|
1854
|
-
const result = args[0];
|
|
1855
|
-
const input = args[1];
|
|
1856
|
-
if (seen.has(input)) return result;
|
|
1857
|
-
seen.add(input);
|
|
1858
|
-
return rf(result, input);
|
|
1859
|
-
}
|
|
2019
|
+
return (r, x) => {
|
|
2020
|
+
if (seen.has(x)) return r;
|
|
2021
|
+
seen.add(x);
|
|
2022
|
+
return rf(r, x);
|
|
1860
2023
|
};
|
|
1861
|
-
};
|
|
2024
|
+
});
|
|
1862
2025
|
}
|
|
1863
2026
|
|
|
1864
2027
|
export function distinct(coll) {
|
|
1865
2028
|
if (arguments.length === 0) return distinct1();
|
|
1866
|
-
return
|
|
2029
|
+
return lazyIter(coll, function* (it) {
|
|
1867
2030
|
const seen = new Set();
|
|
1868
|
-
for (const x of
|
|
2031
|
+
for (const x of it) {
|
|
1869
2032
|
if (!seen.has(x)) yield x;
|
|
1870
2033
|
seen.add(x);
|
|
1871
2034
|
}
|
|
@@ -1876,28 +2039,21 @@ export function distinct(coll) {
|
|
|
1876
2039
|
const DEDUPE_NONE = Symbol('dedupe-none');
|
|
1877
2040
|
|
|
1878
2041
|
function dedupe1() {
|
|
1879
|
-
return (rf) => {
|
|
2042
|
+
return transducer((rf) => {
|
|
1880
2043
|
let prev = DEDUPE_NONE;
|
|
1881
|
-
return (
|
|
1882
|
-
const
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
if (al === 2) {
|
|
1886
|
-
const result = args[0];
|
|
1887
|
-
const input = args[1];
|
|
1888
|
-
const skip = prev !== DEDUPE_NONE && truth_(_EQ_(prev, input));
|
|
1889
|
-
prev = input;
|
|
1890
|
-
return skip ? result : rf(result, input);
|
|
1891
|
-
}
|
|
2044
|
+
return (r, x) => {
|
|
2045
|
+
const skip = prev !== DEDUPE_NONE && truth_(_EQ_(prev, x));
|
|
2046
|
+
prev = x;
|
|
2047
|
+
return skip ? r : rf(r, x);
|
|
1892
2048
|
};
|
|
1893
|
-
};
|
|
2049
|
+
});
|
|
1894
2050
|
}
|
|
1895
2051
|
|
|
1896
2052
|
export function dedupe(coll) {
|
|
1897
2053
|
if (arguments.length === 0) return dedupe1();
|
|
1898
|
-
return
|
|
2054
|
+
return lazyIter(coll, function* (it) {
|
|
1899
2055
|
let prev = DEDUPE_NONE;
|
|
1900
|
-
for (const x of
|
|
2056
|
+
for (const x of it) {
|
|
1901
2057
|
if (prev === DEDUPE_NONE || !truth_(_EQ_(prev, x))) yield x;
|
|
1902
2058
|
prev = x;
|
|
1903
2059
|
}
|
|
@@ -1937,8 +2093,14 @@ export function fnil(f, x, ...xs) {
|
|
|
1937
2093
|
|
|
1938
2094
|
export function every_QMARK_(pred, coll) {
|
|
1939
2095
|
pred = __toFn(pred);
|
|
1940
|
-
|
|
1941
|
-
if (!pred(
|
|
2096
|
+
if (Array.isArray(coll)) {
|
|
2097
|
+
for (let i = 0; i < coll.length; i++) if (!pred(coll[i])) return false;
|
|
2098
|
+
return true;
|
|
2099
|
+
}
|
|
2100
|
+
const next = chunkCursor(coll);
|
|
2101
|
+
let ch;
|
|
2102
|
+
while ((ch = next()) !== null) {
|
|
2103
|
+
for (let i = 0; i < ch.length; i++) if (!pred(ch[i])) return false;
|
|
1942
2104
|
}
|
|
1943
2105
|
return true;
|
|
1944
2106
|
}
|
|
@@ -1948,36 +2110,27 @@ export function not_every_QMARK_(pred, coll) {
|
|
|
1948
2110
|
}
|
|
1949
2111
|
|
|
1950
2112
|
function keep1(pred) {
|
|
1951
|
-
return (rf) => {
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
if (al === 1) return rf(args[0]);
|
|
1956
|
-
if (al === 2) {
|
|
1957
|
-
const result = args[0];
|
|
1958
|
-
const input = args[1];
|
|
1959
|
-
const v = pred(input);
|
|
1960
|
-
if (v == null) return result;
|
|
1961
|
-
return rf(result, v);
|
|
1962
|
-
}
|
|
1963
|
-
};
|
|
1964
|
-
};
|
|
2113
|
+
return transducer((rf) => (r, x) => {
|
|
2114
|
+
const v = pred(x);
|
|
2115
|
+
return v == null ? r : rf(r, v);
|
|
2116
|
+
});
|
|
1965
2117
|
}
|
|
1966
2118
|
|
|
1967
2119
|
export function keep(pred, coll) {
|
|
1968
2120
|
pred = __toFn(pred);
|
|
1969
2121
|
if (arguments.length === 1) return keep1(pred);
|
|
1970
|
-
return
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
2122
|
+
return mapChunks(coll, (ch) => {
|
|
2123
|
+
const out = [];
|
|
2124
|
+
for (let i = 0; i < ch.length; i++) {
|
|
2125
|
+
const res = pred(ch[i]);
|
|
2126
|
+
if (truth_(res)) out.push(res);
|
|
1974
2127
|
}
|
|
2128
|
+
return out;
|
|
1975
2129
|
});
|
|
1976
2130
|
}
|
|
1977
2131
|
|
|
1978
2132
|
export function reverse(coll) {
|
|
1979
|
-
|
|
1980
|
-
return [...coll].reverse();
|
|
2133
|
+
return toArray(coll).reverse();
|
|
1981
2134
|
}
|
|
1982
2135
|
|
|
1983
2136
|
export function sort(f, coll) {
|
|
@@ -1986,9 +2139,8 @@ export function sort(f, coll) {
|
|
|
1986
2139
|
f = undefined;
|
|
1987
2140
|
}
|
|
1988
2141
|
f = __toFn(f);
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
const clone = [...coll];
|
|
2142
|
+
// need a copy since .sort works in place and .toSorted isn't on Node < 20
|
|
2143
|
+
const clone = toArray(coll);
|
|
1992
2144
|
// result is guaranteed to be stable since ES2019, like CLJS
|
|
1993
2145
|
return clone.sort(f || compare);
|
|
1994
2146
|
}
|
|
@@ -2028,7 +2180,7 @@ export function sort_by(keyfn, comp, coll) {
|
|
|
2028
2180
|
}
|
|
2029
2181
|
|
|
2030
2182
|
export function shuffle(coll) {
|
|
2031
|
-
const result =
|
|
2183
|
+
const result = toArray(coll);
|
|
2032
2184
|
let remaining = result.length;
|
|
2033
2185
|
while (remaining) {
|
|
2034
2186
|
const i = Math.floor(Math.random() * remaining--);
|
|
@@ -2042,9 +2194,20 @@ export function shuffle(coll) {
|
|
|
2042
2194
|
|
|
2043
2195
|
export function some(pred, coll) {
|
|
2044
2196
|
pred = __toFn(pred);
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2197
|
+
if (Array.isArray(coll)) {
|
|
2198
|
+
for (let i = 0; i < coll.length; i++) {
|
|
2199
|
+
const res = pred(coll[i]);
|
|
2200
|
+
if (truth_(res)) return res;
|
|
2201
|
+
}
|
|
2202
|
+
return undefined;
|
|
2203
|
+
}
|
|
2204
|
+
const next = chunkCursor(coll);
|
|
2205
|
+
let ch;
|
|
2206
|
+
while ((ch = next()) !== null) {
|
|
2207
|
+
for (let i = 0; i < ch.length; i++) {
|
|
2208
|
+
const res = pred(ch[i]);
|
|
2209
|
+
if (truth_(res)) return res;
|
|
2210
|
+
}
|
|
2048
2211
|
}
|
|
2049
2212
|
return undefined;
|
|
2050
2213
|
}
|
|
@@ -2130,22 +2293,16 @@ export function frequencies(coll) {
|
|
|
2130
2293
|
return res;
|
|
2131
2294
|
}
|
|
2132
2295
|
|
|
2133
|
-
|
|
2296
|
+
// The lazy-seq macro emits `new LazySeq(() => body)`: a LazyIterable whose step
|
|
2297
|
+
// evaluates the body thunk on first force and reads it unchunked.
|
|
2298
|
+
export class LazySeq extends LazyIterable {
|
|
2134
2299
|
constructor(f) {
|
|
2135
|
-
|
|
2136
|
-
this.res = undefined;
|
|
2137
|
-
}
|
|
2138
|
-
*[Symbol.iterator]() {
|
|
2139
|
-
if (this.res === undefined) {
|
|
2140
|
-
this.res = this.f();
|
|
2141
|
-
this.f = null;
|
|
2142
|
-
}
|
|
2143
|
-
yield* iterable(this.res);
|
|
2300
|
+
super(() => unchunkedSteps(es6_iterator(iterable(f())))());
|
|
2144
2301
|
}
|
|
2145
2302
|
}
|
|
2146
2303
|
|
|
2147
2304
|
export function butlast(coll) {
|
|
2148
|
-
const x =
|
|
2305
|
+
const x = toArray(coll);
|
|
2149
2306
|
x.pop();
|
|
2150
2307
|
return x.length > 0 ? x : null;
|
|
2151
2308
|
}
|
|
@@ -2169,10 +2326,11 @@ export function count(coll) {
|
|
|
2169
2326
|
if (typeof len === 'number') {
|
|
2170
2327
|
return len;
|
|
2171
2328
|
}
|
|
2329
|
+
// sum chunk lengths instead of counting elements one by one
|
|
2330
|
+
const next = chunkCursor(coll);
|
|
2172
2331
|
let ret = 0;
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
}
|
|
2332
|
+
let ch;
|
|
2333
|
+
while ((ch = next()) !== null) ret += ch.length;
|
|
2176
2334
|
return ret;
|
|
2177
2335
|
}
|
|
2178
2336
|
|
|
@@ -2240,6 +2398,12 @@ export function aset(arr, idx, val, ...more) {
|
|
|
2240
2398
|
}
|
|
2241
2399
|
|
|
2242
2400
|
export function dorun(x) {
|
|
2401
|
+
// only a lazy seq needs forcing; realized colls are walked natively
|
|
2402
|
+
if (x instanceof LazyIterable) {
|
|
2403
|
+
const next = chunkCursor(x);
|
|
2404
|
+
while (next() !== null);
|
|
2405
|
+
return null;
|
|
2406
|
+
}
|
|
2243
2407
|
for (const _ of iterable(x)) {
|
|
2244
2408
|
// nothing here, just consume for side effects
|
|
2245
2409
|
}
|
|
@@ -2501,6 +2665,62 @@ export function string_QMARK_(s) {
|
|
|
2501
2665
|
return typeof s === 'string';
|
|
2502
2666
|
}
|
|
2503
2667
|
|
|
2668
|
+
export function unchecked_int(x) {
|
|
2669
|
+
return Math.trunc(x);
|
|
2670
|
+
}
|
|
2671
|
+
|
|
2672
|
+
export function unchecked_inc_int(x) {
|
|
2673
|
+
return x + 1;
|
|
2674
|
+
}
|
|
2675
|
+
|
|
2676
|
+
export function unchecked_dec_int(x) {
|
|
2677
|
+
return x - 1;
|
|
2678
|
+
}
|
|
2679
|
+
|
|
2680
|
+
export function unchecked_add_int(x, y) {
|
|
2681
|
+
return x + y;
|
|
2682
|
+
}
|
|
2683
|
+
|
|
2684
|
+
// keywords/symbols are strings in squint; namespace is the part before "/"
|
|
2685
|
+
export function namespace(x) {
|
|
2686
|
+
// keywords/symbols are strings in squint; namespace is the part before the
|
|
2687
|
+
// "/" ns separator (consistent with `name`, which returns the part after).
|
|
2688
|
+
// i >= 1 so a leading "/" yields a nil namespace rather than an empty one.
|
|
2689
|
+
const i = x.indexOf('/');
|
|
2690
|
+
return i >= 1 ? x.slice(0, i) : null;
|
|
2691
|
+
}
|
|
2692
|
+
|
|
2693
|
+
// squint has no keyword type; keywords are strings, so keyword/keyword? are
|
|
2694
|
+
// string-based. (keyword name) or (keyword ns name).
|
|
2695
|
+
export function keyword(arg1, arg2) {
|
|
2696
|
+
if (arg2 !== undefined) {
|
|
2697
|
+
return (arg1 != null ? arg1 + '/' : '') + arg2;
|
|
2698
|
+
}
|
|
2699
|
+
return arg1;
|
|
2700
|
+
}
|
|
2701
|
+
|
|
2702
|
+
export function keyword_QMARK_(x) {
|
|
2703
|
+
return typeof x === 'string';
|
|
2704
|
+
}
|
|
2705
|
+
|
|
2706
|
+
// squint has no symbol type either; symbols are strings
|
|
2707
|
+
export function symbol_QMARK_(x) {
|
|
2708
|
+
return typeof x === 'string';
|
|
2709
|
+
}
|
|
2710
|
+
|
|
2711
|
+
// squint has no first-class Var objects (#'x emits the value), so var? is false
|
|
2712
|
+
export function var_QMARK_(_x) {
|
|
2713
|
+
return false;
|
|
2714
|
+
}
|
|
2715
|
+
|
|
2716
|
+
export function simple_keyword_QMARK_(x) {
|
|
2717
|
+
return typeof x === 'string' && !x.includes('/');
|
|
2718
|
+
}
|
|
2719
|
+
|
|
2720
|
+
export function qualified_keyword_QMARK_(x) {
|
|
2721
|
+
return typeof x === 'string' && x.includes('/');
|
|
2722
|
+
}
|
|
2723
|
+
|
|
2504
2724
|
export function coll_QMARK_(coll) {
|
|
2505
2725
|
return typeConst(coll) != undefined;
|
|
2506
2726
|
}
|
|
@@ -2554,8 +2774,6 @@ export function neg_int_QMARK_(x) {
|
|
|
2554
2774
|
return int_QMARK_(x) && x < 0;
|
|
2555
2775
|
}
|
|
2556
2776
|
|
|
2557
|
-
const _metaSym = Symbol('meta');
|
|
2558
|
-
|
|
2559
2777
|
export function meta(x) {
|
|
2560
2778
|
if (x instanceof Object) {
|
|
2561
2779
|
return x[_metaSym];
|
|
@@ -2604,7 +2822,7 @@ export function bounded_count(n, coll) {
|
|
|
2604
2822
|
export function find(m, k) {
|
|
2605
2823
|
const v = get(m, k);
|
|
2606
2824
|
if (v !== undefined) {
|
|
2607
|
-
return [k, v];
|
|
2825
|
+
return tagMapEntry([k, v]);
|
|
2608
2826
|
}
|
|
2609
2827
|
}
|
|
2610
2828
|
|
|
@@ -2773,7 +2991,9 @@ export function transient$(x) {
|
|
|
2773
2991
|
}
|
|
2774
2992
|
|
|
2775
2993
|
export function persistent_BANG_(x) {
|
|
2776
|
-
|
|
2994
|
+
// no Object.freeze: persistent structures stay extensible so symbol-keyed
|
|
2995
|
+
// metadata can be attached
|
|
2996
|
+
return x;
|
|
2777
2997
|
}
|
|
2778
2998
|
|
|
2779
2999
|
class SortedSet {
|
|
@@ -3060,6 +3280,7 @@ export function volatile_BANG_(x) {
|
|
|
3060
3280
|
|
|
3061
3281
|
export function vreset_BANG_(vol, v) {
|
|
3062
3282
|
vol.v = v;
|
|
3283
|
+
return v;
|
|
3063
3284
|
}
|
|
3064
3285
|
|
|
3065
3286
|
function toEDN(value, seen = new WeakSet()) {
|