@temperlang/core 0.4.0 → 0.6.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/check-type.js +0 -11
- package/core.js +214 -2
- package/float.js +38 -8
- package/index.js +1 -0
- package/interface.js +1 -1
- package/mapped.js +2 -2
- package/net.js +41 -0
- package/package.json +2 -2
- package/regex.js +8 -2
- package/string.js +66 -5
- package/tsconfig.json +26 -0
package/check-type.js
CHANGED
|
@@ -27,17 +27,6 @@ export const requireInstanceOf = (x, typeRequirement) => {
|
|
|
27
27
|
export const requireNotNull = (x) =>
|
|
28
28
|
x == null ? bubble() : x
|
|
29
29
|
|
|
30
|
-
/**
|
|
31
|
-
* @param {number} x
|
|
32
|
-
* @returns {number}
|
|
33
|
-
*/
|
|
34
|
-
export const requireIsSafeInteger = (x) => {
|
|
35
|
-
if (!Number.isSafeInteger(x)) {
|
|
36
|
-
bubble();
|
|
37
|
-
}
|
|
38
|
-
return x;
|
|
39
|
-
};
|
|
40
|
-
|
|
41
30
|
/**
|
|
42
31
|
* @template X, Y
|
|
43
32
|
* @param {X} x
|
package/core.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// @ts-check
|
|
1
2
|
|
|
2
3
|
/**
|
|
3
4
|
* @param {number} x
|
|
@@ -10,7 +11,7 @@ export const divIntInt = (x, y) => {
|
|
|
10
11
|
bubble();
|
|
11
12
|
}
|
|
12
13
|
/* not NaN or infinite */
|
|
13
|
-
return result;
|
|
14
|
+
return result | 0;
|
|
14
15
|
};
|
|
15
16
|
|
|
16
17
|
/**
|
|
@@ -25,9 +26,137 @@ export const modIntInt = (x, y) => {
|
|
|
25
26
|
bubble();
|
|
26
27
|
}
|
|
27
28
|
/* not NaN or infinite */
|
|
28
|
-
return result;
|
|
29
|
+
return result | 0;
|
|
29
30
|
};
|
|
30
31
|
|
|
32
|
+
/**
|
|
33
|
+
* @param {string} s
|
|
34
|
+
* @param {(number | bigint)?} radix
|
|
35
|
+
* @returns {bigint}
|
|
36
|
+
*/
|
|
37
|
+
export const parseBigInt = (s, radix) => {
|
|
38
|
+
const rdx = BigInt(radix ?? 10);
|
|
39
|
+
let result = 0n;
|
|
40
|
+
// TODO Definitions of whitespace? Better to check /\s/ on the fly?
|
|
41
|
+
s = s.trim();
|
|
42
|
+
let i = 0;
|
|
43
|
+
let sign = 1n;
|
|
44
|
+
if (s.startsWith("-")) {
|
|
45
|
+
i++;
|
|
46
|
+
sign = -1n;
|
|
47
|
+
}
|
|
48
|
+
for (; i < s.length; i++) {
|
|
49
|
+
const c = s.charCodeAt(i);
|
|
50
|
+
/** @type {bigint} */
|
|
51
|
+
let digit;
|
|
52
|
+
if (c >= c0 && c <= c9) {
|
|
53
|
+
digit = BigInt(c - c0);
|
|
54
|
+
} else if (c >= cA && c <= cZ) {
|
|
55
|
+
digit = BigInt(c - cA + 10);
|
|
56
|
+
} else if (c >= ca && c <= cz) {
|
|
57
|
+
digit = BigInt(c - ca + 10);
|
|
58
|
+
} else {
|
|
59
|
+
bubble();
|
|
60
|
+
}
|
|
61
|
+
if (digit >= rdx) {
|
|
62
|
+
bubble();
|
|
63
|
+
}
|
|
64
|
+
result = result * rdx + digit;
|
|
65
|
+
}
|
|
66
|
+
return sign * result;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
const c0 = "0".charCodeAt(0);
|
|
70
|
+
const c9 = "9".charCodeAt(0);
|
|
71
|
+
const cA = "A".charCodeAt(0);
|
|
72
|
+
const cZ = "Z".charCodeAt(0);
|
|
73
|
+
const ca = "a".charCodeAt(0);
|
|
74
|
+
const cz = "z".charCodeAt(0);
|
|
75
|
+
|
|
76
|
+
export const INT32_MAX = (2 ** 31) - 1;
|
|
77
|
+
export const INT32_MIN = -(2 ** 31);
|
|
78
|
+
export const INT64_MAX = (2n ** 63n) - 1n;
|
|
79
|
+
export const INT64_MIN = -(2n ** 63n);
|
|
80
|
+
|
|
81
|
+
// Related to int64 limits above.
|
|
82
|
+
const edge64 = 1n << 64n;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* @param {bigint} x
|
|
86
|
+
* @returns {bigint}
|
|
87
|
+
*/
|
|
88
|
+
export const clampInt64 = (x) => {
|
|
89
|
+
x = x % edge64;
|
|
90
|
+
if (x > INT64_MAX) {
|
|
91
|
+
x -= edge64;
|
|
92
|
+
} else if (x < INT64_MIN) {
|
|
93
|
+
x += edge64;
|
|
94
|
+
}
|
|
95
|
+
return x;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Implements extension method Int64::max
|
|
100
|
+
* @param {bigint} a
|
|
101
|
+
* @param {bigint} b
|
|
102
|
+
* @returns {bigint}
|
|
103
|
+
*/
|
|
104
|
+
export const int64Max = (a, b) => {
|
|
105
|
+
return a > b ? a : b;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Implements extension method Int64::min
|
|
110
|
+
* @param {bigint} a
|
|
111
|
+
* @param {bigint} b
|
|
112
|
+
* @returns {bigint}
|
|
113
|
+
*/
|
|
114
|
+
export const int64Min = (a, b) => {
|
|
115
|
+
return a < b ? a : b;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Implements extension method Int64::toInt32
|
|
120
|
+
* @param {bigint} n
|
|
121
|
+
* @returns {number}
|
|
122
|
+
*/
|
|
123
|
+
export const int64ToInt32 = (n) => {
|
|
124
|
+
if (n < INT32_MIN || n > INT32_MAX) {
|
|
125
|
+
bubble();
|
|
126
|
+
}
|
|
127
|
+
return int64ToInt32Unsafe(n);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Implements extension method Int64::toInt32Unsafe
|
|
132
|
+
* @param {bigint} n
|
|
133
|
+
* @returns {number}
|
|
134
|
+
*/
|
|
135
|
+
export const int64ToInt32Unsafe = (n) => {
|
|
136
|
+
return Number(n) | 0;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* Implements extension method Int64::toFloat64
|
|
141
|
+
* @param {bigint} n
|
|
142
|
+
* @returns {number}
|
|
143
|
+
*/
|
|
144
|
+
export const int64ToFloat64 = (n) => {
|
|
145
|
+
if (n < Number.MIN_SAFE_INTEGER || n > Number.MAX_SAFE_INTEGER) {
|
|
146
|
+
bubble();
|
|
147
|
+
}
|
|
148
|
+
return Number(n);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Implements extension method Int64::toFloat63Unsafe
|
|
153
|
+
* @param {bigint} n
|
|
154
|
+
* @returns {number}
|
|
155
|
+
*/
|
|
156
|
+
export const int64ToFloat64Unsafe = (n) => {
|
|
157
|
+
return Number(n);
|
|
158
|
+
}
|
|
159
|
+
|
|
31
160
|
/**
|
|
32
161
|
* Compare two Strings.
|
|
33
162
|
* @param {string} a
|
|
@@ -64,9 +193,11 @@ export const cmpFloat = (a, b) => {
|
|
|
64
193
|
return 0;
|
|
65
194
|
}
|
|
66
195
|
if (a === b) {
|
|
196
|
+
// @ts-ignore
|
|
67
197
|
return Object.is(a, 0) - Object.is(b, 0);
|
|
68
198
|
}
|
|
69
199
|
if (isNaN(a) || isNaN(b)) {
|
|
200
|
+
// @ts-ignore
|
|
70
201
|
return isNaN(a) - isNaN(b);
|
|
71
202
|
}
|
|
72
203
|
return a - b;
|
|
@@ -86,6 +217,7 @@ export const cmpGeneric = (a, b) => {
|
|
|
86
217
|
return cmpFloat(a, b);
|
|
87
218
|
}
|
|
88
219
|
if (typeof a === "boolean" && typeof b === "boolean") {
|
|
220
|
+
// @ts-ignore
|
|
89
221
|
return a - b;
|
|
90
222
|
}
|
|
91
223
|
bubble();
|
|
@@ -98,6 +230,13 @@ export const bubble = () => {
|
|
|
98
230
|
throw Error();
|
|
99
231
|
};
|
|
100
232
|
|
|
233
|
+
/**
|
|
234
|
+
* TODO Distinguish panic from bubble.
|
|
235
|
+
*
|
|
236
|
+
* @returns {never}
|
|
237
|
+
*/
|
|
238
|
+
export const panic = bubble;
|
|
239
|
+
|
|
101
240
|
/**
|
|
102
241
|
* @template T
|
|
103
242
|
* @param {T} a
|
|
@@ -105,3 +244,76 @@ export const bubble = () => {
|
|
|
105
244
|
export const print = (a) => {
|
|
106
245
|
console.log("%s", a);
|
|
107
246
|
};
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Takes a JSON adapter and a value that it can adapt.
|
|
250
|
+
* This is called when JavaScript code calls JSON.stringify on a Temper type instance
|
|
251
|
+
* that has a zero argument jsonAdapter static method.
|
|
252
|
+
*
|
|
253
|
+
* @return any
|
|
254
|
+
*/
|
|
255
|
+
export let marshalToJsonObject = (jsonAdapter, value) => {
|
|
256
|
+
/** @type {any[]} */
|
|
257
|
+
const stack = [[]];
|
|
258
|
+
let pendingKey = null;
|
|
259
|
+
function store(value) {
|
|
260
|
+
let top = stack[stack.length - 1];
|
|
261
|
+
if (pendingKey !== null) {
|
|
262
|
+
top[pendingKey] = value;
|
|
263
|
+
pendingKey = null;
|
|
264
|
+
} else if (Array.isArray(top)) {
|
|
265
|
+
top.push(value);
|
|
266
|
+
} else {
|
|
267
|
+
throw new Error();
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
let jsonProducer = {
|
|
271
|
+
interchangeContext: { getHeader() { return null; } },
|
|
272
|
+
|
|
273
|
+
startObject() {
|
|
274
|
+
let o = {};
|
|
275
|
+
store(o);
|
|
276
|
+
stack.push(o);
|
|
277
|
+
},
|
|
278
|
+
endObject() { stack.pop(); },
|
|
279
|
+
objectKey(key) { pendingKey = String(key); },
|
|
280
|
+
|
|
281
|
+
startArray() {
|
|
282
|
+
let a = [];
|
|
283
|
+
store(a);
|
|
284
|
+
stack.push(a);
|
|
285
|
+
},
|
|
286
|
+
endArray() { stack.pop(); },
|
|
287
|
+
|
|
288
|
+
nullValue() { store(null); },
|
|
289
|
+
booleanValue(b) { store(!!b); },
|
|
290
|
+
int32Value(v) { store(Math.trunc(v)); },
|
|
291
|
+
float64Value(v) { store(+v); },
|
|
292
|
+
numericTokenValue(s) { store(+s); },
|
|
293
|
+
stringValue(s) { store(`${s}`); },
|
|
294
|
+
|
|
295
|
+
parseErrorReceiver: null,
|
|
296
|
+
}
|
|
297
|
+
jsonAdapter.encodeToJson(value, jsonProducer);
|
|
298
|
+
return stack[0][0];
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
/** @type {{}} */
|
|
302
|
+
let emptySingleton = Object.freeze(
|
|
303
|
+
// Prototype for empty
|
|
304
|
+
Object.create(
|
|
305
|
+
Object.freeze(
|
|
306
|
+
Object.create(
|
|
307
|
+
null,
|
|
308
|
+
{
|
|
309
|
+
toString: {
|
|
310
|
+
value: function toString() { return "(empty)" }
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
)
|
|
314
|
+
)
|
|
315
|
+
)
|
|
316
|
+
);
|
|
317
|
+
|
|
318
|
+
/** @return {{}} */
|
|
319
|
+
export function empty() { return emptySingleton }
|
package/float.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
// @ts-check
|
|
1
2
|
|
|
2
3
|
// Implements extension method Float64::near
|
|
3
|
-
import {bubble} from "./core.js";
|
|
4
|
+
import {bubble, INT32_MAX, INT32_MIN, INT64_MAX, INT64_MIN} from "./core.js";
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Implements extension method Float64::near
|
|
@@ -22,12 +23,12 @@ export const float64Near = (x, y, relTol, absTol) => {
|
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
/**
|
|
25
|
-
* Implements extension method Float64::
|
|
26
|
+
* Implements extension method Float64::toInt32
|
|
26
27
|
* @param {number} n
|
|
27
28
|
* @returns {number}
|
|
28
29
|
*/
|
|
29
|
-
export const
|
|
30
|
-
const i =
|
|
30
|
+
export const float64ToInt32 = (n) => {
|
|
31
|
+
const i = float64ToInt32Unsafe(n);
|
|
31
32
|
if (Math.abs(n - i) < 1) {
|
|
32
33
|
return i;
|
|
33
34
|
} else {
|
|
@@ -36,20 +37,49 @@ export const float64ToInt = (n) => {
|
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
/**
|
|
39
|
-
* Implements extension method Float64::
|
|
40
|
+
* Implements extension method Float64::toInt32Unsafe
|
|
40
41
|
* @param {number} n
|
|
41
42
|
* @returns {number}
|
|
42
43
|
*/
|
|
43
|
-
export const
|
|
44
|
+
export const float64ToInt32Unsafe = (n) => {
|
|
44
45
|
// We are free to do whatever with NaN here.
|
|
45
46
|
return isNaN(n)
|
|
46
47
|
? 0
|
|
47
48
|
: Math.max(
|
|
48
|
-
|
|
49
|
-
Math.min(Math.trunc(n),
|
|
49
|
+
INT32_MIN,
|
|
50
|
+
Math.min(Math.trunc(n), INT32_MAX)
|
|
50
51
|
);
|
|
51
52
|
}
|
|
52
53
|
|
|
54
|
+
/**
|
|
55
|
+
* Implements extension method Float64::toInt64
|
|
56
|
+
* @param {number} n
|
|
57
|
+
* @returns {bigint}
|
|
58
|
+
*/
|
|
59
|
+
export const float64ToInt64 = (n) => {
|
|
60
|
+
// Also blocks NaNs.
|
|
61
|
+
if (!(n >= Number.MIN_SAFE_INTEGER && n <= Number.MAX_SAFE_INTEGER)) {
|
|
62
|
+
bubble();
|
|
63
|
+
}
|
|
64
|
+
return float64ToInt64Unsafe(n);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Implements extension method Float64::toInt64Unsafe
|
|
69
|
+
* @param {number} n
|
|
70
|
+
* @returns {bigint}
|
|
71
|
+
*/
|
|
72
|
+
export const float64ToInt64Unsafe = (n) => {
|
|
73
|
+
// We are free to do whatever with NaN here.
|
|
74
|
+
return isNaN(n)
|
|
75
|
+
? 0n
|
|
76
|
+
: BigInt(Math.max(
|
|
77
|
+
// Avoid converting giant numbers to bigint.
|
|
78
|
+
Number(INT64_MIN),
|
|
79
|
+
Math.min(Math.trunc(n), Number(INT64_MAX)),
|
|
80
|
+
));
|
|
81
|
+
}
|
|
82
|
+
|
|
53
83
|
/**
|
|
54
84
|
* Implements extension method Float64::toString
|
|
55
85
|
* @param {number} n
|
package/index.js
CHANGED
package/interface.js
CHANGED
package/mapped.js
CHANGED
|
@@ -156,7 +156,7 @@ export const mappedHas = (map, key) => {
|
|
|
156
156
|
* @returns {Readonly<K[]>}
|
|
157
157
|
*/
|
|
158
158
|
export const mappedKeys = (map) => {
|
|
159
|
-
return Object.freeze(Array.
|
|
159
|
+
return Object.freeze(Array.from(map.keys()));
|
|
160
160
|
}
|
|
161
161
|
|
|
162
162
|
/**
|
|
@@ -165,7 +165,7 @@ export const mappedKeys = (map) => {
|
|
|
165
165
|
* @returns {Readonly<V[]>}
|
|
166
166
|
*/
|
|
167
167
|
export const mappedValues = (map) => {
|
|
168
|
-
return Object.freeze(Array.
|
|
168
|
+
return Object.freeze(Array.from(map.values()));
|
|
169
169
|
}
|
|
170
170
|
|
|
171
171
|
/**
|
package/net.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @param {string} url
|
|
3
|
+
* @param {"GET" | "POST"} method
|
|
4
|
+
* @param {string | null} bodyContent
|
|
5
|
+
* @param {string | null} bodyMimeType
|
|
6
|
+
* @return {Promise<Response>}
|
|
7
|
+
*/
|
|
8
|
+
export function stdNetSend(url, method, bodyContent, bodyMimeType) {
|
|
9
|
+
let details = { method };
|
|
10
|
+
if (typeof bodyContent === 'string') {
|
|
11
|
+
details.body = bodyContent;
|
|
12
|
+
if (typeof bodyMimeType === 'string') {
|
|
13
|
+
details.headers = { 'Content-Type': bodyMimeType };
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return fetch(url, details);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* @param {Response} r
|
|
21
|
+
* @return {number} an HTTP status code
|
|
22
|
+
*/
|
|
23
|
+
export function netResponseGetStatus(r) {
|
|
24
|
+
return r.status;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @param {Response} r
|
|
29
|
+
* @return {string | null} the mime-type of the body.
|
|
30
|
+
*/
|
|
31
|
+
export function netResponseGetContentType(r) {
|
|
32
|
+
return r.headers.get('Content-Type') || null;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @param {Response} r
|
|
37
|
+
* @return {Promise<string | null>} the body content.
|
|
38
|
+
*/
|
|
39
|
+
export function netResponseGetBodyContent(r) {
|
|
40
|
+
return r.text();
|
|
41
|
+
}
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@temperlang/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Runtime support for JS generated by Temper",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"author": "https://github.com/mikesamuel",
|
|
8
|
-
"license": "Apache-2.0"
|
|
8
|
+
"license": "Apache-2.0 OR MIT"
|
|
9
9
|
}
|
package/regex.js
CHANGED
|
@@ -108,7 +108,7 @@ export const regexCompiledSplit = (_, compiled, text) => {
|
|
|
108
108
|
};
|
|
109
109
|
|
|
110
110
|
/**
|
|
111
|
-
* @param {
|
|
111
|
+
* @param {unknown} _
|
|
112
112
|
* @param {string} formatted
|
|
113
113
|
* @returns {RegExp}
|
|
114
114
|
*/
|
|
@@ -139,10 +139,16 @@ export const regexFormatterAdjustCodeSet = (self, codeSet, regexRefs) => {
|
|
|
139
139
|
return codeSet;
|
|
140
140
|
};
|
|
141
141
|
|
|
142
|
+
/**
|
|
143
|
+
* @param {unknown} _
|
|
144
|
+
* @param {[string]} out
|
|
145
|
+
* @param {number} code
|
|
146
|
+
* @param {boolean} insideCodeSet
|
|
147
|
+
*/
|
|
142
148
|
export const regexFormatterPushCodeTo = (_, out, code, insideCodeSet) => {
|
|
143
149
|
// Ignore insideCodeSet for now.
|
|
144
150
|
// TODO(tjp, regex): Get fancier, including with work in Temper.
|
|
145
|
-
out
|
|
151
|
+
out[0] += `\\u{${code.toString(16)}}`;
|
|
146
152
|
};
|
|
147
153
|
|
|
148
154
|
// Cached later for some approximate efficiency.
|
package/string.js
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
bubble, INT32_MAX, INT32_MIN, INT64_MAX, INT64_MIN, parseBigInt
|
|
3
|
+
} from "./core.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Implements extension method String::fromCodePoint
|
|
7
|
+
* @param {number} codePoint
|
|
8
|
+
* @returns {string}
|
|
9
|
+
*/
|
|
10
|
+
export const stringFromCodePoint = (codePoint) => {
|
|
11
|
+
denySurrogate(codePoint);
|
|
12
|
+
return String.fromCodePoint(codePoint);
|
|
13
|
+
};
|
|
3
14
|
|
|
4
15
|
/**
|
|
5
16
|
* Implements extension method String::fromCodePoints
|
|
@@ -7,6 +18,9 @@ import {bubble} from "./core.js";
|
|
|
7
18
|
* @returns {string}
|
|
8
19
|
*/
|
|
9
20
|
export const stringFromCodePoints = (codePoints) => {
|
|
21
|
+
for (const codePoint of codePoints) {
|
|
22
|
+
denySurrogate(codePoint);
|
|
23
|
+
}
|
|
10
24
|
// TODO Append in batches if codePoints is long?
|
|
11
25
|
return String.fromCodePoint(...codePoints);
|
|
12
26
|
};
|
|
@@ -44,20 +58,38 @@ export const stringToFloat64 = (s) => {
|
|
|
44
58
|
};
|
|
45
59
|
|
|
46
60
|
/**
|
|
47
|
-
* Implements extension method String::
|
|
61
|
+
* Implements extension method String::toInt32
|
|
48
62
|
* @param {string} s
|
|
49
63
|
* @param {number?} radix
|
|
50
64
|
* @returns {number}
|
|
51
65
|
*/
|
|
52
|
-
export const
|
|
66
|
+
export const stringToInt32 = (s, radix) => {
|
|
53
67
|
// This currently maybe allocates for trim and then also for check.
|
|
54
68
|
// TODO Avoid that with manual char checks? Arbitrary base makes regex harder.
|
|
55
69
|
s = s.trim();
|
|
56
70
|
radix = radix ?? 10;
|
|
57
71
|
const result = parseInt(s, radix);
|
|
58
|
-
|
|
72
|
+
// This check also catches nan.
|
|
73
|
+
if (!(result >= INT32_MIN && result <= INT32_MAX)) {
|
|
74
|
+
bubble();
|
|
75
|
+
}
|
|
59
76
|
const trimmed = s.slice(0, s.length - 1);
|
|
60
77
|
if (parseInt(trimmed, radix) === result) {
|
|
78
|
+
// Extraneous junk was ignored that we disallow.
|
|
79
|
+
bubble();
|
|
80
|
+
}
|
|
81
|
+
return result;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* Implements extension method String::toInt64
|
|
86
|
+
* @param {string} s
|
|
87
|
+
* @param {number?} radix
|
|
88
|
+
* @returns {number}
|
|
89
|
+
*/
|
|
90
|
+
export const stringToInt64 = (s, radix) => {
|
|
91
|
+
const result = parseBigInt(s, radix);
|
|
92
|
+
if (result < INT64_MIN || result > INT64_MAX) {
|
|
61
93
|
bubble();
|
|
62
94
|
}
|
|
63
95
|
return result;
|
|
@@ -151,6 +183,25 @@ export const stringPrev = (s, i) => {
|
|
|
151
183
|
return iPrev;
|
|
152
184
|
};
|
|
153
185
|
|
|
186
|
+
/**
|
|
187
|
+
* @param {string} s
|
|
188
|
+
* @param {number} i
|
|
189
|
+
* @param {number} by
|
|
190
|
+
* @returns {number}
|
|
191
|
+
*/
|
|
192
|
+
export const stringStep = (s, i, by) => {
|
|
193
|
+
let step = by >= 0 ? stringNext : stringPrev;
|
|
194
|
+
by = Math.abs(by);
|
|
195
|
+
for (let j = 0; j < by; j += 1) {
|
|
196
|
+
const iOld = i;
|
|
197
|
+
i = step(s, i);
|
|
198
|
+
if (i == iOld) {
|
|
199
|
+
break;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return i;
|
|
203
|
+
};
|
|
204
|
+
|
|
154
205
|
/**
|
|
155
206
|
* @param {string} s
|
|
156
207
|
* @param {(number) => void} f
|
|
@@ -194,5 +245,15 @@ export const requireNoStringIndex = (i) => {
|
|
|
194
245
|
* @param {number} c
|
|
195
246
|
*/
|
|
196
247
|
export const stringBuilderAppendCodePoint = (s, c) => {
|
|
248
|
+
denySurrogate(c);
|
|
197
249
|
s[0] += String.fromCodePoint(c);
|
|
198
250
|
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* @param {number} c
|
|
254
|
+
*/
|
|
255
|
+
const denySurrogate = (c) => {
|
|
256
|
+
if (c >= 0xD800 && c <= 0xDFFF) {
|
|
257
|
+
throw new RangeError(`Invalid Unicode scalar value ${c}`)
|
|
258
|
+
}
|
|
259
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"allowJs": true,
|
|
4
|
+
"noEmit": true,
|
|
5
|
+
"preserveConstEnums": false,
|
|
6
|
+
"removeComments": true,
|
|
7
|
+
"sourceMap": false,
|
|
8
|
+
"target": "es2020"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"async.js",
|
|
12
|
+
"bitvector.js",
|
|
13
|
+
"check-type.js",
|
|
14
|
+
"core.js",
|
|
15
|
+
"date.js",
|
|
16
|
+
"deque.js",
|
|
17
|
+
"float.js",
|
|
18
|
+
"index.js",
|
|
19
|
+
"interface.js",
|
|
20
|
+
"listed.js",
|
|
21
|
+
"mapped.js",
|
|
22
|
+
"pair.js",
|
|
23
|
+
"regex.js",
|
|
24
|
+
"string.js"
|
|
25
|
+
]
|
|
26
|
+
}
|