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.
- package/README.md +315 -318
- package/bench/README.md +369 -0
- package/bench/bench.svg +102 -0
- package/cli.js +104 -30
- package/dist/interop.js +1 -0
- package/dist/jz.js +6024 -0
- package/index.d.ts +126 -0
- package/index.js +362 -84
- package/interop.js +159 -186
- package/jz.svg +5 -0
- package/jzify/arguments.js +97 -0
- package/jzify/bundler.js +382 -0
- package/jzify/classes.js +328 -0
- package/jzify/hoist-vars.js +177 -0
- package/jzify/index.js +51 -0
- package/jzify/names.js +37 -0
- package/jzify/switch.js +106 -0
- package/jzify/transform.js +349 -0
- package/layout.js +184 -0
- package/module/array.js +377 -176
- package/module/collection.js +639 -145
- package/module/console.js +55 -43
- package/module/core.js +264 -153
- package/module/date.js +15 -3
- package/module/function.js +73 -6
- package/module/index.js +2 -1
- package/module/json.js +226 -61
- package/module/math.js +551 -187
- package/module/number.js +327 -60
- package/module/object.js +474 -184
- package/module/regex.js +255 -25
- package/module/schema.js +24 -6
- package/module/simd.js +117 -0
- package/module/string.js +621 -226
- package/module/symbol.js +1 -1
- package/module/timer.js +9 -14
- package/module/typedarray.js +459 -73
- package/package.json +58 -14
- package/src/abi/index.js +39 -23
- package/src/abi/string.js +38 -41
- package/src/ast.js +460 -0
- package/src/autoload.js +29 -24
- package/src/bridge.js +111 -0
- package/src/compile/analyze-scans.js +824 -0
- package/src/compile/analyze.js +1600 -0
- package/src/compile/emit-assign.js +411 -0
- package/src/compile/emit.js +3512 -0
- package/src/compile/flow-types.js +103 -0
- package/src/{compile.js → compile/index.js} +778 -128
- package/src/{infer.js → compile/infer.js} +62 -98
- package/src/compile/loop-divmod.js +155 -0
- package/src/{narrow.js → compile/narrow.js} +409 -106
- package/src/compile/peel-stencil.js +261 -0
- package/src/compile/plan/advise.js +370 -0
- package/src/compile/plan/common.js +150 -0
- package/src/compile/plan/index.js +122 -0
- package/src/compile/plan/inline.js +682 -0
- package/src/compile/plan/literals.js +1199 -0
- package/src/compile/plan/loops.js +472 -0
- package/src/compile/plan/scope.js +649 -0
- package/src/compile/program-facts.js +423 -0
- package/src/ctx.js +220 -64
- package/src/ir.js +589 -172
- package/src/kind-traits.js +132 -0
- package/src/kind.js +524 -0
- package/src/op-policy.js +57 -0
- package/src/{optimize.js → optimize/index.js} +1432 -473
- package/src/optimize/vectorize.js +4660 -0
- package/src/param-reps.js +65 -0
- package/src/parse.js +44 -0
- package/src/{prepare.js → prepare/index.js} +649 -205
- package/src/prepare/lift-iife.js +149 -0
- package/src/reps.js +116 -0
- package/src/resolve.js +12 -3
- package/src/static.js +208 -0
- package/src/type.js +651 -0
- package/src/{assemble.js → wat/assemble.js} +275 -55
- package/src/wat/optimize.js +3938 -0
- package/transform.js +21 -0
- package/wasi.js +47 -5
- package/src/analyze.js +0 -3818
- package/src/emit.js +0 -3040
- package/src/jzify.js +0 -1580
- package/src/plan.js +0 -2132
- package/src/vectorize.js +0 -1088
- /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
|
+
}
|