@@ -196,10 +196,15 @@ private StepAction.StepResult<CallbackState> drainNext(Target t, CallbackState s
196196
197197 private void cleanupCurrentStep (CallbackState state , Environment env ) {
198198 YieldStep step = state .currentStep ;
199- if (step != null && step .preparedEnv != null ) {
200- // Pop the stack trace element that prepareExecution pushed
201- step .preparedEnv .getEnv (GlobalEnv .class ).GetStackTraceManager ().popStackTraceElement ();
202- step .preparedEnv = null ;
199+ if (step != null ) {
200+ if (step .preparedEnv != null ) {
201+ // Pop the stack trace element that prepareExecution pushed
202+ step .preparedEnv .getEnv (GlobalEnv .class ).GetStackTraceManager ().popStackTraceElement ();
203+ step .preparedEnv = null ;
204+ }
205+ if (step .cleanupAction != null ) {
206+ step .cleanupAction .run ();
207+ }
203208 }
204209 state .currentStep = null ;
205210 }
@@ -283,6 +288,14 @@ Mixed getResult() {
283288 return resultSupplier .get ();
284289 }
285290
291+ /**
292+ * Clears all remaining queued steps. Used for short-circuiting (e.g. array_every,
293+ * array_some) where the final result is known before all steps have been processed.
294+ */
295+ public void clear () {
296+ steps .clear ();
297+ }
298+
286299 /**
287300 * Fallback for when CallbackYield functions are called outside the iterative
288301 * interpreter (e.g. during compile-time optimization). Drains all steps synchronously
@@ -311,6 +324,7 @@ public static class YieldStep {
311324 final Callable callable ;
312325 final Mixed [] args ;
313326 BiConsumer <Mixed , Yield > callback ;
327+ Runnable cleanupAction ;
314328 Environment preparedEnv ;
315329
316330 YieldStep (Callable callable , Mixed [] args ) {
@@ -330,6 +344,18 @@ public YieldStep then(BiConsumer<Mixed, Yield> callback) {
330344 return this ;
331345 }
332346
347+ /**
348+ * Register a cleanup action that runs after this step completes, whether
349+ * normally or due to an exception. This is analogous to a {@code finally} block.
350+ *
351+ * @param cleanup The cleanup action to run
352+ * @return This step, for fluent chaining
353+ */
354+ public YieldStep cleanup (Runnable cleanup ) {
355+ this .cleanupAction = cleanup ;
356+ return this ;
357+ }
358+
333359 @ Override
334360 public String toString () {
335361 return "YieldStep{callable=" + callable .getClass ().getSimpleName ()
0 commit comments