toilscript 0.0.1 → 0.1.1

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 (121) hide show
  1. package/LICENSE +201 -201
  2. package/NOTICE +94 -94
  3. package/README.md +101 -114
  4. package/bin/asc.js +0 -0
  5. package/bin/asinit.js +6 -6
  6. package/dist/asc.generated.d.ts +10027 -0
  7. package/dist/asc.js +24474 -0
  8. package/dist/asc.js.map +7 -0
  9. package/dist/importmap.json +9 -0
  10. package/dist/toilscript.generated.d.ts +11242 -0
  11. package/dist/toilscript.js +337 -0
  12. package/dist/toilscript.js.map +7 -0
  13. package/dist/web.js +22 -0
  14. package/lib/binaryen.d.ts +2 -2
  15. package/lib/binaryen.js +2 -2
  16. package/package.json +115 -114
  17. package/std/README.md +6 -6
  18. package/std/assembly/array.ts +550 -550
  19. package/std/assembly/arraybuffer.ts +77 -77
  20. package/std/assembly/atomics.ts +127 -127
  21. package/std/assembly/bindings/asyncify.ts +16 -16
  22. package/std/assembly/bindings/dom.ts +291 -291
  23. package/std/assembly/bindings/node.ts +6 -6
  24. package/std/assembly/bitflags.ts +53 -53
  25. package/std/assembly/builtins.ts +2650 -2650
  26. package/std/assembly/byteslice.ts +177 -177
  27. package/std/assembly/compat.ts +2 -2
  28. package/std/assembly/console.ts +42 -42
  29. package/std/assembly/crypto.ts +9 -9
  30. package/std/assembly/dataview.ts +181 -181
  31. package/std/assembly/date.ts +375 -375
  32. package/std/assembly/diagnostics.ts +11 -11
  33. package/std/assembly/encoding.ts +151 -151
  34. package/std/assembly/endian.ts +45 -45
  35. package/std/assembly/error.ts +44 -44
  36. package/std/assembly/fixedarray.ts +173 -173
  37. package/std/assembly/fixedmap.ts +326 -326
  38. package/std/assembly/fixedset.ts +275 -275
  39. package/std/assembly/function.ts +42 -42
  40. package/std/assembly/index.d.ts +2892 -2891
  41. package/std/assembly/iterator.ts +35 -35
  42. package/std/assembly/map.ts +269 -269
  43. package/std/assembly/math.ts +3289 -3289
  44. package/std/assembly/memory.ts +123 -123
  45. package/std/assembly/number.ts +388 -388
  46. package/std/assembly/object.ts +36 -36
  47. package/std/assembly/performance.ts +9 -9
  48. package/std/assembly/pointer.ts +80 -80
  49. package/std/assembly/polyfills.ts +27 -27
  50. package/std/assembly/process.ts +50 -50
  51. package/std/assembly/reference.ts +48 -48
  52. package/std/assembly/regexp.ts +12 -12
  53. package/std/assembly/rt/README.md +83 -83
  54. package/std/assembly/rt/common.ts +81 -81
  55. package/std/assembly/rt/index-incremental.ts +2 -2
  56. package/std/assembly/rt/index-memory.ts +1 -1
  57. package/std/assembly/rt/index-minimal.ts +2 -2
  58. package/std/assembly/rt/index-stub.ts +1 -1
  59. package/std/assembly/rt/index.d.ts +37 -37
  60. package/std/assembly/rt/itcms.ts +419 -419
  61. package/std/assembly/rt/memory-runtime.ts +94 -94
  62. package/std/assembly/rt/rtrace.ts +15 -15
  63. package/std/assembly/rt/stub.ts +133 -133
  64. package/std/assembly/rt/tcms.ts +254 -254
  65. package/std/assembly/rt/tlsf.ts +592 -592
  66. package/std/assembly/rt.ts +90 -90
  67. package/std/assembly/set.ts +225 -225
  68. package/std/assembly/shared/feature.ts +68 -68
  69. package/std/assembly/shared/runtime.ts +13 -13
  70. package/std/assembly/shared/target.ts +11 -11
  71. package/std/assembly/shared/tsconfig.json +11 -11
  72. package/std/assembly/shared/typeinfo.ts +72 -72
  73. package/std/assembly/staticarray.ts +423 -423
  74. package/std/assembly/string.ts +850 -850
  75. package/std/assembly/symbol.ts +114 -114
  76. package/std/assembly/table.ts +16 -16
  77. package/std/assembly/toilscript.ts +16 -0
  78. package/std/assembly/tsconfig.json +6 -6
  79. package/std/assembly/typedarray.ts +1954 -1954
  80. package/std/assembly/uri.ts +17 -17
  81. package/std/assembly/util/bytes.ts +107 -107
  82. package/std/assembly/util/casemap.ts +497 -497
  83. package/std/assembly/util/error.ts +58 -58
  84. package/std/assembly/util/hash.ts +117 -117
  85. package/std/assembly/util/math.ts +1922 -1922
  86. package/std/assembly/util/memory.ts +290 -290
  87. package/std/assembly/util/number.ts +873 -873
  88. package/std/assembly/util/sort.ts +313 -313
  89. package/std/assembly/util/string.ts +1202 -1202
  90. package/std/assembly/util/uri.ts +275 -275
  91. package/std/assembly/vector.ts +4 -4
  92. package/std/assembly.json +16 -16
  93. package/std/portable/index.d.ts +461 -461
  94. package/std/portable/index.js +416 -416
  95. package/std/portable.json +11 -11
  96. package/std/types/assembly/index.d.ts +1 -1
  97. package/std/types/assembly/package.json +2 -2
  98. package/std/types/portable/index.d.ts +1 -1
  99. package/std/types/portable/package.json +2 -2
  100. package/tsconfig-base.json +13 -13
  101. package/util/README.md +23 -23
  102. package/util/browser/fs.js +1 -1
  103. package/util/browser/module.js +5 -5
  104. package/util/browser/path.js +520 -520
  105. package/util/browser/process.js +59 -59
  106. package/util/browser/url.js +23 -23
  107. package/util/cpu.d.ts +9 -9
  108. package/util/cpu.js +42 -42
  109. package/util/find.d.ts +6 -6
  110. package/util/find.js +20 -20
  111. package/util/node.d.ts +21 -21
  112. package/util/node.js +34 -34
  113. package/util/options.d.ts +70 -70
  114. package/util/options.js +262 -262
  115. package/util/terminal.d.ts +52 -52
  116. package/util/terminal.js +35 -35
  117. package/util/text.d.ts +26 -26
  118. package/util/text.js +114 -114
  119. package/util/tsconfig.json +9 -9
  120. package/util/web.d.ts +11 -11
  121. package/util/web.js +33 -33
@@ -1,375 +1,375 @@
1
- import { E_INVALIDDATE } from "util/error";
2
- import { Date as Date_binding } from "./bindings/dom";
3
-
4
- // @ts-ignore: decorator
5
- @inline const
6
- MILLIS_PER_DAY = 1000 * 60 * 60 * 24,
7
- MILLIS_PER_HOUR = 1000 * 60 * 60,
8
- MILLIS_PER_MINUTE = 1000 * 60,
9
- MILLIS_PER_SECOND = 1000,
10
-
11
- YEARS_PER_EPOCH = 400,
12
- DAYS_PER_EPOCH = 146097,
13
- EPOCH_OFFSET = 719468, // Jan 1, 1970
14
- MILLIS_LIMIT = 8640000000000000;
15
-
16
- // ymdFromEpochDays returns values via globals to avoid allocations
17
- // @ts-ignore: decorator
18
- @lazy let _month: i32, _day: i32;
19
-
20
- export class Date {
21
- private year: i32 = 0;
22
- private month: i32 = 0;
23
- private day: i32 = 0;
24
-
25
- @inline static UTC(
26
- year: i32,
27
- month: i32 = 0,
28
- day: i32 = 1,
29
- hour: i32 = 0,
30
- minute: i32 = 0,
31
- second: i32 = 0,
32
- millisecond: i32 = 0
33
- ): i64 {
34
- if (year >= 0 && year <= 99) year += 1900;
35
- let ms = epochMillis(year, month + 1, day, hour, minute, second, millisecond);
36
- if (invalidDate(ms)) throw new RangeError(E_INVALIDDATE);
37
- return ms;
38
- }
39
-
40
- @inline static now(): i64 {
41
- return <i64>Date_binding.now();
42
- }
43
-
44
- // It can parse only ISO 8601 inputs like YYYY-MM-DDTHH:MM:SS.000Z
45
- @inline static parse(dateString: string): Date {
46
- return this.fromString(dateString);
47
- }
48
-
49
- static fromString(dateTimeString: string): Date {
50
- if (!dateTimeString.length) throw new RangeError(E_INVALIDDATE);
51
- var
52
- hour: i32 = 0,
53
- min: i32 = 0,
54
- sec: i32 = 0,
55
- ms: i32 = 0,
56
- offsetMs: i32 = 0;
57
-
58
- let dateString = dateTimeString;
59
- let posT = dateTimeString.indexOf("T");
60
- if (~posT) {
61
- // includes a time component
62
- let timeString: string;
63
- dateString = dateTimeString.substring(0, posT);
64
- timeString = dateTimeString.substring(posT + 1);
65
-
66
- // might end with an offset ("Z", "+05:30", "-08:00", etc.)
67
- for (let i = timeString.length - 1; i >= 0; i--) {
68
- let c = timeString.charCodeAt(i);
69
- if (c == 90) { // Z
70
- timeString = timeString.substring(0, i);
71
- break;
72
- } else if (c == 43 || c == 45) { // + or -
73
- if (i == timeString.length - 1) {
74
- throw new RangeError(E_INVALIDDATE);
75
- }
76
-
77
- let posColon = timeString.indexOf(":", i + 1);
78
- if (~posColon) {
79
- let offsetHours = i32.parse(timeString.substring(i + 1, posColon));
80
- let offsetMinutes = i32.parse(timeString.substring(posColon + 1));
81
- offsetMs = (offsetHours * 60 + offsetMinutes) * MILLIS_PER_MINUTE;
82
- } else {
83
- let offsetHours = i32.parse(timeString.substring(i + 1));
84
- offsetMs = offsetHours * MILLIS_PER_HOUR;
85
- }
86
-
87
- if (c == 45) offsetMs = -offsetMs; // negative offset
88
- timeString = timeString.substring(0, i);
89
- break;
90
- }
91
- }
92
-
93
- // parse the HH:MM:SS component
94
- let timeParts = timeString.split(":");
95
- let len = timeParts.length;
96
- if (len <= 1) throw new RangeError(E_INVALIDDATE);
97
-
98
- hour = i32.parse(timeParts[0]);
99
- min = i32.parse(timeParts[1]);
100
- if (len >= 3) {
101
- let secAndFrac = timeParts[2];
102
- let posDot = secAndFrac.indexOf(".");
103
- if (~posDot) {
104
- // includes fractional seconds (truncate to milliseconds)
105
- sec = i32.parse(secAndFrac.substring(0, posDot));
106
- ms = i32.parse(secAndFrac.substr(posDot + 1, 3).padEnd(3, "0"));
107
- } else {
108
- sec = i32.parse(secAndFrac);
109
- }
110
- }
111
- }
112
-
113
- // parse the YYYY-MM-DD component
114
- let parts = dateString.split("-");
115
- let year = i32.parse(parts[0]);
116
- let month = 1, day = 1;
117
- let len = parts.length;
118
- if (len >= 2) {
119
- month = i32.parse(parts[1]);
120
- if (len >= 3) {
121
- day = i32.parse(parts[2]);
122
- }
123
- }
124
-
125
- return new Date(epochMillis(year, month, day, hour, min, sec, ms) - offsetMs);
126
- }
127
-
128
- constructor(private epochMillis: i64) {
129
- // this differs from JavaScript which prefer return NaN or "Invalid Date" string
130
- // instead throwing exception.
131
- if (invalidDate(epochMillis)) throw new RangeError(E_INVALIDDATE);
132
-
133
- this.year = dateFromEpoch(epochMillis);
134
- this.month = _month;
135
- this.day = _day;
136
- }
137
-
138
- @inline getTime(): i64 {
139
- return this.epochMillis;
140
- }
141
-
142
- setTime(time: i64): i64 {
143
- if (invalidDate(time)) throw new RangeError(E_INVALIDDATE);
144
-
145
- this.epochMillis = time;
146
- this.year = dateFromEpoch(time);
147
- this.month = _month;
148
- this.day = _day;
149
-
150
- return time;
151
- }
152
-
153
- @inline getUTCFullYear(): i32 {
154
- return this.year;
155
- }
156
-
157
- @inline getUTCMonth(): i32 {
158
- return this.month - 1;
159
- }
160
-
161
- @inline getUTCDate(): i32 {
162
- return this.day;
163
- }
164
-
165
- @inline getUTCDay(): i32 {
166
- return dayOfWeek(this.year, this.month, this.day);
167
- }
168
-
169
- getUTCHours(): i32 {
170
- return i32(euclidRem(this.epochMillis, MILLIS_PER_DAY)) / MILLIS_PER_HOUR;
171
- }
172
-
173
- getUTCMinutes(): i32 {
174
- return i32(euclidRem(this.epochMillis, MILLIS_PER_HOUR)) / MILLIS_PER_MINUTE;
175
- }
176
-
177
- getUTCSeconds(): i32 {
178
- return i32(euclidRem(this.epochMillis, MILLIS_PER_MINUTE)) / MILLIS_PER_SECOND;
179
- }
180
-
181
- getUTCMilliseconds(): i32 {
182
- return i32(euclidRem(this.epochMillis, MILLIS_PER_SECOND));
183
- }
184
-
185
- setUTCMilliseconds(millis: i32): void {
186
- this.setTime(this.epochMillis + (millis - this.getUTCMilliseconds()));
187
- }
188
-
189
- setUTCSeconds(seconds: i32): void {
190
- this.setTime(this.epochMillis + (seconds - this.getUTCSeconds()) * MILLIS_PER_SECOND);
191
- }
192
-
193
- setUTCMinutes(minutes: i32): void {
194
- this.setTime(this.epochMillis + (minutes - this.getUTCMinutes()) * MILLIS_PER_MINUTE);
195
- }
196
-
197
- setUTCHours(hours: i32): void {
198
- this.setTime(this.epochMillis + (hours - this.getUTCHours()) * MILLIS_PER_HOUR);
199
- }
200
-
201
- setUTCDate(day: i32): void {
202
- if (this.day == day) return;
203
- this.setTime(join(this.year, this.month, day, this.epochMillis));
204
- }
205
-
206
- setUTCMonth(month: i32, day: i32 = this.day): void {
207
- if (this.month == month + 1) return;
208
- this.setTime(join(this.year, month + 1, day, this.epochMillis));
209
- }
210
-
211
- setUTCFullYear(year: i32): void {
212
- if (this.year == year) return;
213
- this.setTime(join(year, this.month, this.day, this.epochMillis));
214
- }
215
-
216
- toISOString(): string {
217
- // TODO: add more low-level helper which combine toString and padStart without extra allocation
218
-
219
- let yr = this.year;
220
- let isNeg = yr < 0;
221
- let year = (isNeg || yr >= 10000)
222
- ? (isNeg ? "-" : "+") + stringify(abs(yr), 6)
223
- : stringify(yr, 4);
224
- let month = stringify(this.month, 2);
225
- let day = stringify(this.day);
226
- let hours = stringify(this.getUTCHours());
227
- let mins = stringify(this.getUTCMinutes());
228
- let secs = stringify(this.getUTCSeconds());
229
- let ms = stringify(this.getUTCMilliseconds(), 3);
230
-
231
- return `${year}-${month}-${day}T${hours}:${mins}:${secs}.${ms}Z`;
232
- }
233
-
234
- toUTCString(): string {
235
- const
236
- weeks: StaticArray<string> = [
237
- "Sun, ", "Mon, ", "Tue, ", "Wed, ", "Thu, ", "Fri, ", "Sat, "
238
- ],
239
- months: StaticArray<string> = [
240
- " Jan ", " Feb ", " Mar ", " Apr ", " May ", " Jun ",
241
- " Jul ", " Aug ", " Sep ", " Oct ", " Nov ", " Dec "
242
- ];
243
-
244
- let mo = this.month;
245
- let da = this.day;
246
- let yr = this.year;
247
- let wd = dayOfWeek(yr, mo, da);
248
- let year = stringify(abs(yr), 4);
249
- let month = unchecked(months[mo - 1]);
250
- let week = unchecked(weeks[wd]);
251
- let day = stringify(da);
252
- let hours = stringify(this.getUTCHours());
253
- let mins = stringify(this.getUTCMinutes());
254
- let secs = stringify(this.getUTCSeconds());
255
-
256
- return `${week}${day}${month}${yr < 0 ? "-" : ""}${year} ${hours}:${mins}:${secs} GMT`;
257
- }
258
-
259
- toDateString(): string {
260
- // TODO: use u64 static data instead 4 chars
261
- // also use stream itoa variants.
262
- const
263
- weeks: StaticArray<string> = [
264
- "Sun ", "Mon ", "Tue ", "Wed ", "Thu ", "Fri ", "Sat "
265
- ],
266
- months: StaticArray<string> = [
267
- "Jan ", "Feb ", "Mar ", "Apr ", "May ", "Jun ",
268
- "Jul ", "Aug ", "Sep ", "Oct ", "Nov ", "Dec "
269
- ];
270
-
271
- let mo = this.month;
272
- let da = this.day;
273
- let yr = this.year;
274
- let wd = dayOfWeek(yr, mo, da);
275
- let year = stringify(abs(yr), 4);
276
- let month = unchecked(months[mo - 1]);
277
- let week = unchecked(weeks[wd]);
278
- let day = stringify(da);
279
-
280
- return `${week}${month}${day}${yr < 0 ? " -" : " "}${year}`;
281
- }
282
-
283
- // Note: it uses UTC time instead local time (without timezone offset)
284
- toTimeString(): string {
285
- let hours = stringify(this.getUTCHours());
286
- let mins = stringify(this.getUTCMinutes());
287
- let secs = stringify(this.getUTCSeconds());
288
- // TODO: add timezone
289
- return `${hours}:${mins}:${secs}`;
290
- }
291
-
292
- // Note: it uses UTC datetime instead local datetime (without timezone offset)
293
- toString(): string {
294
- return `${this.toDateString()} ${this.toTimeString()}`;
295
- }
296
- }
297
-
298
- function epochMillis(
299
- year: i32,
300
- month: i32,
301
- day: i32,
302
- hour: i32,
303
- minute: i32,
304
- second: i32,
305
- milliseconds: i32
306
- ): i64 {
307
- return (
308
- daysSinceEpoch(year, month, day) * MILLIS_PER_DAY +
309
- hour * MILLIS_PER_HOUR +
310
- minute * MILLIS_PER_MINUTE +
311
- second * MILLIS_PER_SECOND +
312
- milliseconds
313
- );
314
- }
315
-
316
- // @ts-ignore: decorator
317
- @inline function floorDiv<T extends number>(a: T, b: T): T {
318
- return (a - (a < 0 ? b - 1 : 0)) / b as T;
319
- }
320
-
321
- // @ts-ignore: decorator
322
- @inline function euclidRem<T extends number>(a: T, b: T): T {
323
- let m = a % b;
324
- return m + (m < 0 ? b : 0) as T;
325
- }
326
-
327
- function invalidDate(millis: i64): bool {
328
- // @ts-ignore
329
- return (millis < -MILLIS_LIMIT) | (millis > MILLIS_LIMIT);
330
- }
331
-
332
- // Based on "Euclidean Affine Functions and Applications to Calendar Algorithms"
333
- // Paper: https://arxiv.org/pdf/2102.06959.pdf
334
- function dateFromEpoch(ms: i64): i32 {
335
- let da = (<i32>floorDiv(ms, MILLIS_PER_DAY) * 4 + EPOCH_OFFSET * 4) | 3;
336
- let q0 = floorDiv(da, DAYS_PER_EPOCH); // [0, 146096]
337
- let r1 = <u32>da - q0 * DAYS_PER_EPOCH;
338
- let u1 = u64(r1 | 3) * 2939745;
339
- let dm1 = <u32>u1 / 11758980;
340
- let n1 = 2141 * dm1 + 197913;
341
- let year = 100 * q0 + i32(u1 >>> 32);
342
- let mo = n1 >>> 16;
343
- _day = (n1 & 0xFFFF) / 2141 + 1; // [1, 31]
344
- if (dm1 >= 306) { mo -= 12; ++year; }
345
- _month = mo; // [1, 12]
346
- return year;
347
- }
348
-
349
- // http://howardhinnant.github.io/date_algorithms.html#days_from_civil
350
- function daysSinceEpoch(y: i32, m: i32, d: i32): i64 {
351
- y -= i32(m <= 2);
352
- let era = <u32>floorDiv(y, YEARS_PER_EPOCH);
353
- let yoe = <u32>y - era * YEARS_PER_EPOCH; // [0, 399]
354
- let doy = <u32>(153 * (m + (m > 2 ? -3 : 9)) + 2) / 5 + d - 1; // [0, 365]
355
- let doe = yoe * 365 + yoe / 4 - yoe / 100 + doy; // [0, 146096]
356
- return <i64><i32>(era * 146097 + doe - EPOCH_OFFSET);
357
- }
358
-
359
- // TomohikoSakamoto algorithm from https://en.wikipedia.org/wiki/Determination_of_the_day_of_the_week
360
- function dayOfWeek(year: i32, month: i32, day: i32): i32 {
361
- const tab = memory.data<u8>([0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4]);
362
-
363
- year -= i32(month < 3);
364
- year += floorDiv(year, 4) - floorDiv(year, 100) + floorDiv(year, YEARS_PER_EPOCH);
365
- month = <i32>load<u8>(tab + month - 1);
366
- return euclidRem(year + month + day, 7);
367
- }
368
-
369
- function stringify(value: i32, padding: i32 = 2): string {
370
- return value.toString().padStart(padding, "0");
371
- }
372
-
373
- function join(year: i32, month: i32, day: i32, ms: i64): i64 {
374
- return daysSinceEpoch(year, month, day) * MILLIS_PER_DAY + euclidRem(ms, MILLIS_PER_DAY);
375
- }
1
+ import { E_INVALIDDATE } from "util/error";
2
+ import { Date as Date_binding } from "./bindings/dom";
3
+
4
+ // @ts-ignore: decorator
5
+ @inline const
6
+ MILLIS_PER_DAY = 1000 * 60 * 60 * 24,
7
+ MILLIS_PER_HOUR = 1000 * 60 * 60,
8
+ MILLIS_PER_MINUTE = 1000 * 60,
9
+ MILLIS_PER_SECOND = 1000,
10
+
11
+ YEARS_PER_EPOCH = 400,
12
+ DAYS_PER_EPOCH = 146097,
13
+ EPOCH_OFFSET = 719468, // Jan 1, 1970
14
+ MILLIS_LIMIT = 8640000000000000;
15
+
16
+ // ymdFromEpochDays returns values via globals to avoid allocations
17
+ // @ts-ignore: decorator
18
+ @lazy let _month: i32, _day: i32;
19
+
20
+ export class Date {
21
+ private year: i32 = 0;
22
+ private month: i32 = 0;
23
+ private day: i32 = 0;
24
+
25
+ @inline static UTC(
26
+ year: i32,
27
+ month: i32 = 0,
28
+ day: i32 = 1,
29
+ hour: i32 = 0,
30
+ minute: i32 = 0,
31
+ second: i32 = 0,
32
+ millisecond: i32 = 0
33
+ ): i64 {
34
+ if (year >= 0 && year <= 99) year += 1900;
35
+ let ms = epochMillis(year, month + 1, day, hour, minute, second, millisecond);
36
+ if (invalidDate(ms)) throw new RangeError(E_INVALIDDATE);
37
+ return ms;
38
+ }
39
+
40
+ @inline static now(): i64 {
41
+ return <i64>Date_binding.now();
42
+ }
43
+
44
+ // It can parse only ISO 8601 inputs like YYYY-MM-DDTHH:MM:SS.000Z
45
+ @inline static parse(dateString: string): Date {
46
+ return this.fromString(dateString);
47
+ }
48
+
49
+ static fromString(dateTimeString: string): Date {
50
+ if (!dateTimeString.length) throw new RangeError(E_INVALIDDATE);
51
+ var
52
+ hour: i32 = 0,
53
+ min: i32 = 0,
54
+ sec: i32 = 0,
55
+ ms: i32 = 0,
56
+ offsetMs: i32 = 0;
57
+
58
+ let dateString = dateTimeString;
59
+ let posT = dateTimeString.indexOf("T");
60
+ if (~posT) {
61
+ // includes a time component
62
+ let timeString: string;
63
+ dateString = dateTimeString.substring(0, posT);
64
+ timeString = dateTimeString.substring(posT + 1);
65
+
66
+ // might end with an offset ("Z", "+05:30", "-08:00", etc.)
67
+ for (let i = timeString.length - 1; i >= 0; i--) {
68
+ let c = timeString.charCodeAt(i);
69
+ if (c == 90) { // Z
70
+ timeString = timeString.substring(0, i);
71
+ break;
72
+ } else if (c == 43 || c == 45) { // + or -
73
+ if (i == timeString.length - 1) {
74
+ throw new RangeError(E_INVALIDDATE);
75
+ }
76
+
77
+ let posColon = timeString.indexOf(":", i + 1);
78
+ if (~posColon) {
79
+ let offsetHours = i32.parse(timeString.substring(i + 1, posColon));
80
+ let offsetMinutes = i32.parse(timeString.substring(posColon + 1));
81
+ offsetMs = (offsetHours * 60 + offsetMinutes) * MILLIS_PER_MINUTE;
82
+ } else {
83
+ let offsetHours = i32.parse(timeString.substring(i + 1));
84
+ offsetMs = offsetHours * MILLIS_PER_HOUR;
85
+ }
86
+
87
+ if (c == 45) offsetMs = -offsetMs; // negative offset
88
+ timeString = timeString.substring(0, i);
89
+ break;
90
+ }
91
+ }
92
+
93
+ // parse the HH:MM:SS component
94
+ let timeParts = timeString.split(":");
95
+ let len = timeParts.length;
96
+ if (len <= 1) throw new RangeError(E_INVALIDDATE);
97
+
98
+ hour = i32.parse(timeParts[0]);
99
+ min = i32.parse(timeParts[1]);
100
+ if (len >= 3) {
101
+ let secAndFrac = timeParts[2];
102
+ let posDot = secAndFrac.indexOf(".");
103
+ if (~posDot) {
104
+ // includes fractional seconds (truncate to milliseconds)
105
+ sec = i32.parse(secAndFrac.substring(0, posDot));
106
+ ms = i32.parse(secAndFrac.substr(posDot + 1, 3).padEnd(3, "0"));
107
+ } else {
108
+ sec = i32.parse(secAndFrac);
109
+ }
110
+ }
111
+ }
112
+
113
+ // parse the YYYY-MM-DD component
114
+ let parts = dateString.split("-");
115
+ let year = i32.parse(parts[0]);
116
+ let month = 1, day = 1;
117
+ let len = parts.length;
118
+ if (len >= 2) {
119
+ month = i32.parse(parts[1]);
120
+ if (len >= 3) {
121
+ day = i32.parse(parts[2]);
122
+ }
123
+ }
124
+
125
+ return new Date(epochMillis(year, month, day, hour, min, sec, ms) - offsetMs);
126
+ }
127
+
128
+ constructor(private epochMillis: i64) {
129
+ // this differs from JavaScript which prefer return NaN or "Invalid Date" string
130
+ // instead throwing exception.
131
+ if (invalidDate(epochMillis)) throw new RangeError(E_INVALIDDATE);
132
+
133
+ this.year = dateFromEpoch(epochMillis);
134
+ this.month = _month;
135
+ this.day = _day;
136
+ }
137
+
138
+ @inline getTime(): i64 {
139
+ return this.epochMillis;
140
+ }
141
+
142
+ setTime(time: i64): i64 {
143
+ if (invalidDate(time)) throw new RangeError(E_INVALIDDATE);
144
+
145
+ this.epochMillis = time;
146
+ this.year = dateFromEpoch(time);
147
+ this.month = _month;
148
+ this.day = _day;
149
+
150
+ return time;
151
+ }
152
+
153
+ @inline getUTCFullYear(): i32 {
154
+ return this.year;
155
+ }
156
+
157
+ @inline getUTCMonth(): i32 {
158
+ return this.month - 1;
159
+ }
160
+
161
+ @inline getUTCDate(): i32 {
162
+ return this.day;
163
+ }
164
+
165
+ @inline getUTCDay(): i32 {
166
+ return dayOfWeek(this.year, this.month, this.day);
167
+ }
168
+
169
+ getUTCHours(): i32 {
170
+ return i32(euclidRem(this.epochMillis, MILLIS_PER_DAY)) / MILLIS_PER_HOUR;
171
+ }
172
+
173
+ getUTCMinutes(): i32 {
174
+ return i32(euclidRem(this.epochMillis, MILLIS_PER_HOUR)) / MILLIS_PER_MINUTE;
175
+ }
176
+
177
+ getUTCSeconds(): i32 {
178
+ return i32(euclidRem(this.epochMillis, MILLIS_PER_MINUTE)) / MILLIS_PER_SECOND;
179
+ }
180
+
181
+ getUTCMilliseconds(): i32 {
182
+ return i32(euclidRem(this.epochMillis, MILLIS_PER_SECOND));
183
+ }
184
+
185
+ setUTCMilliseconds(millis: i32): void {
186
+ this.setTime(this.epochMillis + (millis - this.getUTCMilliseconds()));
187
+ }
188
+
189
+ setUTCSeconds(seconds: i32): void {
190
+ this.setTime(this.epochMillis + (seconds - this.getUTCSeconds()) * MILLIS_PER_SECOND);
191
+ }
192
+
193
+ setUTCMinutes(minutes: i32): void {
194
+ this.setTime(this.epochMillis + (minutes - this.getUTCMinutes()) * MILLIS_PER_MINUTE);
195
+ }
196
+
197
+ setUTCHours(hours: i32): void {
198
+ this.setTime(this.epochMillis + (hours - this.getUTCHours()) * MILLIS_PER_HOUR);
199
+ }
200
+
201
+ setUTCDate(day: i32): void {
202
+ if (this.day == day) return;
203
+ this.setTime(join(this.year, this.month, day, this.epochMillis));
204
+ }
205
+
206
+ setUTCMonth(month: i32, day: i32 = this.day): void {
207
+ if (this.month == month + 1) return;
208
+ this.setTime(join(this.year, month + 1, day, this.epochMillis));
209
+ }
210
+
211
+ setUTCFullYear(year: i32): void {
212
+ if (this.year == year) return;
213
+ this.setTime(join(year, this.month, this.day, this.epochMillis));
214
+ }
215
+
216
+ toISOString(): string {
217
+ // TODO: add more low-level helper which combine toString and padStart without extra allocation
218
+
219
+ let yr = this.year;
220
+ let isNeg = yr < 0;
221
+ let year = (isNeg || yr >= 10000)
222
+ ? (isNeg ? "-" : "+") + stringify(abs(yr), 6)
223
+ : stringify(yr, 4);
224
+ let month = stringify(this.month, 2);
225
+ let day = stringify(this.day);
226
+ let hours = stringify(this.getUTCHours());
227
+ let mins = stringify(this.getUTCMinutes());
228
+ let secs = stringify(this.getUTCSeconds());
229
+ let ms = stringify(this.getUTCMilliseconds(), 3);
230
+
231
+ return `${year}-${month}-${day}T${hours}:${mins}:${secs}.${ms}Z`;
232
+ }
233
+
234
+ toUTCString(): string {
235
+ const
236
+ weeks: StaticArray<string> = [
237
+ "Sun, ", "Mon, ", "Tue, ", "Wed, ", "Thu, ", "Fri, ", "Sat, "
238
+ ],
239
+ months: StaticArray<string> = [
240
+ " Jan ", " Feb ", " Mar ", " Apr ", " May ", " Jun ",
241
+ " Jul ", " Aug ", " Sep ", " Oct ", " Nov ", " Dec "
242
+ ];
243
+
244
+ let mo = this.month;
245
+ let da = this.day;
246
+ let yr = this.year;
247
+ let wd = dayOfWeek(yr, mo, da);
248
+ let year = stringify(abs(yr), 4);
249
+ let month = unchecked(months[mo - 1]);
250
+ let week = unchecked(weeks[wd]);
251
+ let day = stringify(da);
252
+ let hours = stringify(this.getUTCHours());
253
+ let mins = stringify(this.getUTCMinutes());
254
+ let secs = stringify(this.getUTCSeconds());
255
+
256
+ return `${week}${day}${month}${yr < 0 ? "-" : ""}${year} ${hours}:${mins}:${secs} GMT`;
257
+ }
258
+
259
+ toDateString(): string {
260
+ // TODO: use u64 static data instead 4 chars
261
+ // also use stream itoa variants.
262
+ const
263
+ weeks: StaticArray<string> = [
264
+ "Sun ", "Mon ", "Tue ", "Wed ", "Thu ", "Fri ", "Sat "
265
+ ],
266
+ months: StaticArray<string> = [
267
+ "Jan ", "Feb ", "Mar ", "Apr ", "May ", "Jun ",
268
+ "Jul ", "Aug ", "Sep ", "Oct ", "Nov ", "Dec "
269
+ ];
270
+
271
+ let mo = this.month;
272
+ let da = this.day;
273
+ let yr = this.year;
274
+ let wd = dayOfWeek(yr, mo, da);
275
+ let year = stringify(abs(yr), 4);
276
+ let month = unchecked(months[mo - 1]);
277
+ let week = unchecked(weeks[wd]);
278
+ let day = stringify(da);
279
+
280
+ return `${week}${month}${day}${yr < 0 ? " -" : " "}${year}`;
281
+ }
282
+
283
+ // Note: it uses UTC time instead local time (without timezone offset)
284
+ toTimeString(): string {
285
+ let hours = stringify(this.getUTCHours());
286
+ let mins = stringify(this.getUTCMinutes());
287
+ let secs = stringify(this.getUTCSeconds());
288
+ // TODO: add timezone
289
+ return `${hours}:${mins}:${secs}`;
290
+ }
291
+
292
+ // Note: it uses UTC datetime instead local datetime (without timezone offset)
293
+ toString(): string {
294
+ return `${this.toDateString()} ${this.toTimeString()}`;
295
+ }
296
+ }
297
+
298
+ function epochMillis(
299
+ year: i32,
300
+ month: i32,
301
+ day: i32,
302
+ hour: i32,
303
+ minute: i32,
304
+ second: i32,
305
+ milliseconds: i32
306
+ ): i64 {
307
+ return (
308
+ daysSinceEpoch(year, month, day) * MILLIS_PER_DAY +
309
+ hour * MILLIS_PER_HOUR +
310
+ minute * MILLIS_PER_MINUTE +
311
+ second * MILLIS_PER_SECOND +
312
+ milliseconds
313
+ );
314
+ }
315
+
316
+ // @ts-ignore: decorator
317
+ @inline function floorDiv<T extends number>(a: T, b: T): T {
318
+ return (a - (a < 0 ? b - 1 : 0)) / b as T;
319
+ }
320
+
321
+ // @ts-ignore: decorator
322
+ @inline function euclidRem<T extends number>(a: T, b: T): T {
323
+ let m = a % b;
324
+ return m + (m < 0 ? b : 0) as T;
325
+ }
326
+
327
+ function invalidDate(millis: i64): bool {
328
+ // @ts-ignore
329
+ return (millis < -MILLIS_LIMIT) | (millis > MILLIS_LIMIT);
330
+ }
331
+
332
+ // Based on "Euclidean Affine Functions and Applications to Calendar Algorithms"
333
+ // Paper: https://arxiv.org/pdf/2102.06959.pdf
334
+ function dateFromEpoch(ms: i64): i32 {
335
+ let da = (<i32>floorDiv(ms, MILLIS_PER_DAY) * 4 + EPOCH_OFFSET * 4) | 3;
336
+ let q0 = floorDiv(da, DAYS_PER_EPOCH); // [0, 146096]
337
+ let r1 = <u32>da - q0 * DAYS_PER_EPOCH;
338
+ let u1 = u64(r1 | 3) * 2939745;
339
+ let dm1 = <u32>u1 / 11758980;
340
+ let n1 = 2141 * dm1 + 197913;
341
+ let year = 100 * q0 + i32(u1 >>> 32);
342
+ let mo = n1 >>> 16;
343
+ _day = (n1 & 0xFFFF) / 2141 + 1; // [1, 31]
344
+ if (dm1 >= 306) { mo -= 12; ++year; }
345
+ _month = mo; // [1, 12]
346
+ return year;
347
+ }
348
+
349
+ // http://howardhinnant.github.io/date_algorithms.html#days_from_civil
350
+ function daysSinceEpoch(y: i32, m: i32, d: i32): i64 {
351
+ y -= i32(m <= 2);
352
+ let era = <u32>floorDiv(y, YEARS_PER_EPOCH);
353
+ let yoe = <u32>y - era * YEARS_PER_EPOCH; // [0, 399]
354
+ let doy = <u32>(153 * (m + (m > 2 ? -3 : 9)) + 2) / 5 + d - 1; // [0, 365]
355
+ let doe = yoe * 365 + yoe / 4 - yoe / 100 + doy; // [0, 146096]
356
+ return <i64><i32>(era * 146097 + doe - EPOCH_OFFSET);
357
+ }
358
+
359
+ // TomohikoSakamoto algorithm from https://en.wikipedia.org/wiki/Determination_of_the_day_of_the_week
360
+ function dayOfWeek(year: i32, month: i32, day: i32): i32 {
361
+ const tab = memory.data<u8>([0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4]);
362
+
363
+ year -= i32(month < 3);
364
+ year += floorDiv(year, 4) - floorDiv(year, 100) + floorDiv(year, YEARS_PER_EPOCH);
365
+ month = <i32>load<u8>(tab + month - 1);
366
+ return euclidRem(year + month + day, 7);
367
+ }
368
+
369
+ function stringify(value: i32, padding: i32 = 2): string {
370
+ return value.toString().padStart(padding, "0");
371
+ }
372
+
373
+ function join(year: i32, month: i32, day: i32, ms: i64): i64 {
374
+ return daysSinceEpoch(year, month, day) * MILLIS_PER_DAY + euclidRem(ms, MILLIS_PER_DAY);
375
+ }