@temperlang/core 0.0.3 → 0.0.4
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 +417 -242
- package/interface-types.js +0 -0
- package/package.json +1 -1
- package/regex.js +49 -6
package/index.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
export * from
|
|
2
|
-
export * from
|
|
1
|
+
export * from "./interface-types.js";
|
|
2
|
+
export * from "./regex.js";
|
|
3
3
|
|
|
4
|
-
export const noResultException = new (
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
super("NoResult");
|
|
8
|
-
}
|
|
4
|
+
export const noResultException = new (class NoResultException extends Error {
|
|
5
|
+
constructor() {
|
|
6
|
+
super("NoResult");
|
|
9
7
|
}
|
|
10
|
-
);
|
|
8
|
+
})();
|
|
11
9
|
|
|
12
10
|
// Implements extension method String::isEmpty
|
|
13
|
-
export function stringIsEmpty(s) {
|
|
11
|
+
export function stringIsEmpty(s) {
|
|
12
|
+
return s === "";
|
|
13
|
+
}
|
|
14
14
|
// Implements extension method String::split
|
|
15
15
|
export function stringSplit(s, separator) {
|
|
16
16
|
return s.split(separator).map((s) => s);
|
|
@@ -18,18 +18,16 @@ export function stringSplit(s, separator) {
|
|
|
18
18
|
|
|
19
19
|
/** Specifically for utf8 and utf32, since utf16 is simpler in js. */
|
|
20
20
|
class TrickyStringSlice {
|
|
21
|
-
#length;
|
|
22
|
-
|
|
23
21
|
hasAtLeast(count) {
|
|
24
22
|
// Repeated calls to hasAtLeast are potentially expensive.
|
|
25
|
-
return (this
|
|
23
|
+
return (this.length ?? this._lengthUntil(count)) >= count;
|
|
26
24
|
}
|
|
27
25
|
|
|
28
26
|
get length() {
|
|
29
|
-
if (this
|
|
30
|
-
this
|
|
27
|
+
if (this._length === undefined) {
|
|
28
|
+
this._length = this._lengthUntil();
|
|
31
29
|
}
|
|
32
|
-
return this
|
|
30
|
+
return this._length;
|
|
33
31
|
}
|
|
34
32
|
|
|
35
33
|
_lengthUntil(stop = undefined) {
|
|
@@ -39,62 +37,58 @@ class TrickyStringSlice {
|
|
|
39
37
|
}
|
|
40
38
|
|
|
41
39
|
class Utf8StringSlice extends TrickyStringSlice {
|
|
42
|
-
/** The underlying string value. */
|
|
43
|
-
#content;
|
|
44
|
-
/**
|
|
45
|
-
* The byte index approximation of the left side.
|
|
46
|
-
* A byte index approximation is an integer, i, such that:
|
|
47
|
-
* - (i >> 2) is the index of a codepoint in #content
|
|
48
|
-
* - (i & 3) is the index of a byte within the UTF-8 representation of that codepoint.
|
|
49
|
-
*/
|
|
50
|
-
#left;
|
|
51
|
-
/** The byte index approximation of the right side. */
|
|
52
|
-
#right;
|
|
53
|
-
|
|
54
40
|
constructor(content, left = 0, right = content.length * 4) {
|
|
55
41
|
super();
|
|
56
|
-
this
|
|
57
|
-
this
|
|
58
|
-
this
|
|
42
|
+
this.content = content;
|
|
43
|
+
this.left = left;
|
|
44
|
+
this.right = right;
|
|
59
45
|
}
|
|
60
46
|
|
|
61
47
|
toString() {
|
|
62
|
-
let left = this
|
|
63
|
-
let right = this
|
|
64
|
-
let content = this
|
|
48
|
+
let left = this.left;
|
|
49
|
+
let right = this.right;
|
|
50
|
+
let content = this.content;
|
|
65
51
|
|
|
66
|
-
if (left === right) {
|
|
52
|
+
if (left === right) {
|
|
53
|
+
return "";
|
|
54
|
+
}
|
|
67
55
|
|
|
68
56
|
// If we're only using some bytes on the left or right, replace that codepoint with U+FFFD.
|
|
69
57
|
let leftPartial = left & 3; // Do we have an incomplete code-point on the left?
|
|
70
58
|
let leftIndex = (left + 3) >> 2;
|
|
71
59
|
let rightIndex = right >> 2;
|
|
72
|
-
let rightPartial =
|
|
60
|
+
let rightPartial = right & 3;
|
|
73
61
|
|
|
74
62
|
// If leftIndex is in the middle of a surrogate pair, advance over the tail.
|
|
75
63
|
if (leftIndex < rightIndex) {
|
|
76
64
|
let leftCodeUnitUtf16 = content.charCodeAt(leftIndex);
|
|
77
|
-
if (
|
|
65
|
+
if (0xdc00 < leftCodeUnitUtf16 && leftCodeUnitUtf16 <= 0xdfff) {
|
|
78
66
|
leftIndex += 1;
|
|
79
67
|
}
|
|
80
68
|
}
|
|
81
69
|
|
|
82
|
-
if (leftIndex > rightIndex) {
|
|
70
|
+
if (leftIndex > rightIndex) {
|
|
71
|
+
return "\uFFFD";
|
|
72
|
+
}
|
|
83
73
|
|
|
84
74
|
let sub = content.substring(leftIndex, rightIndex);
|
|
85
75
|
if (leftPartial || rightPartial) {
|
|
86
|
-
return `${leftPartial ? "\uFFFD" : ""}${sub}${
|
|
76
|
+
return `${leftPartial ? "\uFFFD" : ""}${sub}${
|
|
77
|
+
rightPartial ? "\uFFFD" : ""
|
|
78
|
+
}`;
|
|
87
79
|
} else {
|
|
88
80
|
return sub;
|
|
89
81
|
}
|
|
90
82
|
}
|
|
91
83
|
|
|
92
|
-
valueOf() {
|
|
84
|
+
valueOf() {
|
|
85
|
+
return this.toString();
|
|
86
|
+
}
|
|
93
87
|
|
|
94
88
|
_lengthUntil(stop) {
|
|
95
|
-
const left = this
|
|
96
|
-
const right = this
|
|
97
|
-
const content = this
|
|
89
|
+
const left = this.left;
|
|
90
|
+
const right = this.right;
|
|
91
|
+
const content = this.content;
|
|
98
92
|
let i = left >> 2;
|
|
99
93
|
// Add bytes between codePointBoundaryBeforeLimit and right
|
|
100
94
|
// Subtract bytes past zeroth in codepoint for left
|
|
@@ -113,17 +107,17 @@ class Utf8StringSlice extends TrickyStringSlice {
|
|
|
113
107
|
}
|
|
114
108
|
|
|
115
109
|
get isEmpty() {
|
|
116
|
-
return this
|
|
110
|
+
return this.left >= this.right;
|
|
117
111
|
}
|
|
118
112
|
|
|
119
113
|
read() {
|
|
120
|
-
let left = this
|
|
121
|
-
let right = this
|
|
114
|
+
let left = this.left;
|
|
115
|
+
let right = this.right;
|
|
122
116
|
if (left >= right) {
|
|
123
117
|
throw noResultException;
|
|
124
118
|
}
|
|
125
119
|
|
|
126
|
-
let content = this
|
|
120
|
+
let content = this.content;
|
|
127
121
|
let cp = content.codePointAt(left >> 2);
|
|
128
122
|
if (cp < 0x80) {
|
|
129
123
|
return cp;
|
|
@@ -131,7 +125,8 @@ class Utf8StringSlice extends TrickyStringSlice {
|
|
|
131
125
|
let byteOffset = left & 3;
|
|
132
126
|
let nBytes = nUtf8BytesInChar(cp);
|
|
133
127
|
let byteInfo = byteInfos[(nBytes - 1) * 4 + byteOffset];
|
|
134
|
-
let codeUnit =
|
|
128
|
+
let codeUnit =
|
|
129
|
+
((cp >>> byteInfo.shift) & byteInfo.andMask) | byteInfo.orMask;
|
|
135
130
|
return codeUnit;
|
|
136
131
|
}
|
|
137
132
|
}
|
|
@@ -140,12 +135,12 @@ class Utf8StringSlice extends TrickyStringSlice {
|
|
|
140
135
|
if (count <= 0) {
|
|
141
136
|
return this;
|
|
142
137
|
} else if (count === 1) {
|
|
143
|
-
let left = this
|
|
144
|
-
let right = this
|
|
138
|
+
let left = this.left;
|
|
139
|
+
let right = this.right;
|
|
145
140
|
if (left >= right) {
|
|
146
141
|
return this;
|
|
147
142
|
}
|
|
148
|
-
let content = this
|
|
143
|
+
let content = this.content;
|
|
149
144
|
let cp = content.codePointAt(left >> 2);
|
|
150
145
|
let newLeft;
|
|
151
146
|
if (cp < 0x80) {
|
|
@@ -153,7 +148,10 @@ class Utf8StringSlice extends TrickyStringSlice {
|
|
|
153
148
|
} else {
|
|
154
149
|
let byteOffset = left & 3;
|
|
155
150
|
let nBytes = nUtf8BytesInChar(cp);
|
|
156
|
-
newLeft =
|
|
151
|
+
newLeft =
|
|
152
|
+
byteOffset + 1 < nBytes
|
|
153
|
+
? left + 1
|
|
154
|
+
: (left & ~3) + ((nBytes + 4) & ~3);
|
|
157
155
|
}
|
|
158
156
|
return new Utf8StringSlice(content, newLeft, right);
|
|
159
157
|
} else {
|
|
@@ -162,7 +160,7 @@ class Utf8StringSlice extends TrickyStringSlice {
|
|
|
162
160
|
}
|
|
163
161
|
|
|
164
162
|
[Symbol.iterator]() {
|
|
165
|
-
function
|
|
163
|
+
function* bytes(content, left, limit) {
|
|
166
164
|
let i = left;
|
|
167
165
|
while (i < limit) {
|
|
168
166
|
let cp = content.codePointAt(i >> 2);
|
|
@@ -173,127 +171,115 @@ class Utf8StringSlice extends TrickyStringSlice {
|
|
|
173
171
|
let byteOffset = i & 3;
|
|
174
172
|
let nBytes = nUtf8BytesInChar(cp);
|
|
175
173
|
let byteInfo = byteInfos[(nBytes - 1) * 4 + byteOffset];
|
|
176
|
-
let codeUnit =
|
|
174
|
+
let codeUnit =
|
|
175
|
+
((cp >>> byteInfo.shift) & byteInfo.andMask) | byteInfo.orMask;
|
|
177
176
|
yield codeUnit;
|
|
178
|
-
i =
|
|
177
|
+
i = byteOffset + 1 < nBytes ? i + 1 : (i & ~3) + ((nBytes + 4) & ~3);
|
|
179
178
|
}
|
|
180
179
|
}
|
|
181
180
|
}
|
|
182
|
-
return bytes(this
|
|
181
|
+
return bytes(this.content, this.left, this.right);
|
|
183
182
|
}
|
|
184
183
|
|
|
185
184
|
toJSON() {
|
|
186
|
-
return { content: this
|
|
185
|
+
return { content: this.content, left: this.left, right: this.right };
|
|
187
186
|
}
|
|
188
187
|
}
|
|
189
188
|
|
|
190
189
|
class Utf16StringSlice {
|
|
191
|
-
/** The underlying string value. */
|
|
192
|
-
#content;
|
|
193
|
-
/**
|
|
194
|
-
* A regular character offset of the left of the slice, inclusive.
|
|
195
|
-
*/
|
|
196
|
-
#left;
|
|
197
|
-
/** A regular character offset of the right of the slice, exclusive. */
|
|
198
|
-
#right;
|
|
199
|
-
|
|
200
190
|
constructor(content, left = 0, right = content.length) {
|
|
201
|
-
this
|
|
202
|
-
this
|
|
203
|
-
this
|
|
191
|
+
this.content = content;
|
|
192
|
+
this.left = left;
|
|
193
|
+
this.right = right;
|
|
204
194
|
}
|
|
205
195
|
|
|
206
196
|
toString() {
|
|
207
|
-
return this
|
|
197
|
+
return this.content.substring(this.left, this.right);
|
|
208
198
|
}
|
|
209
199
|
|
|
210
|
-
valueOf() {
|
|
200
|
+
valueOf() {
|
|
201
|
+
return this.toString();
|
|
202
|
+
}
|
|
211
203
|
|
|
212
204
|
hasAtLeast(count) {
|
|
213
205
|
return this.length >= count;
|
|
214
206
|
}
|
|
215
207
|
|
|
216
208
|
get length() {
|
|
217
|
-
return this
|
|
209
|
+
return this.right - this.left;
|
|
218
210
|
}
|
|
219
211
|
|
|
220
212
|
get isEmpty() {
|
|
221
|
-
return this
|
|
213
|
+
return this.left >= this.right;
|
|
222
214
|
}
|
|
223
215
|
|
|
224
216
|
read() {
|
|
225
|
-
let left = this
|
|
226
|
-
let right = this
|
|
227
|
-
if (left >= right) {
|
|
228
|
-
|
|
217
|
+
let left = this.left;
|
|
218
|
+
let right = this.right;
|
|
219
|
+
if (left >= right) {
|
|
220
|
+
throw noResultException;
|
|
221
|
+
}
|
|
222
|
+
return this.content.charCodeAt(left);
|
|
229
223
|
}
|
|
230
224
|
|
|
231
225
|
advance(count) {
|
|
232
226
|
if (count <= 0) {
|
|
233
227
|
return this;
|
|
234
228
|
} else {
|
|
235
|
-
let left = this
|
|
236
|
-
let right = this
|
|
229
|
+
let left = this.left;
|
|
230
|
+
let right = this.right;
|
|
237
231
|
if (left >= right) {
|
|
238
232
|
return this;
|
|
239
233
|
}
|
|
240
234
|
let newLeft = left + count;
|
|
241
|
-
if (newLeft >= right) {
|
|
242
|
-
|
|
235
|
+
if (newLeft >= right) {
|
|
236
|
+
newLeft = right;
|
|
237
|
+
}
|
|
238
|
+
return new Utf16StringSlice(this.content, newLeft, right);
|
|
243
239
|
}
|
|
244
240
|
}
|
|
245
241
|
|
|
246
242
|
[Symbol.iterator]() {
|
|
247
|
-
function
|
|
243
|
+
function* chars(content, left, limit) {
|
|
248
244
|
let i = left;
|
|
249
245
|
while (i < limit) {
|
|
250
|
-
yield content.charCodeAt(i)
|
|
251
|
-
i += 1
|
|
246
|
+
yield content.charCodeAt(i);
|
|
247
|
+
i += 1;
|
|
252
248
|
}
|
|
253
249
|
}
|
|
254
|
-
return chars(this
|
|
250
|
+
return chars(this.content, this.left, this.right);
|
|
255
251
|
}
|
|
256
252
|
|
|
257
253
|
toJSON() {
|
|
258
|
-
return { content: this
|
|
254
|
+
return { content: this.content, left: this.left, right: this.right };
|
|
259
255
|
}
|
|
260
256
|
}
|
|
261
257
|
|
|
262
258
|
class CodePointsStringSlice extends TrickyStringSlice {
|
|
263
|
-
/** The underlying string value. */
|
|
264
|
-
#content;
|
|
265
|
-
/**
|
|
266
|
-
* A regular character offset of the left of the slice, inclusive.
|
|
267
|
-
*/
|
|
268
|
-
#left;
|
|
269
|
-
/** A regular character offset of the right of the slice, exclusive. */
|
|
270
|
-
#right;
|
|
271
|
-
|
|
272
259
|
constructor(content, left = 0, right = content.length) {
|
|
273
260
|
super();
|
|
274
|
-
this
|
|
275
|
-
this
|
|
276
|
-
this
|
|
261
|
+
this.content = content;
|
|
262
|
+
this.left = left;
|
|
263
|
+
this.right = right;
|
|
277
264
|
}
|
|
278
265
|
|
|
279
266
|
toString() {
|
|
280
|
-
return this
|
|
267
|
+
return this.content.substring(this.left, this.right);
|
|
281
268
|
}
|
|
282
269
|
|
|
283
|
-
valueOf() {
|
|
270
|
+
valueOf() {
|
|
271
|
+
return this.toString();
|
|
272
|
+
}
|
|
284
273
|
|
|
285
274
|
_lengthUntil(stop) {
|
|
286
|
-
|
|
287
|
-
const right = this.#right;
|
|
288
|
-
const content = this.#content;
|
|
289
|
-
let i = left;
|
|
275
|
+
let i = this.left;
|
|
290
276
|
let len = 0;
|
|
291
|
-
while (i < right) {
|
|
277
|
+
while (i < this.right) {
|
|
292
278
|
if (stop !== undefined && len >= stop) {
|
|
293
279
|
break;
|
|
294
280
|
}
|
|
295
|
-
let cp = content.codePointAt(i);
|
|
296
|
-
if (cp >
|
|
281
|
+
let cp = this.content.codePointAt(i);
|
|
282
|
+
if (cp > 0xffff) {
|
|
297
283
|
i += 2;
|
|
298
284
|
} else {
|
|
299
285
|
i += 1;
|
|
@@ -304,58 +290,59 @@ class CodePointsStringSlice extends TrickyStringSlice {
|
|
|
304
290
|
}
|
|
305
291
|
|
|
306
292
|
get isEmpty() {
|
|
307
|
-
return this
|
|
293
|
+
return this.left >= this.right;
|
|
308
294
|
}
|
|
309
295
|
|
|
310
296
|
read() {
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
return this
|
|
297
|
+
if (this.left >= this.right) {
|
|
298
|
+
throw noResultException;
|
|
299
|
+
}
|
|
300
|
+
return this.content.codePointAt(this.left);
|
|
315
301
|
}
|
|
316
302
|
|
|
317
303
|
advance(count) {
|
|
318
304
|
if (count <= 0) {
|
|
319
305
|
return this;
|
|
320
306
|
} else {
|
|
321
|
-
let left = this
|
|
322
|
-
let right = this
|
|
323
|
-
let content = this
|
|
307
|
+
let left = this.left;
|
|
308
|
+
let right = this.right;
|
|
309
|
+
let content = this.content;
|
|
324
310
|
if (left >= right) {
|
|
325
311
|
return this;
|
|
326
312
|
}
|
|
327
313
|
let newLeft = left;
|
|
328
314
|
for (let i = count; i && newLeft < right; --i) {
|
|
329
315
|
let cp = content.codePointAt(newLeft);
|
|
330
|
-
if (cp >
|
|
316
|
+
if (cp > 0xffff) {
|
|
331
317
|
newLeft += 2;
|
|
332
318
|
} else {
|
|
333
319
|
newLeft += 1;
|
|
334
320
|
}
|
|
335
321
|
}
|
|
336
|
-
if (newLeft >= right) {
|
|
337
|
-
|
|
322
|
+
if (newLeft >= right) {
|
|
323
|
+
newLeft = right;
|
|
324
|
+
}
|
|
325
|
+
return new CodePointsStringSlice(this.content, newLeft, right);
|
|
338
326
|
}
|
|
339
327
|
}
|
|
340
328
|
|
|
341
329
|
[Symbol.iterator]() {
|
|
342
|
-
function
|
|
330
|
+
function* chars(content, left, limit) {
|
|
343
331
|
let i = left;
|
|
344
332
|
while (i < limit) {
|
|
345
333
|
let cp = content.codePointAt(i);
|
|
346
334
|
yield cp;
|
|
347
|
-
i +=
|
|
335
|
+
i += cp > 0xffff ? 2 : 1;
|
|
348
336
|
}
|
|
349
337
|
}
|
|
350
|
-
return chars(this
|
|
338
|
+
return chars(this.content, this.left, this.right);
|
|
351
339
|
}
|
|
352
340
|
|
|
353
341
|
toJSON() {
|
|
354
|
-
return { content: this
|
|
342
|
+
return { content: this.content, left: this.left, right: this.right };
|
|
355
343
|
}
|
|
356
344
|
}
|
|
357
345
|
|
|
358
|
-
|
|
359
346
|
// Implements extension method String::utf8
|
|
360
347
|
export function stringUtf8(string) {
|
|
361
348
|
return new Utf8StringSlice(string);
|
|
@@ -376,33 +363,57 @@ export function intToString(i, radix) {
|
|
|
376
363
|
return i.toString(radix);
|
|
377
364
|
}
|
|
378
365
|
|
|
366
|
+
// Implements extension method Float64::toInt
|
|
367
|
+
export function float64ToInt(n) {
|
|
368
|
+
const i = float64ToIntUnsafe(n);
|
|
369
|
+
if (Math.abs(n - i) < 1) {
|
|
370
|
+
return i;
|
|
371
|
+
} else {
|
|
372
|
+
throw noResultException;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
// Implements extension method Float64::toIntUnsafe
|
|
377
|
+
export function float64ToIntUnsafe(n) {
|
|
378
|
+
// We are free to do whatever with NaN here.
|
|
379
|
+
return isNaN(n)
|
|
380
|
+
? 0
|
|
381
|
+
: Math.max(
|
|
382
|
+
Number.MIN_SAFE_INTEGER,
|
|
383
|
+
Math.min(Math.trunc(n), Number.MAX_SAFE_INTEGER)
|
|
384
|
+
);
|
|
385
|
+
}
|
|
386
|
+
|
|
379
387
|
// Implements extension method Float64::toString
|
|
380
388
|
export function float64ToString(n) {
|
|
381
389
|
// TODO(mikesamuel, issue#579): need functional test to nail down
|
|
382
390
|
// double formatting threshholds.
|
|
383
391
|
switch (n) {
|
|
384
392
|
case 0:
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
return "0.0"
|
|
389
|
-
}
|
|
390
|
-
else {
|
|
391
|
-
return "-0.0"
|
|
393
|
+
if (Object.is(n, -0)) {
|
|
394
|
+
return "-0.0";
|
|
395
|
+
} else {
|
|
396
|
+
return "0.0";
|
|
392
397
|
}
|
|
393
398
|
case Infinity:
|
|
394
|
-
return "∞"
|
|
399
|
+
return "∞";
|
|
395
400
|
case Number.NEGATIVE_INFINITY:
|
|
396
|
-
return "-∞"
|
|
401
|
+
return "-∞";
|
|
397
402
|
default:
|
|
398
|
-
|
|
399
|
-
|
|
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
|
+
}
|
|
412
|
+
}
|
|
400
413
|
}
|
|
401
414
|
|
|
402
415
|
function nUtf8BytesInChar(cp) {
|
|
403
|
-
return (cp <
|
|
404
|
-
? ((cp < 0x80) ? 1 : 2)
|
|
405
|
-
: ((cp < 0x10000) ? 3 : 4)
|
|
416
|
+
return cp < 0x0800 ? (cp < 0x80 ? 1 : 2) : cp < 0x10000 ? 3 : 4;
|
|
406
417
|
}
|
|
407
418
|
|
|
408
419
|
/*
|
|
@@ -451,9 +462,7 @@ export function listBuilderAdd(ls, newItem, at) {
|
|
|
451
462
|
}
|
|
452
463
|
ls.splice(at, 0, newItem);
|
|
453
464
|
}
|
|
454
|
-
return; // of type tVoid
|
|
455
465
|
}
|
|
456
|
-
|
|
457
466
|
// Implements extension method ListBuilder::addAll
|
|
458
467
|
export function listBuilderAddAll(ls, newItems, at) {
|
|
459
468
|
if (at === undefined) {
|
|
@@ -464,7 +473,6 @@ export function listBuilderAddAll(ls, newItems, at) {
|
|
|
464
473
|
}
|
|
465
474
|
ls.splice(at, 0, ...newItems);
|
|
466
475
|
}
|
|
467
|
-
return; // of type tVoid
|
|
468
476
|
}
|
|
469
477
|
// Implements extension method List::filter
|
|
470
478
|
export function listFilter(ls, predicate) {
|
|
@@ -494,13 +502,15 @@ export function listFilter(ls, predicate) {
|
|
|
494
502
|
// Implements extension method List::get
|
|
495
503
|
export function listGet(ls, i) {
|
|
496
504
|
let { length } = ls;
|
|
497
|
-
if (0 <= i && i < length) {
|
|
505
|
+
if (0 <= i && i < length) {
|
|
506
|
+
return ls[i];
|
|
507
|
+
}
|
|
498
508
|
throw noResultException;
|
|
499
509
|
}
|
|
500
510
|
// Implements extension method List::getOr
|
|
501
511
|
export function listGetOr(ls, i, fallback) {
|
|
502
512
|
let { length } = ls;
|
|
503
|
-
return
|
|
513
|
+
return 0 <= i && i < length ? ls[i] : fallback;
|
|
504
514
|
}
|
|
505
515
|
// Implements extension method List::isEmpty
|
|
506
516
|
export function listIsEmpty(ls) {
|
|
@@ -508,7 +518,7 @@ export function listIsEmpty(ls) {
|
|
|
508
518
|
}
|
|
509
519
|
// Implements extension method List::join
|
|
510
520
|
export function listJoin(ls, separator, elementStringifier) {
|
|
511
|
-
let joined =
|
|
521
|
+
let joined = "";
|
|
512
522
|
let { length } = ls;
|
|
513
523
|
for (let i = 0; i < length; ++i) {
|
|
514
524
|
if (i) {
|
|
@@ -521,9 +531,13 @@ export function listJoin(ls, separator, elementStringifier) {
|
|
|
521
531
|
return joined;
|
|
522
532
|
}
|
|
523
533
|
// Implements extension method List::length
|
|
524
|
-
export function listLength(ls) {
|
|
534
|
+
export function listLength(ls) {
|
|
535
|
+
return ls.length;
|
|
536
|
+
}
|
|
525
537
|
// Implements extension method List::mapDropping
|
|
526
|
-
export function listMapDropping() {
|
|
538
|
+
export function listMapDropping() {
|
|
539
|
+
throw new Error("TODO List::mapDropping");
|
|
540
|
+
}
|
|
527
541
|
// Implements extension method List::map
|
|
528
542
|
export function listMap(ls, transform) {
|
|
529
543
|
let mapped = [];
|
|
@@ -534,6 +548,14 @@ export function listMap(ls, transform) {
|
|
|
534
548
|
}
|
|
535
549
|
return freeze(mapped);
|
|
536
550
|
}
|
|
551
|
+
// Implements extension method ListBuilder::removeLast
|
|
552
|
+
export function listBuilderRemoveLast(ls) {
|
|
553
|
+
if (ls.length) {
|
|
554
|
+
return ls.pop();
|
|
555
|
+
} else {
|
|
556
|
+
throw noResultException;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
537
559
|
// Implements extension method ListBuilder::reverse
|
|
538
560
|
export function listBuilderReverse(ls) {
|
|
539
561
|
let { length } = ls;
|
|
@@ -548,11 +570,17 @@ export function listBuilderReverse(ls) {
|
|
|
548
570
|
}
|
|
549
571
|
// Implements extension method ListBuilder::set
|
|
550
572
|
export function listBuilderSet(ls, i, newValue) {
|
|
551
|
-
|
|
552
|
-
if (0 <= i && i <= length) {
|
|
573
|
+
if (0 <= i && i <= ls.length) {
|
|
553
574
|
ls[i] = newValue;
|
|
554
575
|
}
|
|
555
|
-
|
|
576
|
+
}
|
|
577
|
+
// Implements extension method ListBuilder::removeLast
|
|
578
|
+
export function listBuilderSplice(ls, index, removeCount, newValues) {
|
|
579
|
+
// Missing count is all, but explicit undefined is 0, so give explicit length.
|
|
580
|
+
if (removeCount === undefined) {
|
|
581
|
+
removeCount = ls.length;
|
|
582
|
+
}
|
|
583
|
+
return freeze(ls.splice(index, removeCount, ...(newValues || [])));
|
|
556
584
|
}
|
|
557
585
|
// Implements extension method ListBuilder::toList
|
|
558
586
|
export function listBuilderToList(ls) {
|
|
@@ -560,11 +588,87 @@ export function listBuilderToList(ls) {
|
|
|
560
588
|
}
|
|
561
589
|
// Implements extension method List::slice
|
|
562
590
|
export function listSlice(ls, startInclusive, endExclusive) {
|
|
563
|
-
if (startInclusive < 0) {
|
|
564
|
-
|
|
591
|
+
if (startInclusive < 0) {
|
|
592
|
+
startInclusive = 0;
|
|
593
|
+
}
|
|
594
|
+
if (endExclusive < 0) {
|
|
595
|
+
endExclusive = 0;
|
|
596
|
+
}
|
|
565
597
|
return freeze(ls.slice(startInclusive, endExclusive));
|
|
566
598
|
}
|
|
567
599
|
|
|
600
|
+
// Map
|
|
601
|
+
class FreezeMap extends Map {
|
|
602
|
+
// TODO Don't worry to freeze? Or worry more by wrapping private map?
|
|
603
|
+
// TODO Wrapping/Object.proxy presumably pays an extra cost when wrapped.
|
|
604
|
+
clear() {
|
|
605
|
+
throw new TypeError();
|
|
606
|
+
}
|
|
607
|
+
delete() {
|
|
608
|
+
throw new TypeError();
|
|
609
|
+
}
|
|
610
|
+
set(key, value) {
|
|
611
|
+
if (Object.isFrozen(this)) {
|
|
612
|
+
// Crash only after frozen because constructor calls set.
|
|
613
|
+
throw new TypeError();
|
|
614
|
+
}
|
|
615
|
+
return super.set(key, value);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
export function mapConstructor(entries) {
|
|
619
|
+
return Object.freeze(new FreezeMap(entries));
|
|
620
|
+
}
|
|
621
|
+
// MapBuilder
|
|
622
|
+
export function mapBuilderConstructor(entries) {
|
|
623
|
+
return new Map();
|
|
624
|
+
}
|
|
625
|
+
export function mapBuilderRemove(builder, key) {
|
|
626
|
+
const result = builder.get(key);
|
|
627
|
+
if (builder.delete(key)) {
|
|
628
|
+
return result;
|
|
629
|
+
} else {
|
|
630
|
+
throw noResultException;
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
export function mapBuilderSet(builder, key, value) {
|
|
634
|
+
builder.set(key, value);
|
|
635
|
+
}
|
|
636
|
+
export function mapBuilderToMap(builder) {
|
|
637
|
+
return Object.freeze(new FreezeMap(builder));
|
|
638
|
+
}
|
|
639
|
+
// Pair
|
|
640
|
+
class Pair {
|
|
641
|
+
constructor(key, value) {
|
|
642
|
+
this.key = key;
|
|
643
|
+
this.value = value;
|
|
644
|
+
}
|
|
645
|
+
get [0]() {
|
|
646
|
+
return this.key;
|
|
647
|
+
}
|
|
648
|
+
get [1]() {
|
|
649
|
+
return this.value;
|
|
650
|
+
}
|
|
651
|
+
get length() {
|
|
652
|
+
return 2;
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
export function pairConstructor(key, value) {
|
|
656
|
+
return Object.freeze(new Pair(key, value));
|
|
657
|
+
}
|
|
658
|
+
// Mapped
|
|
659
|
+
export function mappedGet(map, key) {
|
|
660
|
+
const result = map.get(key);
|
|
661
|
+
// 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?
|
|
663
|
+
if (result === undefined) {
|
|
664
|
+
throw noResultException;
|
|
665
|
+
}
|
|
666
|
+
return result;
|
|
667
|
+
}
|
|
668
|
+
export function mappedToList(map) {
|
|
669
|
+
return Array.from(map, ([key, value]) => new Pair(key, value));
|
|
670
|
+
}
|
|
671
|
+
|
|
568
672
|
// Implements extension method Deque::constructor
|
|
569
673
|
const DEQUE_NTAKEN = Symbol("Deque::nTaken");
|
|
570
674
|
export function dequeConstructor() {
|
|
@@ -592,7 +696,9 @@ export function dequeRemoveFirst(deque) {
|
|
|
592
696
|
}
|
|
593
697
|
let item = deque[nTaken];
|
|
594
698
|
let nShiftThreshhold = (length / 2) | 0;
|
|
595
|
-
if (nShiftThreshhold < 32) {
|
|
699
|
+
if (nShiftThreshhold < 32) {
|
|
700
|
+
nShiftThreshhold = 32;
|
|
701
|
+
}
|
|
596
702
|
if (nTaken >= nShiftThreshhold) {
|
|
597
703
|
deque.splice(0, nTaken + 1);
|
|
598
704
|
deque[DEQUE_NTAKEN] = 0;
|
|
@@ -603,36 +709,24 @@ export function dequeRemoveFirst(deque) {
|
|
|
603
709
|
return item;
|
|
604
710
|
}
|
|
605
711
|
|
|
606
|
-
const ZERO_N = BigInt(0);
|
|
607
|
-
const ONE_N = BigInt(1);
|
|
608
712
|
class DenseBitVector {
|
|
609
|
-
#bits /* : BigInt */;
|
|
610
|
-
|
|
611
713
|
constructor() {
|
|
612
|
-
this
|
|
714
|
+
this.bits = [];
|
|
613
715
|
}
|
|
614
716
|
|
|
615
717
|
get(index) {
|
|
616
|
-
return
|
|
718
|
+
return this.bits[index] == null ? false : this.bits[index];
|
|
617
719
|
}
|
|
618
720
|
|
|
619
721
|
set(index, newBitValue) {
|
|
620
|
-
|
|
621
|
-
this.#bits = newBitValue
|
|
622
|
-
? (this.#bits | mask)
|
|
623
|
-
: (this.#bits & ~mask);
|
|
722
|
+
this.bits[index] = Boolean(newBitValue);
|
|
624
723
|
}
|
|
625
724
|
|
|
626
725
|
toString() {
|
|
627
|
-
return
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
valueOf() {
|
|
631
|
-
return this.#bits;
|
|
726
|
+
return `0b${this.bits.map(Number).join("")}`;
|
|
632
727
|
}
|
|
633
|
-
|
|
634
728
|
toJSON() {
|
|
635
|
-
return this
|
|
729
|
+
return this.bits;
|
|
636
730
|
}
|
|
637
731
|
}
|
|
638
732
|
|
|
@@ -651,7 +745,7 @@ export function denseBitVectorSet(denseBitVector, index, newBitValue) {
|
|
|
651
745
|
|
|
652
746
|
// Implements extension method Boolean::toString
|
|
653
747
|
export function booleanToString(b) {
|
|
654
|
-
return b ?
|
|
748
|
+
return b ? "true" : "false";
|
|
655
749
|
}
|
|
656
750
|
|
|
657
751
|
// Implements Symbol construction.
|
|
@@ -660,7 +754,7 @@ export function symbolFor(text) {
|
|
|
660
754
|
}
|
|
661
755
|
|
|
662
756
|
// Stubs out static property verification
|
|
663
|
-
export function getStatic(
|
|
757
|
+
export function getStatic(reifiedType, symbol) {
|
|
664
758
|
return undefined; // TODO(bps, #780)
|
|
665
759
|
}
|
|
666
760
|
|
|
@@ -679,116 +773,197 @@ export {
|
|
|
679
773
|
// Export runtime value type checks used for safe casting
|
|
680
774
|
|
|
681
775
|
export function requireIsArray(x) {
|
|
682
|
-
if (!isArray) {
|
|
776
|
+
if (!isArray(x)) {
|
|
777
|
+
throw noResultException;
|
|
778
|
+
}
|
|
683
779
|
return x;
|
|
684
780
|
}
|
|
685
781
|
|
|
686
782
|
export function requireInstanceOf(x, typeRequirement) {
|
|
687
|
-
if (!(x instanceof typeRequirement)) {
|
|
783
|
+
if (!(x instanceof typeRequirement)) {
|
|
784
|
+
throw noResultException;
|
|
785
|
+
}
|
|
688
786
|
return x;
|
|
689
787
|
}
|
|
690
788
|
|
|
691
789
|
export function requireIsSafeInteger(x) {
|
|
692
|
-
if (!isSafeInteger(x)) {
|
|
790
|
+
if (!isSafeInteger(x)) {
|
|
791
|
+
throw noResultException;
|
|
792
|
+
}
|
|
693
793
|
return x;
|
|
694
794
|
}
|
|
695
795
|
|
|
696
796
|
export function requireSame(x, y) {
|
|
697
|
-
if (x !== y) {
|
|
797
|
+
if (x !== y) {
|
|
798
|
+
throw noResultException;
|
|
799
|
+
}
|
|
698
800
|
return x;
|
|
699
801
|
}
|
|
700
802
|
|
|
701
803
|
export function requireTypeOf(x, typeOfString) {
|
|
702
|
-
if (typeof x !== typeOfString) {
|
|
804
|
+
if (typeof x !== typeOfString) {
|
|
805
|
+
throw noResultException;
|
|
806
|
+
}
|
|
703
807
|
return x;
|
|
704
808
|
}
|
|
705
809
|
|
|
706
810
|
// When we need a reference to builtin that normally we inline
|
|
707
|
-
export function bitwiseAnd(a, b) {
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
export function
|
|
811
|
+
export function bitwiseAnd(a, b) {
|
|
812
|
+
return a & b;
|
|
813
|
+
}
|
|
814
|
+
export function bitwiseOr(a, b) {
|
|
815
|
+
return a | b;
|
|
816
|
+
}
|
|
817
|
+
export function booleanNegation(b) {
|
|
818
|
+
return !b;
|
|
819
|
+
}
|
|
820
|
+
export function divDubDub(x, y) {
|
|
821
|
+
return x / y;
|
|
822
|
+
}
|
|
711
823
|
export function divIntInt(x, y) {
|
|
712
824
|
const result = trunc(x / y);
|
|
713
|
-
if (!isSafeInteger(result)) {
|
|
825
|
+
if (!isSafeInteger(result)) {
|
|
826
|
+
throw noResultException;
|
|
827
|
+
}
|
|
714
828
|
/* not NaN or infinite */
|
|
715
829
|
return result;
|
|
716
830
|
}
|
|
717
|
-
export function
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
export function
|
|
726
|
-
|
|
831
|
+
export function modIntInt(x, y) {
|
|
832
|
+
const result = trunc(x % y);
|
|
833
|
+
if (!isSafeInteger(result)) {
|
|
834
|
+
throw noResultException;
|
|
835
|
+
}
|
|
836
|
+
/* not NaN or infinite */
|
|
837
|
+
return result;
|
|
838
|
+
}
|
|
839
|
+
export function minusDub(x) {
|
|
840
|
+
return -x;
|
|
841
|
+
}
|
|
842
|
+
export function minusInt(x) {
|
|
843
|
+
return -x;
|
|
844
|
+
}
|
|
845
|
+
export function minusDubDub(x, y) {
|
|
846
|
+
return x - y;
|
|
847
|
+
}
|
|
848
|
+
export function minusIntInt(x, y) {
|
|
849
|
+
return x - y;
|
|
850
|
+
}
|
|
851
|
+
export function plusDub(x) {
|
|
852
|
+
return +x;
|
|
853
|
+
}
|
|
854
|
+
export function plusInt(x) {
|
|
855
|
+
return +x;
|
|
856
|
+
}
|
|
857
|
+
export function plusDubDub(x, y) {
|
|
858
|
+
return x + y;
|
|
859
|
+
}
|
|
860
|
+
export function plusIntInt(x, y) {
|
|
861
|
+
return x + y;
|
|
862
|
+
}
|
|
863
|
+
export function timesDubDub(x, y) {
|
|
864
|
+
return x * y;
|
|
865
|
+
}
|
|
866
|
+
export function timesIntInt(x, y) {
|
|
867
|
+
return x * y;
|
|
868
|
+
}
|
|
727
869
|
export function strCat(...args) {
|
|
728
|
-
let s =
|
|
870
|
+
let s = "";
|
|
729
871
|
for (let arg of args) {
|
|
730
872
|
s += String(arg); // Does not throw on Symbols
|
|
731
873
|
}
|
|
732
|
-
return s
|
|
874
|
+
return s;
|
|
733
875
|
}
|
|
734
|
-
export function listify(...args) {
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
throw noResultException;
|
|
876
|
+
export function listify(...args) {
|
|
877
|
+
return freeze(args);
|
|
878
|
+
}
|
|
879
|
+
export function cmpGeneric(a, b) {
|
|
880
|
+
if (typeof a === "string" && typeof b === "string") {
|
|
881
|
+
if (Object.is(a, b)) {
|
|
882
|
+
return 0;
|
|
742
883
|
}
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
if (d) { break; }
|
|
753
|
-
i += ca < 0x10000 ? 1 : 2;
|
|
754
|
-
}
|
|
755
|
-
if (!d) {
|
|
756
|
-
d = aLen - bLen;
|
|
757
|
-
}
|
|
758
|
-
} else {
|
|
759
|
-
d = (a < b) ? -1 : 1;
|
|
884
|
+
const aLen = a.length;
|
|
885
|
+
const bLen = b.length;
|
|
886
|
+
const minLen = aLen < bLen ? aLen : bLen;
|
|
887
|
+
for (let i = 0; i < minLen; ) {
|
|
888
|
+
const ca = a.codePointAt(i);
|
|
889
|
+
const cb = b.codePointAt(i);
|
|
890
|
+
const d = ca - cb;
|
|
891
|
+
if (d !== 0) {
|
|
892
|
+
return d;
|
|
760
893
|
}
|
|
761
|
-
|
|
894
|
+
i += ca < 0x10000 ? 1 : 2;
|
|
895
|
+
}
|
|
896
|
+
return aLen - bLen;
|
|
897
|
+
}
|
|
898
|
+
if (typeof a === "number" && typeof b === "number") {
|
|
899
|
+
if (Object.is(a, b)) {
|
|
900
|
+
return 0;
|
|
762
901
|
}
|
|
763
|
-
if (
|
|
764
|
-
|
|
765
|
-
return genericCmp(1/a, 1/b);
|
|
902
|
+
if (a === b) {
|
|
903
|
+
return Object.is(a, 0) - Object.is(b, 0);
|
|
766
904
|
}
|
|
767
|
-
return
|
|
768
|
-
}
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
return
|
|
777
|
-
}
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
}
|
|
787
|
-
|
|
905
|
+
return a - b;
|
|
906
|
+
}
|
|
907
|
+
if (typeof a === "boolean" && typeof b === "boolean") {
|
|
908
|
+
return a - b;
|
|
909
|
+
}
|
|
910
|
+
throw noResultException;
|
|
911
|
+
};
|
|
912
|
+
export function ltGeneric(a, b) {
|
|
913
|
+
if (typeof a === "number" && typeof b === "number") {
|
|
914
|
+
return a < b || (a === 0 && b === 0 && Object.is(a, 0) < Object.is(b, 0));
|
|
915
|
+
}
|
|
916
|
+
if (typeof a == "boolean" && typeof b === "boolean") {
|
|
917
|
+
return a < b;
|
|
918
|
+
}
|
|
919
|
+
return cmpGeneric(a, b) < 0;
|
|
920
|
+
}
|
|
921
|
+
export function leGeneric(a, b) {
|
|
922
|
+
if (typeof a === "number" && typeof b === "number") {
|
|
923
|
+
return a <= b && (a !== 0 || b !== 0 || Object.is(a, 0) <= Object.is(b, 0));
|
|
924
|
+
}
|
|
925
|
+
if (typeof a == "boolean" && typeof b === "boolean") {
|
|
926
|
+
return a <= b;
|
|
927
|
+
}
|
|
928
|
+
return cmpGeneric(a, b) <= 0;
|
|
929
|
+
}
|
|
930
|
+
export function gtGeneric(a, b) {
|
|
931
|
+
if (typeof a === "number" && typeof b === "number") {
|
|
932
|
+
return a > b || (a === 0 && b === 0 && Object.is(a, 0) > Object.is(b, 0));
|
|
933
|
+
}
|
|
934
|
+
if (typeof a == "boolean" && typeof b === "boolean") {
|
|
935
|
+
return a > b;
|
|
936
|
+
}
|
|
937
|
+
return cmpGeneric(a, b) > 0;
|
|
938
|
+
}
|
|
939
|
+
export function geGeneric(a, b) {
|
|
940
|
+
if (typeof a === "number" && typeof b === "number") {
|
|
941
|
+
return a >= b && (a !== 0 || b !== 0 || Object.is(a, 0) >= Object.is(b, 0));
|
|
942
|
+
}
|
|
943
|
+
if (typeof a == "boolean" && typeof b === "boolean") {
|
|
944
|
+
return a >= b;
|
|
945
|
+
}
|
|
946
|
+
return cmpGeneric(a, b) >= 0;
|
|
947
|
+
}
|
|
948
|
+
export function eqGeneric(a, b) {
|
|
949
|
+
return Object.is(a, b);
|
|
950
|
+
}
|
|
951
|
+
export function neGeneric(a, b) {
|
|
952
|
+
return !Object.is(a, b);
|
|
953
|
+
}
|
|
954
|
+
export function fail() {
|
|
955
|
+
throw noResultException;
|
|
956
|
+
}
|
|
788
957
|
export function print(a) {
|
|
789
958
|
console.log("%s", a);
|
|
790
959
|
return void 0;
|
|
791
960
|
}
|
|
792
961
|
export function nexter(f) {
|
|
793
|
-
return (
|
|
962
|
+
return (
|
|
963
|
+
(generator) => () =>
|
|
964
|
+
generator.next()
|
|
965
|
+
)(f());
|
|
794
966
|
}
|
|
967
|
+
|
|
968
|
+
// We might customize this in the future, but actual global console works today.
|
|
969
|
+
export const globalConsole = console;
|
package/interface-types.js
CHANGED
|
File without changes
|
package/package.json
CHANGED
package/regex.js
CHANGED
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
import {noResultException} from "./index.js";
|
|
2
2
|
|
|
3
|
-
export function
|
|
3
|
+
export function compiledRegexCompiledFound(_, compiled, text) {
|
|
4
4
|
return compiled.test(text);
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
export function compiledRegexCompiledFind(_, compiled, text, regexRefs) {
|
|
8
|
+
return compiledRegexCompiledFindEx(_, compiled, text, regexRefs).groups;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @param {RegExp} compiled
|
|
13
|
+
* @param {string} text
|
|
14
|
+
*/
|
|
15
|
+
function compiledRegexCompiledFindEx(_, compiled, text, regexRefs) {
|
|
8
16
|
const match = compiled.exec(text);
|
|
9
17
|
if (match === null) {
|
|
10
18
|
throw noResultException;
|
|
@@ -24,16 +32,16 @@ export function compiledRegexCompiledFind(_, compiled, text, regexRefs) {
|
|
|
24
32
|
}
|
|
25
33
|
const begins = codePointIndices(text, rawBegins);
|
|
26
34
|
// Form the matches.
|
|
27
|
-
const Group = regexRefs.
|
|
28
|
-
const resultGroups =
|
|
35
|
+
const Group = regexRefs.group.constructor;
|
|
36
|
+
const resultGroups = new Map();
|
|
29
37
|
if (defaultFull) {
|
|
30
|
-
resultGroups.
|
|
38
|
+
resultGroups.set("full", new Group("full", match[0], begins.full));
|
|
31
39
|
}
|
|
32
40
|
for (const entry of Object.entries(groups)) {
|
|
33
41
|
const [name, value] = entry;
|
|
34
|
-
resultGroups.
|
|
42
|
+
resultGroups.set(name, new Group(name, value ?? "", begins[name] ?? -1));
|
|
35
43
|
}
|
|
36
|
-
return
|
|
44
|
+
return { groups: resultGroups, index: match.index, length: match[0].length };
|
|
37
45
|
}
|
|
38
46
|
|
|
39
47
|
function codePointIndices(text, unitNameIndexArray) {
|
|
@@ -55,6 +63,41 @@ function codePointIndices(text, unitNameIndexArray) {
|
|
|
55
63
|
return codeIndices;
|
|
56
64
|
}
|
|
57
65
|
|
|
66
|
+
/**
|
|
67
|
+
* @param {RegExp} compiled
|
|
68
|
+
* @param {string} text
|
|
69
|
+
* @param {(groups: Map<string, any>) => string} format
|
|
70
|
+
* @returns {string}
|
|
71
|
+
*/
|
|
72
|
+
export function compiledRegexCompiledReplace(
|
|
73
|
+
_,
|
|
74
|
+
compiled,
|
|
75
|
+
text,
|
|
76
|
+
format,
|
|
77
|
+
regexRefs
|
|
78
|
+
) {
|
|
79
|
+
// Simple string replace doesn't provide all match group details if we want to
|
|
80
|
+
// make our interface consistent, so we have to do this manually here.
|
|
81
|
+
// The hope is that we can optimize a bunch out when we have compile-time
|
|
82
|
+
// 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
|
+
}
|
|
94
|
+
}
|
|
95
|
+
// Index and length in js space should save some processing.
|
|
96
|
+
const { groups, index, length } = match;
|
|
97
|
+
const content = format(groups);
|
|
98
|
+
return text.slice(0, index) + content + text.slice(index + length);
|
|
99
|
+
}
|
|
100
|
+
|
|
58
101
|
export function compiledRegexCompileFormatted(_, formatted) {
|
|
59
102
|
return new RegExp(formatted, "du"); // d:hasIndices, u:unicode
|
|
60
103
|
}
|