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

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

Expand Messages
  • ZyX
    Fixed a crash during vim quit if there are python funcrefs left. Not the best fix though. diff -r c015eedb9b4a -r d6d331602742 runtime/doc/if_pyth.txt ... +++
    Message 1 of 22 , Jul 16, 2013
    • 0 Attachment
      Fixed a crash during vim quit if there are python funcrefs left.

      Not the best fix though.

      diff -r c015eedb9b4a -r d6d331602742 runtime/doc/if_pyth.txt
      --- a/runtime/doc/if_pyth.txt Sun Jul 14 15:06:50 2013 +0200
      +++ b/runtime/doc/if_pyth.txt Tue Jul 16 23:27:39 2013 +0400
      @@ -655,7 +655,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 c015eedb9b4a -r d6d331602742 runtime/doc/version7.txt
      --- a/runtime/doc/version7.txt Sun Jul 14 15:06:50 2013 +0200
      +++ b/runtime/doc/version7.txt Tue Jul 16 23:27:39 2013 +0400
      @@ -70,6 +70,7 @@

      VERSION 7.4 |version-7.4|
      New regexp engine |new-regexp-engine|
      +Better vim ↔ python interface |new-python-interfac|
      Changed |changed-7.4|
      Added |added-7.4|
      Fixed |fixed-7.4|
      @@ -10182,16 +10183,168 @@

      More information here: |two-engines|

      +Better vim ↔ python interface *new-python-interface*
      +-----------------------------
      +
      +Added |python-bindeval| function. Unlike |python-eval| this one returns
      + |python-Dictionary|, |python-List| and |python-Function| objects for
      + dictionaries lists and functions respectively in place of their python
      + built-in equivalents (or None if we are talking about function references).
      +For simple types this function returns python built-in types and not only
      + python `str()` like |python-eval| does. On python 3 it will return `bytes()`
      + objects in place of `str()` ones avoiding possibility of UnicodeDecodeError.
      +Interface of new objects mimics standard python `dict()` and `list()`
      + interfaces to some extent. Extent will be improved in the future.
      +
      +Added special |python-vars| objects also available for |python-buffer| and
      +|python-window|. They ease access to VimL variables from python.
      +
      +Now you no longer need to alter `sys.path` to import your module: special
      +hooks are responsible for importing from {rtp}/python2, {rtp}/python3 and
      +{rtp}/pythonx directories (for python 2, python 3 and both respectively).
      +See |python-special-path|.
      +
      +Added possibility to work with |tabpage|s through |python-tabpage| object.
      +
      +Added automatic conversion of vim errors and exceptions to python
      +exceptions.
      +
      +Changed the behavior of |python-buffers| object: it now uses buffer numbers
      +as keys in place of the index of the buffer in the internal buffer list.
      +This should not break anything as the only way to get this index was
      +iterating over |python-buffers|.
      +
      +Added |:pydo| and |:py3do| commands.
      +
      +Added |pyeval()| and |py3eval()| functions.
      +
      +Now in all places which previously accepted `str()` objects in both python
      +version both `str()` and `unicode()` (python 2) or `bytes()` and `str()`
      +(python 3) are accepted.
      +
      +|python-window| has gained `.col` and `.row` attributes that are currently
      +the only way to get internal window positions.
      +
      +Added or fixed support for `dir()` in vim python objects.
      +
      +Old python versions (≤2.2) are no longer supported. Building with them did
      +not work anyway.

      Changed *changed-7.4*
      -------

      -Todo.
      -
      +Functions:
      + Added ability to use |Dictionary-function|s for |sort()|ing, via
      + optional third argument. (Nikolay Pavlov)
      +
      + Added special |expand()| argument that expands to the current line
      + number.
      +
      + Made it possible to force |char2nr()| always give unicode codepoints
      + regardless of current encoding. (Yasuhiro Matsumoto)
      +
      + Made it possible for functions generating file list generate |List|
      + and not NL-separated string. (e.g. |glob()|, |expand()|) (Christian
      + Brabandt)
      +
      + Functions that obtain variables from the specific window, tabpage or
      + buffer scope dictionary can now return specified default value in
      + place of empty string in case variable is not found. (|gettabvar()|,
      + |getwinvar()|, |getbufvar()|) (Shougo Matsushita, Hirohito Higashi)
      +
      +Options:
      + Added ability to automatically save selection into the system
      + clipboard when using non-GUI version of vim (autoselectplus in
      + 'clipboard'). Also added ability to use system clipboard as default
      + register (previously only primary selection could be used). (Ivan
      + Krasilnikov, Christian Brabandt, Bram Moolenaar)
      +
      + Added special 'shiftwidth' value that makes 'sw' follow 'tabstop'. As
      + indenting via 'indentexpr' became tricky |shiftwidth()| function was
      + added. Also added equivalent special value to 'softtabstop' option.
      + (Christian Brabandt, so8res)
      +
      + Added ability to delete comment leader when using |J| by `j` flag in
      + 'formatoptions' (|fo-table|). (Lech Lorens)
      +
      + Added ability to control indentation inside namespaces: |cino-N|.
      + (Konstantin Lepa)
      +
      + Added ability to control alignment inside `if` condition separately
      + from alignment inside function arguments: |cino-k|. (Lech Lorens)
      +
      + Added ability to show absolute number in number column when
      + 'relativenumber' option is on. (Christian Brabandt)
      +
      +Comands:
      + Made it possible to remove all signs from the current buffer using
      + |:sign-unplace|. (Christian Brabandt)
      +
      + Added |:language| autocompletion. (Dominique Pelle)
      +
      + |:diffoff| now saves the local values of some settings and restores
      + them in place of blindly resetting them to the defaults. (Christian
      + Brabandt)
      +
      + Added |:map-nowait| creating mapping which when having lhs that is the
      + prefix of another mapping’s lhs will not allow vim to wait for user to
      + type more characters to resolve ambiguity, forcing vim to take the
      + shorter alternative: one with <nowait>.
      +
      + Added more |:command-complete| completion types: |:behave| suboptions,
      + color schemes, compilers, |:cscope| suboptions, files from 'path',
      + |:history| suboptions, locale names, |:syntime| suboptions, user
      + names. (Dominique Pelle)
      +
      +Other:
      + Improved support for cmd.exe. (Ben Fritz, Bram Moolenaar)
      +
      + Added |v:windowid| variable containing current window number in GUI
      + vim. (Christian J. Robinson, Lech Lorens)
      +
      + Lua interface now also uses userdata binded to vim structures. (Taro
      + Muraoka, Luis Carvalho)
      +
      + Added rxvt-unicode and >xterm-277 mouse support. (Yiding Jia, Hayaki
      + Saito)

      Added *added-7.4*
      -----

      +Added support for |Lists| and |Dictionaries| in |viminfo|. (Christian
      +Brabandt)
      +
      +Functions:
      + Bitwise functions: |and()|, |or()|, |invert()|, |xor()|.
      +
      + Added |luaeval()| function. (Taro Muraoka, Luis Carvalho)
      +
      + Added |sha256()| function. (Tyru, Hirohito Higashi)
      +
      + Added |wildmenumode()| function. (Christian Brabandt)
      +
      + Debugging functions: |screenattr()|, |screenchar()|, |screencol()|,
      + |screenrow()|. (Simon Ruderich, Bram Moolenaar)
      +
      +Autocommands:
      + Added |InsertCharPre| event launched before inserting character.
      + (Jakson A. Aquino)
      +
      + Added |CompleteDone| event launched after finishing completion in
      + insert mode. (idea by Florian Klein)
      +
      + Added |QuitPre| event launched when commands that can either close vim
      + or only some window(s) are launched.
      +
      + Added |TextChanged| and |TextChangedI| events launched when text is
      + changed.
      +
      +Commands:
      + |:syntime| command useful for debugging.
      +
      +Options:
      + Made it possible to ignore case when completing: 'wildignorecase'.
      +
      Various syntax, indent and other plugins were added.


      diff -r c015eedb9b4a -r d6d331602742 src/eval.c
      --- a/src/eval.c Sun Jul 14 15:06:50 2013 +0200
      +++ b/src/eval.c Tue Jul 16 23:27:39 2013 +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
      @@ -166,7 +167,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
      @@ -188,16 +188,31 @@
      #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.
      @@ -272,6 +287,9 @@
      dict_T *fd_dict; /* Dictionary used */
      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;


      @@ -438,17 +456,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));
      @@ -794,6 +811,7 @@
      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 runevent));
      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));
      @@ -818,8 +836,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));
      @@ -835,6 +854,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.
      */
      @@ -1558,10 +1582,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;
      @@ -1573,11 +1597,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), TRUE);
      + if (func == NULL)
      + {
      + vim_free(argvars);
      + return FAIL;
      + }
      +
      for (i = 0; i < argc; i++)
      {
      /* Pass a NULL or empty argument as an empty string */
      @@ -1612,9 +1644,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;
      @@ -1625,6 +1657,8 @@
      if (ret == FAIL)
      clear_tv(rettv);

      + func_unref(func);
      +
      return ret;
      }

      @@ -3382,8 +3416,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;
      @@ -3403,14 +3436,14 @@
      return;
      }

      - tofree = trans_function_name(&arg, eap->skip, TFN_INT, &fudi);
      + func = get_called_function(&arg, eap->skip, &fudi, TRUE);
      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
      @@ -3418,10 +3451,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);
      @@ -3457,7 +3486,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)
      {
      @@ -3499,8 +3528,8 @@
      }

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

      /*
      @@ -4471,12 +4500,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;
      }
      @@ -5145,21 +5179,36 @@
      {
      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);
      + func = deref_func_name(s, len, TRUE);
      +
      + if (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;
      }

      @@ -6120,9 +6169,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;
      @@ -7414,7 +7467,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);
      @@ -7593,8 +7646,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:
      @@ -7675,10 +7728,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:
      @@ -7699,17 +7752,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);
      @@ -7720,10 +7781,12 @@
      s = r = alloc(len);
      if (r != NULL)
      {
      - if (function)
      - {
      - STRCPY(r, "function('");
      - r += 10;
      + if (fname_u)
      + {
      + STRCPY(r, fname_u);
      + r += flen;
      + *r++ = '(';
      + *r++ = '\'';
      }
      else
      *r++ = '\'';
      @@ -7735,7 +7798,7 @@
      MB_COPY_CHAR(p, r);
      }
      *r++ = '\'';
      - if (function)
      + if (fname_u)
      *r++ = ')';
      *r++ = NUL;
      }
      @@ -7828,321 +7891,323 @@
      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},
      - {"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},
      + {"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},
      + {"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)
      @@ -8236,9 +8301,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 */
      {
      @@ -8259,39 +8324,160 @@
      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.
      + *
      + * With runevent set to FALSE FuncUndefined event is not called.
      + */
      + func_T *
      +deref_func_name(name, len, runevent)
      char_u *name;
      - int *lenp;
      + const int len;
      + int runevent;
      {
      dictitem_T *v;
      int cc;
      -
      - cc = name[*lenp];
      - name[*lenp] = NUL;
      + func_T *r = NULL;
      +
      + cc = name[len];
      + name[len] = NUL;
      v = find_var(name, NULL);
      - name[*lenp] = cc;
      + name[len] = 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;
      + 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 (runevent
      + && 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 (vim_strchr(fname, AUTOLOAD_CHAR) != NULL)
      + {
      + 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;
      }

      /*
      @@ -8299,10 +8485,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 */
      @@ -8339,15 +8524,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)
      @@ -8357,17 +8547,75 @@
      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 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 */
      +};
      +
      + 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"
      @@ -8375,212 +8623,130 @@
      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;
      + /* Try loading a package. */
      + if (aufp->auf_func == NULL && script_autoload(aufp->auf_name, TRUE) &&
      + !aborting())
      + /* loaded a package, search for the function again */
      + aufp->auf_func = deref_func_name(aufp->auf_name,
      + STRLEN(aufp->auf_name),
      + TRUE);
      +
      + 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 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 */
      +};
      +
      +/*
      + * 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;
      }

      /*
      @@ -9212,8 +9378,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;
      @@ -9239,9 +9405,9 @@
      }

      if (item == NULL)
      - r = call_func(name, (int)STRLEN(name), rettv, argc, argv,
      + r = call_func(func, rettv, argc, argv,
      curwin->w_cursor.lnum, curwin->w_cursor.lnum,
      - &dummy, TRUE, selfdict);
      + &dummy, selfdict);

      /* Free the arguments. */
      while (argc > 0)
      @@ -9258,7 +9424,7 @@
      typval_T *argvars;
      typval_T *rettv;
      {
      - char_u *func;
      + func_T *func;
      dict_T *selfdict = NULL;

      if (argvars[1].v_type != VAR_LIST)
      @@ -9270,11 +9436,18 @@
      return;

      if (argvars[0].v_type == VAR_FUNC)
      - func = argvars[0].vval.v_string;
      - else
      - func = get_tv_string(&argvars[0]);
      - if (*func == NUL)
      - return; /* type error or empty name */
      + {
      + func = argvars[0].vval.v_func;
      + ++func->fv_refcount;
      + }
      + else
      + {
      + char_u *name;
      + name = get_tv_string(&argvars[0]);
      + if (name == NUL)
      + return; /* type error or empty name */
      + func = deref_func_name(name, STRLEN(name), TRUE);
      + }

      if (argvars[2].v_type != VAR_UNKNOWN)
      {
      @@ -9287,6 +9460,8 @@
      }

      (void)func_call(func, &argvars[1], selfdict, rettv);
      +
      + func_unref(func);
      }

      #ifdef FEAT_FLOAT
      @@ -10977,36 +11152,20 @@
      typval_T *rettv;
      {
      char_u *s;
      + func_T *func;

      s = get_tv_string(&argvars[0]);
      - if (s == NULL || *s == NUL || VIM_ISDIGIT(*s))
      - EMSG2(_(e_invarg2), s);
      - /* Don't check an autoload name for existence here. */
      - else if (vim_strchr(s, AUTOLOAD_CHAR) == NULL && !function_exists(s))
      - EMSG2(_("E700: Unknown function: %s"), s);
      - else
      - {
      - if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
      - {
      - char sid_buf[25];
      - int off = *s == 's' ? 2 : 5;
      -
      - /* Expand s: and <SID> into <SNR>nr_, so that the function can
      - * also be called from another script. Using trans_function_name()
      - * would also work, but some plugins depend on the name being
      - * printable text. */
      - sprintf(sid_buf, "<SNR>%ld_", (long)current_SID);
      - rettv->vval.v_string =
      - alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
      - if (rettv->vval.v_string != NULL)
      - {
      - STRCPY(rettv->vval.v_string, sid_buf);
      - STRCAT(rettv->vval.v_string, s + off);
      - }
      - }
      - else
      - rettv->vval.v_string = vim_strsave(s);
      +
      + func = deref_func_name(s, STRLEN(s), FALSE);
      +
      + if (func != NULL)
      + {
      rettv->v_type = VAR_FUNC;
      + rettv->vval.v_func = func;
      + }
      + else
      + {
      + EMSG2(_(e_unknown_function), s);
      }
      }

      @@ -16948,7 +17107,7 @@
      item_compare2 __ARGS((const void *s1, const void *s2));

      static int item_compare_ic;
      -static char_u *item_compare_func;
      +static func_T *item_compare_func;
      static dict_T *item_compare_selfdict;
      static int item_compare_func_err;
      #define ITEM_COMPARE_FAIL 999
      @@ -17008,8 +17167,8 @@
      copy_tv(&(*(listitem_T **)s2)->li_tv, &argv[1]);

      rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
      - res = call_func(item_compare_func, (int)STRLEN(item_compare_func),
      - &rettv, 2, argv, 0L, 0L, &dummy, TRUE,
      + res = call_func(item_compare_func,
      + &rettv, 2, argv, 0L, 0L, &dummy,
      item_compare_selfdict);
      clear_tv(&argv[0]);
      clear_tv(&argv[1]);
      @@ -17061,7 +17220,7 @@
      {
      /* optional second argument: {func} */
      if (argvars[1].v_type == VAR_FUNC)
      - item_compare_func = argvars[1].vval.v_string;
      + item_compare_func = argvars[1].vval.v_func;
      else
      {
      int error = FALSE;
      @@ -17072,7 +17231,18 @@
      if (i == 1)
      item_compare_ic = TRUE;
      else
      - item_compare_func = get_tv_string(&argvars[1]);
      + {
      + char_u *name;
      +
      + name = get_tv_string(&argvars[1]);
      + if (*name == NUL)
      + return;
      +
      + item_compare_func = deref_func_name(name, STRLEN(name),
      + TRUE);
      + if (item_compare_func == NULL)
      + return;
      + }
      }

      if (argvars[2].v_type != VAR_UNKNOWN)
      @@ -17117,6 +17287,9 @@
      }
      }

      + if (item_compare_func != NULL)
      + func_unref(item_compare_func);
      +
      vim_free(ptrs);
      }
      }
      @@ -19795,13 +19968,14 @@
      {
      if (**arg == '(')
      {
      + func_T *func;
      /* need to copy the funcref so that we can clear rettv */
      functv = *rettv;
      rettv->v_type = VAR_UNKNOWN;

      /* Invoke the function. Recursive! */
      - s = functv.vval.v_string;
      - ret = get_func_tv(s, (int)STRLEN(s), rettv, arg,
      + func = functv.vval.v_func;
      + ret = get_func_tv(func, rettv, arg,
      curwin->w_cursor.lnum, curwin->w_cursor.lnum,
      &len, evaluate, selfdict);

      @@ -19887,8 +20061,8 @@
      switch (varp->v_type)
      {
      case VAR_FUNC:
      - func_unref(varp->vval.v_string);
      - /*FALLTHROUGH*/
      + func_unref(varp->vval.v_func);
      + break;
      case VAR_STRING:
      vim_free(varp->vval.v_string);
      <br/><br/>(Message over 64 KB, truncated)
    • ZyX
      ... New status: vim tests pass, my own new tests pass, checked out aurum with this branch, it fails badly. In some of the tests while manually playing with
      Message 2 of 22 , Jul 18, 2013
      • 0 Attachment
        On Sunday, July 14, 2013 7:31:07 PM UTC+4, ZyX wrote:
        > Recent progress on https://bitbucket.org/ZyX_I/vim, branch extended-funcrefs. Use the new head, it was rebased. Use this branch in case patch will appear to be invalid.
        >
        > For merging some time after vim-7.4 release, just giving more time to test. Current status: vim tests pass, my (and other) plugins’ tests were not checked and there still are some TODO items awaiting implementations. Lua interface must break I guess: did not test, deferred. Don’t know about other interfaces, but AFAIR only lua and python have special objects for function references. Maybe also mzscheme?

        New status: vim tests pass, my own new tests pass, checked out aurum with this branch, it fails badly. In some of the tests while manually playing with things I succeeded to crash vim (using python; crash happened at exit), but currently unable to reproduce the crash. Aurum and frawor it is based on both make an extensive use of anonymous functions. Fail messages come from frawor and show that besides “unknown function” function in question is executed:

        Error detected while processing function s:F.newplugin..s:F.updatedeplen:
        line 5:
        E117: Unknown function: updatedeplen
        Error detected while processing function FraworRegister..s:F.newplugin..s:F.updatedeplen:
        line 5:
        E117: Unknown function: updatedeplen
        Error detected while processing /tmp/aurum-tests-0/t/rtp/autoload/frawor/functions.vim:
        line 4:
        E171: Missing :endif
        Error detected while processing function FraworLoad..s:F.loadplugin:
        line 14:
        E171: Missing :endif
        Error detected while processing /tmp/aurum-tests-0/t/rtp/autoload/frawor.vim:
        line 60:
        E171: Missing :endif
        Error detected while processing function FraworRegister..s:F.newplugin..s:F.updatedeplen:
        line 5:
        E117: Unknown function: updatedeplen
        E117: Unknown function: updatedeplen
        E117: Unknown function: updatedeplen
        Error detected while processing function FraworRegister..s:F.newplugin..s:F.updatedeplen..s:F.updatedeplen..s:F.updatedeplen..s:F.updatedeplen:
        line 5:
        E117: Unknown function: updatedeplen
        Error detected while processing function FraworRegister..s:F.newplugin..s:F.updatedeplen..s:F.updatedeplen..s:F.updatedeplen..s:F.updatedeplen..s:F.updatedeplen:
        line 5:
        E117: Unknown function: updatedeplen

        --
        --
        You received this message from the "vim_dev" maillist.
        Do not top-post! Type your reply below the text you are replying to.
        For more information, visit http://www.vim.org/maillist.php

        ---
        You received this message because you are subscribed to the Google Groups "vim_dev" group.
        To unsubscribe from this group and stop receiving emails from it, send an email to vim_dev+unsubscribe@....
        For more options, visit https://groups.google.com/groups/opt_out.
      • ZyX
        Fixed “Unknown function” errors, now it crashes with some problems related to selfdict reported by valgrind. diff -r c015eedb9b4a -r ac4d567505ed
        Message 3 of 22 , Jul 18, 2013
        • 0 Attachment
          Fixed “Unknown function” errors, now it crashes with some problems related to selfdict reported by valgrind.

          diff -r c015eedb9b4a -r ac4d567505ed runtime/doc/if_pyth.txt
          --- a/runtime/doc/if_pyth.txt Sun Jul 14 15:06:50 2013 +0200
          +++ b/runtime/doc/if_pyth.txt Fri Jul 19 08:56:45 2013 +0400
          @@ -655,7 +655,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 c015eedb9b4a -r ac4d567505ed runtime/doc/version7.txt
          --- a/runtime/doc/version7.txt Sun Jul 14 15:06:50 2013 +0200
          +++ b/runtime/doc/version7.txt Fri Jul 19 08:56:45 2013 +0400
          @@ -70,6 +70,7 @@

          VERSION 7.4 |version-7.4|
          New regexp engine |new-regexp-engine|
          +Better vim ↔ python interface |new-python-interfac|
          Changed |changed-7.4|
          Added |added-7.4|
          Fixed |fixed-7.4|
          @@ -10182,16 +10183,168 @@

          More information here: |two-engines|

          +Better vim ↔ python interface *new-python-interface*
          +-----------------------------
          +
          +Added |python-bindeval| function. Unlike |python-eval| this one returns
          + |python-Dictionary|, |python-List| and |python-Function| objects for
          + dictionaries lists and functions respectively in place of their python
          + built-in equivalents (or None if we are talking about function references).
          +For simple types this function returns python built-in types and not only
          + python `str()` like |python-eval| does. On python 3 it will return `bytes()`
          + objects in place of `str()` ones avoiding possibility of UnicodeDecodeError.
          +Interface of new objects mimics standard python `dict()` and `list()`
          + interfaces to some extent. Extent will be improved in the future.
          +
          +Added special |python-vars| objects also available for |python-buffer| and
          +|python-window|. They ease access to VimL variables from python.
          +
          +Now you no longer need to alter `sys.path` to import your module: special
          +hooks are responsible for importing from {rtp}/python2, {rtp}/python3 and
          +{rtp}/pythonx directories (for python 2, python 3 and both respectively).
          +See |python-special-path|.
          +
          +Added possibility to work with |tabpage|s through |python-tabpage| object.
          +
          +Added automatic conversion of vim errors and exceptions to python
          +exceptions.
          +
          +Changed the behavior of |python-buffers| object: it now uses buffer numbers
          +as keys in place of the index of the buffer in the internal buffer list.
          +This should not break anything as the only way to get this index was
          +iterating over |python-buffers|.
          +
          +Added |:pydo| and |:py3do| commands.
          +
          +Added |pyeval()| and |py3eval()| functions.
          +
          +Now in all places which previously accepted `str()` objects in both python
          +version both `str()` and `unicode()` (python 2) or `bytes()` and `str()`
          +(python 3) are accepted.
          +
          +|python-window| has gained `.col` and `.row` attributes that are currently
          +the only way to get internal window positions.
          +
          +Added or fixed support for `dir()` in vim python objects.
          +
          +Old python versions (≤2.2) are no longer supported. Building with them did
          +not work anyway.

          Changed *changed-7.4*
          -------

          -Todo.
          -
          +Functions:
          + Added ability to use |Dictionary-function|s for |sort()|ing, via
          + optional third argument. (Nikolay Pavlov)
          +
          + Added special |expand()| argument that expands to the current line
          + number.
          +
          + Made it possible to force |char2nr()| always give unicode codepoints
          + regardless of current encoding. (Yasuhiro Matsumoto)
          +
          + Made it possible for functions generating file list generate |List|
          + and not NL-separated string. (e.g. |glob()|, |expand()|) (Christian
          + Brabandt)
          +
          + Functions that obtain variables from the specific window, tabpage or
          + buffer scope dictionary can now return specified default value in
          + place of empty string in case variable is not found. (|gettabvar()|,
          + |getwinvar()|, |getbufvar()|) (Shougo Matsushita, Hirohito Higashi)
          +
          +Options:
          + Added ability to automatically save selection into the system
          + clipboard when using non-GUI version of vim (autoselectplus in
          + 'clipboard'). Also added ability to use system clipboard as default
          + register (previously only primary selection could be used). (Ivan
          + Krasilnikov, Christian Brabandt, Bram Moolenaar)
          +
          + Added special 'shiftwidth' value that makes 'sw' follow 'tabstop'. As
          + indenting via 'indentexpr' became tricky |shiftwidth()| function was
          + added. Also added equivalent special value to 'softtabstop' option.
          + (Christian Brabandt, so8res)
          +
          + Added ability to delete comment leader when using |J| by `j` flag in
          + 'formatoptions' (|fo-table|). (Lech Lorens)
          +
          + Added ability to control indentation inside namespaces: |cino-N|.
          + (Konstantin Lepa)
          +
          + Added ability to control alignment inside `if` condition separately
          + from alignment inside function arguments: |cino-k|. (Lech Lorens)
          +
          + Added ability to show absolute number in number column when
          + 'relativenumber' option is on. (Christian Brabandt)
          +
          +Comands:
          + Made it possible to remove all signs from the current buffer using
          + |:sign-unplace|. (Christian Brabandt)
          +
          + Added |:language| autocompletion. (Dominique Pelle)
          +
          + |:diffoff| now saves the local values of some settings and restores
          + them in place of blindly resetting them to the defaults. (Christian
          + Brabandt)
          +
          + Added |:map-nowait| creating mapping which when having lhs that is the
          + prefix of another mapping’s lhs will not allow vim to wait for user to
          + type more characters to resolve ambiguity, forcing vim to take the
          + shorter alternative: one with <nowait>.
          +
          + Added more |:command-complete| completion types: |:behave| suboptions,
          + color schemes, compilers, |:cscope| suboptions, files from 'path',
          + |:history| suboptions, locale names, |:syntime| suboptions, user
          + names. (Dominique Pelle)
          +
          +Other:
          + Improved support for cmd.exe. (Ben Fritz, Bram Moolenaar)
          +
          + Added |v:windowid| variable containing current window number in GUI
          + vim. (Christian J. Robinson, Lech Lorens)
          +
          + Lua interface now also uses userdata binded to vim structures. (Taro
          + Muraoka, Luis Carvalho)
          +
          + Added rxvt-unicode and >xterm-277 mouse support. (Yiding Jia, Hayaki
          + Saito)

          Added *added-7.4*
          -----

          +Added support for |Lists| and |Dictionaries| in |viminfo|. (Christian
          +Brabandt)
          +
          +Functions:
          + Bitwise functions: |and()|, |or()|, |invert()|, |xor()|.
          +
          + Added |luaeval()| function. (Taro Muraoka, Luis Carvalho)
          +
          + Added |sha256()| function. (Tyru, Hirohito Higashi)
          +
          + Added |wildmenumode()| function. (Christian Brabandt)
          +
          + Debugging functions: |screenattr()|, |screenchar()|, |screencol()|,
          + |screenrow()|. (Simon Ruderich, Bram Moolenaar)
          +
          +Autocommands:
          + Added |InsertCharPre| event launched before inserting character.
          + (Jakson A. Aquino)
          +
          + Added |CompleteDone| event launched after finishing completion in
          + insert mode. (idea by Florian Klein)
          +
          + Added |QuitPre| event launched when commands that can either close vim
          + or only some window(s) are launched.
          +
          + Added |TextChanged| and |TextChangedI| events launched when text is
          + changed.
          +
          +Commands:
          + |:syntime| command useful for debugging.
          +
          +Options:
          + Made it possible to ignore case when completing: 'wildignorecase'.
          +
          Various syntax, indent and other plugins were added.


          diff -r c015eedb9b4a -r ac4d567505ed src/eval.c
          --- a/src/eval.c Sun Jul 14 15:06:50 2013 +0200
          +++ b/src/eval.c Fri Jul 19 08:56:45 2013 +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
          @@ -166,7 +167,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
          @@ -188,16 +188,31 @@
          #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.
          @@ -272,6 +287,9 @@
          dict_T *fd_dict; /* Dictionary used */
          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;


          @@ -438,17 +456,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));
          @@ -794,6 +811,7 @@
          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 runevent));
          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));
          @@ -818,8 +836,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));
          @@ -835,6 +854,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.
          */
          @@ -1558,10 +1582,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;
          @@ -1573,11 +1597,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), TRUE);
          + if (func == NULL)
          + {
          + vim_free(argvars);
          + return FAIL;
          + }
          +
          for (i = 0; i < argc; i++)
          {
          /* Pass a NULL or empty argument as an empty string */
          @@ -1612,9 +1644,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;
          @@ -1625,6 +1657,8 @@
          if (ret == FAIL)
          clear_tv(rettv);

          + func_unref(func);
          +
          return ret;
          }

          @@ -3382,8 +3416,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;
          @@ -3403,14 +3436,14 @@
          return;
          }

          - tofree = trans_function_name(&arg, eap->skip, TFN_INT, &fudi);
          + func = get_called_function(&arg, eap->skip, &fudi, TRUE);
          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
          @@ -3418,10 +3451,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);
          @@ -3457,7 +3486,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)
          {
          @@ -3499,8 +3528,8 @@
          }

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

          /*
          @@ -4471,12 +4500,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;
          }
          @@ -5145,21 +5179,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, TRUE);
          + 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;
          }

          @@ -6120,9 +6172,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;
          @@ -7414,7 +7470,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);
          @@ -7593,8 +7649,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:
          @@ -7675,10 +7731,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:
          @@ -7699,17 +7755,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);
          @@ -7720,10 +7784,12 @@
          s = r = alloc(len);
          if (r != NULL)
          {
          - if (function)
          - {
          - STRCPY(r, "function('");
          - r += 10;
          + if (fname_u)
          + {
          + STRCPY(r, fname_u);
          + r += flen;
          + *r++ = '(';
          + *r++ = '\'';
          }
          else
          *r++ = '\'';
          @@ -7735,7 +7801,7 @@
          MB_COPY_CHAR(p, r);
          }
          *r++ = '\'';
          - if (function)
          + if (fname_u)
          *r++ = ')';
          *r++ = NUL;
          }
          @@ -7828,321 +7894,323 @@
          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},
          - {"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},
          + {"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},
          + {"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)
          @@ -8236,9 +8304,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 */
          {
          @@ -8259,39 +8327,160 @@
          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.
          + *
          + * With runevent set to FALSE FuncUndefined event is not called.
          + */
          + func_T *
          +deref_func_name(name, len, runevent)
          char_u *name;
          - int *lenp;
          + const int len;
          + int runevent;
          {
          dictitem_T *v;
          int cc;
          -
          - cc = name[*lenp];
          - name[*lenp] = NUL;
          + func_T *r = NULL;
          +
          + cc = name[len];
          + name[len] = NUL;
          v = find_var(name, NULL);
          - name[*lenp] = cc;
          + name[len] = 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;
          + 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 (runevent
          + && 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 (vim_strchr(fname, AUTOLOAD_CHAR) != NULL)
          + {
          + 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;
          }

          /*
          @@ -8299,10 +8488,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 */
          @@ -8339,15 +8527,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)
          @@ -8357,17 +8550,75 @@
          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 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 */
          +};
          +
          + 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"
          @@ -8375,212 +8626,130 @@
          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;
          + /* Try loading a package. */
          + if (aufp->auf_func == NULL && script_autoload(aufp->auf_name, TRUE) &&
          + !aborting())
          + /* loaded a package, search for the function again */
          + aufp->auf_func = deref_func_name(aufp->auf_name,
          + STRLEN(aufp->auf_name),
          + TRUE);
          +
          + 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 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 */
          +};
          +
          +/*
          + * 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;
          }

          /*
          @@ -9212,8 +9381,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;
          @@ -9239,9 +9408,9 @@
          }

          if (item == NULL)
          - r = call_func(name, (int)STRLEN(name), rettv, argc, argv,
          + r = call_func(func, rettv, argc, argv,
          curwin->w_cursor.lnum, curwin->w_cursor.lnum,
          - &dummy, TRUE, selfdict);
          + &dummy, selfdict);

          /* Free the arguments. */
          while (argc > 0)
          @@ -9258,7 +9427,7 @@
          typval_T *argvars;
          typval_T *rettv;
          {
          - char_u *func;
          + func_T *func;
          dict_T *selfdict = NULL;

          if (argvars[1].v_type != VAR_LIST)
          @@ -9270,11 +9439,18 @@
          return;

          if (argvars[0].v_type == VAR_FUNC)
          - func = argvars[0].vval.v_string;
          - else
          - func = get_tv_string(&argvars[0]);
          - if (*func == NUL)
          - return; /* type error or empty name */
          + {
          + func = argvars[0].vval.v_func;
          + ++func->fv_refcount;
          + }
          + else
          + {
          + char_u *name;
          + name = get_tv_string(&argvars[0]);
          + if (name == NUL)
          + return; /* type error or empty name */
          + func = deref_func_name(name, STRLEN(name), TRUE);
          + }

          if (argvars[2].v_type != VAR_UNKNOWN)
          {
          @@ -9287,6 +9463,8 @@
          }

          (void)func_call(func, &argvars[1], selfdict, rettv);
          +
          + func_unref(func);
          }

          #ifdef FEAT_FLOAT
          @@ -10977,36 +11155,20 @@
          typval_T *rettv;
          {
          char_u *s;
          + func_T *func;

          s = get_tv_string(&argvars[0]);
          - if (s == NULL || *s == NUL || VIM_ISDIGIT(*s))
          - EMSG2(_(e_invarg2), s);
          - /* Don't check an autoload name for existence here. */
          - else if (vim_strchr(s, AUTOLOAD_CHAR) == NULL && !function_exists(s))
          - EMSG2(_("E700: Unknown function: %s"), s);
          - else
          - {
          - if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
          - {
          - char sid_buf[25];
          - int off = *s == 's' ? 2 : 5;
          -
          - /* Expand s: and <SID> into <SNR>nr_, so that the function can
          - * also be called from another script. Using trans_function_name()
          - * would also work, but some plugins depend on the name being
          - * printable text. */
          - sprintf(sid_buf, "<SNR>%ld_", (long)current_SID);
          - rettv->vval.v_string =
          - alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
          - if (rettv->vval.v_string != NULL)
          - {
          - STRCPY(rettv->vval.v_string, sid_buf);
          - STRCAT(rettv->vval.v_string, s + off);
          - }
          - }
          - else
          - rettv->vval.v_string = vim_strsave(s);
          +
          + func = deref_func_name(s, STRLEN(s), FALSE);
          +
          + if (func != NULL)
          + {
          rettv->v_type = VAR_FUNC;
          + rettv->vval.v_func = func;
          + }
          + else
          + {
          + EMSG2(_(e_unknown_function), s);
          }
          }

          @@ -16948,7 +17110,7 @@
          item_compare2 __ARGS((const void *s1, const void *s2));

          static int item_compare_ic;
          -static char_u *item_compare_func;
          +static func_T *item_compare_func;
          static dict_T *item_compare_selfdict;
          static int item_compare_func_err;
          #define ITEM_COMPARE_FAIL 999
          @@ -17008,8 +17170,8 @@
          copy_tv(&(*(listitem_T **)s2)->li_tv, &argv[1]);

          rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
          - res = call_func(item_compare_func, (int)STRLEN(item_compare_func),
          - &rettv, 2, argv, 0L, 0L, &dummy, TRUE,
          + res = call_func(item_compare_func,
          + &rettv, 2, argv, 0L, 0L, &dummy,
          item_compare_selfdict);
          clear_tv(&argv[0]);
          clear_tv(&argv[1]);
          @@ -17061,7 +17223,7 @@
          {
          /* optional second argument: {func} */
          if (argvars[1].v_type == VAR_FUNC)
          - item_compare_func = argvars[1].vval.v_string;
          + item_compare_func = argvars[1].vval.v_func;
          else
          {
          int error = FALSE;
          @@ -17072,7 +17234,18 @@
          if (i == 1)
          item_compare_ic = TRUE;
          else
          - item_compare_func = get_tv_string(&argvars[1]);
          + {
          + char_u *name;
          +
          + name = get_tv_string(&argvars[1]);
          + if (*name == NUL)
          + return;
          +
          + item_compare_func = deref_func_name(name, STRLEN(name),
          + TRUE);
          + if (item_compare_func == NULL)
          + return;
          + }
          }

          if (argvars[2].v_type != VAR_UNKNOWN)
          @@ -17117,6 +17290,9 @@
          }
          }

          + if (item_compare_func != NULL)
          + func_unref(item_compare_func);
          +
          vim_free(ptrs);
          }
          }
          @@ -19795,13 +19971,14 @@
          {
          if (**arg == '(')
          {
          + func_T *func;
          /* need to copy the funcref so that we can clear rettv */
          functv = *rettv;
          rettv->v_type = VAR_UNKNOWN;

          /* Invoke the function. Recursive! */
          - s = functv.vval.v_string;
          - ret = get_func_tv(s, (int)STRLEN(s), rettv, arg,
          + func = functv.vval.v_func;
          + ret = get_func_tv(func, rettv, arg,
          curwin->w_cursor.lnum, curwin->w_cursor.lnum,
          &len, evaluate, selfdict);

          @@ -19887,8 +20064,8 @@
          switch (varp->v_type)
          {
          case VAR_FUNC:
          - func_unref(varp->vval.v_string);
          - /*FALLTHROUGH*/
          + func_unref(varp-<br/><br/>(Message over 64 KB, truncated)
        • ZyX
          ... Fixed crash and error reported when using exists( *dict.non_func_ref ), merged branch with upstream. Problems with sort(, function()) popped out, also some
          Message 4 of 22 , Jul 20, 2013
          • 0 Attachment
            On Friday, July 19, 2013 8:59:14 AM UTC+4, ZyX wrote:
            > Fixed “Unknown function” errors, now it crashes with some problems related to selfdict reported by valgrind.

            Fixed crash and error reported when using exists('*dict.non_func_ref'), merged branch with upstream. Problems with sort(, function()) popped out, also some invalid reads/writes at exit reported by valgrind.

            diff -r f2f3329c80d1 -r 9456fca78ad6 runtime/doc/if_pyth.txt
            --- a/runtime/doc/if_pyth.txt Wed Jul 17 22:35:39 2013 +0200
            +++ b/runtime/doc/if_pyth.txt Sat Jul 20 15:13:34 2013 +0400
            @@ -655,7 +655,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 f2f3329c80d1 -r 9456fca78ad6 runtime/doc/version7.txt
            --- a/runtime/doc/version7.txt Wed Jul 17 22:35:39 2013 +0200
            +++ b/runtime/doc/version7.txt Sat Jul 20 15:13:34 2013 +0400
            @@ -70,6 +70,7 @@

            VERSION 7.4 |version-7.4|
            New regexp engine |new-regexp-engine|
            +Better vim ↔ python interface |new-python-interfac|
            Changed |changed-7.4|
            Added |added-7.4|
            Fixed |fixed-7.4|
            @@ -10182,16 +10183,168 @@

            More information here: |two-engines|

            +Better vim ↔ python interface *new-python-interface*
            +-----------------------------
            +
            +Added |python-bindeval| function. Unlike |python-eval| this one returns
            + |python-Dictionary|, |python-List| and |python-Function| objects for
            + dictionaries lists and functions respectively in place of their python
            + built-in equivalents (or None if we are talking about function references).
            +For simple types this function returns python built-in types and not only
            + python `str()` like |python-eval| does. On python 3 it will return `bytes()`
            + objects in place of `str()` ones avoiding possibility of UnicodeDecodeError.
            +Interface of new objects mimics standard python `dict()` and `list()`
            + interfaces to some extent. Extent will be improved in the future.
            +
            +Added special |python-vars| objects also available for |python-buffer| and
            +|python-window|. They ease access to VimL variables from python.
            +
            +Now you no longer need to alter `sys.path` to import your module: special
            +hooks are responsible for importing from {rtp}/python2, {rtp}/python3 and
            +{rtp}/pythonx directories (for python 2, python 3 and both respectively).
            +See |python-special-path|.
            +
            +Added possibility to work with |tabpage|s through |python-tabpage| object.
            +
            +Added automatic conversion of vim errors and exceptions to python
            +exceptions.
            +
            +Changed the behavior of |python-buffers| object: it now uses buffer numbers
            +as keys in place of the index of the buffer in the internal buffer list.
            +This should not break anything as the only way to get this index was
            +iterating over |python-buffers|.
            +
            +Added |:pydo| and |:py3do| commands.
            +
            +Added |pyeval()| and |py3eval()| functions.
            +
            +Now in all places which previously accepted `str()` objects in both python
            +version both `str()` and `unicode()` (python 2) or `bytes()` and `str()`
            +(python 3) are accepted.
            +
            +|python-window| has gained `.col` and `.row` attributes that are currently
            +the only way to get internal window positions.
            +
            +Added or fixed support for `dir()` in vim python objects.
            +
            +Old python versions (≤2.2) are no longer supported. Building with them did
            +not work anyway.

            Changed *changed-7.4*
            -------

            -Todo.
            -
            +Functions:
            + Added ability to use |Dictionary-function|s for |sort()|ing, via
            + optional third argument. (Nikolay Pavlov)
            +
            + Added special |expand()| argument that expands to the current line
            + number.
            +
            + Made it possible to force |char2nr()| always give unicode codepoints
            + regardless of current encoding. (Yasuhiro Matsumoto)
            +
            + Made it possible for functions generating file list generate |List|
            + and not NL-separated string. (e.g. |glob()|, |expand()|) (Christian
            + Brabandt)
            +
            + Functions that obtain variables from the specific window, tabpage or
            + buffer scope dictionary can now return specified default value in
            + place of empty string in case variable is not found. (|gettabvar()|,
            + |getwinvar()|, |getbufvar()|) (Shougo Matsushita, Hirohito Higashi)
            +
            +Options:
            + Added ability to automatically save selection into the system
            + clipboard when using non-GUI version of vim (autoselectplus in
            + 'clipboard'). Also added ability to use system clipboard as default
            + register (previously only primary selection could be used). (Ivan
            + Krasilnikov, Christian Brabandt, Bram Moolenaar)
            +
            + Added special 'shiftwidth' value that makes 'sw' follow 'tabstop'. As
            + indenting via 'indentexpr' became tricky |shiftwidth()| function was
            + added. Also added equivalent special value to 'softtabstop' option.
            + (Christian Brabandt, so8res)
            +
            + Added ability to delete comment leader when using |J| by `j` flag in
            + 'formatoptions' (|fo-table|). (Lech Lorens)
            +
            + Added ability to control indentation inside namespaces: |cino-N|.
            + (Konstantin Lepa)
            +
            + Added ability to control alignment inside `if` condition separately
            + from alignment inside function arguments: |cino-k|. (Lech Lorens)
            +
            + Added ability to show absolute number in number column when
            + 'relativenumber' option is on. (Christian Brabandt)
            +
            +Comands:
            + Made it possible to remove all signs from the current buffer using
            + |:sign-unplace|. (Christian Brabandt)
            +
            + Added |:language| autocompletion. (Dominique Pelle)
            +
            + |:diffoff| now saves the local values of some settings and restores
            + them in place of blindly resetting them to the defaults. (Christian
            + Brabandt)
            +
            + Added |:map-nowait| creating mapping which when having lhs that is the
            + prefix of another mapping’s lhs will not allow vim to wait for user to
            + type more characters to resolve ambiguity, forcing vim to take the
            + shorter alternative: one with <nowait>.
            +
            + Added more |:command-complete| completion types: |:behave| suboptions,
            + color schemes, compilers, |:cscope| suboptions, files from 'path',
            + |:history| suboptions, locale names, |:syntime| suboptions, user
            + names. (Dominique Pelle)
            +
            +Other:
            + Improved support for cmd.exe. (Ben Fritz, Bram Moolenaar)
            +
            + Added |v:windowid| variable containing current window number in GUI
            + vim. (Christian J. Robinson, Lech Lorens)
            +
            + Lua interface now also uses userdata binded to vim structures. (Taro
            + Muraoka, Luis Carvalho)
            +
            + Added rxvt-unicode and >xterm-277 mouse support. (Yiding Jia, Hayaki
            + Saito)

            Added *added-7.4*
            -----

            +Added support for |Lists| and |Dictionaries| in |viminfo|. (Christian
            +Brabandt)
            +
            +Functions:
            + Bitwise functions: |and()|, |or()|, |invert()|, |xor()|.
            +
            + Added |luaeval()| function. (Taro Muraoka, Luis Carvalho)
            +
            + Added |sha256()| function. (Tyru, Hirohito Higashi)
            +
            + Added |wildmenumode()| function. (Christian Brabandt)
            +
            + Debugging functions: |screenattr()|, |screenchar()|, |screencol()|,
            + |screenrow()|. (Simon Ruderich, Bram Moolenaar)
            +
            +Autocommands:
            + Added |InsertCharPre| event launched before inserting character.
            + (Jakson A. Aquino)
            +
            + Added |CompleteDone| event launched after finishing completion in
            + insert mode. (idea by Florian Klein)
            +
            + Added |QuitPre| event launched when commands that can either close vim
            + or only some window(s) are launched.
            +
            + Added |TextChanged| and |TextChangedI| events launched when text is
            + changed.
            +
            +Commands:
            + |:syntime| command useful for debugging.
            +
            +Options:
            + Made it possible to ignore case when completing: 'wildignorecase'.
            +
            Various syntax, indent and other plugins were added.


            diff -r f2f3329c80d1 -r 9456fca78ad6 src/eval.c
            --- a/src/eval.c Wed Jul 17 22:35:39 2013 +0200
            +++ b/src/eval.c Sat Jul 20 15:13:34 2013 +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
            @@ -166,7 +167,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
            @@ -188,16 +188,31 @@
            #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.
            @@ -269,9 +284,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;


            @@ -438,17 +457,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));
            @@ -794,6 +812,7 @@
            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 runevent, int raise));
            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));
            @@ -818,8 +837,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));
            @@ -835,6 +855,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.
            */
            @@ -1558,10 +1583,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;
            @@ -1573,11 +1598,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), TRUE);
            + if (func == NULL)
            + {
            + vim_free(argvars);
            + return FAIL;
            + }
            +
            for (i = 0; i < argc; i++)
            {
            /* Pass a NULL or empty argument as an empty string */
            @@ -1612,9 +1645,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;
            @@ -1625,6 +1658,8 @@
            if (ret == FAIL)
            clear_tv(rettv);

            + func_unref(func);
            +
            return ret;
            }

            @@ -3382,8 +3417,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;
            @@ -3403,14 +3437,14 @@
            return;
            }

            - tofree = trans_function_name(&arg, eap->skip, TFN_INT, &fudi);
            + func = get_called_function(&arg, eap->skip, &fudi, TRUE, TRUE);
            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
            @@ -3418,10 +3452,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);
            @@ -3457,7 +3487,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)
            {
            @@ -3499,8 +3529,8 @@
            }

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

            /*
            @@ -4471,12 +4501,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;
            }
            @@ -5145,21 +5180,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, TRUE);
            + 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;
            }

            @@ -6120,9 +6173,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;
            @@ -7414,7 +7471,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);
            @@ -7593,8 +7650,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:
            @@ -7675,10 +7732,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:
            @@ -7699,17 +7756,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);
            @@ -7720,10 +7785,12 @@
            s = r = alloc(len);
            if (r != NULL)
            {
            - if (function)
            - {
            - STRCPY(r, "function('");
            - r += 10;
            + if (fname_u)
            + {
            + STRCPY(r, fname_u);
            + r += flen;
            + *r++ = '(';
            + *r++ = '\'';
            }
            else
            *r++ = '\'';
            @@ -7735,7 +7802,7 @@
            MB_COPY_CHAR(p, r);
            }
            *r++ = '\'';
            - if (function)
            + if (fname_u)
            *r++ = ')';
            *r++ = NUL;
            }
            @@ -7828,321 +7895,323 @@
            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},
            - {"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},
            + {"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},
            + {"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)
            @@ -8236,9 +8305,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 */
            {
            @@ -8259,39 +8328,160 @@
            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.
            + *
            + * With runevent set to FALSE FuncUndefined event is not called.
            + */
            + func_T *
            +deref_func_name(name, len, runevent)
            char_u *name;
            - int *lenp;
            + const int len;
            + int runevent;
            {
            dictitem_T *v;
            int cc;
            -
            - cc = name[*lenp];
            - name[*lenp] = NUL;
            + func_T *r = NULL;
            +
            + cc = name[len];
            + name[len] = NUL;
            v = find_var(name, NULL);
            - name[*lenp] = cc;
            + name[len] = 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;
            + 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 (runevent
            + && 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 (vim_strchr(fname, AUTOLOAD_CHAR) != NULL)
            + {
            + 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;
            }

            /*
            @@ -8299,10 +8489,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 */
            @@ -8339,15 +8528,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)
            @@ -8357,17 +8551,75 @@
            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 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 */
            +};
            +
            + 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"
            @@ -8375,212 +8627,130 @@
            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;
            + /* Try loading a package. */
            + if (aufp->auf_func == NULL && script_autoload(aufp->auf_name, TRUE) &&
            + !aborting())
            + /* loaded a package, search for the function again */
            + aufp->auf_func = deref_func_name(aufp->auf_name,
            + STRLEN(aufp->auf_name),
            + TRUE);
            +
            + 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 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 */
            +};
            +
            +/*
            + * 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;
            }

            /*
            @@ -9212,8 +9382,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;
            @@ -9239,9 +9409,9 @@
            }

            if (item == NULL)
            - r = call_func(name, (int)STRLEN(name), rettv, argc, argv,
            + r = call_func(func, rettv, argc, argv,
            curwin->w_cursor.lnum, curwin->w_cursor.lnum,
            - &dummy, TRUE, selfdict);
            + &dummy, selfdict);

            /* Free the arguments. */
            while (argc > 0)
            @@ -9258,7 +9428,7 @@
            typval_T *argvars;
            typval_T *rettv;
            {
            - char_u *func;
            + func_T *func;
            dict_T *selfdict = NULL;

            if (argvars[1].v_type != VAR_LIST)
            @@ -9270,11 +9440,18 @@
            return;

            if (argvars[0].v_type == VAR_FUNC)
            - func = argvars[0].vval.v_string;
            - else
            - func = get_tv_string(&argvars[0]);
            - if (*func == NUL)
            - return; /* type error or empty name */
            + {
            + func = argvars[0].vval.v_func;
            + ++func->fv_refcount;
            + }
            + else
            + {
            + char_u *name;
            + name = get_tv_string(&argvars[0]);
            + if (name == NUL)
            + return; /* type error or empty name */
            + func = deref_func_name(name, STRLEN(name), TRUE);
            + }

            if (argvars[2].v_type != VAR_UNKNOWN)
            {
            @@ -9287,6 +9464,8 @@
            }

            (void)func_call(func, &argvars[1], selfdict, rettv);
            +
            + func_unref(func);
            }

            #ifdef FEAT_FLOAT
            @@ -10977,36 +11156,20 @@
            typval_T *rettv;
            {
            char_u *s;
            + func_T *func;

            s = get_tv_string(&argvars[0]);
            - if (s == NULL || *s == NUL || VIM_ISDIGIT(*s))
            - EMSG2(_(e_invarg2), s);
            - /* Don't check an autoload name for existence here. */
            - else if (vim_strchr(s, AUTOLOAD_CHAR) == NULL && !function_exists(s))
            - EMSG2(_("E700: Unknown function: %s"), s);
            - else
            - {
            - if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
            - {
            - char sid_buf[25];
            - int off = *s == 's' ? 2 : 5;
            -
            - /* Expand s: and <SID> into <SNR>nr_, so that the function can
            - * also be called from another script. Using trans_function_name()
            - * would also work, but some plugins depend on the name being
            - * printable text. */
            - sprintf(sid_buf, "<SNR>%ld_", (long)current_SID);
            - rettv->vval.v_string =
            - alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
            - if (rettv->vval.v_string != NULL)
            - {
            - STRCPY(rettv->vval.v_string, sid_buf);
            - STRCAT(rettv->vval.v_string, s + off);
            - }
            - }
            - else
            - rettv->vval.v_string = vim_strsave(s);
            +
            + func = deref_func_name(s, STRLEN(s), FALSE);
            +
            + if (func != NULL)
            + {
            rettv->v_type = VAR_FUNC;
            + rettv->vval.v_func = func;
            + }
            + else
            + {
            + EMSG2(_(e_unknown_function), s);
            }
            }

            @@ -16948,7 +17111,7 @@
            item_compare2 __ARGS((const void *s1, const void *s2));

            static int item_compare_ic;
            -static char_u *item_compare_func;
            +static func_T *item_compare_func;
            static dict_T *item_compare_selfdict;
            static int item_compare_func_err;
            #define ITEM_COMPARE_FAIL 999
            @@ -17008,8 +17171,8 @@
            copy_tv(&(*(listitem_T **)s2)->li_tv, &argv[1]);

            rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
            - res = call_func(item_compare_func, (int)STRLEN(item_compare_func),
            - &rettv, 2, argv, 0L, 0L, &dummy, TRUE,
            + res = call_func(item_compare_func,
            + &rettv, 2, argv, 0L, 0L, &dummy,
            item_compare_selfdict);
            clear_tv(&argv[0]);
            clear_tv(&argv[1]);
            @@ -17061,7 +17224,7 @@
            {
            /* optional second argument: {func} */
            if (argvars[1].v_type == VAR_FUNC)
            - item_compare_func = argvars[1].vval.v_string;
            + item_compare_func = argvars[1].vval.v_func;
            else
            {
            int error = FALSE;
            @@ -17072,7 +17235,18 @@
            if (i == 1)
            item_compare_ic = TRUE;
            else
            - item_compare_func = get_tv_string(&argvars[1]);
            + {
            + char_u *name;
            +
            + name = get_tv_string(&argvars[1]);
            + if (*name == NUL)
            + return;
            +
            + item_compare_func = deref_func_name(name, STRLEN(name),
            + TRUE);
            + if (item_compare_func == NULL)
            + return;
            + }
            }

            if (argvars[2].v_type != VAR_UNKNOWN)
            @@ -17117,6 +17291,9 @@
            }
            }

            + if (item_compare_func != NULL)
            + func_unref(item_compare_func);
            +
            vim_free(ptrs);
            }
            }
            @@ -19795,13 +19972,14 @@
            {
            if (**arg == '(')
            {
            + func_T *func;
            /* need to copy the funcref so that we can clear rettv */
            functv = *rettv;
            rettv->v_type = VAR_UNKNOWN;

            /* Invoke the function. Recursive! */
            - <br/><br/>(Message over 64 KB, truncated)
          • ZyX
            ... Fixed sort(, funcref). diff -r f2f3329c80d1 -r a6952dd2b722 runtime/doc/if_pyth.txt ... +++ b/runtime/doc/if_pyth.txt Sat Jul 20 16:03:38 2013 +0400 @@
            Message 5 of 22 , Jul 20, 2013
            • 0 Attachment
              On Saturday, July 20, 2013 3:26:00 PM UTC+4, ZyX wrote:
              > On Friday, July 19, 2013 8:59:14 AM UTC+4, ZyX wrote:
              >
              > > Fixed “Unknown function” errors, now it crashes with some problems related to selfdict reported by valgrind.
              >
              >
              >
              > Fixed crash and error reported when using exists('*dict.non_func_ref'), merged branch with upstream. Problems with sort(, function()) popped out, also some invalid reads/writes at exit reported by valgrind.

              Fixed sort(, funcref).

              diff -r f2f3329c80d1 -r a6952dd2b722 runtime/doc/if_pyth.txt
              --- a/runtime/doc/if_pyth.txt Wed Jul 17 22:35:39 2013 +0200
              +++ b/runtime/doc/if_pyth.txt Sat Jul 20 16:03:38 2013 +0400
              @@ -655,7 +655,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 f2f3329c80d1 -r a6952dd2b722 runtime/doc/version7.txt
              --- a/runtime/doc/version7.txt Wed Jul 17 22:35:39 2013 +0200
              +++ b/runtime/doc/version7.txt Sat Jul 20 16:03:38 2013 +0400
              @@ -70,6 +70,7 @@

              VERSION 7.4 |version-7.4|
              New regexp engine |new-regexp-engine|
              +Better vim ↔ python interface |new-python-interfac|
              Changed |changed-7.4|
              Added |added-7.4|
              Fixed |fixed-7.4|
              @@ -10182,16 +10183,168 @@

              More information here: |two-engines|

              +Better vim ↔ python interface *new-python-interface*
              +-----------------------------
              +
              +Added |python-bindeval| function. Unlike |python-eval| this one returns
              + |python-Dictionary|, |python-List| and |python-Function| objects for
              + dictionaries lists and functions respectively in place of their python
              + built-in equivalents (or None if we are talking about function references).
              +For simple types this function returns python built-in types and not only
              + python `str()` like |python-eval| does. On python 3 it will return `bytes()`
              + objects in place of `str()` ones avoiding possibility of UnicodeDecodeError.
              +Interface of new objects mimics standard python `dict()` and `list()`
              + interfaces to some extent. Extent will be improved in the future.
              +
              +Added special |python-vars| objects also available for |python-buffer| and
              +|python-window|. They ease access to VimL variables from python.
              +
              +Now you no longer need to alter `sys.path` to import your module: special
              +hooks are responsible for importing from {rtp}/python2, {rtp}/python3 and
              +{rtp}/pythonx directories (for python 2, python 3 and both respectively).
              +See |python-special-path|.
              +
              +Added possibility to work with |tabpage|s through |python-tabpage| object.
              +
              +Added automatic conversion of vim errors and exceptions to python
              +exceptions.
              +
              +Changed the behavior of |python-buffers| object: it now uses buffer numbers
              +as keys in place of the index of the buffer in the internal buffer list.
              +This should not break anything as the only way to get this index was
              +iterating over |python-buffers|.
              +
              +Added |:pydo| and |:py3do| commands.
              +
              +Added |pyeval()| and |py3eval()| functions.
              +
              +Now in all places which previously accepted `str()` objects in both python
              +version both `str()` and `unicode()` (python 2) or `bytes()` and `str()`
              +(python 3) are accepted.
              +
              +|python-window| has gained `.col` and `.row` attributes that are currently
              +the only way to get internal window positions.
              +
              +Added or fixed support for `dir()` in vim python objects.
              +
              +Old python versions (≤2.2) are no longer supported. Building with them did
              +not work anyway.

              Changed *changed-7.4*
              -------

              -Todo.
              -
              +Functions:
              + Added ability to use |Dictionary-function|s for |sort()|ing, via
              + optional third argument. (Nikolay Pavlov)
              +
              + Added special |expand()| argument that expands to the current line
              + number.
              +
              + Made it possible to force |char2nr()| always give unicode codepoints
              + regardless of current encoding. (Yasuhiro Matsumoto)
              +
              + Made it possible for functions generating file list generate |List|
              + and not NL-separated string. (e.g. |glob()|, |expand()|) (Christian
              + Brabandt)
              +
              + Functions that obtain variables from the specific window, tabpage or
              + buffer scope dictionary can now return specified default value in
              + place of empty string in case variable is not found. (|gettabvar()|,
              + |getwinvar()|, |getbufvar()|) (Shougo Matsushita, Hirohito Higashi)
              +
              +Options:
              + Added ability to automatically save selection into the system
              + clipboard when using non-GUI version of vim (autoselectplus in
              + 'clipboard'). Also added ability to use system clipboard as default
              + register (previously only primary selection could be used). (Ivan
              + Krasilnikov, Christian Brabandt, Bram Moolenaar)
              +
              + Added special 'shiftwidth' value that makes 'sw' follow 'tabstop'. As
              + indenting via 'indentexpr' became tricky |shiftwidth()| function was
              + added. Also added equivalent special value to 'softtabstop' option.
              + (Christian Brabandt, so8res)
              +
              + Added ability to delete comment leader when using |J| by `j` flag in
              + 'formatoptions' (|fo-table|). (Lech Lorens)
              +
              + Added ability to control indentation inside namespaces: |cino-N|.
              + (Konstantin Lepa)
              +
              + Added ability to control alignment inside `if` condition separately
              + from alignment inside function arguments: |cino-k|. (Lech Lorens)
              +
              + Added ability to show absolute number in number column when
              + 'relativenumber' option is on. (Christian Brabandt)
              +
              +Comands:
              + Made it possible to remove all signs from the current buffer using
              + |:sign-unplace|. (Christian Brabandt)
              +
              + Added |:language| autocompletion. (Dominique Pelle)
              +
              + |:diffoff| now saves the local values of some settings and restores
              + them in place of blindly resetting them to the defaults. (Christian
              + Brabandt)
              +
              + Added |:map-nowait| creating mapping which when having lhs that is the
              + prefix of another mapping’s lhs will not allow vim to wait for user to
              + type more characters to resolve ambiguity, forcing vim to take the
              + shorter alternative: one with <nowait>.
              +
              + Added more |:command-complete| completion types: |:behave| suboptions,
              + color schemes, compilers, |:cscope| suboptions, files from 'path',
              + |:history| suboptions, locale names, |:syntime| suboptions, user
              + names. (Dominique Pelle)
              +
              +Other:
              + Improved support for cmd.exe. (Ben Fritz, Bram Moolenaar)
              +
              + Added |v:windowid| variable containing current window number in GUI
              + vim. (Christian J. Robinson, Lech Lorens)
              +
              + Lua interface now also uses userdata binded to vim structures. (Taro
              + Muraoka, Luis Carvalho)
              +
              + Added rxvt-unicode and >xterm-277 mouse support. (Yiding Jia, Hayaki
              + Saito)

              Added *added-7.4*
              -----

              +Added support for |Lists| and |Dictionaries| in |viminfo|. (Christian
              +Brabandt)
              +
              +Functions:
              + Bitwise functions: |and()|, |or()|, |invert()|, |xor()|.
              +
              + Added |luaeval()| function. (Taro Muraoka, Luis Carvalho)
              +
              + Added |sha256()| function. (Tyru, Hirohito Higashi)
              +
              + Added |wildmenumode()| function. (Christian Brabandt)
              +
              + Debugging functions: |screenattr()|, |screenchar()|, |screencol()|,
              + |screenrow()|. (Simon Ruderich, Bram Moolenaar)
              +
              +Autocommands:
              + Added |InsertCharPre| event launched before inserting character.
              + (Jakson A. Aquino)
              +
              + Added |CompleteDone| event launched after finishing completion in
              + insert mode. (idea by Florian Klein)
              +
              + Added |QuitPre| event launched when commands that can either close vim
              + or only some window(s) are launched.
              +
              + Added |TextChanged| and |TextChangedI| events launched when text is
              + changed.
              +
              +Commands:
              + |:syntime| command useful for debugging.
              +
              +Options:
              + Made it possible to ignore case when completing: 'wildignorecase'.
              +
              Various syntax, indent and other plugins were added.


              diff -r f2f3329c80d1 -r a6952dd2b722 src/eval.c
              --- a/src/eval.c Wed Jul 17 22:35:39 2013 +0200
              +++ b/src/eval.c Sat Jul 20 16:03:38 2013 +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
              @@ -166,7 +167,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
              @@ -188,16 +188,31 @@
              #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.
              @@ -269,9 +284,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;


              @@ -438,17 +457,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));
              @@ -794,6 +812,7 @@
              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 runevent, int raise));
              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));
              @@ -818,8 +837,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));
              @@ -835,6 +855,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.
              */
              @@ -1558,10 +1583,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;
              @@ -1573,11 +1598,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), TRUE);
              + if (func == NULL)
              + {
              + vim_free(argvars);
              + return FAIL;
              + }
              +
              for (i = 0; i < argc; i++)
              {
              /* Pass a NULL or empty argument as an empty string */
              @@ -1612,9 +1645,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;
              @@ -1625,6 +1658,8 @@
              if (ret == FAIL)
              clear_tv(rettv);

              + func_unref(func);
              +
              return ret;
              }

              @@ -3382,8 +3417,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;
              @@ -3403,14 +3437,14 @@
              return;
              }

              - tofree = trans_function_name(&arg, eap->skip, TFN_INT, &fudi);
              + func = get_called_function(&arg, eap->skip, &fudi, TRUE, TRUE);
              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
              @@ -3418,10 +3452,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);
              @@ -3457,7 +3487,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)
              {
              @@ -3499,8 +3529,8 @@
              }

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

              /*
              @@ -4471,12 +4501,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;
              }
              @@ -5145,21 +5180,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, TRUE);
              + 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;
              }

              @@ -6120,9 +6173,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;
              @@ -7414,7 +7471,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);
              @@ -7593,8 +7650,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:
              @@ -7675,10 +7732,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:
              @@ -7699,17 +7756,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);
              @@ -7720,10 +7785,12 @@
              s = r = alloc(len);
              if (r != NULL)
              {
              - if (function)
              - {
              - STRCPY(r, "function('");
              - r += 10;
              + if (fname_u)
              + {
              + STRCPY(r, fname_u);
              + r += flen;
              + *r++ = '(';
              + *r++ = '\'';
              }
              else
              *r++ = '\'';
              @@ -7735,7 +7802,7 @@
              MB_COPY_CHAR(p, r);
              }
              *r++ = '\'';
              - if (function)
              + if (fname_u)
              *r++ = ')';
              *r++ = NUL;
              }
              @@ -7828,321 +7895,323 @@
              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},
              - {"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},
              + {"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},
              + {"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)
              @@ -8236,9 +8305,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 */
              {
              @@ -8259,39 +8328,160 @@
              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.
              + *
              + * With runevent set to FALSE FuncUndefined event is not called.
              + */
              + func_T *
              +deref_func_name(name, len, runevent)
              char_u *name;
              - int *lenp;
              + const int len;
              + int runevent;
              {
              dictitem_T *v;
              int cc;
              -
              - cc = name[*lenp];
              - name[*lenp] = NUL;
              + func_T *r = NULL;
              +
              + cc = name[len];
              + name[len] = NUL;
              v = find_var(name, NULL);
              - name[*lenp] = cc;
              + name[len] = 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;
              + 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 (runevent
              + && 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 (vim_strchr(fname, AUTOLOAD_CHAR) != NULL)
              + {
              + 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;
              }

              /*
              @@ -8299,10 +8489,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 */
              @@ -8339,15 +8528,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)
              @@ -8357,17 +8551,75 @@
              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 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 */
              +};
              +
              + 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"
              @@ -8375,212 +8627,130 @@
              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;
              + /* Try loading a package. */
              + if (aufp->auf_func == NULL && script_autoload(aufp->auf_name, TRUE) &&
              + !aborting())
              + /* loaded a package, search for the function again */
              + aufp->auf_func = deref_func_name(aufp->auf_name,
              + STRLEN(aufp->auf_name),
              + TRUE);
              +
              + 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 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 */
              +};
              +
              +/*
              + * 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;
              }

              /*
              @@ -9212,8 +9382,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;
              @@ -9239,9 +9409,9 @@
              }

              if (item == NULL)
              - r = call_func(name, (int)STRLEN(name), rettv, argc, argv,
              + r = call_func(func, rettv, argc, argv,
              curwin->w_cursor.lnum, curwin->w_cursor.lnum,
              - &dummy, TRUE, selfdict);
              + &dummy, selfdict);

              /* Free the arguments. */
              while (argc > 0)
              @@ -9258,7 +9428,7 @@
              typval_T *argvars;
              typval_T *rettv;
              {
              - char_u *func;
              + func_T *func;
              dict_T *selfdict = NULL;

              if (argvars[1].v_type != VAR_LIST)
              @@ -9270,11 +9440,18 @@
              return;

              if (argvars[0].v_type == VAR_FUNC)
              - func = argvars[0].vval.v_string;
              - else
              - func = get_tv_string(&argvars[0]);
              - if (*func == NUL)
              - return; /* type error or empty name */
              + {
              + func = argvars[0].vval.v_func;
              + ++func->fv_refcount;
              + }
              + else
              + {
              + char_u *name;
              + name = get_tv_string(&argvars[0]);
              + if (name == NUL)
              + return; /* type error or empty name */
              + func = deref_func_name(name, STRLEN(name), TRUE);
              + }

              if (argvars[2].v_type != VAR_UNKNOWN)
              {
              @@ -9287,6 +9464,8 @@
              }

              (void)func_call(func, &argvars[1], selfdict, rettv);
              +
              + func_unref(func);
              }

              #ifdef FEAT_FLOAT
              @@ -10977,37 +11156,19 @@
              typval_T *rettv;
              {
              char_u *s;
              + func_T *func;

              s = get_tv_string(&argvars[0]);
              - if (s == NULL || *s == NUL || VIM_ISDIGIT(*s))
              - EMSG2(_(e_invarg2), s);
              - /* Don't check an autoload name for existence here. */
              - else if (vim_strchr(s, AUTOLOAD_CHAR) == NULL && !function_exists(s))
              - EMSG2(_("E700: Unknown function: %s"), s);
              - else
              - {
              - if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
              - {
              - char sid_buf[25];
              - int off = *s == 's' ? 2 : 5;
              -
              - /* Expand s: and <SID> into <SNR>nr_, so that the function can
              - * also be called from another script. Using trans_function_name()
              - * would also work, but some plugins depend on the name being
              - * printable text. */
              - sprintf(sid_buf, "<SNR>%ld_", (long)current_SID);
              - rettv->vval.v_string =
              - alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
              - if (rettv->vval.v_string != NULL)
              - {
              - STRCPY(rettv->vval.v_string, sid_buf);
              - STRCAT(rettv->vval.v_string, s + off);
              - }
              - }
              - else
              - rettv->vval.v_string = vim_strsave(s);
              +
              + func = deref_func_name(s, STRLEN(s), FALSE);
              +
              + if (func != NULL)
              + {
              rettv->v_type = VAR_FUNC;
              - }
              + rettv->vval.v_func = func;
              + }
              + else
              + EMSG2(_(e_unknown_function), s);
              }

              /*
              @@ -16948,7 +17109,7 @@
              item_compare2 __ARGS((const void *s1, const void *s2));

              static int item_compare_ic;
              -static char_u *item_compare_func;
              +static func_T *item_compare_func;
              static dict_T *item_compare_selfdict;
              static int item_compare_func_err;
              #define ITEM_COMPARE_FAIL 999
              @@ -17008,8 +17169,8 @@
              copy_tv(&(*(listitem_T **)s2)->li_tv, &argv[1]);

              rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
              - res = call_func(item_compare_func, (int)STRLEN(item_compare_func),
              - &rettv, 2, argv, 0L, 0L, &dummy, TRUE,
              + res = call_func(item_compare_func,
              + &rettv, 2, argv, 0L, 0L, &dummy,
              item_compare_selfdict);
              clear_tv(&argv[0]);
              clear_tv(&argv[1]);
              @@ -17061,7 +17222,10 @@
              {
              /* optional second argument: {func} */
              if (argvars[1].v_type == VAR_FUNC)
              - item_compare_func = argvars[1].vval.v_string;
              + {
              + item_compare_func = argvars[1].vval.v_func;
              + ++item_compare_func->fv_refcount;
              + }
              else
              {
              int error = FALSE;
              @@ -17072,7 +17236,18 @@
              if (i == 1)
              item_compare_ic = TRUE;
              else
              - item_compare_func = get_tv_string(&argvars[1]);
              + {
              + char_u *name;
              +
              + name = get_tv_string(&argvars[1]);
              + if (*name == NUL)
              + return;
              +
              + item_compare_func = deref_func_name(name, STRLEN(name),
              + TRUE);
              + if (item_compare_func == NULL)
              + return;
              + }
              }

              if (argvars[2].v_type != VAR_UNKNOWN)
              @@ -17117,6 +17292,8 @@
              }
              }

              + func_unref(item_compare_func);
              +
              vim_free(ptrs);
              }
              }
              @@ -19795,13 +19972,14 @@
              {
              if (**arg == '(')
              {
              + func_T *func;
              /* need to copy the funcref so that we can clear rettv */
              <br/><br/>(Message over 64 KB, truncated)
            • ZyX
              ... Fixed valgrind error: the error I reported at https://groups.google.com/forum/#!topic/vim_dev/ZEOh9SeZ2ZY. Deduced (but not checked) possible problems:
              Message 6 of 22 , Sep 22, 2013
              • 0 Attachment
                On Saturday, July 20, 2013 4:06:47 PM UTC+4, ZyX wrote:
                > On Saturday, July 20, 2013 3:26:00 PM UTC+4, ZyX wrote:
                > > On Friday, July 19, 2013 8:59:14 AM UTC+4, ZyX wrote:
                > > > Fixed “Unknown function” errors, now it crashes with some problems related to selfdict reported by valgrind.
                > >
                > > Fixed crash and error reported when using exists('*dict.non_func_ref'), merged branch with upstream. Problems with sort(, function()) popped out, also some invalid reads/writes at exit reported by valgrind.
                >
                > Fixed sort(, funcref).

                Fixed valgrind error: the error I reported at https://groups.google.com/forum/#!topic/vim_dev/ZEOh9SeZ2ZY.

                Deduced (but not checked) possible problems: profiling and debugging.

                For the first I will definitely remove the “Functions that are deleted before Vim exits will not produce profiling information.” statement as I almost completely sure this is implementation problem that will prevent profiling new unnamed function references. It is probably also good idea to add `profile flush` command that will write profiling data to disk and clear it (then `profile pause`+`profile flush` pair will be an equivalent to exiting vim after profiling).

                For the second it may appear that I do not need to do anything.


                I have also a good idea for unnamed functions: binddict(funcref, dict) function that will return a function reference (passed as an argument) binded to the dictionary: an equivalent to python binded methods. Though I likely will not write the implementation until main patch is accepted.

                diff -r c6d1b4d451d4 -r 33ef6b2e551c runtime/doc/if_pyth.txt
                --- a/runtime/doc/if_pyth.txt Sun Sep 22 15:43:37 2013 +0200
                +++ b/runtime/doc/if_pyth.txt Sun Sep 22 22:38:28 2013 +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 c6d1b4d451d4 -r 33ef6b2e551c src/eval.c
                --- a/src/eval.c Sun Sep 22 15:43:37 2013 +0200
                +++ b/src/eval.c Sun Sep 22 22:38:28 2013 +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
                @@ -166,7 +167,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
                @@ -188,16 +188,31 @@
                #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.
                @@ -269,9 +284,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;


                @@ -438,17 +457,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));
                @@ -794,6 +812,7 @@
                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 runevent, int raise));
                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));
                @@ -818,8 +837,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));
                @@ -835,6 +855,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.
                */
                @@ -917,10 +942,9 @@

                /* script-local variables */
                for (i = 1; i <= ga_scripts.ga_len; ++i)
                - {
                vars_clear(&SCRIPT_VARS(i));
                + for (i = 1; i <= ga_scripts.ga_len; ++i)
                vim_free(SCRIPT_SV(i));
                - }
                ga_clear(&ga_scripts);

                /* unreferenced lists and dicts */
                @@ -1558,10 +1582,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;
                @@ -1573,11 +1597,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), TRUE);
                + if (func == NULL)
                + {
                + vim_free(argvars);
                + return FAIL;
                + }
                +
                for (i = 0; i < argc; i++)
                {
                /* Pass a NULL or empty argument as an empty string */
                @@ -1612,9 +1644,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;
                @@ -1625,6 +1657,8 @@
                if (ret == FAIL)
                clear_tv(rettv);

                + func_unref(func);
                +
                return ret;
                }

                @@ -3382,8 +3416,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;
                @@ -3403,14 +3436,14 @@
                return;
                }

                - tofree = trans_function_name(&arg, eap->skip, TFN_INT, &fudi);
                + func = get_called_function(&arg, eap->skip, &fudi, TRUE, TRUE);
                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
                @@ -3418,10 +3451,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);
                @@ -3457,7 +3486,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)
                {
                @@ -3499,8 +3528,8 @@
                }

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

                /*
                @@ -4471,12 +4500,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;
                }
                @@ -5145,21 +5179,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, TRUE);
                + 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;
                }

                @@ -6120,9 +6172,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;
                @@ -7414,7 +7470,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);
                @@ -7593,8 +7649,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:
                @@ -7675,10 +7731,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:
                @@ -7699,17 +7755,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);
                @@ -7720,13 +7784,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; )
                {
                @@ -7735,7 +7799,7 @@
                MB_COPY_CHAR(p, r);
                }
                *r++ = '\'';
                - if (function)
                + if (fname_u)
                *r++ = ')';
                *r++ = NUL;
                }
                @@ -7828,321 +7892,323 @@
                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},
                - {"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},
                + {"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},
                + {"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)
                @@ -8236,9 +8302,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 */
                {
                @@ -8259,39 +8325,160 @@
                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.
                + *
                + * With runevent set to FALSE FuncUndefined event is not called.
                + */
                + func_T *
                +deref_func_name(name, len, runevent)
                char_u *name;
                - int *lenp;
                + const int len;
                + int runevent;
                {
                dictitem_T *v;
                int cc;
                -
                - cc = name[*lenp];
                - name[*lenp] = NUL;
                + func_T *r = NULL;
                +
                + cc = name[len];
                + name[len] = NUL;
                v = find_var(name, NULL);
                - name[*lenp] = cc;
                + name[len] = 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;
                + 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 (runevent
                + && 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 (vim_strchr(fname, AUTOLOAD_CHAR) != NULL)
                + {
                + 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;
                }

                /*
                @@ -8299,10 +8486,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 */
                @@ -8339,15 +8525,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)
                @@ -8357,17 +8548,75 @@
                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 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 */
                +};
                +
                + 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"
                @@ -8375,212 +8624,130 @@
                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;
                + /* Try loading a package. */
                + if (aufp->auf_func == NULL && script_autoload(aufp->auf_name, TRUE) &&
                + !aborting())
                + /* loaded a package, search for the function again */
                + aufp->auf_func = deref_func_name(aufp->auf_name,
                + STRLEN(aufp->auf_name),
                + TRUE);
                +
                + 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 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 */
                +};
                +
                +/*
                + * 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;
                }

                /*
                @@ -9212,8 +9379,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;
                @@ -9239,9 +9406,9 @@
                }

                if (item == NULL)
                - r = call_func(name, (int)STRLEN(name), rettv, argc, argv,
                + r = call_func(func, rettv, argc, argv,
                curwin->w_cursor.lnum, curwin->w_cursor.lnum,
                - &dummy, TRUE, selfdict);
                + &dummy, selfdict);

                /* Free the arguments. */
                while (argc > 0)
                @@ -9258,7 +9425,7 @@
                typval_T *argvars;
                typval_T *rettv;
                {
                - char_u *func;
                + func_T *func;
                dict_T *selfdict = NULL;

                if (argvars[1].v_type != VAR_LIST)
                @@ -9270,11 +9437,18 @@
                return;

                if (argvars[0].v_type == VAR_FUNC)
                - func = argvars[0].vval.v_string;
                - else
                - func = get_tv_string(&argvars[0]);
                - if (*func == NUL)
                - return; /* type error or empty name */
                + {
                + func = argvars[0].vval.v_func;
                + ++func->fv_refcount;
                + }
                + else
                + {
                + char_u *name;
                + name = get_tv_string(&argvars[0]);
                + if (name == NUL)
                + return; /* type error or empty name */
                + func = deref_func_name(name, STRLEN(name), TRUE);
                + }

                if (argvars[2].v_type != VAR_UNKNOWN)
                {
                @@ -9287,6 +9461,8 @@
                }

                (void)func_call(func, &argvars[1], selfdict, rettv);
                +
                + func_unref(func);
                }

                #ifdef FEAT_FLOAT
                @@ -10977,37 +11153,19 @@
                typval_T *rettv;
                {
                char_u *s;
                + func_T *func;

                s = get_tv_string(&argvars[0]);
                - if (s == NULL || *s == NUL || VIM_ISDIGIT(*s))
                - EMSG2(_(e_invarg2), s);
                - /* Don't check an autoload name for existence here. */
                - else if (vim_strchr(s, AUTOLOAD_CHAR) == NULL && !function_exists(s))
                - EMSG2(_("E700: Unknown function: %s"), s);
                - else
                - {
                - if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
                - {
                - char sid_buf[25];
                - int off = *s == 's' ? 2 : 5;
                -
                - /* Expand s: and <SID> into <SNR>nr_, so that the function can
                - * also be called from another script. Using trans_function_name()
                - * would also work, but some plugins depend on the name being
                - * printable text. */
                - sprintf(sid_buf, "<SNR>%ld_", (long)current_SID);
                - rettv->vval.v_string =
                - alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
                - if (rettv->vval.v_string != NULL)
                - {
                - STRCPY(rettv->vval.v_string, sid_buf);
                - STRCAT(rettv->vval.v_string, s + off);
                - }
                - }
                - else
                - rettv->vval.v_string = vim_strsave(s);
                +
                + func = deref_func_name(s, STRLEN(s), FALSE);
                +
                + if (func != NULL)
                + {
                rettv->v_type = VAR_FUNC;
                - }
                + rettv->vval.v_func = func;
                + }
                + else
                + EMSG2(_(e_unknown_function), s);
                }

                /*
                @@ -16965,7 +17123,7 @@
                item_compare2 __ARGS((const void *s1, const void *s2));

                static int item_compare_ic;
                -static char_u *item_compare_func;
                +static func_T *item_compare_func;
                static dict_T *item_compare_selfdict;
                static int item_compare_func_err;
                #define ITEM_COMPARE_FAIL 999
                @@ -17025,8 +17183,8 @@
                copy_tv(&(*(listitem_T **)s2)->li_tv, &argv[1]);

                rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
                - res = call_func(item_compare_func, (int)STRLEN(item_compare_func),
                - &rettv, 2, argv, 0L, 0L, &dummy, TRUE,
                + res = call_func(item_compare_func,
                + &rettv, 2, argv, 0L, 0L, &dummy,
                item_compare_selfdict);
                clear_tv(&argv[0]);
                clear_tv(&argv[1]);
                @@ -17078,7 +17236,10 @@
                {
                /* optional second argument: {func} */
                if (argvars[1].v_type == VAR_FUNC)
                - item_compare_func = argvars[1].vval.v_string;
                + {
                + item_compare_func = argvars[1].vval.v_func;
                + ++item_compare_func->fv_refcount;
                + }
                else
                {
                int error = FALSE;
                @@ -17089,7 +17250,18 @@
                if (i == 1)
                item_compare_ic = TRUE;
                else
                - item_compare_func = get_tv_string(&argvars[1]);
                + {
                + char_u *name;
                +
                + name = get_tv_string(&argvars[1]);
                + if (*name == NUL)
                + return;
                +
                + item_compare_func = deref_func_name(name, STRLEN(name),
                + TRUE);
                + if (item_compare_func == NULL)
                + return;
                + }
                }

                if (argvars[2].v_type != VAR_UNKNOWN)
                @@ -17134,6 +17306,8 @@
                }
                }

                + func_unref(item_compare_func);
                +
                vim_free(ptrs);
                }
                }
                @@ -19812,13 +19986,14 @@
                {
                if (**arg == '(')
                {
                + func_T *func;
                /* need to copy the funcref so that we can clear rettv */
                functv = *rettv;
                rettv->v_type = VAR_UNKNOWN;

                /* Invoke the function. Recursive! */
                - s = functv.vval.v_string;
                - ret = get_func_tv(s, (int)STRLEN(s), rettv, arg,
                + func = functv.vval.v_func;
                + ret = get_func_tv(func, rettv, arg,
                curwin->w_cursor.lnum, curwin->w_cursor.lnum,
                &len, evaluate, selfdict);

                @@ -19904,8 +20079,8 @@
                switch (varp->v_type)
                {
                case VAR_FUNC:
                - func_unref(varp->vval.v_string);
                - /*FALLTHROUGH*/
                + func_unref(varp->vval.v_func);
                + break;
                case VAR_STRING:
                vim_free(varp->vval.v_string);
                break;
                @@ -19941,8 +20116,9 @@
                switch (varp->v_type)
                {
                case VAR_FUNC:
                - func_unref(varp->vval.v_string);
                - /*FALLTHROUGH*/
                + func_unref(varp->vval.v_func);
                + varp->vval.v_func = NULL;
                + break;
                case VAR_STRING:
                vim_free(varp->vval.v_string);
                varp->vval.v_string = NULL;
                @@ -20756,14 +20932,18 @@
                break;
                #endif
                case VAR_STRING:
                - case VAR_FUNC:
                if (from->vval.v_string == NULL)
                to->vval.v_string = NULL;
                else
                - {
                to->vval.v_string = vim_strsave(from->vval.v_string);
                - if (from->v_type == VAR_FUNC)
                - func_ref(to->vval.v_string);
                + break;
                + case VAR_FUNC:
                + if (from->vval.v_func == NULL)
                + to->vval.v_func = NULL;
                + else
                + {
                + to->vval.v_func = from->vval.v_func;
                + ++to->vval.v_func->fv_refcount;
                }
                break;
                case VAR_LIST:
                @@ -21141,12 +21321,12 @@
                char_u *skip_until = NULL;
                dictitem_T *v;
                funcdict_T fudi;
                - static int func_nr = 0; /* number for nameless function */
                int paren;
                hashtab_T *ht;
                int todo;
                hashitem_T *hi;
                int sourcing_lnum_off;
                + int name_len;

                /*
                * ":function" without argument: list functions.
                @@ -21226,8 +21406,13 @@
                */
                p = eap->arg;
                name = trans_function_name(&p, eap->skip, 0, &fudi);
                + name_len = p - eap->arg;
                paren = (vim_strchr(p, '(') != NULL);
                - if (name == NULL && (fudi.fd_dict == NULL || !paren) && !eap->skip)
                + if (name == NULL
                + && (paren
                + ? (fudi.fd_dict == NULL)
                + : (fudi.fd_func == NULL))
                + && !eap->skip)
                {
                /*
                * Return on an invalid expression in braces, unless the expression
                @@ -21265,7 +21450,11 @@
                *p = NUL;
                if (!eap->skip && !got_int)
                {
                - fp = find_func(name);
                + if (fudi.fd_func != NULL
                + && fudi.fd_func->fv_type == &user_func_type)
                + fp = (ufunc_T *) fudi.fd_func->fv_data;
                + else
                + fp = find_func(name);
                if (fp != NULL)
                {
                list_func_head(fp, TRUE);
                @@ -21637,23 +21826,10 @@
                emsg_funcname(e_funcexts, name);
                goto erret;
                }
                - if (fp->uf_calls > 0)
                - {
                - emsg_funcname(N_("E127: Cannot redefine function %s: It is in use"),
                - name);
                - goto erret;
                - }
                - /* redefine existing function */
                - ga_clear_strings(&(fp->uf_args));
                - ga_clear_strings(&(fp->uf_lines));
                - vim_free(name);
                - name = NULL;
                - }
                - }
                - else
                - {
                - char numbuf[20];
                -
                + }
                + }
                + else
                + {
                fp = NULL;
                if (fudi.fd_newkey == NULL && !eap->forceit)
                {
                @@ -21670,83 +21846,99 @@
                else if (tv_check_lock(fudi.fd_di->di_tv.v_lock, eap->arg))
                goto erret;

                - /* Give the function a sequential number. Can only be used with a
                - * Funcref! */
                vim_free(name);
                - sprintf(numbuf, "%d", ++func_nr);
                - name = vim_strsave((char_u *)numbuf);
                + name = vim_strnsave(eap->arg, name_len);
                + flags |= FC_ANON;
                if (name == NULL)
                goto erret;
                }

                + if (fp != NULL)
                + {
                + remove_user_func(fp);
                + func_unref(fp->uf_func);
                + fp = NULL;
                + }
                +
                + if (fudi.fd_dict == NULL && vim_strchr(name, AUTOLOAD_CHAR) != NULL)
                + {
                + int slen, plen;
                + char_u *scriptname;
                +
                + /* Check that the autoload name matches the script name. */
                + j = FAIL;
                + if (sourcing_name != NULL)
                + {
                + scriptname = autoload_name(name);
                + if (scriptname != NULL)
                + {
                + p = vim_strchr(scriptname, '/');
                + plen = (int)STRLEN(p);
                + slen = (int)STRLEN(sourcing_name);
                + if (slen > plen && fnamecmp(p,
                + sourcing_name + slen - plen) == 0)
                + j = OK;
                + vim_free(scriptname);
                + }
                + }
                + if (j == FAIL)
                + {
                + EMSG2(_("E746: Function name does not match script file name: %s"), name);
                + goto erret;
                + }
                + }
                +
                + fp = (ufunc_T *)alloc((unsigned)(sizeof(ufunc_T) + STRLEN(name)));
                if (fp == NULL)
                - {
                - if (fudi.fd_dict == NULL && vim_strchr(name, AUTOLOAD_CHAR) != NULL)
                - {
                - int slen, plen;
                - char_u *scriptname;
                -
                - /* Check that the autoload name matches the script name. */
                - j = FAIL;
                - if (sourcing_name != NULL)
                - {
                - scriptname = autoload_name(name);
                - if (scriptname != NULL)
                - {
                - p = vim_strchr(scriptname, '/');
                - plen = (int)STRLEN(p);
                - slen = (int)STRLEN(sourcing_name);
                - if (slen > plen && fnamecmp(p,
                - sourcing_name + slen - plen) == 0)
                - j = OK;
                - vim_free(scriptname);
                - }
                - }
                - if (j == FAIL)
                - {
                - EMSG2(_("E746: Function name does not match script file name: %s"), name);
                + goto erret;
                +
                + fp->uf_func = func_alloc();
                + if (fp->uf_func == NULL)
                + {
                + vim_free(fp);
                + goto erret;
                + }
                +
                + fp->uf_func->fv_data = fp;
                + ++fp->uf_func->fv_refcount;
                + fp->uf_func->fv_type = &user_func_type;
                +
                + if (fudi.fd_dict != NULL)
                + {
                + if (fudi.fd_di == NULL)
                + {
                + /* add new dict entry */
                + fudi.fd_di = dictitem_alloc(fudi.fd_<br/><br/>(Message over 64 KB, truncated)
              • ZyX
                ... Profiling was definitely a problem. This version fixes it by saving profiling data into a linked list. I also have a patch for ... that writes data to disk
                Message 7 of 22 , Sep 22, 2013
                • 0 Attachment
                  > Fixed valgrind error: the error I reported at https://groups.google.com/forum/#!topic/vim_dev/ZEOh9SeZ2ZY.
                  >
                  > Deduced (but not checked) possible problems: profiling and debugging.
                  >
                  > For the first I will definitely remove the “Functions that are deleted before Vim exits will not produce profiling information.” statement as I almost completely sure this is implementation problem that will prevent profiling new unnamed function references. It is probably also good idea to add `profile flush` command that will write profiling data to disk and clear it (then `profile pause`+`profile flush` pair will be an equivalent to exiting vim after profiling).
                  >
                  > For the second it may appear that I do not need to do anything.

                  Profiling was definitely a problem. This version fixes it by saving profiling data into a linked list. I also have a patch for

                  :profile stop

                  that writes data to disk and deletes profiling information, but it is not included here. Will post once I add tests. It is available at profile-stop bookmark at https://bitbucket.org/ZyX_I/vim.


                  diff -r c6d1b4d451d4 -r d6c8e263d37b runtime/doc/if_pyth.txt
                  --- a/runtime/doc/if_pyth.txt Sun Sep 22 15:43:37 2013 +0200
                  +++ b/runtime/doc/if_pyth.txt Mon Sep 23 08:35:31 2013 +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 c6d1b4d451d4 -r d6c8e263d37b src/eval.c
                  --- a/src/eval.c Sun Sep 22 15:43:37 2013 +0200
                  +++ b/src/eval.c Mon Sep 23 08:35:31 2013 +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
                  @@ -166,7 +167,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 +185,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 +227,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 +291,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;


                  @@ -438,17 +464,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));
                  @@ -794,6 +819,7 @@
                  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 runevent, int raise));
                  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));
                  @@ -802,6 +828,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
                  @@ -818,8 +845,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));
                  @@ -835,6 +863,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.
                  */
                  @@ -917,10 +950,9 @@

                  /* script-local variables */
                  for (i = 1; i <= ga_scripts.ga_len; ++i)
                  - {
                  vars_clear(&SCRIPT_VARS(i));
                  + for (i = 1; i <= ga_scripts.ga_len; ++i)
                  vim_free(SCRIPT_SV(i));
                  - }
                  ga_clear(&ga_scripts);

                  /* unreferenced lists and dicts */
                  @@ -1558,10 +1590,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;
                  @@ -1573,11 +1605,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), TRUE);
                  + if (func == NULL)
                  + {
                  + vim_free(argvars);
                  + return FAIL;
                  + }
                  +
                  for (i = 0; i < argc; i++)
                  {
                  /* Pass a NULL or empty argument as an empty string */
                  @@ -1612,9 +1652,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;
                  @@ -1625,6 +1665,8 @@
                  if (ret == FAIL)
                  clear_tv(rettv);

                  + func_unref(func);
                  +
                  return ret;
                  }

                  @@ -3382,8 +3424,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;
                  @@ -3403,14 +3444,14 @@
                  return;
                  }

                  - tofree = trans_function_name(&arg, eap->skip, TFN_INT, &fudi);
                  + func = get_called_function(&arg, eap->skip, &fudi, TRUE, TRUE);
                  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
                  @@ -3418,10 +3459,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);
                  @@ -3457,7 +3494,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)
                  {
                  @@ -3499,8 +3536,8 @@
                  }

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

                  /*
                  @@ -4471,12 +4508,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;
                  }
                  @@ -5145,21 +5187,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, TRUE);
                  + 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;
                  }

                  @@ -6120,9 +6180,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;
                  @@ -7414,7 +7478,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);
                  @@ -7593,8 +7657,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:
                  @@ -7675,10 +7739,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:
                  @@ -7699,17 +7763,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);
                  @@ -7720,13 +7792,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; )
                  {
                  @@ -7735,7 +7807,7 @@
                  MB_COPY_CHAR(p, r);
                  }
                  *r++ = '\'';
                  - if (function)
                  + if (fname_u)
                  *r++ = ')';
                  *r++ = NUL;
                  }
                  @@ -7828,321 +7900,323 @@
                  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},
                  - {"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},
                  + {"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},
                  + {"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)
                  @@ -8236,9 +8310,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 */
                  {
                  @@ -8259,39 +8333,160 @@
                  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.
                  + *
                  + * With runevent set to FALSE FuncUndefined event is not called.
                  + */
                  + func_T *
                  +deref_func_name(name, len, runevent)
                  char_u *name;
                  - int *lenp;
                  + const int len;
                  + int runevent;
                  {
                  dictitem_T *v;
                  int cc;
                  -
                  - cc = name[*lenp];
                  - name[*lenp] = NUL;
                  + func_T *r = NULL;
                  +
                  + cc = name[len];
                  + name[len] = NUL;
                  v = find_var(name, NULL);
                  - name[*lenp] = cc;
                  + name[len] = 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;
                  + 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 (runevent
                  + && 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 (vim_strchr(fname, AUTOLOAD_CHAR) != NULL)
                  + {
                  + 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;
                  }

                  /*
                  @@ -8299,10 +8494,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 */
                  @@ -8339,15 +8533,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)
                  @@ -8357,17 +8556,75 @@
                  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 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 */
                  +};
                  +
                  + 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"
                  @@ -8375,212 +8632,130 @@
                  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;
                  + /* Try loading a package. */
                  + if (aufp->auf_func == NULL && script_autoload(aufp->auf_name, TRUE) &&
                  + !aborting())
                  + /* loaded a package, search for the function again */
                  + aufp->auf_func = deref_func_name(aufp->auf_name,
                  + STRLEN(aufp->auf_name),
                  + TRUE);
                  +
                  + 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 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 */
                  +};
                  +
                  +/*
                  + * 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;
                  }

                  /*
                  @@ -9212,8 +9387,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;
                  @@ -9239,9 +9414,9 @@
                  }

                  if (item == NULL)
                  - r = call_func(name, (int)STRLEN(name), rettv, argc, argv,
                  + r = call_func(func, rettv, argc, argv,
                  curwin->w_cursor.lnum, curwin->w_cursor.lnum,
                  - &dummy, TRUE, selfdict);
                  + &dummy, selfdict);

                  /* Free the arguments. */
                  while (argc > 0)
                  @@ -9258,7 +9433,7 @@
                  typval_T *argvars;
                  typval_T *rettv;
                  {
                  - char_u *func;
                  + func_T *func;
                  dict_T *selfdict = NULL;

                  if (argvars[1].v_type != VAR_LIST)
                  @@ -9270,11 +9445,18 @@
                  return;

                  if (argvars[0].v_type == VAR_FUNC)
                  - func = argvars[0].vval.v_string;
                  - else
                  - func = get_tv_string(&argvars[0]);
                  - if (*func == NUL)
                  - return; /* type error or empty name */
                  + {
                  + func = argvars[0].vval.v_func;
                  + ++func->fv_refcount;
                  + }
                  + else
                  + {
                  + char_u *name;
                  + name = get_tv_string(&argvars[0]);
                  + if (name == NUL)
                  + return; /* type error or empty name */
                  + func = deref_func_name(name, STRLEN(name), TRUE);
                  + }

                  if (argvars[2].v_type != VAR_UNKNOWN)
                  {
                  @@ -9287,6 +9469,8 @@
                  }

                  (void)func_call(func, &argvars[1], selfdict, rettv);
                  +
                  + func_unref(func);
                  }

                  #ifdef FEAT_FLOAT
                  @@ -10977,37 +11161,19 @@
                  typval_T *rettv;
                  {
                  char_u *s;
                  + func_T *func;

                  s = get_tv_string(&argvars[0]);
                  - if (s == NULL || *s == NUL || VIM_ISDIGIT(*s))
                  - EMSG2(_(e_invarg2), s);
                  - /* Don't check an autoload name for existence here. */
                  - else if (vim_strchr(s, AUTOLOAD_CHAR) == NULL && !function_exists(s))
                  - EMSG2(_("E700: Unknown function: %s"), s);
                  - else
                  - {
                  - if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
                  - {
                  - char sid_buf[25];
                  - int off = *s == 's' ? 2 : 5;
                  -
                  - /* Expand s: and <SID> into <SNR>nr_, so that the function can
                  - * also be called from another script. Using trans_function_name()
                  - * would also work, but some plugins depend on the name being
                  - * printable text. */
                  - sprintf(sid_buf, "<SNR>%ld_", (long)current_SID);
                  - rettv->vval.v_string =
                  - alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
                  - if (rettv->vval.v_string != NULL)
                  - {
                  - STRCPY(rettv->vval.v_string, sid_buf);
                  - STRCAT(rettv->vval.v_string, s + off);
                  - }
                  - }
                  - else
                  - rettv->vval.v_string = vim_strsave(s);
                  +
                  + func = deref_func_name(s, STRLEN(s), FALSE);
                  +
                  + if (func != NULL)
                  + {
                  rettv->v_type = VAR_FUNC;
                  - }
                  + rettv->vval.v_func = func;
                  + }
                  + else
                  + EMSG2(_(e_unknown_function), s);
                  }

                  /*
                  @@ -16965,7 +17131,7 @@
                  item_compare2 __ARGS((const void *s1, const void *s2));

                  static int item_compare_ic;
                  -static char_u *item_compare_func;
                  +static func_T *item_compare_func;
                  static dict_T *item_compare_selfdict;
                  static int item_compare_func_err;
                  #define ITEM_COMPARE_FAIL 999
                  @@ -17025,8 +17191,8 @@
                  copy_tv(&(*(listitem_T **)s2)->li_tv, &argv[1]);

                  rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
                  - res = call_func(item_compare_func, (int)STRLEN(item_compare_func),
                  - &rettv, 2, argv, 0L, 0L, &dummy, TRUE,
                  + res = call_func(item_compare_func,
                  + &rettv, 2, argv, 0L, 0L, &dummy,
                  item_compare_selfdict);
                  clear_tv(&argv[0]);
                  clear_tv(&argv[1]);
                  @@ -17078,7 +17244,10 @@
                  {
                  /* optional second argument: {func} */
                  if (argvars[1].v_type == VAR_FUNC)
                  - item_compare_func = argvars[1].vval.v_string;
                  + {
                  + item_compare_func = argvars[1].vval.v_func;
                  + ++item_compare_func->fv_refcount;
                  + }
                  else
                  {
                  int error = FALSE;
                  @@ -17089,7 +17258,18 @@
                  if (i == 1)
                  item_compare_ic = TRUE;
                  else
                  - item_compare_func = get_tv_string(&argvars[1]);
                  + {
                  + char_u *name;
                  +
                  + name = get_tv_string(&argvars[1]);
                  + if (*name == NUL)
                  + return;
                  +
                  + item_compare_func = deref_func_name(name, STRLEN(name),
                  + TRUE);
                  + if (item_compare_func == NULL)
                  + return;
                  + }
                  }

                  if (argvars[2].v_type != VAR_UNKNOWN)
                  @@ -17134,6 +17314,8 @@
                  }
                  }

                  + func_unref(item_compare_func);
                  +
                  vim_free(ptrs);
                  }
                  }
                  @@ -19812,13 +19994,14 @@
                  {
                  if (**arg == '(')
                  {
                  + func_T *func;
                  /* need to copy the funcref so that we can clear rettv */
                  functv = *rettv;
                  rettv->v_type = VAR_UNKNOWN;

                  /* Invoke the function. Recursive! */
                  - s = functv.vval.v_string;
                  - ret = get_func_tv(s, (int)STRLEN(s), rettv, arg,
                  + func = functv.vval.v_func;
                  + ret = get_func_tv(func, rettv, arg,
                  curwin->w_cursor.lnum, curwin->w_cursor.lnum,
                  &len, evaluate, selfdict);

                  @@ -19904,8 +20087,8 @@
                  switch (varp->v_type)
                  {
                  case VAR_FUNC:
                  - func_unref(varp->vval.v_string);
                  - /*FALLTHROUGH*/
                  + func_unref(varp->vval.v_func);
                  + break;
                  case VAR_STRING:
                  vim_free(varp->vval.v_string);
                  break;
                  @@ -19941,8 +20124,9 @@
                  switch (varp->v_type)
                  {
                  case VAR_FUNC:
                  - func_unref(varp->vval.v_string);
                  - /*FALLTHROUGH*/
                  + func_unref(varp->vval.v_func);
                  + varp->vval.v_func = NULL;
                  + break;
                  case VAR_STRING:
                  vim_free(varp->vval.v_string);
                  varp->vval.v_string = NULL;
                  @@ -20756,14 +20940,18 @@
                  break;
                  #endif
                  case VAR_STRING:
                  - case VAR_FUNC:
                  if (from->vval.v_string == NULL)
                  to->vval.v_string = NULL;
                  else
                  - {
                  to->vval.v_string = vim_strsave(from->vval.v_string);
                  - if (from->v_type == VAR_FUNC)
                  - func_ref(to->vval.v_string);
                  + break;
                  + case VAR_FUNC:
                  + if (from->vval.v_func == NULL)
                  + to->vval.v_func = NULL;
                  + else
                  + {
                  + to->vval.v_func = from->vval.v_func;
                  + ++to->vval.v_func->fv_refcount;
                  }
                  break;
                  case VAR_LIST:
                  @@ -21141,12 +21329,12 @@
                  char_u *skip_until = NULL;
                  dictitem_T *v;
                  funcdict_T fudi;
                  - static int func_nr = 0; /* number for nameless function */
                  int paren;
                  hashtab_T *ht;
                  int todo;
                  hashitem_T *hi;
                  int sourcing_lnum_off;
                  + int name_len;

                  /*
                  * ":function" without argument: list functions.
                  @@ -21226,8 +21414,13 @@
                  */
                  p = eap->arg;
                  name = trans_function_name(&p, eap->skip, 0, &fudi);
                  + name_len = p - eap->arg;
                  paren = (vim_strchr(p, '(') != NULL);
                  - if (name == NULL && (fudi.fd_dict == NULL || !paren) && !eap->skip)
                  + if (name == NULL
                  + && (paren
                  + ? (fudi.fd_dict == NULL)
                  + : (fudi.fd_func == NULL))
                  + && !eap->skip)
                  {
                  /*
                  * Return on an invalid expression in braces, unless the expression
                  @@ -21265,7 +21458,11 @@
                  *p = NUL;
                  if (!eap->skip && !got_int)
                  {
                  - fp = find_func(name);
                  + if (fudi.fd_func != NULL
                  + && fudi.fd_func->fv_type == &user_func_type)
                  + fp = (ufunc_T *) fudi.fd_func->fv_data;
                  + else
                  + fp = find_func(name);
                  if (fp != NULL)
                  {
                  list_func_head(fp, TRUE);
                  @@ -21637,23 +21834,10 @@
                  emsg_funcname(e_funcexts, name);
                  goto erret;
                  }
                  - if (fp->uf_calls > 0)
                  - {
                  - emsg_funcname(N_("E127: Cannot redefine function %s: It is in use"),
                  - name);
                  - goto erret;
                  - }
                  - /* redefine existing function */
                  - ga_clear_strings(&(fp->uf_args));
                  - ga_clear_strings(&(fp->uf_lines));
                  - vim_free(name);
                  - name = NULL;
                  - }
                  - }
                  - else
                  - {
                  - char numbuf[20];
                  -
                  + }
                  + }
                  + else
                  + {
                  fp = NULL;
                  if (fudi.fd_newkey == NULL && !eap->forceit)
                  {
                  @@ -21670,96 +21854,112 @@
                  else if (tv_check_lock(fudi.fd_di->di_tv.v_lock, eap->arg))
                  goto erret;

                  - /* Give the function a sequential number. Can only be used with a
                  - * Funcref! */
                  vim_free(name);
                  - sprintf(numbuf, "%d", ++func_nr);
                  - name = vim_strsave((char_u *)numbuf);
                  + name = vim_strnsave(eap->arg, name_len);
                  + flags |= FC_ANON;
                  if (name == NULL)
                  goto erret;
                  }

                  + if (fp != NULL)
                  + {
                  + remove_user_func(fp);
                  + func_unref(fp->uf_func);
                  + fp = NULL;
                  + }
                  +
                  + if (fudi.fd_dict == NULL && vim_strchr(name, AUTOLOAD_CHAR) != NULL)
                  + {
                  + int slen, plen;
                  + char_u *scriptname;
                  +
                  + /* Check that the autoload name matches the script name. */
                  + j = FAIL;
                  + if (sourcing_name != NULL)
                  + {
                  + scriptname = autoload_name(name);
                  + if (scriptname != NULL)
                  + {
                  + p = vim_strchr(scriptname, '/');
                  + plen = (int)STRLEN(p);
                  + slen = (int)STRLEN(sourcing_name);
                  + if (slen > plen && fnamecmp(p,
                  + sourcing_name + slen - plen) == 0)
                  + j = OK;
                  + vim_free(scriptname);
                  + }
                  + }
                  + if (j == FAIL)
                  + {
                  + EMSG2(_("E746: Function name does not match script file name: %s"), name);
                  + goto erret;
                  + }
                  + }
                  +
                  + fp = (ufunc_T *)alloc((unsigned)(sizeof(ufunc_T) + STRLEN(name)));
                  if (fp == NULL)
                  - {
                  - if (fudi.fd_dict == NULL && vim_strchr(name, AUTOLOAD_CHAR) != NULL)
                  - {
                  - int slen, plen;
                  - char_u *scriptname;
                  -
                  - /* Check that the autoload name matches the script name. */
                  - j = FAIL;
                  - if (sourcing_name != NULL)
                  - {
                  - scriptname = autoload_name(name);
                  - if (scriptname != NULL)
                  - {
                  - p = vim_strchr(scriptname, '/');
                  - plen = (int)STRLEN(p);
                  - slen = (int)STRLEN(sourcing_na<br/><br/>(Message over 64 KB, truncated)
                • ZyX
                  ... A few fixes: 1. Purged out note about the requirement of not deleting profiled functions from documentation. 2. function( script#function ) no longer
                  Message 8 of 22 , Sep 24, 2013
                  • 0 Attachment
                    > Profiling was definitely a problem. This version fixes it by saving profiling data into a linked list. I also have a patch for
                    >
                    > :profile stop
                    >
                    > that writes data to disk and deletes profiling information, but it is not included here. Will post once I add tests. It is available at profile-stop bookmark at https://bitbucket.org/ZyX_I/vim.

                    A few fixes:
                    1. Purged out note about the requirement of not deleting profiled functions from documentation.
                    2. function('script#function') no longer autoloads scripts
                    3. function('Funcref') no longer returns a new reference to Funcref, errorring out instead.
                    4. if Funcref is a reference to autoload function that was not defined when reference was created :fu Funcref works
                    5. trying to call a reference to an undefined autoload function no longer falls into infinite recursion

                    diff -r c6d1b4d451d4 -r 57bc5a57e6cb runtime/doc/if_pyth.txt
                    --- a/runtime/doc/if_pyth.txt Sun Sep 22 15:43:37 2013 +0200
                    +++ b/runtime/doc/if_pyth.txt Wed Sep 25 00:20:18 2013 +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 c6d1b4d451d4 -r 57bc5a57e6cb runtime/doc/repeat.txt
                    --- a/runtime/doc/repeat.txt Sun Sep 22 15:43:37 2013 +0200
                    +++ b/runtime/doc/repeat.txt Wed Sep 25 00:20:18 2013 +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 c6d1b4d451d4 -r 57bc5a57e6cb src/eval.c
                    --- a/src/eval.c Sun Sep 22 15:43:37 2013 +0200
                    +++ b/src/eval.c Wed Sep 25 00:20:18 2013 +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
                    @@ -166,7 +167,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 +185,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 +227,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 +291,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;


                    @@ -438,17 +464,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));
                    @@ -794,6 +819,7 @@
                    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 runevent, int raise));
                    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));
                    @@ -802,6 +828,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
                    @@ -818,8 +845,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));
                    @@ -835,6 +863,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.
                    */
                    @@ -917,10 +950,9 @@

                    /* script-local variables */
                    for (i = 1; i <= ga_scripts.ga_len; ++i)
                    - {
                    vars_clear(&SCRIPT_VARS(i));
                    + for (i = 1; i <= ga_scripts.ga_len; ++i)
                    vim_free(SCRIPT_SV(i));
                    - }
                    ga_clear(&ga_scripts);

                    /* unreferenced lists and dicts */
                    @@ -1558,10 +1590,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;
                    @@ -1573,11 +1605,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 */
                    @@ -1612,9 +1652,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;
                    @@ -1625,6 +1665,8 @@
                    if (ret == FAIL)
                    clear_tv(rettv);

                    + func_unref(func);
                    +
                    return ret;
                    }

                    @@ -3382,8 +3424,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;
                    @@ -3403,14 +3444,14 @@
                    return;
                    }

                    - tofree = trans_function_name(&arg, eap->skip, TFN_INT, &fudi);
                    + func = get_called_function(&arg, eap->skip, &fudi, TRUE, TRUE);
                    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
                    @@ -3418,10 +3459,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);
                    @@ -3457,7 +3494,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)
                    {
                    @@ -3499,8 +3536,8 @@
                    }

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

                    /*
                    @@ -4471,12 +4508,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;
                    }
                    @@ -5145,21 +5187,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;
                    }

                    @@ -6120,9 +6180,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;
                    @@ -7414,7 +7478,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);
                    @@ -7593,8 +7657,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:
                    @@ -7675,10 +7739,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:
                    @@ -7699,17 +7763,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);
                    @@ -7720,13 +7792,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; )
                    {
                    @@ -7735,7 +7807,7 @@
                    MB_COPY_CHAR(p, r);
                    }
                    *r++ = '\'';
                    - if (function)
                    + if (fname_u)
                    *r++ = ')';
                    *r++ = NUL;
                    }
                    @@ -7828,321 +7900,323 @@
                    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},
                    - {"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},
                    + {"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},
                    + {"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)
                    @@ -8236,9 +8310,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 */
                    {
                    @@ -8259,39 +8333,166 @@
                    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.
                    + *
                    + * With check_var set to FALSE deref_func_name does not attempt to lookup
                    + * function reference in a variable.
                    + * With runevent set to FALSE FuncUndefined event is not called.
                    + */
                    + 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);
                    + 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)
                    + {
                    + 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;
                    }

                    /*
                    @@ -8299,10 +8500,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 */
                    @@ -8339,15 +8539,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)
                    @@ -8357,17 +8562,75 @@
                    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 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 */
                    +};
                    +
                    + 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"
                    @@ -8375,212 +8638,132 @@
                    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;
                    + /* 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|DF_RUN_EVENT);
                    +
                    + 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 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 */
                    +};
                    +
                    +/*
                    + * 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;
                    }

                    /*
                    @@ -9212,8 +9395,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;
                    @@ -9239,9 +9422,9 @@
                    }

                    if (item == NULL)
                    - r = call_func(name, (int)STRLEN(name), rettv, argc, argv,
                    + r = call_func(func, rettv, argc, argv,
                    curwin->w_cursor.lnum, curwin->w_cursor.lnum,
                    - &dummy, TRUE, selfdict);
                    + &dummy, selfdict);

                    /* Free the arguments. */
                    while (argc > 0)
                    @@ -9258,7 +9441,7 @@
                    typval_T *argvars;
                    typval_T *rettv;
                    {
                    - char_u *func;
                    + func_T *func;
                    dict_T *selfdict = NULL;

                    if (argvars[1].v_type != VAR_LIST)
                    @@ -9270,11 +9453,18 @@
                    return;

                    if (argvars[0].v_type == VAR_FUNC)
                    - func = argvars[0].vval.v_string;
                    - else
                    - func = get_tv_string(&argvars[0]);
                    - if (*func == NUL)
                    - return; /* type error or empty name */
                    + {
                    + func = argvars[0].vval.v_func;
                    + ++func->fv_refcount;
                    + }
                    + else
                    + {
                    + char_u *name;
                    + name = get_tv_string(&argvars[0]);
                    + if (name == NUL)
                    + return; /* type error or empty name */
                    + func = deref_func_name(name, STRLEN(name), DF_NO_VAR);
                    + }

                    if (argvars[2].v_type != VAR_UNKNOWN)
                    {
                    @@ -9287,6 +9477,8 @@
                    }

                    (void)func_call(func, &argvars[1], selfdict, rettv);
                    +
                    + func_unref(func);
                    }

                    #ifdef FEAT_FLOAT
                    @@ -10977,37 +11169,19 @@
                    typval_T *rettv;
                    {
                    char_u *s;
                    + func_T *func;

                    s = get_tv_string(&argvars[0]);
                    - if (s == NULL || *s == NUL || VIM_ISDIGIT(*s))
                    - EMSG2(_(e_invarg2), s);
                    - /* Don't check an autoload name for existence here. */
                    - else if (vim_strchr(s, AUTOLOAD_CHAR) == NULL && !function_exists(s))
                    - EMSG2(_("E700: Unknown function: %s"), s);
                    - else
                    - {
                    - if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
                    - {
                    - char sid_buf[25];
                    - int off = *s == 's' ? 2 : 5;
                    -
                    - /* Expand s: and <SID> into <SNR>nr_, so that the function can
                    - * also be called from another script. Using trans_function_name()
                    - * would also work, but some plugins depend on the name being
                    - * printable text. */
                    - sprintf(sid_buf, "<SNR>%ld_", (long)current_SID);
                    - rettv->vval.v_string =
                    - alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
                    - if (rettv->vval.v_string != NULL)
                    - {
                    - STRCPY(rettv->vval.v_string, sid_buf);
                    - STRCAT(rettv->vval.v_string, s + off);
                    - }
                    - }
                    - else
                    - rettv->vval.v_string = vim_strsave(s);
                    +
                    + func = deref_func_name(s, STRLEN(s), DF_CREATE_AUTOLOAD);
                    +
                    + if (func != NULL)
                    + {
                    rettv->v_type = VAR_FUNC;
                    - }
                    + rettv->vval.v_func = func;
                    + }
                    + else
                    + EMSG2(_(e_unknown_function), s);
                    }

                    /*
                    @@ -16965,7 +17139,7 @@
                    item_compare2 __ARGS((const void *s1, const void *s2));

                    static int item_compare_ic;
                    -static char_u *item_compare_func;
                    +static func_T *item_compare_func;
                    static dict_T *item_compare_selfdict;
                    static int item_compare_func_err;
                    #define ITEM_COMPARE_FAIL 999
                    @@ -17025,8 +17199,8 @@
                    copy_tv(&(*(listitem_T **)s2)->li_tv, &argv[1]);

                    rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
                    - res = call_func(item_compare_func, (int)STRLEN(item_compare_func),
                    - &rettv, 2, argv, 0L, 0L, &dummy, TRUE,
                    + res = call_func(item_compare_func,
                    + &rettv, 2, argv, 0L, 0L, &dummy,
                    item_compare_selfdict);
                    clear_tv(&argv[0]);
                    clear_tv(&argv[1]);
                    @@ -17078,7 +17252,10 @@
                    {
                    /* optional second argument: {func} */
                    if (argvars[1].v_type == VAR_FUNC)
                    - item_compare_func = argvars[1].vval.v_string;
                    + {
                    + item_compare_func = argvars[1].vval.v_func;
                    + ++item_compare_func->fv_refcount;
                    + }
                    else
                    {
                    int error = FALSE;
                    @@ -17089,7 +17266,18 @@
                    if (i == 1)
                    item_compare_ic = TRUE;
                    else
                    - item_compare_func = get_tv_string(&argvars[1]);
                    + {
                    + char_u *name;
                    +
                    + name = get_tv_string(&argvars[1]);
                    + if (*name == NUL)
                    + return;
                    +
                    + item_compare_func = deref_func_name(name, STRLEN(name),
                    + DF_NO_VAR);
                    + if (item_compare_func == NULL)
                    + return;
                    + }
                    }

                    if (argvars[2].v_type != VAR_UNKNOWN)
                    @@ -17134,6 +17322,8 @@
                    }
                    }

                    + func_unref(item_compare_func);
                    +
                    vim_free(ptrs);
                    }
                    }
                    @@ -19812,13 +20002,14 @@
                    {
                    if (**arg == '(')
                    {
                    + func_T *func;
                    /* need to copy the funcref so that we can clear rettv */
                    functv = *rettv;
                    rettv->v_type = VAR_UNKNOWN;

                    /* Invoke the function. Recursive! */
                    - s = functv.vval.v_string;
                    - ret = get_func_tv(s, (int)STRLEN(s), rettv, arg,
                    + func = functv.vval.v_func;
                    + ret = get_func_tv(func, rettv, arg,
                    curwin->w_cursor.lnum, curwin->w_cursor.lnum,
                    &len, evaluate, selfdict);

                    @@ -19904,8 +20095,8 @@
                    switch (varp->v_type)
                    {
                    case VAR_FUNC:
                    - func_unref(varp->vval.v_string);
                    - /*FALLTHROUGH*/
                    + func_unref(varp->vval.v_func);
                    + break;
                    case VAR_STRING:
                    vim_free(varp->vval.v_string);
                    break;
                    @@ -19941,8 +20132,9 @@
                    switch (varp->v_type)
                    {
                    case VAR_FUNC:
                    - func_unref(varp->vval.v_string);
                    - /*FALLTHROUGH*/
                    + func_unref(varp->vval.v_func);
                    + varp->vval.v_func = NULL;
                    + break;
                    case VAR_STRING:
                    vim_free(varp->vval.v_string);
                    varp->vval.v_string = NULL;
                    @@ -20756,14 +20948,18 @@
                    break;
                    #endif
                    case VAR_STRING:
                    - case VAR_FUNC:
                    if (from->vval.v_string == NULL)
                    to->vval.v_string = NULL;
                    else
                    - {
                    to->vval.v_string = vim_strsave(from->vval.v_string);
                    - if (from->v_type == VAR_FUNC)
                    - func_ref(to->vval.v_string);
                    + break;
                    + case VAR_FUNC:
                    + if (from->vval.v_func == NULL)
                    + to->vval.v_func = NULL;
                    + else
                    + {
                    + to->vval.v_func = from->vval.v_func;
                    + ++to->vval.v_func->fv_refcount;
                    }
                    break;
                    case VAR_LIST:
                    @@ -21141,12 +21337,12 @@
                    char_u *skip_until = NULL;
                    dictitem_T *v;
                    funcdict_T fudi;
                    - static int func_nr = 0; /* number for nameless function */
                    int paren;
                    hashtab_T *ht;
                    int todo;
                    hashitem_T *hi;
                    int sourcing_lnum_off;
                    + int name_len;

                    /*
                    * ":function" without argument: list functions.
                    @@ -21226,8 +21422,13 @@
                    */
                    p = eap->arg;
                    name = trans_function_name(&p, eap->skip, 0, &fudi);
                    + name_len = p - eap->arg;
                    paren = (vim_strchr(p, '(') != NULL);
                    - if (name == NULL && (fudi.fd_dict == NULL || !paren) && !eap->skip)
                    + if (name == NULL
                    + && (paren
                    + ? (fudi.fd_dict == NULL)
                    + : (fudi.fd_func == NULL))
                    + && !eap->skip)
                    {
                    /*
                    * Return on an invalid expression in braces, unless the expression
                    @@ -21265,7 +21466,18 @@
                    *p = NUL;
                    if (!eap->skip && !got_int)
                    {
                    - fp = find_func(name);
                    + if (fudi.fd_func != NULL
                    + && fudi.fd_func->fv_type == &user_func_type)
                    + fp = (ufunc_T *) fudi.fd_func->fv_data;
                    + else if (fudi.fd_func != NULL
                    + && fudi.fd_func->fv_type == &autoload_func_type
                    + && ((aufunc_T *) fudi.fd_func->fv_data)->auf_func != NULL
                    + && ((aufunc_T *) fudi.fd_func->fv_data)->auf_func->fv_type
                    + == &user_func_type)
                    + fp = ((ufunc_T *)
                    + ((aufunc_T *)fudi.fd_func->fv_data)->auf_func->fv_data);
                    + else
                    + fp = find_func(name);
                    if (fp != NULL)
                    {
                    list_func_head(fp, TRUE);
                    @@ -21637,23 +21849,10 @@
                    emsg_funcname(e_funcexts, name);
                    goto erret;
                    }
                    - if (fp->uf_calls > 0)
                    - {
                    - emsg_funcname(N_("E127: Cannot redefine function %s: It is in use"),
                    - name);
                    - goto erret;
                    - }
                    - /* redefine existing function */
                    - ga_clear_strings(&(fp->uf_args));
                    - ga_clear_strings(&(fp->uf_lines));
                    - vim_free(name);
                    - name = NULL;
                    - }
                    - }
                    - else
                    - {
                    - char numbuf[20];
                    -
                    + }
                    + }
                    + else
                    + {
                    fp = NULL;
                    if (fudi.fd_newkey == NULL && !eap->forceit)
                    {
                    @@ -21670,96 +21869,112 @@
                    else if (tv_check_lock(fudi.fd_di->di_tv.v_lock, eap->arg))
                    goto erret;

                    - /* Give the function a sequential number. Can only be used with a
                    - * Funcref! */
                    vim_free(name);
                    - sprintf(numbuf, "%d", ++func_nr);
                    - name = vim_strsave((char_u *)numbuf);
                    + name = vim_strnsave(eap->arg, name_len);
                    + flags |= FC_ANON;
                    if (name == NULL)
                    goto erret;
                    }

                    + if (fp != NULL)
                    + {
                    + remove_user_func(fp);
                    + func_unref(fp->uf_func);
                    + fp = NULL;
                    + }
                    +
                    + if (fudi.fd_dict == <br/><br/>(Message over 64 KB, truncated)
                  • ZyX
                    Added tests, added functype() function, a bit more fixes: - Two autoload function references when called for the first time caused script being loaded twice,
                    Message 9 of 22 , Sep 28, 2013
                    • 0 Attachment
                      Added tests, added functype() function, a bit more fixes:

                      - Two autoload function references when called for the first time caused script being loaded twice, no matter whether or not referenced function was defined.
                      - It is now possible to save function references in autoload variables (variables with a hash) (assuming they start with a capital letter of course).
                      - Ability to load function references from the variables was tested and fixed.
                      - Added a check whether function name containing hash is a valid one when creating autoload function (this functionality is missing in default branch).

                      diff -r 3a32cbcc2449 -r 419a14acd856 Filelist
                      --- a/Filelist Wed Sep 25 23:24:58 2013 +0200
                      +++ b/Filelist Sat Sep 28 22:24:12 2013 +0400
                      @@ -83,6 +83,7 @@
                      src/testdir/test[0-9]*.ok \
                      src/testdir/test49.vim \
                      src/testdir/test60.vim \
                      + src/testdir/Test100.vim \
                      src/testdir/test83-tags? \
                      src/testdir/python2/*.py \
                      src/testdir/python3/*.py \
                      diff -r 3a32cbcc2449 -r 419a14acd856 runtime/doc/eval.txt
                      --- a/runtime/doc/eval.txt Wed Sep 25 23:24:58 2013 +0200
                      +++ b/runtime/doc/eval.txt Sat Sep 28 22:24:12 2013 +0400
                      @@ -1772,7 +1772,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}
                      @@ -3104,6 +3105,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 3a32cbcc2449 -r 419a14acd856 runtime/doc/if_pyth.txt
                      --- a/runtime/doc/if_pyth.txt Wed Sep 25 23:24:58 2013 +0200
                      +++ b/runtime/doc/if_pyth.txt Sat Sep 28 22:24:12 2013 +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 3a32cbcc2449 -r 419a14acd856 runtime/doc/repeat.txt
                      --- a/runtime/doc/repeat.txt Wed Sep 25 23:24:58 2013 +0200
                      +++ b/runtime/doc/repeat.txt Sat Sep 28 22:24:12 2013 +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 3a32cbcc2449 -r 419a14acd856 src/Makefile
                      --- a/src/Makefile Wed Sep 25 23:24:58 2013 +0200
                      +++ b/src/Makefile Sat Sep 28 22:24:12 2013 +0400
                      @@ -1882,7 +1882,8 @@
                      test60 test61 test62 test63 test64 test65 test66 test67 test68 test69 \
                      test70 test71 test72 test73 test74 test75 test76 test77 test78 test79 \
                      test80 test81 test82 test83 test84 test85 test86 test87 test88 test89 \
                      - test90 test91 test92 test93 test94 test95 test96 test97 test98 test99:
                      + test90 test91 test92 test93 test94 test95 test96 test97 test98 test99 \
                      + test100:
                      cd testdir; rm $@.out; $(MAKE) -f Makefile $@.out VIMPROG=../$(VIMTARGET)

                      testclean:
                      diff -r 3a32cbcc2449 -r 419a14acd856 src/eval.c
                      --- a/src/eval.c Wed Sep 25 23:24:58 2013 +0200
                      +++ b/src/eval.c Sat Sep 28 22:24:12 2013 +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
                      @@ -153,10 +154,16 @@

                      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
                      +
                      /*
                      * Structure to hold info for a user function.
                      */
                      @@ -166,7 +173,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 +191,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 +233,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 +297,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;


                      @@ -438,17 +470,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));
                      @@ -534,6 +565,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));
                      @@ -790,10 +822,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));
                      @@ -802,6 +836,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
                      @@ -818,8 +853,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));
                      @@ -835,6 +871,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.
                      */
                      @@ -1559,10 +1600,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;
                      @@ -1574,11 +1615,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 */
                      @@ -1613,9 +1662,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;
                      @@ -1626,6 +1675,8 @@
                      if (ret == FAIL)
                      clear_tv(rettv);

                      + func_unref(func);
                      +
                      return ret;
                      }

                      @@ -3383,8 +3434,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;
                      @@ -3404,14 +3454,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
                      @@ -3419,10 +3469,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);
                      @@ -3458,7 +3504,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)
                      {
                      @@ -3500,8 +3546,8 @@
                      }

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

                      /*
                      @@ -4472,12 +4518,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;
                      }
                      @@ -5146,21 +5197,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;
                      }

                      @@ -6121,9 +6190,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;
                      @@ -7415,7 +7488,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);
                      @@ -7594,8 +7667,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:
                      @@ -7676,10 +7749,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:
                      @@ -7700,17 +7773,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);
                      @@ -7721,13 +7802,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; )
                      {
                      @@ -7736,7 +7817,7 @@
                      MB_COPY_CHAR(p, r);
                      }
                      *r++ = '\'';
                      - if (function)
                      + if (fname_u)
                      *r++ = ')';
                      *r++ = NUL;
                      }
                      @@ -7829,321 +7910,324 @@
                      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},
                      - {"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},
                      + {"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)
                      @@ -8237,9 +8321,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 */
                      {
                      @@ -8260,39 +8344,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);
                      + 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;
                      }

                      /*
                      @@ -8300,10 +8515,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 */
                      @@ -8340,15 +8554,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)
                      @@ -8358,17 +8577,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 = "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"
                      @@ -8376,212 +8664,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 = "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;
                      }

                      /*
                      @@ -9213,8 +9466,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;
                      @@ -9240,9 +9493,9 @@
                      }

                      if (item == NULL)
                      - r = call_func(name, (int)STRLEN(name), rettv, argc, argv,
                      + r = call_func(func, rettv, argc, argv,
                      curwin->w_cursor.lnum, curwin->w_cursor.lnum,
                      - &dummy, TRUE, selfdict);
                      + &dummy, selfdict);

                      /* Free the arguments. */
                      while (argc > 0)
                      @@ -9259,7 +9512,7 @@
                      typval_T *argvars;
                      typval_T *rettv;
                      {
                      - char_u *func;
                      + func_T *func;
                      dict_T *selfdict = NULL;

                      if (argvars[1].v_type != VAR_LIST)
                      @@ -9271,11 +9524,18 @@
                      return;

                      if (argvars[0].v_type == VAR_FUNC)
                      - func = argvars[0].vval.v_string;
                      - else
                      - func = get_tv_string(&argvars[0]);
                      - if (*func == NUL)
                      - return; /* type error or empty name */
                      + {
                      + func = argvars[0].vval.v_func;
                      + ++func->fv_refcount;
                      + }
                      + else
                      + {
                      + char_u *name;
                      + name = get_tv_string(&argvars[0]);
                      + if (name == NUL)
                      + return; /* type error or empty name */
                      + func = deref_func_name(name, STRLEN(name), DF_NO_VAR);
                      + }

                      if (argvars[2].v_type != VAR_UNKNOWN)
                      {
                      @@ -9288,6 +9548,8 @@
                      }

                      (void)func_call(func, &argvars[1], selfdict, rettv);
                      +
                      + func_unref(func);
                      }

                      #ifdef FEAT_FLOAT
                      @@ -10978,37 +11240,38 @@
                      typval_T *rettv;
                      {
                      char_u *s;
                      + func_T *func;

                      s = get_tv_string(&argvars[0]);
                      - if (s == NULL || *s == NUL || VIM_ISDIGIT(*s))
                      - EMSG2(_(e_invarg2), s);
                      - /* Don't check an autoload name for existence here. */
                      - else if (vim_strchr(s, AUTOLOAD_CHAR) == NULL && !function_exists(s))
                      - EMSG2(_("E700: Unknown function: %s"), s);
                      - else
                      - {
                      - if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
                      - {
                      - char sid_buf[25];
                      - int off = *s == 's' ? 2 : 5;
                      -
                      - /* Expand s: and <SID> into <SNR>nr_, so that the function can
                      - * also be called from another script. Using trans_function_name()
                      - * would also work, but some plugins depend on the name being
                      - * printable text. */
                      - sprintf(sid_buf, "<SNR>%ld_", (long)current_SID);
                      - rettv->vval.v_string =
                      - alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
                      - if (rettv->vval.v_string != NULL)
                      - {
                      - STRCPY(rettv->vval.v_string, sid_buf);
                      - STRCAT(rettv->vval.v_string, s + off);
                      - }
                      - }
                      - else
                      - rettv->vval.v_string = vim_strsave(s);
                      +
                      + func = deref_func_name(s, STRLEN(s), DF_CREATE_AUTOLOAD);
                      +<br/><br/>(Message over 64 KB, truncated)
                    • ZyX
                      Some updates: fixed mzscheme and merged with upstream. diff -r c7bcb04f613e -r a5a312aafd97 Filelist ... +++ b/Filelist Sun Dec 15 16:21:59 2013 +0400 @@ -84,6
                      Message 10 of 22 , Dec 15, 2013
                      • 0 Attachment
                        Some updates: fixed mzscheme and merged with upstream.

                        diff -r c7bcb04f613e -r a5a312aafd97 Filelist
                        --- a/Filelist Sat Dec 14 13:06:17 2013 +0100
                        +++ b/Filelist Sun Dec 15 16:21:59 2013 +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 \
                        diff -r c7bcb04f613e -r a5a312aafd97 runtime/doc/eval.txt
                        --- a/runtime/doc/eval.txt Sat Dec 14 13:06:17 2013 +0100
                        +++ b/runtime/doc/eval.txt Sun Dec 15 16:21:59 2013 +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 c7bcb04f613e -r a5a312aafd97 runtime/doc/if_pyth.txt
                        --- a/runtime/doc/if_pyth.txt Sat Dec 14 13:06:17 2013 +0100
                        +++ b/runtime/doc/if_pyth.txt Sun Dec 15 16:21:59 2013 +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 c7bcb04f613e -r a5a312aafd97 runtime/doc/repeat.txt
                        --- a/runtime/doc/repeat.txt Sat Dec 14 13:06:17 2013 +0100
                        +++ b/runtime/doc/repeat.txt Sun Dec 15 16:21:59 2013 +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 c7bcb04f613e -r a5a312aafd97 src/eval.c
                        --- a/src/eval.c Sat Dec 14 13:06:17 2013 +0100
                        +++ b/src/eval.c Sun Dec 15 16:21:59 2013 +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
                        @@ -153,10 +154,16 @@

                        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
                        +
                        /*
                        * Structure to hold info for a user function.
                        */
                        @@ -166,7 +173,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 +191,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 +233,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 +297,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 +471,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 +568,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));
                        @@ -793,10 +825,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 +839,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 +856,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 +874,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 +1604,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 +1619,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 +1666,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 +1679,8 @@
                        if (ret == FAIL)
                        clear_tv(rettv);

                        + func_unref(func);
                        +
                        return ret;
                        }

                        @@ -3387,8 +3438,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 +3458,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 +3473,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 +3508,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 +3550,8 @@
                        }

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

                        /*
                        @@ -4476,12 +4522,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 +5201,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;
                        }

                        @@ -6125,9 +6194,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 +7492,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 +7671,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 +7753,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 +7777,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 +7806,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 +7821,7 @@
                        MB_COPY_CHAR(p, r);
                        }
                        *r++ = '\'';
                        - if (function)
                        + if (fname_u)
                        *r++ = ')';
                        *r++ = NUL;
                        }
                        @@ -7833,322 +7914,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 +8326,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 +8349,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);
                        + 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 +8520,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 +8559,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 +8582,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 = "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 +8669,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 = "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 +9494,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 +9521,9 @@
                        }

                        if (item == NULL)
                        - r = call_func(name, (int)STRLEN(name), rettv, argc, argv,
                        + r = call_func(func, rettv, argc, argv,
                        curwin->w_cursor.lnum, curwin->w_cursor.lnum,
                        - &dummy, TRUE, selfdict);
                        + &dummy, selfdict);

                        /* Free the arguments. */
                        while (argc > 0)
                        @@ -9287,7 +9540,7 @@
                        typval_T *argvars;
                        typval_T *rettv;
                        {
                        - char_u *func;
                        + func_T *func;
                        dict_T *selfdict = NULL;

                        if (argvars[1].v_type != VAR_LIST)
                        @@ -9299,11 +9552,18 @@
                        return;

                        if (argvars[0].v_type == VAR_FUNC)
                        - func = argvars[0].vval.v_string;
                        - else
                        - func = get_tv_string(&argvars[0]);
                        - if (*func == NUL)
                        - return; /* type error or empty name */
                        + {
                        + func = argvars[0].vval.v_func;
                        + ++func->fv_refcount;
                        + }
                        + else
                        + {
                        + char_u *name;
                        + name = get_tv_string(&argvars[0]);
                        + if (name == NUL)
                        + return; /* type error or empty name */
                        + func = deref_func_name(name, STRLEN(name), DF_NO_VAR);
                        + }

                        if (argvars[2].v_type != VAR_UNKNOWN)
                        {
                        @@ -9316,6 +9576,8 @@
                        }

                        (void)func_call(func, &argvars[1], selfdict, rettv);
                        +
                        + func_unref(func);
                        }

                        #ifdef FEAT_FLOAT
                        @@ -11006,37 +11268,38 @@
                        typval_T *rettv;
                        {
                        char_u *s;
                        + func_T *func;

                        s = get_tv_string(&argvars[0]);
                        - if (s == NULL || *s == NUL || VIM_ISDIGIT(*s))
                        - EMSG2(_(e_invarg2), s);
                        - /* Don't check an autoload name for existence here. */
                        - else if (vim_strchr(s, AUTOLOAD_CHAR) == NULL && !function_exists(s))
                        - EMSG2(_("E700: Unknown function: %s"), s);
                        - else
                        - {
                        - if (STRNCMP(s, "s:", 2) == 0 || STRNCMP(s, "<SID>", 5) == 0)
                        - {
                        - char sid_buf[25];
                        - int off = *s == 's' ? 2 : 5;
                        -
                        - /* Expand s: and <SID> into <SNR>nr_, so that the function can
                        - * also be called from another script. Using trans_function_name()
                        - * would also work, but some plugins depend on the name being
                        - * printable text. */
                        - sprintf(sid_buf, "<SNR>%ld_", (long)current_SID);
                        - rettv->vval.v_string =
                        - alloc((int)(STRLEN(sid_buf) + STRLEN(s + off) + 1));
                        - if (rettv->vval.v_string != NULL)
                        - {
                        - STRCPY(rettv->vval.v_string, sid_buf);
                        - STRCAT(rettv->vval.v_string, s + off);
                        - }
                        - }
                        - else
                        - rettv->vval.v_string = vim_strsave(s);
                        +
                        + func = deref_func_name(s, STRLEN(s), DF_CREATE_AUTOLOAD);
                        +
                        + if (func != NULL)
                        + {
                        rettv->v_type = VAR_FUNC;
                        - }
                        + rettv->vval.v_func = func;
                        + }
                        + else
                        + EMSG2(_(e_unknown_function), s);
                        +}
                        +
                        +/*
                        + * "functype()" function
                        + */
                        + static void
                        +f_functype(argvars, rettv)
                        + typval_T *argvars;
                        + typval_T *rettv;
                        +{
                        + if (argvars[0].v_type != VAR_FUNC || argvars[0].vval.v_func == NULL)
                        + {
                        + EMSG(_(e_funcref));
                        + return;
                        + }
                        +
                        + if ((rettv->vval.v_string = FUNC_TYPE(argvars[0].vval.v_func)) == NULL)
                        + return;
                        + rettv->v_type = VAR_STRING;
                        }

                        /*
                        @@ -14451,15 +14714,15 @@
                        }

                        void
                        -mzscheme_call_vim(name, args, rettv)
                        - char_u *name;
                        +mzscheme_call_vim(func, args, rettv)
                        + func_T *func;
                        typval_T *args;
                        typval_T *rettv;
                        {
                        typval_T argvars[3];

                        - argvars[0].v_type = VAR_STRING;
                        - argvars[0].vval.v_string = name;
                        + argvars[0].v_type = VAR_FUNC;
                        + argvars[0].vval.v_func = func;
                        copy_tv(args, &argvars[1]);
                        argvars[2].v_type = VAR_UNKNOWN;
                        f_call(argvars, rettv);
                        @@ -17003,7 +17266,7 @@
                        item_compare2 __ARGS(<br/><br/>(Message over 64 KB, truncated)
                      • ZyX
                        Merged with upstream, removed no_autoload global, made islocked() and :lockvar no longer trigger script autoloading. Also fixed some compilation warnings. diff
                        Message 11 of 22 , 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)
                        Your message has been successfully submitted and would be delivered to recipients shortly.