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