0
0
mirror of https://github.com/vim/vim.git synced 2025-09-24 03:44:06 -04:00

patch 8.1.1803: all builtin functions are global

Problem:    All builtin functions are global.
Solution:   Add the method call operator ->.  Implemented for a limited number
            of functions.
This commit is contained in:
Bram Moolenaar
2019-08-03 21:58:38 +02:00
parent b2129068a5
commit ac92e25a33
10 changed files with 336 additions and 42 deletions

View File

@@ -4412,6 +4412,7 @@ eval6(
* + in front unary plus (ignored)
* trailing [] subscript in String or List
* trailing .name entry in Dictionary
* trailing ->name() method call
*
* "arg" must point to the first non-white of the expression.
* "arg" is advanced to the next non-white after the recognized expression.
@@ -4690,13 +4691,12 @@ eval7(
funcexe_T funcexe;
// Invoke the function.
funcexe.argv_func = NULL;
vim_memset(&funcexe, 0, sizeof(funcexe));
funcexe.firstline = curwin->w_cursor.lnum;
funcexe.lastline = curwin->w_cursor.lnum;
funcexe.doesrange = &len;
funcexe.evaluate = evaluate;
funcexe.partial = partial;
funcexe.selfdict = NULL;
ret = get_func_tv(s, len, rettv, arg, &funcexe);
}
vim_free(s);
@@ -4801,6 +4801,70 @@ eval7(
return ret;
}
/*
* Evaluate "->method()".
* "*arg" points to the '-'.
* Returns FAIL or OK. "*arg" is advanced to after the ')'.
*/
static int
eval_method(
char_u **arg,
typval_T *rettv,
int evaluate,
int verbose) /* give error messages */
{
char_u *name;
long len;
funcexe_T funcexe;
int ret = OK;
typval_T base = *rettv;
// Skip over the ->.
*arg += 2;
// Locate the method name.
name = *arg;
for (len = 0; ASCII_ISALNUM(name[len]) || name[len] == '_'; ++len)
;
if (len == 0)
{
if (verbose)
emsg(_("E260: Missing name after ->"));
return FAIL;
}
// Check for the "(". Skip over white space after it.
if (name[len] != '(')
{
if (verbose)
semsg(_(e_missingparen), name);
return FAIL;
}
*arg += len;
vim_memset(&funcexe, 0, sizeof(funcexe));
funcexe.evaluate = evaluate;
funcexe.basetv = &base;
rettv->v_type = VAR_UNKNOWN;
ret = get_func_tv(name, len, rettv, arg, &funcexe);
/* Clear the funcref afterwards, so that deleting it while
* evaluating the arguments is possible (see test55). */
if (evaluate)
clear_tv(&base);
/* Stop the expression evaluation when immediately aborting on
* error, or when an interrupt occurred or an exception was thrown
* but not caught. */
if (aborting())
{
if (ret == OK)
clear_tv(rettv);
ret = FAIL;
}
return ret;
}
/*
* Evaluate an "[expr]" or "[expr:expr]" index. Also "dict.key".
* "*arg" points to the '[' or '.'.
@@ -7359,9 +7423,13 @@ check_vars(char_u *name, int len)
}
/*
* Handle expr[expr], expr[expr:expr] subscript and .name lookup.
* Also handle function call with Funcref variable: func(expr)
* Can all be combined: dict.func(expr)[idx]['func'](expr)
* Handle:
* - expr[expr], expr[expr:expr] subscript
* - ".name" lookup
* - function call with Funcref variable: func(expr)
* - method call: var->method()
*
* Can all be combined in any order: dict.func(expr)[idx]['func'](expr)->len()
*/
int
handle_subscript(
@@ -7378,14 +7446,15 @@ handle_subscript(
// "." is ".name" lookup when we found a dict or when evaluating and
// scriptversion is at least 2, where string concatenation is "..".
while (ret == OK
&& (**arg == '['
|| (**arg == '.' && (rettv->v_type == VAR_DICT
&& (((**arg == '['
|| (**arg == '.' && (rettv->v_type == VAR_DICT
|| (!evaluate
&& (*arg)[1] != '.'
&& current_sctx.sc_version >= 2)))
|| (**arg == '(' && (!evaluate || rettv->v_type == VAR_FUNC
|| (**arg == '(' && (!evaluate || rettv->v_type == VAR_FUNC
|| rettv->v_type == VAR_PARTIAL)))
&& !VIM_ISWHITE(*(*arg - 1)))
&& !VIM_ISWHITE(*(*arg - 1)))
|| (**arg == '-' && (*arg)[1] == '>')))
{
if (**arg == '(')
{
@@ -7410,10 +7479,9 @@ handle_subscript(
else
s = (char_u *)"";
funcexe.argv_func = NULL;
vim_memset(&funcexe, 0, sizeof(funcexe));
funcexe.firstline = curwin->w_cursor.lnum;
funcexe.lastline = curwin->w_cursor.lnum;
funcexe.doesrange = NULL;
funcexe.evaluate = evaluate;
funcexe.partial = pt;
funcexe.selfdict = selfdict;
@@ -7436,6 +7504,14 @@ handle_subscript(
dict_unref(selfdict);
selfdict = NULL;
}
else if (**arg == '-')
{
if (eval_method(arg, rettv, evaluate, verbose) == FAIL)
{
clear_tv(rettv);
ret = FAIL;
}
}
else /* **arg == '[' || **arg == '.' */
{
dict_unref(selfdict);