Mercurial > vim
comparison src/vim9cmds.c @ 30333:fc0830246f49 v9.0.0502
patch 9.0.0502: a closure in a nested loop in a :def function does not work
Commit: https://github.com/vim/vim/commit/cc34181f9994d64f8c8fa2f5845eaf0cc963067f
Author: Bram Moolenaar <Bram@vim.org>
Date: Mon Sep 19 15:54:34 2022 +0100
patch 9.0.0502: a closure in a nested loop in a :def function does not work
Problem: A closure in a nested loop in a :def function does not work.
Solution: Use an array of loopvars, one per loop level.
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Mon, 19 Sep 2022 17:00:07 +0200 |
parents | bee38b1d323c |
children | ee039a6049ff |
comparison
equal
deleted
inserted
replaced
30332:462d122636b3 | 30333:fc0830246f49 |
---|---|
345 return NULL; | 345 return NULL; |
346 scope->se_outer = cctx->ctx_scope; | 346 scope->se_outer = cctx->ctx_scope; |
347 cctx->ctx_scope = scope; | 347 cctx->ctx_scope = scope; |
348 scope->se_type = type; | 348 scope->se_type = type; |
349 scope->se_local_count = cctx->ctx_locals.ga_len; | 349 scope->se_local_count = cctx->ctx_locals.ga_len; |
350 if (scope->se_outer != NULL) | |
351 scope->se_loop_depth = scope->se_outer->se_loop_depth; | |
350 return scope; | 352 return scope; |
351 } | 353 } |
352 | 354 |
353 /* | 355 /* |
354 * Free the current scope and go back to the outer scope. | 356 * Free the current scope and go back to the outer scope. |
821 size_t varlen; | 823 size_t varlen; |
822 garray_T *instr = &cctx->ctx_instr; | 824 garray_T *instr = &cctx->ctx_instr; |
823 scope_T *scope; | 825 scope_T *scope; |
824 forscope_T *forscope; | 826 forscope_T *forscope; |
825 lvar_T *loop_lvar; // loop iteration variable | 827 lvar_T *loop_lvar; // loop iteration variable |
828 int loop_lvar_idx; | |
826 lvar_T *funcref_lvar; | 829 lvar_T *funcref_lvar; |
830 int funcref_lvar_idx; | |
827 lvar_T *var_lvar; // variable for "var" | 831 lvar_T *var_lvar; // variable for "var" |
828 type_T *vartype; | 832 type_T *vartype; |
829 type_T *item_type = &t_any; | 833 type_T *item_type = &t_any; |
830 int idx; | 834 int idx; |
831 int prev_lnum = cctx->ctx_prev_lnum; | 835 int prev_lnum = cctx->ctx_prev_lnum; |
865 } | 869 } |
866 | 870 |
867 scope = new_scope(cctx, FOR_SCOPE); | 871 scope = new_scope(cctx, FOR_SCOPE); |
868 if (scope == NULL) | 872 if (scope == NULL) |
869 return NULL; | 873 return NULL; |
874 if (scope->se_loop_depth == MAX_LOOP_DEPTH) | |
875 { | |
876 emsg(_(e_loop_nesting_too_deep)); | |
877 return NULL; | |
878 } | |
879 ++scope->se_loop_depth; | |
870 forscope = &scope->se_u.se_for; | 880 forscope = &scope->se_u.se_for; |
871 | 881 |
872 // Reserve a variable to store the loop iteration counter and initialize it | 882 // Reserve a variable to store the loop iteration counter and initialize it |
873 // to -1. | 883 // to -1. |
874 loop_lvar = reserve_local(cctx, (char_u *)"", 0, FALSE, &t_number); | 884 loop_lvar = reserve_local(cctx, (char_u *)"", 0, FALSE, &t_number); |
875 if (loop_lvar == NULL) | 885 if (loop_lvar == NULL) |
876 { | 886 { |
877 drop_scope(cctx); | 887 drop_scope(cctx); |
878 return NULL; // out of memory | 888 return NULL; // out of memory |
879 } | 889 } |
880 generate_STORENR(cctx, loop_lvar->lv_idx, -1); | 890 // get the index before a following reserve_local() makes the lval invalid |
891 loop_lvar_idx = loop_lvar->lv_idx; | |
892 generate_STORENR(cctx, loop_lvar_idx, -1); | |
881 | 893 |
882 // Reserve a variable to store ec_funcrefs.ga_len, used in ISN_ENDLOOP. | 894 // Reserve a variable to store ec_funcrefs.ga_len, used in ISN_ENDLOOP. |
883 // The variable index is always the loop var index plus one. | 895 // The variable index is always the loop var index plus one. |
884 // It is not used when no closures are encountered, we don't know yet. | 896 // It is not used when no closures are encountered, we don't know yet. |
885 funcref_lvar = reserve_local(cctx, (char_u *)"", 0, FALSE, &t_number); | 897 funcref_lvar = reserve_local(cctx, (char_u *)"", 0, FALSE, &t_number); |
886 if (funcref_lvar == NULL) | 898 if (funcref_lvar == NULL) |
887 { | 899 { |
888 drop_scope(cctx); | 900 drop_scope(cctx); |
889 return NULL; // out of memory | 901 return NULL; // out of memory |
890 } | 902 } |
903 // get the index before a following reserve_local() makes the lval invalid | |
904 funcref_lvar_idx = funcref_lvar->lv_idx; | |
891 | 905 |
892 // compile "expr", it remains on the stack until "endfor" | 906 // compile "expr", it remains on the stack until "endfor" |
893 arg = p; | 907 arg = p; |
894 if (compile_expr0(&arg, cctx) == FAIL) | 908 if (compile_expr0(&arg, cctx) == FAIL) |
895 { | 909 { |
949 isn = generate_instr_debug(cctx); | 963 isn = generate_instr_debug(cctx); |
950 ++isn->isn_arg.debug.dbg_var_names_len; | 964 ++isn->isn_arg.debug.dbg_var_names_len; |
951 cctx->ctx_prev_lnum = save_prev_lnum; | 965 cctx->ctx_prev_lnum = save_prev_lnum; |
952 } | 966 } |
953 | 967 |
954 generate_FOR(cctx, loop_lvar->lv_idx); | 968 generate_FOR(cctx, loop_lvar_idx); |
955 | 969 |
956 arg = arg_start; | 970 arg = arg_start; |
957 if (var_list) | 971 if (var_list) |
958 { | 972 { |
959 generate_UNPACK(cctx, var_count, semicolon); | 973 generate_UNPACK(cctx, var_count, semicolon); |
1051 arg = skipwhite(p); | 1065 arg = skipwhite(p); |
1052 vim_free(name); | 1066 vim_free(name); |
1053 } | 1067 } |
1054 | 1068 |
1055 // remember the number of variables and closures, used for ENDLOOP | 1069 // remember the number of variables and closures, used for ENDLOOP |
1056 compile_fill_loop_info(&forscope->fs_loop_info, | 1070 compile_fill_loop_info(&forscope->fs_loop_info, funcref_lvar_idx, cctx); |
1057 funcref_lvar->lv_idx, cctx); | 1071 forscope->fs_loop_info.li_depth = scope->se_loop_depth - 1; |
1058 } | 1072 } |
1059 | 1073 |
1060 return arg_end; | 1074 return arg_end; |
1061 | 1075 |
1062 failed: | 1076 failed: |
1073 static int | 1087 static int |
1074 compile_loop_end(loop_info_T *loop_info, cctx_T *cctx) | 1088 compile_loop_end(loop_info_T *loop_info, cctx_T *cctx) |
1075 { | 1089 { |
1076 if (cctx->ctx_locals.ga_len > loop_info->li_local_count | 1090 if (cctx->ctx_locals.ga_len > loop_info->li_local_count |
1077 && cctx->ctx_closure_count > loop_info->li_closure_count) | 1091 && cctx->ctx_closure_count > loop_info->li_closure_count) |
1078 return generate_ENDLOOP(cctx, loop_info->li_funcref_idx, | 1092 return generate_ENDLOOP(cctx, loop_info); |
1079 loop_info->li_local_count); | |
1080 return OK; | 1093 return OK; |
1081 } | 1094 } |
1082 | 1095 |
1083 /* | 1096 /* |
1084 * compile "endfor" | 1097 * compile "endfor" |
1149 { | 1162 { |
1150 char_u *p = arg; | 1163 char_u *p = arg; |
1151 scope_T *scope; | 1164 scope_T *scope; |
1152 whilescope_T *whilescope; | 1165 whilescope_T *whilescope; |
1153 lvar_T *funcref_lvar; | 1166 lvar_T *funcref_lvar; |
1167 int funcref_lvar_idx; | |
1154 | 1168 |
1155 scope = new_scope(cctx, WHILE_SCOPE); | 1169 scope = new_scope(cctx, WHILE_SCOPE); |
1156 if (scope == NULL) | 1170 if (scope == NULL) |
1157 return NULL; | 1171 return NULL; |
1172 if (scope->se_loop_depth == MAX_LOOP_DEPTH) | |
1173 { | |
1174 emsg(_(e_loop_nesting_too_deep)); | |
1175 return NULL; | |
1176 } | |
1177 ++scope->se_loop_depth; | |
1158 whilescope = &scope->se_u.se_while; | 1178 whilescope = &scope->se_u.se_while; |
1159 | 1179 |
1160 // "endwhile" jumps back here, one before when profiling or using cmdmods | 1180 // "endwhile" jumps back here, one before when profiling or using cmdmods |
1161 whilescope->ws_top_label = current_instr_idx(cctx); | 1181 whilescope->ws_top_label = current_instr_idx(cctx); |
1162 | 1182 |
1166 if (funcref_lvar == NULL) | 1186 if (funcref_lvar == NULL) |
1167 { | 1187 { |
1168 drop_scope(cctx); | 1188 drop_scope(cctx); |
1169 return NULL; // out of memory | 1189 return NULL; // out of memory |
1170 } | 1190 } |
1191 // get the index before a following reserve_local() makes the lval invalid | |
1192 funcref_lvar_idx = funcref_lvar->lv_idx; | |
1171 | 1193 |
1172 // remember the number of variables and closures, used for ENDLOOP | 1194 // remember the number of variables and closures, used for ENDLOOP |
1173 compile_fill_loop_info(&whilescope->ws_loop_info, | 1195 compile_fill_loop_info(&whilescope->ws_loop_info, funcref_lvar_idx, cctx); |
1174 funcref_lvar->lv_idx, cctx); | 1196 whilescope->ws_loop_info.li_depth = scope->se_loop_depth - 1; |
1175 | 1197 |
1176 // compile "expr" | 1198 // compile "expr" |
1177 if (compile_expr0(&p, cctx) == FAIL) | 1199 if (compile_expr0(&p, cctx) == FAIL) |
1178 return NULL; | 1200 return NULL; |
1179 | 1201 |
1191 // CMDMOD_REV must come before the jump | 1213 // CMDMOD_REV must come before the jump |
1192 generate_undo_cmdmods(cctx); | 1214 generate_undo_cmdmods(cctx); |
1193 | 1215 |
1194 // "while_end" is set when ":endwhile" is found | 1216 // "while_end" is set when ":endwhile" is found |
1195 if (compile_jump_to_end(&whilescope->ws_end_label, | 1217 if (compile_jump_to_end(&whilescope->ws_end_label, |
1196 JUMP_WHILE_FALSE, funcref_lvar->lv_idx, cctx) == FAIL) | 1218 JUMP_WHILE_FALSE, funcref_lvar_idx, cctx) == FAIL) |
1197 return FAIL; | 1219 return FAIL; |
1198 } | 1220 } |
1199 | 1221 |
1200 return p; | 1222 return p; |
1201 } | 1223 } |
1247 return arg; | 1269 return arg; |
1248 } | 1270 } |
1249 | 1271 |
1250 /* | 1272 /* |
1251 * Get the current information about variables declared inside a loop. | 1273 * Get the current information about variables declared inside a loop. |
1252 * Returns zero if there are none, otherwise the count. | 1274 * Returns TRUE if there are any and fills "lvi". |
1253 * "loop_var_idx" is then set to the index of the first variable. | 1275 */ |
1254 */ | 1276 int |
1255 short | 1277 get_loop_var_info(cctx_T *cctx, loopvarinfo_T *lvi) |
1256 get_loop_var_info(cctx_T *cctx, short *loop_var_idx) | |
1257 { | 1278 { |
1258 scope_T *scope = cctx->ctx_scope; | 1279 scope_T *scope = cctx->ctx_scope; |
1259 int start_local_count; | 1280 int prev_local_count = 0; |
1260 | 1281 |
1261 while (scope != NULL && scope->se_type != WHILE_SCOPE | 1282 CLEAR_POINTER(lvi); |
1283 for (;;) | |
1284 { | |
1285 loop_info_T *loopinfo; | |
1286 int cur_local_last; | |
1287 int start_local_count; | |
1288 | |
1289 while (scope != NULL && scope->se_type != WHILE_SCOPE | |
1262 && scope->se_type != FOR_SCOPE) | 1290 && scope->se_type != FOR_SCOPE) |
1291 scope = scope->se_outer; | |
1292 if (scope == NULL) | |
1293 break; | |
1294 | |
1295 if (scope->se_type == WHILE_SCOPE) | |
1296 { | |
1297 loopinfo = &scope->se_u.se_while.ws_loop_info; | |
1298 // :while reserves one variable for funcref count | |
1299 cur_local_last = loopinfo->li_local_count - 1; | |
1300 } | |
1301 else | |
1302 { | |
1303 loopinfo = &scope->se_u.se_for.fs_loop_info; | |
1304 // :for reserves three variable: loop count, funcref count and loop | |
1305 // var | |
1306 cur_local_last = loopinfo->li_local_count - 3; | |
1307 } | |
1308 | |
1309 start_local_count = loopinfo->li_local_count; | |
1310 if (cctx->ctx_locals.ga_len > start_local_count) | |
1311 { | |
1312 lvi->lvi_loop[loopinfo->li_depth].var_idx = | |
1313 (short)start_local_count; | |
1314 lvi->lvi_loop[loopinfo->li_depth].var_count = | |
1315 (short)(cctx->ctx_locals.ga_len - start_local_count | |
1316 - prev_local_count); | |
1317 if (lvi->lvi_depth == 0) | |
1318 lvi->lvi_depth = loopinfo->li_depth + 1; | |
1319 } | |
1320 | |
1263 scope = scope->se_outer; | 1321 scope = scope->se_outer; |
1264 if (scope == NULL) | 1322 prev_local_count = cctx->ctx_locals.ga_len - cur_local_last; |
1265 return 0; | 1323 } |
1266 | 1324 return lvi->lvi_depth > 0; |
1267 if (scope->se_type == WHILE_SCOPE) | 1325 } |
1268 start_local_count = scope->se_u.se_while.ws_loop_info.li_local_count; | 1326 |
1269 else | 1327 /* |
1270 start_local_count = scope->se_u.se_for.fs_loop_info.li_local_count; | 1328 * Get the index of the variable "idx" in a loop, if any. |
1271 if (cctx->ctx_locals.ga_len > start_local_count) | 1329 */ |
1272 { | 1330 void |
1273 *loop_var_idx = (short)start_local_count; | 1331 get_loop_var_idx(cctx_T *cctx, int idx, lvar_T *lvar) |
1274 return (short)(cctx->ctx_locals.ga_len - start_local_count); | 1332 { |
1275 } | 1333 loopvarinfo_T lvi; |
1276 return 0; | 1334 |
1277 } | 1335 lvar->lv_loop_depth = -1; |
1278 | 1336 lvar->lv_loop_idx = -1; |
1279 /* | 1337 if (get_loop_var_info(cctx, &lvi)) |
1280 * Get the index of the first variable in a loop, if any. | 1338 { |
1281 * Returns -1 if none. | 1339 int depth; |
1282 */ | 1340 |
1283 int | 1341 for (depth = lvi.lvi_depth - 1; depth >= 0; --depth) |
1284 get_loop_var_idx(cctx_T *cctx) | 1342 if (idx >= lvi.lvi_loop[depth].var_idx |
1285 { | 1343 && idx < lvi.lvi_loop[depth].var_idx |
1286 short loop_var_idx; | 1344 + lvi.lvi_loop[depth].var_count) |
1287 | 1345 { |
1288 if (get_loop_var_info(cctx, &loop_var_idx) > 0) | 1346 lvar->lv_loop_depth = depth; |
1289 return loop_var_idx; | 1347 lvar->lv_loop_idx = lvi.lvi_loop[depth].var_idx; |
1290 return -1; | 1348 return; |
1349 } | |
1350 } | |
1291 } | 1351 } |
1292 | 1352 |
1293 /* | 1353 /* |
1294 * Common for :break, :continue and :return | 1354 * Common for :break, :continue and :return |
1295 */ | 1355 */ |