mirror of
https://github.com/morluto/rea.git
synced 2026-10-27 18:05:45 +00:00
fix(javascript): bound loop capture and rest-copy expansion
This commit is contained in:
1 parent
be2811e414
commit
cd1878f3fe
5 files changed
+251
-45
No files matched your search
@@ -0,0 +1,111 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
import { analyzeJavaScriptSemantics } from "./javascriptSemanticAnalysis.js";
|
||||
import { onlyCallable } from "./javascriptSemanticAnalysis.fixture.js";
|
||||
|
||||
const returnedValue = (body: string, expression: string) =>
|
||||
onlyCallable(
|
||||
analyzeJavaScriptSemantics(
|
||||
`export function result() { ${body} return ${expression}; }`,
|
||||
),
|
||||
"result",
|
||||
).returnSites[0]?.value;
|
||||
|
||||
describe("member-path cycles and captured aliases", () => {
|
||||
const branches = Array.from(
|
||||
{ length: 16 },
|
||||
(_, index) => `if (flag === ${index}) node = node.m${index};`,
|
||||
).join(" else ");
|
||||
|
||||
it.each(["copy[key].value = 2;", "mutate(copy[key]);"])(
|
||||
"retains shared-child effects through rest copies: %s",
|
||||
(effect) => {
|
||||
const body = `
|
||||
const seed = { mode: "initial", m15: { m15: { child: { value: 1 } } } };
|
||||
let node = seed.m15;
|
||||
while (node) {
|
||||
${branches}
|
||||
const { ignore, ...copy } = node;
|
||||
${effect}
|
||||
}
|
||||
`;
|
||||
expect(returnedValue(body, "seed.m15.m15.child.value")?.status).toBe(
|
||||
"unknown",
|
||||
);
|
||||
expect(returnedValue(body, "seed.mode")).toEqual({
|
||||
status: "literal",
|
||||
value: "initial",
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
it.each([
|
||||
["while", (body: string) => `while (node) { ${body} }`],
|
||||
["do/while", (body: string) => `do { ${body} } while (node);`],
|
||||
["for", (body: string) => `for (; node; ) { ${body} }`],
|
||||
["for/in", (body: string) => `for (const key in { a: 1 }) { ${body} }`],
|
||||
["for/of", (body: string) => `for (const item of [1]) { ${body} }`],
|
||||
] as const)(
|
||||
"keeps a late child effect within its siblings in %s",
|
||||
(_kind, loop) => {
|
||||
const body = `
|
||||
const seed = { mode: "initial", m15: { value: 1, keep: 3 } };
|
||||
let node = seed;
|
||||
${loop(`${branches} node.value = 2;`)}
|
||||
`;
|
||||
expect(returnedValue(body, "seed.m15.value")?.status).toBe("unknown");
|
||||
expect(returnedValue(body, "seed.mode")).toEqual({
|
||||
status: "literal",
|
||||
value: "initial",
|
||||
});
|
||||
expect(returnedValue(body, "seed.m15.keep")).toEqual({
|
||||
status: "literal",
|
||||
value: 3,
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
it("keeps an acyclic chain of reassignments within its selected child", () => {
|
||||
const body = `
|
||||
const seed = { branch: { child: { value: 1 }, keep: 3 }, keep: 4 };
|
||||
let node = seed;
|
||||
node = node.branch;
|
||||
node = node.child;
|
||||
mutate(node);
|
||||
`;
|
||||
expect(returnedValue(body, "seed.branch.child.value")?.status).toBe(
|
||||
"unknown",
|
||||
);
|
||||
expect(returnedValue(body, "seed.branch.keep")).toEqual({
|
||||
status: "literal",
|
||||
value: 3,
|
||||
});
|
||||
expect(returnedValue(body, "seed.keep")).toEqual({
|
||||
status: "literal",
|
||||
value: 4,
|
||||
});
|
||||
});
|
||||
|
||||
it("selects saved aliases at their capture, before or after a rebind", () => {
|
||||
const body = `
|
||||
const seed = { branch: { child: { value: 1 }, keep: 3 } };
|
||||
let node = seed.branch;
|
||||
const before = node;
|
||||
node = node.child;
|
||||
const after = node;
|
||||
`;
|
||||
expect(
|
||||
returnedValue(`${body} mutate(after);`, "seed.branch.child.value")
|
||||
?.status,
|
||||
).toBe("unknown");
|
||||
expect(returnedValue(`${body} mutate(after);`, "seed.branch.keep")).toEqual(
|
||||
{
|
||||
status: "literal",
|
||||
value: 3,
|
||||
},
|
||||
);
|
||||
expect(
|
||||
returnedValue(`${body} mutate(before);`, "seed.branch.keep")?.status,
|
||||
).toBe("unknown");
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user