mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-25 06:24:27 +08:00
Captured bindings live in shared boxes, and every analysis skips boxed locals: a function-wrapped program's const N turned all index math into checked f64 arithmetic and every captured array read into a retained box load. copyStableCaptures keeps the boxes (environments, ownership and cycle tracing are unchanged) but reads bindings that nothing writes after their only initialization through plain immutable locals: split declarations in the declaring function, one entry copy per closure body, and numeric constants propagated into the copy. Hoisted function bindings qualify through their single assignment, and calls through a binding of an environment-free function become direct calls of a capture-free copy (int32 ABI clones and inlining apply). Constant callbacks resolve hoisted function bindings, copies of a scalar capture keep double storage, and AmbientReceiverReaders moves to ir/ so the pass can use it.
69 lines
1.9 KiB
TypeScript
69 lines
1.9 KiB
TypeScript
// Nested function declarations captured by sibling functions keep their
|
|
// JavaScript identity and hoisting: calls through the capture reach the
|
|
// declared body, mutual recursion works across the hoisted pair, each call
|
|
// of the enclosing function creates fresh function objects, and a
|
|
// function binding that some code reassigns stays a shared binding.
|
|
|
|
function spectral(): number {
|
|
const N = 5;
|
|
function A(i: number, j: number): number {
|
|
return 1.0 / (((i + j) * (i + j + 1)) / 2 + i + 1);
|
|
}
|
|
function mulAv(v: number[], out: number[]): void {
|
|
for (let i = 0; i < N; i++) {
|
|
let s = 0;
|
|
for (let j = 0; j < N; j++) s += A(i, j) * v[j]!;
|
|
out[i] = s;
|
|
}
|
|
}
|
|
const u = [1, 1, 1, 1, 1];
|
|
const t = [0, 0, 0, 0, 0];
|
|
mulAv(u, t);
|
|
mulAv(t, u);
|
|
return u.reduce((a, b) => a + b, 0);
|
|
}
|
|
console.log("spectral", spectral().toFixed(9));
|
|
|
|
function parity(n: number): string {
|
|
function isEven(k: number): boolean {
|
|
return k === 0 ? true : isOdd(k - 1);
|
|
}
|
|
function isOdd(k: number): boolean {
|
|
return k === 0 ? false : isEven(k - 1);
|
|
}
|
|
const check = (k: number): string => (isEven(k) ? "even" : "odd");
|
|
return check(n) + "/" + check(n + 1);
|
|
}
|
|
console.log("parity", parity(10), parity(7));
|
|
|
|
function identity(): () => number {
|
|
function inner(): number {
|
|
return 42;
|
|
}
|
|
return inner;
|
|
}
|
|
const first = identity();
|
|
const second = identity();
|
|
console.log("identity", first === second, first === first, first(), second());
|
|
|
|
function reassigned(): string {
|
|
let greet = (): string => "hello";
|
|
const call = (): string => greet();
|
|
const before = call();
|
|
greet = (): string => "bye";
|
|
return before + " " + call();
|
|
}
|
|
console.log("reassigned", reassigned());
|
|
|
|
function hoistedCall(): number {
|
|
const total = sum(4);
|
|
function sum(n: number): number {
|
|
return n <= 0 ? 0 : n + helper(n - 1);
|
|
}
|
|
function helper(n: number): number {
|
|
return sum(n);
|
|
}
|
|
return total + sum(3);
|
|
}
|
|
console.log("hoisted", hoistedCall());
|