Mercurial > vim
diff src/structs.h @ 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 | 7d25264c246c |
children | 107eae953b87 |
line wrap: on
line diff
--- a/src/structs.h +++ b/src/structs.h @@ -889,6 +889,7 @@ typedef struct { } cs_pend; void *cs_forinfo[CSTACK_LEN]; // info used by ":for" int cs_line[CSTACK_LEN]; // line nr of ":while"/":for" line + int cs_block_id[CSTACK_LEN]; // block ID stack int cs_script_var_len[CSTACK_LEN]; // value of sn_var_vals.ga_len // when entering the block int cs_idx; // current entry, or -1 if none @@ -1701,18 +1702,47 @@ struct funccal_entry { * Holds the hashtab with variables local to each sourced script. * Each item holds a variable (nameless) that points to the dict_T. */ -typedef struct -{ +typedef struct { dictitem_T sv_var; dict_T sv_dict; } scriptvar_T; /* + * Entry for "sn_all_vars". Contains the s: variables from sn_vars plus the + * block-local ones. + */ +typedef struct sallvar_S sallvar_T; +struct sallvar_S { + sallvar_T *sav_next; // var with same name but different block + int sav_block_id; // block ID where declared + int sav_var_vals_idx; // index in sn_var_vals + + // So long as the variable is valid (block it was defined in is still + // active) "sav_di" is used. It is set to NULL when leaving the block, + // then sav_tv and sav_flags are used. + dictitem_T *sav_di; // dictitem with di_key and di_tv + typval_T sav_tv; // type and value of the variable + char_u sav_flags; // DI_FLAGS_ flags (only used for variable) + char_u sav_key[1]; // key (actually longer!) +}; + +/* + * In the sn_all_vars hashtab item "hi_key" points to "sav_key" in a sallvar_T. + * This makes it possible to store and find the sallvar_T. + * SAV2HIKEY() converts a sallvar_T pointer to a hashitem key pointer. + * HIKEY2SAV() converts a hashitem key pointer to a sallvar_T pointer. + * HI2SAV() converts a hashitem pointer to a sallvar_T pointer. + */ +#define SAV2HIKEY(sav) ((sav)->sav_key) +#define HIKEY2SAV(p) ((sallvar_T *)(p - offsetof(sallvar_T, sav_key))) +#define HI2SAV(hi) HIKEY2SAV((hi)->hi_key) + +/* * Entry for "sn_var_vals". Used for script-local variables. */ typedef struct { - char_u *sv_name; // points into "sn_vars" di_key - typval_T *sv_tv; // points into "sn_vars" di_tv + char_u *sv_name; // points into "sn_all_vars" di_key + typval_T *sv_tv; // points into "sn_vars" or "sn_all_vars" di_tv type_T *sv_type; int sv_const; int sv_export; // "export let var = val" @@ -1742,12 +1772,27 @@ typedef struct { char_u *sn_name; - scriptvar_T *sn_vars; // stores s: variables for this script - garray_T sn_var_vals; // same variables as a list of svar_T + // "sn_vars" stores the s: variables currently valid. When leaving a block + // variables local to that block are removed. + scriptvar_T *sn_vars; + + // Specific for a Vim9 script. + // "sn_all_vars" stores all script variables ever declared. So long as the + // variable is still valid the value is in "sn_vars->sv_dict...di_tv". + // When the block of a declaration is left the value is moved to + // "sn_all_vars..sav_tv". + // Variables with duplicate names are possible, the sav_block_id must be + // used to check that which variable is valid. + dict_T sn_all_vars; // all script variables, dict of sallvar_T + + // Stores the same variables as in "sn_all_vars" as a list of svar_T, so + // that they can be quickly found by index instead of a hash table lookup. + // Also stores the type. + garray_T sn_var_vals; garray_T sn_imports; // imported items, imported_T - garray_T sn_type_list; // keeps types used by variables + int sn_current_block_id; // Unique ID for each script block int sn_version; // :scriptversion int sn_had_command; // TRUE if any command was executed