jz 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/README.md +288 -314
  2. package/bench/README.md +319 -0
  3. package/bench/bench.svg +112 -0
  4. package/cli.js +32 -24
  5. package/index.js +177 -55
  6. package/interop.js +88 -159
  7. package/jz.svg +5 -0
  8. package/jzify/arguments.js +97 -0
  9. package/jzify/bundler.js +382 -0
  10. package/jzify/classes.js +328 -0
  11. package/jzify/hoist-vars.js +177 -0
  12. package/jzify/index.js +51 -0
  13. package/jzify/names.js +37 -0
  14. package/jzify/switch.js +106 -0
  15. package/jzify/transform.js +349 -0
  16. package/layout.js +179 -0
  17. package/module/array.js +322 -153
  18. package/module/collection.js +603 -145
  19. package/module/console.js +55 -43
  20. package/module/core.js +281 -142
  21. package/module/date.js +15 -3
  22. package/module/function.js +73 -6
  23. package/module/index.js +2 -1
  24. package/module/json.js +226 -61
  25. package/module/math.js +461 -185
  26. package/module/number.js +306 -60
  27. package/module/object.js +448 -184
  28. package/module/regex.js +255 -25
  29. package/module/schema.js +24 -6
  30. package/module/simd.js +85 -0
  31. package/module/string.js +591 -220
  32. package/module/symbol.js +1 -1
  33. package/module/timer.js +9 -14
  34. package/module/typedarray.js +45 -48
  35. package/package.json +41 -12
  36. package/src/abi/index.js +39 -23
  37. package/src/abi/string.js +38 -41
  38. package/src/ast.js +460 -0
  39. package/src/autoload.js +26 -24
  40. package/src/bridge.js +111 -0
  41. package/src/compile/analyze-scans.js +661 -0
  42. package/src/compile/analyze.js +1565 -0
  43. package/src/compile/emit-assign.js +408 -0
  44. package/src/compile/emit.js +3201 -0
  45. package/src/compile/flow-types.js +103 -0
  46. package/src/{compile.js → compile/index.js} +497 -125
  47. package/src/{infer.js → compile/infer.js} +27 -98
  48. package/src/{narrow.js → compile/narrow.js} +302 -96
  49. package/src/compile/plan/advise.js +316 -0
  50. package/src/compile/plan/common.js +150 -0
  51. package/src/compile/plan/index.js +118 -0
  52. package/src/compile/plan/inline.js +679 -0
  53. package/src/compile/plan/literals.js +984 -0
  54. package/src/compile/plan/loops.js +472 -0
  55. package/src/compile/plan/scope.js +573 -0
  56. package/src/compile/program-facts.js +404 -0
  57. package/src/ctx.js +176 -58
  58. package/src/ir.js +540 -171
  59. package/src/kind-traits.js +105 -0
  60. package/src/kind.js +462 -0
  61. package/src/op-policy.js +57 -0
  62. package/src/{optimize.js → optimize/index.js} +1106 -446
  63. package/src/optimize/vectorize.js +1874 -0
  64. package/src/param-reps.js +65 -0
  65. package/src/parse.js +44 -0
  66. package/src/{prepare.js → prepare/index.js} +600 -205
  67. package/src/reps.js +115 -0
  68. package/src/resolve.js +12 -3
  69. package/src/static.js +199 -0
  70. package/src/type.js +647 -0
  71. package/src/{assemble.js → wat/assemble.js} +86 -48
  72. package/src/wat/optimize.js +3760 -0
  73. package/transform.js +21 -0
  74. package/wasi.js +47 -5
  75. package/src/analyze.js +0 -3818
  76. package/src/emit.js +0 -2997
  77. package/src/jzify.js +0 -1553
  78. package/src/plan.js +0 -2132
  79. package/src/vectorize.js +0 -1088
  80. /package/src/{codegen.js → wat/codegen.js} +0 -0
@@ -0,0 +1,103 @@
1
+ /**
2
+ * Flow-sensitive type refinement.
3
+ *
4
+ * A `typeof x === 'string'` guard, an `instanceof` check, or an `Array.isArray(x)`
5
+ * call inside an `if` cond proves something about `x` in the then-branch. Encoded
6
+ * here as a `name → {val?, notString?}` Map (the "refinements" set) installed into
7
+ * `ctx.func.refinements` for the duration of the branch.
8
+ *
9
+ * Lifecycle: every emit site that descends into a conditional branch wraps the
10
+ * inner emit() in `withRefinements(refs, body, () => emit(b))`. Saves/restores
11
+ * the prior ctx state and skips refinement for names reassigned inside `body`
12
+ * (refinement would be unsound).
13
+ *
14
+ * Read side: lookupValType (src/reps.js) checks ctx.func.refinements first —
15
+ * see its lookup-priority docs.
16
+ *
17
+ * @module compile/flow-types
18
+ */
19
+
20
+ import { ctx } from '../ctx.js'
21
+ import { VAL } from '../reps.js'
22
+ import { isReassigned, TYPEOF } from '../ast.js'
23
+ import { typeofPredicate } from './infer.js'
24
+
25
+ const TYPEOF_CODE_TO_VAL = { [TYPEOF.number]: VAL.NUMBER, [TYPEOF.string]: VAL.STRING, [TYPEOF.function]: VAL.CLOSURE }
26
+
27
+ /** Walk a boolean condition gathering refinements implied for the `sense` branch
28
+ * (sense=true = then-branch, sense=false = else-branch). `out` is a Map mutated
29
+ * in place; returns the same Map for chaining. */
30
+ export function extractRefinements(cond, out, sense = true) {
31
+ if (!Array.isArray(cond)) return out
32
+ const op = cond[0]
33
+ // ! flips sense
34
+ if (op === '!') return extractRefinements(cond[1], out, !sense)
35
+ // && under positive sense refines with union of both branches.
36
+ // || under negative sense (De Morgan) similarly refines the else-branch.
37
+ if (op === '&&' && sense) { extractRefinements(cond[1], out, true); extractRefinements(cond[2], out, true); return out }
38
+ if (op === '||' && !sense) { extractRefinements(cond[1], out, false); extractRefinements(cond[2], out, false); return out }
39
+ // typeof x == 'number' | 'string' | 'function' — sense must be positive for "==", negative for "!="
40
+ if ((op === '==' || op === '===' || op === '!=' || op === '!==')) {
41
+ const tp = typeofPredicate(cond)
42
+ if (tp) {
43
+ const wantPositive = tp.eq ? sense : !sense
44
+ if (wantPositive) {
45
+ const val = TYPEOF_CODE_TO_VAL[tp.code]
46
+ if (val) mergeRefinement(out, tp.name, { val })
47
+ } else if (tp.code === 'string' || tp.code === TYPEOF.string) {
48
+ // Negative branch of typeof-string guard (e.g. post `if (typeof x === 'string') return`)
49
+ // proves the binding is not a primitive string in the suffix scope — feeds B4's
50
+ // length / subscript dispatch elision the same way write-shape evidence does.
51
+ mergeRefinement(out, tp.name, { notString: true })
52
+ }
53
+ }
54
+ return out
55
+ }
56
+ // Type-predicate calls under positive sense — refine by the asserted VAL.
57
+ // Callee may be the flattened string 'Array.isArray' or the raw ['.', 'Array',
58
+ // 'isArray'] pair; __is_map / __is_set / __is_typed come from jzify's
59
+ // instanceof lowering as a bare string callee.
60
+ if (op === '()' && sense && typeof cond[2] === 'string') {
61
+ const callee = cond[1]
62
+ const val = predicateRefinement(callee)
63
+ if (val != null) { mergeRefinement(out, cond[2], { val }); return out }
64
+ }
65
+ return out
66
+ }
67
+
68
+ /** Map a call-callee shape to the VAL kind it asserts under positive sense, or null. */
69
+ export function predicateRefinement(callee) {
70
+ if (callee === 'Array.isArray') return VAL.ARRAY
71
+ if (Array.isArray(callee) && callee[0] === '.' && callee[1] === 'Array' && callee[2] === 'isArray')
72
+ return VAL.ARRAY
73
+ if (callee === '__is_map') return VAL.MAP
74
+ if (callee === '__is_set') return VAL.SET
75
+ if (callee === '__is_typed') return VAL.TYPED
76
+ return null
77
+ }
78
+
79
+ /** Merge a refinement fact into the per-name slot. Later facts override; non-overlapping
80
+ * fields union. Keeps the call-side simple (always assign through this). */
81
+ export function mergeRefinement(out, name, fact) {
82
+ const cur = out.get(name)
83
+ out.set(name, cur ? { ...cur, ...fact } : fact)
84
+ }
85
+
86
+ /** Apply refinements for the duration of `fn()`. Restores prior state on return/throw. */
87
+ export function withRefinements(refs, body, fn) {
88
+ if (!refs || refs.size === 0) return fn()
89
+ const cur = ctx.func.refinements
90
+ // Drop names that are reassigned in the body — refinement would be unsound.
91
+ const saved = []
92
+ for (const [name, val] of refs) {
93
+ if (isReassigned(body, name)) continue
94
+ saved.push([name, cur.get(name)])
95
+ cur.set(name, val)
96
+ }
97
+ try { return fn() }
98
+ finally {
99
+ for (const [name, prev] of saved) {
100
+ if (prev === undefined) cur.delete(name); else cur.set(name, prev)
101
+ }
102
+ }
103
+ }