squint-cljs 0.13.195 → 0.14.197

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.
@@ -70,7 +70,7 @@ function dequal(foo, bar) {
70
70
 
71
71
  // LazyIterable falls through to the sequential-equality path below; it is an
72
72
  // object but must compare element-wise, not by enumerable properties
73
- if ((!ctor || typeof foo === 'object') && !(foo instanceof LazyIterable)) {
73
+ if ((!ctor || typeof foo === 'object') && foo[TYPE_TAG] !== LAZY_ITERABLE_TYPE) {
74
74
  len = 0;
75
75
  for (const k in foo) {
76
76
  if (has.call(foo, k) && ++len && !has.call(bar, k)) return false;
@@ -86,12 +86,12 @@ function dequal(foo, bar) {
86
86
  // collections keep their fast paths.
87
87
  if (
88
88
  foo && bar &&
89
- (Array.isArray(foo) || foo instanceof LazyIterable) &&
90
- (Array.isArray(bar) || bar instanceof LazyIterable)
89
+ (Array.isArray(foo) || foo[TYPE_TAG] === LAZY_ITERABLE_TYPE) &&
90
+ (Array.isArray(bar) || bar[TYPE_TAG] === LAZY_ITERABLE_TYPE)
91
91
  ) {
92
92
  const fi = foo[Symbol.iterator]();
93
93
  const bi = bar[Symbol.iterator]();
94
- while (true) {
94
+ for (;;) {
95
95
  const a = fi.next();
96
96
  const b = bi.next();
97
97
  if (a.done || b.done) return !!(a.done && b.done);
@@ -249,6 +249,21 @@ const LIST_TYPE = 4;
249
249
  const SET_TYPE = 5;
250
250
  const LAZY_ITERABLE_TYPE = 6;
251
251
 
252
+ // type tag set in each collection ctor, read by typeConst (DCE: no instanceof).
253
+ const TYPE_TAG = Symbol('squint.lang.type');
254
+ const SORTED_TAG = Symbol('squint.lang.sorted');
255
+
256
+ // @__NO_SIDE_EFFECTS__ lets a bundler drop unused defclass/withApply calls; see doc/dev/dce.md
257
+ // @__NO_SIDE_EFFECTS__
258
+ function defclass(c) {
259
+ return c;
260
+ }
261
+ // @__NO_SIDE_EFFECTS__
262
+ function withApply(f, applyFn) {
263
+ f.squint$lang$variadic = applyFn;
264
+ return f;
265
+ }
266
+
252
267
  function emptyOfType(type) {
253
268
  switch (type) {
254
269
  case MAP_TYPE:
@@ -274,7 +289,7 @@ function isObj(coll) {
274
289
  }
275
290
 
276
291
  function isVectorArray(x) {
277
- return Array.isArray(x) && !(x instanceof List);
292
+ return Array.isArray(x) && x[TYPE_TAG] !== LIST_TYPE;
278
293
  }
279
294
 
280
295
  export function object_QMARK_(coll) {
@@ -291,13 +306,10 @@ function typeConst(obj) {
291
306
  }
292
307
  if (obj instanceof Map) return MAP_TYPE;
293
308
  if (obj instanceof Set) return SET_TYPE;
294
- if (obj instanceof List) return LIST_TYPE;
309
+ // brand, not instanceof, so dispatch does not reference the classes
310
+ const tag = obj[TYPE_TAG];
311
+ if (tag !== undefined) return tag;
295
312
  if (isVectorArray(obj)) return ARRAY_TYPE;
296
- if (obj instanceof LazyIterable) return LAZY_ITERABLE_TYPE;
297
- if (obj instanceof SortedSet) return SET_TYPE;
298
-
299
- // everything more specific than Object should go before this
300
- if (obj instanceof Object) return OBJECT_TYPE;
301
313
 
302
314
  return undefined;
303
315
  }
@@ -380,17 +392,31 @@ function conj_BANG_set(o, rest) {
380
392
  }
381
393
 
382
394
  export function conj_BANG_(...xs) {
383
- if (xs.length === 0) {
395
+ const n = xs.length;
396
+ if (n === 0) {
384
397
  return vector();
385
398
  }
386
399
 
387
- const [_o, ...rest] = xs;
388
-
389
- let o = _o;
400
+ let o = xs[0];
390
401
  if (o === null || o === undefined) {
391
402
  o = [];
392
403
  }
393
404
 
405
+ // Fast path for the common single-element conj! onto an array or set,
406
+ // avoiding the rest-array allocation and spread.
407
+ if (n === 2) {
408
+ switch (typeConst(o)) {
409
+ case ARRAY_TYPE:
410
+ o.push(xs[1]);
411
+ return o;
412
+ case SET_TYPE:
413
+ o.add(xs[1]);
414
+ return o;
415
+ }
416
+ }
417
+
418
+ const rest = xs.slice(1);
419
+
394
420
  switch (typeConst(o)) {
395
421
  case SET_TYPE:
396
422
  conj_BANG_set(o, rest);
@@ -440,7 +466,8 @@ export function conj(...xs) {
440
466
 
441
467
  switch (typeConst(o)) {
442
468
  case SET_TYPE:
443
- if (o instanceof SortedSet) {
469
+ // brand, not instanceof, so conj does not pin SortedSet
470
+ if (o[SORTED_TAG]) {
444
471
  // prevent re-sorting of collection
445
472
  return copyMeta(o, conj_BANG_set(new o.constructor(o), rest));
446
473
  } else {
@@ -518,19 +545,19 @@ export function dissoc_BANG_(m, ...ks) {
518
545
  export function dissoc(m, ...ks) {
519
546
  if (!m) return;
520
547
  if (ks.length === 0) return m;
548
+ if (typeConst(m) === MAP_TYPE) {
549
+ let present = false;
550
+ for (const k of ks) if (m.has(k)) { present = true; break; }
551
+ if (!present) return m;
552
+ const m2 = copy(m);
553
+ for (const k of ks) m2.delete(k);
554
+ return m2;
555
+ }
556
+ let present = false;
557
+ for (const k of ks) if (k in m) { present = true; break; }
558
+ if (!present) return m;
521
559
  const m2 = copy(m);
522
- switch (typeConst(m)) {
523
- case MAP_TYPE:
524
- for (const k of ks) {
525
- m2.delete(k);
526
- }
527
- break;
528
- default:
529
- for (const k of ks) {
530
- delete m2[k];
531
- }
532
- break;
533
- }
560
+ for (const k of ks) delete m2[k];
534
561
  return m2;
535
562
  }
536
563
 
@@ -542,8 +569,21 @@ export function dec(n) {
542
569
  return n - 1;
543
570
  }
544
571
 
572
+ export const _STAR_print_newline_STAR_ = { val: false };
573
+ export const _STAR_print_fn_STAR_ = { val: (s) => console.log(s) };
574
+ export const _STAR_print_err_fn_STAR_ = { val: (s) => console.error(s) };
575
+
576
+ export function print(...args) {
577
+ _STAR_print_fn_STAR_.val(args.map((v) => toEDN(v, undefined, false)).join(' '));
578
+ }
579
+
545
580
  export function println(...args) {
546
- console.log(...args);
581
+ print(...args);
582
+ if (_STAR_print_newline_STAR_.val) _STAR_print_fn_STAR_.val('\n');
583
+ }
584
+
585
+ export function pr(...xs) {
586
+ _STAR_print_fn_STAR_.val(pr_str(...xs));
547
587
  }
548
588
 
549
589
  export function nth(coll, idx, orElse) {
@@ -813,8 +853,8 @@ function* _reductions2(f, s) {
813
853
  }
814
854
 
815
855
  function* _reductions3(f, init, coll) {
816
- let i = init,
817
- rst = coll;
856
+ let i = init;
857
+ const rst = coll;
818
858
  while (true) {
819
859
  if (reduced_QMARK_(i)) {
820
860
  yield i.value;
@@ -854,8 +894,11 @@ const CHUNK_SIZE = 32;
854
894
 
855
895
  // One cell of a self-caching chunked seq. `step` is a thunk returning
856
896
  // [nonEmptyChunkArray, nextStep] or null at the end. See doc/dev/lazy-seqs.md.
897
+ const LazyIterable = defclass(
857
898
  class LazyIterable {
858
899
  constructor(step) {
900
+ this[TYPE_TAG] = LAZY_ITERABLE_TYPE;
901
+ this[IIterable] = true; // Closure compatibility
859
902
  this.step = step;
860
903
  this.realized = false;
861
904
  this.chunk = null; // array, or null when this is the terminal (empty) cell
@@ -892,9 +935,18 @@ class LazyIterable {
892
935
  },
893
936
  };
894
937
  }
938
+ // CLJS supports (.indexOf coll x) on seqs; mirror it so lazy seqs work like
939
+ // arrays. Uses value equality, like cljs.core, and returns -1 when absent.
940
+ indexOf(x, fromIndex = 0) {
941
+ let i = 0;
942
+ for (const v of this) {
943
+ if (i >= fromIndex && dequal(v, x)) return i;
944
+ i++;
945
+ }
946
+ return -1;
947
+ }
895
948
  }
896
-
897
- LazyIterable.prototype[IIterable] = true; // Closure compatibility
949
+ );
898
950
 
899
951
  // One-element chunks: an unchunked seq, realized one element at a time.
900
952
  function unchunkedSteps(iter) {
@@ -979,7 +1031,8 @@ function mapChunks(coll, xf) {
979
1031
  return new LazyIterable(step(src, 0));
980
1032
  }
981
1033
 
982
- export class Cons {
1034
+ export const Cons = defclass(
1035
+ class Cons {
983
1036
  constructor(x, coll) {
984
1037
  this.x = x;
985
1038
  this.coll = coll;
@@ -1007,6 +1060,7 @@ export class Cons {
1007
1060
  };
1008
1061
  }
1009
1062
  }
1063
+ );
1010
1064
 
1011
1065
  export function cons(x, coll) {
1012
1066
  return new Cons(x, coll);
@@ -1387,17 +1441,33 @@ export function set_QMARK_(x) {
1387
1441
  return typeConst(x) === SET_TYPE;
1388
1442
  }
1389
1443
 
1390
- const IApply__apply = Symbol('IApply__apply');
1391
-
1392
1444
  export function apply(f, ...args) {
1393
1445
  f = __toFn(f);
1394
1446
  const xs = args.slice(0, args.length - 1);
1395
- const coll = iterable(args[args.length - 1]);
1396
- const af = f[IApply__apply];
1397
- if (af) {
1398
- return af(...xs, coll);
1447
+ const last = args[args.length - 1];
1448
+ // variadic impl hint; see doc/adr/0001
1449
+ const v = f.squint$lang$variadic;
1450
+ if (v) {
1451
+ // pull maxfa fixed args (bounded, lazy-safe); more left -> variadic, else fixed
1452
+ const maxfa = v.length - 1;
1453
+ const fixed = [];
1454
+ let i = 0, rest;
1455
+ for (; i < maxfa && i < xs.length; i++) fixed.push(xs[i]);
1456
+ if (i < maxfa) {
1457
+ let s = seq(last);
1458
+ for (; i < maxfa && s != null; i++) {
1459
+ fixed.push(first(s));
1460
+ s = next(s);
1461
+ }
1462
+ rest = s;
1463
+ } else {
1464
+ rest = i < xs.length ? concat1([xs.slice(i), last]) : last;
1465
+ }
1466
+ rest = rest == null ? null : seq(rest);
1467
+ if (rest == null) return f(...fixed);
1468
+ return v(...fixed, rest);
1399
1469
  }
1400
- return f(...xs, ...coll);
1470
+ return f(...xs, ...iterable(last));
1401
1471
  }
1402
1472
 
1403
1473
  export function even_QMARK_(x) {
@@ -1420,6 +1490,7 @@ export function constantly(x) {
1420
1490
  class List extends Array {
1421
1491
  constructor(...args) {
1422
1492
  super();
1493
+ this[TYPE_TAG] = LIST_TYPE;
1423
1494
  this.push(...args);
1424
1495
  }
1425
1496
  }
@@ -1491,14 +1562,10 @@ function concat1(colls) {
1491
1562
  return new LazyIterable(step(null));
1492
1563
  }
1493
1564
 
1494
- export function concat(...colls) {
1495
- return concat1(colls);
1496
- }
1497
-
1498
- // lazy seqable argument
1499
- concat[IApply__apply] = (colls) => {
1500
- return concat1(colls);
1501
- };
1565
+ export const concat = withApply(
1566
+ (...colls) => concat1(colls),
1567
+ (colls) => concat1(colls), // lazy seqable argument
1568
+ );
1502
1569
 
1503
1570
  export function mapcat(f, ...colls) {
1504
1571
  if (colls.length === 0) {
@@ -2699,6 +2766,13 @@ export function keyword(arg1, arg2) {
2699
2766
  return arg1;
2700
2767
  }
2701
2768
 
2769
+ export function symbol(arg1, arg2) {
2770
+ if (arg2 !== undefined) {
2771
+ return (arg1 != null ? arg1 + '/' : '') + arg2;
2772
+ }
2773
+ return arg1;
2774
+ }
2775
+
2702
2776
  export function keyword_QMARK_(x) {
2703
2777
  return typeof x === 'string';
2704
2778
  }
@@ -2760,6 +2834,10 @@ export function int_QMARK_(x) {
2760
2834
  return Number.isInteger(x);
2761
2835
  }
2762
2836
 
2837
+ export function double_QMARK_(x) {
2838
+ return typeof x === 'number';
2839
+ }
2840
+
2763
2841
  export const integer_QMARK_ = int_QMARK_;
2764
2842
 
2765
2843
  export function pos_int_QMARK_(x) {
@@ -2794,6 +2872,10 @@ export function with_meta(x, m) {
2794
2872
  return ret;
2795
2873
  }
2796
2874
 
2875
+ export function vary_meta(x, f, ...args) {
2876
+ return with_meta(x, f(meta(x), ...args));
2877
+ }
2878
+
2797
2879
  export function boolean_QMARK_(x) {
2798
2880
  return x === true || x === false;
2799
2881
  }
@@ -2881,9 +2963,11 @@ export function parse_long(s) {
2881
2963
 
2882
2964
  export function parse_double(s) {
2883
2965
  if (string_QMARK_(s)) {
2966
+ // eslint-disable-next-line no-control-regex -- \x00-\x20 mirrors Java trim
2884
2967
  if (/^[\x00-\x20]*[+-]?NaN[\x00-\x20]*$/.test(s)) {
2885
2968
  return NaN;
2886
2969
  } else if (
2970
+ // eslint-disable-next-line no-control-regex -- \x00-\x20 mirrors Java trim
2887
2971
  /^[\x00-\x20]*[+-]?(Infinity|((\d+\.?\d*|\.\d+)([eE][+-]?\d+)?)[dDfF]?)[\x00-\x20]*$/.test(
2888
2972
  s
2889
2973
  )
@@ -2996,8 +3080,11 @@ export function persistent_BANG_(x) {
2996
3080
  return x;
2997
3081
  }
2998
3082
 
3083
+ const SortedSet = defclass(
2999
3084
  class SortedSet {
3000
3085
  constructor(xs) {
3086
+ this[TYPE_TAG] = SET_TYPE;
3087
+ this[SORTED_TAG] = true;
3001
3088
  const isSorted = xs instanceof SortedSet;
3002
3089
  if (!isSorted) {
3003
3090
  xs = sort(xs);
@@ -3060,6 +3147,7 @@ class SortedSet {
3060
3147
  return this.keys();
3061
3148
  }
3062
3149
  }
3150
+ );
3063
3151
 
3064
3152
  export function sorted_set(...xs) {
3065
3153
  return new SortedSet(xs);
@@ -3283,7 +3371,8 @@ export function vreset_BANG_(vol, v) {
3283
3371
  return v;
3284
3372
  }
3285
3373
 
3286
- function toEDN(value, seen = new WeakSet()) {
3374
+ // readably false: strings unquoted
3375
+ function toEDN(value, seen = new WeakSet(), readably = true) {
3287
3376
  if (value == null) return 'nil';
3288
3377
  if (typeof value === 'number') {
3289
3378
  if (value === Infinity) return '##Inf';
@@ -3292,39 +3381,48 @@ function toEDN(value, seen = new WeakSet()) {
3292
3381
  return String(value);
3293
3382
  }
3294
3383
  if (typeof value === 'boolean') return String(value);
3295
- if (typeof value === 'string') return JSON.stringify(value);
3384
+ if (typeof value === 'string') return readably ? JSON.stringify(value) : value;
3296
3385
  if (typeof value === 'bigint') return `${value}N`;
3297
3386
 
3298
3387
  if (typeof value === 'object') {
3388
+ // seen tracks the current ancestor path only. A shared reference that
3389
+ // appears under sibling branches is a DAG, not a cycle, so delete on exit.
3299
3390
  if (seen.has(value)) return '#object[circular]';
3300
3391
  seen.add(value);
3301
3392
  const T = typeConst(value);
3302
- let keys;
3393
+ let keys, result;
3303
3394
  switch (T) {
3304
3395
  case ARRAY_TYPE:
3305
- return `[${value.map((v) => toEDN(v, seen)).join(' ')}]`;
3396
+ result = `[${value.map((v) => toEDN(v, seen, readably)).join(' ')}]`;
3397
+ break;
3306
3398
  case SET_TYPE:
3307
- return `#{${Array.from(value)
3308
- .map((v) => toEDN(v, seen))
3399
+ result = `#{${Array.from(value)
3400
+ .map((v) => toEDN(v, seen, readably))
3309
3401
  .join(' ')}}`;
3402
+ break;
3310
3403
  case MAP_TYPE:
3311
- return `#js/Map {${Array.from(value.entries())
3312
- .map(([k, v]) => `${toEDN(k, seen)} ${toEDN(v, seen)}`)
3404
+ result = `#js/Map {${Array.from(value.entries())
3405
+ .map(([k, v]) => `${toEDN(k, seen, readably)} ${toEDN(v, seen, readably)}`)
3313
3406
  .join(', ')}}`;
3407
+ break;
3314
3408
  case LAZY_ITERABLE_TYPE:
3315
3409
  case LIST_TYPE:
3316
- return `(${mapv((v) => `${toEDN(v, seen)}`, value).join(', ')})`;
3410
+ result = `(${mapv((v) => `${toEDN(v, seen, readably)}`, value).join(', ')})`;
3411
+ break;
3317
3412
  default:
3318
3413
  // Non-plain objects (Promise, Error, Date, class instances, ...) have a
3319
3414
  // constructor other than Object. Print them as #<Name> rather than {}
3320
3415
  // (which is what Object.keys would yield for opaque values like a
3321
3416
  // Promise).
3322
3417
  if (value.constructor && value.constructor !== Object) {
3418
+ seen.delete(value);
3323
3419
  return `#<${value.constructor.name}>`;
3324
3420
  }
3325
3421
  keys = Object.keys(value);
3326
- return `{${keys.map((k) => `:${k} ${toEDN(value[k], seen)}`).join(', ')}}`;
3422
+ result = `{${keys.map((k) => `:${k} ${toEDN(value[k], seen, readably)}`).join(', ')}}`;
3327
3423
  }
3424
+ seen.delete(value);
3425
+ return result;
3328
3426
  }
3329
3427
 
3330
3428
  return `#object[${value.constructor.name}]`;
@@ -3335,5 +3433,6 @@ export function pr_str(...xs) {
3335
3433
  }
3336
3434
 
3337
3435
  export function prn(...xs) {
3338
- return console.log(pr_str(...xs));
3436
+ _STAR_print_fn_STAR_.val(pr_str(...xs));
3437
+ if (_STAR_print_newline_STAR_.val) _STAR_print_fn_STAR_.val('\n');
3339
3438
  }