@@ -27,6 +27,7 @@ static void wait_if_paused(Interpreter* interp) {
2727
2828static mtx_t g_tns_lock ;
2929static mtx_t g_parfor_merge_lock ;
30+ static int g_for_temp_id = 0 ;
3031
3132static const char * stmt_type_name (StmtType type ) {
3233 switch (type ) {
@@ -2796,29 +2797,114 @@ static ExecResult exec_stmt(Interpreter* interp, Stmt* stmt, Env* env, LabelMap*
27962797 int64_t limit = target .as .i ;
27972798 value_free (target );
27982799
2800+ /*
2801+ * Create a loop-local binding for the counter so it does not
2802+ * persist after the loop finishes. We implement this by
2803+ * creating a unique temporary local variable and aliasing the
2804+ * user-visible counter name to that temporary binding for the
2805+ * duration of the loop. After the loop we remove the alias and
2806+ * restore any previous local binding if necessary.
2807+ */
2808+ char temp_name [64 ];
2809+ int my_temp_id = ++ g_for_temp_id ;
2810+ snprintf (temp_name , sizeof (temp_name ), "__for_cnt_%d_%d_%d" , my_temp_id , stmt -> line , stmt -> column );
2811+
2812+ /* Save any previous value (in local or parent) so we can restore local bindings */
2813+ Value prev_val = value_null ();
2814+ DeclType prev_type = TYPE_UNKNOWN ;
2815+ bool prev_initialized = false;
2816+ env_get (env , stmt -> as .for_stmt .counter , & prev_val , & prev_type , & prev_initialized );
2817+
2818+ /* Detect whether a local binding already exists (trial define) */
2819+ bool local_existed = true;
2820+ if (env_define (env , stmt -> as .for_stmt .counter , TYPE_INT )) {
2821+ /* no local existed; clean up the probe */
2822+ env_delete (env , stmt -> as .for_stmt .counter );
2823+ local_existed = false;
2824+ }
2825+
2826+ /* Create the temporary target binding */
2827+ if (!env_define (env , temp_name , TYPE_INT )) {
2828+ int retries = 0 ;
2829+ while (retries < 1000 && !env_define (env , temp_name , TYPE_INT )) {
2830+ my_temp_id = ++ g_for_temp_id ;
2831+ snprintf (temp_name , sizeof (temp_name ), "__for_cnt_%d_%d_%d" , my_temp_id , stmt -> line , stmt -> column );
2832+ retries ++ ;
2833+ }
2834+ if (retries >= 1000 ) {
2835+ value_free (prev_val );
2836+ interp -> loop_depth -- ;
2837+ return make_error ("Internal error setting up FOR counter" , stmt -> line , stmt -> column );
2838+ }
2839+ }
2840+
2841+ /* Create a local alias `counter -> temp_name` (creates local entry if missing)
2842+ * This will shadow any parent binding for the duration of the loop.
2843+ */
2844+ if (!env_set_alias (env , stmt -> as .for_stmt .counter , temp_name , TYPE_INT , true)) {
2845+ /* cleanup temp binding */
2846+ env_delete (env , temp_name );
2847+ value_free (prev_val );
2848+ interp -> loop_depth -- ;
2849+ return make_error ("Cannot create loop-local counter" , stmt -> line , stmt -> column );
2850+ }
2851+
27992852 for (int64_t idx = 1 ; idx <= limit ; idx ++ ) {
28002853 if (++ iteration_count > max_iterations ) {
2854+ /* cleanup alias/temp and restore previous local if needed */
2855+ env_delete (env , stmt -> as .for_stmt .counter );
2856+ env_delete (env , temp_name );
2857+ if (local_existed ) {
2858+ env_define (env , stmt -> as .for_stmt .counter , prev_type );
2859+ if (prev_initialized ) env_assign (env , stmt -> as .for_stmt .counter , prev_val , prev_type , false);
2860+ }
2861+ value_free (prev_val );
28012862 interp -> loop_depth -- ;
28022863 return make_error ("Infinite loop detected" , stmt -> line , stmt -> column );
28032864 }
28042865
2805- // Bind or assign the loop counter in the current environment
2866+ /* Assign to the aliased counter (writes to temp_name) */
28062867 if (!env_assign (env , stmt -> as .for_stmt .counter , value_int (idx ), TYPE_INT , true)) {
28072868 char buf [256 ];
28082869 snprintf (buf , sizeof (buf ), "Cannot assign to frozen identifier '%s'" , stmt -> as .for_stmt .counter );
2870+ /* cleanup alias and temp binding before returning */
2871+ env_delete (env , stmt -> as .for_stmt .counter );
2872+ env_delete (env , temp_name );
2873+ if (local_existed ) {
2874+ env_define (env , stmt -> as .for_stmt .counter , prev_type );
2875+ if (prev_initialized ) env_assign (env , stmt -> as .for_stmt .counter , prev_val , prev_type , false);
2876+ }
2877+ value_free (prev_val );
2878+ interp -> loop_depth -- ;
28092879 return make_error (buf , stmt -> line , stmt -> column );
28102880 }
28112881
28122882 ExecResult res = exec_stmt (interp , stmt -> as .for_stmt .body , env , labels );
28132883
28142884 if (res .status == EXEC_ERROR || res .status == EXEC_RETURN || res .status == EXEC_GOTO ) {
2885+ /* cleanup before propagating */
2886+ env_delete (env , stmt -> as .for_stmt .counter );
2887+ env_delete (env , temp_name );
2888+ if (local_existed ) {
2889+ env_define (env , stmt -> as .for_stmt .counter , prev_type );
2890+ if (prev_initialized ) env_assign (env , stmt -> as .for_stmt .counter , prev_val , prev_type , false);
2891+ }
2892+ value_free (prev_val );
28152893 interp -> loop_depth -- ;
28162894 return res ;
28172895 }
28182896
28192897 if (res .status == EXEC_BREAK ) {
28202898 if (res .break_count > 1 ) {
28212899 res .break_count -- ;
2900+ /* cleanup before returning */
2901+ env_delete (env , stmt -> as .for_stmt .counter );
2902+ env_delete (env , temp_name );
2903+ if (local_existed ) {
2904+ env_define (env , stmt -> as .for_stmt .counter , prev_type );
2905+ if (prev_initialized ) env_assign (env , stmt -> as .for_stmt .counter , prev_val , prev_type , false);
2906+ }
2907+ value_free (prev_val );
28222908 interp -> loop_depth -- ;
28232909 return res ;
28242910 }
@@ -2828,6 +2914,15 @@ static ExecResult exec_stmt(Interpreter* interp, Stmt* stmt, Env* env, LabelMap*
28282914 // EXEC_CONTINUE is treated as a normal completion (loop continues)
28292915 }
28302916
2917+ /* Normal loop completion: remove alias and temp binding, restore local if needed */
2918+ env_delete (env , stmt -> as .for_stmt .counter );
2919+ env_delete (env , temp_name );
2920+ if (local_existed ) {
2921+ env_define (env , stmt -> as .for_stmt .counter , prev_type );
2922+ if (prev_initialized ) env_assign (env , stmt -> as .for_stmt .counter , prev_val , prev_type , false);
2923+ }
2924+ value_free (prev_val );
2925+
28312926 interp -> loop_depth -- ;
28322927 return make_ok (value_null ());
28332928 }
0 commit comments