comparison src/vim9compile.c @ 22596:107eae953b87 v8.2.1846

patch 8.2.1846: Vim9: block variables are not found in compiled function Commit: https://github.com/vim/vim/commit/fbbcd00367e1a4fafd047d42ffce0e5dce88925c Author: Bram Moolenaar <Bram@vim.org> Date: Thu Oct 15 12:46:44 2020 +0200 patch 8.2.1846: Vim9: block variables are not found in compiled function Problem: Vim9: variables declared in a local block are not found in when a function is compiled. Solution: Look for script variables in sn_all_vars.
author Bram Moolenaar <Bram@vim.org>
date Thu, 15 Oct 2020 13:00:05 +0200
parents c271498e03b2
children c7ef64b85e9b
comparison
equal deleted inserted replaced
22595:a42172375311 22596:107eae953b87
193 * Returns the argument type in "type" 193 * Returns the argument type in "type"
194 * Sets "gen_load_outer" to TRUE if found in outer scope. 194 * Sets "gen_load_outer" to TRUE if found in outer scope.
195 * Returns OK when found, FAIL otherwise. 195 * Returns OK when found, FAIL otherwise.
196 */ 196 */
197 static int 197 static int
198 lookup_arg( 198 arg_exists(
199 char_u *name, 199 char_u *name,
200 size_t len, 200 size_t len,
201 int *idxp, 201 int *idxp,
202 type_T **type, 202 type_T **type,
203 int *gen_load_outer, 203 int *gen_load_outer,
245 } 245 }
246 246
247 if (cctx->ctx_outer != NULL) 247 if (cctx->ctx_outer != NULL)
248 { 248 {
249 // Lookup the name for an argument of the outer function. 249 // Lookup the name for an argument of the outer function.
250 if (lookup_arg(name, len, idxp, type, gen_load_outer, cctx->ctx_outer) 250 if (arg_exists(name, len, idxp, type, gen_load_outer, cctx->ctx_outer)
251 == OK) 251 == OK)
252 { 252 {
253 *gen_load_outer = TRUE; 253 *gen_load_outer = TRUE;
254 return OK; 254 return OK;
255 } 255 }
257 257
258 return FAIL; 258 return FAIL;
259 } 259 }
260 260
261 /* 261 /*
262 * Lookup a script-local variable in the current script, possibly defined in a
263 * block that contains the function "cctx->ctx_ufunc".
264 * "cctx" is NULL at the script level.
265 * if "len" is <= 0 "name" must be NUL terminated.
266 * Return NULL when not found.
267 */
268 static sallvar_T *
269 find_script_var(char_u *name, size_t len, cctx_T *cctx)
270 {
271 scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid);
272 hashitem_T *hi;
273 int cc;
274 sallvar_T *sav;
275 ufunc_T *ufunc;
276
277 // Find the list of all script variables with the right name.
278 if (len > 0)
279 {
280 cc = name[len];
281 name[len] = NUL;
282 }
283 hi = hash_find(&si->sn_all_vars.dv_hashtab, name);
284 if (len > 0)
285 name[len] = cc;
286 if (HASHITEM_EMPTY(hi))
287 return NULL;
288
289 sav = HI2SAV(hi);
290 if (sav->sav_block_id == 0 || cctx == NULL)
291 // variable defined in the script scope or not in a function.
292 return sav;
293
294 // Go over the variables with this name and find one that was visible
295 // from the function.
296 ufunc = cctx->ctx_ufunc;
297 while (sav != NULL)
298 {
299 int idx;
300
301 // Go over the blocks that this function was defined in. If the
302 // variable block ID matches it was visible to the function.
303 for (idx = 0; idx < ufunc->uf_block_depth; ++idx)
304 if (ufunc->uf_block_ids[idx] == sav->sav_block_id)
305 return sav;
306 sav = sav->sav_next;
307 }
308
309 return NULL;
310 }
311
312 /*
262 * Returnd TRUE if the script context is Vim9 script. 313 * Returnd TRUE if the script context is Vim9 script.
263 */ 314 */
264 static int 315 static int
265 script_is_vim9() 316 script_is_vim9()
266 { 317 {
267 return SCRIPT_ITEM(current_sctx.sc_sid)->sn_version == SCRIPT_VERSION_VIM9; 318 return SCRIPT_ITEM(current_sctx.sc_sid)->sn_version == SCRIPT_VERSION_VIM9;
268 } 319 }
269 320
270 /* 321 /*
271 * Lookup a variable in the current script. 322 * Lookup a variable (without s: prefix) in the current script.
272 * If "vim9script" is TRUE the script must be Vim9 script. Used for "var" 323 * If "vim9script" is TRUE the script must be Vim9 script. Used for "var"
273 * without "s:". 324 * without "s:".
325 * "cctx" is NULL at the script level.
274 * Returns OK or FAIL. 326 * Returns OK or FAIL.
275 */ 327 */
276 static int 328 static int
277 lookup_script(char_u *name, size_t len, int vim9script) 329 script_var_exists(char_u *name, size_t len, int vim9script, cctx_T *cctx)
278 { 330 {
279 int cc; 331 int is_vim9_script;
280 hashtab_T *ht;
281 dictitem_T *di;
282 332
283 if (current_sctx.sc_sid <= 0) 333 if (current_sctx.sc_sid <= 0)
284 return FAIL; 334 return FAIL;
285 ht = &SCRIPT_VARS(current_sctx.sc_sid); 335 is_vim9_script = script_is_vim9();
286 if (vim9script && !script_is_vim9()) 336 if (vim9script && !is_vim9_script)
287 return FAIL; 337 return FAIL;
288 cc = name[len]; 338 if (is_vim9_script)
289 name[len] = NUL; 339 {
290 di = find_var_in_ht(ht, 0, name, TRUE); 340 // Check script variables that were visible where the function was
291 name[len] = cc; 341 // defined.
292 return di == NULL ? FAIL: OK; 342 if (find_script_var(name, len, cctx) != NULL)
343 return OK;
344 }
345 else
346 {
347 hashtab_T *ht = &SCRIPT_VARS(current_sctx.sc_sid);
348 dictitem_T *di;
349 int cc;
350
351 // Check script variables that are currently visible
352 cc = name[len];
353 name[len] = NUL;
354 di = find_var_in_ht(ht, 0, name, TRUE);
355 name[len] = cc;
356 if (di != NULL)
357 return OK;
358 }
359
360 return FAIL;
293 } 361 }
294 362
295 /* 363 /*
296 * Check if "p[len]" is already defined, either in script "import_sid" or in 364 * Check if "p[len]" is already defined, either in script "import_sid" or in
297 * compilation context "cctx". 365 * compilation context "cctx". "cctx" is NULL at the script level.
298 * Does not check the global namespace. 366 * Does not check the global namespace.
299 * Return FAIL and give an error if it defined. 367 * Return FAIL and give an error if it defined.
300 */ 368 */
301 int 369 int
302 check_defined(char_u *p, size_t len, cctx_T *cctx) 370 check_defined(char_u *p, size_t len, cctx_T *cctx)
303 { 371 {
304 int c = p[len]; 372 int c = p[len];
305 ufunc_T *ufunc = NULL; 373 ufunc_T *ufunc = NULL;
306 374
307 p[len] = NUL; 375 p[len] = NUL;
308 if (lookup_script(p, len, FALSE) == OK 376 if (script_var_exists(p, len, FALSE, cctx) == OK
309 || (cctx != NULL 377 || (cctx != NULL
310 && (lookup_local(p, len, cctx) != NULL 378 && (lookup_local(p, len, cctx) != NULL
311 || lookup_arg(p, len, NULL, NULL, NULL, cctx) == OK)) 379 || arg_exists(p, len, NULL, NULL, NULL, cctx) == OK))
312 || find_imported(p, len, cctx) != NULL 380 || find_imported(p, len, cctx) != NULL
313 || (ufunc = find_func_even_dead(p, FALSE, cctx)) != NULL) 381 || (ufunc = find_func_even_dead(p, FALSE, cctx)) != NULL)
314 { 382 {
315 // A local or script-local function can shadow a global function. 383 // A local or script-local function can shadow a global function.
316 if (ufunc == NULL || !func_is_global(ufunc) 384 if (ufunc == NULL || !func_is_global(ufunc)
1697 int isConst, 1765 int isConst,
1698 type_T *type) 1766 type_T *type)
1699 { 1767 {
1700 lvar_T *lvar; 1768 lvar_T *lvar;
1701 1769
1702 if (lookup_arg(name, len, NULL, NULL, NULL, cctx) == OK) 1770 if (arg_exists(name, len, NULL, NULL, NULL, cctx) == OK)
1703 { 1771 {
1704 emsg_namelen(_(e_str_is_used_as_argument), name, (int)len); 1772 emsg_namelen(_(e_str_is_used_as_argument), name, (int)len);
1705 return NULL; 1773 return NULL;
1706 } 1774 }
1707 1775
1758 * Returns the index in "sn_var_vals" if found. 1826 * Returns the index in "sn_var_vals" if found.
1759 * If found but not in "sn_var_vals" returns -1. 1827 * If found but not in "sn_var_vals" returns -1.
1760 * If not found returns -2. 1828 * If not found returns -2.
1761 */ 1829 */
1762 int 1830 int
1763 get_script_item_idx(int sid, char_u *name, int check_writable) 1831 get_script_item_idx(int sid, char_u *name, int check_writable, cctx_T *cctx)
1764 { 1832 {
1765 hashtab_T *ht; 1833 hashtab_T *ht;
1766 dictitem_T *di; 1834 dictitem_T *di;
1767 scriptitem_T *si = SCRIPT_ITEM(sid); 1835 scriptitem_T *si = SCRIPT_ITEM(sid);
1836 svar_T *sv;
1768 int idx; 1837 int idx;
1769 1838
1770 // First look the name up in the hashtable.
1771 if (!SCRIPT_ID_VALID(sid)) 1839 if (!SCRIPT_ID_VALID(sid))
1772 return -1; 1840 return -1;
1841 if (sid == current_sctx.sc_sid)
1842 {
1843 sallvar_T *sav = find_script_var(name, (size_t)-1, cctx);
1844
1845 if (sav == NULL)
1846 return -2;
1847 idx = sav->sav_var_vals_idx;
1848 sv = ((svar_T *)si->sn_var_vals.ga_data) + idx;
1849 if (check_writable && sv->sv_const)
1850 semsg(_(e_readonlyvar), name);
1851 return idx;
1852 }
1853
1854 // First look the name up in the hashtable.
1773 ht = &SCRIPT_VARS(sid); 1855 ht = &SCRIPT_VARS(sid);
1774 di = find_var_in_ht(ht, 0, name, TRUE); 1856 di = find_var_in_ht(ht, 0, name, TRUE);
1775 if (di == NULL) 1857 if (di == NULL)
1776 return -2; 1858 return -2;
1777 1859
1778 // Now find the svar_T index in sn_var_vals. 1860 // Now find the svar_T index in sn_var_vals.
1779 for (idx = 0; idx < si->sn_var_vals.ga_len; ++idx) 1861 for (idx = 0; idx < si->sn_var_vals.ga_len; ++idx)
1780 { 1862 {
1781 svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data) + idx; 1863 sv = ((svar_T *)si->sn_var_vals.ga_data) + idx;
1782
1783 if (sv->sv_tv == &di->di_tv) 1864 if (sv->sv_tv == &di->di_tv)
1784 { 1865 {
1785 if (check_writable && sv->sv_const) 1866 if (check_writable && sv->sv_const)
1786 semsg(_(e_readonlyvar), name); 1867 semsg(_(e_readonlyvar), name);
1787 return idx; 1868 return idx;
2081 imported_T *import; 2162 imported_T *import;
2082 2163
2083 if (!SCRIPT_ID_VALID(current_sctx.sc_sid)) 2164 if (!SCRIPT_ID_VALID(current_sctx.sc_sid))
2084 return FAIL; 2165 return FAIL;
2085 si = SCRIPT_ITEM(current_sctx.sc_sid); 2166 si = SCRIPT_ITEM(current_sctx.sc_sid);
2086 idx = get_script_item_idx(current_sctx.sc_sid, name, FALSE); 2167 idx = get_script_item_idx(current_sctx.sc_sid, name, FALSE, cctx);
2087 if (idx == -1 || si->sn_version != SCRIPT_VERSION_VIM9) 2168 if (idx == -1 || si->sn_version != SCRIPT_VERSION_VIM9)
2088 { 2169 {
2089 // variable is not in sn_var_vals: old style script. 2170 // variable is not in sn_var_vals: old style script.
2090 return generate_OLDSCRIPT(cctx, ISN_LOADS, name, current_sctx.sc_sid, 2171 return generate_OLDSCRIPT(cctx, ISN_LOADS, name, current_sctx.sc_sid,
2091 &t_any); 2172 &t_any);
2128 while (eval_isnamec(*p)) 2209 while (eval_isnamec(*p))
2129 ++p; 2210 ++p;
2130 cc = *p; 2211 cc = *p;
2131 *p = NUL; 2212 *p = NUL;
2132 2213
2133 idx = find_exported(import->imp_sid, exp_name, &ufunc, &type); 2214 idx = find_exported(import->imp_sid, exp_name, &ufunc, &type, cctx);
2134 *p = cc; 2215 *p = cc;
2135 p = skipwhite(p); 2216 p = skipwhite(p);
2136 2217
2137 // TODO: what if it is a function? 2218 // TODO: what if it is a function?
2138 if (idx < 0) 2219 if (idx < 0)
2255 2336
2256 name = vim_strnsave(*arg, end - *arg); 2337 name = vim_strnsave(*arg, end - *arg);
2257 if (name == NULL) 2338 if (name == NULL)
2258 return FAIL; 2339 return FAIL;
2259 2340
2260 if (lookup_arg(*arg, len, &idx, &type, &gen_load_outer, cctx) == OK) 2341 if (arg_exists(*arg, len, &idx, &type, &gen_load_outer, cctx) == OK)
2261 { 2342 {
2262 if (!gen_load_outer) 2343 if (!gen_load_outer)
2263 gen_load = TRUE; 2344 gen_load = TRUE;
2264 } 2345 }
2265 else 2346 else
2277 } 2358 }
2278 else 2359 else
2279 { 2360 {
2280 // "var" can be script-local even without using "s:" if it 2361 // "var" can be script-local even without using "s:" if it
2281 // already exists in a Vim9 script or when it's imported. 2362 // already exists in a Vim9 script or when it's imported.
2282 if (lookup_script(*arg, len, TRUE) == OK 2363 if (script_var_exists(*arg, len, TRUE, cctx) == OK
2283 || find_imported(name, 0, cctx) != NULL) 2364 || find_imported(name, 0, cctx) != NULL)
2284 res = compile_load_scriptvar(cctx, name, *arg, &end, FALSE); 2365 res = compile_load_scriptvar(cctx, name, *arg, &end, FALSE);
2285 2366
2286 // When evaluating an expression and the name starts with an 2367 // When evaluating an expression and the name starts with an
2287 // uppercase letter or "x:" it can be a user defined function. 2368 // uppercase letter or "x:" it can be a user defined function.
4466 eap->getline = exarg_getline; 4547 eap->getline = exarg_getline;
4467 eap->cookie = cctx; 4548 eap->cookie = cctx;
4468 eap->skip = cctx->ctx_skip == SKIP_YES; 4549 eap->skip = cctx->ctx_skip == SKIP_YES;
4469 eap->forceit = FALSE; 4550 eap->forceit = FALSE;
4470 lambda_name = get_lambda_name(); 4551 lambda_name = get_lambda_name();
4471 ufunc = def_function(eap, lambda_name); 4552 ufunc = define_function(eap, lambda_name);
4472 4553
4473 if (ufunc == NULL) 4554 if (ufunc == NULL)
4474 return eap->skip ? (char_u *)"" : NULL; 4555 return eap->skip ? (char_u *)"" : NULL;
4475 if (ufunc->uf_def_status == UF_TO_BE_COMPILED 4556 if (ufunc->uf_def_status == UF_TO_BE_COMPILED
4476 && compile_def_function(ufunc, TRUE, cctx) == FAIL) 4557 && compile_def_function(ufunc, TRUE, cctx) == FAIL)
4492 else 4573 else
4493 { 4574 {
4494 // Define a local variable for the function reference. 4575 // Define a local variable for the function reference.
4495 lvar_T *lvar = reserve_local(cctx, name_start, name_end - name_start, 4576 lvar_T *lvar = reserve_local(cctx, name_start, name_end - name_start,
4496 TRUE, ufunc->uf_func_type); 4577 TRUE, ufunc->uf_func_type);
4578 int block_depth = cctx->ctx_ufunc->uf_block_depth;
4497 4579
4498 if (lvar == NULL) 4580 if (lvar == NULL)
4499 return NULL; 4581 return NULL;
4500 if (generate_FUNCREF(cctx, ufunc) == FAIL) 4582 if (generate_FUNCREF(cctx, ufunc) == FAIL)
4501 return NULL; 4583 return NULL;
4502 r = generate_STORE(cctx, ISN_STORE, lvar->lv_idx, NULL); 4584 r = generate_STORE(cctx, ISN_STORE, lvar->lv_idx, NULL);
4585
4586 // copy over the block scope IDs
4587 if (block_depth > 0)
4588 {
4589 ufunc->uf_block_ids = ALLOC_MULT(int, block_depth);
4590 if (ufunc->uf_block_ids != NULL)
4591 {
4592 mch_memmove(ufunc->uf_block_ids, cctx->ctx_ufunc->uf_block_ids,
4593 sizeof(int) * block_depth);
4594 ufunc->uf_block_depth = block_depth;
4595 }
4596 }
4503 } 4597 }
4504 4598
4505 // TODO: warning for trailing text? 4599 // TODO: warning for trailing text?
4506 return r == FAIL ? NULL : (char_u *)""; 4600 return r == FAIL ? NULL : (char_u *)"";
4507 } 4601 }
4898 4992
4899 lvar = lookup_local(var_start, varlen, cctx); 4993 lvar = lookup_local(var_start, varlen, cctx);
4900 if (lvar == NULL) 4994 if (lvar == NULL)
4901 { 4995 {
4902 CLEAR_FIELD(arg_lvar); 4996 CLEAR_FIELD(arg_lvar);
4903 if (lookup_arg(var_start, varlen, 4997 if (arg_exists(var_start, varlen,
4904 &arg_lvar.lv_idx, &arg_lvar.lv_type, 4998 &arg_lvar.lv_idx, &arg_lvar.lv_type,
4905 &arg_lvar.lv_from_outer, cctx) == OK) 4999 &arg_lvar.lv_from_outer, cctx) == OK)
4906 { 5000 {
4907 if (is_decl) 5001 if (is_decl)
4908 { 5002 {
4923 else 5017 else
4924 { 5018 {
4925 int script_namespace = varlen > 1 5019 int script_namespace = varlen > 1
4926 && STRNCMP(var_start, "s:", 2) == 0; 5020 && STRNCMP(var_start, "s:", 2) == 0;
4927 int script_var = (script_namespace 5021 int script_var = (script_namespace
4928 ? lookup_script(var_start + 2, varlen - 2, FALSE) 5022 ? script_var_exists(var_start + 2, varlen - 2,
4929 : lookup_script(var_start, varlen, TRUE)) == OK; 5023 FALSE, cctx)
5024 : script_var_exists(var_start, varlen,
5025 TRUE, cctx)) == OK;
4930 imported_T *import = 5026 imported_T *import =
4931 find_imported(var_start, varlen, cctx); 5027 find_imported(var_start, varlen, cctx);
4932 5028
4933 if (script_namespace || script_var || import != NULL) 5029 if (script_namespace || script_var || import != NULL)
4934 { 5030 {
4960 if (import != NULL) 5056 if (import != NULL)
4961 scriptvar_sid = import->imp_sid; 5057 scriptvar_sid = import->imp_sid;
4962 if (SCRIPT_ID_VALID(scriptvar_sid)) 5058 if (SCRIPT_ID_VALID(scriptvar_sid))
4963 { 5059 {
4964 scriptvar_idx = get_script_item_idx(scriptvar_sid, 5060 scriptvar_idx = get_script_item_idx(scriptvar_sid,
4965 rawname, TRUE); 5061 rawname, TRUE, cctx);
4966 if (scriptvar_idx >= 0) 5062 if (scriptvar_idx >= 0)
4967 { 5063 {
4968 scriptitem_T *si = SCRIPT_ITEM(scriptvar_sid); 5064 scriptitem_T *si = SCRIPT_ITEM(scriptvar_sid);
4969 svar_T *sv = 5065 svar_T *sv =
4970 ((svar_T *)si->sn_var_vals.ga_data) 5066 ((svar_T *)si->sn_var_vals.ga_data)
6962 if (*ea.cmd == '&' 7058 if (*ea.cmd == '&'
6963 || *ea.cmd == '$' 7059 || *ea.cmd == '$'
6964 || *ea.cmd == '@' 7060 || *ea.cmd == '@'
6965 || ((len) > 2 && ea.cmd[1] == ':') 7061 || ((len) > 2 && ea.cmd[1] == ':')
6966 || lookup_local(ea.cmd, len, &cctx) != NULL 7062 || lookup_local(ea.cmd, len, &cctx) != NULL
6967 || lookup_arg(ea.cmd, len, NULL, NULL, 7063 || arg_exists(ea.cmd, len, NULL, NULL,
6968 NULL, &cctx) == OK 7064 NULL, &cctx) == OK
6969 || lookup_script(ea.cmd, len, FALSE) == OK 7065 || script_var_exists(ea.cmd, len,
7066 FALSE, &cctx) == OK
6970 || find_imported(ea.cmd, len, &cctx) != NULL) 7067 || find_imported(ea.cmd, len, &cctx) != NULL)
6971 { 7068 {
6972 line = compile_assignment(ea.cmd, &ea, CMD_SIZE, &cctx); 7069 line = compile_assignment(ea.cmd, &ea, CMD_SIZE, &cctx);
6973 if (line == NULL || line == ea.cmd) 7070 if (line == NULL || line == ea.cmd)
6974 goto erret; 7071 goto erret;