mirror of
https://github.com/vim/vim.git
synced 2025-09-10 22:33:40 -04:00
patch 9.1.0440: function get_lval() is too long
Problem: function get_lval() is too long Solution: factor out the get_lval_subscript() function (Yegappan Lakshmanan) closes: #14839 Signed-off-by: Yegappan Lakshmanan <yegappan@yahoo.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
parent
42a5b5a6d0
commit
44cadaa18c
439
src/eval.c
439
src/eval.c
@ -1650,6 +1650,238 @@ get_lval_class_or_obj(
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get the lval of a list/dict/blob/object/class subitem starting at "p". Loop
|
||||||
|
* until no more [idx] or .key is following.
|
||||||
|
*
|
||||||
|
* Returns a pointer to the character after the subscript on success or NULL on
|
||||||
|
* failure.
|
||||||
|
*/
|
||||||
|
static char_u *
|
||||||
|
get_lval_subscript(
|
||||||
|
lval_T *lp,
|
||||||
|
char_u *p,
|
||||||
|
char_u *name,
|
||||||
|
typval_T *rettv,
|
||||||
|
hashtab_T *ht,
|
||||||
|
dictitem_T *v,
|
||||||
|
int unlet,
|
||||||
|
int flags, // GLV_ values
|
||||||
|
class_T *cl_exec)
|
||||||
|
{
|
||||||
|
int vim9script = in_vim9script();
|
||||||
|
int quiet = flags & GLV_QUIET;
|
||||||
|
char_u *key = NULL;
|
||||||
|
int len;
|
||||||
|
typval_T var1;
|
||||||
|
typval_T var2;
|
||||||
|
int empty1 = FALSE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Loop until no more [idx] or .key is following.
|
||||||
|
*/
|
||||||
|
var1.v_type = VAR_UNKNOWN;
|
||||||
|
var2.v_type = VAR_UNKNOWN;
|
||||||
|
|
||||||
|
while (*p == '[' || (*p == '.' && p[1] != '=' && p[1] != '.'))
|
||||||
|
{
|
||||||
|
vartype_T v_type = lp->ll_tv->v_type;
|
||||||
|
|
||||||
|
if (*p == '.' && v_type != VAR_DICT
|
||||||
|
&& v_type != VAR_OBJECT
|
||||||
|
&& v_type != VAR_CLASS)
|
||||||
|
{
|
||||||
|
if (!quiet)
|
||||||
|
semsg(_(e_dot_not_allowed_after_str_str),
|
||||||
|
vartype_name(v_type), name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (v_type != VAR_LIST
|
||||||
|
&& v_type != VAR_DICT
|
||||||
|
&& v_type != VAR_BLOB
|
||||||
|
&& v_type != VAR_OBJECT
|
||||||
|
&& v_type != VAR_CLASS)
|
||||||
|
{
|
||||||
|
if (!quiet)
|
||||||
|
semsg(_(e_index_not_allowed_after_str_str),
|
||||||
|
vartype_name(v_type), name);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A NULL list/blob works like an empty list/blob, allocate one now.
|
||||||
|
int r = OK;
|
||||||
|
if (v_type == VAR_LIST && lp->ll_tv->vval.v_list == NULL)
|
||||||
|
r = rettv_list_alloc(lp->ll_tv);
|
||||||
|
else if (v_type == VAR_BLOB && lp->ll_tv->vval.v_blob == NULL)
|
||||||
|
r = rettv_blob_alloc(lp->ll_tv);
|
||||||
|
if (r == FAIL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (lp->ll_range)
|
||||||
|
{
|
||||||
|
if (!quiet)
|
||||||
|
emsg(_(e_slice_must_come_last));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
#ifdef LOG_LOCKVAR
|
||||||
|
ch_log(NULL, "LKVAR: get_lval() loop: p: %s, type: %s", p,
|
||||||
|
vartype_name(v_type));
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (vim9script && lp->ll_valtype == NULL
|
||||||
|
&& v != NULL
|
||||||
|
&& lp->ll_tv == &v->di_tv
|
||||||
|
&& ht != NULL && ht == get_script_local_ht())
|
||||||
|
{
|
||||||
|
svar_T *sv = find_typval_in_script(lp->ll_tv, 0, TRUE);
|
||||||
|
|
||||||
|
// Vim9 script local variable: get the type
|
||||||
|
if (sv != NULL)
|
||||||
|
{
|
||||||
|
lp->ll_valtype = sv->sv_type;
|
||||||
|
#ifdef LOG_LOCKVAR
|
||||||
|
ch_log(NULL, "LKVAR: ... loop: vim9 assign type: %s",
|
||||||
|
vartype_name(lp->ll_valtype->tt_type));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
len = -1;
|
||||||
|
if (*p == '.')
|
||||||
|
{
|
||||||
|
key = p + 1;
|
||||||
|
|
||||||
|
for (len = 0; ASCII_ISALNUM(key[len]) || key[len] == '_'; ++len)
|
||||||
|
;
|
||||||
|
if (len == 0)
|
||||||
|
{
|
||||||
|
if (!quiet)
|
||||||
|
emsg(_(e_cannot_use_empty_key_for_dictionary));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
p = key + len;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Get the index [expr] or the first index [expr: ].
|
||||||
|
p = skipwhite(p + 1);
|
||||||
|
if (*p == ':')
|
||||||
|
empty1 = TRUE;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
empty1 = FALSE;
|
||||||
|
if (eval1(&p, &var1, &EVALARG_EVALUATE) == FAIL) // recursive!
|
||||||
|
return NULL;
|
||||||
|
if (tv_get_string_chk(&var1) == NULL)
|
||||||
|
{
|
||||||
|
// not a number or string
|
||||||
|
clear_tv(&var1);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
p = skipwhite(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Optionally get the second index [ :expr].
|
||||||
|
if (*p == ':')
|
||||||
|
{
|
||||||
|
if (v_type == VAR_DICT)
|
||||||
|
{
|
||||||
|
if (!quiet)
|
||||||
|
emsg(_(e_cannot_slice_dictionary));
|
||||||
|
clear_tv(&var1);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (rettv != NULL
|
||||||
|
&& !(rettv->v_type == VAR_LIST
|
||||||
|
&& rettv->vval.v_list != NULL)
|
||||||
|
&& !(rettv->v_type == VAR_BLOB
|
||||||
|
&& rettv->vval.v_blob != NULL))
|
||||||
|
{
|
||||||
|
if (!quiet)
|
||||||
|
emsg(_(e_slice_requires_list_or_blob_value));
|
||||||
|
clear_tv(&var1);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
p = skipwhite(p + 1);
|
||||||
|
if (*p == ']')
|
||||||
|
lp->ll_empty2 = TRUE;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lp->ll_empty2 = FALSE;
|
||||||
|
// recursive!
|
||||||
|
if (eval1(&p, &var2, &EVALARG_EVALUATE) == FAIL)
|
||||||
|
{
|
||||||
|
clear_tv(&var1);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
if (tv_get_string_chk(&var2) == NULL)
|
||||||
|
{
|
||||||
|
// not a number or string
|
||||||
|
clear_tv(&var1);
|
||||||
|
clear_tv(&var2);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lp->ll_range = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
lp->ll_range = FALSE;
|
||||||
|
|
||||||
|
if (*p != ']')
|
||||||
|
{
|
||||||
|
if (!quiet)
|
||||||
|
emsg(_(e_missing_closing_square_brace));
|
||||||
|
clear_tv(&var1);
|
||||||
|
clear_tv(&var2);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip to past ']'.
|
||||||
|
++p;
|
||||||
|
}
|
||||||
|
#ifdef LOG_LOCKVAR
|
||||||
|
if (len == -1)
|
||||||
|
ch_log(NULL, "LKVAR: ... loop: p: %s, '[' key: %s", p,
|
||||||
|
empty1 ? ":" : (char*)tv_get_string(&var1));
|
||||||
|
else
|
||||||
|
ch_log(NULL, "LKVAR: ... loop: p: %s, '.' key: %s", p, key);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (v_type == VAR_DICT)
|
||||||
|
{
|
||||||
|
glv_status_T glv_status;
|
||||||
|
|
||||||
|
glv_status = get_lval_dict_item(name, lp, key, len, &p, &var1,
|
||||||
|
flags, unlet, rettv);
|
||||||
|
if (glv_status == GLV_FAIL)
|
||||||
|
return NULL;
|
||||||
|
if (glv_status == GLV_STOP)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (v_type == VAR_BLOB)
|
||||||
|
{
|
||||||
|
if (get_lval_blob(lp, &var1, &var2, empty1, quiet) == FAIL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (v_type == VAR_LIST)
|
||||||
|
{
|
||||||
|
if (get_lval_list(lp, &var1, &var2, empty1, flags, quiet) == FAIL)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else // v_type == VAR_CLASS || v_type == VAR_OBJECT
|
||||||
|
{
|
||||||
|
if (get_lval_class_or_obj(cl_exec, v_type, lp, key, p, flags,
|
||||||
|
quiet) == FAIL)
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clear_tv(&var1);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get an lval: variable, Dict item or List item that can be assigned a value
|
* Get an lval: variable, Dict item or List item that can be assigned a value
|
||||||
* to: "name", "na{me}", "name[expr]", "name[expr:expr]", "name[expr][expr]",
|
* to: "name", "na{me}", "name[expr]", "name[expr:expr]", "name[expr][expr]",
|
||||||
@ -1683,11 +1915,6 @@ get_lval(
|
|||||||
char_u *expr_start, *expr_end;
|
char_u *expr_start, *expr_end;
|
||||||
int cc;
|
int cc;
|
||||||
dictitem_T *v = NULL;
|
dictitem_T *v = NULL;
|
||||||
typval_T var1;
|
|
||||||
typval_T var2;
|
|
||||||
int empty1 = FALSE;
|
|
||||||
char_u *key = NULL;
|
|
||||||
int len;
|
|
||||||
hashtab_T *ht = NULL;
|
hashtab_T *ht = NULL;
|
||||||
int quiet = flags & GLV_QUIET;
|
int quiet = flags & GLV_QUIET;
|
||||||
int writing = 0;
|
int writing = 0;
|
||||||
@ -1864,204 +2091,10 @@ get_lval(
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
// If the next character is a "." or a "[", then process the subitem.
|
||||||
* Loop until no more [idx] or .key is following.
|
p = get_lval_subscript(lp, p, name, rettv, ht, v, unlet, flags, cl_exec);
|
||||||
*/
|
if (p == NULL)
|
||||||
var1.v_type = VAR_UNKNOWN;
|
|
||||||
var2.v_type = VAR_UNKNOWN;
|
|
||||||
while (*p == '[' || (*p == '.' && p[1] != '=' && p[1] != '.'))
|
|
||||||
{
|
|
||||||
vartype_T v_type = lp->ll_tv->v_type;
|
|
||||||
|
|
||||||
if (*p == '.' && v_type != VAR_DICT
|
|
||||||
&& v_type != VAR_OBJECT
|
|
||||||
&& v_type != VAR_CLASS)
|
|
||||||
{
|
|
||||||
if (!quiet)
|
|
||||||
semsg(_(e_dot_not_allowed_after_str_str),
|
|
||||||
vartype_name(v_type), name);
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
|
||||||
if (v_type != VAR_LIST
|
|
||||||
&& v_type != VAR_DICT
|
|
||||||
&& v_type != VAR_BLOB
|
|
||||||
&& v_type != VAR_OBJECT
|
|
||||||
&& v_type != VAR_CLASS)
|
|
||||||
{
|
|
||||||
if (!quiet)
|
|
||||||
semsg(_(e_index_not_allowed_after_str_str),
|
|
||||||
vartype_name(v_type), name);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// A NULL list/blob works like an empty list/blob, allocate one now.
|
|
||||||
int r = OK;
|
|
||||||
if (v_type == VAR_LIST && lp->ll_tv->vval.v_list == NULL)
|
|
||||||
r = rettv_list_alloc(lp->ll_tv);
|
|
||||||
else if (v_type == VAR_BLOB && lp->ll_tv->vval.v_blob == NULL)
|
|
||||||
r = rettv_blob_alloc(lp->ll_tv);
|
|
||||||
if (r == FAIL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (lp->ll_range)
|
|
||||||
{
|
|
||||||
if (!quiet)
|
|
||||||
emsg(_(e_slice_must_come_last));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
#ifdef LOG_LOCKVAR
|
|
||||||
ch_log(NULL, "LKVAR: get_lval() loop: p: %s, type: %s", p,
|
|
||||||
vartype_name(v_type));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (vim9script && lp->ll_valtype == NULL
|
|
||||||
&& v != NULL
|
|
||||||
&& lp->ll_tv == &v->di_tv
|
|
||||||
&& ht != NULL && ht == get_script_local_ht())
|
|
||||||
{
|
|
||||||
svar_T *sv = find_typval_in_script(lp->ll_tv, 0, TRUE);
|
|
||||||
|
|
||||||
// Vim9 script local variable: get the type
|
|
||||||
if (sv != NULL)
|
|
||||||
{
|
|
||||||
lp->ll_valtype = sv->sv_type;
|
|
||||||
#ifdef LOG_LOCKVAR
|
|
||||||
ch_log(NULL, "LKVAR: ... loop: vim9 assign type: %s",
|
|
||||||
vartype_name(lp->ll_valtype->tt_type));
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
len = -1;
|
|
||||||
if (*p == '.')
|
|
||||||
{
|
|
||||||
key = p + 1;
|
|
||||||
for (len = 0; ASCII_ISALNUM(key[len]) || key[len] == '_'; ++len)
|
|
||||||
;
|
|
||||||
if (len == 0)
|
|
||||||
{
|
|
||||||
if (!quiet)
|
|
||||||
emsg(_(e_cannot_use_empty_key_for_dictionary));
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
p = key + len;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Get the index [expr] or the first index [expr: ].
|
|
||||||
p = skipwhite(p + 1);
|
|
||||||
if (*p == ':')
|
|
||||||
empty1 = TRUE;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
empty1 = FALSE;
|
|
||||||
if (eval1(&p, &var1, &EVALARG_EVALUATE) == FAIL) // recursive!
|
|
||||||
return NULL;
|
|
||||||
if (tv_get_string_chk(&var1) == NULL)
|
|
||||||
{
|
|
||||||
// not a number or string
|
|
||||||
clear_tv(&var1);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
p = skipwhite(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Optionally get the second index [ :expr].
|
|
||||||
if (*p == ':')
|
|
||||||
{
|
|
||||||
if (v_type == VAR_DICT)
|
|
||||||
{
|
|
||||||
if (!quiet)
|
|
||||||
emsg(_(e_cannot_slice_dictionary));
|
|
||||||
clear_tv(&var1);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (rettv != NULL
|
|
||||||
&& !(rettv->v_type == VAR_LIST
|
|
||||||
&& rettv->vval.v_list != NULL)
|
|
||||||
&& !(rettv->v_type == VAR_BLOB
|
|
||||||
&& rettv->vval.v_blob != NULL))
|
|
||||||
{
|
|
||||||
if (!quiet)
|
|
||||||
emsg(_(e_slice_requires_list_or_blob_value));
|
|
||||||
clear_tv(&var1);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
p = skipwhite(p + 1);
|
|
||||||
if (*p == ']')
|
|
||||||
lp->ll_empty2 = TRUE;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
lp->ll_empty2 = FALSE;
|
|
||||||
// recursive!
|
|
||||||
if (eval1(&p, &var2, &EVALARG_EVALUATE) == FAIL)
|
|
||||||
{
|
|
||||||
clear_tv(&var1);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (tv_get_string_chk(&var2) == NULL)
|
|
||||||
{
|
|
||||||
// not a number or string
|
|
||||||
clear_tv(&var1);
|
|
||||||
clear_tv(&var2);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
lp->ll_range = TRUE;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
lp->ll_range = FALSE;
|
|
||||||
|
|
||||||
if (*p != ']')
|
|
||||||
{
|
|
||||||
if (!quiet)
|
|
||||||
emsg(_(e_missing_closing_square_brace));
|
|
||||||
clear_tv(&var1);
|
|
||||||
clear_tv(&var2);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Skip to past ']'.
|
|
||||||
++p;
|
|
||||||
}
|
|
||||||
#ifdef LOG_LOCKVAR
|
|
||||||
if (len == -1)
|
|
||||||
ch_log(NULL, "LKVAR: ... loop: p: %s, '[' key: %s", p,
|
|
||||||
empty1 ? ":" : (char*)tv_get_string(&var1));
|
|
||||||
else
|
|
||||||
ch_log(NULL, "LKVAR: ... loop: p: %s, '.' key: %s", p, key);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (v_type == VAR_DICT)
|
|
||||||
{
|
|
||||||
glv_status_T glv_status;
|
|
||||||
|
|
||||||
glv_status = get_lval_dict_item(name, lp, key, len, &p, &var1,
|
|
||||||
flags, unlet, rettv);
|
|
||||||
if (glv_status == GLV_FAIL)
|
|
||||||
return NULL;
|
|
||||||
if (glv_status == GLV_STOP)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (v_type == VAR_BLOB)
|
|
||||||
{
|
|
||||||
if (get_lval_blob(lp, &var1, &var2, empty1, quiet) == FAIL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
else if (v_type == VAR_LIST)
|
|
||||||
{
|
|
||||||
if (get_lval_list(lp, &var1, &var2, empty1, flags, quiet) == FAIL)
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
else // v_type == VAR_CLASS || v_type == VAR_OBJECT
|
|
||||||
{
|
|
||||||
if (get_lval_class_or_obj(cl_exec, v_type, lp, key, p, flags,
|
|
||||||
quiet) == FAIL)
|
|
||||||
return FAIL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (vim9script && lp->ll_valtype != NULL && rettv != NULL)
|
if (vim9script && lp->ll_valtype != NULL && rettv != NULL)
|
||||||
{
|
{
|
||||||
@ -2073,8 +2106,6 @@ get_lval(
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
clear_tv(&var1);
|
|
||||||
lp->ll_name_end = p;
|
lp->ll_name_end = p;
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
@ -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 */
|
||||||
|
/**/
|
||||||
|
440,
|
||||||
/**/
|
/**/
|
||||||
439,
|
439,
|
||||||
/**/
|
/**/
|
||||||
|
Loading…
x
Reference in New Issue
Block a user