jz 0.8.1 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +56 -9
- package/bench/README.md +121 -50
- package/bench/bench.svg +27 -27
- package/cli.js +3 -1
- package/dist/interop.js +1 -1
- package/dist/jz.js +7541 -6271
- package/index.js +165 -74
- package/interop.js +189 -17
- package/jzify/arguments.js +32 -1
- package/jzify/async.js +409 -0
- package/jzify/classes.js +136 -18
- package/jzify/generators.js +639 -0
- package/jzify/hoist-vars.js +73 -1
- package/jzify/index.js +123 -4
- package/jzify/names.js +1 -0
- package/jzify/transform.js +239 -1
- package/layout.js +48 -3
- package/module/array.js +299 -44
- package/module/atomics.js +144 -0
- package/module/collection.js +1429 -155
- package/module/core.js +431 -40
- package/module/date.js +142 -120
- package/module/fs.js +144 -0
- package/module/function.js +6 -3
- package/module/index.js +4 -1
- package/module/json.js +270 -49
- package/module/math.js +892 -32
- package/module/number.js +532 -163
- package/module/object.js +353 -95
- package/module/regex.js +157 -7
- package/module/schema.js +100 -2
- package/module/string.js +301 -84
- package/module/typedarray.js +264 -72
- package/module/web.js +36 -0
- package/package.json +5 -5
- package/src/abi/string.js +71 -5
- package/src/ast.js +11 -5
- package/src/autoload.js +28 -1
- package/src/bridge.js +7 -2
- package/src/compile/analyze-scans.js +22 -7
- package/src/compile/analyze.js +136 -30
- package/src/compile/dyn-closure-tables.js +277 -0
- package/src/compile/emit-assign.js +281 -15
- package/src/compile/emit.js +979 -54
- package/src/compile/index.js +271 -29
- package/src/compile/infer.js +34 -3
- package/src/compile/inplace-store.js +329 -0
- package/src/compile/narrow.js +543 -15
- package/src/compile/peel-stencil.js +5 -0
- package/src/compile/plan/index.js +45 -3
- package/src/compile/plan/inline.js +8 -1
- package/src/compile/plan/literals.js +39 -0
- package/src/compile/plan/scope.js +430 -23
- package/src/compile/program-facts.js +732 -38
- package/src/ctx.js +64 -9
- package/src/helper-counters.js +7 -1
- package/src/ir.js +113 -5
- package/src/kind-traits.js +66 -3
- package/src/kind.js +84 -12
- package/src/op-policy.js +7 -4
- package/src/optimize/index.js +1060 -750
- package/src/optimize/recurse.js +2 -2
- package/src/optimize/vectorize.js +972 -67
- package/src/prepare/index.js +792 -63
- package/src/prepare/math-kernel.js +331 -0
- package/src/prepare/pre-eval.js +714 -0
- package/src/snapshot.js +194 -0
- package/src/type.js +1170 -56
- package/src/wat/assemble.js +403 -65
- package/src/wat/codegen.js +74 -14
- package/transform.js +113 -4
- package/wasi.js +3 -0
package/module/date.js
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* @module date
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import { typed, asF64, toNumF64, allocPtr, temp } from '../src/ir.js'
|
|
12
|
+
import { typed, asF64, toNumF64, allocPtr, temp, NULL_WAT } from '../src/ir.js'
|
|
13
13
|
import { emit, deps } from '../src/bridge.js'
|
|
14
14
|
import { inc, PTR } from '../src/ctx.js'
|
|
15
15
|
import { VAL } from '../src/reps.js'
|
|
@@ -51,10 +51,23 @@ export default (ctx) => {
|
|
|
51
51
|
__date_write2: [],
|
|
52
52
|
__date_write3: [],
|
|
53
53
|
__date_write4: [],
|
|
54
|
-
__date_to_iso_string: ['__mkstr', '__alloc', '
|
|
55
|
-
__date_to_utc_string: ['__mkstr', '__alloc', '__itoa', '__date_weekday', '__date_date_from_time', '__date_month_from_time', '__date_year_from_time', '__date_hour_from_time', '__date_min_from_time', '__date_sec_from_time', '__date_write2', '__date_write4'],
|
|
54
|
+
__date_to_iso_string: ['__mkstr', '__alloc', '__date_year_from_time', '__date_month_from_time', '__date_date_from_time', '__date_hour_from_time', '__date_min_from_time', '__date_sec_from_time', '__date_ms_from_time', '__date_write2', '__date_write3', '__date_write4'],
|
|
55
|
+
__date_to_utc_string: ['__mkstr', '__alloc', '__itoa', '__date_wd_name', '__date_mon_name', '__date_weekday', '__date_date_from_time', '__date_month_from_time', '__date_year_from_time', '__date_hour_from_time', '__date_min_from_time', '__date_sec_from_time', '__date_write2', '__date_write4'],
|
|
56
|
+
__date_wd_name: [],
|
|
57
|
+
__date_mon_name: [],
|
|
58
|
+
__date_invalid_string: ['__alloc', '__mkstr'],
|
|
59
|
+
__date_to_date_string: ['__mkstr', '__alloc', '__itoa', '__date_invalid_string', '__date_wd_name', '__date_mon_name', '__date_weekday', '__date_month_from_time', '__date_date_from_time', '__date_year_from_time', '__date_write2', '__date_write4'],
|
|
60
|
+
__date_to_time_string: ['__mkstr', '__alloc', '__date_invalid_string', '__date_hour_from_time', '__date_min_from_time', '__date_sec_from_time', '__date_write2'],
|
|
61
|
+
__date_to_json: ['__date_to_iso_string'],
|
|
56
62
|
})
|
|
57
63
|
|
|
64
|
+
// Brand: dates carry their own registered 1-slot schema (a key no user
|
|
65
|
+
// identifier can produce) instead of aux=0 — which aliases schema id 0, the
|
|
66
|
+
// first real literal shape, so dyn-get / {...date} / structuredClone would
|
|
67
|
+
// read that schema's layout against the date's single-slot block. With the
|
|
68
|
+
// brand, every generic OBJECT consumer sees the true shape.
|
|
69
|
+
ctx.schema.dateSid = ctx.schema.register(['\x00time'])
|
|
70
|
+
|
|
58
71
|
const dateArg = (node, fallback, required = false) => {
|
|
59
72
|
if (node === undefined) return typed(['f64.const', required ? NaN : fallback], 'f64')
|
|
60
73
|
if (Array.isArray(node) && node[0] == null && node[1] === undefined) return typed(['f64.const', NaN], 'f64')
|
|
@@ -381,27 +394,59 @@ export default (ctx) => {
|
|
|
381
394
|
(i32.store8 (i32.add (local.get $buf) (i32.const 2)) (i32.add (i32.const 48) (local.get $d)))
|
|
382
395
|
(i32.store8 (i32.add (local.get $buf) (i32.const 3)) (i32.add (i32.const 48) (i32.rem_u (local.get $v) (i32.const 10)))))`
|
|
383
396
|
|
|
397
|
+
// ── Name tables & fixed text ──────────────────────────────────────────────
|
|
398
|
+
// 3-letter weekday/month names as generated if-chains of byte stores — one
|
|
399
|
+
// table shared by toUTCString and toDateString.
|
|
400
|
+
|
|
401
|
+
const name3 = (fn, names) => `(func $${fn} (param $p i32) (param $i i32)
|
|
402
|
+
${names.map((n, i) => `(if (i32.eq (local.get $i) (i32.const ${i}))
|
|
403
|
+
(then
|
|
404
|
+
(i32.store8 (local.get $p) (i32.const ${n.charCodeAt(0)}))
|
|
405
|
+
(i32.store8 (i32.add (local.get $p) (i32.const 1)) (i32.const ${n.charCodeAt(1)}))
|
|
406
|
+
(i32.store8 (i32.add (local.get $p) (i32.const 2)) (i32.const ${n.charCodeAt(2)}))))`).join('\n ')})`
|
|
407
|
+
|
|
408
|
+
ctx.core.stdlib['__date_wd_name'] = name3('__date_wd_name', ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'])
|
|
409
|
+
ctx.core.stdlib['__date_mon_name'] = name3('__date_mon_name', ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'])
|
|
410
|
+
|
|
411
|
+
// WAT fragment: store a fixed ASCII run at cursor $p, advance $p past it.
|
|
412
|
+
const storeLit = (s) => {
|
|
413
|
+
let out = ''
|
|
414
|
+
for (let k = 0; k < s.length; k++)
|
|
415
|
+
out += `(i32.store8 ${k ? `(i32.add (local.get $p) (i32.const ${k}))` : '(local.get $p)'} (i32.const ${s.charCodeAt(k)}))\n `
|
|
416
|
+
return out + `(local.set $p (i32.add (local.get $p) (i32.const ${s.length})))`
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
ctx.core.stdlib['__date_invalid_string'] = `(func $__date_invalid_string (result f64)
|
|
420
|
+
(local $buf i32) (local $p i32)
|
|
421
|
+
(local.set $buf (call $__alloc (i32.const 12)))
|
|
422
|
+
(local.set $p (local.get $buf))
|
|
423
|
+
${storeLit('Invalid Date')}
|
|
424
|
+
(call $__mkstr (local.get $buf) (i32.const 12)))`
|
|
425
|
+
|
|
384
426
|
// ── toISOString ───────────────────────────────────────────────────────────
|
|
385
427
|
|
|
386
428
|
ctx.core.stdlib['__date_to_iso_string'] = `(func $__date_to_iso_string (param $t f64) (result f64)
|
|
387
|
-
(local $buf i32) (local $p i32) (local $year f64) (local $yv i32)
|
|
429
|
+
(local $buf i32) (local $p i32) (local $year f64) (local $yv i32)
|
|
388
430
|
(if (f64.ne (local.get $t) (local.get $t)) (then (return (call $__mkstr (i32.const 0) (i32.const 0)))))
|
|
389
431
|
(local.set $buf (call $__alloc (i32.const 40)))
|
|
390
432
|
(local.set $p (local.get $buf))
|
|
391
433
|
(local.set $year (call $__date_year_from_time (local.get $t)))
|
|
392
|
-
(if (f64.
|
|
434
|
+
(if (i32.and (f64.ge (local.get $year) (f64.const 0)) (f64.le (local.get $year) (f64.const 9999)))
|
|
393
435
|
(then
|
|
394
|
-
(
|
|
395
|
-
(local.set $p (i32.add (local.get $p) (i32.const 1)))
|
|
396
|
-
(local.set $year (f64.neg (local.get $year)))))
|
|
397
|
-
(local.set $yv (i32.trunc_sat_f64_u (local.get $year)))
|
|
398
|
-
(if (i32.le_u (local.get $yv) (i32.const 9999))
|
|
399
|
-
(then
|
|
400
|
-
(call $__date_write4 (local.get $p) (local.get $yv))
|
|
436
|
+
(call $__date_write4 (local.get $p) (i32.trunc_sat_f64_u (local.get $year)))
|
|
401
437
|
(local.set $p (i32.add (local.get $p) (i32.const 4))))
|
|
402
438
|
(else
|
|
403
|
-
|
|
404
|
-
(
|
|
439
|
+
;; expanded years (spec: DateString): explicit sign + 6-digit zero-padded
|
|
440
|
+
(if (f64.lt (local.get $year) (f64.const 0))
|
|
441
|
+
(then
|
|
442
|
+
(i32.store8 (local.get $p) (i32.const 45))
|
|
443
|
+
(local.set $year (f64.neg (local.get $year))))
|
|
444
|
+
(else (i32.store8 (local.get $p) (i32.const 43))))
|
|
445
|
+
(local.set $p (i32.add (local.get $p) (i32.const 1)))
|
|
446
|
+
(local.set $yv (i32.trunc_sat_f64_u (local.get $year)))
|
|
447
|
+
(call $__date_write2 (local.get $p) (i32.div_u (local.get $yv) (i32.const 10000)))
|
|
448
|
+
(call $__date_write4 (i32.add (local.get $p) (i32.const 2)) (i32.rem_u (local.get $yv) (i32.const 10000)))
|
|
449
|
+
(local.set $p (i32.add (local.get $p) (i32.const 6)))))
|
|
405
450
|
(i32.store8 (local.get $p) (i32.const 45))
|
|
406
451
|
(local.set $p (i32.add (local.get $p) (i32.const 1)))
|
|
407
452
|
(call $__date_write2 (local.get $p) (i32.add (i32.trunc_sat_f64_s (call $__date_month_from_time (local.get $t))) (i32.const 1)))
|
|
@@ -433,118 +478,19 @@ export default (ctx) => {
|
|
|
433
478
|
// ── toUTCString ───────────────────────────────────────────────────────────
|
|
434
479
|
|
|
435
480
|
ctx.core.stdlib['__date_to_utc_string'] = `(func $__date_to_utc_string (param $t f64) (result f64)
|
|
436
|
-
(local $buf i32) (local $p i32) (local $
|
|
481
|
+
(local $buf i32) (local $p i32) (local $year f64) (local $yv i32) (local $nd i32)
|
|
437
482
|
(if (f64.ne (local.get $t) (local.get $t)) (then (return (call $__mkstr (i32.const 0) (i32.const 0)))))
|
|
438
483
|
(local.set $buf (call $__alloc (i32.const 48)))
|
|
439
484
|
(local.set $p (local.get $buf))
|
|
440
|
-
(local.
|
|
441
|
-
(if (i32.eq (local.get $wd) (i32.const 0))
|
|
442
|
-
(then
|
|
443
|
-
(i32.store8 (local.get $p) (i32.const 83))
|
|
444
|
-
(i32.store8 (i32.add (local.get $p) (i32.const 1)) (i32.const 117))
|
|
445
|
-
(i32.store8 (i32.add (local.get $p) (i32.const 2)) (i32.const 110))))
|
|
446
|
-
(if (i32.eq (local.get $wd) (i32.const 1))
|
|
447
|
-
(then
|
|
448
|
-
(i32.store8 (local.get $p) (i32.const 77))
|
|
449
|
-
(i32.store8 (i32.add (local.get $p) (i32.const 1)) (i32.const 111))
|
|
450
|
-
(i32.store8 (i32.add (local.get $p) (i32.const 2)) (i32.const 110))))
|
|
451
|
-
(if (i32.eq (local.get $wd) (i32.const 2))
|
|
452
|
-
(then
|
|
453
|
-
(i32.store8 (local.get $p) (i32.const 84))
|
|
454
|
-
(i32.store8 (i32.add (local.get $p) (i32.const 1)) (i32.const 117))
|
|
455
|
-
(i32.store8 (i32.add (local.get $p) (i32.const 2)) (i32.const 101))))
|
|
456
|
-
(if (i32.eq (local.get $wd) (i32.const 3))
|
|
457
|
-
(then
|
|
458
|
-
(i32.store8 (local.get $p) (i32.const 87))
|
|
459
|
-
(i32.store8 (i32.add (local.get $p) (i32.const 1)) (i32.const 101))
|
|
460
|
-
(i32.store8 (i32.add (local.get $p) (i32.const 2)) (i32.const 100))))
|
|
461
|
-
(if (i32.eq (local.get $wd) (i32.const 4))
|
|
462
|
-
(then
|
|
463
|
-
(i32.store8 (local.get $p) (i32.const 84))
|
|
464
|
-
(i32.store8 (i32.add (local.get $p) (i32.const 1)) (i32.const 104))
|
|
465
|
-
(i32.store8 (i32.add (local.get $p) (i32.const 2)) (i32.const 117))))
|
|
466
|
-
(if (i32.eq (local.get $wd) (i32.const 5))
|
|
467
|
-
(then
|
|
468
|
-
(i32.store8 (local.get $p) (i32.const 70))
|
|
469
|
-
(i32.store8 (i32.add (local.get $p) (i32.const 1)) (i32.const 114))
|
|
470
|
-
(i32.store8 (i32.add (local.get $p) (i32.const 2)) (i32.const 105))))
|
|
471
|
-
(if (i32.eq (local.get $wd) (i32.const 6))
|
|
472
|
-
(then
|
|
473
|
-
(i32.store8 (local.get $p) (i32.const 83))
|
|
474
|
-
(i32.store8 (i32.add (local.get $p) (i32.const 1)) (i32.const 97))
|
|
475
|
-
(i32.store8 (i32.add (local.get $p) (i32.const 2)) (i32.const 116))))
|
|
485
|
+
(call $__date_wd_name (local.get $p) (i32.trunc_sat_f64_s (call $__date_weekday (local.get $t))))
|
|
476
486
|
(local.set $p (i32.add (local.get $p) (i32.const 3)))
|
|
477
|
-
|
|
478
|
-
(i32.store8 (i32.add (local.get $p) (i32.const 1)) (i32.const 32))
|
|
479
|
-
(local.set $p (i32.add (local.get $p) (i32.const 2)))
|
|
487
|
+
${storeLit(', ')}
|
|
480
488
|
(call $__date_write2 (local.get $p) (i32.trunc_sat_f64_s (call $__date_date_from_time (local.get $t))))
|
|
481
489
|
(local.set $p (i32.add (local.get $p) (i32.const 2)))
|
|
482
|
-
|
|
483
|
-
(local.
|
|
484
|
-
(local.set $month (i32.trunc_sat_f64_s (call $__date_month_from_time (local.get $t))))
|
|
485
|
-
(if (i32.eq (local.get $month) (i32.const 0))
|
|
486
|
-
(then
|
|
487
|
-
(i32.store8 (local.get $p) (i32.const 74))
|
|
488
|
-
(i32.store8 (i32.add (local.get $p) (i32.const 1)) (i32.const 97))
|
|
489
|
-
(i32.store8 (i32.add (local.get $p) (i32.const 2)) (i32.const 110))))
|
|
490
|
-
(if (i32.eq (local.get $month) (i32.const 1))
|
|
491
|
-
(then
|
|
492
|
-
(i32.store8 (local.get $p) (i32.const 70))
|
|
493
|
-
(i32.store8 (i32.add (local.get $p) (i32.const 1)) (i32.const 101))
|
|
494
|
-
(i32.store8 (i32.add (local.get $p) (i32.const 2)) (i32.const 98))))
|
|
495
|
-
(if (i32.eq (local.get $month) (i32.const 2))
|
|
496
|
-
(then
|
|
497
|
-
(i32.store8 (local.get $p) (i32.const 77))
|
|
498
|
-
(i32.store8 (i32.add (local.get $p) (i32.const 1)) (i32.const 97))
|
|
499
|
-
(i32.store8 (i32.add (local.get $p) (i32.const 2)) (i32.const 114))))
|
|
500
|
-
(if (i32.eq (local.get $month) (i32.const 3))
|
|
501
|
-
(then
|
|
502
|
-
(i32.store8 (local.get $p) (i32.const 65))
|
|
503
|
-
(i32.store8 (i32.add (local.get $p) (i32.const 1)) (i32.const 112))
|
|
504
|
-
(i32.store8 (i32.add (local.get $p) (i32.const 2)) (i32.const 114))))
|
|
505
|
-
(if (i32.eq (local.get $month) (i32.const 4))
|
|
506
|
-
(then
|
|
507
|
-
(i32.store8 (local.get $p) (i32.const 77))
|
|
508
|
-
(i32.store8 (i32.add (local.get $p) (i32.const 1)) (i32.const 97))
|
|
509
|
-
(i32.store8 (i32.add (local.get $p) (i32.const 2)) (i32.const 121))))
|
|
510
|
-
(if (i32.eq (local.get $month) (i32.const 5))
|
|
511
|
-
(then
|
|
512
|
-
(i32.store8 (local.get $p) (i32.const 74))
|
|
513
|
-
(i32.store8 (i32.add (local.get $p) (i32.const 1)) (i32.const 117))
|
|
514
|
-
(i32.store8 (i32.add (local.get $p) (i32.const 2)) (i32.const 110))))
|
|
515
|
-
(if (i32.eq (local.get $month) (i32.const 6))
|
|
516
|
-
(then
|
|
517
|
-
(i32.store8 (local.get $p) (i32.const 74))
|
|
518
|
-
(i32.store8 (i32.add (local.get $p) (i32.const 1)) (i32.const 117))
|
|
519
|
-
(i32.store8 (i32.add (local.get $p) (i32.const 2)) (i32.const 108))))
|
|
520
|
-
(if (i32.eq (local.get $month) (i32.const 7))
|
|
521
|
-
(then
|
|
522
|
-
(i32.store8 (local.get $p) (i32.const 65))
|
|
523
|
-
(i32.store8 (i32.add (local.get $p) (i32.const 1)) (i32.const 117))
|
|
524
|
-
(i32.store8 (i32.add (local.get $p) (i32.const 2)) (i32.const 103))))
|
|
525
|
-
(if (i32.eq (local.get $month) (i32.const 8))
|
|
526
|
-
(then
|
|
527
|
-
(i32.store8 (local.get $p) (i32.const 83))
|
|
528
|
-
(i32.store8 (i32.add (local.get $p) (i32.const 1)) (i32.const 101))
|
|
529
|
-
(i32.store8 (i32.add (local.get $p) (i32.const 2)) (i32.const 112))))
|
|
530
|
-
(if (i32.eq (local.get $month) (i32.const 9))
|
|
531
|
-
(then
|
|
532
|
-
(i32.store8 (local.get $p) (i32.const 79))
|
|
533
|
-
(i32.store8 (i32.add (local.get $p) (i32.const 1)) (i32.const 99))
|
|
534
|
-
(i32.store8 (i32.add (local.get $p) (i32.const 2)) (i32.const 116))))
|
|
535
|
-
(if (i32.eq (local.get $month) (i32.const 10))
|
|
536
|
-
(then
|
|
537
|
-
(i32.store8 (local.get $p) (i32.const 78))
|
|
538
|
-
(i32.store8 (i32.add (local.get $p) (i32.const 1)) (i32.const 111))
|
|
539
|
-
(i32.store8 (i32.add (local.get $p) (i32.const 2)) (i32.const 118))))
|
|
540
|
-
(if (i32.eq (local.get $month) (i32.const 11))
|
|
541
|
-
(then
|
|
542
|
-
(i32.store8 (local.get $p) (i32.const 68))
|
|
543
|
-
(i32.store8 (i32.add (local.get $p) (i32.const 1)) (i32.const 101))
|
|
544
|
-
(i32.store8 (i32.add (local.get $p) (i32.const 2)) (i32.const 99))))
|
|
490
|
+
${storeLit(' ')}
|
|
491
|
+
(call $__date_mon_name (local.get $p) (i32.trunc_sat_f64_s (call $__date_month_from_time (local.get $t))))
|
|
545
492
|
(local.set $p (i32.add (local.get $p) (i32.const 3)))
|
|
546
|
-
|
|
547
|
-
(local.set $p (i32.add (local.get $p) (i32.const 1)))
|
|
493
|
+
${storeLit(' ')}
|
|
548
494
|
(local.set $year (call $__date_year_from_time (local.get $t)))
|
|
549
495
|
(if (f64.lt (local.get $year) (f64.const 0))
|
|
550
496
|
(then
|
|
@@ -578,6 +524,63 @@ export default (ctx) => {
|
|
|
578
524
|
(local.set $p (i32.add (local.get $p) (i32.const 4)))
|
|
579
525
|
(call $__mkstr (local.get $buf) (i32.sub (local.get $p) (local.get $buf))))`
|
|
580
526
|
|
|
527
|
+
// ── toDateString / toTimeString / toJSON ──────────────────────────────────
|
|
528
|
+
// jz is UTC-only: the "local" date/time slices are the UTC ones and the zone
|
|
529
|
+
// suffix is the fixed UTC designation — a documented divergence, same policy
|
|
530
|
+
// as getHours ≡ getUTCHours.
|
|
531
|
+
|
|
532
|
+
ctx.core.stdlib['__date_to_date_string'] = `(func $__date_to_date_string (param $t f64) (result f64)
|
|
533
|
+
(local $buf i32) (local $p i32) (local $year f64) (local $yv i32) (local $nd i32)
|
|
534
|
+
(if (f64.ne (local.get $t) (local.get $t)) (then (return (call $__date_invalid_string))))
|
|
535
|
+
(local.set $buf (call $__alloc (i32.const 32)))
|
|
536
|
+
(local.set $p (local.get $buf))
|
|
537
|
+
(call $__date_wd_name (local.get $p) (i32.trunc_sat_f64_s (call $__date_weekday (local.get $t))))
|
|
538
|
+
(local.set $p (i32.add (local.get $p) (i32.const 3)))
|
|
539
|
+
${storeLit(' ')}
|
|
540
|
+
(call $__date_mon_name (local.get $p) (i32.trunc_sat_f64_s (call $__date_month_from_time (local.get $t))))
|
|
541
|
+
(local.set $p (i32.add (local.get $p) (i32.const 3)))
|
|
542
|
+
${storeLit(' ')}
|
|
543
|
+
(call $__date_write2 (local.get $p) (i32.trunc_sat_f64_s (call $__date_date_from_time (local.get $t))))
|
|
544
|
+
(local.set $p (i32.add (local.get $p) (i32.const 2)))
|
|
545
|
+
${storeLit(' ')}
|
|
546
|
+
(local.set $year (call $__date_year_from_time (local.get $t)))
|
|
547
|
+
(if (f64.lt (local.get $year) (f64.const 0))
|
|
548
|
+
(then
|
|
549
|
+
(i32.store8 (local.get $p) (i32.const 45))
|
|
550
|
+
(local.set $p (i32.add (local.get $p) (i32.const 1)))
|
|
551
|
+
(local.set $year (f64.neg (local.get $year)))))
|
|
552
|
+
(local.set $yv (i32.trunc_sat_f64_u (local.get $year)))
|
|
553
|
+
(if (i32.le_u (local.get $yv) (i32.const 9999))
|
|
554
|
+
(then
|
|
555
|
+
(call $__date_write4 (local.get $p) (local.get $yv))
|
|
556
|
+
(local.set $p (i32.add (local.get $p) (i32.const 4))))
|
|
557
|
+
(else
|
|
558
|
+
(local.set $nd (call $__itoa (local.get $yv) (local.get $p)))
|
|
559
|
+
(local.set $p (i32.add (local.get $p) (local.get $nd)))))
|
|
560
|
+
(call $__mkstr (local.get $buf) (i32.sub (local.get $p) (local.get $buf))))`
|
|
561
|
+
|
|
562
|
+
ctx.core.stdlib['__date_to_time_string'] = `(func $__date_to_time_string (param $t f64) (result f64)
|
|
563
|
+
(local $buf i32) (local $p i32)
|
|
564
|
+
(if (f64.ne (local.get $t) (local.get $t)) (then (return (call $__date_invalid_string))))
|
|
565
|
+
(local.set $buf (call $__alloc (i32.const 48)))
|
|
566
|
+
(local.set $p (local.get $buf))
|
|
567
|
+
(call $__date_write2 (local.get $p) (i32.trunc_sat_f64_s (call $__date_hour_from_time (local.get $t))))
|
|
568
|
+
(local.set $p (i32.add (local.get $p) (i32.const 2)))
|
|
569
|
+
${storeLit(':')}
|
|
570
|
+
(call $__date_write2 (local.get $p) (i32.trunc_sat_f64_s (call $__date_min_from_time (local.get $t))))
|
|
571
|
+
(local.set $p (i32.add (local.get $p) (i32.const 2)))
|
|
572
|
+
${storeLit(':')}
|
|
573
|
+
(call $__date_write2 (local.get $p) (i32.trunc_sat_f64_s (call $__date_sec_from_time (local.get $t))))
|
|
574
|
+
(local.set $p (i32.add (local.get $p) (i32.const 2)))
|
|
575
|
+
${storeLit(' GMT+0000 (Coordinated Universal Time)')}
|
|
576
|
+
(call $__mkstr (local.get $buf) (i32.sub (local.get $p) (local.get $buf))))`
|
|
577
|
+
|
|
578
|
+
// Serialization protocol: invalid date → null (JSON.stringify emits null),
|
|
579
|
+
// finite date → ISO string.
|
|
580
|
+
ctx.core.stdlib['__date_to_json'] = `(func $__date_to_json (param $t f64) (result f64)
|
|
581
|
+
(if (f64.ne (local.get $t) (local.get $t)) (then (return ${NULL_WAT})))
|
|
582
|
+
(call $__date_to_iso_string (local.get $t)))`
|
|
583
|
+
|
|
581
584
|
// === Minimal Date value object ===
|
|
582
585
|
// Represented as PTR.OBJECT with a single f64 slot at offset 0 (the time value).
|
|
583
586
|
// No schemaId (aux=0); dynamic property access falls through to undefined.
|
|
@@ -603,7 +606,7 @@ export default (ctx) => {
|
|
|
603
606
|
inc('__date_from_value')
|
|
604
607
|
timeVal = typed(['call', '$__date_from_value', ['i64.reinterpret_f64', asF64(emit(ms))]], 'f64')
|
|
605
608
|
}
|
|
606
|
-
const out = allocPtr({ type: PTR.OBJECT, len: 1, cap: 1, stride: 8, tag: 'date' })
|
|
609
|
+
const out = allocPtr({ type: PTR.OBJECT, aux: ctx.schema.dateSid, len: 1, cap: 1, stride: 8, tag: 'date' })
|
|
607
610
|
return typed(['block', ['result', 'f64'],
|
|
608
611
|
out.init,
|
|
609
612
|
['f64.store', ['local.get', `$${out.local}`], timeVal],
|
|
@@ -801,4 +804,23 @@ export default (ctx) => {
|
|
|
801
804
|
return typed(['call', '$__date_to_utc_string', emitDateLoad(dateExpr)], 'f64')
|
|
802
805
|
}
|
|
803
806
|
ctx.core.emit[`.${VAL.DATE}:toUTCString`] = ctx.core.emit['.toUTCString']
|
|
807
|
+
|
|
808
|
+
ctx.core.emit['.toDateString'] = (dateExpr) => {
|
|
809
|
+
inc('__date_to_date_string')
|
|
810
|
+
return typed(['call', '$__date_to_date_string', emitDateLoad(dateExpr)], 'f64')
|
|
811
|
+
}
|
|
812
|
+
ctx.core.emit[`.${VAL.DATE}:toDateString`] = ctx.core.emit['.toDateString']
|
|
813
|
+
|
|
814
|
+
ctx.core.emit['.toTimeString'] = (dateExpr) => {
|
|
815
|
+
inc('__date_to_time_string')
|
|
816
|
+
return typed(['call', '$__date_to_time_string', emitDateLoad(dateExpr)], 'f64')
|
|
817
|
+
}
|
|
818
|
+
ctx.core.emit[`.${VAL.DATE}:toTimeString`] = ctx.core.emit['.toTimeString']
|
|
819
|
+
|
|
820
|
+
// Typed-key only: users legitimately define `toJSON` on plain objects, so the
|
|
821
|
+
// bare generic key stays free — only a *proven* Date routes here.
|
|
822
|
+
ctx.core.emit[`.${VAL.DATE}:toJSON`] = (dateExpr) => {
|
|
823
|
+
inc('__date_to_json')
|
|
824
|
+
return typed(['call', '$__date_to_json', emitDateLoad(dateExpr)], 'f64')
|
|
825
|
+
}
|
|
804
826
|
}
|
package/module/fs.js
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fs — basic file IO over WASI (host:'wasi' only).
|
|
3
|
+
*
|
|
4
|
+
* `fs.read(path)` → string, `fs.write(path, data)` → undefined. Synchronous by
|
|
5
|
+
* construction — WASI preview1 IS synchronous, so no event-loop breach. Paths
|
|
6
|
+
* resolve against the FIRST PREOPEN (fd 3, the wasi convention): run under
|
|
7
|
+
* wasmtime/node:wasi with a preopened directory. jz strings are raw UTF-8
|
|
8
|
+
* bytes, so read/write are binary-lossless (a byte is `s.charCodeAt(i)`).
|
|
9
|
+
*
|
|
10
|
+
* Failures throw the WASI errno as a number (e.g. 44 = NOENT) — jz errors are
|
|
11
|
+
* values; catch and inspect. host:'js' rejects at compile with a wiring hint.
|
|
12
|
+
*
|
|
13
|
+
* @module fs
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { typed, asI64 } from '../src/ir.js'
|
|
17
|
+
import { emit, hostImport } from '../src/bridge.js'
|
|
18
|
+
import { inc, err, LAYOUT } from '../src/ctx.js'
|
|
19
|
+
|
|
20
|
+
const setupWasi = (ctx) => {
|
|
21
|
+
const needPathOpen = () => hostImport('wasi_snapshot_preview1', 'path_open',
|
|
22
|
+
['func', '$__path_open', ['param', 'i32'], ['param', 'i32'], ['param', 'i32'], ['param', 'i32'], ['param', 'i32'], ['param', 'i64'], ['param', 'i64'], ['param', 'i32'], ['param', 'i32'], ['result', 'i32']])
|
|
23
|
+
const needFdRead = () => hostImport('wasi_snapshot_preview1', 'fd_read',
|
|
24
|
+
['func', '$__fd_read', ['param', 'i32'], ['param', 'i32'], ['param', 'i32'], ['param', 'i32'], ['result', 'i32']])
|
|
25
|
+
const needFdWrite = () => hostImport('wasi_snapshot_preview1', 'fd_write',
|
|
26
|
+
['func', '$__fd_write', ['param', 'i32'], ['param', 'i32'], ['param', 'i32'], ['param', 'i32'], ['result', 'i32']])
|
|
27
|
+
const needFdClose = () => hostImport('wasi_snapshot_preview1', 'fd_close',
|
|
28
|
+
['func', '$__fd_close', ['param', 'i32'], ['result', 'i32']])
|
|
29
|
+
const needFilestat = () => hostImport('wasi_snapshot_preview1', 'fd_filestat_get',
|
|
30
|
+
['func', '$__fd_filestat_get', ['param', 'i32'], ['param', 'i32'], ['result', 'i32']])
|
|
31
|
+
|
|
32
|
+
// Stage a jz string's bytes into linear memory → packed (ptr<<32)|len in an
|
|
33
|
+
// i64 (SSO strings live in the box, heap strings in place — no copy).
|
|
34
|
+
ctx.core.stdlib['__fs_path'] = `(func $__fs_path (param $str i64) (result i64)
|
|
35
|
+
(local $aux i32) (local $len i32) (local $off i32) (local $buf i32)
|
|
36
|
+
(local.set $aux (call $__ptr_aux (local.get $str)))
|
|
37
|
+
(if (i32.and (local.get $aux) (i32.const ${LAYOUT.SSO_BIT}))
|
|
38
|
+
(then
|
|
39
|
+
(local.set $len (i32.and (i32.shr_u (local.get $aux) (i32.const 10)) (i32.const 7)))
|
|
40
|
+
(local.set $buf (call $__alloc (local.get $len)))
|
|
41
|
+
(local.set $off (i32.const 0))
|
|
42
|
+
(block $done (loop $loop
|
|
43
|
+
(br_if $done (i32.ge_s (local.get $off) (local.get $len)))
|
|
44
|
+
(i32.store8 (i32.add (local.get $buf) (local.get $off))
|
|
45
|
+
(call $__sso_char (local.get $str) (local.get $off)))
|
|
46
|
+
(local.set $off (i32.add (local.get $off) (i32.const 1)))
|
|
47
|
+
(br $loop))))
|
|
48
|
+
(else
|
|
49
|
+
(local.set $buf (call $__ptr_offset (local.get $str)))
|
|
50
|
+
(local.set $len (call $__str_len (local.get $str)))))
|
|
51
|
+
(i64.or (i64.shl (i64.extend_i32_u (local.get $buf)) (i64.const 32))
|
|
52
|
+
(i64.extend_i32_u (local.get $len))))`
|
|
53
|
+
|
|
54
|
+
// read: path_open(preopen fd 3) → filestat size → exact alloc → read loop → string
|
|
55
|
+
ctx.core.stdlib['__fs_read'] = `(func $__fs_read (param $path i64) (result f64)
|
|
56
|
+
(local $pl i64) (local $scratch i32) (local $fd i32) (local $e i32)
|
|
57
|
+
(local $size i32) (local $buf i32) (local $total i32) (local $n i32)
|
|
58
|
+
(local.set $pl (call $__fs_path (local.get $path)))
|
|
59
|
+
(local.set $scratch (call $__alloc (i32.const 64)))
|
|
60
|
+
;; rights: FD_READ(2) | FD_FILESTAT_GET(1<<21)
|
|
61
|
+
(local.set $e (call $__path_open (i32.const 3) (i32.const 1)
|
|
62
|
+
(i32.wrap_i64 (i64.shr_u (local.get $pl) (i64.const 32)))
|
|
63
|
+
(i32.wrap_i64 (i64.and (local.get $pl) (i64.const 0xffffffff)))
|
|
64
|
+
(i32.const 0) (i64.const ${2 | (1 << 21)}) (i64.const 0) (i32.const 0)
|
|
65
|
+
(local.get $scratch)))
|
|
66
|
+
(if (local.get $e) (then (throw $__jz_err (f64.convert_i32_u (local.get $e)))))
|
|
67
|
+
(local.set $fd (i32.load (local.get $scratch)))
|
|
68
|
+
(local.set $e (call $__fd_filestat_get (local.get $fd) (local.get $scratch)))
|
|
69
|
+
(if (local.get $e) (then
|
|
70
|
+
(drop (call $__fd_close (local.get $fd)))
|
|
71
|
+
(throw $__jz_err (f64.convert_i32_u (local.get $e)))))
|
|
72
|
+
;; filestat.size at offset 32 (u64; jz caps at i32 addressable)
|
|
73
|
+
(local.set $size (i32.wrap_i64 (i64.load offset=32 (local.get $scratch))))
|
|
74
|
+
(local.set $buf (call $__alloc (local.get $size)))
|
|
75
|
+
(local.set $total (i32.const 0))
|
|
76
|
+
(block $eof (loop $read
|
|
77
|
+
(br_if $eof (i32.ge_u (local.get $total) (local.get $size)))
|
|
78
|
+
(i32.store (local.get $scratch) (i32.add (local.get $buf) (local.get $total)))
|
|
79
|
+
(i32.store offset=4 (local.get $scratch) (i32.sub (local.get $size) (local.get $total)))
|
|
80
|
+
(local.set $e (call $__fd_read (local.get $fd) (local.get $scratch) (i32.const 1)
|
|
81
|
+
(i32.add (local.get $scratch) (i32.const 8))))
|
|
82
|
+
(if (local.get $e) (then
|
|
83
|
+
(drop (call $__fd_close (local.get $fd)))
|
|
84
|
+
(throw $__jz_err (f64.convert_i32_u (local.get $e)))))
|
|
85
|
+
(local.set $n (i32.load offset=8 (local.get $scratch)))
|
|
86
|
+
(br_if $eof (i32.eqz (local.get $n)))
|
|
87
|
+
(local.set $total (i32.add (local.get $total) (local.get $n)))
|
|
88
|
+
(br $read)))
|
|
89
|
+
(drop (call $__fd_close (local.get $fd)))
|
|
90
|
+
(call $__mkstr (local.get $buf) (local.get $total)))`
|
|
91
|
+
|
|
92
|
+
// write: path_open CREAT|TRUNC → fd_write loop → close
|
|
93
|
+
ctx.core.stdlib['__fs_write'] = `(func $__fs_write (param $path i64) (param $data i64)
|
|
94
|
+
(local $pl i64) (local $dl i64) (local $scratch i32) (local $fd i32) (local $e i32)
|
|
95
|
+
(local $buf i32) (local $len i32) (local $total i32) (local $n i32)
|
|
96
|
+
(local.set $pl (call $__fs_path (local.get $path)))
|
|
97
|
+
(local.set $dl (call $__fs_path (local.get $data)))
|
|
98
|
+
(local.set $scratch (call $__alloc (i32.const 16)))
|
|
99
|
+
;; oflags: CREAT(1)|TRUNC(8); rights: FD_WRITE(64)
|
|
100
|
+
(local.set $e (call $__path_open (i32.const 3) (i32.const 1)
|
|
101
|
+
(i32.wrap_i64 (i64.shr_u (local.get $pl) (i64.const 32)))
|
|
102
|
+
(i32.wrap_i64 (i64.and (local.get $pl) (i64.const 0xffffffff)))
|
|
103
|
+
(i32.const 9) (i64.const 64) (i64.const 0) (i32.const 0)
|
|
104
|
+
(local.get $scratch)))
|
|
105
|
+
(if (local.get $e) (then (throw $__jz_err (f64.convert_i32_u (local.get $e)))))
|
|
106
|
+
(local.set $fd (i32.load (local.get $scratch)))
|
|
107
|
+
(local.set $buf (i32.wrap_i64 (i64.shr_u (local.get $dl) (i64.const 32))))
|
|
108
|
+
(local.set $len (i32.wrap_i64 (i64.and (local.get $dl) (i64.const 0xffffffff))))
|
|
109
|
+
(local.set $total (i32.const 0))
|
|
110
|
+
(block $done (loop $write
|
|
111
|
+
(br_if $done (i32.ge_u (local.get $total) (local.get $len)))
|
|
112
|
+
(i32.store (local.get $scratch) (i32.add (local.get $buf) (local.get $total)))
|
|
113
|
+
(i32.store offset=4 (local.get $scratch) (i32.sub (local.get $len) (local.get $total)))
|
|
114
|
+
(local.set $e (call $__fd_write (local.get $fd) (local.get $scratch) (i32.const 1)
|
|
115
|
+
(i32.add (local.get $scratch) (i32.const 8))))
|
|
116
|
+
(if (local.get $e) (then
|
|
117
|
+
(drop (call $__fd_close (local.get $fd)))
|
|
118
|
+
(throw $__jz_err (f64.convert_i32_u (local.get $e)))))
|
|
119
|
+
(local.set $n (i32.load offset=8 (local.get $scratch)))
|
|
120
|
+
(br_if $done (i32.eqz (local.get $n)))
|
|
121
|
+
(local.set $total (i32.add (local.get $total) (local.get $n)))
|
|
122
|
+
(br $write)))
|
|
123
|
+
(drop (call $__fd_close (local.get $fd))))`
|
|
124
|
+
|
|
125
|
+
ctx.core.emit['fs.read'] = (path) => {
|
|
126
|
+
needPathOpen(); needFdRead(); needFdClose(); needFilestat()
|
|
127
|
+
inc('__fs_path'); inc('__fs_read')
|
|
128
|
+
return typed(['call', '$__fs_read', asI64(emit(path))], 'f64')
|
|
129
|
+
}
|
|
130
|
+
ctx.core.emit['fs.write'] = (path, data) => {
|
|
131
|
+
needPathOpen(); needFdWrite(); needFdClose()
|
|
132
|
+
inc('__fs_path'); inc('__fs_write')
|
|
133
|
+
return ['call', '$__fs_write', asI64(emit(path)), asI64(emit(data))]
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export default (ctx) => {
|
|
138
|
+
if (ctx.transform.host === 'wasi') setupWasi(ctx)
|
|
139
|
+
else {
|
|
140
|
+
const reject = (m) => () => err(`fs.${m} needs a WASI host — compile with host:'wasi' (CLI --host wasi), or wire your own file access via {imports}`)
|
|
141
|
+
ctx.core.emit['fs.read'] = reject('read')
|
|
142
|
+
ctx.core.emit['fs.write'] = reject('write')
|
|
143
|
+
}
|
|
144
|
+
}
|
package/module/function.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* @module fn
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import { typed, asF64, asI32, mkPtrIR, temp, tempI32, MAX_CLOSURE_ARITY, UNDEF_NAN, appendStaticSlots } from '../src/ir.js'
|
|
13
|
+
import { typed, asF64, asI32, mkPtrIR, temp, tempI32, MAX_CLOSURE_ARITY, UNDEF_NAN, appendStaticSlots, carrierF64 } from '../src/ir.js'
|
|
14
14
|
import { emit } from '../src/bridge.js'
|
|
15
15
|
import { isReassigned } from '../src/ast.js'
|
|
16
16
|
import { findFreeVars } from '../src/compile/analyze.js'
|
|
@@ -297,12 +297,15 @@ export default (ctx) => {
|
|
|
297
297
|
['i64.const', LAYOUT.AUX_MASK]]]]], 'f64')
|
|
298
298
|
}
|
|
299
299
|
|
|
300
|
-
// Inline path: emit each arg, pad missing slots with UNDEF
|
|
300
|
+
// Inline path: emit each arg, pad missing slots with UNDEF. Closure ABI slots
|
|
301
|
+
// are untyped boxed-value positions — a bool arg crosses as its atom box so
|
|
302
|
+
// the callee observes boolean identity (typeof/String/strict-eq); pre-emitted
|
|
303
|
+
// IR (has .type) has no AST node to consult and keeps the plain box.
|
|
301
304
|
const n = args.length
|
|
302
305
|
if (n > MAX_CLOSURE_ARITY) err(`Closure call with ${n} args exceeds MAX_CLOSURE_ARITY=${MAX_CLOSURE_ARITY}`)
|
|
303
306
|
const W = ctx.closure.width ?? MAX_CLOSURE_ARITY
|
|
304
307
|
const slots = []
|
|
305
|
-
for (let i = 0; i < n; i++) slots.push(
|
|
308
|
+
for (let i = 0; i < n; i++) slots.push(args[i]?.type ? asF64(args[i]) : carrierF64(args[i], emit(args[i])))
|
|
306
309
|
for (let i = n; i < W; i++) slots.push(UNDEF_LIT())
|
|
307
310
|
|
|
308
311
|
return typed(['block', ['result', 'f64'],
|
package/module/index.js
CHANGED
|
@@ -10,8 +10,11 @@ import collection from './collection.js'
|
|
|
10
10
|
import symbol from './symbol.js'
|
|
11
11
|
import console from './console.js'
|
|
12
12
|
import json from './json.js'
|
|
13
|
+
import atomics from './atomics.js'
|
|
13
14
|
import regex from './regex.js'
|
|
14
15
|
import timer from './timer.js'
|
|
15
16
|
import date from './date.js'
|
|
16
17
|
import simd from './simd.js'
|
|
17
|
-
|
|
18
|
+
import fs from './fs.js'
|
|
19
|
+
import web from './web.js'
|
|
20
|
+
export { math, core, array, object, string, number, fn, typedarray, collection, symbol, console, json, regex, timer, date, simd , atomics, fs, web }
|