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 }