Skip to content

Commit daced3a

Browse files
authored
Merge pull request #3 from btc-vision/closures
Refactor closure capture analysis and remove collectCapturedNames
2 parents ab763df + 9675719 commit daced3a

File tree

8 files changed

+7078
-1713
lines changed

8 files changed

+7078
-1713
lines changed

src/compiler.ts

Lines changed: 519 additions & 297 deletions
Large diffs are not rendered by default.

tests/compiler/closure-class.debug.wat

Lines changed: 143 additions & 143 deletions
Large diffs are not rendered by default.

tests/compiler/closure-class.release.wat

Lines changed: 138 additions & 138 deletions
Large diffs are not rendered by default.

tests/compiler/closure-stress.debug.wat

Lines changed: 196 additions & 196 deletions
Large diffs are not rendered by default.

tests/compiler/closure-stress.release.wat

Lines changed: 173 additions & 173 deletions
Large diffs are not rendered by default.

tests/compiler/closure.debug.wat

Lines changed: 3230 additions & 431 deletions
Large diffs are not rendered by default.

tests/compiler/closure.release.wat

Lines changed: 2500 additions & 335 deletions
Large diffs are not rendered by default.

tests/compiler/closure.ts

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,182 @@ function testSharedEnvironment(): i32 {
5151
return getter();
5252
}
5353
assert(testSharedEnvironment() == 50);
54+
55+
// ============================================================================
56+
// Tests for closure capture from various control flow constructs
57+
// ============================================================================
58+
59+
// Test 7: Capture from while loop
60+
function testCaptureInWhile(): i32 {
61+
let sum = 0;
62+
let i = 0;
63+
while (i < 3) {
64+
let adder = (): void => { sum = sum + i; };
65+
adder();
66+
i++;
67+
}
68+
return sum; // 0 + 1 + 2 = 3
69+
}
70+
assert(testCaptureInWhile() == 3);
71+
72+
// Test 8: Capture from do-while loop
73+
function testCaptureInDoWhile(): i32 {
74+
let product = 1;
75+
let i = 1;
76+
do {
77+
let multiplier = (): void => { product = product * i; };
78+
multiplier();
79+
i++;
80+
} while (i <= 4);
81+
return product; // 1 * 1 * 2 * 3 * 4 = 24
82+
}
83+
assert(testCaptureInDoWhile() == 24);
84+
85+
// Test 9: Capture from for loop
86+
function testCaptureInFor(): i32 {
87+
let result = 0;
88+
for (let i = 1; i <= 5; i++) {
89+
let addI = (): void => { result = result + i; };
90+
addI();
91+
}
92+
return result; // 1 + 2 + 3 + 4 + 5 = 15
93+
}
94+
assert(testCaptureInFor() == 15);
95+
96+
// Test 10: Capture from switch statement
97+
function testCaptureInSwitch(x: i32): i32 {
98+
let captured = 0;
99+
switch (x) {
100+
case 1: {
101+
let setCaptured = (): void => { captured = 10; };
102+
setCaptured();
103+
break;
104+
}
105+
case 2: {
106+
let setCaptured = (): void => { captured = 20; };
107+
setCaptured();
108+
break;
109+
}
110+
default: {
111+
let setCaptured = (): void => { captured = 99; };
112+
setCaptured();
113+
break;
114+
}
115+
}
116+
return captured;
117+
}
118+
assert(testCaptureInSwitch(1) == 10);
119+
assert(testCaptureInSwitch(2) == 20);
120+
assert(testCaptureInSwitch(3) == 99);
121+
122+
// Test 11: Capture from array literal
123+
function testCaptureInArrayLiteral(): i32 {
124+
let x = 5;
125+
let y = 10;
126+
let fns = [
127+
(): i32 => x,
128+
(): i32 => y,
129+
(): i32 => x + y
130+
];
131+
return fns[0]() + fns[1]() + fns[2](); // 5 + 10 + 15 = 30
132+
}
133+
assert(testCaptureInArrayLiteral() == 30);
134+
135+
// Test 12: Closure returning closure (nested capture)
136+
function testNestedClosureCapture(): i32 {
137+
let outer = 100;
138+
let makeAdder = (): (y: i32) => i32 => {
139+
return (y: i32): i32 => outer + y;
140+
};
141+
let adder = makeAdder();
142+
return adder(23); // 100 + 23 = 123
143+
}
144+
assert(testNestedClosureCapture() == 123);
145+
146+
// Test 13: Multiple closures in array capturing same variable
147+
function testMultipleClosuresInArray(): i32 {
148+
let shared = 0;
149+
let incrementers: Array<() => void> = [];
150+
151+
for (let i = 0; i < 3; i++) {
152+
incrementers.push((): void => { shared = shared + 1; });
153+
}
154+
155+
for (let i = 0; i < incrementers.length; i++) {
156+
incrementers[i]();
157+
}
158+
159+
return shared; // Should be 3
160+
}
161+
assert(testMultipleClosuresInArray() == 3);
162+
163+
// Test 14: Closure with ternary expression using captured variable
164+
function testCaptureInTernary(): i32 {
165+
let flag = true;
166+
let a = 10;
167+
let b = 20;
168+
let chooser = (): i32 => flag ? a : b;
169+
170+
assert(chooser() == 10);
171+
flag = false;
172+
return chooser(); // Should be 20 now
173+
}
174+
assert(testCaptureInTernary() == 20);
175+
176+
// Test 15: Closure capturing from condition expression
177+
function testCaptureFromCondition(): i32 {
178+
let threshold = 50;
179+
let value = 75;
180+
let isAboveThreshold = (): bool => value > threshold;
181+
182+
assert(isAboveThreshold() == true);
183+
value = 25;
184+
return isAboveThreshold() ? 1 : 0; // Should be 0
185+
}
186+
assert(testCaptureFromCondition() == 0);
187+
188+
// Test 16: Deeply nested loops with closure
189+
function testDeepLoopCapture(): i32 {
190+
let total = 0;
191+
for (let i = 0; i < 2; i++) {
192+
for (let j = 0; j < 2; j++) {
193+
let addBoth = (): void => { total = total + i + j; };
194+
addBoth();
195+
}
196+
}
197+
// i=0,j=0: +0, i=0,j=1: +1, i=1,j=0: +1, i=1,j=1: +2 = 4
198+
return total;
199+
}
200+
assert(testDeepLoopCapture() == 4);
201+
202+
// Test 17: Closure capturing counter pattern
203+
function makeCounter(): () => i32 {
204+
let count = 0;
205+
return (): i32 => {
206+
count = count + 1;
207+
return count;
208+
};
209+
}
210+
let counter1 = makeCounter();
211+
let counter2 = makeCounter();
212+
assert(counter1() == 1);
213+
assert(counter1() == 2);
214+
assert(counter2() == 1); // Independent counter
215+
assert(counter1() == 3);
216+
assert(counter2() == 2);
217+
218+
// Test 18: Closure with parameter default value capturing outer variable
219+
function testDefaultParamCapture(): i32 {
220+
let defaultVal = 42;
221+
let fn = (x: i32 = defaultVal): i32 => x;
222+
return fn();
223+
}
224+
assert(testDefaultParamCapture() == 42);
225+
226+
// Test 19: Closure with parameter default value using another param
227+
function testDefaultParamWithOtherParam(): i32 {
228+
let multiplier = 3;
229+
let fn = (a: i32, b: i32 = a * multiplier): i32 => b;
230+
return fn(10); // b defaults to 10 * 3 = 30
231+
}
232+
assert(testDefaultParamWithOtherParam() == 30);

0 commit comments

Comments
 (0)