@temperlang/core 0.3.0 → 0.4.0

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/index.js CHANGED
@@ -1,1255 +1,13 @@
1
- export * from "./interface-types.js";
1
+ export * from "./async.js";
2
+ export * from "./bitvector.js";
3
+ export * from "./check-type.js";
4
+ export * from "./core.js";
5
+ export * from "./date.js";
6
+ export * from "./deque.js";
7
+ export * from "./float.js";
8
+ export * from "./interface.js";
9
+ export * from "./listed.js";
10
+ export * from "./mapped.js";
11
+ export * from "./pair.js";
2
12
  export * from "./regex.js";
3
-
4
- // Implements extension method String::isEmpty
5
- export function stringIsEmpty(s) {
6
- return s === "";
7
- }
8
-
9
- // Implements extension method String::split
10
- export function stringSplit(s, separator) {
11
- return separator ? s.split(separator).map((s) => s) : Array.from(s);
12
- }
13
-
14
- /**
15
- * Implements extension method String::toFloat64
16
- * @param {string} s
17
- */
18
- export function stringToFloat64(s) {
19
- // TODO Consider JSON.parse + bonus constants instead? Faster or not?
20
- if (!/^\s*-?(?:\d+(?:\.\d+)?(?:[eE][-+]?\d+)?|NaN|Infinity)\s*$/.test(s)) {
21
- bubble();
22
- }
23
- return Number(s);
24
- }
25
-
26
- /**
27
- * Implements extension method String::toInt
28
- * @param {string} s
29
- */
30
- export function stringToInt(s) {
31
- // I'm not sure there's another simple reliable way to know if it's all used.
32
- // This also checks against things like 2e0 -> 2.
33
- if (!/^\s*-?\d+\s*$/.test(s)) {
34
- bubble();
35
- }
36
- const result = parseInt(s, 10);
37
- // TODO Could we use a more precise regex above to avoid this check here?
38
- requireIsSafeInteger(result);
39
- return result;
40
- }
41
-
42
- /**
43
- * @typedef StringSlice
44
- */
45
- let StringSlice;
46
-
47
- /**
48
- * Specifically for utf8 and utf32, since utf16 is simpler in js.
49
- *
50
- * @implements StringSlice
51
- */
52
- class TrickyStringSlice {
53
- hasAtLeast(count) {
54
- // Repeated calls to hasAtLeast are potentially expensive.
55
- return (this.length ?? this._lengthUntil(count)) >= count;
56
- }
57
-
58
- get length() {
59
- if (this._length === undefined) {
60
- this._length = this._lengthUntil();
61
- }
62
- return this._length;
63
- }
64
-
65
- _lengthUntil(stop = undefined) {
66
- // To be overridden in subclasses.
67
- return 0;
68
- }
69
- }
70
-
71
- class Utf8StringSlice extends TrickyStringSlice {
72
- constructor(content, left = 0, right = content.length * 4) {
73
- super();
74
- this.content = content;
75
- this.left = left;
76
- this.right = right;
77
- }
78
-
79
- toString() {
80
- let left = this.left;
81
- let right = this.right;
82
- let content = this.content;
83
-
84
- if (left === right) {
85
- return "";
86
- }
87
-
88
- // If we're only using some bytes on the left or right, replace that codepoint with U+FFFD.
89
- let leftPartial = left & 3; // Do we have an incomplete code-point on the left?
90
- let leftIndex = (left + 3) >> 2;
91
- let rightIndex = right >> 2;
92
- let rightPartial = right & 3;
93
-
94
- // If leftIndex is in the middle of a surrogate pair, advance over the tail.
95
- if (leftIndex < rightIndex) {
96
- let leftCodeUnitUtf16 = content.charCodeAt(leftIndex);
97
- if (0xdc00 < leftCodeUnitUtf16 && leftCodeUnitUtf16 <= 0xdfff) {
98
- leftIndex += 1;
99
- }
100
- }
101
-
102
- if (leftIndex > rightIndex) {
103
- return "\uFFFD";
104
- }
105
-
106
- let sub = content.substring(leftIndex, rightIndex);
107
- if (leftPartial || rightPartial) {
108
- return `${leftPartial ? "\uFFFD" : ""}${sub}${
109
- rightPartial ? "\uFFFD" : ""
110
- }`;
111
- } else {
112
- return sub;
113
- }
114
- }
115
-
116
- valueOf() {
117
- return this.toString();
118
- }
119
-
120
- _lengthUntil(stop) {
121
- const left = this.left;
122
- const right = this.right;
123
- const content = this.content;
124
- let i = left >> 2;
125
- // Add bytes between codePointBoundaryBeforeLimit and right
126
- // Subtract bytes past zeroth in codepoint for left
127
- let len = (right & 3) - (left & 3);
128
- const codePointBoundaryBeforeLimit = (right & ~3) >> 2;
129
- while (i < codePointBoundaryBeforeLimit) {
130
- if (stop !== undefined && len >= stop) {
131
- break;
132
- }
133
- let cp = content.codePointAt(i);
134
- let nBytes = nUtf8BytesInChar(cp);
135
- len += nBytes;
136
- i += (4 + nBytes) >> 2;
137
- }
138
- return len;
139
- }
140
-
141
- get isEmpty() {
142
- return this.left >= this.right;
143
- }
144
-
145
- read() {
146
- let left = this.left;
147
- let right = this.right;
148
- if (left >= right) {
149
- bubble();
150
- }
151
-
152
- let content = this.content;
153
- let cp = content.codePointAt(left >> 2);
154
- if (cp < 0x80) {
155
- return cp;
156
- } else {
157
- let byteOffset = left & 3;
158
- let nBytes = nUtf8BytesInChar(cp);
159
- let byteInfo = byteInfos[(nBytes - 1) * 4 + byteOffset];
160
- let codeUnit =
161
- ((cp >>> byteInfo.shift) & byteInfo.andMask) | byteInfo.orMask;
162
- return codeUnit;
163
- }
164
- }
165
-
166
- /**
167
- * @param {number} count
168
- * @return {number}
169
- */
170
- _advanceLeft(count) {
171
- let left = this.left;
172
- let content = this.content;
173
- let contentLen = content.length;
174
- let idx = left >> 2;
175
- let sub = left & 3;
176
-
177
- while (count > 0 && idx < contentLen) {
178
- let cp = content.codePointAt(idx);
179
- let rem = nUtf8BytesInChar(cp) - sub;
180
- if (rem > count) {
181
- sub += count;
182
- count = 0;
183
- } else {
184
- count -= rem;
185
- sub = 0;
186
- idx += cp > 0x10000 ? 2 : 1;
187
- }
188
- }
189
-
190
- return count ? this.right : Math.min(idx << 2 | sub, this.right);
191
- }
192
-
193
- /**
194
- * @param {number} count
195
- * @return {Utf8StringSlice}
196
- */
197
- advance(count) {
198
- let newLeft = this._advanceLeft(count);
199
- return (this.left === newLeft)
200
- ? this
201
- : new Utf8StringSlice(this.content, newLeft, this.right);
202
- }
203
-
204
- /**
205
- * @param {number} count
206
- * @return {Utf8StringSlice}
207
- */
208
- limit(count) {
209
- let newRight = this._advanceLeft(count);
210
- return (this.right === newRight)
211
- ? this
212
- : new Utf8StringSlice(this.content, this.left, newRight);
213
- }
214
-
215
- /**
216
- * @param {StringSlice} slice
217
- * @return {Utf8StringSlice}
218
- */
219
- intersect(slice) {
220
- let { content, left, right } = this;
221
- let { left: otherLeft, right: otherRight } = slice;
222
-
223
- // Derivation of this in StringSliceHelpers
224
- let newLeft, newRight;
225
- if (otherLeft >= right) {
226
- newLeft = newRight = right;
227
- } else if (otherRight <= left) {
228
- newLeft = newLeft = left;
229
- } else {
230
- newLeft = Math.max(left, otherLeft);
231
- newRight = Math.min(right, otherRight);
232
- }
233
- return newLeft === left && newRight === right
234
- ? this : new Utf8StringSlice(content, newLeft, newRight);
235
- }
236
-
237
- /**
238
- * @param {StringSlice} slice
239
- * @returns {Utf8StringSlice}
240
- */
241
- excludeAfter(slice) {
242
- let { content, left, right } = this;
243
- let { left: otherLeft } = slice;
244
- let newRight = Math.max(left, Math.min(right, otherLeft));
245
- return right === newRight
246
- ? this : new Utf8StringSlice(content, left, newRight);
247
- }
248
-
249
- [Symbol.iterator]() {
250
- function* bytes(content, left, limit) {
251
- let i = left;
252
- while (i < limit) {
253
- let cp = content.codePointAt(i >> 2);
254
- if (cp < 0x80) {
255
- yield cp;
256
- i += 4;
257
- } else {
258
- let byteOffset = i & 3;
259
- let nBytes = nUtf8BytesInChar(cp);
260
- let byteInfo = byteInfos[(nBytes - 1) * 4 + byteOffset];
261
- let codeUnit =
262
- ((cp >>> byteInfo.shift) & byteInfo.andMask) | byteInfo.orMask;
263
- yield codeUnit;
264
- i = byteOffset + 1 < nBytes ? i + 1 : (i & ~3) + ((nBytes + 4) & ~3);
265
- }
266
- }
267
- }
268
- return bytes(this.content, this.left, this.right);
269
- }
270
-
271
- toJSON() {
272
- return { content: this.content, left: this.left, right: this.right };
273
- }
274
- }
275
-
276
- /**
277
- * @implements StringSlice
278
- */
279
- class Utf16StringSlice {
280
- constructor(content, left = 0, right = content.length) {
281
- this.content = content;
282
- this.left = left;
283
- this.right = right;
284
- }
285
-
286
- toString() {
287
- return this.content.substring(this.left, this.right);
288
- }
289
-
290
- valueOf() {
291
- return this.toString();
292
- }
293
-
294
- hasAtLeast(count) {
295
- return this.length >= count;
296
- }
297
-
298
- get length() {
299
- return this.right - this.left;
300
- }
301
-
302
- get isEmpty() {
303
- return this.left >= this.right;
304
- }
305
-
306
- read() {
307
- let left = this.left;
308
- let right = this.right;
309
- if (left >= right) {
310
- bubble();
311
- }
312
- return this.content.charCodeAt(left);
313
- }
314
-
315
- /**
316
- * @param {number} count
317
- * @return {number}
318
- */
319
- _advanceLeft(count) {
320
- return Math.min(this.left + count, this.right);
321
- }
322
-
323
- /**
324
- * @param {number} count
325
- * @return {Utf16StringSlice}
326
- */
327
- advance(count) {
328
- let newLeft = this._advanceLeft(count);
329
- return this.left === newLeft
330
- ? this
331
- : new Utf16StringSlice(this.content, newLeft, this.right);
332
- }
333
-
334
- /**
335
- * @param {number} count
336
- * @return {Utf16StringSlice}
337
- */
338
- limit(count) {
339
- let newRight = this._advanceLeft(count);
340
- return this.right === newRight
341
- ? this
342
- : new Utf16StringSlice(this.content, this.left, newRight);
343
- }
344
-
345
- /**
346
- * @param {StringSlice} slice
347
- * @return {Utf16StringSlice}
348
- */
349
- intersect(slice) {
350
- let { content, left, right } = this;
351
- let { left: otherLeft, right: otherRight } = slice;
352
-
353
- // Derivation of this in StringSliceHelpers
354
- let newLeft, newRight;
355
- if (otherLeft >= right) {
356
- newLeft = newRight = right;
357
- } else if (otherRight <= left) {
358
- newLeft = newLeft = left;
359
- } else {
360
- newLeft = Math.max(left, otherLeft);
361
- newRight = Math.min(right, otherRight);
362
- }
363
- return newLeft === left && newRight === right
364
- ? this : new Utf16StringSlice(content, newLeft, newRight);
365
- }
366
-
367
- /**
368
- * @param {StringSlice} slice
369
- * @returns {Utf16StringSlice}
370
- */
371
- excludeAfter(slice) {
372
- let { content, left, right } = this;
373
- let { left: otherLeft } = slice;
374
- let newRight = Math.max(left, Math.min(right, otherLeft));
375
- return right === newRight
376
- ? this : new Utf16StringSlice(content, left, newRight);
377
- }
378
-
379
- [Symbol.iterator]() {
380
- function* chars(content, left, limit) {
381
- let i = left;
382
- while (i < limit) {
383
- yield content.charCodeAt(i);
384
- i += 1;
385
- }
386
- }
387
- return chars(this.content, this.left, this.right);
388
- }
389
-
390
- toJSON() {
391
- return { content: this.content, left: this.left, right: this.right };
392
- }
393
- }
394
-
395
- class CodePointStringSlice extends TrickyStringSlice {
396
- constructor(content, left = 0, right = content.length) {
397
- super();
398
- this.content = content;
399
- this.left = left;
400
- this.right = right;
401
- }
402
-
403
- toString() {
404
- return this.content.substring(this.left, this.right);
405
- }
406
-
407
- valueOf() {
408
- return this.toString();
409
- }
410
-
411
- _lengthUntil(stop) {
412
- let i = this.left;
413
- let len = 0;
414
- while (i < this.right) {
415
- if (stop !== undefined && len >= stop) {
416
- break;
417
- }
418
- let cp = this.content.codePointAt(i);
419
- if (cp > 0xffff) {
420
- i += 2;
421
- } else {
422
- i += 1;
423
- }
424
- len += 1;
425
- }
426
- return len;
427
- }
428
-
429
- get isEmpty() {
430
- return this.left >= this.right;
431
- }
432
-
433
- read() {
434
- if (this.left >= this.right) {
435
- bubble();
436
- }
437
- return this.content.codePointAt(this.left);
438
- }
439
-
440
- /**
441
- * @param {number} count
442
- * @return {number}
443
- */
444
- _advanceLeft(count) {
445
- let left = this.left;
446
- let right = this.right;
447
- let content = this.content;
448
- if (count <= 0) { return left }
449
- let newLeft = left;
450
- for (let i = count; i && newLeft < right; --i) {
451
- let cp = content.codePointAt(newLeft);
452
- if (cp > 0xffff) {
453
- newLeft += 2;
454
- } else {
455
- newLeft += 1;
456
- }
457
- }
458
- if (newLeft >= right) {
459
- newLeft = right;
460
- }
461
- return newLeft;
462
- }
463
-
464
- /**
465
- * @param {number} count
466
- * @return {CodePointStringSlice}
467
- */
468
- advance(count) {
469
- let newLeft = this._advanceLeft(count);
470
- return (newLeft === this.left)
471
- ? this
472
- : new CodePointStringSlice(this.content, newLeft, this.right);
473
- }
474
-
475
- /**
476
- * @param {number} count
477
- * @return {CodePointStringSlice}
478
- */
479
- limit(count) {
480
- let newRight = this._advanceLeft(count);
481
- return (newRight === this.right)
482
- ? this
483
- : new CodePointStringSlice(this.content, this.left, newRight);
484
- }
485
-
486
- /**
487
- * @param {StringSlice} slice
488
- * @return {CodePointStringSlice}
489
- */
490
- intersect(slice) {
491
- let { content, left, right } = this;
492
- let { left: otherLeft, right: otherRight } = slice;
493
-
494
- // Derivation of this in StringSliceHelpers
495
- let newLeft, newRight;
496
- if (otherLeft >= right) {
497
- newLeft = newRight = right;
498
- } else if (otherRight <= left) {
499
- newLeft = newLeft = left;
500
- } else {
501
- newLeft = Math.max(left, otherLeft);
502
- newRight = Math.min(right, otherRight);
503
- }
504
- return newLeft === left && newRight === right
505
- ? this : new CodePointStringSlice(content, newLeft, newRight);
506
- }
507
-
508
- /**
509
- * @param {StringSlice} slice
510
- * @returns {CodePointStringSlice}
511
- */
512
- excludeAfter(slice) {
513
- let { content, left, right } = this;
514
- let { left: otherLeft } = slice;
515
- let newRight = Math.max(left, Math.min(right, otherLeft));
516
- return right === newRight ? this : new CodePointStringSlice(content, left, newRight);
517
- }
518
-
519
- [Symbol.iterator]() {
520
- function* chars(content, left, limit) {
521
- let i = left;
522
- while (i < limit) {
523
- let cp = content.codePointAt(i);
524
- yield cp;
525
- i += cp > 0xffff ? 2 : 1;
526
- }
527
- }
528
- return chars(this.content, this.left, this.right);
529
- }
530
-
531
- toJSON() {
532
- return { content: this.content, left: this.left, right: this.right };
533
- }
534
- }
535
-
536
- // Implements extension method String::utf8
537
- export function stringUtf8(string) {
538
- return new Utf8StringSlice(string);
539
- }
540
-
541
- // Implements extension method String::utf16
542
- export function stringUtf16(string) {
543
- return new Utf16StringSlice(string);
544
- }
545
-
546
- // Implements extension method String::codePoints
547
- export function stringCodePoints(string) {
548
- return new CodePointStringSlice(string);
549
- }
550
-
551
- // Implements extension method Int::toString
552
- export function intToString(i, radix) {
553
- return i.toString(radix);
554
- }
555
-
556
- // Implements extension method Float64::near
557
- export function float64Near(x, y, relTol, absTol) {
558
- if (relTol === undefined) {
559
- relTol = 1e-9;
560
- }
561
- if (absTol === undefined) {
562
- absTol = 0;
563
- }
564
- const margin = Math.max(Math.max(Math.abs(x), Math.abs(y)) * relTol, absTol);
565
- return Math.abs(x - y) < margin;
566
- }
567
-
568
- // Implements extension method Float64::toInt
569
- export function float64ToInt(n) {
570
- const i = float64ToIntUnsafe(n);
571
- if (Math.abs(n - i) < 1) {
572
- return i;
573
- } else {
574
- bubble();
575
- }
576
- }
577
-
578
- // Implements extension method Float64::toIntUnsafe
579
- export function float64ToIntUnsafe(n) {
580
- // We are free to do whatever with NaN here.
581
- return isNaN(n)
582
- ? 0
583
- : Math.max(
584
- Number.MIN_SAFE_INTEGER,
585
- Math.min(Math.trunc(n), Number.MAX_SAFE_INTEGER)
586
- );
587
- }
588
-
589
- // Implements extension method Float64::toString
590
- export function float64ToString(n) {
591
- // TODO(mikesamuel, issue#579): need functional test to nail down
592
- // double formatting threshholds.
593
- if (n == 0) {
594
- return Object.is(n, -0) ? "-0.0" : "0.0";
595
- } else {
596
- let result = n.toString();
597
- // Rely on eagerness and js number formatting rules here.
598
- const groups = /(-?[0-9]+)(\.[0-9]+)?(.+)?/.exec(result);
599
- if (groups === null) {
600
- return result;
601
- } else {
602
- // Guarantee a decimal point for floats.
603
- return `${groups[1]}${groups[2] || ".0"}${groups[3] || ""}`;
604
- }
605
- }
606
- }
607
-
608
- function nUtf8BytesInChar(cp) {
609
- return cp < 0x0800 ? (cp < 0x80 ? 1 : 2) : cp < 0x10000 ? 3 : 4;
610
- }
611
-
612
- /*
613
- * | First code point | Last code point | Byte 0 | Byte 1 | Byte 2 | Byte 3 |
614
- * | ---------------- | --------------- | --------- | --------- | --------- | --------- |
615
- * | U+0000 | U+007F | 0xxx_xxxx | | | |
616
- * | U+0080 | U+07FF | 110x_xxxx | 10xx_xxxx | | |
617
- * | U+0800 | U+FFFF | 1110_xxxx | 10xx_xxxx | 10xx_xxxx | |
618
- * | U+10000 | U+10FFFF | 1111_0xxx | 10xx_xxxx | 10xx_xxxx | 10xx_xxxx |
619
- */
620
- const byteInfos = [
621
- { andMask: 0b0111_1111, orMask: 0, shift: 0 },
622
- null,
623
- null,
624
- null,
625
-
626
- { andMask: 0b0001_1111, orMask: 0b1100_0000, shift: 6 },
627
- { andMask: 0b0011_1111, orMask: 0b1000_0000, shift: 0 },
628
- null,
629
- null,
630
-
631
- { andMask: 0b0000_1111, orMask: 0b1110_0000, shift: 12 },
632
- { andMask: 0b0011_1111, orMask: 0b1000_0000, shift: 6 },
633
- { andMask: 0b0011_1111, orMask: 0b1000_0000, shift: 0 },
634
- null,
635
-
636
- { andMask: 0b0000_0111, orMask: 0b1111_0000, shift: 18 },
637
- { andMask: 0b0011_1111, orMask: 0b1000_0000, shift: 12 },
638
- { andMask: 0b0011_1111, orMask: 0b1000_0000, shift: 6 },
639
- { andMask: 0b0011_1111, orMask: 0b1000_0000, shift: 0 },
640
- ];
641
-
642
- // Implements extension method ListBuilder::add
643
- export function listBuilderAdd(ls, newItem, at) {
644
- if (at === undefined) {
645
- // Technically, we could also use splice instead of push for this case.
646
- // Which is better might depend on minifiers and/or execution speed.
647
- ls.push(newItem);
648
- } else {
649
- if (at < 0 || at > ls.length) {
650
- bubble();
651
- }
652
- ls.splice(at, 0, newItem);
653
- }
654
- }
655
- // Implements extension method ListBuilder::addAll
656
- export function listBuilderAddAll(ls, newItems, at) {
657
- if (at === undefined) {
658
- ls.push(...newItems);
659
- } else {
660
- if (at < 0 || at > ls.length) {
661
- bubble();
662
- }
663
- ls.splice(at, 0, ...newItems);
664
- }
665
- }
666
- // Implements extension method Listed::filter
667
- export function listedFilter(ls, predicate) {
668
- let filtered = null;
669
- let nFiltered = 0; // Just past index of last element of ls filtered onto filtered
670
- let { length } = ls;
671
- for (let i = 0; i < length; ++i) {
672
- let element = ls[i];
673
- let ok = predicate(element);
674
- if (!ok) {
675
- if (!filtered) {
676
- filtered = [];
677
- }
678
- filtered.push(...ls.slice(nFiltered, i));
679
- nFiltered = i + 1;
680
- }
681
- }
682
- let fullyFiltered;
683
- if (filtered) {
684
- filtered.push(...ls.slice(nFiltered, length));
685
- fullyFiltered = filtered;
686
- } else {
687
- fullyFiltered = ls;
688
- }
689
- return freeze(fullyFiltered);
690
- }
691
- // Implements extension method Listed::get
692
- export function listedGet(ls, i) {
693
- let { length } = ls;
694
- if (0 <= i && i < length) {
695
- return ls[i];
696
- }
697
- bubble();
698
- }
699
- // Implements extension method Listed::getOr
700
- export function listedGetOr(ls, i, fallback) {
701
- let { length } = ls;
702
- return 0 <= i && i < length ? ls[i] : fallback;
703
- }
704
- // Implements extension method List::isEmpty
705
- export function listIsEmpty(ls) {
706
- return !ls.length;
707
- }
708
- // Implements extension method Listed::join
709
- export function listedJoin(ls, separator, elementStringifier) {
710
- let joined = "";
711
- let { length } = ls;
712
- for (let i = 0; i < length; ++i) {
713
- if (i) {
714
- joined += separator;
715
- }
716
- let element = ls[i];
717
- let stringifiedElement = elementStringifier(element);
718
- joined += stringifiedElement;
719
- }
720
- return joined;
721
- }
722
- // Implements extension method Listed::mapDropping
723
- export function listedMapDropping() {
724
- throw new Error("TODO List::mapDropping");
725
- }
726
- // Implements extension method Listed::map
727
- export function listedMap(ls, transform) {
728
- let mapped = [];
729
- let { length } = ls;
730
- for (let i = 0; i < length; ++i) {
731
- let transformed = transform(ls[i]);
732
- mapped[i] = transformed;
733
- }
734
- return freeze(mapped);
735
- }
736
- // Implements extension method Listed::reduceFrom
737
- export function listedReduceFrom(ls, initial, accumulate) {
738
- return ls.reduce(accumulate, initial);
739
- }
740
- // Implements extension method Listed::toList
741
- export function listedToList(ls) {
742
- if (Object.isFrozen(ls)) {
743
- return ls;
744
- } else {
745
- return listBuilderToList(ls);
746
- }
747
- }
748
- // Implements extension method ListBuilder::removeLast
749
- export function listBuilderRemoveLast(ls) {
750
- if (ls.length) {
751
- return ls.pop();
752
- } else {
753
- bubble();
754
- }
755
- }
756
- // Implements extension method ListBuilder::reverse
757
- export function listBuilderReverse(ls) {
758
- let { length } = ls;
759
- let lastIndex = length - 1;
760
- let mid = length >> 1;
761
- for (let i = 0; i < mid; ++i) {
762
- let j = lastIndex - i;
763
- let a = ls[i];
764
- ls[i] = ls[j];
765
- ls[j] = a;
766
- }
767
- }
768
- // Implements extension method ListBuilder::set
769
- export function listBuilderSet(ls, i, newValue) {
770
- if (0 <= i && i <= ls.length) {
771
- ls[i] = newValue;
772
- }
773
- }
774
- // Implements extension method ListBuilder::removeLast
775
- export function listBuilderSplice(ls, index, removeCount, newValues) {
776
- // Missing count is all, but explicit undefined is 0, so give explicit length.
777
- if (removeCount === undefined) {
778
- removeCount = ls.length;
779
- }
780
- return freeze(ls.splice(index, removeCount, ...(newValues || [])));
781
- }
782
- // Implements extension method ListBuilder::toList
783
- export function listBuilderToList(ls) {
784
- return freeze(ls.slice());
785
- }
786
- // Implements extension method Listed::slice
787
- export function listedSlice(ls, startInclusive, endExclusive) {
788
- if (startInclusive < 0) {
789
- startInclusive = 0;
790
- }
791
- if (endExclusive < 0) {
792
- endExclusive = 0;
793
- }
794
- return freeze(ls.slice(startInclusive, endExclusive));
795
- }
796
-
797
- // Map
798
- class FreezeMap extends Map {
799
- // TODO Don't worry to freeze? Or worry more by wrapping private map?
800
- // TODO Wrapping/Object.proxy presumably pays an extra cost when wrapped.
801
- clear() {
802
- throw new TypeError();
803
- }
804
- delete() {
805
- throw new TypeError();
806
- }
807
- set(key, value) {
808
- if (Object.isFrozen(this)) {
809
- // Crash only after frozen because constructor calls set.
810
- throw new TypeError();
811
- }
812
- return super.set(key, value);
813
- }
814
- }
815
- export function mapConstructor(entries) {
816
- return freeze(new FreezeMap(entries));
817
- }
818
- // MapBuilder
819
- export function mapBuilderConstructor(entries) {
820
- return new Map();
821
- }
822
- export function mapBuilderRemove(builder, key) {
823
- const result = builder.get(key);
824
- if (builder.delete(key)) {
825
- return result;
826
- } else {
827
- bubble();
828
- }
829
- }
830
- export function mapBuilderSet(builder, key, value) {
831
- builder.set(key, value);
832
- }
833
- export function mappedToMap(mapped) {
834
- if (mapped instanceof FreezeMap) {
835
- return mapped;
836
- }
837
- return freeze(new FreezeMap(mapped));
838
- }
839
- export function mapBuilderToMap(mapped) {
840
- return freeze(new FreezeMap(mapped));
841
- }
842
- export function mappedToMapBuilder(mapped) {
843
- return new Map(mapped);
844
- }
845
- // Pair
846
- class Pair {
847
- constructor(key, value) {
848
- this.key = key;
849
- this.value = value;
850
- }
851
- get [0]() {
852
- return this.key;
853
- }
854
- get [1]() {
855
- return this.value;
856
- }
857
- get length() {
858
- return 2;
859
- }
860
- }
861
- export function pairConstructor(key, value) {
862
- return freeze(new Pair(key, value));
863
- }
864
- // Mapped
865
- export function mappedLength(map) {
866
- return map.size;
867
- }
868
- export function mappedGet(map, key) {
869
- const result = map.get(key);
870
- // TODO Under compiler-error-free Temper, could undefined values get set?
871
- // TODO Would Map<?, Void> be impossible to feed once we get checks in place?
872
- if (result === undefined) {
873
- bubble();
874
- }
875
- return result;
876
- }
877
- export function mappedGetOr(map, key, fallback) {
878
- return map.get(key) ?? fallback;
879
- }
880
- export function mappedHas(map, key) {
881
- return map.has(key);
882
- }
883
- export function mappedKeys(map) {
884
- return freeze(Array.prototype.slice.call(map.keys()));
885
- }
886
- export function mappedValues(map) {
887
- return freeze(Array.prototype.slice.call(map.values()));
888
- }
889
- export function mappedToList(map) {
890
- return freeze(Array.from(map, ([key, value]) => new Pair(key, value)));
891
- }
892
- export function mappedToListWith(map, func) {
893
- return freeze(Array.from(map, ([key, value]) => func(key, value)));
894
- }
895
- export function mappedToListBuilder(map) {
896
- return freeze(Array.from(map, ([key, value]) => new Pair(key, value)));
897
- }
898
- export function mappedToListBuilderWith(map, func) {
899
- return freeze(Array.from(map, ([key, value]) => func(key, value)));
900
- }
901
- export function mappedForEach(map, func) {
902
- map.forEach((v, k) => func(k, v));
903
- }
904
-
905
- // Implements Date::constructor
906
- export function dateConstructor(year, month, day) {
907
- let d = new Date(0);
908
- // If we were to pass year into `new Date`, then it would
909
- // have 1900 added when in the range [0, 99].
910
- // developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/Date#year
911
- d.setUTCFullYear(year);
912
- d.setUTCMonth(month - 1 /* JS months are zero indexed */);
913
- d.setUTCDate(day); // UTCDay is day of the week
914
- return d;
915
- }
916
-
917
- // Implements Date::today
918
- /**
919
- * @returns {Date}
920
- */
921
- export function dateToday() {
922
- let d = new Date(Date.now());
923
- // Get rid of the time component.
924
- d.setTime(
925
- Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate())
926
- );
927
- return d;
928
- }
929
-
930
- // Implements Date::yearsBetween
931
- /**
932
- * @param {Date} start
933
- * @param {Date} end
934
- *
935
- * @returns {number}
936
- */
937
- export function dateYearsBetween(start, end) {
938
- let yearDelta = end.getUTCFullYear() - start.getUTCFullYear();
939
- let monthDelta = end.getUTCMonth() - start.getUTCMonth();
940
- return yearDelta -
941
- // If the end month/day is before the start's then we
942
- // don't have a full year.
943
- (monthDelta < 0 || monthDelta == 0 && end.getUTCDate() < start.getUTCDate());
944
- }
945
-
946
- // Implements extension method Deque::constructor
947
- const DEQUE_NTAKEN = Symbol("Deque::nTaken");
948
- export function dequeConstructor() {
949
- let deque = [];
950
- Object.defineProperty(deque, DEQUE_NTAKEN, { value: 0, writable: true });
951
- return deque;
952
- }
953
- // Implements extension method Deque::add
954
- export function dequeAdd(deque, element) {
955
- deque.push(element);
956
- }
957
- // Implements extension method Deque::isEmpty
958
- export function dequeIsEmpty(deque) {
959
- return deque.length === (deque[DEQUE_NTAKEN] || 0);
960
- }
961
- // Implements extension method Deque::removeFirst
962
- export function dequeRemoveFirst(deque) {
963
- // https://gist.github.com/mikesamuel/444258e7005e8fc9534d9cf274b1df58
964
- let nTaken = deque[DEQUE_NTAKEN];
965
- let length = deque.length;
966
- if (length === nTaken) {
967
- deque[DEQUE_NTAKEN] = 0;
968
- deque.length = 0;
969
- bubble();
970
- }
971
- let item = deque[nTaken];
972
- let nShiftThreshhold = (length / 2) | 0;
973
- if (nShiftThreshhold < 32) {
974
- nShiftThreshhold = 32;
975
- }
976
- if (nTaken >= nShiftThreshhold) {
977
- deque.splice(0, nTaken + 1);
978
- deque[DEQUE_NTAKEN] = 0;
979
- } else {
980
- deque[nTaken] = undefined;
981
- deque[DEQUE_NTAKEN] = nTaken + 1;
982
- }
983
- return item;
984
- }
985
-
986
- class DenseBitVector {
987
- constructor() {
988
- this.bits = [];
989
- }
990
-
991
- get(index) {
992
- return this.bits[index] == null ? false : this.bits[index];
993
- }
994
-
995
- set(index, newBitValue) {
996
- this.bits[index] = Boolean(newBitValue);
997
- }
998
-
999
- toString() {
1000
- return `0b${this.bits.map(Number).join("")}`;
1001
- }
1002
- toJSON() {
1003
- return this.bits;
1004
- }
1005
- }
1006
-
1007
- // Implements extension method DenseBitVector::constructor
1008
- export function denseBitVectorConstructor(capacity) {
1009
- return new DenseBitVector();
1010
- }
1011
- // Implements extension method DenseBitVector::get
1012
- export function denseBitVectorGet(denseBitVector, index) {
1013
- return denseBitVector.get(index);
1014
- }
1015
- // Implements extension method DenseBitVector::set
1016
- export function denseBitVectorSet(denseBitVector, index, newBitValue) {
1017
- return denseBitVector.set(index, newBitValue);
1018
- }
1019
-
1020
- // Implements extension method Boolean::toString
1021
- export function booleanToString(b) {
1022
- return b ? "true" : "false";
1023
- }
1024
-
1025
- // Implements Symbol construction.
1026
- export function symbolFor(text) {
1027
- return Symbol.for(text);
1028
- }
1029
-
1030
- // Stubs out static property verification
1031
- export function getStatic(reifiedType, symbol) {
1032
- return undefined; // TODO(bps, #780)
1033
- }
1034
-
1035
- const String = "".constructor;
1036
- const { isArray } = Array;
1037
- const { isSafeInteger } = Number;
1038
- const { trunc } = Math;
1039
- const { freeze } = Object;
1040
-
1041
- export {
1042
- // Export reliable paths to JS builtins, so they can import them
1043
- // via an unambiguous name locally and not worry about masking.
1044
- isArray,
1045
- isSafeInteger,
1046
- };
1047
-
1048
- // Export runtime value type checks used for safe casting
1049
-
1050
- export function requireIsArray(x) {
1051
- if (!isArray(x)) {
1052
- bubble();
1053
- }
1054
- return x;
1055
- }
1056
-
1057
- export function requireInstanceOf(x, typeRequirement) {
1058
- if (!(x instanceof typeRequirement)) {
1059
- bubble();
1060
- }
1061
- return x;
1062
- }
1063
-
1064
- export function requireIsSafeInteger(x) {
1065
- if (!isSafeInteger(x)) {
1066
- bubble();
1067
- }
1068
- return x;
1069
- }
1070
-
1071
- export function requireSame(x, y) {
1072
- if (x !== y) {
1073
- bubble();
1074
- }
1075
- return x;
1076
- }
1077
-
1078
- export function requireTypeOf(x, typeOfString) {
1079
- if (typeof x !== typeOfString) {
1080
- bubble();
1081
- }
1082
- return x;
1083
- }
1084
-
1085
- // When we need a reference to builtin that normally we inline
1086
- export function bitwiseAnd(a, b) {
1087
- return a & b;
1088
- }
1089
- export function bitwiseOr(a, b) {
1090
- return a | b;
1091
- }
1092
- export function booleanNegation(b) {
1093
- return !b;
1094
- }
1095
- export function divDubDub(x, y) {
1096
- return x / y;
1097
- }
1098
- export function divIntInt(x, y) {
1099
- const result = trunc(x / y);
1100
- if (!isSafeInteger(result)) {
1101
- bubble();
1102
- }
1103
- /* not NaN or infinite */
1104
- return result;
1105
- }
1106
- export function modIntInt(x, y) {
1107
- const result = trunc(x % y);
1108
- if (!isSafeInteger(result)) {
1109
- bubble();
1110
- }
1111
- /* not NaN or infinite */
1112
- return result;
1113
- }
1114
- export function minusDub(x) {
1115
- return -x;
1116
- }
1117
- export function minusInt(x) {
1118
- return -x;
1119
- }
1120
- export function minusDubDub(x, y) {
1121
- return x - y;
1122
- }
1123
- export function minusIntInt(x, y) {
1124
- return x - y;
1125
- }
1126
- export function plusDub(x) {
1127
- return +x;
1128
- }
1129
- export function plusInt(x) {
1130
- return +x;
1131
- }
1132
- export function plusDubDub(x, y) {
1133
- return x + y;
1134
- }
1135
- export function plusIntInt(x, y) {
1136
- return x + y;
1137
- }
1138
- export function timesDubDub(x, y) {
1139
- return x * y;
1140
- }
1141
- export function timesIntInt(x, y) {
1142
- return x * y;
1143
- }
1144
- export function strCat(...args) {
1145
- let s = "";
1146
- for (let arg of args) {
1147
- s += String(arg); // Does not throw on Symbols
1148
- }
1149
- return s;
1150
- }
1151
- export function listify(...args) {
1152
- return freeze(args);
1153
- }
1154
- export function cmpGeneric(a, b) {
1155
- if (typeof a === "string" && typeof b === "string") {
1156
- if (Object.is(a, b)) {
1157
- return 0;
1158
- }
1159
- const aLen = a.length;
1160
- const bLen = b.length;
1161
- const minLen = aLen < bLen ? aLen : bLen;
1162
- for (let i = 0; i < minLen; ) {
1163
- const ca = a.codePointAt(i);
1164
- const cb = b.codePointAt(i);
1165
- const d = ca - cb;
1166
- if (d !== 0) {
1167
- return d;
1168
- }
1169
- i += ca < 0x10000 ? 1 : 2;
1170
- }
1171
- return aLen - bLen;
1172
- }
1173
- if (typeof a === "number" && typeof b === "number") {
1174
- if (Object.is(a, b)) {
1175
- return 0;
1176
- }
1177
- if (a === b) {
1178
- return Object.is(a, 0) - Object.is(b, 0);
1179
- }
1180
- if (isNaN(a) || isNaN(b)) {
1181
- return isNaN(a) - isNaN(b);
1182
- }
1183
- return a - b;
1184
- }
1185
- if (typeof a === "boolean" && typeof b === "boolean") {
1186
- return a - b;
1187
- }
1188
- bubble();
1189
- };
1190
- export function ltGeneric(a, b) {
1191
- if (typeof a === "number" && typeof b === "number") {
1192
- return (
1193
- (isNaN(b) && !isNaN(a)) ||
1194
- a < b ||
1195
- (a === 0 && b === 0 && Object.is(a, 0) < Object.is(b, 0))
1196
- );
1197
- }
1198
- if (typeof a == "boolean" && typeof b === "boolean") {
1199
- return a < b;
1200
- }
1201
- return cmpGeneric(a, b) < 0;
1202
- }
1203
- export function leGeneric(a, b) {
1204
- if (typeof a === "number" && typeof b === "number") {
1205
- return (
1206
- isNaN(b) ||
1207
- (a <= b && (a !== 0 || b !== 0 || Object.is(a, 0) <= Object.is(b, 0)))
1208
- );
1209
- }
1210
- if (typeof a == "boolean" && typeof b === "boolean") {
1211
- return a <= b;
1212
- }
1213
- return cmpGeneric(a, b) <= 0;
1214
- }
1215
- export function gtGeneric(a, b) {
1216
- if (typeof a === "number" && typeof b === "number") {
1217
- return (
1218
- (isNaN(a) && !isNaN(b)) ||
1219
- a > b ||
1220
- (a === 0 && b === 0 && Object.is(a, 0) > Object.is(b, 0))
1221
- );
1222
- }
1223
- if (typeof a == "boolean" && typeof b === "boolean") {
1224
- return a > b;
1225
- }
1226
- return cmpGeneric(a, b) > 0;
1227
- }
1228
- export function geGeneric(a, b) {
1229
- if (typeof a === "number" && typeof b === "number") {
1230
- return (
1231
- isNaN(a) ||
1232
- (a >= b && (a !== 0 || b !== 0 || Object.is(a, 0) >= Object.is(b, 0)))
1233
- );
1234
- }
1235
- if (typeof a == "boolean" && typeof b === "boolean") {
1236
- return a >= b;
1237
- }
1238
- return cmpGeneric(a, b) >= 0;
1239
- }
1240
- export function eqGeneric(a, b) {
1241
- return Object.is(a, b);
1242
- }
1243
- export function neGeneric(a, b) {
1244
- return !Object.is(a, b);
1245
- }
1246
- export function bubble() {
1247
- throw Error();
1248
- }
1249
- export function print(a) {
1250
- console.log("%s", a);
1251
- return void 0;
1252
- }
1253
-
1254
- // We might customize this in the future, but actual global console works today.
1255
- export const globalConsole = console;
13
+ export * from "./string.js";