Mercurial > vim
comparison src/vim9instr.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 | 029c59bf78f1 |
children | 72e6073a2822 |
comparison
equal
deleted
inserted
replaced
30332:462d122636b3 | 30333:fc0830246f49 |
---|---|
995 int | 995 int |
996 generate_LOADOUTER( | 996 generate_LOADOUTER( |
997 cctx_T *cctx, | 997 cctx_T *cctx, |
998 int idx, | 998 int idx, |
999 int nesting, | 999 int nesting, |
1000 int loop_depth, | |
1000 int loop_idx, | 1001 int loop_idx, |
1001 type_T *type) | 1002 type_T *type) |
1002 { | 1003 { |
1003 isn_T *isn; | 1004 isn_T *isn; |
1004 | 1005 |
1006 if ((isn = generate_instr_type2(cctx, ISN_LOADOUTER, type, type)) == NULL) | 1007 if ((isn = generate_instr_type2(cctx, ISN_LOADOUTER, type, type)) == NULL) |
1007 return FAIL; | 1008 return FAIL; |
1008 if (nesting == 1 && loop_idx >= 0 && idx >= loop_idx) | 1009 if (nesting == 1 && loop_idx >= 0 && idx >= loop_idx) |
1009 { | 1010 { |
1010 // Load a variable defined in a loop. A copy will be made at the end | 1011 // Load a variable defined in a loop. A copy will be made at the end |
1011 // of the loop. TODO: how about deeper nesting? | 1012 // of the loop. |
1012 isn->isn_arg.outer.outer_idx = idx - loop_idx; | 1013 isn->isn_arg.outer.outer_idx = idx - loop_idx; |
1013 isn->isn_arg.outer.outer_depth = OUTER_LOOP_DEPTH; | 1014 isn->isn_arg.outer.outer_depth = -loop_depth - 1; |
1014 } | 1015 } |
1015 else | 1016 else |
1016 { | 1017 { |
1017 isn->isn_arg.outer.outer_idx = idx; | 1018 isn->isn_arg.outer.outer_idx = idx; |
1018 isn->isn_arg.outer.outer_depth = nesting; | 1019 isn->isn_arg.outer.outer_depth = nesting; |
1205 isn_T **isnp) | 1206 isn_T **isnp) |
1206 { | 1207 { |
1207 isn_T *isn; | 1208 isn_T *isn; |
1208 type_T *type; | 1209 type_T *type; |
1209 funcref_extra_T *extra; | 1210 funcref_extra_T *extra; |
1210 short loop_var_idx; | 1211 loopvarinfo_T loopinfo; |
1211 short loop_var_count; | 1212 int has_vars; |
1212 | 1213 |
1213 RETURN_OK_IF_SKIP(cctx); | 1214 RETURN_OK_IF_SKIP(cctx); |
1214 if ((isn = generate_instr(cctx, ISN_FUNCREF)) == NULL) | 1215 if ((isn = generate_instr(cctx, ISN_FUNCREF)) == NULL) |
1215 return FAIL; | 1216 return FAIL; |
1216 if (isnp != NULL) | 1217 if (isnp != NULL) |
1217 *isnp = isn; | 1218 *isnp = isn; |
1218 | 1219 |
1219 loop_var_count = get_loop_var_info(cctx, &loop_var_idx); | 1220 has_vars = get_loop_var_info(cctx, &loopinfo); |
1220 if (ufunc->uf_def_status == UF_NOT_COMPILED || loop_var_count > 0) | 1221 if (ufunc->uf_def_status == UF_NOT_COMPILED || has_vars) |
1221 { | 1222 { |
1222 extra = ALLOC_CLEAR_ONE(funcref_extra_T); | 1223 extra = ALLOC_CLEAR_ONE(funcref_extra_T); |
1223 if (extra == NULL) | 1224 if (extra == NULL) |
1224 return FAIL; | 1225 return FAIL; |
1225 isn->isn_arg.funcref.fr_extra = extra; | 1226 isn->isn_arg.funcref.fr_extra = extra; |
1226 extra->fre_loop_var_idx = loop_var_idx; | 1227 extra->fre_loopvar_info = loopinfo; |
1227 extra->fre_loop_var_count = loop_var_count; | |
1228 } | 1228 } |
1229 if (ufunc->uf_def_status == UF_NOT_COMPILED) | 1229 if (ufunc->uf_def_status == UF_NOT_COMPILED) |
1230 extra->fre_func_name = vim_strsave(ufunc->uf_name); | 1230 extra->fre_func_name = vim_strsave(ufunc->uf_name); |
1231 else | 1231 else |
1232 isn->isn_arg.funcref.fr_dfunc_idx = ufunc->uf_dfunc_idx; | 1232 isn->isn_arg.funcref.fr_dfunc_idx = ufunc->uf_dfunc_idx; |
1233 | |
1234 // Reserve an extra variable to keep track of the number of closures | |
1235 // created. | |
1233 cctx->ctx_has_closure = 1; | 1236 cctx->ctx_has_closure = 1; |
1234 | 1237 |
1235 // If the referenced function is a closure, it may use items further up in | 1238 // If the referenced function is a closure, it may use items further up in |
1236 // the nested context, including this one. But not a function defined at | 1239 // the nested context, including this one. But not a function defined at |
1237 // the script level. | 1240 // the script level. |
1250 */ | 1253 */ |
1251 int | 1254 int |
1252 generate_NEWFUNC( | 1255 generate_NEWFUNC( |
1253 cctx_T *cctx, | 1256 cctx_T *cctx, |
1254 char_u *lambda_name, | 1257 char_u *lambda_name, |
1255 char_u *func_name, | 1258 char_u *func_name) |
1256 short loop_var_idx, | |
1257 short loop_var_count) | |
1258 { | 1259 { |
1259 isn_T *isn; | 1260 isn_T *isn; |
1260 int ret = OK; | 1261 int ret = OK; |
1261 | 1262 |
1262 if (cctx->ctx_skip != SKIP_YES) | 1263 if (cctx->ctx_skip != SKIP_YES) |
1269 | 1270 |
1270 if (arg == NULL) | 1271 if (arg == NULL) |
1271 ret = FAIL; | 1272 ret = FAIL; |
1272 else | 1273 else |
1273 { | 1274 { |
1275 // Reserve an extra variable to keep track of the number of | |
1276 // closures created. | |
1277 cctx->ctx_has_closure = 1; | |
1278 | |
1274 isn->isn_arg.newfunc.nf_arg = arg; | 1279 isn->isn_arg.newfunc.nf_arg = arg; |
1275 arg->nfa_lambda = lambda_name; | 1280 arg->nfa_lambda = lambda_name; |
1276 arg->nfa_global = func_name; | 1281 arg->nfa_global = func_name; |
1277 arg->nfa_loop_var_idx = loop_var_idx; | 1282 (void)get_loop_var_info(cctx, &arg->nfa_loopvar_info); |
1278 arg->nfa_loop_var_count = loop_var_count; | |
1279 return OK; | 1283 return OK; |
1280 } | 1284 } |
1281 } | 1285 } |
1282 } | 1286 } |
1283 vim_free(lambda_name); | 1287 vim_free(lambda_name); |
1369 isn_T *isn; | 1373 isn_T *isn; |
1370 | 1374 |
1371 RETURN_OK_IF_SKIP(cctx); | 1375 RETURN_OK_IF_SKIP(cctx); |
1372 if ((isn = generate_instr(cctx, ISN_FOR)) == NULL) | 1376 if ((isn = generate_instr(cctx, ISN_FOR)) == NULL) |
1373 return FAIL; | 1377 return FAIL; |
1374 isn->isn_arg.forloop.for_idx = loop_idx; | 1378 isn->isn_arg.forloop.for_loop_idx = loop_idx; |
1375 | 1379 |
1376 // type doesn't matter, will be stored next | 1380 // type doesn't matter, will be stored next |
1377 return push_type_stack(cctx, &t_any); | 1381 return push_type_stack(cctx, &t_any); |
1378 } | 1382 } |
1379 | 1383 |
1380 int | 1384 int |
1381 generate_ENDLOOP( | 1385 generate_ENDLOOP(cctx_T *cctx, loop_info_T *loop_info) |
1382 cctx_T *cctx, | |
1383 int funcref_idx, | |
1384 int prev_local_count) | |
1385 { | 1386 { |
1386 isn_T *isn; | 1387 isn_T *isn; |
1387 | 1388 |
1388 RETURN_OK_IF_SKIP(cctx); | 1389 RETURN_OK_IF_SKIP(cctx); |
1389 if ((isn = generate_instr(cctx, ISN_ENDLOOP)) == NULL) | 1390 if ((isn = generate_instr(cctx, ISN_ENDLOOP)) == NULL) |
1390 return FAIL; | 1391 return FAIL; |
1391 isn->isn_arg.endloop.end_funcref_idx = funcref_idx; | 1392 isn->isn_arg.endloop.end_depth = loop_info->li_depth; |
1392 isn->isn_arg.endloop.end_var_idx = prev_local_count; | 1393 isn->isn_arg.endloop.end_funcref_idx = loop_info->li_funcref_idx; |
1394 isn->isn_arg.endloop.end_var_idx = loop_info->li_local_count; | |
1393 isn->isn_arg.endloop.end_var_count = | 1395 isn->isn_arg.endloop.end_var_count = |
1394 cctx->ctx_locals.ga_len - prev_local_count; | 1396 cctx->ctx_locals.ga_len - loop_info->li_local_count; |
1395 return OK; | 1397 return OK; |
1396 } | 1398 } |
1397 | 1399 |
1398 /* | 1400 /* |
1399 * Generate an ISN_TRYCONT instruction. | 1401 * Generate an ISN_TRYCONT instruction. |