summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2016-07-17 18:29:19 +0200
committerBram Moolenaar <Bram@vim.org>2016-07-17 18:29:19 +0200
commita9b579f3d7463720a316e11e77a7a9fbb9267986 (patch)
tree44c8c9db5628fdb95f6fa89ce7b3e89cddedb839
parentda861d631d7e22654faee2789286c685ad548911 (diff)
patch 7.4.2058v7.4.2058
Problem: eval.c is too big. Solution: Move user functions to userfunc.c
-rw-r--r--Filelist2
-rw-r--r--src/Makefile10
-rw-r--r--src/eval.c3579
-rw-r--r--src/globals.h2
-rw-r--r--src/proto.h1
-rw-r--r--src/proto/eval.pro47
-rw-r--r--src/proto/userfunc.pro52
-rw-r--r--src/structs.h45
-rw-r--r--src/userfunc.c3494
-rw-r--r--src/version.c2
-rw-r--r--src/vim.h25
11 files changed, 3728 insertions, 3531 deletions
diff --git a/Filelist b/Filelist
index c395418cb0..dc9a2308b7 100644
--- a/Filelist
+++ b/Filelist
@@ -84,6 +84,7 @@ SRC_ALL = \
src/termlib.c \
src/ui.c \
src/undo.c \
+ src/userfunc.c \
src/version.c \
src/version.h \
src/vim.h \
@@ -175,6 +176,7 @@ SRC_ALL = \
src/proto/termlib.pro \
src/proto/ui.pro \
src/proto/undo.pro \
+ src/proto/userfunc.pro \
src/proto/version.pro \
src/proto/winclip.pro \
src/proto/window.pro \
diff --git a/src/Makefile b/src/Makefile
index 8b15226669..7ab4d328f6 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1531,6 +1531,7 @@ BASIC_SRC = \
term.c \
ui.c \
undo.c \
+ userfunc.c \
version.c \
window.c \
$(OS_EXTRA_SRC)
@@ -1631,6 +1632,7 @@ OBJ_COMMON = \
objects/term.o \
objects/ui.o \
objects/undo.o \
+ objects/userfunc.o \
objects/version.o \
objects/window.o \
$(GUI_OBJ) \
@@ -1731,6 +1733,7 @@ PRO_AUTO = \
termlib.pro \
ui.pro \
undo.pro \
+ userfunc.pro \
version.pro \
window.pro \
gui_beval.pro \
@@ -3066,6 +3069,9 @@ objects/ui.o: ui.c
objects/undo.o: undo.c
$(CCC) -o $@ undo.c
+objects/userfunc.o: userfunc.c
+ $(CCC) -o $@ userfunc.c
+
objects/window.o: window.c
$(CCC) -o $@ window.c
@@ -3379,6 +3385,10 @@ objects/undo.o: undo.c vim.h auto/config.h feature.h os_unix.h auto/osdef.h \
ascii.h keymap.h term.h macros.h option.h structs.h regexp.h gui.h \
gui_beval.h proto/gui_beval.pro alloc.h ex_cmds.h proto.h globals.h \
farsi.h arabic.h
+objects/userfunc.o: userfunc.c vim.h auto/config.h feature.h os_unix.h auto/osdef.h \
+ ascii.h keymap.h term.h macros.h option.h structs.h regexp.h gui.h \
+ gui_beval.h proto/gui_beval.pro alloc.h ex_cmds.h proto.h globals.h \
+ farsi.h arabic.h
objects/version.o: version.c vim.h auto/config.h feature.h os_unix.h auto/osdef.h \
ascii.h keymap.h term.h macros.h option.h structs.h regexp.h gui.h \
gui_beval.h proto/gui_beval.pro alloc.h ex_cmds.h proto.h globals.h \
diff --git a/src/eval.c b/src/eval.c
index 3b4f2c460d..f930e47b62 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -30,54 +30,6 @@
#define DICT_MAXNEST 100 /* maximum nesting of lists and dicts */
-#define DO_NOT_FREE_CNT 99999 /* refcount for dict or list that should not
- be freed. */
-
-/*
- * Structure returned by get_lval() and used by set_var_lval().
- * For a plain name:
- * "name" points to the variable name.
- * "exp_name" is NULL.
- * "tv" is NULL
- * For a magic braces name:
- * "name" points to the expanded variable name.
- * "exp_name" is non-NULL, to be freed later.
- * "tv" is NULL
- * For an index in a list:
- * "name" points to the (expanded) variable name.
- * "exp_name" NULL or non-NULL, to be freed later.
- * "tv" points to the (first) list item value
- * "li" points to the (first) list item
- * "range", "n1", "n2" and "empty2" indicate what items are used.
- * For an existing Dict item:
- * "name" points to the (expanded) variable name.
- * "exp_name" NULL or non-NULL, to be freed later.
- * "tv" points to the dict item value
- * "newkey" is NULL
- * For a non-existing Dict item:
- * "name" points to the (expanded) variable name.
- * "exp_name" NULL or non-NULL, to be freed later.
- * "tv" points to the Dictionary typval_T
- * "newkey" is the key for the new item.
- */
-typedef struct lval_S
-{
- char_u *ll_name; /* start of variable name (can be NULL) */
- char_u *ll_exp_name; /* NULL or expanded name in allocated memory. */
- typval_T *ll_tv; /* Typeval of item being used. If "newkey"
- isn't NULL it's the Dict to which to add
- the item. */
- listitem_T *ll_li; /* The list item or NULL. */
- list_T *ll_list; /* The list or NULL. */
- int ll_range; /* TRUE when a [i:j] range was used */
- long ll_n1; /* First index for list */
- long ll_n2; /* Second index for list range */
- int ll_empty2; /* Second index is empty: [i:] */
- dict_T *ll_dict; /* The Dictionary or NULL */
- dictitem_T *ll_di; /* The dictitem or NULL */
- char_u *ll_newkey; /* New key for Dict in alloc. mem or NULL. */
-} lval_T;
-
static char *e_letunexp = N_("E18: Unexpected characters in :let");
static char *e_undefvar = N_("E121: Undefined variable: %s");
static char *e_missbrac = N_("E111: Missing ']'");
@@ -87,14 +39,8 @@ static char *e_listreq = N_("E714: List required");
#ifdef FEAT_QUICKFIX
static char *e_stringreq = N_("E928: String required");
#endif
-static char *e_toomanyarg = N_("E118: Too many arguments for function: %s");
-static char *e_dictkey = N_("E716: Key not present in Dictionary: %s");
-static char *e_funcexts = N_("E122: Function %s already exists, add ! to replace it");
-static char *e_funcdict = N_("E717: Dictionary entry already exists");
-static char *e_funcref = N_("E718: Funcref required");
static char *e_dictrange = N_("E719: Cannot use [:] with a Dictionary");
static char *e_letwrong = N_("E734: Wrong variable type for %s=");
-static char *e_nofunc = N_("E130: Unknown function: %s");
static char *e_illvar = N_("E461: Illegal variable name: %s");
#ifdef FEAT_FLOAT
static char *e_float_as_string = N_("E806: using Float as a String");
@@ -134,107 +80,9 @@ static garray_T ga_scripts = {0, 0, sizeof(scriptvar_T *), 4, NULL};
static int echo_attr = 0; /* attributes used for ":echo" */
-/* Values for trans_function_name() argument: */
-#define TFN_INT 1 /* internal function name OK */
-#define TFN_QUIET 2 /* no error messages */
-#define TFN_NO_AUTOLOAD 4 /* do not use script autoloading */
-
-/* Values for get_lval() flags argument: */
-#define GLV_QUIET TFN_QUIET /* no error messages */
-#define GLV_NO_AUTOLOAD TFN_NO_AUTOLOAD /* do not use script autoloading */
-
-/*
- * Structure to hold info for a user function.
- */
-typedef struct ufunc ufunc_T;
-
-struct ufunc
-{
- 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
- int uf_profiling; /* TRUE when func is being profiled */
- /* profiling the function as a whole */
- int uf_tm_count; /* nr of calls */
- proftime_T uf_tm_total; /* time spent in function + children */
- proftime_T uf_tm_self; /* time spent in function itself */
- proftime_T uf_tm_children; /* time spent in children this call */
- /* profiling the function per line */
- int *uf_tml_count; /* nr of times line was executed */
- proftime_T *uf_tml_total; /* time spent in a line + children */
- proftime_T *uf_tml_self; /* time spent in a line itself */
- proftime_T uf_tml_start; /* start time for current line */
- proftime_T uf_tml_children; /* time spent in children for this line */
- 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 */
-#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 */
- char_u uf_name[1]; /* name of function (actually longer); can
- start with <SNR>123_ (<SNR> is K_SPECIAL
- KS_EXTRA KE_SNR) */
-};
-
-/* 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" */
-
-/*
- * All user-defined functions are found in this hashtable.
- */
-static hashtab_T func_hashtab;
-
/* The names of packages that once were loaded are remembered. */
static garray_T ga_loaded = {0, 0, sizeof(char_u *), 4, NULL};
-/* From user function to hashitem and back. */
-static ufunc_T dumuf;
-#define UF2HIKEY(fp) ((fp)->uf_name)
-#define HIKEY2UF(p) ((ufunc_T *)(p - (dumuf.uf_name - (char_u *)&dumuf)))
-#define HI2UF(hi) HIKEY2UF((hi)->hi_key)
-
-#define FUNCARG(fp, j) ((char_u **)(fp->uf_args.ga_data))[j]
-#define FUNCLINE(fp, j) ((char_u **)(fp->uf_lines.ga_data))[j]
-
-#define MAX_FUNC_ARGS 20 /* maximum number of function arguments */
-#define VAR_SHORT_LEN 20 /* short variable name length */
-#define FIXVAR_CNT 12 /* number of fixed variables */
-
-/* structure to hold info for a function that is currently being executed. */
-typedef struct funccall_S funccall_T;
-
-struct funccall_S
-{
- ufunc_T *func; /* function being called */
- int linenr; /* next line to be executed */
- int returned; /* ":return" used */
- struct /* fixed variables for arguments */
- {
- dictitem_T var; /* variable (without room for name) */
- char_u room[VAR_SHORT_LEN]; /* room for the name */
- } fixvar[FIXVAR_CNT];
- dict_T l_vars; /* l: local function variables */
- dictitem_T l_vars_var; /* variable for l: scope */
- dict_T l_avars; /* a: argument variables */
- dictitem_T l_avars_var; /* variable for a: scope */
- list_T l_varlist; /* list for a:000 */
- listitem_T l_listitems[MAX_FUNC_ARGS]; /* listitems for a:000 */
- typval_T *rettv; /* return value */
- linenr_T breakpoint; /* next line with breakpoint or zero */
- int dbg_tick; /* debug_tick when breakpoint was set */
- int level; /* top nesting level of executed function */
-#ifdef FEAT_PROFILE
- proftime_T prof_child; /* time spent in a child */
-#endif
- funccall_T *caller; /* calling function or NULL */
-};
-
/*
* Info used by a ":for" loop.
*/
@@ -246,16 +94,6 @@ typedef struct
list_T *fi_list; /* list being used */
} forinfo_T;
-/*
- * Struct used by trans_function_name()
- */
-typedef struct
-{
- dict_T *fd_dict; /* Dictionary used */
- char_u *fd_newkey; /* new key in "dict" in allocated memory */
- dictitem_T *fd_di; /* Dictionary item used */
-} funcdict_T;
-
/*
* Array to hold the value of v: variables.
@@ -373,7 +211,6 @@ static void restore_vimvar(int idx, typval_T *save_tv);
static int ex_let_vars(char_u *arg, typval_T *tv, int copy, int semicolon, int var_count, char_u *nextchars);
static char_u *skip_var_list(char_u *arg, int *var_count, int *semicolon);
static char_u *skip_var_one(char_u *arg);
-static void list_hashtable_vars(hashtab_T *ht, char_u *prefix, int empty, int *first);
static void list_glob_vars(int *first);
static void list_buf_vars(int *first);
static void list_win_vars(int *first);
@@ -382,12 +219,9 @@ static void list_tab_vars(int *first);
#endif
static void list_vim_vars(int *first);
static void list_script_vars(int *first);
-static void list_func_vars(int *first);
static char_u *list_arg_vars(exarg_T *eap, char_u *arg, int *first);
static char_u *ex_let_one(char_u *arg, typval_T *tv, int copy, char_u *endchars, char_u *op);
static int check_changedtick(char_u *arg);
-static char_u *get_lval(char_u *name, typval_T *rettv, lval_T *lp, int unlet, int skip, int flags, int fne_flags);
-static void clear_lval(lval_T *lp);
static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, int copy, char_u *op);
static int tv_op(typval_T *tv1, typval_T *tv2, char_u *op);
static void ex_unletlock(exarg_T *eap, char_u *argstart, int deep);
@@ -396,7 +230,6 @@ static int do_lock_var(lval_T *lp, char_u *name_end, int deep, int lock);
static void item_lock(typval_T *tv, int deep, int lock);
static int tv_islocked(typval_T *tv);
-static int eval0(char_u *arg, typval_T *rettv, char_u **nextcmd, int evaluate);
static int eval2(char_u **arg, typval_T *rettv, int evaluate);
static int eval3(char_u **arg, typval_T *rettv, int evaluate);
static int eval4(char_u **arg, typval_T *rettv, int evaluate);
@@ -409,14 +242,7 @@ static int get_option_tv(char_u **arg, typval_T *rettv, int evaluate);
static int get_string_tv(char_u **arg, typval_T *rettv, int evaluate);
static int get_lit_string_tv(char_u **arg, typval_T *rettv, int evaluate);
static int free_unref_items(int copyID);
-static int get_function_args(char_u **argp, char_u endchar, garray_T *newargs, int *varargs, int skip);
-static int get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate);
-static char_u *echo_string(typval_T *tv, char_u **tofree, char_u *numbuf, int copyID);
static int get_env_tv(char_u **arg, typval_T *rettv, int evaluate);
-static int find_internal_func(char_u *name);
-static char_u *deref_func_name(char_u *name, int *lenp, partial_T **partial, int no_autoload);
-static int get_func_tv(char_u *name, int len, typval_T *rettv, char_u **arg, linenr_T firstline, linenr_T lastline, int *doesrange, int evaluate, partial_T *partial, dict_T *selfdict);
-static void emsg_funcname(char *ermsg, char_u *name);
static int non_zero_arg(typval_T *argvars);
#ifdef FEAT_FLOAT
@@ -818,17 +644,9 @@ static void f_xor(typval_T *argvars, typval_T *rettv);
static int list2fpos(typval_T *arg, pos_T *posp, int *fnump, colnr_T *curswantp);
static pos_T *var2fpos(typval_T *varp, int dollar_lnum, int *fnum);
static int get_env_len(char_u **arg);
-static int get_id_len(char_u **arg);
static int get_name_len(char_u **arg, char_u **alias, int evaluate, int verbose);
-static char_u *find_name_end(char_u *arg, char_u **expr_start, char_u **expr_end, int flags);
-#define FNE_INCL_BR 1 /* find_name_end(): include [] in name */
-#define FNE_CHECK_START 2 /* find_name_end(): check name starts with
- valid character */
static char_u * make_expanded_name(char_u *in_start, char_u *expr_start, char_u *expr_end, char_u *in_end);
-static int eval_isnamec(int c);
-static int eval_isnamec1(int c);
static int get_var_tv(char_u *name, int len, typval_T *rettv, dictitem_T **dip, int verbose, int no_autoload);
-static int handle_subscript(char_u **arg, typval_T *rettv, int evaluate, int verbose);
static typval_T *alloc_string_tv(char_u *string);
static void init_tv(typval_T *varp);
#ifdef FEAT_FLOAT
@@ -836,47 +654,14 @@ static float_T get_tv_float(typval_T *varp);
#endif
static linenr_T get_tv_lnum(typval_T *argvars);
static linenr_T get_tv_lnum_buf(typval_T *argvars, buf_T *buf);
-static dictitem_T *find_var(char_u *name, hashtab_T **htp, int no_autoload);
static dictitem_T *find_var_in_ht(hashtab_T *ht, int htname, char_u *varname, int no_autoload);
static hashtab_T *find_var_ht(char_u *name, char_u **varname);
-static funccall_T *get_funccal(void);
-static void vars_clear_ext(hashtab_T *ht, int free_val);
static void delete_var(hashtab_T *ht, hashitem_T *hi);
static void list_one_var(dictitem_T *v, char_u *prefix, int *first);
static void list_one_var_a(char_u *prefix, char_u *name, int type, char_u *string, int *first);
static void set_var(char_u *name, typval_T *varp, int copy);
static int var_check_fixed(int flags, char_u *name, int use_gettext);
static char_u *find_option_end(char_u **arg, int *opt_flags);
-static char_u *trans_function_name(char_u **pp, int skip, int flags, funcdict_T *fd, partial_T **partial);
-static int eval_fname_script(char_u *p);
-static int eval_fname_sid(char_u *p);
-static void list_func_head(ufunc_T *fp, int indent);
-static ufunc_T *find_func(char_u *name);
-static int function_exists(char_u *name);
-static int builtin_function(char_u *name, int len);
-#ifdef FEAT_PROFILE
-static void func_do_profile(ufunc_T *fp);
-static void prof_sort_list(FILE *fd, ufunc_T **sorttab, int st_len, char *title, int prefer_self);
-static void prof_func_line(FILE *fd, int count, proftime_T *total, proftime_T *self, int prefer_self);
-static int
-# ifdef __BORLANDC__
- _RTLENTRYF
-# endif
- prof_total_cmp(const void *s1, const void *s2);
-static int
-# ifdef __BORLANDC__
- _RTLENTRYF
-# endif
- prof_self_cmp(const void *s1, const void *s2);
-#endif
-static int script_autoload(char_u *name, int reload);
-static char_u *autoload_name(char_u *name);
-static void cat_func_name(char_u *buf, ufunc_T *fp);
-static void func_free(ufunc_T *fp);
-static void call_user_func(ufunc_T *fp, int argcount, typval_T *argvars, typval_T *rettv, linenr_T firstline, linenr_T lastline, dict_T *selfdict);
-static int can_free_funccal(funccall_T *fc, int copyID) ;
-static void free_funccal(funccall_T *fc, int free_val);
-static void add_nr_var(dict_T *dp, dictitem_T *v, char *name, varnumber_T nr);
static win_T *find_win_by_nr(typval_T *vp, tabpage_T *tp);
static win_T *find_tabwin(typval_T *wvp, typval_T *tvp);
static void getwinvar(typval_T *argvars, typval_T *rettv, int off);
@@ -905,7 +690,7 @@ eval_init(void)
init_var_dict(&vimvardict, &vimvars_var, VAR_SCOPE);
vimvardict.dv_lock = VAR_FIXED;
hash_init(&compat_hashtab);
- hash_init(&func_hashtab);
+ func_init();
for (i = 0; i < VV_LEN; ++i)
{
@@ -1002,62 +787,9 @@ eval_clear(void)
/* functions */
free_all_functions();
- hash_clear(&func_hashtab);
}
#endif
-/*
- * Return the name of the executed function.
- */
- char_u *
-func_name(void *cookie)
-{
- return ((funccall_T *)cookie)->func->uf_name;
-}
-
-/*
- * Return the address holding the next breakpoint line for a funccall cookie.
- */
- linenr_T *
-func_breakpoint(void *cookie)
-{
- return &((funccall_T *)cookie)->breakpoint;
-}
-
-/*
- * Return the address holding the debug tick for a funccall cookie.
- */
- int *
-func_dbg_tick(void *cookie)
-{
- return &((funccall_T *)cookie)->dbg_tick;
-}
-
-/*
- * Return the nesting level for a funccall cookie.
- */
- int
-func_level(void *cookie)
-{
- return ((funccall_T *)cookie)->level;
-}
-
-/* pointer to funccal for currently active function */
-funccall_T *current_funccal = NULL;
-
-/* pointer to list of previously used funccal, still around because some
- * item in it is still being used. */
-funccall_T *previous_funccal = NULL;
-
-/*
- * Return TRUE when a function was ended by a ":return" command.
- */
- int
-current_func_returned(void)
-{
- return current_funccal->returned;
-}
-
/*
* Set an internal variable to a string value. Creates the variable if it does
@@ -1767,65 +1499,6 @@ call_func_retlist(
}
#endif
-/*
- * Save the current function call pointer, and set it to NULL.
- * Used when executing autocommands and for ":source".
- */
- void *
-save_funccal(void)
-{
- funccall_T *fc = current_funccal;
-
- current_funccal = NULL;
- return (void *)fc;
-}
-
- void
-restore_funccal(void *vfc)
-{
- funccall_T *fc = (funccall_T *)vfc;
-
- current_funccal = fc;
-}
-
-#if defined(FEAT_PROFILE) || defined(PROTO)
-/*
- * Prepare profiling for entering a child or something else that is not
- * counted for the script/function itself.
- * Should always be called in pair with prof_child_exit().
- */
- void
-prof_child_enter(
- proftime_T *tm) /* place to store waittime */
-{
- funccall_T *fc = current_funccal;
-
- if (fc != NULL && fc->func->uf_profiling)
- profile_start(&fc->prof_child);
- script_prof_save(tm);
-}
-
-/*
- * Take care of time spent in a child.
- * Should always be called after prof_child_enter().
- */
- void
-prof_child_exit(
- proftime_T *tm) /* where waittime was stored */
-{
- funccall_T *fc = current_funccal;
-
- if (fc != NULL && fc->func->uf_profiling)
- {
- profile_end(&fc->prof_child);
- profile_sub_wait(tm, &fc->prof_child); /* don't count waiting time */
- profile_add(&fc->func->uf_tm_children, &fc->prof_child);
- profile_add(&fc->func->uf_tml_children, &fc->prof_child);
- }
- script_prof_restore(tm);
-}
-#endif
-
#ifdef FEAT_FOLDING
/*
@@ -2130,7 +1803,7 @@ skip_var_one(char_u *arg)
* List variables for hashtab "ht" with prefix "prefix".
* If "empty" is TRUE also list NULL strings as empty strings.
*/
- static void
+ void
list_hashtable_vars(
hashtab_T *ht,
char_u *prefix,
@@ -2223,17 +1896,6 @@ list_script_vars(int *first)
}
/*
- * List function variables, if there is a function.
- */
- static void
-list_func_vars(int *first)
-{
- if (current_funccal != NULL)
- list_hashtable_vars(&current_funccal->l_vars.dv_hashtab,
- (char_u *)"l:", FALSE, first);
-}
-
-/*
* List variables in "arg".
*/
static char_u *
@@ -2567,7 +2229,7 @@ check_changedtick(char_u *arg)
* When an evaluation error occurs "lp->ll_name" is NULL;
* Returns NULL for a parsing error. Still need to free items in "lp"!
*/
- static char_u *
+ char_u *
get_lval(
char_u *name,
typval_T *rettv,
@@ -2912,7 +2574,7 @@ get_lval(
/*
* Clear lval "lp" that was filled by get_lval().
*/
- static void
+ void
clear_lval(lval_T *lp)
{
vim_free(lp->ll_exp_name);
@@ -3405,139 +3067,6 @@ set_context_for_expression(
#endif /* FEAT_CMDL_COMPL */
/*
- * ":1,25call func(arg1, arg2)" function call.
- */
- void
-ex_call(exarg_T *eap)
-{
- char_u *arg = eap->arg;
- char_u *startarg;
- char_u *name;
- char_u *tofree;
- int len;
- typval_T rettv;
- linenr_T lnum;
- int doesrange;
- int failed = FALSE;
- funcdict_T fudi;
- partial_T *partial = NULL;
-
- if (eap->skip)
- {
- /* trans_function_name() doesn't work well when skipping, use eval0()
- * instead to skip to any following command, e.g. for:
- * :if 0 | call dict.foo().bar() | endif */
- ++emsg_skip;
- if (eval0(eap->arg, &rettv, &eap->nextcmd, FALSE) != FAIL)
- clear_tv(&rettv);
- --emsg_skip;
- return;
- }
-
- tofree = trans_function_name(&arg, eap->skip, TFN_INT, &fudi, &partial);
- 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)
- return;
-
- /* Increase refcount on dictionary, it could get deleted when evaluating
- * the arguments. */
- if (fudi.fd_dict != NULL)
- ++fudi.fd_dict->dv_refcount;
-
- /* If it is the name of a variable of type VAR_FUNC or VAR_PARTIAL use its
- * contents. For VAR_PARTIAL get its partial, unless we already have one
- * from trans_function_name(). */
- len = (int)STRLEN(tofree);
- name = deref_func_name(tofree, &len,
- partial != NULL ? NULL : &partial, FALSE);
-
- /* Skip white space to allow ":call func ()". Not good, but required for
- * backward compatibility. */
- startarg = skipwhite(arg);
- rettv.v_type = VAR_UNKNOWN; /* clear_tv() uses this */
-
- if (*startarg != '(')
- {
- EMSG2(_("E107: Missing parentheses: %s"), eap->arg);
- goto end;
- }
-
- /*
- * When skipping, evaluate the function once, to find the end of the
- * arguments.
- * When the function takes a range, this is discovered after the first
- * call, and the loop is broken.
- */
- if (eap->skip)
- {
- ++emsg_skip;
- lnum = eap->line2; /* do it once, also with an invalid range */
- }
- else
- lnum = eap->line1;
- for ( ; lnum <= eap->line2; ++lnum)
- {
- if (!eap->skip && eap->addr_count > 0)
- {
- curwin->w_cursor.lnum = lnum;
- curwin->w_cursor.col = 0;
-#ifdef FEAT_VIRTUALEDIT
- curwin->w_cursor.coladd = 0;
-#endif
- }
- arg = startarg;
- if (get_func_tv(name, (int)STRLEN(name), &rettv, &arg,
- eap->line1, eap->line2, &doesrange,
- !eap->skip, partial, fudi.fd_dict) == FAIL)
- {
- failed = TRUE;
- break;
- }
-
- /* Handle a function returning a Funcref, Dictionary or List. */
- if (handle_subscript(&arg, &rettv, !eap->skip, TRUE) == FAIL)
- {
- failed = TRUE;
- break;
- }
-
- clear_tv(&rettv);
- if (doesrange || eap->skip)
- break;
-
- /* Stop when immediately aborting on error, or when an interrupt
- * occurred or an exception was thrown but not caught.
- * get_func_tv() returned OK, so that the check for trailing
- * characters below is executed. */
- if (aborting())
- break;
- }
- if (eap->skip)
- --emsg_skip;
-
- if (!failed)
- {
- /* Check for trailing illegal characters and a following command. */
- if (!ends_excmd(*arg))
- {
- emsg_severe = TRUE;
- EMSG(_(e_trailing));
- }
- else
- eap->nextcmd = check_nextcmd(arg);
- }
-
-end:
- dict_unref(fudi.fd_dict);
- vim_free(tofree);
-}
-
-/*
* ":unlet[!] var1 ... " command.
*/
void
@@ -3703,22 +3232,23 @@ do_unlet(char_u *name, int forceit)
ht = find_var_ht(name, &varname);
if (ht != NULL && *varname != NUL)
{
- if (ht == &globvarht)
- d = &globvardict;
- else if (current_funccal != NULL
- && ht == &current_funccal->l_vars.dv_hashtab)
- d = &current_funccal->l_vars;
- else if (ht == &compat_hashtab)
- d = &vimvardict;
- else
- {
- di = find_var_in_ht(ht, *name, (char_u *)"", FALSE);
- d = di == NULL ? NULL : di->di_tv.vval.v_dict;
- }
+ d = get_current_funccal_dict(ht);
if (d == NULL)
{
- EMSG2(_(e_intern2), "do_unlet()");
- return FAIL;
+ if (ht == &globvarht)
+ d = &globvardict;
+ else if (ht == &compat_hashtab)
+ d = &vimvardict;
+ else
+ {
+ di = find_var_in_ht(ht, *name, (char_u *)"", FALSE);
+ d = di == NULL ? NULL : di->di_tv.vval.v_dict;
+ }
+ if (d == NULL)
+ {
+ EMSG2(_(e_intern2), "do_unlet()");
+ return FAIL;
+ }
}
hi = hash_find(ht, varname);
if (!HASHITEM_EMPTY(hi))
@@ -4115,7 +3645,7 @@ typedef enum
* Note: "rettv.v_lock" is not set.
* Return OK or FAIL.
*/
- static int
+ int
eval0(
char_u *arg,
typval_T *rettv,
@@ -6088,9 +5618,6 @@ get_copyID(void)
return current_copyID;
}
-/* Used by get_func_tv() */
-static garray_T funcargs = GA_EMPTY;
-
/*
* Garbage collection for lists and dictionaries.
*
@@ -6124,9 +5651,7 @@ garbage_collect(int testing)
buf_T *buf;
win_T *wp;
int i;
- funccall_T *fc, **pfc;
int did_free = FALSE;
- int did_free_funccal = FALSE;
#ifdef FEAT_WINDOWS
tabpage_T *tp;
#endif
@@ -6151,13 +5676,7 @@ garbage_collect(int testing)
/* Don't free variables in the previous_funccal list unless they are only
* referenced through previous_funccal. This must be first, because if
* the item is referenced elsewhere the funccal must not be freed. */
- for (fc = previous_funccal; fc != NULL; fc = fc->caller)
- {
- abort = abort || set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID + 1,
- NULL);
- abort = abort || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID + 1,
- NULL);
- }
+ abort = abort || set_ref_in_previous_funccal(copyID);
/* script-local variables */
for (i = 1; i <= ga_scripts.ga_len; ++i)
@@ -6189,16 +5708,10 @@ garbage_collect(int testing)
abort = abort || set_ref_in_ht(&globvarht, copyID, NULL);
/* function-local variables */
- for (fc = current_funccal; fc != NULL; fc = fc->caller)
- {
- abort = abort || set_ref_in_ht(&fc->l_vars.dv_hashtab, copyID, NULL);
- abort = abort || set_ref_in_ht(&fc->l_avars.dv_hashtab, copyID, NULL);
- }
+ abort = abort || set_ref_in_call_stack(copyID);
/* function call arguments, if v:testing is set. */
- for (i = 0; i < funcargs.ga_len; ++i)
- abort = abort || set_ref_in_item(((typval_T **)funcargs.ga_data)[i],
- copyID, NULL, NULL);
+ abort = abort || set_ref_in_func_args(copyID);
/* v: vars */
abort = abort || set_ref_in_ht(&vimvarht, copyID, NULL);
@@ -6236,24 +5749,9 @@ garbage_collect(int testing)
/*
* 3. Check if any funccal can be freed now.
+ * This may call us back recursively.
*/
- for (pfc = &previous_funccal; *pfc != NULL; )
- {
- if (can_free_funccal(*pfc, copyID))
- {
- fc = *pfc;
- *pfc = fc->caller;
- free_funccal(fc, TRUE);
- did_free = TRUE;
- did_free_funccal = TRUE;
- }
- else
- pfc = &(*pfc)->caller;
- }
- if (did_free_funccal)
- /* When a funccal was freed some more items might be garbage
- * collected, so run again. */
- (void)garbage_collect(testing);
+ free_unref_funccal(copyID, testing);
}
else if (p_verbose > 0)
{
@@ -6567,202 +6065,6 @@ set_ref_in_item(
return abort;
}
-/* Get function arguments. */
- static int
-get_function_args(
- char_u **argp,
- char_u endchar,
- garray_T *newargs,
- int *varargs,
- int skip)
-{
- int mustend = FALSE;
- char_u *arg = *argp;
- char_u *p = arg;
- int c;
- int i;
-
- if (newargs != NULL)
- ga_init2(newargs, (int)sizeof(char_u *), 3);
-
- if (varargs != NULL)
- *varargs = FALSE;
-
- /*
- * Isolate the arguments: "arg1, arg2, ...)"
- */
- while (*p != endchar)
- {
- if (p[0] == '.' && p[1] == '.' && p[2] == '.')
- {
- if (varargs != NULL)
- *varargs = TRUE;
- p += 3;
- mustend = TRUE;
- }
- else
- {
- arg = p;
- while (ASCII_ISALNUM(*p) || *p == '_')
- ++p;
- if (arg == p || isdigit(*arg)
- || (p - arg == 9 && STRNCMP(arg, "firstline", 9) == 0)
- || (p - arg == 8 && STRNCMP(arg, "lastline", 8) == 0))
- {
- if (!skip)
- EMSG2(_("E125: Illegal argument: %s"), arg);
- break;
- }
- if (newargs != NULL && ga_grow(newargs, 1) == FAIL)
- return FAIL;
- if (newargs != NULL)
- {
- c = *p;
- *p = NUL;
- arg = vim_strsave(arg);
- if (arg == NULL)
- goto err_ret;
-
- /* Check for duplicate argument name. */
- for (i = 0; i < newargs->ga_len; ++i)
- if (STRCMP(((char_u **)(newargs->ga_data))[i], arg) == 0)
- {
- EMSG2(_("E853: Duplicate argument name: %s"), arg);
- vim_free(arg);
- goto err_ret;
- }
- ((char_u **)(newargs->ga_data))[newargs->ga_len] = arg;
- newargs->ga_len++;
-
- *p = c;
- }
- if (*p == ',')
- ++p;
- else
- mustend = TRUE;
- }
- p = skipwhite(p);
- if (mustend && *p != endchar)
- {
- if (!skip)
- EMSG2(_(e_invarg2), *argp);
- break;
- }
- }
- ++p; /* skip the ')' */
-
- *argp = p;
- return OK;
-
-err_ret:
- if (newargs != NULL)
- ga_clear_strings(newargs);
- return FAIL;
-}
-
-/*
- * Parse a lambda expression and get a Funcref from "*arg".
- * Return OK or FAIL. Returns NOTDONE for dict or {expr}.
- */
- static int
-get_lambda_tv(char_u **arg, typval_T *rettv, int evaluate)
-{
- garray_T newargs;
- garray_T newlines;
- ufunc_T *fp = NULL;
- int varargs;
- int ret;
- char_u name[20];
- char_u *start = skipwhite(*arg + 1);
- char_u *s, *e;
- static int lambda_no = 0;
-
- ga_init(&newargs);
- ga_init(&newlines);
-
- /* First, check if this is a lambda expression. "->" must exist. */
- ret = get_function_args(&start, '-', NULL, NULL, TRUE);
- if (ret == FAIL || *start != '>')
- return NOTDONE;
-
- /* Parse the arguments again. */
- *arg = skipwhite(*arg + 1);
- ret = get_function_args(arg, '-', &newargs, &varargs, FALSE);
- if (ret == FAIL || **arg != '>')
- goto errret;
-
- /* Get the start and the end of the expression. */
- *arg = skipwhite(*arg + 1);
- s = *arg;
- ret = skip_expr(arg);
- if (ret == FAIL)
- goto errret;
- e = *arg;
- *arg = skipwhite(*arg);
- if (**arg != '}')
- goto errret;
- ++*arg;
-
- if (evaluate)
- {
- int len;
- char_u *p;
-
- fp = (ufunc_T *)alloc((unsigned)(sizeof(ufunc_T) + 20));
- if (fp == NULL)
- goto errret;
-
- sprintf((char*)name, "<lambda>%d", ++lambda_no);
-
- ga_init2(&newlines, (int)sizeof(char_u *), 1);
- if (ga_grow(&newlines, 1) == FAIL)
- goto errret;
-
- /* Add "return " before the expression.
- * TODO: Support multiple expressions. */
- len = 7 + e - s + 1;
- p = (char_u *)alloc(len);
- if (p == NULL)
- goto errret;
- ((char_u **)(newlines.ga_data))[newlines.ga_len++] = p;
- STRCPY(p, "return ");
- STRNCPY(p + 7, s, e - s);
- p[7 + e - s] = NUL;
-
- fp->uf_refcount = 1;
- STRCPY(fp->uf_name, name);
- hash_add(&func_hashtab, UF2HIKEY(fp));
- fp->uf_args = newargs;
- fp->uf_lines = newlines;
-
-#ifdef FEAT_PROFILE
- fp->uf_tml_count = NULL;
- fp->uf_tml_total = NULL;
- fp->uf_tml_self = NULL;
- fp->uf_profiling = FALSE;
- if (prof_def_func())
- func_do_profile(fp);
-#endif
- fp->uf_varargs = TRUE;
- fp->uf_flags = 0;
- fp->uf_calls = 0;
- fp->uf_script_ID = current_SID;
-
- rettv->vval.v_string = vim_strsave(name);
- rettv->v_type = VAR_FUNC;
- }