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 “Unknown function” errors, now it crashes with some problems related to selfdict reported by valgrind. diff -r c015eedb9b4a -r ac4d567505ed
    Message 1 of 22 , Jul 18 9:59 PM
    • 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 2 of 22 , Jul 20 4:26 AM
      • 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 3 of 22 , Jul 20 5:06 AM
        • 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 4 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 5 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 6 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 7 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 8 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 9 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.