jz 0.5.1 → 0.7.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 (86) hide show
  1. package/README.md +315 -318
  2. package/bench/README.md +369 -0
  3. package/bench/bench.svg +102 -0
  4. package/cli.js +104 -30
  5. package/dist/interop.js +1 -0
  6. package/dist/jz.js +6024 -0
  7. package/index.d.ts +126 -0
  8. package/index.js +362 -84
  9. package/interop.js +159 -186
  10. package/jz.svg +5 -0
  11. package/jzify/arguments.js +97 -0
  12. package/jzify/bundler.js +382 -0
  13. package/jzify/classes.js +328 -0
  14. package/jzify/hoist-vars.js +177 -0
  15. package/jzify/index.js +51 -0
  16. package/jzify/names.js +37 -0
  17. package/jzify/switch.js +106 -0
  18. package/jzify/transform.js +349 -0
  19. package/layout.js +184 -0
  20. package/module/array.js +377 -176
  21. package/module/collection.js +639 -145
  22. package/module/console.js +55 -43
  23. package/module/core.js +264 -153
  24. package/module/date.js +15 -3
  25. package/module/function.js +73 -6
  26. package/module/index.js +2 -1
  27. package/module/json.js +226 -61
  28. package/module/math.js +551 -187
  29. package/module/number.js +327 -60
  30. package/module/object.js +474 -184
  31. package/module/regex.js +255 -25
  32. package/module/schema.js +24 -6
  33. package/module/simd.js +117 -0
  34. package/module/string.js +621 -226
  35. package/module/symbol.js +1 -1
  36. package/module/timer.js +9 -14
  37. package/module/typedarray.js +459 -73
  38. package/package.json +58 -14
  39. package/src/abi/index.js +39 -23
  40. package/src/abi/string.js +38 -41
  41. package/src/ast.js +460 -0
  42. package/src/autoload.js +29 -24
  43. package/src/bridge.js +111 -0
  44. package/src/compile/analyze-scans.js +824 -0
  45. package/src/compile/analyze.js +1600 -0
  46. package/src/compile/emit-assign.js +411 -0
  47. package/src/compile/emit.js +3512 -0
  48. package/src/compile/flow-types.js +103 -0
  49. package/src/{compile.js → compile/index.js} +778 -128
  50. package/src/{infer.js → compile/infer.js} +62 -98
  51. package/src/compile/loop-divmod.js +155 -0
  52. package/src/{narrow.js → compile/narrow.js} +409 -106
  53. package/src/compile/peel-stencil.js +261 -0
  54. package/src/compile/plan/advise.js +370 -0
  55. package/src/compile/plan/common.js +150 -0
  56. package/src/compile/plan/index.js +122 -0
  57. package/src/compile/plan/inline.js +682 -0
  58. package/src/compile/plan/literals.js +1199 -0
  59. package/src/compile/plan/loops.js +472 -0
  60. package/src/compile/plan/scope.js +649 -0
  61. package/src/compile/program-facts.js +423 -0
  62. package/src/ctx.js +220 -64
  63. package/src/ir.js +589 -172
  64. package/src/kind-traits.js +132 -0
  65. package/src/kind.js +524 -0
  66. package/src/op-policy.js +57 -0
  67. package/src/{optimize.js → optimize/index.js} +1432 -473
  68. package/src/optimize/vectorize.js +4660 -0
  69. package/src/param-reps.js +65 -0
  70. package/src/parse.js +44 -0
  71. package/src/{prepare.js → prepare/index.js} +649 -205
  72. package/src/prepare/lift-iife.js +149 -0
  73. package/src/reps.js +116 -0
  74. package/src/resolve.js +12 -3
  75. package/src/static.js +208 -0
  76. package/src/type.js +651 -0
  77. package/src/{assemble.js → wat/assemble.js} +275 -55
  78. package/src/wat/optimize.js +3938 -0
  79. package/transform.js +21 -0
  80. package/wasi.js +47 -5
  81. package/src/analyze.js +0 -3818
  82. package/src/emit.js +0 -3040
  83. package/src/jzify.js +0 -1580
  84. package/src/plan.js +0 -2132
  85. package/src/vectorize.js +0 -1088
  86. /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
+ }