ReviewOS

also looking at this

home-lang/home

fix(interpreter): keep the return value across deferred user calls

#929
Open mkantautas wants to merge fix/interpreter-defer-return-value into main
2 files +203 -84
packages/interpreter/src/interpreter.zigmodified+30-84
Changes to packages/interpreter/src/interpreter.zig
@@ -316,12 +316,7 @@ pub const Interpreter = struct {
316316 }
317317
318318 // Execute defers at end of then block
319 const defers = then_env.getDefers();
320 var i: usize = defers.len;
321 while (i > 0) {
322 i -= 1;
323 _ = self.evaluateExpression(defers[i], &then_env) catch {};
324 }
319 self.runDefers(&then_env, then_err);
325320
326321 if (then_err) |err| return err;
327322 } else if (if_stmt.else_block) |else_block| {
@@ -338,12 +333,7 @@ pub const Interpreter = struct {
338333 }
339334
340335 // Execute defers at end of else block
341 const defers = else_env.getDefers();
342 var i: usize = defers.len;
343 while (i > 0) {
344 i -= 1;
345 _ = self.evaluateExpression(defers[i], &else_env) catch {};
346 }
336 self.runDefers(&else_env, else_err);
347337
348338 if (else_err) |err| return err;
349339 }
@@ -372,12 +362,7 @@ pub const Interpreter = struct {
372362 }
373363
374364 // Execute defers at end of iteration
375 const defers = iter_env.getDefers();
376 var i: usize = defers.len;
377 while (i > 0) {
378 i -= 1;
379 _ = self.evaluateExpression(defers[i], &iter_env) catch {};
380 }
365 self.runDefers(&iter_env, iter_err);
381366
382367 // Handle errors after defers
383368 if (iter_err) |err| {
@@ -438,12 +423,7 @@ pub const Interpreter = struct {
438423 }
439424
440425 // Execute defers at end of iteration
441 const defers = iter_env.getDefers();
442 var di: usize = defers.len;
443 while (di > 0) {
444 di -= 1;
445 _ = self.evaluateExpression(defers[di], &iter_env) catch {};
446 }
426 self.runDefers(&iter_env, iter_err);
447427
448428 if (iter_err) |err| {
449429 if (err == error.Return) return err;
@@ -484,12 +464,7 @@ pub const Interpreter = struct {
484464 };
485465 }
486466
487 const defers = iter_env.getDefers();
488 var di: usize = defers.len;
489 while (di > 0) {
490 di -= 1;
491 _ = self.evaluateExpression(defers[di], &iter_env) catch {};
492 }
467 self.runDefers(&iter_env, iter_err);
493468
494469 if (iter_err) |err| {
495470 if (err == error.Return) return err;
@@ -539,12 +514,7 @@ pub const Interpreter = struct {
539514 };
540515 }
541516
542 const defers = iter_env.getDefers();
543 var di: usize = defers.len;
544 while (di > 0) {
545 di -= 1;
546 _ = self.evaluateExpression(defers[di], &iter_env) catch {};
547 }
517 self.runDefers(&iter_env, iter_err);
548518
549519 if (iter_err) |err| {
550520 if (err == error.Return) return err;
@@ -587,12 +557,7 @@ pub const Interpreter = struct {
587557 };
588558 }
589559
590 const defers = iter_env.getDefers();
591 var di: usize = defers.len;
592 while (di > 0) {
593 di -= 1;
594 _ = self.evaluateExpression(defers[di], &iter_env) catch {};
595 }
560 self.runDefers(&iter_env, iter_err);
596561
597562 if (iter_err) |err| {
598563 if (err == error.Return) return err;
@@ -800,12 +765,7 @@ pub const Interpreter = struct {
800765 }
801766
802767 // Execute defers in reverse order (LIFO)
803 const defers = block_env.getDefers();
804 var i: usize = defers.len;
805 while (i > 0) {
806 i -= 1;
807 _ = self.evaluateExpression(defers[i], &block_env) catch {};
808 }
768 self.runDefers(&block_env, block_err);
809769
810770 // Propagate any error that occurred
811771 if (block_err) |err| {
@@ -9072,12 +9032,7 @@ pub const Interpreter = struct {
90729032 }
90739033
90749034 // Execute defers in reverse order before returning
9075 const defers = closure_env.getDefers();
9076 var i: usize = defers.len;
9077 while (i > 0) {
9078 i -= 1;
9079 _ = self.evaluateExpression(defers[i], closure_env) catch {};
9080 }
9035 self.runDefers(closure_env, closure_err);
90819036
90829037 // Handle return or error
90839038 if (closure_err) |err| {
@@ -9132,12 +9087,7 @@ pub const Interpreter = struct {
91329087 }
91339088
91349089 // Execute defers in reverse order before returning
9135 const defers = closure_env.getDefers();
9136 var i: usize = defers.len;
9137 while (i > 0) {
9138 i -= 1;
9139 _ = self.evaluateExpression(defers[i], &closure_env) catch {};
9140 }
9090 self.runDefers(&closure_env, closure_err);
91419091
91429092 // Handle return or error
91439093 if (closure_err) |err| {
@@ -9229,12 +9179,7 @@ pub const Interpreter = struct {
92299179 };
92309180 }
92319181
9232 const defers = closure_env.getDefers();
9233 var i: usize = defers.len;
9234 while (i > 0) {
9235 i -= 1;
9236 _ = self.evaluateExpression(defers[i], &closure_env) catch {};
9237 }
9182 self.runDefers(&closure_env, closure_err);
92389183
92399184 if (closure_err) |err| {
92409185 if (err == error.Return) {
@@ -10948,6 +10893,22 @@ pub const Interpreter = struct {
1094810893 return error.UndefinedFunction;
1094910894 }
1095010895
10896 /// Run `env`'s deferred expressions in reverse order. `scope_err` is the
10897 /// error the scope is exiting with. A deferred call to a user function
10898 /// clears `return_value`, so when the scope is unwinding a `return` and the
10899 /// defers leave the slot empty, the pending value is put back.
10900 fn runDefers(self: *Interpreter, env: *Environment, scope_err: ?InterpreterError) void {
10901 const pending_return = self.return_value;
10902 const defers = env.getDefers();
10903 var i: usize = defers.len;
10904 while (i > 0) {
10905 i -= 1;
10906 _ = self.evaluateExpression(defers[i], env) catch {};
10907 }
10908 const returning = if (scope_err) |err| err == error.Return else false;
10909 if (returning and self.return_value == null) self.return_value = pending_return;
10910 }
10911
1095110912 fn calculateRangeLength(range: .RangeValue) i64 {
1095210913 if (range.step == 0) return 0;
1095310914 const diff = range.end - range.start;
@@ -11041,12 +11002,7 @@ pub const Interpreter = struct {
1104111002 }
1104211003
1104311004 // Execute defers in reverse order before returning
11044 const defers = func_env.getDefers();
11045 var i: usize = defers.len;
11046 while (i > 0) {
11047 i -= 1;
11048 _ = self.evaluateExpression(defers[i], &func_env) catch {};
11049 }
11005 self.runDefers(&func_env, func_err);
1105011006
1105111007 // Handle return or error
1105211008 if (func_err) |err| {
@@ -11122,12 +11078,7 @@ pub const Interpreter = struct {
1112211078 }
1112311079
1112411080 // Execute defers in reverse order before returning
11125 const defers = method_env.getDefers();
11126 var i: usize = defers.len;
11127 while (i > 0) {
11128 i -= 1;
11129 _ = self.evaluateExpression(defers[i], &method_env) catch {};
11130 }
11081 self.runDefers(&method_env, method_err);
1113111082
1113211083 // Handle return or error
1113311084 if (method_err) |err| {
@@ -11178,12 +11129,7 @@ pub const Interpreter = struct {
1117811129 }
1117911130
1118011131 // Execute defers in reverse order before returning
11181 const defers = method_env.getDefers();
11182 var i: usize = defers.len;
11183 while (i > 0) {
11184 i -= 1;
11185 _ = self.evaluateExpression(defers[i], &method_env) catch {};
11186 }
11132 self.runDefers(&method_env, method_err);
1118711133
1118811134 // Handle return or error
1118911135 if (method_err) |err| {
packages/interpreter/tests/program_eval_test.zigmodified+173-0
Changes to packages/interpreter/tests/program_eval_test.zig
@@ -99,3 +99,176 @@ test "eval: runaway user recursion returns a runtime error" {
9999 \\}
100100 ));
101101}
102
103test "eval: deferred user function calls keep the pending return value" {
104 try runProgram(
105 \\struct Box {
106 \\ v: int,
107 \\}
108 \\
109 \\impl Box {
110 \\ fn get(self): int {
111 \\ defer cleanup()
112 \\ return self.v
113 \\ }
114 \\}
115 \\
116 \\fn cleanup() {
117 \\}
118 \\
119 \\fn direct(): int {
120 \\ defer cleanup()
121 \\ return 7
122 \\}
123 \\
124 \\fn in_if(): int {
125 \\ if true {
126 \\ defer cleanup()
127 \\ return 8
128 \\ }
129 \\ return 0
130 \\}
131 \\
132 \\fn in_else(): int {
133 \\ if false {
134 \\ return 0
135 \\ } else {
136 \\ defer cleanup()
137 \\ return 9
138 \\ }
139 \\ return 0
140 \\}
141 \\
142 \\fn in_while(): int {
143 \\ while true {
144 \\ defer cleanup()
145 \\ return 10
146 \\ }
147 \\ return 0
148 \\}
149 \\
150 \\fn in_range_loop(): int {
151 \\ for i in 0..3 {
152 \\ defer cleanup()
153 \\ return i + 11
154 \\ }
155 \\ return 0
156 \\}
157 \\
158 \\fn in_array_loop(): int {
159 \\ for x in [12] {
160 \\ defer cleanup()
161 \\ return x
162 \\ }
163 \\ return 0
164 \\}
165 \\
166 \\fn in_block(): int {
167 \\ {
168 \\ defer cleanup()
169 \\ return 13
170 \\ }
171 \\ return 0
172 \\}
173 \\
174 \\fn main() {
175 \\ let closure = fn(): int {
176 \\ defer cleanup()
177 \\ return 14
178 \\ }
179 \\ let box = Box { v: 15 }
180 \\ assert(direct() == 7)
181 \\ assert(in_if() == 8)
182 \\ assert(in_else() == 9)
183 \\ assert(in_while() == 10)
184 \\ assert(in_range_loop() == 11)
185 \\ assert(in_array_loop() == 12)
186 \\ assert(in_block() == 13)
187 \\ assert(closure() == 14)
188 \\ assert(box.get() == 15)
189 \\}
190 );
191}
192
193test "eval: a value left behind by a call inside a defer does not replace the pending return" {
194 try runProgram(
195 \\fn noop() {
196 \\}
197 \\
198 \\fn cleanup() {
199 \\ let c = fn(): int {
200 \\ return 99
201 \\ }
202 \\ c()
203 \\ defer noop()
204 \\}
205 \\
206 \\fn outer(): int {
207 \\ defer cleanup()
208 \\ return 7
209 \\}
210 \\
211 \\fn main() {
212 \\ assert(outer() == 7)
213 \\}
214 );
215}
216
217test "eval: a return inside a deferred block still sets the returned value" {
218 try runProgram(
219 \\fn final_return(): int {
220 \\ defer {
221 \\ return 5
222 \\ }
223 \\ return 7
224 \\}
225 \\
226 \\fn earlier_return(): int {
227 \\ defer {
228 \\ return 6
229 \\ 0
230 \\ }
231 \\ return 7
232 \\}
233 \\
234 \\fn main() {
235 \\ assert(final_return() == 5)
236 \\ assert(earlier_return() == 6)
237 \\}
238 );
239}
240
241test "eval: deferred calls run in reverse order before the return value is used" {
242 try runProgram(
243 \\fn inner(): int {
244 \\ defer note(1)
245 \\ return 99
246 \\}
247 \\
248 \\let mut order = 0
249 \\
250 \\fn note(n: int) {
251 \\ order = order * 10 + n
252 \\}
253 \\
254 \\fn first() {
255 \\ note(2)
256 \\}
257 \\
258 \\fn second() {
259 \\ assert(inner() == 99)
260 \\ note(3)
261 \\}
262 \\
263 \\fn outer(): int {
264 \\ defer first()
265 \\ defer second()
266 \\ return 7
267 \\}
268 \\
269 \\fn main() {
270 \\ assert(outer() == 7)
271 \\ assert(order == 132)
272 \\}
273 );
274}