Mercurial > vim
comparison src/vim9script.c @ 22594:209c7aa56325 v8.2.1845
patch 8.2.1845: Vim9: function defined in a block can't use block variables
Commit: https://github.com/vim/vim/commit/8d739de43b84ef7817b3b5b826d1cbfe7572a62a
Author: Bram Moolenaar <Bram@vim.org>
Date: Wed Oct 14 19:39:19 2020 +0200
patch 8.2.1845: Vim9: function defined in a block can't use block variables
Problem: Vim9: function defined in a block can't use variables defined in
that block.
Solution: First step: Make a second hashtab that holds all script variables,
also block-local ones, with more information.
author | Bram Moolenaar <Bram@vim.org> |
---|---|
date | Wed, 14 Oct 2020 19:45:04 +0200 |
parents | 35ef9b0a81a3 |
children | 107eae953b87 |
comparison
equal
deleted
inserted
replaced
22593:a6030e19b08f | 22594:209c7aa56325 |
---|---|
132 | 132 |
133 /* | 133 /* |
134 * Free all imported items in script "sid". | 134 * Free all imported items in script "sid". |
135 */ | 135 */ |
136 void | 136 void |
137 free_imports(int sid) | 137 free_imports_and_script_vars(int sid) |
138 { | 138 { |
139 scriptitem_T *si = SCRIPT_ITEM(sid); | 139 scriptitem_T *si = SCRIPT_ITEM(sid); |
140 int idx; | 140 int idx; |
141 | 141 |
142 for (idx = 0; idx < si->sn_imports.ga_len; ++idx) | 142 for (idx = 0; idx < si->sn_imports.ga_len; ++idx) |
144 imported_T *imp = ((imported_T *)si->sn_imports.ga_data) + idx; | 144 imported_T *imp = ((imported_T *)si->sn_imports.ga_data) + idx; |
145 | 145 |
146 vim_free(imp->imp_name); | 146 vim_free(imp->imp_name); |
147 } | 147 } |
148 ga_clear(&si->sn_imports); | 148 ga_clear(&si->sn_imports); |
149 ga_clear(&si->sn_var_vals); | 149 |
150 free_all_script_vars(si); | |
151 | |
150 clear_type_list(&si->sn_type_list); | 152 clear_type_list(&si->sn_type_list); |
151 } | 153 } |
152 | 154 |
153 /* | 155 /* |
154 * ":import Item from 'filename'" | 156 * ":import Item from 'filename'" |
563 vim_free(name); | 565 vim_free(name); |
564 return p; | 566 return p; |
565 } | 567 } |
566 | 568 |
567 /* | 569 /* |
570 * Vim9 part of adding a script variable: add it to sn_all_vars and | |
571 * sn_var_vals. | |
572 * When "type" is NULL use "tv" for the type. | |
573 */ | |
574 void | |
575 add_vim9_script_var(dictitem_T *di, typval_T *tv, type_T *type) | |
576 { | |
577 scriptitem_T *si = SCRIPT_ITEM(current_sctx.sc_sid); | |
578 | |
579 // Store a pointer to the typval_T, so that it can be found by | |
580 // index instead of using a hastab lookup. | |
581 if (ga_grow(&si->sn_var_vals, 1) == OK) | |
582 { | |
583 svar_T *sv = ((svar_T *)si->sn_var_vals.ga_data) | |
584 + si->sn_var_vals.ga_len; | |
585 hashitem_T *hi; | |
586 sallvar_T *newsav = (sallvar_T *)alloc_clear( | |
587 sizeof(sallvar_T) + STRLEN(di->di_key)); | |
588 | |
589 if (newsav == NULL) | |
590 return; | |
591 | |
592 sv->sv_tv = &di->di_tv; | |
593 if (type == NULL) | |
594 sv->sv_type = typval2type(tv, &si->sn_type_list); | |
595 else | |
596 sv->sv_type = type; | |
597 sv->sv_const = (di->di_flags & DI_FLAGS_LOCK) ? ASSIGN_CONST : 0; | |
598 sv->sv_export = is_export; | |
599 newsav->sav_var_vals_idx = si->sn_var_vals.ga_len; | |
600 ++si->sn_var_vals.ga_len; | |
601 | |
602 STRCPY(&newsav->sav_key, di->di_key); | |
603 sv->sv_name = newsav->sav_key; | |
604 newsav->sav_di = di; | |
605 newsav->sav_block_id = si->sn_current_block_id; | |
606 | |
607 hi = hash_find(&si->sn_all_vars.dv_hashtab, newsav->sav_key); | |
608 if (!HASHITEM_EMPTY(hi)) | |
609 { | |
610 sallvar_T *sav = HI2SAV(hi); | |
611 | |
612 // variable with this name exists in another block | |
613 while (sav->sav_next != NULL) | |
614 sav = sav->sav_next; | |
615 sav->sav_next = newsav; | |
616 } | |
617 else | |
618 // new variable name | |
619 hash_add(&si->sn_all_vars.dv_hashtab, newsav->sav_key); | |
620 | |
621 // let ex_export() know the export worked. | |
622 is_export = FALSE; | |
623 } | |
624 } | |
625 | |
626 void | |
627 hide_script_var(scriptitem_T *si, svar_T *sv) | |
628 { | |
629 hashtab_T *script_ht = get_script_local_ht(); | |
630 hashtab_T *all_ht = &si->sn_all_vars.dv_hashtab; | |
631 hashitem_T *script_hi; | |
632 hashitem_T *all_hi; | |
633 | |
634 // Remove a variable declared inside the block, if it still exists. | |
635 // The typval is moved into the sallvar_T. | |
636 script_hi = hash_find(script_ht, sv->sv_name); | |
637 all_hi = hash_find(all_ht, sv->sv_name); | |
638 if (!HASHITEM_EMPTY(script_hi) && !HASHITEM_EMPTY(all_hi)) | |
639 { | |
640 dictitem_T *di = HI2DI(script_hi); | |
641 sallvar_T *sav = HI2SAV(all_hi); | |
642 | |
643 sav->sav_tv = di->di_tv; | |
644 di->di_tv.v_type = VAR_UNKNOWN; | |
645 sav->sav_flags = di->di_flags; | |
646 sav->sav_di = NULL; | |
647 delete_var(script_ht, script_hi); | |
648 } | |
649 } | |
650 | |
651 /* | |
652 * Free the script variables from "sn_all_vars". | |
653 */ | |
654 void | |
655 free_all_script_vars(scriptitem_T *si) | |
656 { | |
657 int todo; | |
658 hashtab_T *ht = &si->sn_all_vars.dv_hashtab; | |
659 hashitem_T *hi; | |
660 sallvar_T *sav; | |
661 sallvar_T *sav_next; | |
662 | |
663 hash_lock(ht); | |
664 todo = (int)ht->ht_used; | |
665 for (hi = ht->ht_array; todo > 0; ++hi) | |
666 { | |
667 if (!HASHITEM_EMPTY(hi)) | |
668 { | |
669 --todo; | |
670 | |
671 // Free the variable. Don't remove it from the hashtab, ht_array | |
672 // might change then. hash_clear() takes care of it later. | |
673 sav = HI2SAV(hi); | |
674 while (sav != NULL) | |
675 { | |
676 sav_next = sav->sav_next; | |
677 if (sav->sav_di == NULL) | |
678 clear_tv(&sav->sav_tv); | |
679 vim_free(sav); | |
680 sav = sav_next; | |
681 } | |
682 } | |
683 } | |
684 hash_clear(ht); | |
685 hash_init(ht); | |
686 | |
687 ga_clear(&si->sn_var_vals); | |
688 } | |
689 | |
690 /* | |
568 * Find the script-local variable that links to "dest". | 691 * Find the script-local variable that links to "dest". |
569 * Returns NULL if not found. | 692 * Returns NULL if not found. |
570 */ | 693 */ |
571 svar_T * | 694 svar_T * |
572 find_typval_in_script(typval_T *dest) | 695 find_typval_in_script(typval_T *dest) |