diff options
author | Bram Moolenaar <Bram@vim.org> | 2016-07-17 18:29:19 +0200 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2016-07-17 18:29:19 +0200 |
commit | a9b579f3d7463720a316e11e77a7a9fbb9267986 (patch) | |
tree | 44c8c9db5628fdb95f6fa89ce7b3e89cddedb839 | |
parent | da861d631d7e22654faee2789286c685ad548911 (diff) |
patch 7.4.2058v7.4.2058
Problem: eval.c is too big.
Solution: Move user functions to userfunc.c
-rw-r--r-- | Filelist | 2 | ||||
-rw-r--r-- | src/Makefile | 10 | ||||
-rw-r--r-- | src/eval.c | 3579 | ||||
-rw-r--r-- | src/globals.h | 2 | ||||
-rw-r--r-- | src/proto.h | 1 | ||||
-rw-r--r-- | src/proto/eval.pro | 47 | ||||
-rw-r--r-- | src/proto/userfunc.pro | 52 | ||||
-rw-r--r-- | src/structs.h | 45 | ||||
-rw-r--r-- | src/userfunc.c | 3494 | ||||
-rw-r--r-- | src/version.c | 2 | ||||
-rw-r--r-- | src/vim.h | 25 |
11 files changed, 3728 insertions, 3531 deletions
@@ -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(¤t_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 == ¤t_funccal->l_vars.dv_hashtab) - d = ¤t_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; - } |