@temperlang/core 0.0.5 → 0.1.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.
Files changed (3) hide show
  1. package/index.js +300 -121
  2. package/package.json +1 -1
  3. package/regex.js +16 -20
package/index.js CHANGED
@@ -1,21 +1,44 @@
1
1
  export * from "./interface-types.js";
2
2
  export * from "./regex.js";
3
3
 
4
- export const noResultException = new (class NoResultException extends Error {
5
- constructor() {
6
- super("NoResult");
7
- }
8
- })();
9
-
10
4
  // Implements extension method String::isEmpty
11
5
  export function stringIsEmpty(s) {
12
6
  return s === "";
13
7
  }
8
+
14
9
  // Implements extension method String::split
15
10
  export function stringSplit(s, separator) {
16
11
  return s.split(separator).map((s) => s);
17
12
  }
18
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
+
19
42
  /** Specifically for utf8 and utf32, since utf16 is simpler in js. */
20
43
  class TrickyStringSlice {
21
44
  hasAtLeast(count) {
@@ -114,7 +137,7 @@ class Utf8StringSlice extends TrickyStringSlice {
114
137
  let left = this.left;
115
138
  let right = this.right;
116
139
  if (left >= right) {
117
- throw noResultException;
140
+ bubble();
118
141
  }
119
142
 
120
143
  let content = this.content;
@@ -131,32 +154,53 @@ class Utf8StringSlice extends TrickyStringSlice {
131
154
  }
132
155
  }
133
156
 
134
- advance(count) {
135
- if (count <= 0) {
136
- return this;
137
- } else if (count === 1) {
138
- let left = this.left;
139
- let right = this.right;
140
- if (left >= right) {
141
- return this;
142
- }
143
- let content = this.content;
144
- let cp = content.codePointAt(left >> 2);
145
- let newLeft;
146
- if (cp < 0x80) {
147
- newLeft = left + 4;
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;
148
174
  } else {
149
- let byteOffset = left & 3;
150
- let nBytes = nUtf8BytesInChar(cp);
151
- newLeft =
152
- byteOffset + 1 < nBytes
153
- ? left + 1
154
- : (left & ~3) + ((nBytes + 4) & ~3);
175
+ count -= rem;
176
+ sub = 0;
177
+ idx += cp > 0x10000 ? 2 : 1;
155
178
  }
156
- return new Utf8StringSlice(content, newLeft, right);
157
- } else {
158
- throw new Error("TODO");
159
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);
160
204
  }
161
205
 
162
206
  [Symbol.iterator]() {
@@ -217,26 +261,39 @@ class Utf16StringSlice {
217
261
  let left = this.left;
218
262
  let right = this.right;
219
263
  if (left >= right) {
220
- throw noResultException;
264
+ bubble();
221
265
  }
222
266
  return this.content.charCodeAt(left);
223
267
  }
224
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
+ */
225
281
  advance(count) {
226
- if (count <= 0) {
227
- return this;
228
- } else {
229
- let left = this.left;
230
- let right = this.right;
231
- if (left >= right) {
232
- return this;
233
- }
234
- let newLeft = left + count;
235
- if (newLeft >= right) {
236
- newLeft = right;
237
- }
238
- return new Utf16StringSlice(this.content, newLeft, right);
239
- }
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);
240
297
  }
241
298
 
242
299
  [Symbol.iterator]() {
@@ -295,35 +352,55 @@ class CodePointsStringSlice extends TrickyStringSlice {
295
352
 
296
353
  read() {
297
354
  if (this.left >= this.right) {
298
- throw noResultException;
355
+ bubble();
299
356
  }
300
357
  return this.content.codePointAt(this.left);
301
358
  }
302
359
 
303
- advance(count) {
304
- if (count <= 0) {
305
- return this;
306
- } else {
307
- let left = this.left;
308
- let right = this.right;
309
- let content = this.content;
310
- if (left >= right) {
311
- return this;
312
- }
313
- let newLeft = left;
314
- for (let i = count; i && newLeft < right; --i) {
315
- let cp = content.codePointAt(newLeft);
316
- if (cp > 0xffff) {
317
- newLeft += 2;
318
- } else {
319
- newLeft += 1;
320
- }
321
- }
322
- if (newLeft >= right) {
323
- newLeft = right;
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;
324
376
  }
325
- return new CodePointsStringSlice(this.content, newLeft, right);
326
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);
327
404
  }
328
405
 
329
406
  [Symbol.iterator]() {
@@ -363,13 +440,25 @@ export function intToString(i, radix) {
363
440
  return i.toString(radix);
364
441
  }
365
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
+
366
455
  // Implements extension method Float64::toInt
367
456
  export function float64ToInt(n) {
368
457
  const i = float64ToIntUnsafe(n);
369
458
  if (Math.abs(n - i) < 1) {
370
459
  return i;
371
460
  } else {
372
- throw noResultException;
461
+ bubble();
373
462
  }
374
463
  }
375
464
 
@@ -388,27 +477,18 @@ export function float64ToIntUnsafe(n) {
388
477
  export function float64ToString(n) {
389
478
  // TODO(mikesamuel, issue#579): need functional test to nail down
390
479
  // double formatting threshholds.
391
- switch (n) {
392
- case 0:
393
- if (Object.is(n, -0)) {
394
- return "-0.0";
395
- } else {
396
- return "0.0";
397
- }
398
- case Infinity:
399
- return "∞";
400
- case Number.NEGATIVE_INFINITY:
401
- return "-∞";
402
- default:
403
- let result = n.toString();
404
- // Rely on eagerness and js number formatting rules here.
405
- const groups = /(-?[0-9]+)(\.[0-9]+)?(.+)?/.exec(result);
406
- if (groups === null) {
407
- return result;
408
- } else {
409
- // Guarantee a decimal point for floats.
410
- return `${groups[1]}${groups[2] || ".0"}${groups[3] || ""}`;
411
- }
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
+ }
412
492
  }
413
493
  }
414
494
 
@@ -446,10 +526,6 @@ const byteInfos = [
446
526
  { andMask: 0b0011_1111, orMask: 0b1000_0000, shift: 0 },
447
527
  ];
448
528
 
449
- function freeze(items) {
450
- return Object.freeze(items);
451
- }
452
-
453
529
  // Implements extension method ListBuilder::add
454
530
  export function listBuilderAdd(ls, newItem, at) {
455
531
  if (at === undefined) {
@@ -458,7 +534,7 @@ export function listBuilderAdd(ls, newItem, at) {
458
534
  ls.push(newItem);
459
535
  } else {
460
536
  if (at < 0 || at > ls.length) {
461
- throw noResultException;
537
+ bubble();
462
538
  }
463
539
  ls.splice(at, 0, newItem);
464
540
  }
@@ -469,7 +545,7 @@ export function listBuilderAddAll(ls, newItems, at) {
469
545
  ls.push(...newItems);
470
546
  } else {
471
547
  if (at < 0 || at > ls.length) {
472
- throw noResultException;
548
+ bubble();
473
549
  }
474
550
  ls.splice(at, 0, ...newItems);
475
551
  }
@@ -505,7 +581,7 @@ export function listGet(ls, i) {
505
581
  if (0 <= i && i < length) {
506
582
  return ls[i];
507
583
  }
508
- throw noResultException;
584
+ bubble();
509
585
  }
510
586
  // Implements extension method List::getOr
511
587
  export function listGetOr(ls, i, fallback) {
@@ -548,12 +624,20 @@ export function listMap(ls, transform) {
548
624
  }
549
625
  return freeze(mapped);
550
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
+ }
551
635
  // Implements extension method ListBuilder::removeLast
552
636
  export function listBuilderRemoveLast(ls) {
553
637
  if (ls.length) {
554
638
  return ls.pop();
555
639
  } else {
556
- throw noResultException;
640
+ bubble();
557
641
  }
558
642
  }
559
643
  // Implements extension method ListBuilder::reverse
@@ -616,7 +700,7 @@ class FreezeMap extends Map {
616
700
  }
617
701
  }
618
702
  export function mapConstructor(entries) {
619
- return Object.freeze(new FreezeMap(entries));
703
+ return freeze(new FreezeMap(entries));
620
704
  }
621
705
  // MapBuilder
622
706
  export function mapBuilderConstructor(entries) {
@@ -627,14 +711,23 @@ export function mapBuilderRemove(builder, key) {
627
711
  if (builder.delete(key)) {
628
712
  return result;
629
713
  } else {
630
- throw noResultException;
714
+ bubble();
631
715
  }
632
716
  }
633
717
  export function mapBuilderSet(builder, key, value) {
634
718
  builder.set(key, value);
635
719
  }
636
- export function mapBuilderToMap(builder) {
637
- return Object.freeze(new FreezeMap(builder));
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);
638
731
  }
639
732
  // Pair
640
733
  class Pair {
@@ -653,20 +746,88 @@ class Pair {
653
746
  }
654
747
  }
655
748
  export function pairConstructor(key, value) {
656
- return Object.freeze(new Pair(key, value));
749
+ return freeze(new Pair(key, value));
657
750
  }
658
751
  // Mapped
752
+ export function mappedLength(map) {
753
+ return map.size;
754
+ }
659
755
  export function mappedGet(map, key) {
660
756
  const result = map.get(key);
661
757
  // TODO Under compiler-error-free Temper, could undefined values get set?
662
- // TODO Would Map<?, Void> be impossible to feed once we get checks in place?
758
+ // TODO Would Map<?, Void> be impossible to feed once we get checks in place?
663
759
  if (result === undefined) {
664
- throw noResultException;
760
+ bubble();
665
761
  }
666
762
  return result;
667
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
+ }
668
776
  export function mappedToList(map) {
669
- return Array.from(map, ([key, value]) => new Pair(key, value));
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());
670
831
  }
671
832
 
672
833
  // Implements extension method Deque::constructor
@@ -692,7 +853,7 @@ export function dequeRemoveFirst(deque) {
692
853
  if (length === nTaken) {
693
854
  deque[DEQUE_NTAKEN] = 0;
694
855
  deque.length = 0;
695
- throw noResultException;
856
+ bubble();
696
857
  }
697
858
  let item = deque[nTaken];
698
859
  let nShiftThreshhold = (length / 2) | 0;
@@ -762,6 +923,7 @@ const String = "".constructor;
762
923
  const { isArray } = Array;
763
924
  const { isSafeInteger } = Number;
764
925
  const { trunc } = Math;
926
+ const { freeze } = Object;
765
927
 
766
928
  export {
767
929
  // Export reliable paths to JS builtins, so they can import them
@@ -774,35 +936,35 @@ export {
774
936
 
775
937
  export function requireIsArray(x) {
776
938
  if (!isArray(x)) {
777
- throw noResultException;
939
+ bubble();
778
940
  }
779
941
  return x;
780
942
  }
781
943
 
782
944
  export function requireInstanceOf(x, typeRequirement) {
783
945
  if (!(x instanceof typeRequirement)) {
784
- throw noResultException;
946
+ bubble();
785
947
  }
786
948
  return x;
787
949
  }
788
950
 
789
951
  export function requireIsSafeInteger(x) {
790
952
  if (!isSafeInteger(x)) {
791
- throw noResultException;
953
+ bubble();
792
954
  }
793
955
  return x;
794
956
  }
795
957
 
796
958
  export function requireSame(x, y) {
797
959
  if (x !== y) {
798
- throw noResultException;
960
+ bubble();
799
961
  }
800
962
  return x;
801
963
  }
802
964
 
803
965
  export function requireTypeOf(x, typeOfString) {
804
966
  if (typeof x !== typeOfString) {
805
- throw noResultException;
967
+ bubble();
806
968
  }
807
969
  return x;
808
970
  }
@@ -823,7 +985,7 @@ export function divDubDub(x, y) {
823
985
  export function divIntInt(x, y) {
824
986
  const result = trunc(x / y);
825
987
  if (!isSafeInteger(result)) {
826
- throw noResultException;
988
+ bubble();
827
989
  }
828
990
  /* not NaN or infinite */
829
991
  return result;
@@ -831,7 +993,7 @@ export function divIntInt(x, y) {
831
993
  export function modIntInt(x, y) {
832
994
  const result = trunc(x % y);
833
995
  if (!isSafeInteger(result)) {
834
- throw noResultException;
996
+ bubble();
835
997
  }
836
998
  /* not NaN or infinite */
837
999
  return result;
@@ -902,16 +1064,23 @@ export function cmpGeneric(a, b) {
902
1064
  if (a === b) {
903
1065
  return Object.is(a, 0) - Object.is(b, 0);
904
1066
  }
1067
+ if (isNaN(a) || isNaN(b)) {
1068
+ return isNaN(a) - isNaN(b);
1069
+ }
905
1070
  return a - b;
906
1071
  }
907
1072
  if (typeof a === "boolean" && typeof b === "boolean") {
908
1073
  return a - b;
909
1074
  }
910
- throw noResultException;
1075
+ bubble();
911
1076
  };
912
1077
  export function ltGeneric(a, b) {
913
1078
  if (typeof a === "number" && typeof b === "number") {
914
- return a < b || (a === 0 && b === 0 && Object.is(a, 0) < Object.is(b, 0));
1079
+ return (
1080
+ (isNaN(b) && !isNaN(a)) ||
1081
+ a < b ||
1082
+ (a === 0 && b === 0 && Object.is(a, 0) < Object.is(b, 0))
1083
+ );
915
1084
  }
916
1085
  if (typeof a == "boolean" && typeof b === "boolean") {
917
1086
  return a < b;
@@ -920,7 +1089,10 @@ export function ltGeneric(a, b) {
920
1089
  }
921
1090
  export function leGeneric(a, b) {
922
1091
  if (typeof a === "number" && typeof b === "number") {
923
- return a <= b && (a !== 0 || b !== 0 || Object.is(a, 0) <= Object.is(b, 0));
1092
+ return (
1093
+ isNaN(b) ||
1094
+ (a <= b && (a !== 0 || b !== 0 || Object.is(a, 0) <= Object.is(b, 0)))
1095
+ );
924
1096
  }
925
1097
  if (typeof a == "boolean" && typeof b === "boolean") {
926
1098
  return a <= b;
@@ -929,7 +1101,11 @@ export function leGeneric(a, b) {
929
1101
  }
930
1102
  export function gtGeneric(a, b) {
931
1103
  if (typeof a === "number" && typeof b === "number") {
932
- return a > b || (a === 0 && b === 0 && Object.is(a, 0) > Object.is(b, 0));
1104
+ return (
1105
+ (isNaN(a) && !isNaN(b)) ||
1106
+ a > b ||
1107
+ (a === 0 && b === 0 && Object.is(a, 0) > Object.is(b, 0))
1108
+ );
933
1109
  }
934
1110
  if (typeof a == "boolean" && typeof b === "boolean") {
935
1111
  return a > b;
@@ -938,7 +1114,10 @@ export function gtGeneric(a, b) {
938
1114
  }
939
1115
  export function geGeneric(a, b) {
940
1116
  if (typeof a === "number" && typeof b === "number") {
941
- return a >= b && (a !== 0 || b !== 0 || Object.is(a, 0) >= Object.is(b, 0));
1117
+ return (
1118
+ isNaN(a) ||
1119
+ (a >= b && (a !== 0 || b !== 0 || Object.is(a, 0) >= Object.is(b, 0)))
1120
+ );
942
1121
  }
943
1122
  if (typeof a == "boolean" && typeof b === "boolean") {
944
1123
  return a >= b;
@@ -951,8 +1130,8 @@ export function eqGeneric(a, b) {
951
1130
  export function neGeneric(a, b) {
952
1131
  return !Object.is(a, b);
953
1132
  }
954
- export function fail() {
955
- throw noResultException;
1133
+ export function bubble() {
1134
+ throw Error();
956
1135
  }
957
1136
  export function print(a) {
958
1137
  console.log("%s", a);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@temperlang/core",
3
- "version": "0.0.5",
3
+ "version": "0.1.0",
4
4
  "description": "Runtime support for JS generated by Temper",
5
5
  "main": "index.js",
6
6
  "type": "module",
package/regex.js CHANGED
@@ -1,21 +1,24 @@
1
- import {noResultException} from "./index.js";
2
-
3
1
  export function compiledRegexCompiledFound(_, compiled, text) {
4
2
  return compiled.test(text);
5
3
  }
6
4
 
7
5
  export function compiledRegexCompiledFind(_, compiled, text, regexRefs) {
8
- return compiledRegexCompiledFindEx(_, compiled, text, regexRefs).groups;
6
+ const match = compiledRegexCompiledFindEx(_, compiled, text, regexRefs);
7
+ if (match === undefined) {
8
+ // We could just fail on `undefined.groups`, but that seems accidental.
9
+ throw Error();
10
+ }
11
+ return match.groups;
9
12
  }
10
13
 
11
14
  /**
12
- * @param {RegExp} compiled
13
- * @param {string} text
15
+ * @param {RegExp} compiled
16
+ * @param {string} text
14
17
  */
15
18
  function compiledRegexCompiledFindEx(_, compiled, text, regexRefs) {
16
19
  const match = compiled.exec(text);
17
20
  if (match === null) {
18
- throw noResultException;
21
+ return undefined;
19
22
  }
20
23
  const { groups, indices: { groups: indexGroups } } = match;
21
24
  // Find the begin indices in code points for all matched groups.
@@ -64,9 +67,9 @@ function codePointIndices(text, unitNameIndexArray) {
64
67
  }
65
68
 
66
69
  /**
67
- * @param {RegExp} compiled
68
- * @param {string} text
69
- * @param {(groups: Map<string, any>) => string} format
70
+ * @param {RegExp} compiled
71
+ * @param {string} text
72
+ * @param {(groups: Map<string, any>) => string} format
70
73
  * @returns {string}
71
74
  */
72
75
  export function compiledRegexCompiledReplace(
@@ -80,17 +83,10 @@ export function compiledRegexCompiledReplace(
80
83
  // make our interface consistent, so we have to do this manually here.
81
84
  // The hope is that we can optimize a bunch out when we have compile-time
82
85
  // contant patterns and customized match result types.
83
- let match;
84
- try {
85
- match = compiledRegexCompiledFindEx(_, compiled, text, regexRefs);
86
- } catch (e) {
87
- if (e === noResultException) {
88
- // Manually handle no match case for our manual replace logic.
89
- return text;
90
- } else {
91
- // This shouldn't happen if we don't have bugs, but forward it in case.
92
- throw e;
93
- }
86
+ let match = compiledRegexCompiledFindEx(_, compiled, text, regexRefs);
87
+ if (match === undefined) {
88
+ // Manually handle no match case for our manual replace logic.
89
+ return text;
94
90
  }
95
91
  // Index and length in js space should save some processing.
96
92
  const { groups, index, length } = match;