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