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