Mercurial > vim
comparison src/vim9compile.c @ 27611:e311a80f8cbe v8.2.4332
patch 8.2.4332: Vim9: incomplete test for existing script variable in block
Commit: https://github.com/vim/vim/commit/dce2441a603f2c9343a4a46091283a32420d80a2
Author: Bram Moolenaar <Bram@vim.org>
Date: Tue Feb 8 20:35:30 2022 +0000
patch 8.2.4332: Vim9: incomplete test for existing script variable in block
Problem: Vim9: incomplete test for existing script variable in block.
Solution: Add a couple more tests. Fix uncovered problem.
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Tue, 08 Feb 2022 21:45:03 +0100 |
parents | d504745607bc |
children | 42d0279c6e7c |
comparison
equal
deleted
inserted
replaced
27610:81772f743738 | 27611:e311a80f8cbe |
---|---|
150 | 150 |
151 /* | 151 /* |
152 * Lookup a script-local variable in the current script, possibly defined in a | 152 * Lookup a script-local variable in the current script, possibly defined in a |
153 * block that contains the function "cctx->ctx_ufunc". | 153 * block that contains the function "cctx->ctx_ufunc". |
154 * "cctx" is NULL at the script level. | 154 * "cctx" is NULL at the script level. |
155 * "cstack_T" is NULL in a function. | |
155 * If "len" is <= 0 "name" must be NUL terminated. | 156 * If "len" is <= 0 "name" must be NUL terminated. |
156 * Return NULL when not found. | 157 * Return NULL when not found. |
157 */ | 158 */ |
158 static sallvar_T * | 159 static sallvar_T * |
159 find_script_var(char_u *name, size_t len, cctx_T *cctx) | 160 find_script_var(char_u *name, size_t len, cctx_T *cctx, cstack_T *cstack) |
160 { | 161 { |
161 scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid); | 162 scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid); |
162 hashitem_T *hi; | 163 hashitem_T *hi; |
163 int cc; | 164 int cc; |
164 sallvar_T *sav; | 165 sallvar_T *sav; |
181 // variable defined in the top script scope is always visible | 182 // variable defined in the top script scope is always visible |
182 return sav; | 183 return sav; |
183 | 184 |
184 if (cctx == NULL) | 185 if (cctx == NULL) |
185 { | 186 { |
186 // Not in a function scope, find variable with block id equal to or | 187 // Not in a function scope, find variable with block ID equal to or |
187 // smaller than the current block id. | 188 // smaller than the current block id. If "cstack" is not NULL go up |
189 // the block scopes (more accurate). | |
188 while (sav != NULL) | 190 while (sav != NULL) |
189 { | 191 { |
190 if (sav->sav_block_id <= si->sn_current_block_id) | 192 if (cstack != NULL) |
193 { | |
194 int idx; | |
195 | |
196 for (idx = cstack->cs_idx; idx >= 0; --idx) | |
197 if (cstack->cs_block_id[idx] == sav->sav_block_id) | |
198 break; | |
199 if (idx >= 0) | |
200 break; | |
201 } | |
202 else if (sav->sav_block_id <= si->sn_current_block_id) | |
191 break; | 203 break; |
192 sav = sav->sav_next; | 204 sav = sav->sav_next; |
193 } | 205 } |
194 return sav; | 206 return sav; |
195 } | 207 } |
223 } | 235 } |
224 | 236 |
225 /* | 237 /* |
226 * Lookup a variable (without s: prefix) in the current script. | 238 * Lookup a variable (without s: prefix) in the current script. |
227 * "cctx" is NULL at the script level. | 239 * "cctx" is NULL at the script level. |
240 * "cstack" is NULL in a function. | |
228 * Returns OK or FAIL. | 241 * Returns OK or FAIL. |
229 */ | 242 */ |
230 int | 243 int |
231 script_var_exists(char_u *name, size_t len, cctx_T *cctx) | 244 script_var_exists(char_u *name, size_t len, cctx_T *cctx, cstack_T *cstack) |
232 { | 245 { |
233 if (current_sctx.sc_sid <= 0) | 246 if (current_sctx.sc_sid <= 0) |
234 return FAIL; | 247 return FAIL; |
235 if (script_is_vim9()) | 248 if (script_is_vim9()) |
236 { | 249 { |
237 // Check script variables that were visible where the function was | 250 // Check script variables that were visible where the function was |
238 // defined. | 251 // defined. |
239 if (find_script_var(name, len, cctx) != NULL) | 252 if (find_script_var(name, len, cctx, cstack) != NULL) |
240 return OK; | 253 return OK; |
241 } | 254 } |
242 else | 255 else |
243 { | 256 { |
244 hashtab_T *ht = &SCRIPT_VARS(current_sctx.sc_sid); | 257 hashtab_T *ht = &SCRIPT_VARS(current_sctx.sc_sid); |
265 variable_exists(char_u *name, size_t len, cctx_T *cctx) | 278 variable_exists(char_u *name, size_t len, cctx_T *cctx) |
266 { | 279 { |
267 return (cctx != NULL | 280 return (cctx != NULL |
268 && (lookup_local(name, len, NULL, cctx) == OK | 281 && (lookup_local(name, len, NULL, cctx) == OK |
269 || arg_exists(name, len, NULL, NULL, NULL, cctx) == OK)) | 282 || arg_exists(name, len, NULL, NULL, NULL, cctx) == OK)) |
270 || script_var_exists(name, len, cctx) == OK | 283 || script_var_exists(name, len, cctx, NULL) == OK |
271 || find_imported(name, len, FALSE, cctx) != NULL; | 284 || find_imported(name, len, FALSE, cctx) != NULL; |
272 } | 285 } |
273 | 286 |
274 /* | 287 /* |
275 * Return TRUE if "name" is a local variable, argument, script variable, | 288 * Return TRUE if "name" is a local variable, argument, script variable, |
307 * Does not check the global namespace. | 320 * Does not check the global namespace. |
308 * If "is_arg" is TRUE the error message is for an argument name. | 321 * If "is_arg" is TRUE the error message is for an argument name. |
309 * Return FAIL and give an error if it defined. | 322 * Return FAIL and give an error if it defined. |
310 */ | 323 */ |
311 int | 324 int |
312 check_defined(char_u *p, size_t len, cctx_T *cctx, int is_arg) | 325 check_defined( |
326 char_u *p, | |
327 size_t len, | |
328 cctx_T *cctx, | |
329 cstack_T *cstack, | |
330 int is_arg) | |
313 { | 331 { |
314 int c = p[len]; | 332 int c = p[len]; |
315 ufunc_T *ufunc = NULL; | 333 ufunc_T *ufunc = NULL; |
316 | 334 |
317 // underscore argument is OK | 335 // underscore argument is OK |
318 if (len == 1 && *p == '_') | 336 if (len == 1 && *p == '_') |
319 return OK; | 337 return OK; |
320 | 338 |
321 if (script_var_exists(p, len, cctx) == OK) | 339 if (script_var_exists(p, len, cctx, cstack) == OK) |
322 { | 340 { |
323 if (is_arg) | 341 if (is_arg) |
324 semsg(_(e_argument_already_declared_in_script_str), p); | 342 semsg(_(e_argument_already_declared_in_script_str), p); |
325 else | 343 else |
326 semsg(_(e_variable_already_declared_in_script_str), p); | 344 semsg(_(e_variable_already_declared_in_script_str), p); |
524 | 542 |
525 if (!SCRIPT_ID_VALID(sid)) | 543 if (!SCRIPT_ID_VALID(sid)) |
526 return -1; | 544 return -1; |
527 if (sid == current_sctx.sc_sid) | 545 if (sid == current_sctx.sc_sid) |
528 { | 546 { |
529 sallvar_T *sav = find_script_var(name, 0, cctx); | 547 sallvar_T *sav = find_script_var(name, 0, cctx, NULL); |
530 | 548 |
531 if (sav == NULL) | 549 if (sav == NULL) |
532 return -2; | 550 return -2; |
533 idx = sav->sav_var_vals_idx; | 551 idx = sav->sav_var_vals_idx; |
534 sv = ((svar_T *)si->sn_var_vals.ga_data) + idx; | 552 sv = ((svar_T *)si->sn_var_vals.ga_data) + idx; |
882 if (name_start[1] == ':' && !is_global) | 900 if (name_start[1] == ':' && !is_global) |
883 { | 901 { |
884 semsg(_(e_namespace_not_supported_str), name_start); | 902 semsg(_(e_namespace_not_supported_str), name_start); |
885 return NULL; | 903 return NULL; |
886 } | 904 } |
887 if (check_defined(name_start, name_end - name_start, cctx, FALSE) == FAIL) | 905 if (check_defined(name_start, name_end - name_start, cctx, |
906 NULL, FALSE) == FAIL) | |
888 return NULL; | 907 return NULL; |
889 if (!ASCII_ISUPPER(is_global ? name_start[2] : name_start[0])) | 908 if (!ASCII_ISUPPER(is_global ? name_start[2] : name_start[0])) |
890 { | 909 { |
891 semsg(_(e_function_name_must_start_with_capital_str), name_start); | 910 semsg(_(e_function_name_must_start_with_capital_str), name_start); |
892 return NULL; | 911 return NULL; |
1354 { | 1373 { |
1355 int script_namespace = lhs->lhs_varlen > 1 | 1374 int script_namespace = lhs->lhs_varlen > 1 |
1356 && STRNCMP(var_start, "s:", 2) == 0; | 1375 && STRNCMP(var_start, "s:", 2) == 0; |
1357 int script_var = (script_namespace | 1376 int script_var = (script_namespace |
1358 ? script_var_exists(var_start + 2, lhs->lhs_varlen - 2, | 1377 ? script_var_exists(var_start + 2, lhs->lhs_varlen - 2, |
1359 cctx) | 1378 cctx, NULL) |
1360 : script_var_exists(var_start, lhs->lhs_varlen, | 1379 : script_var_exists(var_start, lhs->lhs_varlen, |
1361 cctx)) == OK; | 1380 cctx, NULL)) == OK; |
1362 imported_T *import = | 1381 imported_T *import = |
1363 find_imported(var_start, lhs->lhs_varlen, FALSE, cctx); | 1382 find_imported(var_start, lhs->lhs_varlen, FALSE, cctx); |
1364 | 1383 |
1365 if (script_namespace || script_var || import != NULL) | 1384 if (script_namespace || script_var || import != NULL) |
1366 { | 1385 { |
1440 + lhs->lhs_scriptvar_idx; | 1459 + lhs->lhs_scriptvar_idx; |
1441 lhs->lhs_type = sv->sv_type; | 1460 lhs->lhs_type = sv->sv_type; |
1442 } | 1461 } |
1443 } | 1462 } |
1444 } | 1463 } |
1445 else if (check_defined(var_start, lhs->lhs_varlen, cctx, FALSE) | 1464 else if (check_defined(var_start, lhs->lhs_varlen, cctx, |
1446 == FAIL) | 1465 NULL, FALSE) == FAIL) |
1447 return FAIL; | 1466 return FAIL; |
1448 } | 1467 } |
1449 } | 1468 } |
1450 | 1469 |
1451 if (declare_error) | 1470 if (declare_error) |
2468 | 2487 |
2469 // Check for arguments shadowing variables from the context. | 2488 // Check for arguments shadowing variables from the context. |
2470 for (i = 0; i < ufunc->uf_args.ga_len; ++i) | 2489 for (i = 0; i < ufunc->uf_args.ga_len; ++i) |
2471 { | 2490 { |
2472 arg = ((char_u **)(ufunc->uf_args.ga_data))[i]; | 2491 arg = ((char_u **)(ufunc->uf_args.ga_data))[i]; |
2473 if (check_defined(arg, STRLEN(arg), cctx, TRUE) == FAIL) | 2492 if (check_defined(arg, STRLEN(arg), cctx, NULL, TRUE) == FAIL) |
2474 { | 2493 { |
2475 r = FAIL; | 2494 r = FAIL; |
2476 break; | 2495 break; |
2477 } | 2496 } |
2478 } | 2497 } |