gofront 1.5.1 → 1.6.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 (91) hide show
  1. package/README.md +174 -466
  2. package/package.json +16 -20
  3. package/src/backend/js/expressions.js +288 -128
  4. package/src/backend/js/index.js +138 -56
  5. package/src/backend/js/runtime.js +1055 -53
  6. package/src/backend/js/source-map.js +32 -0
  7. package/src/backend/js/statements.js +151 -83
  8. package/src/backend/js/stdlib/base64.js +12 -0
  9. package/src/backend/js/stdlib/binary.js +102 -0
  10. package/src/backend/js/stdlib/bits.js +15 -1
  11. package/src/backend/js/stdlib/builder.js +28 -9
  12. package/src/backend/js/stdlib/bytes.js +75 -18
  13. package/src/backend/js/stdlib/errors.js +22 -3
  14. package/src/backend/js/stdlib/fmt.js +95 -20
  15. package/src/backend/js/stdlib/hex.js +17 -0
  16. package/src/backend/js/stdlib/html.js +1 -1
  17. package/src/backend/js/stdlib/index.js +19 -0
  18. package/src/backend/js/stdlib/io.js +105 -3
  19. package/src/backend/js/stdlib/maps.js +1 -1
  20. package/src/backend/js/stdlib/math.js +13 -1
  21. package/src/backend/js/stdlib/path.js +20 -6
  22. package/src/backend/js/stdlib/rand.js +10 -5
  23. package/src/backend/js/stdlib/sha256.js +12 -0
  24. package/src/backend/js/stdlib/shared.js +17 -0
  25. package/src/backend/js/stdlib/slices.js +53 -27
  26. package/src/backend/js/stdlib/sort.js +1 -1
  27. package/src/backend/js/stdlib/strconv.js +52 -11
  28. package/src/backend/js/stdlib/strings.js +152 -16
  29. package/src/backend/js/stdlib/sync.js +13 -0
  30. package/src/backend/js/stdlib/testing.js +2 -2
  31. package/src/backend/js/stdlib/time.js +93 -22
  32. package/src/backend/js/stdlib/unicode.js +2 -2
  33. package/src/backend/js/templ.js +1 -1
  34. package/src/backend/wasm/boundary.js +1677 -58
  35. package/src/backend/wasm/const-fold.js +205 -0
  36. package/src/backend/wasm/emit-builtins.js +1230 -0
  37. package/src/backend/wasm/emit-exprs.js +2096 -0
  38. package/src/backend/wasm/emit-maps.js +1999 -0
  39. package/src/backend/wasm/emit-shared.js +519 -0
  40. package/src/backend/wasm/emit-stdlib.js +13 -0
  41. package/src/backend/wasm/emit-stmts.js +2466 -0
  42. package/src/backend/wasm/emit.js +656 -5031
  43. package/src/backend/wasm/encode.js +259 -85
  44. package/src/backend/wasm/glue.js +19 -5
  45. package/src/backend/wasm/index.js +2432 -86
  46. package/src/backend/wasm/monomorph.js +711 -0
  47. package/src/backend/wasm/optimize.js +236 -0
  48. package/src/backend/wasm/stdlib/bytes.js +5039 -0
  49. package/src/backend/wasm/stdlib/core.js +8903 -0
  50. package/src/backend/wasm/stdlib/index.js +40 -0
  51. package/src/backend/wasm/stdlib/io.js +2161 -0
  52. package/src/backend/wasm/stdlib/packages.js +2400 -0
  53. package/src/backend/wasm/stdlib/pure.js +720 -0
  54. package/src/backend/wasm/stdlib/time.js +1200 -0
  55. package/src/backend/wasm/types.js +312 -36
  56. package/src/backend/wasm/wat.js +49 -2
  57. package/src/cli-core.js +276 -73
  58. package/src/compiler.js +162 -25
  59. package/src/dts-parser.js +79 -126
  60. package/src/index.js +88 -121
  61. package/src/lexer.js +80 -29
  62. package/src/lower/boxing.js +4 -6
  63. package/src/lower/captures.js +12 -23
  64. package/src/lower/escape.js +4 -9
  65. package/src/lower/functions.js +277 -5
  66. package/src/lower/globals.js +7 -15
  67. package/src/lower/index.js +5 -2
  68. package/src/lower/ownership.js +35 -19
  69. package/src/lower/range.js +2 -5
  70. package/src/lower/walk.js +25 -0
  71. package/src/minifier.js +20 -68
  72. package/src/parser/declarations.js +3 -6
  73. package/src/parser/expressions.js +3 -8
  74. package/src/parser/index.js +18 -3
  75. package/src/parser/statements.js +25 -38
  76. package/src/parser/types.js +1 -2
  77. package/src/resolver.js +3 -27
  78. package/src/templ-lexer.js +29 -63
  79. package/src/templ-parser.js +22 -45
  80. package/src/test-runner.js +20 -0
  81. package/src/typechecker/assignability.js +123 -14
  82. package/src/typechecker/expressions.js +244 -4
  83. package/src/typechecker/index.js +27 -1
  84. package/src/typechecker/resolve.js +71 -12
  85. package/src/typechecker/statements.js +0 -7
  86. package/src/typechecker/stdlib/core.js +292 -103
  87. package/src/typechecker/stdlib/extended.js +471 -4
  88. package/src/typechecker/stdlib/shared.js +53 -0
  89. package/src/typechecker/stdlib.js +2 -0
  90. package/src/typechecker/types.js +545 -8
  91. package/src/vendor.js +2 -2
@@ -0,0 +1,1200 @@
1
+ // src/backend/wasm/stdlib/time.js
2
+ // FunctionEmitter mixin: time package.
3
+
4
+ const DURATION_VALS = {
5
+ Nanosecond: 1n,
6
+ Microsecond: 1000n,
7
+ Millisecond: 1000000n,
8
+ Second: 1000000000n,
9
+ Minute: 60000000000n,
10
+ Hour: 3600000000000n,
11
+ };
12
+
13
+ const LAYOUT_STRS = {
14
+ RFC3339: "2006-01-02T15:04:05Z07:00",
15
+ RFC3339Nano: "2006-01-02T15:04:05.999999999Z07:00",
16
+ DateOnly: "2006-01-02",
17
+ TimeOnly: "15:04:05",
18
+ DateTime: "2006-01-02 15:04:05",
19
+ };
20
+
21
+ const TIME_INT_CONSTS = {
22
+ January: 1,
23
+ February: 2,
24
+ March: 3,
25
+ April: 4,
26
+ May: 5,
27
+ June: 6,
28
+ July: 7,
29
+ August: 8,
30
+ September: 9,
31
+ October: 10,
32
+ November: 11,
33
+ December: 12,
34
+ Sunday: 0,
35
+ Monday: 1,
36
+ Tuesday: 2,
37
+ Wednesday: 3,
38
+ Thursday: 4,
39
+ Friday: 5,
40
+ Saturday: 6,
41
+ };
42
+
43
+ export class TimeEmitter {
44
+ _isTimeConst(expr) {
45
+ const f = expr.field;
46
+ return (
47
+ this._isPkgExpr(expr, "time") &&
48
+ (f in DURATION_VALS ||
49
+ f in LAYOUT_STRS ||
50
+ f in TIME_INT_CONSTS ||
51
+ f === "UTC" ||
52
+ f === "Local")
53
+ );
54
+ }
55
+
56
+ _isUtcExpr(expr) {
57
+ if (!expr) return false;
58
+ if (
59
+ expr.kind === "SelectorExpr" &&
60
+ (expr.sel?.name === "UTC" || expr.field === "UTC")
61
+ )
62
+ return true;
63
+ if (expr.kind === "Ident" && expr.name === "UTC") return true;
64
+ return false;
65
+ }
66
+
67
+ emitTimeConst(field, targetWasmType) {
68
+ if (field in DURATION_VALS) {
69
+ this.pushInstruction({ op: "i64.const", value: DURATION_VALS[field] });
70
+ if (targetWasmType === "i32") {
71
+ this.pushInstruction("i32.wrap_i64");
72
+ }
73
+ return;
74
+ }
75
+ if (field in LAYOUT_STRS) {
76
+ this.emitBasicLit(
77
+ { kind: "BasicLit", litKind: "STRING", value: LAYOUT_STRS[field] },
78
+ targetWasmType,
79
+ );
80
+ return;
81
+ }
82
+ if (field in TIME_INT_CONSTS) {
83
+ const v = TIME_INT_CONSTS[field];
84
+ if (targetWasmType === "i64") {
85
+ this.pushInstruction({ op: "i64.const", value: BigInt(v) });
86
+ } else {
87
+ this.pushInstruction({ op: "i32.const", value: v });
88
+ }
89
+ return;
90
+ }
91
+ if (field === "UTC" || field === "Local") {
92
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
93
+ }
94
+ }
95
+
96
+ emitTimeCall(field, call, targetWasmType) {
97
+ switch (field) {
98
+ case "Now":
99
+ this._emitTimeNow(targetWasmType);
100
+ break;
101
+ case "Since":
102
+ this._emitTimeSince(call.args, targetWasmType);
103
+ break;
104
+ case "Unix":
105
+ this._emitTimeUnix(call.args, targetWasmType);
106
+ break;
107
+ case "Date":
108
+ this._emitTimeDate(call.args, targetWasmType);
109
+ break;
110
+ case "Parse":
111
+ this._emitTimeParse(call.args, targetWasmType);
112
+ break;
113
+ default:
114
+ throw new Error(`Unsupported time function '${field}'`);
115
+ }
116
+ }
117
+
118
+ emitTimeMethodCall(field, expr, args, targetWasmType) {
119
+ switch (field) {
120
+ case "Format":
121
+ this._emitTimeMethodFormat(expr, args, targetWasmType);
122
+ break;
123
+ case "String":
124
+ this._emitTimeMethodString(expr, targetWasmType);
125
+ break;
126
+ case "Unix":
127
+ this._emitTimeMethodUnix(expr, targetWasmType);
128
+ break;
129
+ case "UnixMilli":
130
+ this._emitTimeMethodUnixMilli(expr, targetWasmType);
131
+ break;
132
+ case "Add":
133
+ this._emitTimeMethodAdd(expr, args, targetWasmType);
134
+ break;
135
+ case "Sub":
136
+ this._emitTimeMethodSub(expr, args, targetWasmType);
137
+ break;
138
+ case "Before":
139
+ this._emitTimeMethodBefore(expr, args, targetWasmType);
140
+ break;
141
+ case "After":
142
+ this._emitTimeMethodAfter(expr, args, targetWasmType);
143
+ break;
144
+ case "Equal":
145
+ this._emitTimeMethodEqual(expr, args, targetWasmType);
146
+ break;
147
+ case "Hour":
148
+ this._emitTimeMethodHour(expr, targetWasmType);
149
+ break;
150
+ case "Minute":
151
+ this._emitTimeMethodMinute(expr, targetWasmType);
152
+ break;
153
+ case "Second":
154
+ this._emitTimeMethodSecond(expr, targetWasmType);
155
+ break;
156
+ case "Weekday":
157
+ this._emitTimeMethodWeekday(expr, targetWasmType);
158
+ break;
159
+ case "Year":
160
+ this._emitTimeMethodYMD(expr, targetWasmType, 0);
161
+ break;
162
+ case "Month":
163
+ this._emitTimeMethodYMD(expr, targetWasmType, 1);
164
+ break;
165
+ case "Day":
166
+ this._emitTimeMethodYMD(expr, targetWasmType, 2);
167
+ break;
168
+ case "IsZero":
169
+ this._emitTimeMethodIsZero(expr);
170
+ break;
171
+ case "UnixNano":
172
+ this._emitTimeMethodUnixNano(expr, targetWasmType);
173
+ break;
174
+ case "Nanosecond":
175
+ this._emitTimeMethodNanosecond(expr, targetWasmType);
176
+ break;
177
+ case "UTC":
178
+ this._emitTimeMethodUTC(expr);
179
+ break;
180
+ case "Local":
181
+ this._emitTimeMethodLocal(expr);
182
+ break;
183
+ default:
184
+ throw new Error(`Unsupported time.Time method '${field}'`);
185
+ }
186
+ }
187
+
188
+ emitDurationMethodCall(field, expr, _args, _targetWasmType) {
189
+ switch (field) {
190
+ case "Nanoseconds":
191
+ this.emitExpr(expr, "i64");
192
+ return;
193
+ case "Microseconds":
194
+ this.emitExpr(expr, "i64");
195
+ this.pushInstruction({ op: "i64.const", value: 1000n });
196
+ this.pushInstruction("i64.div_s");
197
+ return;
198
+ case "Milliseconds":
199
+ this.emitExpr(expr, "i64");
200
+ this.pushInstruction({ op: "i64.const", value: 1000000n });
201
+ this.pushInstruction("i64.div_s");
202
+ return;
203
+ case "Seconds":
204
+ this.emitExpr(expr, "i64");
205
+ this.pushInstruction("f64.convert_i64_s");
206
+ this.pushInstruction({ op: "f64.const", value: 1000000000.0 });
207
+ this.pushInstruction("f64.div");
208
+ return;
209
+ case "Minutes":
210
+ this.emitExpr(expr, "i64");
211
+ this.pushInstruction("f64.convert_i64_s");
212
+ this.pushInstruction({ op: "f64.const", value: 60000000000.0 });
213
+ this.pushInstruction("f64.div");
214
+ return;
215
+ case "Hours":
216
+ this.emitExpr(expr, "i64");
217
+ this.pushInstruction("f64.convert_i64_s");
218
+ this.pushInstruction({ op: "f64.const", value: 3600000000000.0 });
219
+ this.pushInstruction("f64.div");
220
+ return;
221
+ case "String":
222
+ this.emitExpr(expr, "i64");
223
+ this._callStdlib("time_duration_string");
224
+ return;
225
+ default:
226
+ throw new Error(`Unsupported time.Duration method '${field}'`);
227
+ }
228
+ }
229
+
230
+ _emitTimeNow(_targetWasmType) {
231
+ const timeInfo = this.mod.getStructType("time.Time");
232
+ const msTmp = this.acquireTemp("f64");
233
+ const offTmp = this.acquireTemp("i32");
234
+ this._callStdlib("time_now_ms");
235
+ this.pushInstruction({ op: "local.tee", index: msTmp });
236
+ this._callStdlib("time_timezone_offset");
237
+ this.pushInstruction({ op: "local.set", index: offTmp });
238
+ this.pushInstruction({ op: "local.get", index: msTmp });
239
+ this.pushInstruction({ op: "f64.const", value: 1000000 });
240
+ this.pushInstruction("f64.mul");
241
+ this.pushInstruction("i64.trunc_sat_f64_s");
242
+ this.pushInstruction({ op: "local.get", index: offTmp });
243
+ this.pushInstruction({ op: "struct.new", typeIndex: timeInfo.typeIndex });
244
+ this.releaseTemp(offTmp, "i32");
245
+ this.releaseTemp(msTmp, "f64");
246
+ }
247
+
248
+ _emitTimeSince(args, targetWasmType) {
249
+ const timeInfo = this.mod.getStructType("time.Time");
250
+ const timeW = {
251
+ kind: "ref",
252
+ nullable: true,
253
+ typeIndex: timeInfo.typeIndex,
254
+ };
255
+ const argTmp = this.acquireTemp(timeW);
256
+ this.emitExpr(args[0], timeW);
257
+ this.pushInstruction({ op: "local.set", index: argTmp });
258
+
259
+ const msTmp = this.acquireTemp("f64");
260
+ this._callStdlib("time_now_ms");
261
+ this.pushInstruction({ op: "local.set", index: msTmp });
262
+ this.pushInstruction({ op: "local.get", index: msTmp });
263
+ this.pushInstruction({ op: "f64.const", value: 1000000 });
264
+ this.pushInstruction("f64.mul");
265
+ this.pushInstruction("i64.trunc_sat_f64_s");
266
+ this.pushInstruction({ op: "local.get", index: argTmp });
267
+ this.pushInstruction({
268
+ op: "struct.get",
269
+ typeIndex: timeInfo.typeIndex,
270
+ fieldIndex: 0,
271
+ });
272
+ this.pushInstruction("i64.sub");
273
+ this.releaseTemp(msTmp, "f64");
274
+ this.releaseTemp(argTmp, timeW);
275
+
276
+ if (targetWasmType === "i32") {
277
+ this.pushInstruction("i32.wrap_i64");
278
+ }
279
+ }
280
+
281
+ _emitTimeUnix(args, _targetWasmType) {
282
+ const timeInfo = this.mod.getStructType("time.Time");
283
+ const secTmp = this.acquireTemp("i64");
284
+ const nsecTmp = this.acquireTemp("i64");
285
+ const nanoTmp = this.acquireTemp("i64");
286
+ const offTmp = this.acquireTemp("i32");
287
+
288
+ this.emitExpr(args[0], "i64");
289
+ this.pushInstruction({ op: "local.set", index: secTmp });
290
+ this.emitExpr(args[1], "i64");
291
+ this.pushInstruction({ op: "local.set", index: nsecTmp });
292
+
293
+ this.pushInstruction({ op: "local.get", index: secTmp });
294
+ this.pushInstruction({ op: "i64.const", value: 1000000000n });
295
+ this.pushInstruction("i64.mul");
296
+ this.pushInstruction({ op: "local.get", index: nsecTmp });
297
+ this.pushInstruction("i64.add");
298
+ this.pushInstruction({ op: "local.tee", index: nanoTmp });
299
+
300
+ this.pushInstruction({ op: "i64.const", value: 1000000n });
301
+ this.pushInstruction("i64.div_s");
302
+ this.pushInstruction("f64.convert_i64_s");
303
+ this._callStdlib("time_timezone_offset");
304
+ this.pushInstruction({ op: "local.set", index: offTmp });
305
+
306
+ this.pushInstruction({ op: "local.get", index: nanoTmp });
307
+ this.pushInstruction({ op: "local.get", index: offTmp });
308
+ this.pushInstruction({ op: "struct.new", typeIndex: timeInfo.typeIndex });
309
+
310
+ this.releaseTemp(offTmp, "i32");
311
+ this.releaseTemp(nanoTmp, "i64");
312
+ this.releaseTemp(nsecTmp, "i64");
313
+ this.releaseTemp(secTmp, "i64");
314
+ }
315
+
316
+ _emitCivilDays(yTmp, mTmp, dTmp, daysTmp) {
317
+ // Evaluates:
318
+ // if (m <= 2) y -= 1
319
+ // era = (y >= 0 ? y : y - 399) / 400
320
+ // yoe = y - era * 400
321
+ // doy = (153 * (m > 2 ? m - 3 : m + 9) + 2) / 5 + d - 1
322
+ // doe = yoe * 365 + yoe / 4 - yoe / 100 + doy
323
+ // days = era * 146097 + doe - 719468
324
+ const eraTmp = this.acquireTemp("i32");
325
+ const yoeTmp = this.acquireTemp("i32");
326
+ const doyTmp = this.acquireTemp("i32");
327
+ const doeTmp = this.acquireTemp("i32");
328
+
329
+ this.pushInstruction({ op: "local.get", index: mTmp });
330
+ this.pushInstruction({ op: "i32.const", value: 2 });
331
+ this.pushInstruction("i32.le_s");
332
+ this.pushInstruction({ op: "if", blockType: "void" });
333
+ this.pushInstruction({ op: "local.get", index: yTmp });
334
+ this.pushInstruction({ op: "i32.const", value: 1 });
335
+ this.pushInstruction("i32.sub");
336
+ this.pushInstruction({ op: "local.set", index: yTmp });
337
+ this.pushInstruction("end");
338
+
339
+ this.pushInstruction({ op: "local.get", index: yTmp });
340
+ this.pushInstruction({ op: "i32.const", value: 0 });
341
+ this.pushInstruction("i32.ge_s");
342
+ this.pushInstruction({ op: "if", blockType: "i32" });
343
+ this.pushInstruction({ op: "local.get", index: yTmp });
344
+ this.pushInstruction("else");
345
+ this.pushInstruction({ op: "local.get", index: yTmp });
346
+ this.pushInstruction({ op: "i32.const", value: 399 });
347
+ this.pushInstruction("i32.sub");
348
+ this.pushInstruction("end");
349
+ this.pushInstruction({ op: "i32.const", value: 400 });
350
+ this.pushInstruction("i32.div_s");
351
+ this.pushInstruction({ op: "local.set", index: eraTmp });
352
+ this.pushInstruction({ op: "local.get", index: yTmp });
353
+ this.pushInstruction({ op: "local.get", index: eraTmp });
354
+ this.pushInstruction({ op: "i32.const", value: 400 });
355
+ this.pushInstruction("i32.mul");
356
+ this.pushInstruction("i32.sub");
357
+ this.pushInstruction({ op: "local.set", index: yoeTmp });
358
+
359
+ // doy = (153 * (m > 2 ? m - 3 : m + 9) + 2) / 5 + d - 1
360
+ this.pushInstruction({ op: "local.get", index: mTmp });
361
+ this.pushInstruction({ op: "i32.const", value: 2 });
362
+ this.pushInstruction("i32.gt_s");
363
+ this.pushInstruction({ op: "if", blockType: "i32" });
364
+ this.pushInstruction({ op: "local.get", index: mTmp });
365
+ this.pushInstruction({ op: "i32.const", value: 3 });
366
+ this.pushInstruction("i32.sub");
367
+ this.pushInstruction("else");
368
+ this.pushInstruction({ op: "local.get", index: mTmp });
369
+ this.pushInstruction({ op: "i32.const", value: 9 });
370
+ this.pushInstruction("i32.add");
371
+ this.pushInstruction("end");
372
+ this.pushInstruction({ op: "i32.const", value: 153 });
373
+ this.pushInstruction("i32.mul");
374
+ this.pushInstruction({ op: "i32.const", value: 2 });
375
+ this.pushInstruction("i32.add");
376
+ this.pushInstruction({ op: "i32.const", value: 5 });
377
+ this.pushInstruction("i32.div_s");
378
+ this.pushInstruction({ op: "local.get", index: dTmp });
379
+ this.pushInstruction("i32.add");
380
+ this.pushInstruction({ op: "i32.const", value: 1 });
381
+ this.pushInstruction("i32.sub");
382
+ this.pushInstruction({ op: "local.set", index: doyTmp });
383
+
384
+ // doe = yoe * 365 + yoe / 4 - yoe / 100 + doy
385
+ this.pushInstruction({ op: "local.get", index: yoeTmp });
386
+ this.pushInstruction({ op: "i32.const", value: 365 });
387
+ this.pushInstruction("i32.mul");
388
+ this.pushInstruction({ op: "local.get", index: yoeTmp });
389
+ this.pushInstruction({ op: "i32.const", value: 4 });
390
+ this.pushInstruction("i32.div_s");
391
+ this.pushInstruction("i32.add");
392
+ this.pushInstruction({ op: "local.get", index: yoeTmp });
393
+ this.pushInstruction({ op: "i32.const", value: 100 });
394
+ this.pushInstruction("i32.div_s");
395
+ this.pushInstruction("i32.sub");
396
+ this.pushInstruction({ op: "local.get", index: doyTmp });
397
+ this.pushInstruction("i32.add");
398
+ this.pushInstruction({ op: "local.set", index: doeTmp });
399
+
400
+ // days = era * 146097 + doe - 719468 (in i64)
401
+ this.pushInstruction({ op: "local.get", index: eraTmp });
402
+ this.pushInstruction("i64.extend_i32_s");
403
+ this.pushInstruction({ op: "i64.const", value: 146097n });
404
+ this.pushInstruction("i64.mul");
405
+ this.pushInstruction({ op: "local.get", index: doeTmp });
406
+ this.pushInstruction("i64.extend_i32_s");
407
+ this.pushInstruction("i64.add");
408
+ this.pushInstruction({ op: "i64.const", value: 719468n });
409
+ this.pushInstruction("i64.sub");
410
+ this.pushInstruction({ op: "local.set", index: daysTmp });
411
+
412
+ this.releaseTemp(doeTmp, "i32");
413
+ this.releaseTemp(doyTmp, "i32");
414
+ this.releaseTemp(yoeTmp, "i32");
415
+ this.releaseTemp(eraTmp, "i32");
416
+ }
417
+
418
+ _emitTimeDate(args, _targetWasmType) {
419
+ const timeInfo = this.mod.getStructType("time.Time");
420
+ const yTmp = this.acquireTemp("i32");
421
+ const mTmp = this.acquireTemp("i32");
422
+ const dTmp = this.acquireTemp("i32");
423
+ const hrTmp = this.acquireTemp("i32");
424
+ const minTmp = this.acquireTemp("i32");
425
+ const secTmp = this.acquireTemp("i32");
426
+ const nsecTmp = this.acquireTemp("i64");
427
+ const locTmp = this.acquireTemp("anyref");
428
+
429
+ this.emitExpr(args[0], "i32");
430
+ this.pushInstruction({ op: "local.set", index: yTmp });
431
+ this.emitExpr(args[1], "i32");
432
+ this.pushInstruction({ op: "local.set", index: mTmp });
433
+ this.emitExpr(args[2], "i32");
434
+ this.pushInstruction({ op: "local.set", index: dTmp });
435
+ this.emitExpr(args[3], "i32");
436
+ this.pushInstruction({ op: "local.set", index: hrTmp });
437
+ this.emitExpr(args[4], "i32");
438
+ this.pushInstruction({ op: "local.set", index: minTmp });
439
+ this.emitExpr(args[5], "i32");
440
+ this.pushInstruction({ op: "local.set", index: secTmp });
441
+ this.emitExpr(args[6], "i64");
442
+ this.pushInstruction({ op: "local.set", index: nsecTmp });
443
+ this.emitExpr(args[7], "anyref");
444
+ this.pushInstruction({ op: "local.set", index: locTmp });
445
+
446
+ const daysTmp = this.acquireTemp("i64");
447
+ this._emitCivilDays(yTmp, mTmp, dTmp, daysTmp);
448
+
449
+ const localSecTmp = this.acquireTemp("i64");
450
+ // secOfDay = hr * 3600 + min * 60 + sec
451
+ this.pushInstruction({ op: "local.get", index: hrTmp });
452
+ this.pushInstruction({ op: "i32.const", value: 3600 });
453
+ this.pushInstruction("i32.mul");
454
+ this.pushInstruction({ op: "local.get", index: minTmp });
455
+ this.pushInstruction({ op: "i32.const", value: 60 });
456
+ this.pushInstruction("i32.mul");
457
+ this.pushInstruction("i32.add");
458
+ this.pushInstruction({ op: "local.get", index: secTmp });
459
+ this.pushInstruction("i32.add");
460
+ this.pushInstruction("i64.extend_i32_s");
461
+ this.pushInstruction({ op: "local.get", index: daysTmp });
462
+ this.pushInstruction({ op: "i64.const", value: 86400n });
463
+ this.pushInstruction("i64.mul");
464
+ this.pushInstruction("i64.add");
465
+ this.pushInstruction({ op: "local.set", index: localSecTmp });
466
+
467
+ const offTmp = this.acquireTemp("i32");
468
+ if (this._isUtcExpr(args[7])) {
469
+ this.pushInstruction({ op: "i32.const", value: 0 });
470
+ this.pushInstruction({ op: "local.set", index: offTmp });
471
+ } else {
472
+ this.pushInstruction({ op: "local.get", index: localSecTmp });
473
+ this.pushInstruction({ op: "i64.const", value: 1000n });
474
+ this.pushInstruction("i64.mul");
475
+ this.pushInstruction("f64.convert_i64_s");
476
+ this._callStdlib("time_timezone_offset");
477
+ this.pushInstruction({ op: "local.set", index: offTmp });
478
+ }
479
+
480
+ // unixSec = localSec - offset
481
+ this.pushInstruction({ op: "local.get", index: localSecTmp });
482
+ this.pushInstruction({ op: "local.get", index: offTmp });
483
+ this.pushInstruction("i64.extend_i32_s");
484
+ this.pushInstruction("i64.sub");
485
+ this.pushInstruction({ op: "i64.const", value: 1000000000n });
486
+ this.pushInstruction("i64.mul");
487
+ this.pushInstruction({ op: "local.get", index: nsecTmp });
488
+ this.pushInstruction("i64.add");
489
+
490
+ this.pushInstruction({ op: "local.get", index: offTmp });
491
+ this.pushInstruction({ op: "struct.new", typeIndex: timeInfo.typeIndex });
492
+
493
+ this.releaseTemp(offTmp, "i32");
494
+ this.releaseTemp(localSecTmp, "i64");
495
+ this.releaseTemp(daysTmp, "i64");
496
+ this.releaseTemp(locTmp, "anyref");
497
+ this.releaseTemp(nsecTmp, "i64");
498
+ this.releaseTemp(secTmp, "i32");
499
+ this.releaseTemp(minTmp, "i32");
500
+ this.releaseTemp(hrTmp, "i32");
501
+ this.releaseTemp(dTmp, "i32");
502
+ this.releaseTemp(mTmp, "i32");
503
+ this.releaseTemp(yTmp, "i32");
504
+ }
505
+
506
+ _emitTimeParse(args, _targetWasmType) {
507
+ const timeInfo = this.mod.getStructType("time.Time");
508
+ const timeW = {
509
+ kind: "ref",
510
+ nullable: true,
511
+ typeIndex: timeInfo.typeIndex,
512
+ };
513
+ const msTmp = this.acquireTemp("f64");
514
+ const offTmp = this.acquireTemp("i32");
515
+ const errStrTmp = this.acquireTemp("externref");
516
+ const resTimeTmp = this.acquireTemp(timeW);
517
+ const resErrTmp = this.acquireTemp("anyref");
518
+
519
+ this.emitExpr(args[0], "externref");
520
+ this.emitExpr(args[1], "externref");
521
+ this._callStdlib("time_parse");
522
+ this.pushInstruction({ op: "local.set", index: msTmp });
523
+ this._callStdlib("time_parse_offset");
524
+ this.pushInstruction({ op: "local.set", index: offTmp });
525
+ this._callStdlib("time_parse_err");
526
+ this.pushInstruction({ op: "local.set", index: errStrTmp });
527
+
528
+ this.pushInstruction({ op: "local.get", index: errStrTmp });
529
+ this.pushInstruction("ref.is_null");
530
+ this.pushInstruction({ op: "if", blockType: "void" });
531
+
532
+ // Success
533
+ this.pushInstruction({ op: "local.get", index: msTmp });
534
+ this.pushInstruction({ op: "f64.const", value: 1000000 });
535
+ this.pushInstruction("f64.mul");
536
+ this.pushInstruction("i64.trunc_sat_f64_s");
537
+ this.pushInstruction({ op: "local.get", index: offTmp });
538
+ this.pushInstruction({ op: "struct.new", typeIndex: timeInfo.typeIndex });
539
+ this.pushInstruction({ op: "local.set", index: resTimeTmp });
540
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
541
+ this.pushInstruction({ op: "local.set", index: resErrTmp });
542
+
543
+ this.pushInstruction("else");
544
+
545
+ // Error
546
+ this.pushInstruction({ op: "i64.const", value: 0n });
547
+ this.pushInstruction({ op: "i32.const", value: 0 });
548
+ this.pushInstruction({ op: "struct.new", typeIndex: timeInfo.typeIndex });
549
+ this.pushInstruction({ op: "local.set", index: resTimeTmp });
550
+ this.pushInstruction({ op: "local.get", index: errStrTmp });
551
+ this.pushInstruction({ op: "ref.null", heapType: "any" });
552
+ this.pushInstruction({
553
+ op: "call",
554
+ funcIndex: this.mod.resolveFuncIndex("__mk_error"),
555
+ });
556
+ this.pushInstruction({ op: "local.set", index: resErrTmp });
557
+
558
+ this.pushInstruction("end");
559
+
560
+ this.pushInstruction({ op: "local.get", index: resTimeTmp });
561
+ this.pushInstruction({ op: "local.get", index: resErrTmp });
562
+
563
+ this.releaseTemp(resErrTmp, "anyref");
564
+ this.releaseTemp(resTimeTmp, timeW);
565
+ this.releaseTemp(errStrTmp, "externref");
566
+ this.releaseTemp(offTmp, "i32");
567
+ this.releaseTemp(msTmp, "f64");
568
+ }
569
+
570
+ _emitTimeMethodAdd(expr, args, _targetWasmType) {
571
+ const timeInfo = this.mod.getStructType("time.Time");
572
+ const timeW = {
573
+ kind: "ref",
574
+ nullable: true,
575
+ typeIndex: timeInfo.typeIndex,
576
+ };
577
+ const rTmp = this.acquireTemp(timeW);
578
+ const dTmp = this.acquireTemp("i64");
579
+
580
+ this.emitExpr(expr, timeW);
581
+ this.pushInstruction({ op: "local.set", index: rTmp });
582
+ this.emitExpr(args[0], "i64");
583
+ this.pushInstruction({ op: "local.set", index: dTmp });
584
+
585
+ this.pushInstruction({ op: "local.get", index: rTmp });
586
+ this.pushInstruction({
587
+ op: "struct.get",
588
+ typeIndex: timeInfo.typeIndex,
589
+ fieldIndex: 0,
590
+ });
591
+ this.pushInstruction({ op: "local.get", index: dTmp });
592
+ this.pushInstruction("i64.add");
593
+
594
+ this.pushInstruction({ op: "local.get", index: rTmp });
595
+ this.pushInstruction({
596
+ op: "struct.get",
597
+ typeIndex: timeInfo.typeIndex,
598
+ fieldIndex: 1,
599
+ });
600
+
601
+ this.pushInstruction({ op: "struct.new", typeIndex: timeInfo.typeIndex });
602
+
603
+ this.releaseTemp(dTmp, "i64");
604
+ this.releaseTemp(rTmp, timeW);
605
+ }
606
+
607
+ _emitTimeMethodSub(expr, args, targetWasmType) {
608
+ const timeInfo = this.mod.getStructType("time.Time");
609
+ const timeW = {
610
+ kind: "ref",
611
+ nullable: true,
612
+ typeIndex: timeInfo.typeIndex,
613
+ };
614
+ const rTmp = this.acquireTemp(timeW);
615
+ const uTmp = this.acquireTemp(timeW);
616
+
617
+ this.emitExpr(expr, timeW);
618
+ this.pushInstruction({ op: "local.set", index: rTmp });
619
+ this.emitExpr(args[0], timeW);
620
+ this.pushInstruction({ op: "local.set", index: uTmp });
621
+
622
+ this.pushInstruction({ op: "local.get", index: rTmp });
623
+ this.pushInstruction({
624
+ op: "struct.get",
625
+ typeIndex: timeInfo.typeIndex,
626
+ fieldIndex: 0,
627
+ });
628
+ this.pushInstruction({ op: "local.get", index: uTmp });
629
+ this.pushInstruction({
630
+ op: "struct.get",
631
+ typeIndex: timeInfo.typeIndex,
632
+ fieldIndex: 0,
633
+ });
634
+ this.pushInstruction("i64.sub");
635
+
636
+ this.releaseTemp(uTmp, timeW);
637
+ this.releaseTemp(rTmp, timeW);
638
+
639
+ if (targetWasmType === "i32") {
640
+ this.pushInstruction("i32.wrap_i64");
641
+ }
642
+ }
643
+
644
+ _emitTimeMethodBefore(expr, args, _targetWasmType) {
645
+ this._emitTimeCmp(expr, args, "i64.lt_s");
646
+ }
647
+
648
+ _emitTimeMethodAfter(expr, args, _targetWasmType) {
649
+ this._emitTimeCmp(expr, args, "i64.gt_s");
650
+ }
651
+
652
+ _emitTimeMethodEqual(expr, args, _targetWasmType) {
653
+ this._emitTimeCmp(expr, args, "i64.eq");
654
+ }
655
+
656
+ _emitTimeCmp(expr, args, op) {
657
+ const timeInfo = this.mod.getStructType("time.Time");
658
+ const timeW = {
659
+ kind: "ref",
660
+ nullable: true,
661
+ typeIndex: timeInfo.typeIndex,
662
+ };
663
+ const rTmp = this.acquireTemp(timeW);
664
+ const uTmp = this.acquireTemp(timeW);
665
+
666
+ this.emitExpr(expr, timeW);
667
+ this.pushInstruction({ op: "local.set", index: rTmp });
668
+ this.emitExpr(args[0], timeW);
669
+ this.pushInstruction({ op: "local.set", index: uTmp });
670
+
671
+ this.pushInstruction({ op: "local.get", index: rTmp });
672
+ this.pushInstruction({
673
+ op: "struct.get",
674
+ typeIndex: timeInfo.typeIndex,
675
+ fieldIndex: 0,
676
+ });
677
+ this.pushInstruction({ op: "local.get", index: uTmp });
678
+ this.pushInstruction({
679
+ op: "struct.get",
680
+ typeIndex: timeInfo.typeIndex,
681
+ fieldIndex: 0,
682
+ });
683
+ this.pushInstruction(op);
684
+
685
+ this.releaseTemp(uTmp, timeW);
686
+ this.releaseTemp(rTmp, timeW);
687
+ }
688
+
689
+ _emitTimeGetNano(expr) {
690
+ const timeInfo = this.mod.getStructType("time.Time");
691
+ this.emitExpr(expr, {
692
+ kind: "ref",
693
+ nullable: true,
694
+ typeIndex: timeInfo.typeIndex,
695
+ });
696
+ this.pushInstruction({
697
+ op: "struct.get",
698
+ typeIndex: timeInfo.typeIndex,
699
+ fieldIndex: 0,
700
+ });
701
+ return timeInfo;
702
+ }
703
+
704
+ _emitTimeMethodUnix(expr, targetWasmType) {
705
+ this._emitTimeGetNano(expr);
706
+ this.pushInstruction({ op: "i64.const", value: 1000000000n });
707
+ this.pushInstruction("i64.div_s");
708
+ if (targetWasmType === "i32") {
709
+ this.pushInstruction("i32.wrap_i64");
710
+ }
711
+ }
712
+
713
+ _emitTimeMethodUnixMilli(expr, targetWasmType) {
714
+ this._emitTimeGetNano(expr);
715
+ this.pushInstruction({ op: "i64.const", value: 1000000n });
716
+ this.pushInstruction("i64.div_s");
717
+ if (targetWasmType === "i32") {
718
+ this.pushInstruction("i32.wrap_i64");
719
+ }
720
+ }
721
+
722
+ _emitTimeMethodUnixNano(expr, targetWasmType) {
723
+ this._emitTimeGetNano(expr);
724
+ if (targetWasmType === "i32") {
725
+ this.pushInstruction("i32.wrap_i64");
726
+ }
727
+ }
728
+
729
+ _emitTimeMethodIsZero(expr) {
730
+ this._emitTimeGetNano(expr);
731
+ this.pushInstruction({ op: "i64.const", value: 0n });
732
+ this.pushInstruction("i64.eq");
733
+ }
734
+
735
+ _emitTimeMethodNanosecond(expr, targetWasmType) {
736
+ this._emitTimeGetNano(expr);
737
+ this.pushInstruction({ op: "i64.const", value: 1000000000n });
738
+ this.pushInstruction("i64.rem_s");
739
+ const nsTmp = this.acquireTemp("i64");
740
+ this.pushInstruction({ op: "local.tee", index: nsTmp });
741
+ this.pushInstruction({ op: "i64.const", value: 0n });
742
+ this.pushInstruction("i64.lt_s");
743
+ this.pushInstruction({ op: "if", blockType: "i64" });
744
+ this.pushInstruction({ op: "local.get", index: nsTmp });
745
+ this.pushInstruction({ op: "i64.const", value: 1000000000n });
746
+ this.pushInstruction("i64.add");
747
+ this.pushInstruction({ op: "else" });
748
+ this.pushInstruction({ op: "local.get", index: nsTmp });
749
+ this.pushInstruction("end");
750
+ this.releaseTemp(nsTmp, "i64");
751
+ if (targetWasmType !== "i64") {
752
+ this.pushInstruction("i32.wrap_i64");
753
+ }
754
+ }
755
+
756
+ _emitTimeMethodUTC(expr) {
757
+ const timeInfo = this._emitTimeGetNano(expr);
758
+ this.pushInstruction({ op: "i32.const", value: 0 });
759
+ this.pushInstruction({
760
+ op: "struct.new",
761
+ typeIndex: timeInfo.typeIndex,
762
+ });
763
+ }
764
+
765
+ _emitTimeMethodLocal(expr) {
766
+ const timeInfo = this.mod.getStructType("time.Time");
767
+ const timeW = {
768
+ kind: "ref",
769
+ nullable: true,
770
+ typeIndex: timeInfo.typeIndex,
771
+ };
772
+ const rTmp = this.acquireTemp(timeW);
773
+ this.emitExpr(expr, timeW);
774
+ this.pushInstruction({ op: "local.set", index: rTmp });
775
+
776
+ this.pushInstruction({ op: "local.get", index: rTmp });
777
+ this.pushInstruction({
778
+ op: "struct.get",
779
+ typeIndex: timeInfo.typeIndex,
780
+ fieldIndex: 0,
781
+ });
782
+
783
+ this.pushInstruction({ op: "local.get", index: rTmp });
784
+ this.pushInstruction({
785
+ op: "struct.get",
786
+ typeIndex: timeInfo.typeIndex,
787
+ fieldIndex: 0,
788
+ });
789
+ this.pushInstruction({ op: "i64.const", value: 1000000n });
790
+ this.pushInstruction("i64.div_s");
791
+ this.pushInstruction("f64.convert_i64_s");
792
+ this.pushInstruction({
793
+ op: "call",
794
+ funcIndex: this.mod.getTimezoneOffsetImportIndex(),
795
+ });
796
+
797
+ this.pushInstruction({
798
+ op: "struct.new",
799
+ typeIndex: timeInfo.typeIndex,
800
+ });
801
+ this.releaseTemp(rTmp, timeW);
802
+ }
803
+
804
+ _emitCivilDateFromDays(daysTmp, yTmp, mTmp, dTmp) {
805
+ // Computes (y, m, d) in i32 from days in i64
806
+ const d64 = this.acquireTemp("i64");
807
+ this.pushInstruction({ op: "local.get", index: daysTmp });
808
+ this.pushInstruction({ op: "i64.const", value: 719468n });
809
+ this.pushInstruction("i64.add");
810
+ this.pushInstruction({ op: "local.set", index: d64 });
811
+
812
+ const eraTmp = this.acquireTemp("i32");
813
+ const doeTmp = this.acquireTemp("i32");
814
+ const yoeTmp = this.acquireTemp("i32");
815
+ const doyTmp = this.acquireTemp("i32");
816
+ const mpTmp = this.acquireTemp("i32");
817
+
818
+ // era = (d64 >= 0 ? d64 : d64 - 146096n) / 146097n
819
+ this.pushInstruction({ op: "local.get", index: d64 });
820
+ this.pushInstruction({ op: "i64.const", value: 0n });
821
+ this.pushInstruction("i64.ge_s");
822
+ this.pushInstruction({ op: "if", blockType: "i64" });
823
+ this.pushInstruction({ op: "local.get", index: d64 });
824
+ this.pushInstruction("else");
825
+ this.pushInstruction({ op: "local.get", index: d64 });
826
+ this.pushInstruction({ op: "i64.const", value: 146096n });
827
+ this.pushInstruction("i64.sub");
828
+ this.pushInstruction("end");
829
+ this.pushInstruction({ op: "i64.const", value: 146097n });
830
+ this.pushInstruction("i64.div_s");
831
+ this.pushInstruction("i32.wrap_i64");
832
+ this.pushInstruction({ op: "local.set", index: eraTmp });
833
+
834
+ // doe = i32(d64 - era * 146097n)
835
+ this.pushInstruction({ op: "local.get", index: d64 });
836
+ this.pushInstruction({ op: "local.get", index: eraTmp });
837
+ this.pushInstruction("i64.extend_i32_s");
838
+ this.pushInstruction({ op: "i64.const", value: 146097n });
839
+ this.pushInstruction("i64.mul");
840
+ this.pushInstruction("i64.sub");
841
+ this.pushInstruction("i32.wrap_i64");
842
+ this.pushInstruction({ op: "local.set", index: doeTmp });
843
+
844
+ // yoe = (doe - doe/1460 + doe/36524 - doe/146096) / 365
845
+ this.pushInstruction({ op: "local.get", index: doeTmp });
846
+ this.pushInstruction({ op: "local.get", index: doeTmp });
847
+ this.pushInstruction({ op: "i32.const", value: 1460 });
848
+ this.pushInstruction("i32.div_s");
849
+ this.pushInstruction("i32.sub");
850
+ this.pushInstruction({ op: "local.get", index: doeTmp });
851
+ this.pushInstruction({ op: "i32.const", value: 36524 });
852
+ this.pushInstruction("i32.div_s");
853
+ this.pushInstruction("i32.add");
854
+ this.pushInstruction({ op: "local.get", index: doeTmp });
855
+ this.pushInstruction({ op: "i32.const", value: 146096 });
856
+ this.pushInstruction("i32.div_s");
857
+ this.pushInstruction("i32.sub");
858
+ this.pushInstruction({ op: "i32.const", value: 365 });
859
+ this.pushInstruction("i32.div_s");
860
+ this.pushInstruction({ op: "local.set", index: yoeTmp });
861
+
862
+ // y = yoe + era * 400
863
+ this.pushInstruction({ op: "local.get", index: yoeTmp });
864
+ this.pushInstruction({ op: "local.get", index: eraTmp });
865
+ this.pushInstruction({ op: "i32.const", value: 400 });
866
+ this.pushInstruction("i32.mul");
867
+ this.pushInstruction("i32.add");
868
+ this.pushInstruction({ op: "local.set", index: yTmp });
869
+
870
+ // doy = doe - (365*yoe + yoe/4 - yoe/100)
871
+ this.pushInstruction({ op: "local.get", index: doeTmp });
872
+ this.pushInstruction({ op: "local.get", index: yoeTmp });
873
+ this.pushInstruction({ op: "i32.const", value: 365 });
874
+ this.pushInstruction("i32.mul");
875
+ this.pushInstruction({ op: "local.get", index: yoeTmp });
876
+ this.pushInstruction({ op: "i32.const", value: 4 });
877
+ this.pushInstruction("i32.div_s");
878
+ this.pushInstruction("i32.add");
879
+ this.pushInstruction({ op: "local.get", index: yoeTmp });
880
+ this.pushInstruction({ op: "i32.const", value: 100 });
881
+ this.pushInstruction("i32.div_s");
882
+ this.pushInstruction("i32.sub");
883
+ this.pushInstruction("i32.sub");
884
+ this.pushInstruction({ op: "local.set", index: doyTmp });
885
+
886
+ // mp = (5*doy + 2) / 153
887
+ this.pushInstruction({ op: "local.get", index: doyTmp });
888
+ this.pushInstruction({ op: "i32.const", value: 5 });
889
+ this.pushInstruction("i32.mul");
890
+ this.pushInstruction({ op: "i32.const", value: 2 });
891
+ this.pushInstruction("i32.add");
892
+ this.pushInstruction({ op: "i32.const", value: 153 });
893
+ this.pushInstruction("i32.div_s");
894
+ this.pushInstruction({ op: "local.set", index: mpTmp });
895
+
896
+ // d = doy - (153*mp + 2)/5 + 1
897
+ this.pushInstruction({ op: "local.get", index: doyTmp });
898
+ this.pushInstruction({ op: "local.get", index: mpTmp });
899
+ this.pushInstruction({ op: "i32.const", value: 153 });
900
+ this.pushInstruction("i32.mul");
901
+ this.pushInstruction({ op: "i32.const", value: 2 });
902
+ this.pushInstruction("i32.add");
903
+ this.pushInstruction({ op: "i32.const", value: 5 });
904
+ this.pushInstruction("i32.div_s");
905
+ this.pushInstruction("i32.sub");
906
+ this.pushInstruction({ op: "i32.const", value: 1 });
907
+ this.pushInstruction("i32.add");
908
+ this.pushInstruction({ op: "local.set", index: dTmp });
909
+
910
+ // m = mp + (mp < 10 ? 3 : -9)
911
+ this.pushInstruction({ op: "local.get", index: mpTmp });
912
+ this.pushInstruction({ op: "local.get", index: mpTmp });
913
+ this.pushInstruction({ op: "i32.const", value: 10 });
914
+ this.pushInstruction("i32.lt_s");
915
+ this.pushInstruction({ op: "if", blockType: "i32" });
916
+ this.pushInstruction({ op: "i32.const", value: 3 });
917
+ this.pushInstruction("else");
918
+ this.pushInstruction({ op: "i32.const", value: -9 });
919
+ this.pushInstruction("end");
920
+ this.pushInstruction("i32.add");
921
+ this.pushInstruction({ op: "local.set", index: mTmp });
922
+
923
+ // if (m <= 2) y += 1
924
+ this.pushInstruction({ op: "local.get", index: mTmp });
925
+ this.pushInstruction({ op: "i32.const", value: 2 });
926
+ this.pushInstruction("i32.le_s");
927
+ this.pushInstruction({ op: "if", blockType: "void" });
928
+ this.pushInstruction({ op: "local.get", index: yTmp });
929
+ this.pushInstruction({ op: "i32.const", value: 1 });
930
+ this.pushInstruction("i32.add");
931
+ this.pushInstruction({ op: "local.set", index: yTmp });
932
+ this.pushInstruction("end");
933
+
934
+ this.releaseTemp(mpTmp, "i32");
935
+ this.releaseTemp(doyTmp, "i32");
936
+ this.releaseTemp(yoeTmp, "i32");
937
+ this.releaseTemp(doeTmp, "i32");
938
+ this.releaseTemp(eraTmp, "i32");
939
+ this.releaseTemp(d64, "i64");
940
+ }
941
+
942
+ _emitTimeDecomposeParts(expr) {
943
+ const timeInfo = this.mod.getStructType("time.Time");
944
+ const timeW = {
945
+ kind: "ref",
946
+ nullable: true,
947
+ typeIndex: timeInfo.typeIndex,
948
+ };
949
+ const rTmp = this.acquireTemp(timeW);
950
+ this.emitExpr(expr, timeW);
951
+ this.pushInstruction({ op: "local.set", index: rTmp });
952
+
953
+ const localSecTmp = this.acquireTemp("i64");
954
+ const daysTmp = this.acquireTemp("i64");
955
+ const remSecTmp = this.acquireTemp("i64");
956
+ const offTmp = this.acquireTemp("i32");
957
+ const nanoTmp = this.acquireTemp("i64");
958
+
959
+ this.pushInstruction({ op: "local.get", index: rTmp });
960
+ this.pushInstruction({
961
+ op: "struct.get",
962
+ typeIndex: timeInfo.typeIndex,
963
+ fieldIndex: 0,
964
+ });
965
+ this.pushInstruction({ op: "local.set", index: nanoTmp });
966
+
967
+ this.pushInstruction({ op: "local.get", index: rTmp });
968
+ this.pushInstruction({
969
+ op: "struct.get",
970
+ typeIndex: timeInfo.typeIndex,
971
+ fieldIndex: 1,
972
+ });
973
+ this.pushInstruction({ op: "local.set", index: offTmp });
974
+
975
+ // localSec = nanoTmp / 1000000000n + offTmp
976
+ this.pushInstruction({ op: "local.get", index: nanoTmp });
977
+ this.pushInstruction({ op: "i64.const", value: 1000000000n });
978
+ this.pushInstruction("i64.div_s");
979
+ this.pushInstruction({ op: "local.get", index: offTmp });
980
+ this.pushInstruction("i64.extend_i32_s");
981
+ this.pushInstruction("i64.add");
982
+ this.pushInstruction({ op: "local.set", index: localSecTmp });
983
+
984
+ // days = localSec / 86400n
985
+ this.pushInstruction({ op: "local.get", index: localSecTmp });
986
+ this.pushInstruction({ op: "i64.const", value: 86400n });
987
+ this.pushInstruction("i64.div_s");
988
+ this.pushInstruction({ op: "local.set", index: daysTmp });
989
+
990
+ // remSec = localSec % 86400n
991
+ this.pushInstruction({ op: "local.get", index: localSecTmp });
992
+ this.pushInstruction({ op: "i64.const", value: 86400n });
993
+ this.pushInstruction("i64.rem_s");
994
+ this.pushInstruction({ op: "local.tee", index: remSecTmp });
995
+ this.pushInstruction({ op: "i64.const", value: 0n });
996
+ this.pushInstruction("i64.lt_s");
997
+ this.pushInstruction({ op: "if", blockType: "void" });
998
+ this.pushInstruction({ op: "local.get", index: remSecTmp });
999
+ this.pushInstruction({ op: "i64.const", value: 86400n });
1000
+ this.pushInstruction("i64.add");
1001
+ this.pushInstruction({ op: "local.set", index: remSecTmp });
1002
+ this.pushInstruction({ op: "local.get", index: daysTmp });
1003
+ this.pushInstruction({ op: "i64.const", value: 1n });
1004
+ this.pushInstruction("i64.sub");
1005
+ this.pushInstruction({ op: "local.set", index: daysTmp });
1006
+ this.pushInstruction("end");
1007
+
1008
+ return { rTmp, timeW, localSecTmp, daysTmp, remSecTmp, offTmp, nanoTmp };
1009
+ }
1010
+
1011
+ _emitTimeMethodHour(expr, targetWasmType) {
1012
+ const p = this._emitTimeDecomposeParts(expr);
1013
+ this.pushInstruction({ op: "local.get", index: p.remSecTmp });
1014
+ this.pushInstruction({ op: "i64.const", value: 3600n });
1015
+ this.pushInstruction("i64.div_s");
1016
+ this.pushInstruction("i32.wrap_i64");
1017
+ if (targetWasmType === "i64") this.pushInstruction("i64.extend_i32_s");
1018
+ this._releaseTimeDecomposeParts(p);
1019
+ }
1020
+
1021
+ _emitTimeMethodMinute(expr, targetWasmType) {
1022
+ const p = this._emitTimeDecomposeParts(expr);
1023
+ this.pushInstruction({ op: "local.get", index: p.remSecTmp });
1024
+ this.pushInstruction({ op: "i64.const", value: 3600n });
1025
+ this.pushInstruction("i64.rem_s");
1026
+ this.pushInstruction({ op: "i64.const", value: 60n });
1027
+ this.pushInstruction("i64.div_s");
1028
+ this.pushInstruction("i32.wrap_i64");
1029
+ if (targetWasmType === "i64") this.pushInstruction("i64.extend_i32_s");
1030
+ this._releaseTimeDecomposeParts(p);
1031
+ }
1032
+
1033
+ _emitTimeMethodSecond(expr, targetWasmType) {
1034
+ const p = this._emitTimeDecomposeParts(expr);
1035
+ this.pushInstruction({ op: "local.get", index: p.remSecTmp });
1036
+ this.pushInstruction({ op: "i64.const", value: 60n });
1037
+ this.pushInstruction("i64.rem_s");
1038
+ this.pushInstruction("i32.wrap_i64");
1039
+ if (targetWasmType === "i64") this.pushInstruction("i64.extend_i32_s");
1040
+ this._releaseTimeDecomposeParts(p);
1041
+ }
1042
+
1043
+ _emitTimeMethodWeekday(expr, targetWasmType) {
1044
+ const p = this._emitTimeDecomposeParts(expr);
1045
+ const wdTmp = this.acquireTemp("i32");
1046
+ this.pushInstruction({ op: "local.get", index: p.daysTmp });
1047
+ this.pushInstruction({ op: "i64.const", value: 4n });
1048
+ this.pushInstruction("i64.add");
1049
+ this.pushInstruction({ op: "i64.const", value: 7n });
1050
+ this.pushInstruction("i64.rem_s");
1051
+ this.pushInstruction("i32.wrap_i64");
1052
+ this.pushInstruction({ op: "local.tee", index: wdTmp });
1053
+ this.pushInstruction({ op: "i32.const", value: 0 });
1054
+ this.pushInstruction("i32.lt_s");
1055
+ this.pushInstruction({ op: "if", blockType: "void" });
1056
+ this.pushInstruction({ op: "local.get", index: wdTmp });
1057
+ this.pushInstruction({ op: "i32.const", value: 7 });
1058
+ this.pushInstruction("i32.add");
1059
+ this.pushInstruction({ op: "local.set", index: wdTmp });
1060
+ this.pushInstruction("end");
1061
+
1062
+ this.pushInstruction({ op: "local.get", index: wdTmp });
1063
+ if (targetWasmType === "i64") this.pushInstruction("i64.extend_i32_s");
1064
+ this.releaseTemp(wdTmp, "i32");
1065
+ this._releaseTimeDecomposeParts(p);
1066
+ }
1067
+
1068
+ _emitTimeMethodYMD(expr, targetWasmType, partIdx) {
1069
+ const p = this._emitTimeDecomposeParts(expr);
1070
+ const yTmp = this.acquireTemp("i32");
1071
+ const mTmp = this.acquireTemp("i32");
1072
+ const dTmp = this.acquireTemp("i32");
1073
+ this._emitCivilDateFromDays(p.daysTmp, yTmp, mTmp, dTmp);
1074
+ this.pushInstruction({
1075
+ op: "local.get",
1076
+ index: partIdx === 0 ? yTmp : partIdx === 1 ? mTmp : dTmp,
1077
+ });
1078
+ if (targetWasmType === "i64") this.pushInstruction("i64.extend_i32_s");
1079
+ this.releaseTemp(dTmp, "i32");
1080
+ this.releaseTemp(mTmp, "i32");
1081
+ this.releaseTemp(yTmp, "i32");
1082
+ this._releaseTimeDecomposeParts(p);
1083
+ }
1084
+
1085
+ _releaseTimeDecomposeParts(p) {
1086
+ this.releaseTemp(p.nanoTmp, "i64");
1087
+ this.releaseTemp(p.offTmp, "i32");
1088
+ this.releaseTemp(p.remSecTmp, "i64");
1089
+ this.releaseTemp(p.daysTmp, "i64");
1090
+ this.releaseTemp(p.localSecTmp, "i64");
1091
+ this.releaseTemp(p.rTmp, p.timeW);
1092
+ }
1093
+
1094
+ _emitTimeMethodFormat(expr, args, _targetWasmType) {
1095
+ const p = this._emitTimeDecomposeParts(expr);
1096
+ const layoutTmp = this.acquireTemp("externref");
1097
+ this.emitExpr(args[0], "externref");
1098
+ this.pushInstruction({ op: "local.set", index: layoutTmp });
1099
+
1100
+ const yTmp = this.acquireTemp("i32");
1101
+ const mTmp = this.acquireTemp("i32");
1102
+ const dTmp = this.acquireTemp("i32");
1103
+ this._emitCivilDateFromDays(p.daysTmp, yTmp, mTmp, dTmp);
1104
+
1105
+ // hr = remSec / 3600
1106
+ const hrTmp = this.acquireTemp("i32");
1107
+ this.pushInstruction({ op: "local.get", index: p.remSecTmp });
1108
+ this.pushInstruction({ op: "i64.const", value: 3600n });
1109
+ this.pushInstruction("i64.div_s");
1110
+ this.pushInstruction("i32.wrap_i64");
1111
+ this.pushInstruction({ op: "local.set", index: hrTmp });
1112
+
1113
+ // min = (remSec % 3600) / 60
1114
+ const minTmp = this.acquireTemp("i32");
1115
+ this.pushInstruction({ op: "local.get", index: p.remSecTmp });
1116
+ this.pushInstruction({ op: "i64.const", value: 3600n });
1117
+ this.pushInstruction("i64.rem_s");
1118
+ this.pushInstruction({ op: "i64.const", value: 60n });
1119
+ this.pushInstruction("i64.div_s");
1120
+ this.pushInstruction("i32.wrap_i64");
1121
+ this.pushInstruction({ op: "local.set", index: minTmp });
1122
+
1123
+ // sec = remSec % 60
1124
+ const secTmp = this.acquireTemp("i32");
1125
+ this.pushInstruction({ op: "local.get", index: p.remSecTmp });
1126
+ this.pushInstruction({ op: "i64.const", value: 60n });
1127
+ this.pushInstruction("i64.rem_s");
1128
+ this.pushInstruction("i32.wrap_i64");
1129
+ this.pushInstruction({ op: "local.set", index: secTmp });
1130
+
1131
+ // wd = (days + 4) % 7
1132
+ const wdTmp = this.acquireTemp("i32");
1133
+ this.pushInstruction({ op: "local.get", index: p.daysTmp });
1134
+ this.pushInstruction({ op: "i64.const", value: 4n });
1135
+ this.pushInstruction("i64.add");
1136
+ this.pushInstruction({ op: "i64.const", value: 7n });
1137
+ this.pushInstruction("i64.rem_s");
1138
+ this.pushInstruction("i32.wrap_i64");
1139
+ this.pushInstruction({ op: "local.tee", index: wdTmp });
1140
+ this.pushInstruction({ op: "i32.const", value: 0 });
1141
+ this.pushInstruction("i32.lt_s");
1142
+ this.pushInstruction({ op: "if", blockType: "void" });
1143
+ this.pushInstruction({ op: "local.get", index: wdTmp });
1144
+ this.pushInstruction({ op: "i32.const", value: 7 });
1145
+ this.pushInstruction("i32.add");
1146
+ this.pushInstruction({ op: "local.set", index: wdTmp });
1147
+ this.pushInstruction("end");
1148
+
1149
+ // ms = i32((nanoTmp % 1000000000n) / 1000000n)
1150
+ const msTmp = this.acquireTemp("i32");
1151
+ this.pushInstruction({ op: "local.get", index: p.nanoTmp });
1152
+ this.pushInstruction({ op: "i64.const", value: 1000000000n });
1153
+ this.pushInstruction("i64.rem_s");
1154
+ this.pushInstruction({ op: "i64.const", value: 1000000n });
1155
+ this.pushInstruction("i64.div_s");
1156
+ this.pushInstruction("i32.wrap_i64");
1157
+ this.pushInstruction({ op: "local.tee", index: msTmp });
1158
+ this.pushInstruction({ op: "i32.const", value: 0 });
1159
+ this.pushInstruction("i32.lt_s");
1160
+ this.pushInstruction({ op: "if", blockType: "void" });
1161
+ this.pushInstruction({ op: "local.get", index: msTmp });
1162
+ this.pushInstruction({ op: "i32.const", value: 1000 });
1163
+ this.pushInstruction("i32.add");
1164
+ this.pushInstruction({ op: "local.set", index: msTmp });
1165
+ this.pushInstruction("end");
1166
+
1167
+ // Call time_format(y, m, d, hr, min, sec, wd, ms, off, layout)
1168
+ this.pushInstruction({ op: "local.get", index: yTmp });
1169
+ this.pushInstruction({ op: "local.get", index: mTmp });
1170
+ this.pushInstruction({ op: "local.get", index: dTmp });
1171
+ this.pushInstruction({ op: "local.get", index: hrTmp });
1172
+ this.pushInstruction({ op: "local.get", index: minTmp });
1173
+ this.pushInstruction({ op: "local.get", index: secTmp });
1174
+ this.pushInstruction({ op: "local.get", index: wdTmp });
1175
+ this.pushInstruction({ op: "local.get", index: msTmp });
1176
+ this.pushInstruction({ op: "local.get", index: p.offTmp });
1177
+ this.pushInstruction({ op: "local.get", index: layoutTmp });
1178
+ this._callStdlib("time_format");
1179
+
1180
+ this.releaseTemp(msTmp, "i32");
1181
+ this.releaseTemp(wdTmp, "i32");
1182
+ this.releaseTemp(secTmp, "i32");
1183
+ this.releaseTemp(minTmp, "i32");
1184
+ this.releaseTemp(hrTmp, "i32");
1185
+ this.releaseTemp(dTmp, "i32");
1186
+ this.releaseTemp(mTmp, "i32");
1187
+ this.releaseTemp(yTmp, "i32");
1188
+ this.releaseTemp(layoutTmp, "externref");
1189
+ this._releaseTimeDecomposeParts(p);
1190
+ }
1191
+
1192
+ _emitTimeMethodString(expr, targetWasmType) {
1193
+ const strLit = {
1194
+ kind: "BasicLit",
1195
+ litKind: "STRING",
1196
+ value: "2006-01-02T15:04:05Z07:00",
1197
+ };
1198
+ this._emitTimeMethodFormat(expr, [strLit], targetWasmType);
1199
+ }
1200
+ }