0
0
mirror of https://github.com/vim/vim.git synced 2025-09-23 03:43:49 -04:00

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.
This commit is contained in:
Bram Moolenaar
2020-10-14 19:39:19 +02:00
parent 3d30af8783
commit 8d739de43b
7 changed files with 209 additions and 61 deletions

View File

@@ -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