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 (as_name == NULL 604 && check_defined(name, len, cctx, FALSE) == FAIL) 605 goto erret; 606 607 imported = new_imported(gap != NULL ? gap 608 : &SCRIPT_ITEM(import_sid)->sn_imports); 609 if (imported == NULL) 610 goto erret; 611 612 if (as_name == NULL) 613 { 614 imported->imp_name = name; 615 ((char_u **)names.ga_data)[i] = NULL; 616 } 617 else 618 { 619 // "import This as That ..." 620 imported->imp_name = as_name; 621 ((char_u **)as_names.ga_data)[i] = NULL; 622 } 623 imported->imp_sid = sid; 624 if (idx >= 0) 625 { 626 imported->imp_type = type; 627 imported->imp_var_vals_idx = idx; 628 } 629 else 630 { 631 imported->imp_type = ufunc->uf_func_type; 632 imported->imp_funcname = ufunc->uf_name; 633 } 634 } 635 } 636 } 637 erret: 638 ga_clear_strings(&names); 639 ga_clear_strings(&as_names); 640 return cmd_end; 641 } 642 643 /* 644 * Declare a script-local variable without init: "let var: type". 645 * "const" is an error since the value is missing. 646 * Returns a pointer to after the type. 647 */ 648 char_u * 649 vim9_declare_scriptvar(exarg_T *eap, char_u *arg) 650 { 651 char_u *p; 652 char_u *name; 653 scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid); 654 type_T *type; 655 typval_T init_tv; 656 657 if (eap->cmdidx == CMD_final || eap->cmdidx == CMD_const) 658 { 659 if (eap->cmdidx == CMD_final) 660 emsg(_(e_final_requires_a_value)); 661 else 662 emsg(_(e_const_requires_a_value)); 663 return arg + STRLEN(arg); 664 } 665 666 // Check for valid starting character. 667 if (!eval_isnamec1(*arg)) 668 { 669 semsg(_(e_invarg2), arg); 670 return arg + STRLEN(arg); 671 } 672 673 for (p = arg + 1; *p != NUL && eval_isnamec(*p); MB_PTR_ADV(p)) 674 if (*p == ':' && (VIM_ISWHITE(p[1]) || p != arg + 1)) 675 break; 676 677 if (*p != ':') 678 { 679 emsg(_(e_type_or_initialization_required)); 680 return arg + STRLEN(arg); 681 } 682 if (!VIM_ISWHITE(p[1])) 683 { 684 semsg(_(e_white_space_required_after_str_str), ":", p); 685 return arg + STRLEN(arg); 686 } 687 name = vim_strnsave(arg, p - arg); 688 689 // parse type 690 p = skipwhite(p + 1); 691 type = parse_type(&p, &si->sn_type_list, TRUE); 692 if (type == NULL) 693 { 694 vim_free(name); 695 return p; 696 } 697 698 // Create the variable with 0/NULL value. 699 CLEAR_FIELD(init_tv); 700 if (type->tt_type == VAR_ANY) 701 // A variable of type "any" is not possible, just use zero instead 702 init_tv.v_type = VAR_NUMBER; 703 else 704 init_tv.v_type = type->tt_type; 705 set_var_const(name, type, &init_tv, FALSE, 0, 0); 706 707 vim_free(name); 708 return p; 709 } 710 711 /* 712 * Vim9 part of adding a script variable: add it to sn_all_vars (lookup by name 713 * with a hashtable) and sn_var_vals (lookup by index). 714 * When "create" is TRUE this is a new variable, otherwise find and update an 715 * existing variable. 716 * "flags" can have ASSIGN_FINAL or ASSIGN_CONST. 717 * When "*type" is NULL use "tv" for the type and update "*type". If 718 * "do_member" is TRUE also use the member type, otherwise use "any". 719 */ 720 void 721 update_vim9_script_var( 722 int create, 723 dictitem_T *di, 724 int flags, 725 typval_T *tv, 726 type_T **type, 727 int do_member) 728 { 729 scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid); 730 hashitem_T *hi; 731 svar_T *sv; 732 733 if (create) 734 { 735 sallvar_T *newsav; 736 737 // Store a pointer to the typval_T, so that it can be found by index 738 // instead of using a hastab lookup. 739 if (ga_grow(&si->sn_var_vals, 1) == FAIL) 740 return; 741 742 sv = ((svar_T *)si->sn_var_vals.ga_data) + si->sn_var_vals.ga_len; 743 newsav = (sallvar_T *)alloc_clear( 744 sizeof(sallvar_T) + STRLEN(di->di_key)); 745 if (newsav == NULL) 746 return; 747 748 sv->sv_tv = &di->di_tv; 749 sv->sv_const = (flags & ASSIGN_FINAL) ? ASSIGN_FINAL 750 : (flags & ASSIGN_CONST) ? ASSIGN_CONST : 0; 751 sv->sv_export = is_export; 752 newsav->sav_var_vals_idx = si->sn_var_vals.ga_len; 753 ++si->sn_var_vals.ga_len; 754 STRCPY(&newsav->sav_key, di->di_key); 755 sv->sv_name = newsav->sav_key; 756 newsav->sav_di = di; 757 newsav->sav_block_id = si->sn_current_block_id; 758 759 hi = hash_find(&si->sn_all_vars.dv_hashtab, newsav->sav_key); 760 if (!HASHITEM_EMPTY(hi)) 761 { 762 sallvar_T *sav = HI2SAV(hi); 763 764 // variable with this name exists in another block 765 while (sav->sav_next != NULL) 766 sav = sav->sav_next; 767 sav->sav_next = newsav; 768 } 769 else 770 // new variable name 771 hash_add(&si->sn_all_vars.dv_hashtab, newsav->sav_key); 772 } 773 else 774 { 775 sv = find_typval_in_script(&di->di_tv); 776 } 777 if (sv != NULL) 778 { 779 if (*type == NULL) 780 *type = typval2type(tv, get_copyID(), &si->sn_type_list, 781 do_member); 782 sv->sv_type = *type; 783 } 784 785 // let ex_export() know the export worked. 786 is_export = FALSE; 787 } 788 789 /* 790 * Hide a script variable when leaving a block. 791 * "idx" is de index in sn_var_vals. 792 * When "func_defined" is non-zero then a function was defined in this block, 793 * the variable may be accessed by it. Otherwise the variable can be cleared. 794 */ 795 void 796 hide_script_var(scriptitem_T *si, int idx, int func_defined) 797 { 798 svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data) + idx; 799 hashtab_T *script_ht = get_script_local_ht(); 800 hashtab_T *all_ht = &si->sn_all_vars.dv_hashtab; 801 hashitem_T *script_hi; 802 hashitem_T *all_hi; 803 804 // Remove a variable declared inside the block, if it still exists. 805 // If it was added in a nested block it will already have been removed. 806 // The typval is moved into the sallvar_T. 807 script_hi = hash_find(script_ht, sv->sv_name); 808 all_hi = hash_find(all_ht, sv->sv_name); 809 if (!HASHITEM_EMPTY(script_hi) && !HASHITEM_EMPTY(all_hi)) 810 { 811 dictitem_T *di = HI2DI(script_hi); 812 sallvar_T *sav = HI2SAV(all_hi); 813 sallvar_T *sav_prev = NULL; 814 815 // There can be multiple entries with the same name in different 816 // blocks, find the right one. 817 while (sav != NULL && sav->sav_var_vals_idx != idx) 818 { 819 sav_prev = sav; 820 sav = sav->sav_next; 821 } 822 if (sav != NULL) 823 { 824 if (func_defined) 825 { 826 // move the typval from the dictitem to the sallvar 827 sav->sav_tv = di->di_tv; 828 di->di_tv.v_type = VAR_UNKNOWN; 829 sav->sav_flags = di->di_flags; 830 sav->sav_di = NULL; 831 sv->sv_tv = &sav->sav_tv; 832 } 833 else 834 { 835 if (sav_prev == NULL) 836 hash_remove(all_ht, all_hi); 837 else 838 sav_prev->sav_next = sav->sav_next; 839 sv->sv_name = NULL; 840 vim_free(sav); 841 } 842 delete_var(script_ht, script_hi); 843 } 844 } 845 } 846 847 /* 848 * Free the script variables from "sn_all_vars". 849 */ 850 void 851 free_all_script_vars(scriptitem_T *si) 852 { 853 int todo; 854 hashtab_T *ht = &si->sn_all_vars.dv_hashtab; 855 hashitem_T *hi; 856 sallvar_T *sav; 857 sallvar_T *sav_next; 858 859 hash_lock(ht); 860 todo = (int)ht->ht_used; 861 for (hi = ht->ht_array; todo > 0; ++hi) 862 { 863 if (!HASHITEM_EMPTY(hi)) 864 { 865 --todo; 866 867 // Free the variable. Don't remove it from the hashtab, ht_array 868 // might change then. hash_clear() takes care of it later. 869 sav = HI2SAV(hi); 870 while (sav != NULL) 871 { 872 sav_next = sav->sav_next; 873 if (sav->sav_di == NULL) 874 clear_tv(&sav->sav_tv); 875 vim_free(sav); 876 sav = sav_next; 877 } 878 } 879 } 880 hash_clear(ht); 881 hash_init(ht); 882 883 ga_clear(&si->sn_var_vals); 884 885 // existing commands using script variable indexes are no longer valid 886 si->sn_script_seq = current_sctx.sc_seq; 887 } 888 889 /* 890 * Find the script-local variable that links to "dest". 891 * Returns NULL if not found. 892 */ 893 svar_T * 894 find_typval_in_script(typval_T *dest) 895 { 896 scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid); 897 int idx; 898 899 if (si->sn_version != SCRIPT_VERSION_VIM9) 900 // legacy script doesn't store variable types 901 return NULL; 902 903 // Find the svar_T in sn_var_vals. 904 for (idx = 0; idx < si->sn_var_vals.ga_len; ++idx) 905 { 906 svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data) + idx; 907 908 // If "sv_name" is NULL the variable was hidden when leaving a block, 909 // don't check "sv_tv" then, it might be used for another variable now. 910 if (sv->sv_name != NULL && sv->sv_tv == dest) 911 return sv; 912 } 913 iemsg("find_typval_in_script(): not found"); 914 return NULL; 915 } 916 917 /* 918 * Check if the type of script variable "dest" allows assigning "value". 919 * If needed convert "value" to a bool. 920 */ 921 int 922 check_script_var_type( 923 typval_T *dest, 924 typval_T *value, 925 char_u *name, 926 where_T where) 927 { 928 svar_T *sv = find_typval_in_script(dest); 929 int ret; 930 931 if (sv != NULL) 932 { 933 if (sv->sv_const != 0) 934 { 935 semsg(_(e_readonlyvar), name); 936 return FAIL; 937 } 938 ret = check_typval_type(sv->sv_type, value, where); 939 if (ret == OK && need_convert_to_bool(sv->sv_type, value)) 940 { 941 int val = tv2bool(value); 942 943 clear_tv(value); 944 value->v_type = VAR_BOOL; 945 value->v_lock = 0; 946 value->vval.v_number = val ? VVAL_TRUE : VVAL_FALSE; 947 } 948 return ret; 949 } 950 951 return OK; // not really 952 } 953 954 #endif // FEAT_EVAL 955