squint-cljs 0.12.193 → 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 -35
- package/lib/compiler.sci.js +1312 -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 +625 -408
- 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
|
}
|
|
@@ -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,26 +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
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
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];
|
|
554
|
+
}
|
|
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;
|
|
523
564
|
}
|
|
524
565
|
}
|
|
525
|
-
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);
|
|
526
569
|
}
|
|
527
570
|
|
|
528
571
|
export function get(coll, key, otherwise = undefined) {
|
|
@@ -586,6 +629,21 @@ export function seqable_QMARK_(x) {
|
|
|
586
629
|
);
|
|
587
630
|
}
|
|
588
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
|
+
|
|
589
647
|
export function iterable(x) {
|
|
590
648
|
// nil puns to empty iterable, support passing nil to first/rest/reduce, etc.
|
|
591
649
|
if (x === null || x === undefined) {
|
|
@@ -597,7 +655,7 @@ export function iterable(x) {
|
|
|
597
655
|
if (x[Symbol.iterator]) {
|
|
598
656
|
return x;
|
|
599
657
|
}
|
|
600
|
-
if (x instanceof Object) return Object.entries(x);
|
|
658
|
+
if (x instanceof Object) return Object.entries(x).map(tagMapEntry);
|
|
601
659
|
throw new TypeError(`${x} is not iterable`);
|
|
602
660
|
}
|
|
603
661
|
|
|
@@ -624,12 +682,24 @@ export function seq(x) {
|
|
|
624
682
|
}
|
|
625
683
|
|
|
626
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
|
+
}
|
|
627
691
|
// destructuring uses iterable protocol
|
|
628
692
|
const [first] = iterable(coll);
|
|
629
693
|
return first;
|
|
630
694
|
}
|
|
631
695
|
|
|
632
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
|
+
}
|
|
633
703
|
const [_, v] = iterable(coll);
|
|
634
704
|
return v;
|
|
635
705
|
}
|
|
@@ -639,13 +709,20 @@ export function ffirst(coll) {
|
|
|
639
709
|
}
|
|
640
710
|
|
|
641
711
|
export function rest(coll) {
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
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
|
|
649
726
|
}
|
|
650
727
|
|
|
651
728
|
class Reduced {
|
|
@@ -660,16 +737,15 @@ class Reduced {
|
|
|
660
737
|
|
|
661
738
|
export function last(coll) {
|
|
662
739
|
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;
|
|
740
|
+
if (Array.isArray(coll)) {
|
|
741
|
+
return coll[coll.length - 1];
|
|
672
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;
|
|
673
749
|
}
|
|
674
750
|
|
|
675
751
|
export function reduced(x) {
|
|
@@ -682,31 +758,43 @@ export function reduced_QMARK_(x) {
|
|
|
682
758
|
|
|
683
759
|
export function reduce(f, arg1, arg2) {
|
|
684
760
|
f = __toFn(f);
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
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;
|
|
694
772
|
}
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
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;
|
|
700
779
|
}
|
|
701
|
-
|
|
702
|
-
|
|
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;
|
|
703
789
|
}
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
val = val
|
|
708
|
-
|
|
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;
|
|
709
795
|
}
|
|
796
|
+
ch = next();
|
|
797
|
+
i = 0;
|
|
710
798
|
}
|
|
711
799
|
return val;
|
|
712
800
|
}
|
|
@@ -739,42 +827,152 @@ function* _reductions3(f, init, coll) {
|
|
|
739
827
|
export function reductions(f, arg1, arg2) {
|
|
740
828
|
f = __toFn(f);
|
|
741
829
|
if (arguments.length === 2) {
|
|
830
|
+
const it = es6_iterator(iterable(arg1));
|
|
742
831
|
return lazy(function* () {
|
|
743
|
-
yield* _reductions2(f,
|
|
832
|
+
yield* _reductions2(f, it);
|
|
744
833
|
});
|
|
745
834
|
}
|
|
835
|
+
const it = es6_iterator(iterable(arg2));
|
|
746
836
|
return lazy(function* () {
|
|
747
|
-
yield* _reductions3(f, arg1,
|
|
837
|
+
yield* _reductions3(f, arg1, it);
|
|
748
838
|
});
|
|
749
839
|
}
|
|
750
840
|
|
|
751
|
-
|
|
841
|
+
// Deprecated: lazy values are now cached, so reuse no longer recomputes. Kept
|
|
842
|
+
// for API compatibility; remove in a future release.
|
|
752
843
|
export function warn_on_lazy_reusage_BANG_() {
|
|
753
|
-
|
|
844
|
+
console.warn(
|
|
845
|
+
'warn-on-lazy-reusage! is deprecated and does nothing: lazy values are now cached.',
|
|
846
|
+
);
|
|
754
847
|
}
|
|
755
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.
|
|
756
853
|
class LazyIterable {
|
|
757
|
-
constructor(
|
|
758
|
-
this.
|
|
759
|
-
this.
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
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]);
|
|
768
868
|
}
|
|
769
869
|
}
|
|
770
|
-
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
|
+
};
|
|
771
890
|
}
|
|
772
891
|
}
|
|
773
892
|
|
|
774
893
|
LazyIterable.prototype[IIterable] = true; // Closure compatibility
|
|
775
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.
|
|
776
905
|
export function lazy(f) {
|
|
777
|
-
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));
|
|
778
976
|
}
|
|
779
977
|
|
|
780
978
|
export class Cons {
|
|
@@ -782,24 +980,35 @@ export class Cons {
|
|
|
782
980
|
this.x = x;
|
|
783
981
|
this.coll = coll;
|
|
784
982
|
}
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
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
|
+
};
|
|
788
1004
|
}
|
|
789
1005
|
}
|
|
790
1006
|
|
|
791
1007
|
export function cons(x, coll) {
|
|
792
1008
|
return new Cons(x, coll);
|
|
793
|
-
// return lazy(function* () {
|
|
794
|
-
// yield x;
|
|
795
|
-
// yield* iterable(coll);
|
|
796
|
-
// });
|
|
797
1009
|
}
|
|
798
1010
|
|
|
799
1011
|
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
1012
|
f = __toFn(f);
|
|
804
1013
|
switch (colls.length) {
|
|
805
1014
|
case 0:
|
|
@@ -822,14 +1031,14 @@ export function map(f, ...colls) {
|
|
|
822
1031
|
};
|
|
823
1032
|
};
|
|
824
1033
|
case 1:
|
|
825
|
-
return
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
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;
|
|
829
1038
|
});
|
|
830
|
-
default:
|
|
1039
|
+
default: {
|
|
1040
|
+
const iters = colls.map((coll) => es6_iterator(iterable(coll)));
|
|
831
1041
|
return lazy(function* () {
|
|
832
|
-
const iters = colls.map((coll) => es6_iterator(iterable(coll)));
|
|
833
1042
|
while (true) {
|
|
834
1043
|
const args = [];
|
|
835
1044
|
for (const i of iters) {
|
|
@@ -842,45 +1051,41 @@ export function map(f, ...colls) {
|
|
|
842
1051
|
yield f(...args);
|
|
843
1052
|
}
|
|
844
1053
|
});
|
|
1054
|
+
}
|
|
845
1055
|
}
|
|
846
1056
|
}
|
|
847
1057
|
|
|
848
|
-
|
|
1058
|
+
// 0/1 arities pass through to rf; step(rf) is the 2-arity reducer
|
|
1059
|
+
function transducer(step) {
|
|
849
1060
|
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
|
-
};
|
|
1061
|
+
const s = step(rf);
|
|
1062
|
+
return (...args) =>
|
|
1063
|
+
args.length === 0 ? rf() : args.length === 1 ? rf(args[0]) : s(args[0], args[1]);
|
|
865
1064
|
};
|
|
866
1065
|
}
|
|
867
1066
|
|
|
1067
|
+
function filter1(pred) {
|
|
1068
|
+
return transducer((rf) => (r, x) => (truth_(pred(x)) ? rf(r, x) : r));
|
|
1069
|
+
}
|
|
1070
|
+
|
|
868
1071
|
export function filter(pred, coll) {
|
|
869
1072
|
if (arguments.length === 1) {
|
|
870
1073
|
return filter1(pred);
|
|
871
1074
|
}
|
|
872
1075
|
pred = __toFn(pred);
|
|
873
|
-
return
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
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);
|
|
878
1081
|
}
|
|
1082
|
+
return out;
|
|
879
1083
|
});
|
|
880
1084
|
}
|
|
881
1085
|
|
|
882
1086
|
export function filterv(pred, coll) {
|
|
883
|
-
|
|
1087
|
+
// filter is chunked; vec bulk-appends its chunks
|
|
1088
|
+
return pushAll([], filter(pred, coll));
|
|
884
1089
|
}
|
|
885
1090
|
|
|
886
1091
|
export function remove(pred, coll) {
|
|
@@ -891,19 +1096,10 @@ export function remove(pred, coll) {
|
|
|
891
1096
|
}
|
|
892
1097
|
|
|
893
1098
|
function map_indexed1(f) {
|
|
894
|
-
return (rf) => {
|
|
1099
|
+
return transducer((rf) => {
|
|
895
1100
|
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
|
-
};
|
|
1101
|
+
return (r, x) => rf(r, f(++i, x));
|
|
1102
|
+
});
|
|
907
1103
|
}
|
|
908
1104
|
|
|
909
1105
|
export function map_indexed(f, coll) {
|
|
@@ -911,50 +1107,33 @@ export function map_indexed(f, coll) {
|
|
|
911
1107
|
if (arguments.length === 1) {
|
|
912
1108
|
return map_indexed1(f);
|
|
913
1109
|
}
|
|
914
|
-
return
|
|
915
|
-
|
|
916
|
-
for (
|
|
917
|
-
|
|
918
|
-
idx++;
|
|
919
|
-
}
|
|
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;
|
|
920
1114
|
});
|
|
921
1115
|
}
|
|
922
1116
|
|
|
923
1117
|
function keep_indexed2(f, coll) {
|
|
924
1118
|
f = __toFn(f);
|
|
925
|
-
return
|
|
926
|
-
|
|
927
|
-
for (
|
|
928
|
-
const v = f(
|
|
929
|
-
if (truth_(v))
|
|
930
|
-
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);
|
|
931
1124
|
}
|
|
1125
|
+
return out;
|
|
932
1126
|
});
|
|
933
1127
|
}
|
|
934
1128
|
|
|
935
1129
|
function keep_indexed1(f) {
|
|
936
|
-
return (rf) => {
|
|
1130
|
+
return transducer((rf) => {
|
|
937
1131
|
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
|
-
}
|
|
1132
|
+
return (r, x) => {
|
|
1133
|
+
const v = f(++ia, x);
|
|
1134
|
+
return v == null ? r : rf(r, v);
|
|
956
1135
|
};
|
|
957
|
-
};
|
|
1136
|
+
});
|
|
958
1137
|
}
|
|
959
1138
|
|
|
960
1139
|
export function keep_indexed(f, coll) {
|
|
@@ -970,7 +1149,12 @@ export function str(...xs) {
|
|
|
970
1149
|
}
|
|
971
1150
|
|
|
972
1151
|
export function name(x) {
|
|
973
|
-
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
|
+
}
|
|
974
1158
|
throw new Error("Doesn't support name: " + typeof x);
|
|
975
1159
|
}
|
|
976
1160
|
|
|
@@ -1055,22 +1239,29 @@ export function compare_and_set_BANG_(atm, oldv, newv) {
|
|
|
1055
1239
|
}
|
|
1056
1240
|
|
|
1057
1241
|
export function range(begin, end, step) {
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
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);
|
|
1071
1260
|
i += s;
|
|
1072
1261
|
}
|
|
1073
|
-
|
|
1262
|
+
return [out, mkStep(i)];
|
|
1263
|
+
};
|
|
1264
|
+
return new LazyIterable(mkStep(start));
|
|
1074
1265
|
}
|
|
1075
1266
|
|
|
1076
1267
|
export function re_matches(re, s) {
|
|
@@ -1143,9 +1334,12 @@ export function mapv(...args) {
|
|
|
1143
1334
|
}
|
|
1144
1335
|
return ret;
|
|
1145
1336
|
} else {
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
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]));
|
|
1149
1343
|
}
|
|
1150
1344
|
return ret;
|
|
1151
1345
|
}
|
|
@@ -1153,12 +1347,32 @@ export function mapv(...args) {
|
|
|
1153
1347
|
return [...map(...args)];
|
|
1154
1348
|
}
|
|
1155
1349
|
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
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
|
+
}
|
|
1160
1362
|
}
|
|
1161
|
-
|
|
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);
|
|
1162
1376
|
}
|
|
1163
1377
|
|
|
1164
1378
|
export function set(coll) {
|
|
@@ -1223,12 +1437,54 @@ export function array_QMARK_(x) {
|
|
|
1223
1437
|
return Array.isArray(x);
|
|
1224
1438
|
}
|
|
1225
1439
|
|
|
1440
|
+
const CONCAT_DONE = Symbol('concat-done');
|
|
1441
|
+
|
|
1226
1442
|
function concat1(colls) {
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
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;
|
|
1230
1456
|
}
|
|
1231
|
-
|
|
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));
|
|
1232
1488
|
}
|
|
1233
1489
|
|
|
1234
1490
|
export function concat(...colls) {
|
|
@@ -1243,10 +1499,8 @@ concat[IApply__apply] = (colls) => {
|
|
|
1243
1499
|
export function mapcat(f, ...colls) {
|
|
1244
1500
|
if (colls.length === 0) {
|
|
1245
1501
|
return comp(map(f), cat);
|
|
1246
|
-
} else {
|
|
1247
|
-
const mapped = map(f, ...colls);
|
|
1248
|
-
return concat1(mapped);
|
|
1249
1502
|
}
|
|
1503
|
+
return concat1(map(f, ...colls));
|
|
1250
1504
|
}
|
|
1251
1505
|
|
|
1252
1506
|
export function identity(x) {
|
|
@@ -1254,8 +1508,8 @@ export function identity(x) {
|
|
|
1254
1508
|
}
|
|
1255
1509
|
|
|
1256
1510
|
export function interleave(...colls) {
|
|
1511
|
+
const iters = colls.map((coll) => es6_iterator(iterable(coll)));
|
|
1257
1512
|
return lazy(function* () {
|
|
1258
|
-
const iters = colls.map((coll) => es6_iterator(iterable(coll)));
|
|
1259
1513
|
while (true) {
|
|
1260
1514
|
const res = [];
|
|
1261
1515
|
for (const i of iters) {
|
|
@@ -1271,30 +1525,17 @@ export function interleave(...colls) {
|
|
|
1271
1525
|
}
|
|
1272
1526
|
|
|
1273
1527
|
function interpose1(sep) {
|
|
1274
|
-
return (rf) => {
|
|
1528
|
+
return transducer((rf) => {
|
|
1275
1529
|
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
|
-
}
|
|
1530
|
+
return (r, x) => {
|
|
1531
|
+
if (!started) {
|
|
1532
|
+
started = true;
|
|
1533
|
+
return rf(r, x);
|
|
1295
1534
|
}
|
|
1535
|
+
const sepr = rf(r, sep);
|
|
1536
|
+
return reduced_QMARK_(sepr) ? sepr : rf(sepr, x);
|
|
1296
1537
|
};
|
|
1297
|
-
};
|
|
1538
|
+
});
|
|
1298
1539
|
}
|
|
1299
1540
|
|
|
1300
1541
|
export function interpose(sep, coll) {
|
|
@@ -1386,10 +1627,10 @@ export const partitionv = partition; // partition already returns a lazy of arra
|
|
|
1386
1627
|
export const partitionv_all = partition_all;
|
|
1387
1628
|
|
|
1388
1629
|
function partitionInternal(n, step, pad, coll, all) {
|
|
1389
|
-
return
|
|
1630
|
+
return lazyIter(coll, function* (it) {
|
|
1390
1631
|
let p = [];
|
|
1391
1632
|
let i = 0;
|
|
1392
|
-
for (const x of
|
|
1633
|
+
for (const x of it) {
|
|
1393
1634
|
if (i < n) {
|
|
1394
1635
|
p.push(x);
|
|
1395
1636
|
if (p.length === n) {
|
|
@@ -1461,8 +1702,8 @@ export function partition_by(f, coll) {
|
|
|
1461
1702
|
if (arguments.length === 1) {
|
|
1462
1703
|
return partition_by1(f);
|
|
1463
1704
|
}
|
|
1705
|
+
const iter = es6_iterator(coll);
|
|
1464
1706
|
return lazy(function* () {
|
|
1465
|
-
const iter = es6_iterator(coll);
|
|
1466
1707
|
const _fst = iter.next();
|
|
1467
1708
|
if (_fst.done) {
|
|
1468
1709
|
yield* null;
|
|
@@ -1495,7 +1736,7 @@ export function partition_by(f, coll) {
|
|
|
1495
1736
|
export function empty(coll) {
|
|
1496
1737
|
const type = typeConst(coll);
|
|
1497
1738
|
if (type != null) {
|
|
1498
|
-
return emptyOfType(type);
|
|
1739
|
+
return copyMeta(coll, emptyOfType(type));
|
|
1499
1740
|
} else {
|
|
1500
1741
|
throw new Error(`Can't create empty of ${typeof coll}`);
|
|
1501
1742
|
}
|
|
@@ -1561,7 +1802,13 @@ export function into(...args) {
|
|
|
1561
1802
|
case 1:
|
|
1562
1803
|
return args[0];
|
|
1563
1804
|
case 2:
|
|
1564
|
-
|
|
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]);
|
|
1565
1812
|
case 3:
|
|
1566
1813
|
to = args[0];
|
|
1567
1814
|
xform = args[1];
|
|
@@ -1612,42 +1859,23 @@ export function ensure_reduced(x) {
|
|
|
1612
1859
|
}
|
|
1613
1860
|
|
|
1614
1861
|
function take1(n) {
|
|
1615
|
-
return (rf) => {
|
|
1862
|
+
return transducer((rf) => {
|
|
1616
1863
|
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
|
-
}
|
|
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);
|
|
1640
1868
|
};
|
|
1641
|
-
};
|
|
1869
|
+
});
|
|
1642
1870
|
}
|
|
1643
1871
|
|
|
1644
1872
|
export function take(n, coll) {
|
|
1645
1873
|
if (arguments.length === 1) {
|
|
1646
1874
|
return take1(n);
|
|
1647
1875
|
}
|
|
1648
|
-
return
|
|
1876
|
+
return lazyIter(coll, function* (it) {
|
|
1649
1877
|
let i = n - 1;
|
|
1650
|
-
for (const x of
|
|
1878
|
+
for (const x of it) {
|
|
1651
1879
|
if (i-- >= 0) {
|
|
1652
1880
|
yield x;
|
|
1653
1881
|
}
|
|
@@ -1681,22 +1909,7 @@ export function take_last(n, coll) {
|
|
|
1681
1909
|
}
|
|
1682
1910
|
|
|
1683
1911
|
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
|
-
};
|
|
1912
|
+
return transducer((rf) => (r, x) => (truth_(pred(x)) ? rf(r, x) : reduced(r)));
|
|
1700
1913
|
}
|
|
1701
1914
|
|
|
1702
1915
|
export function take_while(pred, coll) {
|
|
@@ -1704,8 +1917,8 @@ export function take_while(pred, coll) {
|
|
|
1704
1917
|
if (arguments.length === 1) {
|
|
1705
1918
|
return take_while1(pred);
|
|
1706
1919
|
}
|
|
1707
|
-
return
|
|
1708
|
-
for (const o of
|
|
1920
|
+
return lazyIter(coll, function* (it) {
|
|
1921
|
+
for (const o of it) {
|
|
1709
1922
|
if (truth_(pred(o))) yield o;
|
|
1710
1923
|
else return;
|
|
1711
1924
|
}
|
|
@@ -1713,23 +1926,10 @@ export function take_while(pred, coll) {
|
|
|
1713
1926
|
}
|
|
1714
1927
|
|
|
1715
1928
|
function take_nth1(n) {
|
|
1716
|
-
return (rf) => {
|
|
1929
|
+
return transducer((rf) => {
|
|
1717
1930
|
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
|
-
};
|
|
1931
|
+
return (r, x) => (rem(++ia, n) === 0 ? rf(r, x) : r);
|
|
1932
|
+
});
|
|
1733
1933
|
}
|
|
1734
1934
|
|
|
1735
1935
|
export function take_nth(n, coll) {
|
|
@@ -1738,9 +1938,9 @@ export function take_nth(n, coll) {
|
|
|
1738
1938
|
return repeat(first(coll));
|
|
1739
1939
|
}
|
|
1740
1940
|
|
|
1741
|
-
return
|
|
1941
|
+
return lazyIter(coll, function* (it) {
|
|
1742
1942
|
let i = 0;
|
|
1743
|
-
for (const x of
|
|
1943
|
+
for (const x of it) {
|
|
1744
1944
|
if (i % n === 0) {
|
|
1745
1945
|
yield x;
|
|
1746
1946
|
}
|
|
@@ -1763,33 +1963,15 @@ export function cycle(coll) {
|
|
|
1763
1963
|
}
|
|
1764
1964
|
|
|
1765
1965
|
function drop1(n) {
|
|
1766
|
-
return (rf) => {
|
|
1966
|
+
return transducer((rf) => {
|
|
1767
1967
|
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
|
-
};
|
|
1968
|
+
return (r, x) => (na-- > 0 ? r : rf(r, x));
|
|
1969
|
+
});
|
|
1787
1970
|
}
|
|
1788
1971
|
|
|
1789
1972
|
export function drop(n, xs) {
|
|
1790
1973
|
if (arguments.length === 1) return drop1(n);
|
|
1791
|
-
return
|
|
1792
|
-
const iter = _iterator(iterable(xs));
|
|
1974
|
+
return lazyIter(xs, function* (iter) {
|
|
1793
1975
|
for (let x = 0; x < n; x++) {
|
|
1794
1976
|
iter.next();
|
|
1795
1977
|
}
|
|
@@ -1798,36 +1980,20 @@ export function drop(n, xs) {
|
|
|
1798
1980
|
}
|
|
1799
1981
|
|
|
1800
1982
|
function drop_while1(pred) {
|
|
1801
|
-
return (rf) => {
|
|
1983
|
+
return transducer((rf) => {
|
|
1802
1984
|
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
|
-
}
|
|
1985
|
+
return (r, x) => {
|
|
1986
|
+
if (da && truth_(pred(x))) return r;
|
|
1987
|
+
da = false;
|
|
1988
|
+
return rf(r, x);
|
|
1822
1989
|
};
|
|
1823
|
-
};
|
|
1990
|
+
});
|
|
1824
1991
|
}
|
|
1825
1992
|
|
|
1826
1993
|
export function drop_while(pred, xs) {
|
|
1827
1994
|
pred = __toFn(pred);
|
|
1828
1995
|
if (arguments.length === 1) return drop_while1(pred);
|
|
1829
|
-
return
|
|
1830
|
-
const iter = _iterator(iterable(xs));
|
|
1996
|
+
return lazyIter(xs, function* (iter) {
|
|
1831
1997
|
while (true) {
|
|
1832
1998
|
const nextItem = iter.next();
|
|
1833
1999
|
if (nextItem.done) {
|
|
@@ -1844,28 +2010,21 @@ export function drop_while(pred, xs) {
|
|
|
1844
2010
|
}
|
|
1845
2011
|
|
|
1846
2012
|
function distinct1() {
|
|
1847
|
-
return (rf) => {
|
|
2013
|
+
return transducer((rf) => {
|
|
1848
2014
|
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
|
-
}
|
|
2015
|
+
return (r, x) => {
|
|
2016
|
+
if (seen.has(x)) return r;
|
|
2017
|
+
seen.add(x);
|
|
2018
|
+
return rf(r, x);
|
|
1860
2019
|
};
|
|
1861
|
-
};
|
|
2020
|
+
});
|
|
1862
2021
|
}
|
|
1863
2022
|
|
|
1864
2023
|
export function distinct(coll) {
|
|
1865
2024
|
if (arguments.length === 0) return distinct1();
|
|
1866
|
-
return
|
|
2025
|
+
return lazyIter(coll, function* (it) {
|
|
1867
2026
|
const seen = new Set();
|
|
1868
|
-
for (const x of
|
|
2027
|
+
for (const x of it) {
|
|
1869
2028
|
if (!seen.has(x)) yield x;
|
|
1870
2029
|
seen.add(x);
|
|
1871
2030
|
}
|
|
@@ -1876,28 +2035,21 @@ export function distinct(coll) {
|
|
|
1876
2035
|
const DEDUPE_NONE = Symbol('dedupe-none');
|
|
1877
2036
|
|
|
1878
2037
|
function dedupe1() {
|
|
1879
|
-
return (rf) => {
|
|
2038
|
+
return transducer((rf) => {
|
|
1880
2039
|
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
|
-
}
|
|
2040
|
+
return (r, x) => {
|
|
2041
|
+
const skip = prev !== DEDUPE_NONE && truth_(_EQ_(prev, x));
|
|
2042
|
+
prev = x;
|
|
2043
|
+
return skip ? r : rf(r, x);
|
|
1892
2044
|
};
|
|
1893
|
-
};
|
|
2045
|
+
});
|
|
1894
2046
|
}
|
|
1895
2047
|
|
|
1896
2048
|
export function dedupe(coll) {
|
|
1897
2049
|
if (arguments.length === 0) return dedupe1();
|
|
1898
|
-
return
|
|
2050
|
+
return lazyIter(coll, function* (it) {
|
|
1899
2051
|
let prev = DEDUPE_NONE;
|
|
1900
|
-
for (const x of
|
|
2052
|
+
for (const x of it) {
|
|
1901
2053
|
if (prev === DEDUPE_NONE || !truth_(_EQ_(prev, x))) yield x;
|
|
1902
2054
|
prev = x;
|
|
1903
2055
|
}
|
|
@@ -1937,8 +2089,14 @@ export function fnil(f, x, ...xs) {
|
|
|
1937
2089
|
|
|
1938
2090
|
export function every_QMARK_(pred, coll) {
|
|
1939
2091
|
pred = __toFn(pred);
|
|
1940
|
-
|
|
1941
|
-
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;
|
|
1942
2100
|
}
|
|
1943
2101
|
return true;
|
|
1944
2102
|
}
|
|
@@ -1948,36 +2106,27 @@ export function not_every_QMARK_(pred, coll) {
|
|
|
1948
2106
|
}
|
|
1949
2107
|
|
|
1950
2108
|
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
|
-
};
|
|
2109
|
+
return transducer((rf) => (r, x) => {
|
|
2110
|
+
const v = pred(x);
|
|
2111
|
+
return v == null ? r : rf(r, v);
|
|
2112
|
+
});
|
|
1965
2113
|
}
|
|
1966
2114
|
|
|
1967
2115
|
export function keep(pred, coll) {
|
|
1968
2116
|
pred = __toFn(pred);
|
|
1969
2117
|
if (arguments.length === 1) return keep1(pred);
|
|
1970
|
-
return
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
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);
|
|
1974
2123
|
}
|
|
2124
|
+
return out;
|
|
1975
2125
|
});
|
|
1976
2126
|
}
|
|
1977
2127
|
|
|
1978
2128
|
export function reverse(coll) {
|
|
1979
|
-
|
|
1980
|
-
return [...coll].reverse();
|
|
2129
|
+
return toArray(coll).reverse();
|
|
1981
2130
|
}
|
|
1982
2131
|
|
|
1983
2132
|
export function sort(f, coll) {
|
|
@@ -1986,9 +2135,8 @@ export function sort(f, coll) {
|
|
|
1986
2135
|
f = undefined;
|
|
1987
2136
|
}
|
|
1988
2137
|
f = __toFn(f);
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
const clone = [...coll];
|
|
2138
|
+
// need a copy since .sort works in place and .toSorted isn't on Node < 20
|
|
2139
|
+
const clone = toArray(coll);
|
|
1992
2140
|
// result is guaranteed to be stable since ES2019, like CLJS
|
|
1993
2141
|
return clone.sort(f || compare);
|
|
1994
2142
|
}
|
|
@@ -2028,7 +2176,7 @@ export function sort_by(keyfn, comp, coll) {
|
|
|
2028
2176
|
}
|
|
2029
2177
|
|
|
2030
2178
|
export function shuffle(coll) {
|
|
2031
|
-
const result =
|
|
2179
|
+
const result = toArray(coll);
|
|
2032
2180
|
let remaining = result.length;
|
|
2033
2181
|
while (remaining) {
|
|
2034
2182
|
const i = Math.floor(Math.random() * remaining--);
|
|
@@ -2042,9 +2190,20 @@ export function shuffle(coll) {
|
|
|
2042
2190
|
|
|
2043
2191
|
export function some(pred, coll) {
|
|
2044
2192
|
pred = __toFn(pred);
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
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
|
+
}
|
|
2048
2207
|
}
|
|
2049
2208
|
return undefined;
|
|
2050
2209
|
}
|
|
@@ -2130,22 +2289,16 @@ export function frequencies(coll) {
|
|
|
2130
2289
|
return res;
|
|
2131
2290
|
}
|
|
2132
2291
|
|
|
2133
|
-
|
|
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 {
|
|
2134
2295
|
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);
|
|
2296
|
+
super(() => unchunkedSteps(es6_iterator(iterable(f())))());
|
|
2144
2297
|
}
|
|
2145
2298
|
}
|
|
2146
2299
|
|
|
2147
2300
|
export function butlast(coll) {
|
|
2148
|
-
const x =
|
|
2301
|
+
const x = toArray(coll);
|
|
2149
2302
|
x.pop();
|
|
2150
2303
|
return x.length > 0 ? x : null;
|
|
2151
2304
|
}
|
|
@@ -2169,10 +2322,11 @@ export function count(coll) {
|
|
|
2169
2322
|
if (typeof len === 'number') {
|
|
2170
2323
|
return len;
|
|
2171
2324
|
}
|
|
2325
|
+
// sum chunk lengths instead of counting elements one by one
|
|
2326
|
+
const next = chunkCursor(coll);
|
|
2172
2327
|
let ret = 0;
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
}
|
|
2328
|
+
let ch;
|
|
2329
|
+
while ((ch = next()) !== null) ret += ch.length;
|
|
2176
2330
|
return ret;
|
|
2177
2331
|
}
|
|
2178
2332
|
|
|
@@ -2240,6 +2394,12 @@ export function aset(arr, idx, val, ...more) {
|
|
|
2240
2394
|
}
|
|
2241
2395
|
|
|
2242
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
|
+
}
|
|
2243
2403
|
for (const _ of iterable(x)) {
|
|
2244
2404
|
// nothing here, just consume for side effects
|
|
2245
2405
|
}
|
|
@@ -2501,6 +2661,62 @@ export function string_QMARK_(s) {
|
|
|
2501
2661
|
return typeof s === 'string';
|
|
2502
2662
|
}
|
|
2503
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
|
+
|
|
2504
2720
|
export function coll_QMARK_(coll) {
|
|
2505
2721
|
return typeConst(coll) != undefined;
|
|
2506
2722
|
}
|
|
@@ -2554,8 +2770,6 @@ export function neg_int_QMARK_(x) {
|
|
|
2554
2770
|
return int_QMARK_(x) && x < 0;
|
|
2555
2771
|
}
|
|
2556
2772
|
|
|
2557
|
-
const _metaSym = Symbol('meta');
|
|
2558
|
-
|
|
2559
2773
|
export function meta(x) {
|
|
2560
2774
|
if (x instanceof Object) {
|
|
2561
2775
|
return x[_metaSym];
|
|
@@ -2604,7 +2818,7 @@ export function bounded_count(n, coll) {
|
|
|
2604
2818
|
export function find(m, k) {
|
|
2605
2819
|
const v = get(m, k);
|
|
2606
2820
|
if (v !== undefined) {
|
|
2607
|
-
return [k, v];
|
|
2821
|
+
return tagMapEntry([k, v]);
|
|
2608
2822
|
}
|
|
2609
2823
|
}
|
|
2610
2824
|
|
|
@@ -2773,7 +2987,9 @@ export function transient$(x) {
|
|
|
2773
2987
|
}
|
|
2774
2988
|
|
|
2775
2989
|
export function persistent_BANG_(x) {
|
|
2776
|
-
|
|
2990
|
+
// no Object.freeze: persistent structures stay extensible so symbol-keyed
|
|
2991
|
+
// metadata can be attached
|
|
2992
|
+
return x;
|
|
2777
2993
|
}
|
|
2778
2994
|
|
|
2779
2995
|
class SortedSet {
|
|
@@ -3060,6 +3276,7 @@ export function volatile_BANG_(x) {
|
|
|
3060
3276
|
|
|
3061
3277
|
export function vreset_BANG_(vol, v) {
|
|
3062
3278
|
vol.v = v;
|
|
3279
|
+
return v;
|
|
3063
3280
|
}
|
|
3064
3281
|
|
|
3065
3282
|
function toEDN(value, seen = new WeakSet()) {
|