mirror of
https://github.com/vim/vim.git
synced 2025-07-26 11:04:33 -04:00
patch 9.0.2020: Vim9: islocked() needs more work
Problem: Vim9: islocked() needs more work Solution: rework islocked() and remove sync_root from get_lval() closes: #13329 Signed-off-by: Christian Brabandt <cb@256bit.org> Co-authored-by: Ernie Rael <errael@raelity.com>
This commit is contained in:
parent
2bbd0d30ee
commit
0f058d1320
36
src/eval.c
36
src/eval.c
@ -1187,7 +1187,6 @@ get_lval(
|
|||||||
char buf[80];
|
char buf[80];
|
||||||
ch_log(NULL, "LKVAR: ...: GLV flags: %s",
|
ch_log(NULL, "LKVAR: ...: GLV flags: %s",
|
||||||
flags_tostring(flags, glv_flag_strings, buf, sizeof(buf)));
|
flags_tostring(flags, glv_flag_strings, buf, sizeof(buf)));
|
||||||
int log_sync_root_key = FALSE;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Clear everything in "lp".
|
// Clear everything in "lp".
|
||||||
@ -1326,21 +1325,16 @@ get_lval(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int sync_root = FALSE;
|
// Without [idx] or .key we are done.
|
||||||
if (vim9script && lval_root != NULL)
|
if (*p != '[' && *p != '.')
|
||||||
{
|
|
||||||
cl_exec = lval_root->lr_cl_exec;
|
|
||||||
sync_root = lval_root->lr_sync_root;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Without [idx] or .key we are done, unless doing sync_root.
|
|
||||||
if (*p != '[' && *p != '.' && (*name == NUL || !sync_root))
|
|
||||||
{
|
{
|
||||||
if (lval_root != NULL)
|
if (lval_root != NULL)
|
||||||
fill_lval_from_lval_root(lp, lval_root);
|
fill_lval_from_lval_root(lp, lval_root);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (vim9script && lval_root != NULL)
|
||||||
|
cl_exec = lval_root->lr_cl_exec;
|
||||||
if (vim9script && lval_root != NULL && lval_root->lr_tv != NULL)
|
if (vim9script && lval_root != NULL && lval_root->lr_tv != NULL)
|
||||||
{
|
{
|
||||||
// using local variable
|
// using local variable
|
||||||
@ -1375,7 +1369,7 @@ get_lval(
|
|||||||
*/
|
*/
|
||||||
var1.v_type = VAR_UNKNOWN;
|
var1.v_type = VAR_UNKNOWN;
|
||||||
var2.v_type = VAR_UNKNOWN;
|
var2.v_type = VAR_UNKNOWN;
|
||||||
while (*p == '[' || (*p == '.' && p[1] != '=' && p[1] != '.') || sync_root)
|
while (*p == '[' || (*p == '.' && p[1] != '=' && p[1] != '.'))
|
||||||
{
|
{
|
||||||
vartype_T v_type = lp->ll_tv->v_type;
|
vartype_T v_type = lp->ll_tv->v_type;
|
||||||
|
|
||||||
@ -1439,19 +1433,7 @@ get_lval(
|
|||||||
}
|
}
|
||||||
|
|
||||||
len = -1;
|
len = -1;
|
||||||
if (sync_root)
|
if (*p == '.')
|
||||||
{
|
|
||||||
// For example, the first token is a member variable name and
|
|
||||||
// lp->ll_tv is a class/object.
|
|
||||||
// Process it directly without looking for "[idx]" or ".name".
|
|
||||||
key = name;
|
|
||||||
sync_root = FALSE; // only first time through
|
|
||||||
#ifdef LOG_LOCKVAR
|
|
||||||
log_sync_root_key = TRUE;
|
|
||||||
ch_log(NULL, "LKVAR: ... loop: name: %s, sync_root", name);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
else if (*p == '.')
|
|
||||||
{
|
{
|
||||||
key = p + 1;
|
key = p + 1;
|
||||||
for (len = 0; ASCII_ISALNUM(key[len]) || key[len] == '_'; ++len)
|
for (len = 0; ASCII_ISALNUM(key[len]) || key[len] == '_'; ++len)
|
||||||
@ -1543,15 +1525,11 @@ get_lval(
|
|||||||
++p;
|
++p;
|
||||||
}
|
}
|
||||||
#ifdef LOG_LOCKVAR
|
#ifdef LOG_LOCKVAR
|
||||||
if (log_sync_root_key)
|
if (len == -1)
|
||||||
ch_log(NULL, "LKVAR: ... loop: p: %s, sync_root key: %s", p,
|
|
||||||
key);
|
|
||||||
else if (len == -1)
|
|
||||||
ch_log(NULL, "LKVAR: ... loop: p: %s, '[' key: %s", p,
|
ch_log(NULL, "LKVAR: ... loop: p: %s, '[' key: %s", p,
|
||||||
empty1 ? ":" : (char*)tv_get_string(&var1));
|
empty1 ? ":" : (char*)tv_get_string(&var1));
|
||||||
else
|
else
|
||||||
ch_log(NULL, "LKVAR: ... loop: p: %s, '.' key: %s", p, key);
|
ch_log(NULL, "LKVAR: ... loop: p: %s, '.' key: %s", p, key);
|
||||||
log_sync_root_key = FALSE;
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (v_type == VAR_DICT)
|
if (v_type == VAR_DICT)
|
||||||
|
@ -7325,64 +7325,48 @@ free_lval_root(lval_root_T *root)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* This is used if executing in a method, the argument string is a
|
* This is used if executing in a method, the argument string is a
|
||||||
* variable/item expr/reference. If it starts with a potential class/object
|
* variable/item expr/reference. It may start with a potential class/object
|
||||||
* variable then return OK, may get later errors in get_lval.
|
* variable.
|
||||||
*
|
*
|
||||||
* Adjust "root" as needed. Note that name may change (for example to skip
|
* Adjust "root" as needed; lr_tv may be changed or freed.
|
||||||
* "this") and is returned. lr_tv may be changed or freed.
|
|
||||||
*
|
*
|
||||||
* Always returns OK.
|
* Always returns OK.
|
||||||
* Free resources and return FAIL if the root should not be used. Otherwise OK.
|
* Free resources and return FAIL if the root should not be used. Otherwise OK.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int
|
static int
|
||||||
fix_variable_reference_lval_root(lval_root_T *root, char_u **p_name)
|
fix_variable_reference_lval_root(lval_root_T *root, char_u *name)
|
||||||
{
|
{
|
||||||
char_u *name = *p_name;
|
|
||||||
char_u *end;
|
|
||||||
dictitem_T *di;
|
|
||||||
|
|
||||||
// Only set lr_sync_root and lr_tv if the name is an object/class
|
// Check if lr_tv is the name of an object/class reference: name start with
|
||||||
// reference: object ("this.") or class because name is class variable.
|
// "this" or name is class variable. Clear lr_tv if neither.
|
||||||
|
int found_member = FALSE;
|
||||||
if (root->lr_tv->v_type == VAR_OBJECT)
|
if (root->lr_tv->v_type == VAR_OBJECT)
|
||||||
{
|
{
|
||||||
if (STRNCMP("this.", name, 5) == 0)
|
if (STRNCMP("this.", name, 5) == 0 ||STRCMP("this", name) == 0)
|
||||||
{
|
found_member = TRUE;
|
||||||
name += 5;
|
|
||||||
root->lr_sync_root = TRUE;
|
|
||||||
}
|
|
||||||
else if (STRCMP("this", name) == 0)
|
|
||||||
{
|
|
||||||
name += 4;
|
|
||||||
root->lr_sync_root = TRUE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (!root->lr_sync_root) // not object member, try class member
|
if (!found_member) // not object member, try class member
|
||||||
{
|
{
|
||||||
// Explicitly check if the name is a class member.
|
// Explicitly check if the name is a class member.
|
||||||
// If it's not then do nothing.
|
// If it's not then do nothing.
|
||||||
|
char_u *end;
|
||||||
for (end = name; ASCII_ISALNUM(*end) || *end == '_'; ++end)
|
for (end = name; ASCII_ISALNUM(*end) || *end == '_'; ++end)
|
||||||
;
|
;
|
||||||
if (class_member_lookup(root->lr_cl_exec, name, end - name, NULL)
|
int idx = class_member_idx(root->lr_cl_exec, name, end - name);
|
||||||
!= NULL)
|
if (idx >= 0)
|
||||||
{
|
{
|
||||||
// Using a class, so reference the class tv.
|
// A class variable, replace lr_tv with it
|
||||||
di = find_var(root->lr_cl_exec->class_name, NULL, FALSE);
|
clear_tv(root->lr_tv);
|
||||||
if (di != NULL)
|
copy_tv(&root->lr_cl_exec->class_members_tv[idx], root->lr_tv);
|
||||||
{
|
found_member = TRUE;
|
||||||
// replace the lr_tv
|
|
||||||
clear_tv(root->lr_tv);
|
|
||||||
copy_tv(&di->di_tv, root->lr_tv);
|
|
||||||
root->lr_sync_root = TRUE;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!root->lr_sync_root)
|
if (!found_member)
|
||||||
{
|
{
|
||||||
free_tv(root->lr_tv);
|
free_tv(root->lr_tv);
|
||||||
root->lr_tv = NULL; // Not a member variable
|
root->lr_tv = NULL; // Not a member variable
|
||||||
}
|
}
|
||||||
*p_name = name;
|
|
||||||
// If FAIL, then must free_lval_root(root);
|
// If FAIL, then must free_lval_root(root);
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
@ -7415,12 +7399,8 @@ f_islocked(typval_T *argvars, typval_T *rettv)
|
|||||||
{
|
{
|
||||||
// Almost always produces a valid lval_root since lr_cl_exec is used
|
// Almost always produces a valid lval_root since lr_cl_exec is used
|
||||||
// for access verification, lr_tv may be set to NULL.
|
// for access verification, lr_tv may be set to NULL.
|
||||||
char_u *tname = name;
|
if (fix_variable_reference_lval_root(&aroot, name) == OK)
|
||||||
if (fix_variable_reference_lval_root(&aroot, &tname) == OK)
|
|
||||||
{
|
|
||||||
name = tname;
|
|
||||||
root = &aroot;
|
root = &aroot;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lval_root_T *lval_root_save = lval_root;
|
lval_root_T *lval_root_save = lval_root;
|
||||||
|
@ -4605,16 +4605,12 @@ typedef struct lval_S
|
|||||||
} lval_T;
|
} lval_T;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This may be used to specify the base typval that get_lval() uses when
|
* This specifies optional parameters for get_lval(). Arguments may be NULL.
|
||||||
* following a chain, for example a[idx1][idx2].
|
|
||||||
* The lr_sync_root flags signals get_lval that the first time through
|
|
||||||
* the indexing loop, skip handling '.' and '[idx]'.
|
|
||||||
*/
|
*/
|
||||||
typedef struct lval_root_S {
|
typedef struct lval_root_S {
|
||||||
typval_T *lr_tv;
|
typval_T *lr_tv; // Base typval.
|
||||||
class_T *lr_cl_exec; // executing class for access checking
|
class_T *lr_cl_exec; // Executing class for access checking.
|
||||||
int lr_is_arg;
|
int lr_is_arg; // name is an arg (not a member).
|
||||||
int lr_sync_root;
|
|
||||||
} lval_root_T;
|
} lval_root_T;
|
||||||
|
|
||||||
// Structure used to save the current state. Used when executing Normal mode
|
// Structure used to save the current state. Used when executing Normal mode
|
||||||
|
@ -704,6 +704,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
2020,
|
||||||
/**/
|
/**/
|
||||||
2019,
|
2019,
|
||||||
/**/
|
/**/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user