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