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