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.
diff --git a/src/eval.c b/src/eval.c
index 6d7bd66..7875ede 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -4412,6 +4412,7 @@
  *  + 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 @@
 		    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 @@
 }
 
 /*
+ * 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 @@
 }
 
 /*
- * 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 @@
     // "." 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 @@
 	    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 @@
 	    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);