summaryrefslogtreecommitdiffstats
path: root/src/eval.c
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2019-08-03 21:58:38 +0200
committerBram Moolenaar <Bram@vim.org>2019-08-03 21:58:38 +0200
commitac92e25a33c37ec5becbfffeccda136c73b761ac (patch)
tree64f77cc6dd9427536fd113451b1878490b5298db /src/eval.c
parentb2129068a55261bea1e293a6a1ce8491a03e7de6 (diff)
patch 8.1.1803: all builtin functions are globalv8.1.1803
Problem: All builtin functions are global. Solution: Add the method call operator ->. Implemented for a limited number of functions.
Diffstat (limited to 'src/eval.c')
-rw-r--r--src/eval.c98
1 files changed, 87 insertions, 11 deletions
diff --git a/src/eval.c b/src/eval.c
index 6d7bd66775..7875edeafe 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -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);
@@ -4802,6 +4802,70 @@ eval7(
}
/*
+ * 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 '.'.
* Returns FAIL or OK. "*arg" is advanced to after the ']'.
@@ -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);