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