1 /* vi:set ts=8 sts=4 sw=4 noet: 2 * 3 * VIM - Vi IMproved by Bram Moolenaar 4 * 5 * Do ":help uganda" in Vim to read copying and usage conditions. 6 * Do ":help credits" in Vim to see a list of people who contributed. 7 * See README.txt for an overview of the Vim source code. 8 */ 9 10 /* 11 * vim9script.c: :vim9script, :import, :export and friends 12 */ 13 14 #include "vim.h" 15 16 #if defined(FEAT_EVAL) 17 # include "vim9.h" 18 #endif 19 20 int 21 in_vim9script(void) 22 { 23 // Do not go up the stack, a ":function" inside vim9script uses legacy 24 // syntax. "sc_version" is also set when compiling a ":def" function in 25 // legacy script. 26 return current_sctx.sc_version == SCRIPT_VERSION_VIM9 27 || (cmdmod.cmod_flags & CMOD_VIM9CMD); 28 } 29 30 /* 31 * ":vim9script". 32 */ 33 void 34 ex_vim9script(exarg_T *eap UNUSED) 35 { 36 #ifdef FEAT_EVAL 37 int sid = current_sctx.sc_sid; 38 scriptitem_T *si; 39 40 if (!getline_equal(eap->getline, eap->cookie, getsourceline)) 41 { 42 emsg(_(e_vim9script_can_only_be_used_in_script)); 43 return; 44 } 45 46 si = SCRIPT_ITEM(sid); 47 if (si->sn_state == SN_STATE_HAD_COMMAND) 48 { 49 emsg(_(e_vim9script_must_be_first_command_in_script)); 50 return; 51 } 52 if (!IS_WHITE_OR_NUL(*eap->arg) && STRCMP(eap->arg, "noclear") != 0) 53 { 54 semsg(_(e_invarg2), eap->arg); 55 return; 56 } 57 if (si->sn_state == SN_STATE_RELOAD && IS_WHITE_OR_NUL(*eap->arg)) 58 { 59 hashtab_T *ht = &SCRIPT_VARS(sid); 60 61 // Reloading a script without the "noclear" argument: clear 62 // script-local variables and functions. 63 hashtab_free_contents(ht); 64 hash_init(ht); 65 delete_script_functions(sid); 66 67 // old imports and script variables are no longer valid 68 free_imports_and_script_vars(sid); 69 } 70 si->sn_state = SN_STATE_HAD_COMMAND; 71 72 current_sctx.sc_version = SCRIPT_VERSION_VIM9; 73 si->sn_version = SCRIPT_VERSION_VIM9; 74 75 if (STRCMP(p_cpo, CPO_VIM) != 0) 76 { 77 si->sn_save_cpo = vim_strsave(p_cpo); 78 set_option_value((char_u *)"cpo", 0L, (char_u *)CPO_VIM, OPT_NO_REDRAW); 79 } 80 #else 81 // No check for this being the first command, it doesn't matter. 82 current_sctx.sc_version = SCRIPT_VERSION_VIM9; 83 #endif 84 } 85 86 /* 87 * When in Vim9 script give an error and return FAIL. 88 */ 89 int 90 not_in_vim9(exarg_T *eap) 91 { 92 if (in_vim9script()) 93 switch (eap->cmdidx) 94 { 95 case CMD_k: 96 if (eap->addr_count > 0) 97 { 98 emsg(_(e_norange)); 99 return FAIL; 100 } 101 // FALLTHROUGH 102 case CMD_append: 103 case CMD_change: 104 case CMD_insert: 105 case CMD_open: 106 case CMD_t: 107 case CMD_xit: 108 semsg(_(e_command_not_supported_in_vim9_script_missing_var_str), eap->cmd); 109 return FAIL; 110 default: break; 111 } 112 return OK; 113 } 114 115 /* 116 * Give an error message if "p" points at "#{" and return TRUE. 117 * This avoids that using a legacy style #{} dictionary leads to difficult to 118 * understand errors. 119 */ 120 int 121 vim9_bad_comment(char_u *p) 122 { 123 if (p[0] == '#' && p[1] == '{' && p[2] != '{') 124 { 125 emsg(_(e_cannot_use_hash_curly_to_start_comment)); 126 return TRUE; 127 } 128 return FALSE; 129 } 130 131 /* 132 * Return TRUE if "p" points at a "#" not followed by one '{'. 133 * Does not check for white space. 134 */ 135 int 136 vim9_comment_start(char_u *p) 137 { 138 return p[0] == '#' && (p[1] != '{' || p[2] == '{'); 139 } 140 141 #if defined(FEAT_EVAL) || defined(PROTO) 142 143 /* 144 * ":export let Name: type" 145 * ":export const Name: type" 146 * ":export def Name(..." 147 * ":export class Name ..." 148 */ 149 void 150 ex_export(exarg_T *eap) 151 { 152 if (!in_vim9script()) 153 { 154 emsg(_(e_export_can_only_be_used_in_vim9script)); 155 return; 156 } 157 158 eap->cmd = eap->arg; 159 (void)find_ex_command(eap, NULL, lookup_scriptitem, NULL); 160 switch (eap->cmdidx) 161 { 162 case CMD_let: 163 case CMD_var: 164 case CMD_final: 165 case CMD_const: 166 case CMD_def: 167 // case CMD_class: 168 is_export = TRUE; 169 do_cmdline(eap->cmd, eap->getline, eap->cookie, 170 DOCMD_VERBOSE + DOCMD_NOWAIT); 171 172 // The command will reset "is_export" when exporting an item. 173 if (is_export) 174 { 175 emsg(_(e_export_with_invalid_argument)); 176 is_export = FALSE; 177 } 178 break; 179 default: 180 emsg(_(e_invalid_command_after_export)); 181 break; 182 } 183 } 184 185 /* 186 * Add a new imported item entry to the current script. 187 */ 188 static imported_T * 189 new_imported(garray_T *gap) 190 { 191 if (ga_grow(gap, 1) == OK) 192 return ((imported_T *)gap->ga_data + gap->ga_len++); 193 return NULL; 194 } 195 196 /* 197 * Free all imported items in script "sid". 198 */ 199 void 200 free_imports_and_script_vars(int sid) 201 { 202 scriptitem_T *si = SCRIPT_ITEM(sid); 203 int idx; 204 205 for (idx = 0; idx < si->sn_imports.ga_len; ++idx) 206 { 207 imported_T *imp = ((imported_T *)si->sn_imports.ga_data) + idx; 208 209 vim_free(imp->imp_name); 210 } 211 ga_clear(&si->sn_imports); 212 213 free_all_script_vars(si); 214 215 clear_type_list(&si->sn_type_list); 216 } 217 218 /* 219 * Mark all imports as possible to redefine. Used when a script is loaded 220 * again but not cleared. 221 */ 222 void 223 mark_imports_for_reload(int sid) 224 { 225 scriptitem_T *si = SCRIPT_ITEM(sid); 226 int idx; 227 228 for (idx = 0; idx < si->sn_imports.ga_len; ++idx) 229 { 230 imported_T *imp = ((imported_T *)si->sn_imports.ga_data) + idx; 231 232 imp->imp_flags |= IMP_FLAGS_RELOAD; 233 } 234 } 235 236 /* 237 * ":import Item from 'filename'" 238 * ":import Item as Alias from 'filename'" 239 * ":import {Item} from 'filename'". 240 * ":import {Item as Alias} from 'filename'" 241 * ":import {Item, Item} from 'filename'" 242 * ":import {Item, Item as Alias} from 'filename'" 243 * 244 * ":import * as Name from 'filename'" 245 */ 246 void 247 ex_import(exarg_T *eap) 248 { 249 char_u *cmd_end; 250 evalarg_T evalarg; 251 252 if (!getline_equal(eap->getline, eap->cookie, getsourceline)) 253 { 254 emsg(_(e_import_can_only_be_used_in_script)); 255 return; 256 } 257 fill_evalarg_from_eap(&evalarg, eap, eap->skip); 258 259 cmd_end = handle_import(eap->arg, NULL, current_sctx.sc_sid, 260 &evalarg, NULL); 261 if (cmd_end != NULL) 262 eap->nextcmd = check_nextcmd(cmd_end); 263 clear_evalarg(&evalarg, eap); 264 } 265 266 /* 267 * Find an exported item in "sid" matching the name at "*argp". 268 * When it is a variable return the index. 269 * When it is a user function return "*ufunc". 270 * When not found returns -1 and "*ufunc" is NULL. 271 */ 272 int 273 find_exported( 274 int sid, 275 char_u *name, 276 ufunc_T **ufunc, 277 type_T **type, 278 cctx_T *cctx, 279 int verbose) 280 { 281 int idx = -1; 282 svar_T *sv; 283 scriptitem_T *script = SCRIPT_ITEM(sid); 284 285 // find name in "script" 286 // TODO: also find script-local user function 287 idx = get_script_item_idx(sid, name, 0, cctx); 288 if (idx >= 0) 289 { 290 sv = ((svar_T *)script->sn_var_vals.ga_data) + idx; 291 if (!sv->sv_export) 292 { 293 if (verbose) 294 semsg(_(e_item_not_exported_in_script_str), name); 295 return -1; 296 } 297 *type = sv->sv_type; 298 *ufunc = NULL; 299 } 300 else 301 { 302 char_u buffer[200]; 303 char_u *funcname; 304 305 // it could be a user function. 306 if (STRLEN(name) < sizeof(buffer) - 15) 307 funcname = buffer; 308 else 309 { 310 funcname = alloc(STRLEN(name) + 15); 311 if (funcname == NULL) 312 return -1; 313 } 314 funcname[0] = K_SPECIAL; 315 funcname[1] = KS_EXTRA; 316 funcname[2] = (int)KE_SNR; 317 sprintf((char *)funcname + 3, "%ld_%s", (long)sid, name); 318 *ufunc = find_func(funcname, FALSE, NULL); 319 if (funcname != buffer) 320 vim_free(funcname); 321 322 if (*ufunc == NULL) 323 { 324 if (verbose) 325 semsg(_(e_item_not_found_in_script_str), name); 326 return -1; 327 } 328 } 329 330 return idx; 331 } 332 333 /* 334 * Handle an ":import" command and add the resulting imported_T to "gap", when 335 * not NULL, or script "import_sid" sn_imports. 336 * "cctx" is NULL at the script level. 337 * Returns a pointer to after the command or NULL in case of failure 338 */ 339 char_u * 340 handle_import( 341 char_u *arg_start, 342 garray_T *gap, 343 int import_sid, 344 evalarg_T *evalarg, 345 void *cctx) 346 { 347 char_u *arg = arg_start; 348 char_u *cmd_end = NULL; 349 int ret = FAIL; 350 typval_T tv; 351 int sid = -1; 352 int res; 353 int mult = FALSE; 354 garray_T names; 355 garray_T as_names; 356 357 ga_init2(&names, sizeof(char_u *), 10); 358 ga_init2(&as_names, sizeof(char_u *), 10); 359 if (*arg == '{') 360 { 361 // "import {item, item} from ..." 362 mult = TRUE; 363 arg = skipwhite_and_linebreak(arg + 1, evalarg); 364 } 365 366 for (;;) 367 { 368 char_u *p = arg; 369 int had_comma = FALSE; 370 char_u *as_name = NULL; 371 372 // accept "*" or "Name" 373 if (!mult && arg[0] == '*' && IS_WHITE_OR_NUL(arg[1])) 374 ++arg; 375 else 376 while (eval_isnamec(*arg)) 377 ++arg; 378 if (p == arg) 379 break; 380 if (ga_grow(&names, 1) == FAIL || ga_grow(&as_names, 1) == FAIL) 381 goto erret; 382 ((char_u **)names.ga_data)[names.ga_len] = vim_strnsave(p, arg - p); 383 ++names.ga_len; 384 385 arg = skipwhite_and_linebreak(arg, evalarg); 386 if (STRNCMP("as", arg, 2) == 0 && IS_WHITE_OR_NUL(arg[2])) 387 { 388 // skip over "as Name "; no line break allowed after "as" 389 arg = skipwhite(arg + 2); 390 p = arg; 391 if (eval_isnamec1(*arg)) 392 while (eval_isnamec(*arg)) 393 ++arg; 394 if (check_defined(p, arg - p, cctx, FALSE) == FAIL) 395 goto erret; 396 as_name = vim_strnsave(p, arg - p); 397 arg = skipwhite_and_linebreak(arg, evalarg); 398 } 399 else if (*arg_start == '*') 400 { 401 emsg(_(e_missing_as_after_star)); 402 goto erret; 403 } 404 // without "as Name" the as_names entry is NULL 405 ((char_u **)as_names.ga_data)[as_names.ga_len] = as_name; 406 ++as_names.ga_len; 407 408 if (!mult) 409 break; 410 if (*arg == ',') 411 { 412 had_comma = TRUE; 413 ++arg; 414 } 415 arg = skipwhite_and_linebreak(arg, evalarg); 416 if (*arg == '}') 417 { 418 ++arg; 419 break; 420 } 421 if (!had_comma) 422 { 423 emsg(_(e_missing_comma_in_import)); 424 goto erret; 425 } 426 } 427 arg = skipwhite_and_linebreak(arg, evalarg); 428 429 if (names.ga_len == 0) 430 { 431 emsg(_(e_syntax_error_in_import)); 432 goto erret; 433 } 434 435 if (STRNCMP("from", arg, 4) != 0 || !IS_WHITE_OR_NUL(arg[4])) 436 { 437 emsg(_(e_missing_from)); 438 goto erret; 439 } 440 441 arg = skipwhite_and_linebreak(arg + 4, evalarg); 442 tv.v_type = VAR_UNKNOWN; 443 // TODO: should we accept any expression? 444 if (*arg == '\'') 445 ret = eval_lit_string(&arg, &tv, TRUE); 446 else if (*arg == '"') 447 ret = eval_string(&arg, &tv, TRUE); 448 if (ret == FAIL || tv.vval.v_string == NULL || *tv.vval.v_string == NUL) 449 { 450 emsg(_(e_invalid_string_after_from)); 451 goto erret; 452 } 453 cmd_end = arg; 454 455 /* 456 * find script file 457 */ 458 if (*tv.vval.v_string == '.') 459 { 460 size_t len; 461 scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid); 462 char_u *tail = gettail(si->sn_name); 463 char_u *from_name; 464 465 // Relative to current script: "./name.vim", "../../name.vim". 466 len = STRLEN(si->sn_name) - STRLEN(tail) + STRLEN(tv.vval.v_string) + 2; 467 from_name = alloc((int)len); 468 if (from_name == NULL) 469 { 470 clear_tv(&tv); 471 goto erret; 472 } 473 vim_strncpy(from_name, si->sn_name, tail - si->sn_name); 474 add_pathsep(from_name); 475 STRCAT(from_name, tv.vval.v_string); 476 simplify_filename(from_name); 477 478 res = do_source(from_name, FALSE, DOSO_NONE, &sid); 479 vim_free(from_name); 480 } 481 else if (mch_isFullName(tv.vval.v_string)) 482 { 483 // Absolute path: "/tmp/name.vim" 484 res = do_source(tv.vval.v_string, FALSE, DOSO_NONE, &sid); 485 } 486 else 487 { 488 size_t len = 7 + STRLEN(tv.vval.v_string) + 1; 489 char_u *from_name; 490 491 // Find file in "import" subdirs in 'runtimepath'. 492 from_name = alloc((int)len); 493 if (from_name == NULL) 494 { 495 clear_tv(&tv); 496 goto erret; 497 } 498 vim_snprintf((char *)from_name, len, "import/%s", tv.vval.v_string); 499 res = source_in_path(p_rtp, from_name, DIP_NOAFTER, &sid); 500 vim_free(from_name); 501 } 502 503 if (res == FAIL || sid <= 0) 504 { 505 semsg(_(e_could_not_import_str), tv.vval.v_string); 506 clear_tv(&tv); 507 goto erret; 508 } 509 clear_tv(&tv); 510 511 if (*arg_start == '*') 512 { 513 imported_T *imported; 514 char_u *as_name = ((char_u **)as_names.ga_data)[0]; 515 516 // "import * as That" 517 imported = find_imported(as_name, STRLEN(as_name), cctx); 518 if (imported != NULL && imported->imp_sid == sid) 519 { 520 if (imported->imp_flags & IMP_FLAGS_RELOAD) 521 // import already defined on a previous script load 522 imported->imp_flags &= ~IMP_FLAGS_RELOAD; 523 else 524 { 525 semsg(_(e_name_already_defined_str), as_name); 526 goto erret; 527 } 528 } 529 530 imported = new_imported(gap != NULL ? gap 531 : &SCRIPT_ITEM(import_sid)->sn_imports); 532 if (imported == NULL) 533 goto erret; 534 imported->imp_name = as_name; 535 ((char_u **)as_names.ga_data)[0] = NULL; 536 imported->imp_sid = sid; 537 imported->imp_flags = IMP_FLAGS_STAR; 538 } 539 else 540 { 541 int i; 542 543 arg = arg_start; 544 if (*arg == '{') 545 arg = skipwhite(arg + 1); 546 for (i = 0; i < names.ga_len; ++i) 547 { 548 char_u *name = ((char_u **)names.ga_data)[i]; 549 char_u *as_name = ((char_u **)as_names.ga_data)[i]; 550 size_t len = STRLEN(name); 551 int idx; 552 imported_T *imported; 553 ufunc_T *ufunc = NULL; 554 type_T *type; 555 556 idx = find_exported(sid, name, &ufunc, &type, cctx, TRUE); 557 558 if (idx < 0 && ufunc == NULL) 559 goto erret; 560 561 // If already imported with the same propertis and the 562 // IMP_FLAGS_RELOAD set then we keep that entry. Otherwise create 563 // a new one (and give an error for an existing import). 564 imported = find_imported(name, len, cctx); 565 if (imported != NULL 566 && (imported->imp_flags & IMP_FLAGS_RELOAD) 567 && imported->imp_sid == sid 568 && (idx >= 0 569 ? (equal_type(imported->imp_type, type) 570 && imported->imp_var_vals_idx == idx) 571 : (equal_type(imported->imp_type, ufunc->uf_func_type) 572 && STRCMP(imported->imp_funcname, 573 ufunc->uf_name) == 0))) 574 { 575 imported->imp_flags &= ~IMP_FLAGS_RELOAD; 576 } 577 else 578 { 579 if (check_defined(name, len, cctx, FALSE) == FAIL) 580 goto erret; 581 582 imported = new_imported(gap != NULL ? gap 583 : &SCRIPT_ITEM(import_sid)->sn_imports); 584 if (imported == NULL) 585 goto erret; 586 587 if (as_name == NULL) 588 { 589 imported->imp_name = name; 590 ((char_u **)names.ga_data)[i] = NULL; 591 } 592 else 593 { 594 // "import This as That ..." 595 imported->imp_name = as_name; 596 ((char_u **)as_names.ga_data)[i] = NULL; 597 } 598 imported->imp_sid = sid; 599 if (idx >= 0) 600 { 601 imported->imp_type = type; 602 imported->imp_var_vals_idx = idx; 603 } 604 else 605 { 606 imported->imp_type = ufunc->uf_func_type; 607 imported->imp_funcname = ufunc->uf_name; 608 } 609 } 610 } 611 } 612 erret: 613 ga_clear_strings(&names); 614 ga_clear_strings(&as_names); 615 return cmd_end; 616 } 617 618 /* 619 * Declare a script-local variable without init: "let var: type". 620 * "const" is an error since the value is missing. 621 * Returns a pointer to after the type. 622 */ 623 char_u * 624 vim9_declare_scriptvar(exarg_T *eap, char_u *arg) 625 { 626 char_u *p; 627 char_u *name; 628 scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid); 629 type_T *type; 630 typval_T init_tv; 631 632 if (eap->cmdidx == CMD_final || eap->cmdidx == CMD_const) 633 { 634 if (eap->cmdidx == CMD_final) 635 emsg(_(e_final_requires_a_value)); 636 else 637 emsg(_(e_const_requires_a_value)); 638 return arg + STRLEN(arg); 639 } 640 641 // Check for valid starting character. 642 if (!eval_isnamec1(*arg)) 643 { 644 semsg(_(e_invarg2), arg); 645 return arg + STRLEN(arg); 646 } 647 648 for (p = arg + 1; *p != NUL && eval_isnamec(*p); MB_PTR_ADV(p)) 649 if (*p == ':' && (VIM_ISWHITE(p[1]) || p != arg + 1)) 650 break; 651 652 if (*p != ':') 653 { 654 emsg(_(e_type_or_initialization_required)); 655 return arg + STRLEN(arg); 656 } 657 if (!VIM_ISWHITE(p[1])) 658 { 659 semsg(_(e_white_space_required_after_str_str), ":", p); 660 return arg + STRLEN(arg); 661 } 662 name = vim_strnsave(arg, p - arg); 663 664 // parse type 665 p = skipwhite(p + 1); 666 type = parse_type(&p, &si->sn_type_list, TRUE); 667 if (type == NULL) 668 { 669 vim_free(name); 670 return p; 671 } 672 673 // Create the variable with 0/NULL value. 674 CLEAR_FIELD(init_tv); 675 if (type->tt_type == VAR_ANY) 676 // A variable of type "any" is not possible, just use zero instead 677 init_tv.v_type = VAR_NUMBER; 678 else 679 init_tv.v_type = type->tt_type; 680 set_var_const(name, type, &init_tv, FALSE, 0, 0); 681 682 vim_free(name); 683 return p; 684 } 685 686 /* 687 * Vim9 part of adding a script variable: add it to sn_all_vars (lookup by name 688 * with a hashtable) and sn_var_vals (lookup by index). 689 * When "create" is TRUE this is a new variable, otherwise find and update an 690 * existing variable. 691 * "flags" can have ASSIGN_FINAL or ASSIGN_CONST. 692 * When "*type" is NULL use "tv" for the type and update "*type". 693 */ 694 void 695 update_vim9_script_var( 696 int create, 697 dictitem_T *di, 698 int flags, 699 typval_T *tv, 700 type_T **type) 701 { 702 scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid); 703 hashitem_T *hi; 704 svar_T *sv; 705 706 if (create) 707 { 708 sallvar_T *newsav; 709 710 // Store a pointer to the typval_T, so that it can be found by index 711 // instead of using a hastab lookup. 712 if (ga_grow(&si->sn_var_vals, 1) == FAIL) 713 return; 714 715 sv = ((svar_T *)si->sn_var_vals.ga_data) + si->sn_var_vals.ga_len; 716 newsav = (sallvar_T *)alloc_clear( 717 sizeof(sallvar_T) + STRLEN(di->di_key)); 718 if (newsav == NULL) 719 return; 720 721 sv->sv_tv = &di->di_tv; 722 sv->sv_const = (flags & ASSIGN_FINAL) ? ASSIGN_FINAL 723 : (flags & ASSIGN_CONST) ? ASSIGN_CONST : 0; 724 sv->sv_export = is_export; 725 newsav->sav_var_vals_idx = si->sn_var_vals.ga_len; 726 ++si->sn_var_vals.ga_len; 727 STRCPY(&newsav->sav_key, di->di_key); 728 sv->sv_name = newsav->sav_key; 729 newsav->sav_di = di; 730 newsav->sav_block_id = si->sn_current_block_id; 731 732 hi = hash_find(&si->sn_all_vars.dv_hashtab, newsav->sav_key); 733 if (!HASHITEM_EMPTY(hi)) 734 { 735 sallvar_T *sav = HI2SAV(hi); 736 737 // variable with this name exists in another block 738 while (sav->sav_next != NULL) 739 sav = sav->sav_next; 740 sav->sav_next = newsav; 741 } 742 else 743 // new variable name 744 hash_add(&si->sn_all_vars.dv_hashtab, newsav->sav_key); 745 } 746 else 747 { 748 sv = find_typval_in_script(&di->di_tv); 749 } 750 if (sv != NULL) 751 { 752 if (*type == NULL) 753 *type = typval2type(tv, get_copyID(), &si->sn_type_list); 754 sv->sv_type = *type; 755 } 756 757 // let ex_export() know the export worked. 758 is_export = FALSE; 759 } 760 761 /* 762 * Hide a script variable when leaving a block. 763 * "idx" is de index in sn_var_vals. 764 * When "func_defined" is non-zero then a function was defined in this block, 765 * the variable may be accessed by it. Otherwise the variable can be cleared. 766 */ 767 void 768 hide_script_var(scriptitem_T *si, int idx, int func_defined) 769 { 770 svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data) + idx; 771 hashtab_T *script_ht = get_script_local_ht(); 772 hashtab_T *all_ht = &si->sn_all_vars.dv_hashtab; 773 hashitem_T *script_hi; 774 hashitem_T *all_hi; 775 776 // Remove a variable declared inside the block, if it still exists. 777 // If it was added in a nested block it will already have been removed. 778 // The typval is moved into the sallvar_T. 779 script_hi = hash_find(script_ht, sv->sv_name); 780 all_hi = hash_find(all_ht, sv->sv_name); 781 if (!HASHITEM_EMPTY(script_hi) && !HASHITEM_EMPTY(all_hi)) 782 { 783 dictitem_T *di = HI2DI(script_hi); 784 sallvar_T *sav = HI2SAV(all_hi); 785 sallvar_T *sav_prev = NULL; 786 787 // There can be multiple entries with the same name in different 788 // blocks, find the right one. 789 while (sav != NULL && sav->sav_var_vals_idx != idx) 790 { 791 sav_prev = sav; 792 sav = sav->sav_next; 793 } 794 if (sav != NULL) 795 { 796 if (func_defined) 797 { 798 // move the typval from the dictitem to the sallvar 799 sav->sav_tv = di->di_tv; 800 di->di_tv.v_type = VAR_UNKNOWN; 801 sav->sav_flags = di->di_flags; 802 sav->sav_di = NULL; 803 sv->sv_tv = &sav->sav_tv; 804 } 805 else 806 { 807 if (sav_prev == NULL) 808 hash_remove(all_ht, all_hi); 809 else 810 sav_prev->sav_next = sav->sav_next; 811 sv->sv_name = NULL; 812 vim_free(sav); 813 } 814 delete_var(script_ht, script_hi); 815 } 816 } 817 } 818 819 /* 820 * Free the script variables from "sn_all_vars". 821 */ 822 void 823 free_all_script_vars(scriptitem_T *si) 824 { 825 int todo; 826 hashtab_T *ht = &si->sn_all_vars.dv_hashtab; 827 hashitem_T *hi; 828 sallvar_T *sav; 829 sallvar_T *sav_next; 830 831 hash_lock(ht); 832 todo = (int)ht->ht_used; 833 for (hi = ht->ht_array; todo > 0; ++hi) 834 { 835 if (!HASHITEM_EMPTY(hi)) 836 { 837 --todo; 838 839 // Free the variable. Don't remove it from the hashtab, ht_array 840 // might change then. hash_clear() takes care of it later. 841 sav = HI2SAV(hi); 842 while (sav != NULL) 843 { 844 sav_next = sav->sav_next; 845 if (sav->sav_di == NULL) 846 clear_tv(&sav->sav_tv); 847 vim_free(sav); 848 sav = sav_next; 849 } 850 } 851 } 852 hash_clear(ht); 853 hash_init(ht); 854 855 ga_clear(&si->sn_var_vals); 856 857 // existing commands using script variable indexes are no longer valid 858 si->sn_script_seq = current_sctx.sc_seq; 859 } 860 861 /* 862 * Find the script-local variable that links to "dest". 863 * Returns NULL if not found. 864 */ 865 svar_T * 866 find_typval_in_script(typval_T *dest) 867 { 868 scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid); 869 int idx; 870 871 if (si->sn_version != SCRIPT_VERSION_VIM9) 872 // legacy script doesn't store variable types 873 return NULL; 874 875 // Find the svar_T in sn_var_vals. 876 for (idx = 0; idx < si->sn_var_vals.ga_len; ++idx) 877 { 878 svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data) + idx; 879 880 // If "sv_name" is NULL the variable was hidden when leaving a block, 881 // don't check "sv_tv" then, it might be used for another variable now. 882 if (sv->sv_name != NULL && sv->sv_tv == dest) 883 return sv; 884 } 885 iemsg("find_typval_in_script(): not found"); 886 return NULL; 887 } 888 889 /* 890 * Check if the type of script variable "dest" allows assigning "value". 891 * If needed convert "value" to a bool. 892 */ 893 int 894 check_script_var_type( 895 typval_T *dest, 896 typval_T *value, 897 char_u *name, 898 where_T where) 899 { 900 svar_T *sv = find_typval_in_script(dest); 901 int ret; 902 903 if (sv != NULL) 904 { 905 if (sv->sv_const != 0) 906 { 907 semsg(_(e_readonlyvar), name); 908 return FAIL; 909 } 910 ret = check_typval_type(sv->sv_type, value, where); 911 if (ret == OK && need_convert_to_bool(sv->sv_type, value)) 912 { 913 int val = tv2bool(value); 914 915 clear_tv(value); 916 value->v_type = VAR_BOOL; 917 value->v_lock = 0; 918 value->vval.v_number = val ? VVAL_TRUE : VVAL_FALSE; 919 } 920 return ret; 921 } 922 923 return OK; // not really 924 } 925 926 #endif // FEAT_EVAL 927