@temperlang/core 0.0.6 → 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.
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 bubbleException = new (class BubbleException extends Error {
5
- constructor() {
6
- super("Bubble");
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 bubbleException;
140
+ bubble();
118
141
  }
119
142
 
120
143
  let content = this.content;
@@ -238,7 +261,7 @@ class Utf16StringSlice {
238
261
  let left = this.left;
239
262
  let right = this.right;
240
263
  if (left >= right) {
241
- throw bubbleException;
264
+ bubble();
242
265
  }
243
266
  return this.content.charCodeAt(left);
244
267
  }
@@ -329,7 +352,7 @@ class CodePointsStringSlice extends TrickyStringSlice {
329
352
 
330
353
  read() {
331
354
  if (this.left >= this.right) {
332
- throw bubbleException;
355
+ bubble();
333
356
  }
334
357
  return this.content.codePointAt(this.left);
335
358
  }
@@ -435,7 +458,7 @@ export function float64ToInt(n) {
435
458
  if (Math.abs(n - i) < 1) {
436
459
  return i;
437
460
  } else {
438
- throw bubbleException;
461
+ bubble();
439
462
  }
440
463
  }
441
464
 
@@ -454,27 +477,18 @@ export function float64ToIntUnsafe(n) {
454
477
  export function float64ToString(n) {
455
478
  // TODO(mikesamuel, issue#579): need functional test to nail down
456
479
  // double formatting threshholds.
457
- switch (n) {
458
- case 0:
459
- if (Object.is(n, -0)) {
460
- return "-0.0";
461
- } else {
462
- return "0.0";
463
- }
464
- case Infinity:
465
- return "∞";
466
- case Number.NEGATIVE_INFINITY:
467
- return "-∞";
468
- default:
469
- let result = n.toString();
470
- // Rely on eagerness and js number formatting rules here.
471
- const groups = /(-?[0-9]+)(\.[0-9]+)?(.+)?/.exec(result);
472
- if (groups === null) {
473
- return result;
474
- } else {
475
- // Guarantee a decimal point for floats.
476
- return `${groups[1]}${groups[2] || ".0"}${groups[3] || ""}`;
477
- }
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
+ }
478
492
  }
479
493
  }
480
494
 
@@ -512,10 +526,6 @@ const byteInfos = [
512
526
  { andMask: 0b0011_1111, orMask: 0b1000_0000, shift: 0 },
513
527
  ];
514
528
 
515
- function freeze(items) {
516
- return Object.freeze(items);
517
- }
518
-
519
529
  // Implements extension method ListBuilder::add
520
530
  export function listBuilderAdd(ls, newItem, at) {
521
531
  if (at === undefined) {
@@ -524,7 +534,7 @@ export function listBuilderAdd(ls, newItem, at) {
524
534
  ls.push(newItem);
525
535
  } else {
526
536
  if (at < 0 || at > ls.length) {
527
- throw bubbleException;
537
+ bubble();
528
538
  }
529
539
  ls.splice(at, 0, newItem);
530
540
  }
@@ -535,7 +545,7 @@ export function listBuilderAddAll(ls, newItems, at) {
535
545
  ls.push(...newItems);
536
546
  } else {
537
547
  if (at < 0 || at > ls.length) {
538
- throw bubbleException;
548
+ bubble();
539
549
  }
540
550
  ls.splice(at, 0, ...newItems);
541
551
  }
@@ -571,7 +581,7 @@ export function listGet(ls, i) {
571
581
  if (0 <= i && i < length) {
572
582
  return ls[i];
573
583
  }
574
- throw bubbleException;
584
+ bubble();
575
585
  }
576
586
  // Implements extension method List::getOr
577
587
  export function listGetOr(ls, i, fallback) {
@@ -627,7 +637,7 @@ export function listBuilderRemoveLast(ls) {
627
637
  if (ls.length) {
628
638
  return ls.pop();
629
639
  } else {
630
- throw bubbleException;
640
+ bubble();
631
641
  }
632
642
  }
633
643
  // Implements extension method ListBuilder::reverse
@@ -690,7 +700,7 @@ class FreezeMap extends Map {
690
700
  }
691
701
  }
692
702
  export function mapConstructor(entries) {
693
- return Object.freeze(new FreezeMap(entries));
703
+ return freeze(new FreezeMap(entries));
694
704
  }
695
705
  // MapBuilder
696
706
  export function mapBuilderConstructor(entries) {
@@ -701,14 +711,23 @@ export function mapBuilderRemove(builder, key) {
701
711
  if (builder.delete(key)) {
702
712
  return result;
703
713
  } else {
704
- throw bubbleException;
714
+ bubble();
705
715
  }
706
716
  }
707
717
  export function mapBuilderSet(builder, key, value) {
708
718
  builder.set(key, value);
709
719
  }
710
- export function mapBuilderToMap(builder) {
711
- 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);
712
731
  }
713
732
  // Pair
714
733
  class Pair {
@@ -727,20 +746,47 @@ class Pair {
727
746
  }
728
747
  }
729
748
  export function pairConstructor(key, value) {
730
- return Object.freeze(new Pair(key, value));
749
+ return freeze(new Pair(key, value));
731
750
  }
732
751
  // Mapped
752
+ export function mappedLength(map) {
753
+ return map.size;
754
+ }
733
755
  export function mappedGet(map, key) {
734
756
  const result = map.get(key);
735
757
  // TODO Under compiler-error-free Temper, could undefined values get set?
736
- // 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?
737
759
  if (result === undefined) {
738
- throw bubbleException;
760
+ bubble();
739
761
  }
740
762
  return result;
741
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
+ }
742
776
  export function mappedToList(map) {
743
- 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));
744
790
  }
745
791
 
746
792
  // Implements Date::constructor
@@ -807,7 +853,7 @@ export function dequeRemoveFirst(deque) {
807
853
  if (length === nTaken) {
808
854
  deque[DEQUE_NTAKEN] = 0;
809
855
  deque.length = 0;
810
- throw bubbleException;
856
+ bubble();
811
857
  }
812
858
  let item = deque[nTaken];
813
859
  let nShiftThreshhold = (length / 2) | 0;
@@ -877,6 +923,7 @@ const String = "".constructor;
877
923
  const { isArray } = Array;
878
924
  const { isSafeInteger } = Number;
879
925
  const { trunc } = Math;
926
+ const { freeze } = Object;
880
927
 
881
928
  export {
882
929
  // Export reliable paths to JS builtins, so they can import them
@@ -889,35 +936,35 @@ export {
889
936
 
890
937
  export function requireIsArray(x) {
891
938
  if (!isArray(x)) {
892
- throw bubbleException;
939
+ bubble();
893
940
  }
894
941
  return x;
895
942
  }
896
943
 
897
944
  export function requireInstanceOf(x, typeRequirement) {
898
945
  if (!(x instanceof typeRequirement)) {
899
- throw bubbleException;
946
+ bubble();
900
947
  }
901
948
  return x;
902
949
  }
903
950
 
904
951
  export function requireIsSafeInteger(x) {
905
952
  if (!isSafeInteger(x)) {
906
- throw bubbleException;
953
+ bubble();
907
954
  }
908
955
  return x;
909
956
  }
910
957
 
911
958
  export function requireSame(x, y) {
912
959
  if (x !== y) {
913
- throw bubbleException;
960
+ bubble();
914
961
  }
915
962
  return x;
916
963
  }
917
964
 
918
965
  export function requireTypeOf(x, typeOfString) {
919
966
  if (typeof x !== typeOfString) {
920
- throw bubbleException;
967
+ bubble();
921
968
  }
922
969
  return x;
923
970
  }
@@ -938,7 +985,7 @@ export function divDubDub(x, y) {
938
985
  export function divIntInt(x, y) {
939
986
  const result = trunc(x / y);
940
987
  if (!isSafeInteger(result)) {
941
- throw bubbleException;
988
+ bubble();
942
989
  }
943
990
  /* not NaN or infinite */
944
991
  return result;
@@ -946,7 +993,7 @@ export function divIntInt(x, y) {
946
993
  export function modIntInt(x, y) {
947
994
  const result = trunc(x % y);
948
995
  if (!isSafeInteger(result)) {
949
- throw bubbleException;
996
+ bubble();
950
997
  }
951
998
  /* not NaN or infinite */
952
999
  return result;
@@ -1017,16 +1064,23 @@ export function cmpGeneric(a, b) {
1017
1064
  if (a === b) {
1018
1065
  return Object.is(a, 0) - Object.is(b, 0);
1019
1066
  }
1067
+ if (isNaN(a) || isNaN(b)) {
1068
+ return isNaN(a) - isNaN(b);
1069
+ }
1020
1070
  return a - b;
1021
1071
  }
1022
1072
  if (typeof a === "boolean" && typeof b === "boolean") {
1023
1073
  return a - b;
1024
1074
  }
1025
- throw bubbleException;
1075
+ bubble();
1026
1076
  };
1027
1077
  export function ltGeneric(a, b) {
1028
1078
  if (typeof a === "number" && typeof b === "number") {
1029
- 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
+ );
1030
1084
  }
1031
1085
  if (typeof a == "boolean" && typeof b === "boolean") {
1032
1086
  return a < b;
@@ -1035,7 +1089,10 @@ export function ltGeneric(a, b) {
1035
1089
  }
1036
1090
  export function leGeneric(a, b) {
1037
1091
  if (typeof a === "number" && typeof b === "number") {
1038
- 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
+ );
1039
1096
  }
1040
1097
  if (typeof a == "boolean" && typeof b === "boolean") {
1041
1098
  return a <= b;
@@ -1044,7 +1101,11 @@ export function leGeneric(a, b) {
1044
1101
  }
1045
1102
  export function gtGeneric(a, b) {
1046
1103
  if (typeof a === "number" && typeof b === "number") {
1047
- 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
+ );
1048
1109
  }
1049
1110
  if (typeof a == "boolean" && typeof b === "boolean") {
1050
1111
  return a > b;
@@ -1053,7 +1114,10 @@ export function gtGeneric(a, b) {
1053
1114
  }
1054
1115
  export function geGeneric(a, b) {
1055
1116
  if (typeof a === "number" && typeof b === "number") {
1056
- 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
+ );
1057
1121
  }
1058
1122
  if (typeof a == "boolean" && typeof b === "boolean") {
1059
1123
  return a >= b;
@@ -1067,7 +1131,7 @@ export function neGeneric(a, b) {
1067
1131
  return !Object.is(a, b);
1068
1132
  }
1069
1133
  export function bubble() {
1070
- throw bubbleException;
1134
+ throw Error();
1071
1135
  }
1072
1136
  export function print(a) {
1073
1137
  console.log("%s", a);
File without changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@temperlang/core",
3
- "version": "0.0.6",
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,11 +1,14 @@
1
- import {bubbleException} 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
  /**
@@ -15,7 +18,7 @@ export function compiledRegexCompiledFind(_, compiled, text, regexRefs) {
15
18
  function compiledRegexCompiledFindEx(_, compiled, text, regexRefs) {
16
19
  const match = compiled.exec(text);
17
20
  if (match === null) {
18
- throw bubbleException;
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.
@@ -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 === bubbleException) {
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;