Loading ...
Sorry, an error occurred while loading the content.

74785Re: [PATCH] Extended funcrefs: use func_T* structure in place of char_u* function names

Expand Messages
  • ZyX
    Jan 6, 2014
    • 0 Attachment
      Merged with upstream, removed no_autoload global, made islocked() and :lockvar no longer trigger script autoloading.

      Also fixed some compilation warnings.

      diff -r bc19475ed196 -r fd7e081faea4 Filelist
      --- a/Filelist Mon Jan 06 15:51:55 2014 +0100
      +++ b/Filelist Tue Jan 07 01:35:53 2014 +0400
      @@ -84,6 +84,8 @@
      src/testdir/test49.vim \
      src/testdir/test60.vim \
      src/testdir/test83-tags? \
      + src/testdir/Test104.vim \
      + src/testdir/test104/autoload/*.vim \
      src/testdir/python2/*.py \
      src/testdir/python3/*.py \
      src/testdir/pythonx/*.py \
      @@ -93,6 +95,7 @@
      src/testdir/pythonx/topmodule/submodule/subsubmodule/subsubsubmodule.py \
      src/testdir/python_after/*.py \
      src/testdir/python_before/*.py \
      + src/testdir/sautest/autoload/*.vim \
      src/proto.h \
      src/proto/blowfish.pro \
      src/proto/buffer.pro \
      diff -r bc19475ed196 -r fd7e081faea4 runtime/doc/eval.txt
      --- a/runtime/doc/eval.txt Mon Jan 06 15:51:55 2014 +0100
      +++ b/runtime/doc/eval.txt Tue Jan 07 01:35:53 2014 +0400
      @@ -1780,7 +1780,8 @@
      foldtext( ) String line displayed for closed fold
      foldtextresult( {lnum}) String text for closed fold at {lnum}
      foreground( ) Number bring the Vim window to the foreground
      -function( {name}) Funcref reference to function {name}
      +function( {name}) Funcref reference to function {name}
      +functype( {func}) String type of function reference {func}
      garbagecollect( [{atexit}]) none free memory, breaking cyclic references
      get( {list}, {idx} [, {def}]) any get item {idx} from {list} or {def}
      get( {dict}, {key} [, {def}]) any get item {key} from {dict} or {def}
      @@ -3128,6 +3129,31 @@
      {name} can be a user defined function or an internal function.


      +functype({func}) *functype()*
      + Given a |Funcref| return string describing its type. Possible
      + values:
      + Value Description ~
      + internal Reference to one of the built-in |functions|.
      + Example: `function('tr')`.
      + user Reference to one of the |user-functions|.
      + Example: `function('NetrwStatusLine')`.
      + autoload Reference to one of the |autoload-functions|
      + that was not yet loaded.
      + Example: `function('zip#Browse')`.
      + autoload:{type} Same as above, but for functions that were
      + already loaded. For `function('zip#Browse')`
      + it will return "autoload:user". {type} may be
      + anything that |functype()| can return
      + (including e.g. "autoload:autoload:internal").
      + python:{type} Reference to some python function. {type} is
      + the python type name.
      + Example: `pyeval('id')` has function type
      + "python:builtin_function_or_method".
      + python3:{type} Same as above, but for python 3 functions.
      + Example: `py3eval('id')` has function type
      + "python3:builtin_function_or_method".
      +
      +
      garbagecollect([{atexit}]) *garbagecollect()*
      Cleanup unused |Lists| and |Dictionaries| that have circular
      references. There is hardly ever a need to invoke this
      diff -r bc19475ed196 -r fd7e081faea4 runtime/doc/if_pyth.txt
      --- a/runtime/doc/if_pyth.txt Mon Jan 06 15:51:55 2014 +0100
      +++ b/runtime/doc/if_pyth.txt Tue Jan 07 01:35:53 2014 +0400
      @@ -656,7 +656,11 @@
      Function-like object, acting like vim |Funcref| object. Supports `.name`
      attribute and is callable. Accepts special keyword argument `self`, see
      |Dictionary-function|. You can also use `vim.Function(name)` constructor,
      - it is the same as `vim.bindeval('function(%s)'%json.dumps(name))`.
      + it is the same as `vim.bindeval('function(%s)'%json.dumps(name))`. Object
      + supports the following attributes:
      + Attribute Description ~
      + name Function name.
      + repr Same as running `vim.bindeval("string(pyeval('func'))")`.

      Examples: >
      f = vim.Function('tr') # Constructor
      diff -r bc19475ed196 -r fd7e081faea4 runtime/doc/repeat.txt
      --- a/runtime/doc/repeat.txt Mon Jan 06 15:51:55 2014 +0100
      +++ b/runtime/doc/repeat.txt Tue Jan 07 01:35:53 2014 +0400
      @@ -668,12 +668,6 @@
      - The time of the lines added up is mostly less than the time of the whole
      function. There is some overhead in between.

      -- Functions that are deleted before Vim exits will not produce profiling
      - information. You can check the |v:profiling| variable if needed: >
      - :if !v:profiling
      - : delfunc MyFunc
      - :endif
      -<
      - Profiling may give weird results on multi-processor systems, when sleep
      mode kicks in or the processor frequency is reduced to save power.

      diff -r bc19475ed196 -r fd7e081faea4 src/eval.c
      --- a/src/eval.c Mon Jan 06 15:51:55 2014 +0100
      +++ b/src/eval.c Tue Jan 07 01:35:53 2014 +0400
      @@ -115,6 +115,7 @@
      #ifdef FEAT_FLOAT
      static char *e_float_as_string = N_("E806: using Float as a String");
      #endif
      +static char *e_unknown_function = N_("E700: Unknown function: %s");

      static dictitem_T globvars_var; /* variable used for g: */
      #define globvarht globvardict.dv_hashtab
      @@ -125,9 +126,6 @@
      */
      static hashtab_T compat_hashtab;

      -/* When using exists() don't auto-load a script. */
      -static int no_autoload = FALSE;
      -
      /*
      * When recursively copying lists and dicts we need to remember which ones we
      * have done to avoid endless recursiveness. This unique ID is used for that.
      @@ -153,10 +151,20 @@

      static int echo_attr = 0; /* attributes used for ":echo" */

      -/* Values for trans_function_name() argument: */
      +/* Values for trans_function_name() flags argument: */
      #define TFN_INT 1 /* internal function name OK */
      #define TFN_QUIET 2 /* no error messages */

      +/* Values for get_called_function() flags argument: */
      +#define GCF_AUTOLOAD 1 /* it is OK to create autoload functions */
      +#define GCF_RUN_EVENT 2 /* run FuncUndefined event */
      +#define GCF_QUIET 4 /* no error messages */
      +#define GCF_ANY_FUNC GCF_AUTOLOAD|GCF_RUN_EVENT
      +
      +/* Values for get_var_tv() flags argument: */
      +#define GVT_VERBOSE 1 /* may give error messages */
      +#define GVT_NO_AUTOLOAD 2 /* disable script autoloading */
      +
      /*
      * Structure to hold info for a user function.
      */
      @@ -166,7 +174,6 @@
      {
      int uf_varargs; /* variable nr of arguments */
      int uf_flags;
      - int uf_calls; /* nr of active calls */
      garray_T uf_args; /* arguments */
      garray_T uf_lines; /* function lines */
      #ifdef FEAT_PROFILE
      @@ -185,19 +192,35 @@
      proftime_T uf_tml_wait; /* start wait time for current line */
      int uf_tml_idx; /* index of line being timed; -1 if none */
      int uf_tml_execed; /* line being timed was executed */
      + ufunc_T *uf_prof_next; /* next profiled function */
      #endif
      scid_T uf_script_ID; /* ID of script where function was defined,
      used for s: variables */
      - int uf_refcount; /* for numbered function: reference count */
      + func_T *uf_func; /* Reference to a func_T structure holding
      + reference to ufunc_T */
      char_u uf_name[1]; /* name of function (actually longer); can
      start with <SNR>123_ (<SNR> is K_SPECIAL
      KS_EXTRA KE_SNR) */
      };

      +/*
      + * Structure to hold info for autoloaded function.
      + */
      +typedef struct aufunc aufunc_T;
      +
      +struct aufunc
      +{
      + char_u *auf_name; /* Function name */
      + func_T *auf_func; /* If function was already autoloaded:
      + record pointer here, otherwise it will hold
      + NULL */
      +};
      +
      /* function flags */
      #define FC_ABORT 1 /* abort function on error */
      #define FC_RANGE 2 /* function accepts range */
      -#define FC_DICT 4 /* Dict function, uses "self" */
      +#define FC_DICT 4 /* Dict function, uses "self" */
      +#define FC_ANON 8 /* Anonymous, not stored in func_hashtab */

      /*
      * All user-defined functions are found in this hashtable.
      @@ -211,6 +234,12 @@
      static dict_T *first_dict = NULL; /* list of all dicts */
      static list_T *first_list = NULL; /* list of all lists */

      +#ifdef FEAT_PROFILE
      +/* Functions being profiled */
      +static ufunc_T *fp_profiled_first = NULL;
      +static ufunc_T *fp_profiled_last = NULL;
      +#endif
      +
      /* From user function to hashitem and back. */
      static ufunc_T dumuf;
      #define UF2HIKEY(fp) ((fp)->uf_name)
      @@ -269,9 +298,13 @@
      */
      typedef struct
      {
      - dict_T *fd_dict; /* Dictionary used */
      + dict_T *fd_dict; /* Dictionary used. Contains borrowed reference.
      + */
      char_u *fd_newkey; /* new key in "dict" in allocated memory */
      dictitem_T *fd_di; /* Dictionary item used */
      + func_T *fd_func; /* Function object, if it was obtained.
      + * Contains borrowed reference, no need to
      + * decref. */
      } funcdict_T;


      @@ -439,17 +472,16 @@
      static int get_dict_tv __ARGS((char_u **arg, typval_T *rettv, int evaluate));
      static char_u *echo_string __ARGS((typval_T *tv, char_u **tofree, char_u *numbuf, int copyID));
      static char_u *tv2string __ARGS((typval_T *tv, char_u **tofree, char_u *numbuf, int copyID));
      -static char_u *string_quote __ARGS((char_u *str, int function));
      #ifdef FEAT_FLOAT
      static int string2float __ARGS((char_u *text, float_T *value));
      #endif
      static int get_env_tv __ARGS((char_u **arg, typval_T *rettv, int evaluate));
      -static int find_internal_func __ARGS((char_u *name));
      -static char_u *deref_func_name __ARGS((char_u *name, int *lenp));
      -static int get_func_tv __ARGS((char_u *name, int len, typval_T *rettv, char_u **arg, linenr_T firstline, linenr_T lastline, int *doesrange, int evaluate, dict_T *selfdict));
      -static int call_func __ARGS((char_u *funcname, int len, typval_T *rettv, int argcount, typval_T *argvars, linenr_T firstline, linenr_T lastline, int *doesrange, int evaluate, dict_T *selfdict));
      +static struct fst *find_internal_func __ARGS((char_u *name));
      +static int get_func_tv __ARGS((func_T *name, typval_T *rettv, char_u **arg, linenr_T firstline, linenr_T lastline, int *doesrange, int evaluate, dict_T *selfdict));
      +static int call_func __ARGS((func_T *func, typval_T *rettv, int argcount, typval_T *argvars, linenr_T firstline, linenr_T lastline, int *doesrange, dict_T *selfdict));
      static void emsg_funcname __ARGS((char *ermsg, char_u *name));
      static int non_zero_arg __ARGS((typval_T *argvars));
      +static aufunc_T *aufunc_alloc __ARGS((void));

      #ifdef FEAT_FLOAT
      static void f_abs __ARGS((typval_T *argvars, typval_T *rettv));
      @@ -537,6 +569,7 @@
      static void f_foldtextresult __ARGS((typval_T *argvars, typval_T *rettv));
      static void f_foreground __ARGS((typval_T *argvars, typval_T *rettv));
      static void f_function __ARGS((typval_T *argvars, typval_T *rettv));
      +static void f_functype __ARGS((typval_T *argvars, typval_T *rettv));
      static void f_garbagecollect __ARGS((typval_T *argvars, typval_T *rettv));
      static void f_get __ARGS((typval_T *argvars, typval_T *rettv));
      static void f_getbufline __ARGS((typval_T *argvars, typval_T *rettv));
      @@ -770,7 +803,7 @@
      static char_u * make_expanded_name __ARGS((char_u *in_start, char_u *expr_start, char_u *expr_end, char_u *in_end));
      static int eval_isnamec __ARGS((int c));
      static int eval_isnamec1 __ARGS((int c));
      -static int get_var_tv __ARGS((char_u *name, int len, typval_T *rettv, int verbose));
      +static int get_var_tv __ARGS((char_u *name, int len, typval_T *rettv, int flags));
      static int handle_subscript __ARGS((char_u **arg, typval_T *rettv, int evaluate, int verbose));
      static typval_T *alloc_tv __ARGS((void));
      static typval_T *alloc_string_tv __ARGS((char_u *string));
      @@ -781,8 +814,8 @@
      static char_u *get_tv_string __ARGS((typval_T *varp));
      static char_u *get_tv_string_buf __ARGS((typval_T *varp, char_u *buf));
      static char_u *get_tv_string_buf_chk __ARGS((typval_T *varp, char_u *buf));
      -static dictitem_T *find_var __ARGS((char_u *name, hashtab_T **htp));
      -static dictitem_T *find_var_in_ht __ARGS((hashtab_T *ht, int htname, char_u *varname, int writing));
      +static dictitem_T *find_var __ARGS((char_u *name, hashtab_T **htp, int no_autoload));
      +static dictitem_T *find_var_in_ht __ARGS((hashtab_T *ht, int htname, char_u *varname, int no_autoload));
      static hashtab_T *find_var_ht __ARGS((char_u *name, char_u **varname));
      static void vars_clear_ext __ARGS((hashtab_T *ht, int free_val));
      static void delete_var __ARGS((hashtab_T *ht, hashitem_T *hi));
      @@ -793,10 +826,12 @@
      static int var_check_fixed __ARGS((int flags, char_u *name));
      static int var_check_func_name __ARGS((char_u *name, int new_var));
      static int valid_varname __ARGS((char_u *varname));
      +static int valid_autoload_name __ARGS((char_u *varname));
      static int tv_check_lock __ARGS((int lock, char_u *name));
      static int item_copy __ARGS((typval_T *from, typval_T *to, int deep, int copyID));
      static char_u *find_option_end __ARGS((char_u **arg, int *opt_flags));
      static char_u *trans_function_name __ARGS((char_u **pp, int skip, int flags, funcdict_T *fd));
      +static func_T *get_called_function __ARGS((char_u **pp, int skip, funcdict_T *fd, int flags));
      static int eval_fname_script __ARGS((char_u *p));
      static int eval_fname_sid __ARGS((char_u *p));
      static void list_func_head __ARGS((ufunc_T *fp, int indent));
      @@ -805,6 +840,7 @@
      static int builtin_function __ARGS((char_u *name));
      #ifdef FEAT_PROFILE
      static void func_do_profile __ARGS((ufunc_T *fp));
      +static void func_clear_profile __ARGS((ufunc_T *fp));
      static void prof_sort_list __ARGS((FILE *fd, ufunc_T **sorttab, int st_len, char *title, int prefer_self));
      static void prof_func_line __ARGS((FILE *fd, int count, proftime_T *total, proftime_T *self, int prefer_self));
      static int
      @@ -821,8 +857,9 @@
      static int script_autoload __ARGS((char_u *name, int reload));
      static char_u *autoload_name __ARGS((char_u *name));
      static void cat_func_name __ARGS((char_u *buf, ufunc_T *fp));
      -static void func_free __ARGS((ufunc_T *fp));
      -static void call_user_func __ARGS((ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rettv, linenr_T firstline, linenr_T lastline, dict_T *selfdict));
      +static void dealloc_user_func __ARGS((ufunc_T *fp));
      +static int call_user_func __ARGS((ufunc_T *fp, typval_T *rettv, int argcount, typval_T *argvars, linenr_T firstline, linenr_T lastline, int *doesrange, dict_T *selfdict));
      +static void remove_user_func __ARGS((ufunc_T *fp));
      static int can_free_funccal __ARGS((funccall_T *fc, int copyID)) ;
      static void free_funccal __ARGS((funccall_T *fc, int free_val));
      static void add_nr_var __ARGS((dict_T *dp, dictitem_T *v, char *name, varnumber_T nr));
      @@ -838,6 +875,11 @@
      static void sortFunctions __ARGS(());
      #endif

      +
      +static funcdef_T user_func_type;
      +static funcdef_T internal_func_type;
      +static funcdef_T autoload_func_type;
      +
      /*
      * Initialize the global and v: variables.
      */
      @@ -1563,10 +1605,10 @@
      * Returns OK or FAIL.
      */
      int
      -call_vim_function(func, argc, argv, safe, str_arg_only, rettv)
      - char_u *func;
      +call_vim_function(name, argc, argv, safe, str_arg_only, rettv)
      + char_u *name;
      int argc;
      - char_u **argv;
      + char_u **argv;
      int safe; /* use the sandbox */
      int str_arg_only; /* all arguments are strings */
      typval_T *rettv;
      @@ -1578,11 +1620,19 @@
      int doesrange;
      void *save_funccalp = NULL;
      int ret;
      + func_T *func;

      argvars = (typval_T *)alloc((unsigned)((argc + 1) * sizeof(typval_T)));
      if (argvars == NULL)
      return FAIL;

      + func = deref_func_name(name, STRLEN(name), DF_ALL);
      + if (func == NULL)
      + {
      + vim_free(argvars);
      + return FAIL;
      + }
      +
      for (i = 0; i < argc; i++)
      {
      /* Pass a NULL or empty argument as an empty string */
      @@ -1617,9 +1667,9 @@
      }

      rettv->v_type = VAR_UNKNOWN; /* clear_tv() uses this */
      - ret = call_func(func, (int)STRLEN(func), rettv, argc, argvars,
      + ret = call_func(func, rettv, argc, argvars,
      curwin->w_cursor.lnum, curwin->w_cursor.lnum,
      - &doesrange, TRUE, NULL);
      + &doesrange, NULL);
      if (safe)
      {
      --sandbox;
      @@ -1630,6 +1680,8 @@
      if (ret == FAIL)
      clear_tv(rettv);

      + func_unref(func);
      +
      return ret;
      }

      @@ -2239,7 +2291,7 @@
      {
      if (tofree != NULL)
      name = tofree;
      - if (get_var_tv(name, len, &tv, TRUE) == FAIL)
      + if (get_var_tv(name, len, &tv, GVT_VERBOSE) == FAIL)
      error = TRUE;
      else
      {
      @@ -2591,7 +2643,7 @@

      cc = *p;
      *p = NUL;
      - v = find_var(lp->ll_name, &ht);
      + v = find_var(lp->ll_name, &ht, FALSE);
      if (v == NULL && !quiet)
      EMSG2(_(e_undefvar), lp->ll_name);
      *p = cc;
      @@ -2903,8 +2955,8 @@
      typval_T tv;

      /* handle +=, -= and .= */
      - if (get_var_tv(lp->ll_name, (int)STRLEN(lp->ll_name),
      - &tv, TRUE) == OK)
      + if (get_var_tv(lp->ll_name, (int)STRLEN(lp->ll_name), &tv,
      + GVT_VERBOSE) == OK)
      {
      if (tv_op(&tv, rettv, op) == OK)
      set_var(lp->ll_name, &tv, FALSE);
      @@ -3387,8 +3439,7 @@
      {
      char_u *arg = eap->arg;
      char_u *startarg;
      - char_u *name;
      - char_u *tofree;
      + func_T *func;
      int len;
      typval_T rettv;
      linenr_T lnum;
      @@ -3408,14 +3459,14 @@
      return;
      }

      - tofree = trans_function_name(&arg, eap->skip, TFN_INT, &fudi);
      + func = get_called_function(&arg, eap->skip, &fudi, GCF_ANY_FUNC);
      if (fudi.fd_newkey != NULL)
      {
      /* Still need to give an error message for missing key. */
      EMSG2(_(e_dictkey), fudi.fd_newkey);
      vim_free(fudi.fd_newkey);
      }
      - if (tofree == NULL)
      + if (func == NULL)
      return;

      /* Increase refcount on dictionary, it could get deleted when evaluating
      @@ -3423,10 +3474,6 @@
      if (fudi.fd_dict != NULL)
      ++fudi.fd_dict->dv_refcount;

      - /* If it is the name of a variable of type VAR_FUNC use its contents. */
      - len = (int)STRLEN(tofree);
      - name = deref_func_name(tofree, &len);
      -
      /* Skip white space to allow ":call func ()". Not good, but required for
      * backward compatibility. */
      startarg = skipwhite(arg);
      @@ -3462,7 +3509,7 @@
      #endif
      }
      arg = startarg;
      - if (get_func_tv(name, (int)STRLEN(name), &rettv, &arg,
      + if (get_func_tv(func, &rettv, &arg,
      eap->line1, eap->line2, &doesrange,
      !eap->skip, fudi.fd_dict) == FAIL)
      {
      @@ -3504,8 +3551,8 @@
      }

      end:
      + func_unref(func);
      dict_unref(fudi.fd_dict);
      - vim_free(tofree);
      }

      /*
      @@ -3709,7 +3756,7 @@
      ret = FAIL;
      else
      {
      - di = find_var(lp->ll_name, NULL);
      + di = find_var(lp->ll_name, NULL, TRUE);
      if (di == NULL)
      ret = FAIL;
      else
      @@ -4476,12 +4523,17 @@
      else
      {
      /* Compare two Funcrefs for being equal or unequal. */
      - if (rettv->vval.v_string == NULL
      - || var2.vval.v_string == NULL)
      + if (rettv->vval.v_func == NULL
      + || var2.vval.v_func == NULL)
      + n1 = FALSE;
      + else if (rettv->vval.v_func->fv_type !=
      + var2.vval.v_func->fv_type)
      n1 = FALSE;
      else
      - n1 = STRCMP(rettv->vval.v_string,
      - var2.vval.v_string) == 0;
      + n1 = rettv->vval.v_func->fv_type->fd_compare(
      + rettv->vval.v_func->fv_data,
      + var2.vval.v_func->fv_data
      + );
      if (type == TYPE_NEQUAL)
      n1 = !n1;
      }
      @@ -5150,21 +5202,39 @@
      {
      if (**arg == '(') /* recursive! */
      {
      + func_T *func;
      /* If "s" is the name of a variable of type VAR_FUNC
      * use its contents. */
      - s = deref_func_name(s, &len);
      -
      - /* Invoke the function. */
      - ret = get_func_tv(s, len, rettv, arg,
      - curwin->w_cursor.lnum, curwin->w_cursor.lnum,
      - &len, evaluate, NULL);
      + if (evaluate)
      + func = deref_func_name(s, len, DF_ALL);
      + else
      + func = NULL;
      +
      + if (evaluate && func == NULL)
      + {
      + char_u cc;
      + ret = FAIL;
      + cc = s[len];
      + s[len] = '\0';
      + emsg_funcname(N_("E117: Unknown function: %s"), s);
      + s[len] = cc;
      + }
      + else
      + {
      + /* Invoke the function. */
      + ret = get_func_tv(func, rettv, arg,
      + curwin->w_cursor.lnum, curwin->w_cursor.lnum,
      + &len, evaluate, NULL);
      +
      + func_unref(func);
      + }

      /* If evaluate is FALSE rettv->v_type was not set in
      * get_func_tv, but it's needed in handle_subscript() to parse
      * what follows. So set it here. */
      if (rettv->v_type == VAR_UNKNOWN && !evaluate && **arg == '(')
      {
      - rettv->vval.v_string = vim_strsave((char_u *)"");
      + rettv->vval.v_func = NULL;
      rettv->v_type = VAR_FUNC;
      }

      @@ -5179,7 +5249,7 @@
      }
      }
      else if (evaluate)
      - ret = get_var_tv(s, len, rettv, TRUE);
      + ret = get_var_tv(s, len, rettv, GVT_VERBOSE);
      else
      ret = OK;
      }
      @@ -6125,9 +6195,13 @@
      return r;

      case VAR_FUNC:
      - return (tv1->vval.v_string != NULL
      - && tv2->vval.v_string != NULL
      - && STRCMP(tv1->vval.v_string, tv2->vval.v_string) == 0);
      + return (tv1->vval.v_func != NULL
      + && tv2->vval.v_func != NULL
      + && tv1->vval.v_func->fv_type == tv2->vval.v_func->fv_type
      + && tv1->vval.v_func->fv_type->fd_compare(
      + tv1->vval.v_func->fv_data,
      + tv2->vval.v_func->fv_data
      + ));

      case VAR_NUMBER:
      return tv1->vval.v_number == tv2->vval.v_number;
      @@ -7419,7 +7493,7 @@
      else
      ga_concat(&ga, (char_u *)", ");

      - tofree = string_quote(hi->hi_key, FALSE);
      + tofree = string_quote(hi->hi_key, NULL);
      if (tofree != NULL)
      {
      ga_concat(&ga, tofree);
      @@ -7598,8 +7672,8 @@
      switch (tv->v_type)
      {
      case VAR_FUNC:
      - *tofree = NULL;
      - r = tv->vval.v_string;
      + r = FUNC_REPR(tv->vval.v_func);
      + *tofree = r;
      break;

      case VAR_LIST:
      @@ -7680,10 +7754,10 @@
      switch (tv->v_type)
      {
      case VAR_FUNC:
      - *tofree = string_quote(tv->vval.v_string, TRUE);
      + *tofree = FUNC_REPR(tv->vval.v_func);
      return *tofree;
      case VAR_STRING:
      - *tofree = string_quote(tv->vval.v_string, FALSE);
      + *tofree = string_quote(tv->vval.v_string, NULL);
      return *tofree;
      #ifdef FEAT_FLOAT
      case VAR_FLOAT:
      @@ -7704,17 +7778,25 @@
      /*
      * Return string "str" in ' quotes, doubling ' characters.
      * If "str" is NULL an empty string is assumed.
      - * If "function" is TRUE make it function('string').
      - */
      - static char_u *
      -string_quote(str, function)
      + * If "fname" is not NULL make it fname('string').
      + */
      + char_u *
      +string_quote(str, fname)
      char_u *str;
      - int function;
      + char *fname;
      {
      unsigned len;
      + unsigned flen = 0;
      char_u *p, *r, *s;
      -
      - len = (function ? 13 : 3);
      + char_u *fname_u = (char_u *) fname;
      +
      + if (fname_u != NULL)
      + flen = STRLEN(fname_u);
      +
      + /* +---+- 2 quotes and NUL *
      + * | | +- parenthesis *
      + * | | | */
      + len = (fname_u == NULL ? 3 : 3 + 2 + flen);
      if (str != NULL)
      {
      len += (unsigned)STRLEN(str);
      @@ -7725,13 +7807,13 @@
      s = r = alloc(len);
      if (r != NULL)
      {
      - if (function)
      - {
      - STRCPY(r, "function('");
      - r += 10;
      - }
      - else
      - *r++ = '\'';
      + if (fname_u)
      + {
      + mch_memmove(r, fname_u, flen);
      + r += flen;
      + *r++ = '(';
      + }
      + *r++ = '\'';
      if (str != NULL)
      for (p = str; *p != NUL; )
      {
      @@ -7740,7 +7822,7 @@
      MB_COPY_CHAR(p, r);
      }
      *r++ = '\'';
      - if (function)
      + if (fname_u)
      *r++ = ')';
      *r++ = NUL;
      }
      @@ -7833,322 +7915,325 @@
      char *f_name; /* function name */
      char f_min_argc; /* minimal number of arguments */
      char f_max_argc; /* maximal number of arguments */
      - void (*f_func) __ARGS((typval_T *args, typval_T *rvar));
      + void (*f_call) __ARGS((typval_T *args, typval_T *rvar));
      /* implementation of function */
      + func_T *f_func; /* reference to a func_T structure holding
      + reference to struct fst */
      } functions[] =
      {
      #ifdef FEAT_FLOAT
      - {"abs", 1, 1, f_abs},
      - {"acos", 1, 1, f_acos}, /* WJMc */
      -#endif
      - {"add", 2, 2, f_add},
      - {"and", 2, 2, f_and},
      - {"append", 2, 2, f_append},
      - {"argc", 0, 0, f_argc},
      - {"argidx", 0, 0, f_argidx},
      - {"argv", 0, 1, f_argv},
      -#ifdef FEAT_FLOAT
      - {"asin", 1, 1, f_asin}, /* WJMc */
      - {"atan", 1, 1, f_atan},
      - {"atan2", 2, 2, f_atan2},
      -#endif
      - {"browse", 4, 4, f_browse},
      - {"browsedir", 2, 2, f_browsedir},
      - {"bufexists", 1, 1, f_bufexists},
      - {"buffer_exists", 1, 1, f_bufexists}, /* obsolete */
      - {"buffer_name", 1, 1, f_bufname}, /* obsolete */
      - {"buffer_number", 1, 1, f_bufnr}, /* obsolete */
      - {"buflisted", 1, 1, f_buflisted},
      - {"bufloaded", 1, 1, f_bufloaded},
      - {"bufname", 1, 1, f_bufname},
      - {"bufnr", 1, 2, f_bufnr},
      - {"bufwinnr", 1, 1, f_bufwinnr},
      - {"byte2line", 1, 1, f_byte2line},
      - {"byteidx", 2, 2, f_byteidx},
      - {"byteidxcomp", 2, 2, f_byteidxcomp},
      - {"call", 2, 3, f_call},
      -#ifdef FEAT_FLOAT
      - {"ceil", 1, 1, f_ceil},
      -#endif
      - {"changenr", 0, 0, f_changenr},
      - {"char2nr", 1, 2, f_char2nr},
      - {"cindent", 1, 1, f_cindent},
      - {"clearmatches", 0, 0, f_clearmatches},
      - {"col", 1, 1, f_col},
      + {"abs", 1, 1, f_abs, NULL},
      + {"acos", 1, 1, f_acos, NULL}, /* WJMc */
      +#endif
      + {"add", 2, 2, f_add, NULL},
      + {"and", 2, 2, f_and, NULL},
      + {"append", 2, 2, f_append, NULL},
      + {"argc", 0, 0, f_argc, NULL},
      + {"argidx", 0, 0, f_argidx, NULL},
      + {"argv", 0, 1, f_argv, NULL},
      +#ifdef FEAT_FLOAT
      + {"asin", 1, 1, f_asin, NULL}, /* WJMc */
      + {"atan", 1, 1, f_atan, NULL},
      + {"atan2", 2, 2, f_atan2, NULL},
      +#endif
      + {"browse", 4, 4, f_browse, NULL},
      + {"browsedir", 2, 2, f_browsedir, NULL},
      + {"bufexists", 1, 1, f_bufexists, NULL},
      + {"buffer_exists", 1, 1, f_bufexists, NULL}, /* obsolete */
      + {"buffer_name", 1, 1, f_bufname, NULL}, /* obsolete */
      + {"buffer_number", 1, 1, f_bufnr, NULL}, /* obsolete */
      + {"buflisted", 1, 1, f_buflisted, NULL},
      + {"bufloaded", 1, 1, f_bufloaded, NULL},
      + {"bufname", 1, 1, f_bufname, NULL},
      + {"bufnr", 1, 2, f_bufnr, NULL},
      + {"bufwinnr", 1, 1, f_bufwinnr, NULL},
      + {"byte2line", 1, 1, f_byte2line, NULL},
      + {"byteidx", 2, 2, f_byteidx, NULL},
      + {"byteidxcomp", 2, 2, f_byteidxcomp, NULL},
      + {"call", 2, 3, f_call, NULL},
      +#ifdef FEAT_FLOAT
      + {"ceil", 1, 1, f_ceil, NULL},
      +#endif
      + {"changenr", 0, 0, f_changenr, NULL},
      + {"char2nr", 1, 2, f_char2nr, NULL},
      + {"cindent", 1, 1, f_cindent, NULL},
      + {"clearmatches", 0, 0, f_clearmatches, NULL},
      + {"col", 1, 1, f_col, NULL},
      #if defined(FEAT_INS_EXPAND)
      - {"complete", 2, 2, f_complete},
      - {"complete_add", 1, 1, f_complete_add},
      - {"complete_check", 0, 0, f_complete_check},
      -#endif
      - {"confirm", 1, 4, f_confirm},
      - {"copy", 1, 1, f_copy},
      -#ifdef FEAT_FLOAT
      - {"cos", 1, 1, f_cos},
      - {"cosh", 1, 1, f_cosh},
      -#endif
      - {"count", 2, 4, f_count},
      - {"cscope_connection",0,3, f_cscope_connection},
      - {"cursor", 1, 3, f_cursor},
      - {"deepcopy", 1, 2, f_deepcopy},
      - {"delete", 1, 1, f_delete},
      - {"did_filetype", 0, 0, f_did_filetype},
      - {"diff_filler", 1, 1, f_diff_filler},
      - {"diff_hlID", 2, 2, f_diff_hlID},
      - {"empty", 1, 1, f_empty},
      - {"escape", 2, 2, f_escape},
      - {"eval", 1, 1, f_eval},
      - {"eventhandler", 0, 0, f_eventhandler},
      - {"executable", 1, 1, f_executable},
      - {"exists", 1, 1, f_exists},
      -#ifdef FEAT_FLOAT
      - {"exp", 1, 1, f_exp},
      -#endif
      - {"expand", 1, 3, f_expand},
      - {"extend", 2, 3, f_extend},
      - {"feedkeys", 1, 2, f_feedkeys},
      - {"file_readable", 1, 1, f_filereadable}, /* obsolete */
      - {"filereadable", 1, 1, f_filereadable},
      - {"filewritable", 1, 1, f_filewritable},
      - {"filter", 2, 2, f_filter},
      - {"finddir", 1, 3, f_finddir},
      - {"findfile", 1, 3, f_findfile},
      -#ifdef FEAT_FLOAT
      - {"float2nr", 1, 1, f_float2nr},
      - {"floor", 1, 1, f_floor},
      - {"fmod", 2, 2, f_fmod},
      -#endif
      - {"fnameescape", 1, 1, f_fnameescape},
      - {"fnamemodify", 2, 2, f_fnamemodify},
      - {"foldclosed", 1, 1, f_foldclosed},
      - {"foldclosedend", 1, 1, f_foldclosedend},
      - {"foldlevel", 1, 1, f_foldlevel},
      - {"foldtext", 0, 0, f_foldtext},
      - {"foldtextresult", 1, 1, f_foldtextresult},
      - {"foreground", 0, 0, f_foreground},
      - {"function", 1, 1, f_function},
      - {"garbagecollect", 0, 1, f_garbagecollect},
      - {"get", 2, 3, f_get},
      - {"getbufline", 2, 3, f_getbufline},
      - {"getbufvar", 2, 3, f_getbufvar},
      - {"getchar", 0, 1, f_getchar},
      - {"getcharmod", 0, 0, f_getcharmod},
      - {"getcmdline", 0, 0, f_getcmdline},
      - {"getcmdpos", 0, 0, f_getcmdpos},
      - {"getcmdtype", 0, 0, f_getcmdtype},
      - {"getcwd", 0, 0, f_getcwd},
      - {"getfontname", 0, 1, f_getfontname},
      - {"getfperm", 1, 1, f_getfperm},
      - {"getfsize", 1, 1, f_getfsize},
      - {"getftime", 1, 1, f_getftime},
      - {"getftype", 1, 1, f_getftype},
      - {"getline", 1, 2, f_getline},
      - {"getloclist", 1, 1, f_getqflist},
      - {"getmatches", 0, 0, f_getmatches},
      - {"getpid", 0, 0, f_getpid},
      - {"getpos", 1, 1, f_getpos},
      - {"getqflist", 0, 0, f_getqflist},
      - {"getreg", 0, 2, f_getreg},
      - {"getregtype", 0, 1, f_getregtype},
      - {"gettabvar", 2, 3, f_gettabvar},
      - {"gettabwinvar", 3, 4, f_gettabwinvar},
      - {"getwinposx", 0, 0, f_getwinposx},
      - {"getwinposy", 0, 0, f_getwinposy},
      - {"getwinvar", 2, 3, f_getwinvar},
      - {"glob", 1, 3, f_glob},
      - {"globpath", 2, 3, f_globpath},
      - {"has", 1, 1, f_has},
      - {"has_key", 2, 2, f_has_key},
      - {"haslocaldir", 0, 0, f_haslocaldir},
      - {"hasmapto", 1, 3, f_hasmapto},
      - {"highlightID", 1, 1, f_hlID}, /* obsolete */
      - {"highlight_exists",1, 1, f_hlexists}, /* obsolete */
      - {"histadd", 2, 2, f_histadd},
      - {"histdel", 1, 2, f_histdel},
      - {"histget", 1, 2, f_histget},
      - {"histnr", 1, 1, f_histnr},
      - {"hlID", 1, 1, f_hlID},
      - {"hlexists", 1, 1, f_hlexists},
      - {"hostname", 0, 0, f_hostname},
      - {"iconv", 3, 3, f_iconv},
      - {"indent", 1, 1, f_indent},
      - {"index", 2, 4, f_index},
      - {"input", 1, 3, f_input},
      - {"inputdialog", 1, 3, f_inputdialog},
      - {"inputlist", 1, 1, f_inputlist},
      - {"inputrestore", 0, 0, f_inputrestore},
      - {"inputsave", 0, 0, f_inputsave},
      - {"inputsecret", 1, 2, f_inputsecret},
      - {"insert", 2, 3, f_insert},
      - {"invert", 1, 1, f_invert},
      - {"isdirectory", 1, 1, f_isdirectory},
      - {"islocked", 1, 1, f_islocked},
      - {"items", 1, 1, f_items},
      - {"join", 1, 2, f_join},
      - {"keys", 1, 1, f_keys},
      - {"last_buffer_nr", 0, 0, f_last_buffer_nr},/* obsolete */
      - {"len", 1, 1, f_len},
      - {"libcall", 3, 3, f_libcall},
      - {"libcallnr", 3, 3, f_libcallnr},
      - {"line", 1, 1, f_line},
      - {"line2byte", 1, 1, f_line2byte},
      - {"lispindent", 1, 1, f_lispindent},
      - {"localtime", 0, 0, f_localtime},
      -#ifdef FEAT_FLOAT
      - {"log", 1, 1, f_log},
      - {"log10", 1, 1, f_log10},
      + {"complete", 2, 2, f_complete, NULL},
      + {"complete_add", 1, 1, f_complete_add, NULL},
      + {"complete_check", 0, 0, f_complete_check, NULL},
      +#endif
      + {"confirm", 1, 4, f_confirm, NULL},
      + {"copy", 1, 1, f_copy, NULL},
      +#ifdef FEAT_FLOAT
      + {"cos", 1, 1, f_cos, NULL},
      + {"cosh", 1, 1, f_cosh, NULL},
      +#endif
      + {"count", 2, 4, f_count, NULL},
      + {"cscope_connection",0,3, f_cscope_connection, NULL},
      + {"cursor", 1, 3, f_cursor, NULL},
      + {"deepcopy", 1, 2, f_deepcopy, NULL},
      + {"delete", 1, 1, f_delete, NULL},
      + {"did_filetype", 0, 0, f_did_filetype, NULL},
      + {"diff_filler", 1, 1, f_diff_filler, NULL},
      + {"diff_hlID", 2, 2, f_diff_hlID, NULL},
      + {"empty", 1, 1, f_empty, NULL},
      + {"escape", 2, 2, f_escape, NULL},
      + {"eval", 1, 1, f_eval, NULL},
      + {"eventhandler", 0, 0, f_eventhandler, NULL},
      + {"executable", 1, 1, f_executable, NULL},
      + {"exists", 1, 1, f_exists, NULL},
      +#ifdef FEAT_FLOAT
      + {"exp", 1, 1, f_exp, NULL},
      +#endif
      + {"expand", 1, 3, f_expand, NULL},
      + {"extend", 2, 3, f_extend, NULL},
      + {"feedkeys", 1, 2, f_feedkeys, NULL},
      + {"file_readable", 1, 1, f_filereadable, NULL}, /* obsolete */
      + {"filereadable", 1, 1, f_filereadable, NULL},
      + {"filewritable", 1, 1, f_filewritable, NULL},
      + {"filter", 2, 2, f_filter, NULL},
      + {"finddir", 1, 3, f_finddir, NULL},
      + {"findfile", 1, 3, f_findfile, NULL},
      +#ifdef FEAT_FLOAT
      + {"float2nr", 1, 1, f_float2nr, NULL},
      + {"floor", 1, 1, f_floor, NULL},
      + {"fmod", 2, 2, f_fmod, NULL},
      +#endif
      + {"fnameescape", 1, 1, f_fnameescape, NULL},
      + {"fnamemodify", 2, 2, f_fnamemodify, NULL},
      + {"foldclosed", 1, 1, f_foldclosed, NULL},
      + {"foldclosedend", 1, 1, f_foldclosedend, NULL},
      + {"foldlevel", 1, 1, f_foldlevel, NULL},
      + {"foldtext", 0, 0, f_foldtext, NULL},
      + {"foldtextresult", 1, 1, f_foldtextresult, NULL},
      + {"foreground", 0, 0, f_foreground, NULL},
      + {"function", 1, 1, f_function, NULL},
      + {"functype", 1, 1, f_functype, NULL},
      + {"garbagecollect", 0, 1, f_garbagecollect, NULL},
      + {"get", 2, 3, f_get, NULL},
      + {"getbufline", 2, 3, f_getbufline, NULL},
      + {"getbufvar", 2, 3, f_getbufvar, NULL},
      + {"getchar", 0, 1, f_getchar, NULL},
      + {"getcharmod", 0, 0, f_getcharmod, NULL},
      + {"getcmdline", 0, 0, f_getcmdline, NULL},
      + {"getcmdpos", 0, 0, f_getcmdpos, NULL},
      + {"getcmdtype", 0, 0, f_getcmdtype, NULL},
      + {"getcwd", 0, 0, f_getcwd, NULL},
      + {"getfontname", 0, 1, f_getfontname, NULL},
      + {"getfperm", 1, 1, f_getfperm, NULL},
      + {"getfsize", 1, 1, f_getfsize, NULL},
      + {"getftime", 1, 1, f_getftime, NULL},
      + {"getftype", 1, 1, f_getftype, NULL},
      + {"getline", 1, 2, f_getline, NULL},
      + {"getloclist", 1, 1, f_getqflist, NULL},
      + {"getmatches", 0, 0, f_getmatches, NULL},
      + {"getpid", 0, 0, f_getpid, NULL},
      + {"getpos", 1, 1, f_getpos, NULL},
      + {"getqflist", 0, 0, f_getqflist, NULL},
      + {"getreg", 0, 2, f_getreg, NULL},
      + {"getregtype", 0, 1, f_getregtype, NULL},
      + {"gettabvar", 2, 3, f_gettabvar, NULL},
      + {"gettabwinvar", 3, 4, f_gettabwinvar, NULL},
      + {"getwinposx", 0, 0, f_getwinposx, NULL},
      + {"getwinposy", 0, 0, f_getwinposy, NULL},
      + {"getwinvar", 2, 3, f_getwinvar, NULL},
      + {"glob", 1, 3, f_glob, NULL},
      + {"globpath", 2, 3, f_globpath, NULL},
      + {"has", 1, 1, f_has, NULL},
      + {"has_key", 2, 2, f_has_key, NULL},
      + {"haslocaldir", 0, 0, f_haslocaldir, NULL},
      + {"hasmapto", 1, 3, f_hasmapto, NULL},
      + {"highlightID", 1, 1, f_hlID, NULL}, /* obsolete */
      + {"highlight_exists",1, 1, f_hlexists, NULL}, /* obsolete */
      + {"histadd", 2, 2, f_histadd, NULL},
      + {"histdel", 1, 2, f_histdel, NULL},
      + {"histget", 1, 2, f_histget, NULL},
      + {"histnr", 1, 1, f_histnr, NULL},
      + {"hlID", 1, 1, f_hlID, NULL},
      + {"hlexists", 1, 1, f_hlexists, NULL},
      + {"hostname", 0, 0, f_hostname, NULL},
      + {"iconv", 3, 3, f_iconv, NULL},
      + {"indent", 1, 1, f_indent, NULL},
      + {"index", 2, 4, f_index, NULL},
      + {"input", 1, 3, f_input, NULL},
      + {"inputdialog", 1, 3, f_inputdialog, NULL},
      + {"inputlist", 1, 1, f_inputlist, NULL},
      + {"inputrestore", 0, 0, f_inputrestore, NULL},
      + {"inputsave", 0, 0, f_inputsave, NULL},
      + {"inputsecret", 1, 2, f_inputsecret, NULL},
      + {"insert", 2, 3, f_insert, NULL},
      + {"invert", 1, 1, f_invert, NULL},
      + {"isdirectory", 1, 1, f_isdirectory, NULL},
      + {"islocked", 1, 1, f_islocked, NULL},
      + {"items", 1, 1, f_items, NULL},
      + {"join", 1, 2, f_join, NULL},
      + {"keys", 1, 1, f_keys, NULL},
      + {"last_buffer_nr", 0, 0, f_last_buffer_nr, NULL},/* obsolete */
      + {"len", 1, 1, f_len, NULL},
      + {"libcall", 3, 3, f_libcall, NULL},
      + {"libcallnr", 3, 3, f_libcallnr, NULL},
      + {"line", 1, 1, f_line, NULL},
      + {"line2byte", 1, 1, f_line2byte, NULL},
      + {"lispindent", 1, 1, f_lispindent, NULL},
      + {"localtime", 0, 0, f_localtime, NULL},
      +#ifdef FEAT_FLOAT
      + {"log", 1, 1, f_log, NULL},
      + {"log10", 1, 1, f_log10, NULL},
      #endif
      #ifdef FEAT_LUA
      - {"luaeval", 1, 2, f_luaeval},
      -#endif
      - {"map", 2, 2, f_map},
      - {"maparg", 1, 4, f_maparg},
      - {"mapcheck", 1, 3, f_mapcheck},
      - {"match", 2, 4, f_match},
      - {"matchadd", 2, 4, f_matchadd},
      - {"matcharg", 1, 1, f_matcharg},
      - {"matchdelete", 1, 1, f_matchdelete},
      - {"matchend", 2, 4, f_matchend},
      - {"matchlist", 2, 4, f_matchlist},
      - {"matchstr", 2, 4, f_matchstr},
      - {"max", 1, 1, f_max},
      - {"min", 1, 1, f_min},
      + {"luaeval", 1, 2, f_luaeval, NULL},
      +#endif
      + {"map", 2, 2, f_map, NULL},
      + {"maparg", 1, 4, f_maparg, NULL},
      + {"mapcheck", 1, 3, f_mapcheck, NULL},
      + {"match", 2, 4, f_match, NULL},
      + {"matchadd", 2, 4, f_matchadd, NULL},
      + {"matcharg", 1, 1, f_matcharg, NULL},
      + {"matchdelete", 1, 1, f_matchdelete, NULL},
      + {"matchend", 2, 4, f_matchend, NULL},
      + {"matchlist", 2, 4, f_matchlist, NULL},
      + {"matchstr", 2, 4, f_matchstr, NULL},
      + {"max", 1, 1, f_max, NULL},
      + {"min", 1, 1, f_min, NULL},
      #ifdef vim_mkdir
      - {"mkdir", 1, 3, f_mkdir},
      -#endif
      - {"mode", 0, 1, f_mode},
      + {"mkdir", 1, 3, f_mkdir, NULL},
      +#endif
      + {"mode", 0, 1, f_mode, NULL},
      #ifdef FEAT_MZSCHEME
      - {"mzeval", 1, 1, f_mzeval},
      -#endif
      - {"nextnonblank", 1, 1, f_nextnonblank},
      - {"nr2char", 1, 2, f_nr2char},
      - {"or", 2, 2, f_or},
      - {"pathshorten", 1, 1, f_pathshorten},
      -#ifdef FEAT_FLOAT
      - {"pow", 2, 2, f_pow},
      -#endif
      - {"prevnonblank", 1, 1, f_prevnonblank},
      - {"printf", 2, 19, f_printf},
      - {"pumvisible", 0, 0, f_pumvisible},
      + {"mzeval", 1, 1, f_mzeval, NULL},
      +#endif
      + {"nextnonblank", 1, 1, f_nextnonblank, NULL},
      + {"nr2char", 1, 2, f_nr2char, NULL},
      + {"or", 2, 2, f_or, NULL},
      + {"pathshorten", 1, 1, f_pathshorten, NULL},
      +#ifdef FEAT_FLOAT
      + {"pow", 2, 2, f_pow, NULL},
      +#endif
      + {"prevnonblank", 1, 1, f_prevnonblank, NULL},
      + {"printf", 2, 19, f_printf, NULL},
      + {"pumvisible", 0, 0, f_pumvisible, NULL},
      #ifdef FEAT_PYTHON3
      - {"py3eval", 1, 1, f_py3eval},
      + {"py3eval", 1, 1, f_py3eval, NULL},
      #endif
      #ifdef FEAT_PYTHON
      - {"pyeval", 1, 1, f_pyeval},
      -#endif
      - {"range", 1, 3, f_range},
      - {"readfile", 1, 3, f_readfile},
      - {"reltime", 0, 2, f_reltime},
      - {"reltimestr", 1, 1, f_reltimestr},
      - {"remote_expr", 2, 3, f_remote_expr},
      - {"remote_foreground", 1, 1, f_remote_foreground},
      - {"remote_peek", 1, 2, f_remote_peek},
      - {"remote_read", 1, 1, f_remote_read},
      - {"remote_send", 2, 3, f_remote_send},
      - {"remove", 2, 3, f_remove},
      - {"rename", 2, 2, f_rename},
      - {"repeat", 2, 2, f_repeat},
      - {"resolve", 1, 1, f_resolve},
      - {"reverse", 1, 1, f_reverse},
      -#ifdef FEAT_FLOAT
      - {"round", 1, 1, f_round},
      -#endif
      - {"screenattr", 2, 2, f_screenattr},
      - {"screenchar", 2, 2, f_screenchar},
      - {"screencol", 0, 0, f_screencol},
      - {"screenrow", 0, 0, f_screenrow},
      - {"search", 1, 4, f_search},
      - {"searchdecl", 1, 3, f_searchdecl},
      - {"searchpair", 3, 7, f_searchpair},
      - {"searchpairpos", 3, 7, f_searchpairpos},
      - {"searchpos", 1, 4, f_searchpos},
      - {"server2client", 2, 2, f_server2client},
      - {"serverlist", 0, 0, f_serverlist},
      - {"setbufvar", 3, 3, f_setbufvar},
      - {"setcmdpos", 1, 1, f_setcmdpos},
      - {"setline", 2, 2, f_setline},
      - {"setloclist", 2, 3, f_setloclist},
      - {"setmatches", 1, 1, f_setmatches},
      - {"setpos", 2, 2, f_setpos},
      - {"setqflist", 1, 2, f_setqflist},
      - {"setreg", 2, 3, f_setreg},
      - {"settabvar", 3, 3, f_settabvar},
      - {"settabwinvar", 4, 4, f_settabwinvar},
      - {"setwinvar", 3, 3, f_setwinvar},
      + {"pyeval", 1, 1, f_pyeval, NULL},
      +#endif
      + {"range", 1, 3, f_range, NULL},
      + {"readfile", 1, 3, f_readfile, NULL},
      + {"reltime", 0, 2, f_reltime, NULL},
      + {"reltimestr", 1, 1, f_reltimestr, NULL},
      + {"remote_expr", 2, 3, f_remote_expr, NULL},
      + {"remote_foreground", 1, 1, f_remote_foreground, NULL},
      + {"remote_peek", 1, 2, f_remote_peek, NULL},
      + {"remote_read", 1, 1, f_remote_read, NULL},
      + {"remote_send", 2, 3, f_remote_send, NULL},
      + {"remove", 2, 3, f_remove, NULL},
      + {"rename", 2, 2, f_rename, NULL},
      + {"repeat", 2, 2, f_repeat, NULL},
      + {"resolve", 1, 1, f_resolve, NULL},
      + {"reverse", 1, 1, f_reverse, NULL},
      +#ifdef FEAT_FLOAT
      + {"round", 1, 1, f_round, NULL},
      +#endif
      + {"screenattr", 2, 2, f_screenattr, NULL},
      + {"screenchar", 2, 2, f_screenchar, NULL},
      + {"screencol", 0, 0, f_screencol, NULL},
      + {"screenrow", 0, 0, f_screenrow, NULL},
      + {"search", 1, 4, f_search, NULL},
      + {"searchdecl", 1, 3, f_searchdecl, NULL},
      + {"searchpair", 3, 7, f_searchpair, NULL},
      + {"searchpairpos", 3, 7, f_searchpairpos, NULL},
      + {"searchpos", 1, 4, f_searchpos, NULL},
      + {"server2client", 2, 2, f_server2client, NULL},
      + {"serverlist", 0, 0, f_serverlist, NULL},
      + {"setbufvar", 3, 3, f_setbufvar, NULL},
      + {"setcmdpos", 1, 1, f_setcmdpos, NULL},
      + {"setline", 2, 2, f_setline, NULL},
      + {"setloclist", 2, 3, f_setloclist, NULL},
      + {"setmatches", 1, 1, f_setmatches, NULL},
      + {"setpos", 2, 2, f_setpos, NULL},
      + {"setqflist", 1, 2, f_setqflist, NULL},
      + {"setreg", 2, 3, f_setreg, NULL},
      + {"settabvar", 3, 3, f_settabvar, NULL},
      + {"settabwinvar", 4, 4, f_settabwinvar, NULL},
      + {"setwinvar", 3, 3, f_setwinvar, NULL},
      #ifdef FEAT_CRYPT
      - {"sha256", 1, 1, f_sha256},
      -#endif
      - {"shellescape", 1, 2, f_shellescape},
      - {"shiftwidth", 0, 0, f_shiftwidth},
      - {"simplify", 1, 1, f_simplify},
      -#ifdef FEAT_FLOAT
      - {"sin", 1, 1, f_sin},
      - {"sinh", 1, 1, f_sinh},
      -#endif
      - {"sort", 1, 3, f_sort},
      - {"soundfold", 1, 1, f_soundfold},
      - {"spellbadword", 0, 1, f_spellbadword},
      - {"spellsuggest", 1, 3, f_spellsuggest},
      - {"split", 1, 3, f_split},
      -#ifdef FEAT_FLOAT
      - {"sqrt", 1, 1, f_sqrt},
      - {"str2float", 1, 1, f_str2float},
      -#endif
      - {"str2nr", 1, 2, f_str2nr},
      - {"strchars", 1, 1, f_strchars},
      - {"strdisplaywidth", 1, 2, f_strdisplaywidth},
      + {"sha256", 1, 1, f_sha256, NULL},
      +#endif
      + {"shellescape", 1, 2, f_shellescape, NULL},
      + {"shiftwidth", 0, 0, f_shiftwidth, NULL},
      + {"simplify", 1, 1, f_simplify, NULL},
      +#ifdef FEAT_FLOAT
      + {"sin", 1, 1, f_sin, NULL},
      + {"sinh", 1, 1, f_sinh, NULL},
      +#endif
      + {"sort", 1, 3, f_sort, NULL},
      + {"soundfold", 1, 1, f_soundfold, NULL},
      + {"spellbadword", 0, 1, f_spellbadword, NULL},
      + {"spellsuggest", 1, 3, f_spellsuggest, NULL},
      + {"split", 1, 3, f_split, NULL},
      +#ifdef FEAT_FLOAT
      + {"sqrt", 1, 1, f_sqrt, NULL},
      + {"str2float", 1, 1, f_str2float, NULL},
      +#endif
      + {"str2nr", 1, 2, f_str2nr, NULL},
      + {"strchars", 1, 1, f_strchars, NULL},
      + {"strdisplaywidth", 1, 2, f_strdisplaywidth, NULL},
      #ifdef HAVE_STRFTIME
      - {"strftime", 1, 2, f_strftime},
      -#endif
      - {"stridx", 2, 3, f_stridx},
      - {"string", 1, 1, f_string},
      - {"strlen", 1, 1, f_strlen},
      - {"strpart", 2, 3, f_strpart},
      - {"strridx", 2, 3, f_strridx},
      - {"strtrans", 1, 1, f_strtrans},
      - {"strwidth", 1, 1, f_strwidth},
      - {"submatch", 1, 1, f_submatch},
      - {"substitute", 4, 4, f_substitute},
      - {"synID", 3, 3, f_synID},
      - {"synIDattr", 2, 3, f_synIDattr},
      - {"synIDtrans", 1, 1, f_synIDtrans},
      - {"synconcealed", 2, 2, f_synconcealed},
      - {"synstack", 2, 2, f_synstack},
      - {"system", 1, 2, f_system},
      - {"tabpagebuflist", 0, 1, f_tabpagebuflist},
      - {"tabpagenr", 0, 1, f_tabpagenr},
      - {"tabpagewinnr", 1, 2, f_tabpagewinnr},
      - {"tagfiles", 0, 0, f_tagfiles},
      - {"taglist", 1, 1, f_taglist},
      -#ifdef FEAT_FLOAT
      - {"tan", 1, 1, f_tan},
      - {"tanh", 1, 1, f_tanh},
      -#endif
      - {"tempname", 0, 0, f_tempname},
      - {"test", 1, 1, f_test},
      - {"tolower", 1, 1, f_tolower},
      - {"toupper", 1, 1, f_toupper},
      - {"tr", 3, 3, f_tr},
      -#ifdef FEAT_FLOAT
      - {"trunc", 1, 1, f_trunc},
      -#endif
      - {"type", 1, 1, f_type},
      - {"undofile", 1, 1, f_undofile},
      - {"undotree", 0, 0, f_undotree},
      - {"values", 1, 1, f_values},
      - {"virtcol", 1, 1, f_virtcol},
      - {"visualmode", 0, 1, f_visualmode},
      - {"wildmenumode", 0, 0, f_wildmenumode},
      - {"winbufnr", 1, 1, f_winbufnr},
      - {"wincol", 0, 0, f_wincol},
      - {"winheight", 1, 1, f_winheight},
      - {"winline", 0, 0, f_winline},
      - {"winnr", 0, 1, f_winnr},
      - {"winrestcmd", 0, 0, f_winrestcmd},
      - {"winrestview", 1, 1, f_winrestview},
      - {"winsaveview", 0, 0, f_winsaveview},
      - {"winwidth", 1, 1, f_winwidth},
      - {"writefile", 2, 3, f_writefile},
      - {"xor", 2, 2, f_xor},
      + {"strftime", 1, 2, f_strftime, NULL},
      +#endif
      + {"stridx", 2, 3, f_stridx, NULL},
      + {"string", 1, 1, f_string, NULL},
      + {"strlen", 1, 1, f_strlen, NULL},
      + {"strpart", 2, 3, f_strpart, NULL},
      + {"strridx", 2, 3, f_strridx, NULL},
      + {"strtrans", 1, 1, f_strtrans, NULL},
      + {"strwidth", 1, 1, f_strwidth, NULL},
      + {"submatch", 1, 1, f_submatch, NULL},
      + {"substitute", 4, 4, f_substitute, NULL},
      + {"synID", 3, 3, f_synID, NULL},
      + {"synIDattr", 2, 3, f_synIDattr, NULL},
      + {"synIDtrans", 1, 1, f_synIDtrans, NULL},
      + {"synconcealed", 2, 2, f_synconcealed, NULL},
      + {"synstack", 2, 2, f_synstack, NULL},
      + {"system", 1, 2, f_system, NULL},
      + {"tabpagebuflist", 0, 1, f_tabpagebuflist, NULL},
      + {"tabpagenr", 0, 1, f_tabpagenr, NULL},
      + {"tabpagewinnr", 1, 2, f_tabpagewinnr, NULL},
      + {"tagfiles", 0, 0, f_tagfiles, NULL},
      + {"taglist", 1, 1, f_taglist, NULL},
      +#ifdef FEAT_FLOAT
      + {"tan", 1, 1, f_tan, NULL},
      + {"tanh", 1, 1, f_tanh, NULL},
      +#endif
      + {"tempname", 0, 0, f_tempname, NULL},
      + {"test", 1, 1, f_test, NULL},
      + {"tolower", 1, 1, f_tolower, NULL},
      + {"toupper", 1, 1, f_toupper, NULL},
      + {"tr", 3, 3, f_tr, NULL},
      +#ifdef FEAT_FLOAT
      + {"trunc", 1, 1, f_trunc, NULL},
      +#endif
      + {"type", 1, 1, f_type, NULL},
      + {"undofile", 1, 1, f_undofile, NULL},
      + {"undotree", 0, 0, f_undotree, NULL},
      + {"values", 1, 1, f_values, NULL},
      + {"virtcol", 1, 1, f_virtcol, NULL},
      + {"visualmode", 0, 1, f_visualmode, NULL},
      + {"wildmenumode", 0, 0, f_wildmenumode, NULL},
      + {"winbufnr", 1, 1, f_winbufnr, NULL},
      + {"wincol", 0, 0, f_wincol, NULL},
      + {"winheight", 1, 1, f_winheight, NULL},
      + {"winline", 0, 0, f_winline, NULL},
      + {"winnr", 0, 1, f_winnr, NULL},
      + {"winrestcmd", 0, 0, f_winrestcmd, NULL},
      + {"winrestview", 1, 1, f_winrestview, NULL},
      + {"winsaveview", 0, 0, f_winsaveview, NULL},
      + {"winwidth", 1, 1, f_winwidth, NULL},
      + {"writefile", 2, 3, f_writefile, NULL},
      + {"xor", 2, 2, f_xor, NULL},
      };

      #if defined(FEAT_CMDL_COMPL) || defined(PROTO)
      @@ -8242,9 +8327,9 @@

      /*
      * Find internal function in table above.
      - * Return index, or -1 if not found
      - */
      - static int
      + * Return pointer, or NULL if not found
      + */
      + static struct fst *
      find_internal_func(name)
      char_u *name; /* name of the function */
      {
      @@ -8265,39 +8350,170 @@
      else if (cmp > 0)
      first = x + 1;
      else
      - return x;
      - }
      - return -1;
      + return &functions[x];
      + }
      + return NULL;
      }

      /*
      * Check if "name" is a variable of type VAR_FUNC. If so, return the function
      - * name it contains, otherwise return "name".
      - */
      - static char_u *
      -deref_func_name(name, lenp)
      + * definition it contains, otherwise try to find internal or user-defined
      + * function with the given name. Returns NULL on failure.
      + *
      + * Flags:
      + * DF_CHECK_VAR : Try loading function from a variable.
      + * DF_RUN_EVENT : Run FuncUndefined event if function was not found
      + * DF_CREATE_AUTOLOAD: Create references to autoload function
      + * DF_NO_VAR : DF_RUN_EVENT and DF_CREATE_AUTOLOAD
      + * DF_ALL : All of the above
      + */
      + func_T *
      +deref_func_name(name, len, flags)
      char_u *name;
      - int *lenp;
      + const int len;
      + int flags;
      {
      dictitem_T *v;
      int cc;
      -
      - cc = name[*lenp];
      - name[*lenp] = NUL;
      - v = find_var(name, NULL);
      - name[*lenp] = cc;
      - if (v != NULL && v->di_tv.v_type == VAR_FUNC)
      - {
      - if (v->di_tv.vval.v_string == NULL)
      - {
      - *lenp = 0;
      - return (char_u *)""; /* just in case */
      - }
      - *lenp = (int)STRLEN(v->di_tv.vval.v_string);
      - return v->di_tv.vval.v_string;
      - }
      -
      - return name;
      + func_T *r = NULL;
      +
      + cc = name[len];
      + if (flags & DF_CHECK_VAR)
      + {
      + name[len] = NUL;
      + v = find_var(name, NULL, FALSE);
      + name[len] = cc;
      +
      + if (v != NULL && v->di_tv.v_type == VAR_FUNC)
      + {
      + if (v->di_tv.vval.v_func == NULL)
      + return NULL;
      + ++v->di_tv.vval.v_func->fv_refcount;
      + return v->di_tv.vval.v_func;
      + }
      + }
      +
      + name[len] = NUL;
      + if (builtin_function(name))
      + {
      + struct fst *intfp;
      + intfp = find_internal_func(name);
      +
      + if (intfp != NULL)
      + {
      + if (intfp->f_func == NULL)
      + {
      + intfp->f_func = func_alloc();
      + if (intfp->f_func != NULL)
      + {
      + ++intfp->f_func->fv_refcount;
      + intfp->f_func->fv_data = intfp;
      + intfp->f_func->fv_type = &internal_func_type;
      + }
      + }
      +
      + r = intfp->f_func;
      + }
      + }
      + else
      + {
      + char_u *fname = NULL;
      + char_u *pp;
      + char_u sid_buf[20];
      + int lead;
      + int old_len;
      + int new_len = len;
      + ufunc_T *fp;
      +
      + lead = eval_fname_script(name);
      + new_len -= lead;
      + old_len = new_len;
      + pp = name + lead;
      +
      + if (lead)
      + {
      + lead = 3;
      + if (eval_fname_sid(name))
      + {
      + if (current_SID <= 0)
      + {
      + EMSG(_(e_usingsid));
      + new_len = 0;
      + }
      + else
      + {
      + sprintf((char *) sid_buf, "%ld_", (long) current_SID);
      + lead += STRLEN(sid_buf);
      + }
      + }
      + else
      + *sid_buf = NUL;
      +
      + if (new_len)
      + fname = (char_u *) alloc(new_len + lead + 1);
      + }
      + else
      + {
      + *sid_buf = NUL;
      + fname = name;
      + }
      +
      + if (fname != NULL)
      + {
      + if (lead)
      + {
      + fname[0] = K_SPECIAL;
      + fname[1] = KS_EXTRA;
      + fname[2] = (int) KE_SNR;
      +
      + if (*sid_buf != NUL)
      + mch_memmove(fname + 3, sid_buf, lead - 3);
      +
      + mch_memmove(fname + lead, pp, (size_t) old_len + 1);
      + }
      + fp = find_func(fname);
      +
      +#ifdef FEAT_AUTOCMD
      + /* Trigger FuncUndefined event, may load the function. */
      + if (flags & DF_RUN_EVENT
      + && fp == NULL
      + && apply_autocmds(EVENT_FUNCUNDEFINED,
      + fname, fname, TRUE, NULL)
      + && !aborting())
      + /* executed an autocommand, search for the function again */
      + fp = find_func(name);
      +#endif
      +
      + if (fp == NULL)
      + {
      + if (flags & DF_CREATE_AUTOLOAD
      + && vim_strchr(fname, AUTOLOAD_CHAR) != NULL
      + && valid_autoload_name(fname))
      + {
      + aufunc_T *aufp;
      +
      + if ((aufp = aufunc_alloc()) != NULL &&
      + (r = func_alloc()) != NULL)
      + {
      + aufp->auf_name = vim_strsave(fname);
      + r->fv_data = (void *) aufp;
      + r->fv_type = &autoload_func_type;
      + }
      + }
      + }
      + else
      + r = fp->uf_func;
      +
      + if (lead)
      + vim_free(fname);
      + }
      + }
      + name[len] = cc;
      +
      + if (r != NULL)
      + ++r->fv_refcount;
      +
      + return r;
      }

      /*
      @@ -8305,10 +8521,9 @@
      * Return OK or FAIL.
      */
      static int
      -get_func_tv(name, len, rettv, arg, firstline, lastline, doesrange,
      +get_func_tv(func, rettv, arg, firstline, lastline, doesrange,
      evaluate, selfdict)
      - char_u *name; /* name of the function */
      - int len; /* length of "name" */
      + func_T *func; /* function definition */
      typval_T *rettv;
      char_u **arg; /* argument, pointing to the '(' */
      linenr_T firstline; /* first line of range */
      @@ -8345,15 +8560,20 @@
      else
      ret = FAIL;

      - if (ret == OK)
      - ret = call_func(name, len, rettv, argcount, argvars,
      - firstline, lastline, doesrange, evaluate, selfdict);
      - else if (!aborting())
      - {
      - if (argcount == MAX_FUNC_ARGS)
      - emsg_funcname(N_("E740: Too many arguments for function %s"), name);
      - else
      - emsg_funcname(N_("E116: Invalid arguments for function %s"), name);
      + if (evaluate)
      + {
      + if (ret == OK)
      + ret = call_func(func, rettv, argcount, argvars,
      + firstline, lastline, doesrange, selfdict);
      + else if (!aborting())
      + {
      + if (argcount == MAX_FUNC_ARGS)
      + emsg_funcname(N_("E740: Too many arguments for function %s"),
      + FUNC_NAME(func));
      + else
      + emsg_funcname(N_("E116: Invalid arguments for function %s"),
      + FUNC_NAME(func));
      + }
      }

      while (--argcount >= 0)
      @@ -8363,17 +8583,86 @@
      return ret;
      }

      -
      -/*
      - * Call a function with its resolved parameters
      - * Return FAIL when the function can't be called, OK otherwise.
      - * Also returns OK when an error was encountered while executing the function.
      - */
      - static int
      -call_func(funcname, len, rettv, argcount, argvars, firstline, lastline,
      - doesrange, evaluate, selfdict)
      - char_u *funcname; /* name of the function */
      - int len; /* length of "name" */
      + static int
      +call_internal_func(intfp, rettv, argcount, argvars, firstline, lastline, doesrange, selfdict)
      + struct fst *intfp; /* pointer to function */
      + typval_T *rettv; /* return value */
      + int argcount; /* nr of args */
      + typval_T *argvars; /* arguments */
      + linenr_T firstline; /* first line of range */
      + linenr_T lastline; /* last line of range */
      + int *doesrange; /* is set to True if function handles range */
      + dict_T *selfdict; /* Dictionary for "self" */
      +{
      + if (argcount < intfp->f_min_argc)
      + return ERROR_TOOFEW;
      + else if (argcount > intfp->f_max_argc)
      + return ERROR_TOOMANY;
      +
      + argvars[argcount].v_type = VAR_UNKNOWN;
      + intfp->f_call(argvars, rettv);
      +
      + return ERROR_NONE;
      +}
      +
      + static char_u *
      +repr_internal_func(intfp)
      + struct fst *intfp;
      +{
      + return string_quote((char_u *) intfp->f_name, "function");
      +}
      +
      + static void
      +dealloc_internal_func(intfp)
      + struct fst *intfp;
      +{
      + intfp->f_func = NULL;
      + return;
      +}
      +
      + static int
      +compare_internal_funcs(intfp1, intfp2)
      + struct fst *intfp1;
      + struct fst *intfp2;
      +{
      + return intfp1 == intfp2;
      +}
      +
      + static char_u *
      +name_internal_func(intfp)
      + struct fst *intfp;
      +{
      + return (char_u *) intfp->f_name;
      +}
      +
      +static char_u *internal_func_type_name = (char_u *) "internal";
      +#define INTERNAL_FUNC_TYPE_LEN 8
      +
      + static char_u *
      +type_internal_func(intfp)
      + struct fst *intfp UNUSED;
      +{
      + return vim_strnsave(internal_func_type_name, INTERNAL_FUNC_TYPE_LEN);
      +}
      +
      +static funcdef_T internal_func_type = {
      + (function_caller) call_internal_func, /* fd_call */
      + (function_representer) repr_internal_func, /* fd_repr */
      + (function_destructor) dealloc_internal_func, /* fd_dealloc */
      + (function_cmp) compare_internal_funcs, /* fd_compare */
      + (function_representer) name_internal_func, /* fd_name */
      + (function_representer) type_internal_func, /* fd_type */
      +};
      +
      + static aufunc_T *
      +aufunc_alloc()
      +{
      + return (aufunc_T *) alloc_clear(sizeof(aufunc_T));
      +}
      +
      + static int
      +call_autoload_func(aufp, rettv, argcount, argvars, firstline, lastline, doesrange, selfdict)
      + aufunc_T *aufp;
      typval_T *rettv; /* return value goes here */
      int argcount; /* number of "argvars" */
      typval_T *argvars; /* vars for arguments, must have "argcount"
      @@ -8381,212 +8670,177 @@
      linenr_T firstline; /* first line of range */
      linenr_T lastline; /* last line of range */
      int *doesrange; /* return: function handled range */
      - int evaluate;
      dict_T *selfdict; /* Dictionary for "self" */
      {
      - int ret = FAIL;
      -#define ERROR_UNKNOWN 0
      -#define ERROR_TOOMANY 1
      -#define ERROR_TOOFEW 2
      -#define ERROR_SCRIPT 3
      -#define ERROR_DICT 4
      -#define ERROR_NONE 5
      -#define ERROR_OTHER 6
      - int error = ERROR_NONE;
      - int i;
      - int llen;
      - ufunc_T *fp;
      -#define FLEN_FIXED 40
      - char_u fname_buf[FLEN_FIXED + 1];
      - char_u *fname;
      - char_u *name;
      -
      - /* Make a copy of the name, if it comes from a funcref variable it could
      - * be changed or deleted in the called function. */
      - name = vim_strnsave(funcname, len);
      - if (name == NULL)
      - return ret;
      -
      - /*
      - * In a script change <SID>name() and s:name() to K_SNR 123_name().
      - * Change <SNR>123_name() to K_SNR 123_name().
      - * Use fname_buf[] when it fits, otherwise allocate memory (slow).
      - */
      - llen = eval_fname_script(name);
      - if (llen > 0)
      - {
      - fname_buf[0] = K_SPECIAL;
      - fname_buf[1] = KS_EXTRA;
      - fname_buf[2] = (int)KE_SNR;
      - i = 3;
      - if (eval_fname_sid(name)) /* "<SID>" or "s:" */
      - {
      - if (current_SID <= 0)
      - error = ERROR_SCRIPT;
      - else
      - {
      - sprintf((char *)fname_buf + 3, "%ld_", (long)current_SID);
      - i = (int)STRLEN(fname_buf);
      - }
      - }
      - if (i + STRLEN(name + llen) < FLEN_FIXED)
      - {
      - STRCPY(fname_buf + i, name + llen);
      - fname = fname_buf;
      - }
      - else
      - {
      - fname = alloc((unsigned)(i + STRLEN(name + llen) + 1));
      - if (fname == NULL)
      - error = ERROR_OTHER;
      - else
      - {
      - mch_memmove(fname, fname_buf, (size_t)i);
      - STRCPY(fname + i, name + llen);
      - }
      - }
      - }
      - else
      - fname = name;
      + /* First, check whether function was already loaded. */
      + if (aufp->auf_func == NULL && !aborting())
      + aufp->auf_func = deref_func_name(aufp->auf_name,
      + STRLEN(aufp->auf_name),
      + DF_CHECK_VAR|DF_RUN_EVENT);
      +
      + /* If not then try loading a package. */
      + if (aufp->auf_func == NULL && script_autoload(aufp->auf_name, TRUE) &&
      + !aborting())
      + /* loaded a package, search for the function again */
      + /* Note: it is allowed for loaded function to be defined in a variable
      + */
      + aufp->auf_func = deref_func_name(aufp->auf_name,
      + STRLEN(aufp->auf_name),
      + DF_CHECK_VAR);
      +
      + if (aufp->auf_func == NULL)
      + {
      + EMSG2(_(e_unknown_function), aufp->auf_name);
      + return ERROR_OTHER;
      + }
      +
      + return FUNC_CALL(aufp->auf_func, rettv, argcount, argvars,
      + firstline, lastline, doesrange, selfdict);
      +}
      +
      + static char_u *
      +repr_autoload_func(aufp)
      + aufunc_T *aufp;
      +{
      + return string_quote(aufp->auf_name, "function");
      +}
      +
      + static void
      +dealloc_autoload_func(aufp)
      + aufunc_T *aufp;
      +{
      + if (aufp->auf_func != NULL)
      + func_unref(aufp->auf_func);
      + vim_free(aufp->auf_name);
      + vim_free(aufp);
      +}
      +
      + static int
      +compare_autoload_funcs(aufp1, aufp2)
      + aufunc_T *aufp1;
      + aufunc_T *aufp2;
      +{
      + return STRCMP(aufp1->auf_name, aufp2->auf_name) == 0;
      +}
      +
      + static char_u *
      +name_autoload_func(aufp)
      + aufunc_T *aufp;
      +{
      + return aufp->auf_name;
      +}
      +
      +static char_u *autoload_func_type_name = (char_u *) "autoload";
      +#define AUTOLOAD_FUNC_TYPE_LEN 8
      +
      + static char_u *
      +type_autoload_func(aufp)
      + aufunc_T *aufp;
      +{
      + if (aufp->auf_func == NULL)
      + return vim_strnsave(autoload_func_type_name, AUTOLOAD_FUNC_TYPE_LEN);
      + else
      + {
      + char_u *loaded_type;
      + int loaded_type_len;
      + char_u *ret_type;
      +
      + if ((loaded_type = FUNC_TYPE(aufp->auf_func)) == NULL)
      + return NULL;
      +
      + loaded_type_len = STRLEN(loaded_type);
      +
      + /* 2: colon and NUL */
      + ret_type = (char_u*)alloc(loaded_type_len + 2 + AUTOLOAD_FUNC_TYPE_LEN);
      +
      + if (ret_type == NULL)
      + return NULL;
      +
      + mch_memmove(ret_type, autoload_func_type_name,
      + (size_t) AUTOLOAD_FUNC_TYPE_LEN);
      + ret_type[AUTOLOAD_FUNC_TYPE_LEN] = ':';
      + mch_memmove(ret_type + AUTOLOAD_FUNC_TYPE_LEN + 1, loaded_type,
      + loaded_type_len);
      + ret_type[AUTOLOAD_FUNC_TYPE_LEN + loaded_type_len + 1] = NUL;
      +
      + vim_free(loaded_type);
      + return ret_type;
      + }
      +}
      +
      +static funcdef_T autoload_func_type = {
      + (function_caller) call_autoload_func, /* fd_call */
      + (function_representer) repr_autoload_func, /* fd_repr */
      + (function_destructor) dealloc_autoload_func, /* fd_dealloc */
      + (function_cmp) compare_autoload_funcs, /* fd_compare */
      + (function_representer) name_autoload_func, /* fd_name */
      + (function_representer) type_autoload_func, /* fd_type */
      +};
      +
      +/*
      + * Call a function with its resolved parameters
      + * Return FAIL when the function can't be called, OK otherwise.
      + * Also returns OK when an error was encountered while executing the function.
      + */
      + static int
      +call_func(func, rettv, argcount, argvars, firstline, lastline, doesrange, selfdict)
      + func_T *func; /* function definition */
      + typval_T *rettv; /* return value goes here */
      + int argcount; /* number of "argvars" */
      + typval_T *argvars; /* vars for arguments, must have "argcount"
      + PLUS ONE elements! */
      + linenr_T firstline; /* first line of range */
      + linenr_T lastline; /* last line of range */
      + int *doesrange; /* return: function handled range */
      + dict_T *selfdict; /* Dictionary for "self" */
      +{
      + int error;

      *doesrange = FALSE;

      -
      - /* execute the function if no errors detected and executing */
      - if (evaluate && error == ERROR_NONE)
      - {
      - rettv->v_type = VAR_NUMBER; /* default rettv is number zero */
      - rettv->vval.v_number = 0;
      - error = ERROR_UNKNOWN;
      -
      - if (!builtin_function(fname))
      - {
      - /*
      - * User defined function.
      - */
      - fp = find_func(fname);
      -
      -#ifdef FEAT_AUTOCMD
      - /* Trigger FuncUndefined event, may load the function. */
      - if (fp == NULL
      - && apply_autocmds(EVENT_FUNCUNDEFINED,
      - fname, fname, TRUE, NULL)
      - && !aborting())
      - {
      - /* executed an autocommand, search for the function again */
      - fp = find_func(fname);
      - }
      -#endif
      - /* Try loading a package. */
      - if (fp == NULL && script_autoload(fname, TRUE) && !aborting())
      - {
      - /* loaded a package, search for the function again */
      - fp = find_func(fname);
      - }
      -
      - if (fp != NULL)
      - {
      - if (fp->uf_flags & FC_RANGE)
      - *doesrange = TRUE;
      - if (argcount < fp->uf_args.ga_len)
      - error = ERROR_TOOFEW;
      - else if (!fp->uf_varargs && argcount > fp->uf_args.ga_len)
      - error = ERROR_TOOMANY;
      - else if ((fp->uf_flags & FC_DICT) && selfdict == NULL)
      - error = ERROR_DICT;
      - else
      - {
      - /*
      - * Call the user function.
      - * Save and restore search patterns, script variables and
      - * redo buffer.
      - */
      - save_search_patterns();
      - saveRedobuff();
      - ++fp->uf_calls;
      - call_user_func(fp, argcount, argvars, rettv,
      - firstline, lastline,
      - (fp->uf_flags & FC_DICT) ? selfdict : NULL);
      - if (--fp->uf_calls <= 0 && isdigit(*fp->uf_name)
      - && fp->uf_refcount <= 0)
      - /* Function was unreferenced while being used, free it
      - * now. */
      - func_free(fp);
      - restoreRedobuff();
      - restore_search_patterns();
      - error = ERROR_NONE;
      - }
      - }
      - }
      - else
      - {
      - /*
      - * Find the function name in the table, call its implementation.
      - */
      - i = find_internal_func(fname);
      - if (i >= 0)
      - {
      - if (argcount < functions[i].f_min_argc)
      - error = ERROR_TOOFEW;
      - else if (argcount > functions[i].f_max_argc)
      - error = ERROR_TOOMANY;
      - else
      - {
      - argvars[argcount].v_type = VAR_UNKNOWN;
      - functions[i].f_func(argvars, rettv);
      - error = ERROR_NONE;
      - }
      - }
      - }
      - /*
      - * The function call (or "FuncUndefined" autocommand sequence) might
      - * have been aborted by an error, an interrupt, or an explicitly thrown
      - * exception that has not been caught so far. This situation can be
      - * tested for by calling aborting(). For an error in an internal
      - * function or for the "E132" error in call_user_func(), however, the
      - * throw point at which the "force_abort" flag (temporarily reset by
      - * emsg()) is normally updated has not been reached yet. We need to
      - * update that flag first to make aborting() reliable.
      - */
      - update_force_abort();
      - }
      - if (error == ERROR_NONE)
      - ret = OK;
      -
      - /*
      - * Report an error unless the argument evaluation or function call has been
      - * cancelled due to an aborting error, an interrupt, or an exception.
      - */
      + if (func == NULL)
      + return FAIL;
      +
      + rettv->v_type = VAR_NUMBER; /* default rettv is number zero */
      + rettv->vval.v_number = 0;
      + error = func->fv_type->fd_call(func->fv_data, rettv, argcount, argvars,
      + firstline, lastline, doesrange, selfdict);
      +
      + /*
      + * The function call (or "FuncUndefined" autocommand sequence) might
      + * have been aborted by an error, an interrupt, or an explicitly thrown
      + * exception that has not been caught so far. This situation can be
      + * tested for by calling aborting(). For an error in an internal
      + * function or for the "E132" error in call_user_func(), however, the
      + * throw point at which the "force_abort" flag (temporarily reset by
      + * emsg()) is normally updated has not been reached yet. We need to
      + * update that flag first to make aborting() reliable.
      + */
      + update_force_abort();
      +
      if (!aborting())
      {
      switch (error)
      {
      - case ERROR_UNKNOWN:
      - emsg_funcname(N_("E117: Unknown function: %s"), name);
      - break;
      case ERROR_TOOMANY:
      - emsg_funcname(e_toomanyarg, name);
      + emsg_funcname(e_toomanyarg, FUNC_NAME(func));
      break;
      case ERROR_TOOFEW:
      emsg_funcname(N_("E119: Not enough arguments for function: %s"),
      - name);
      + FUNC_NAME(func));
      break;
      case ERROR_SCRIPT:
      emsg_funcname(N_("E120: Using <SID> not in a script context: %s"),
      - name);
      + FUNC_NAME(func));
      break;
      case ERROR_DICT:
      emsg_funcname(N_("E725: Calling dict function without Dictionary: %s"),
      - name);
      - break;
      - }
      - }
      -
      - if (fname != name && fname != fname_buf)
      - vim_free(fname);
      - vim_free(name);
      -
      - return ret;
      + FUNC_NAME(func));
      + break;
      + }
      + }
      +
      + return error == ERROR_NONE ? OK : FAIL;
      }

      /*
      @@ -9241,8 +9495,8 @@
      }

      int
      -func_call(name, args, selfdict, rettv)
      - char_u *name;
      +func_call(func, args, selfdict, rettv)
      + func_T *func;
      typval_T *args;
      dict_T *selfdict;
      typval_T *rettv;
      @@ -9268,9 +9522,9 @@
      }
      <br/><br/>(Message over 64 KB, truncated)
    • Show all 22 messages in this topic