Problem: Vim9: redefining a function uses a new index every time.
Solution: When redefining a function clear the contents and re-use the
index.
return FAIL;
if (partial->pt_func != NULL
- && partial->pt_func->uf_dfunc_idx != UF_NOT_COMPILED)
+ && partial->pt_func->uf_def_status != UF_NOT_COMPILED)
{
if (call_def_function(partial->pt_func, argc, argv,
partial, rettv) == FAIL)
if (*name == 'v') // v: variable
return &vimvarht;
if (get_current_funccal() != NULL
- && get_current_funccal()->func->uf_dfunc_idx == UF_NOT_COMPILED)
+ && get_current_funccal()->func->uf_def_status == UF_NOT_COMPILED)
{
// a: and l: are only used in functions defined with ":function"
if (*name == 'a') // a: function argument
int compile_def_function(ufunc_T *ufunc, int set_return_type, cctx_T *outer_cctx);
void set_function_type(ufunc_T *ufunc);
void delete_instr(isn_T *isn);
-void delete_def_function(ufunc_T *ufunc);
+void clear_def_function(ufunc_T *ufunc);
void free_def_functions(void);
/* vim: set ft=c : */
typedef struct funccall_S funccall_T;
// values used for "uf_dfunc_idx"
-# define UF_NOT_COMPILED -2
-# define UF_TO_BE_COMPILED -1
+typedef enum {
+ UF_NOT_COMPILED,
+ UF_TO_BE_COMPILED,
+ UF_COMPILED
+} def_status_T;
/*
* Structure to hold info for a user function.
int uf_flags; // FC_ flags
int uf_calls; // nr of active calls
int uf_cleared; // func_clear() was already called
- int uf_dfunc_idx; // UF_NOT_COMPILED, UF_TO_BE_COMPILED or >= 0
+ def_status_T uf_def_status; // UF_NOT_COMPILED, UF_TO_BE_COMPILED, etc.
+ int uf_dfunc_idx; // only valid if uf_def_status is UF_COMPILED
garray_T uf_args; // arguments, including optional arguments
garray_T uf_def_args; // default argument expressions
fp = alloc_clear(offsetof(ufunc_T, uf_name) + STRLEN(name) + 1);
if (fp == NULL)
goto errret;
- fp->uf_dfunc_idx = UF_NOT_COMPILED;
+ fp->uf_def_status = UF_NOT_COMPILED;
pt = ALLOC_CLEAR_ONE(partial_T);
if (pt == NULL)
goto errret;
{
// When there is a def-function index do not actually remove the
// function, so we can find the index when defining the function again.
- if (fp->uf_dfunc_idx >= 0)
+ if (fp->uf_def_status == UF_COMPILED)
fp->uf_flags |= FC_DEAD;
else
hash_remove(&func_hashtab, hi);
// clear this function
func_clear_items(fp);
funccal_unref(fp->uf_scoped, fp, force);
- delete_def_function(fp);
+ clear_def_function(fp);
}
/*
func_clear_free(ufunc_T *fp, int force)
{
func_clear(fp, force);
- func_free(fp, force);
+ if (force || fp->uf_dfunc_idx == 0)
+ func_free(fp, force);
}
ga_init2(&fc->fc_funcs, sizeof(ufunc_T *), 1);
func_ptr_ref(fp);
- if (fp->uf_dfunc_idx != UF_NOT_COMPILED)
+ if (fp->uf_def_status != UF_NOT_COMPILED)
{
estack_push_ufunc(fp, 1);
save_current_sctx = current_sctx;
// clear the def function index now
fp = HI2UF(hi);
fp->uf_flags &= ~FC_DEAD;
- fp->uf_dfunc_idx = UF_NOT_COMPILED;
+ fp->uf_def_status = UF_NOT_COMPILED;
// Only free functions that are not refcounted, those are
// supposed to be freed when no longer referenced.
msg_start();
if (indent)
msg_puts(" ");
- if (fp->uf_dfunc_idx != UF_NOT_COMPILED)
+ if (fp->uf_def_status != UF_NOT_COMPILED)
msg_puts("def ");
else
msg_puts("function ");
}
msg_putchar(')');
- if (fp->uf_dfunc_idx != UF_NOT_COMPILED)
+ if (fp->uf_def_status != UF_NOT_COMPILED)
{
if (fp->uf_ret_type != &t_void)
{
if (!got_int)
{
msg_putchar('\n');
- if (fp->uf_dfunc_idx != UF_NOT_COMPILED)
+ if (fp->uf_def_status != UF_NOT_COMPILED)
msg_puts(" enddef");
else
msg_puts(" endfunction");
fp->uf_profiling = FALSE;
fp->uf_prof_initialized = FALSE;
#endif
+ clear_def_function(fp);
}
}
}
fp = alloc_clear(offsetof(ufunc_T, uf_name) + STRLEN(name) + 1);
if (fp == NULL)
goto erret;
- fp->uf_dfunc_idx = eap->cmdidx == CMD_def ? UF_TO_BE_COMPILED
+ fp->uf_def_status = eap->cmdidx == CMD_def ? UF_TO_BE_COMPILED
: UF_NOT_COMPILED;
if (fudi.fd_dict != NULL)
{
int lnum_save = SOURCING_LNUM;
- fp->uf_dfunc_idx = UF_TO_BE_COMPILED;
+ fp->uf_def_status = UF_TO_BE_COMPILED;
// error messages are for the first function line
SOURCING_LNUM = sourcing_lnum_top;
SOURCING_LNUM = lnum_save;
}
else
- fp->uf_dfunc_idx = UF_NOT_COMPILED;
+ fp->uf_def_status = UF_NOT_COMPILED;
fp->uf_lines = newlines;
if ((flags & FC_CLOSURE) != 0)
--todo;
ufunc = HI2UF(hi);
if (ufunc->uf_script_ctx.sc_sid == current_sctx.sc_sid
- && ufunc->uf_dfunc_idx == UF_TO_BE_COMPILED)
+ && ufunc->uf_def_status == UF_TO_BE_COMPILED)
{
compile_def_function(ufunc, FALSE, NULL);
static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 1023,
/**/
1022,
/**/
return FAIL;
}
- if (ufunc->uf_dfunc_idx != UF_NOT_COMPILED)
+ if (ufunc->uf_def_status != UF_NOT_COMPILED)
{
int i;
return FAIL;
}
}
- if (ufunc->uf_dfunc_idx == UF_TO_BE_COMPILED)
+ if (ufunc->uf_def_status == UF_TO_BE_COMPILED)
if (compile_def_function(ufunc, TRUE, NULL) == FAIL)
return FAIL;
}
if ((isn = generate_instr(cctx,
- ufunc->uf_dfunc_idx != UF_NOT_COMPILED ? ISN_DCALL
+ ufunc->uf_def_status != UF_NOT_COMPILED ? ISN_DCALL
: ISN_UCALL)) == NULL)
return FAIL;
- if (ufunc->uf_dfunc_idx != UF_NOT_COMPILED)
+ if (ufunc->uf_def_status != UF_NOT_COMPILED)
{
isn->isn_arg.dfunc.cdf_idx = ufunc->uf_dfunc_idx;
isn->isn_arg.dfunc.cdf_argcount = argcount;
// Compile it into instructions.
compile_def_function(ufunc, TRUE, cctx);
- if (ufunc->uf_dfunc_idx >= 0)
+ if (ufunc->uf_def_status == UF_COMPILED)
return generate_FUNCREF(cctx, ufunc->uf_dfunc_idx);
return FAIL;
}
if (ufunc == NULL)
return NULL;
- if (ufunc->uf_dfunc_idx == UF_TO_BE_COMPILED
+ if (ufunc->uf_def_status == UF_TO_BE_COMPILED
&& compile_def_function(ufunc, TRUE, cctx) == FAIL)
return NULL;
/*
* Add a function to the list of :def functions.
- * This "sets ufunc->uf_dfunc_idx" but the function isn't compiled yet.
+ * This sets "ufunc->uf_dfunc_idx" but the function isn't compiled yet.
*/
static int
add_def_function(ufunc_T *ufunc)
{
dfunc_T *dfunc;
+ if (def_functions.ga_len == 0)
+ {
+ // The first position is not used, so that a zero uf_dfunc_idx means it
+ // wasn't set.
+ if (ga_grow(&def_functions, 1) == FAIL)
+ return FAIL;
+ ++def_functions.ga_len;
+ }
+
// Add the function to "def_functions".
if (ga_grow(&def_functions, 1) == FAIL)
return FAIL;
// When using a function that was compiled before: Free old instructions.
// Otherwise add a new entry in "def_functions".
- if (ufunc->uf_dfunc_idx >= 0)
+ if (ufunc->uf_dfunc_idx > 0)
{
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
+ ufunc->uf_dfunc_idx;
dfunc->df_closure_count = cctx.ctx_closure_count;
if (cctx.ctx_outer_used)
ufunc->uf_flags |= FC_CLOSURE;
+ ufunc->uf_def_status = UF_COMPILED;
}
ret = OK;
if (!dfunc->df_deleted
&& ufunc->uf_dfunc_idx == def_functions.ga_len - 1)
--def_functions.ga_len;
- ufunc->uf_dfunc_idx = UF_NOT_COMPILED;
+ ufunc->uf_def_status = UF_NOT_COMPILED;
while (cctx.ctx_scope != NULL)
drop_scope(&cctx);
}
/*
- * When a user function is deleted, delete any associated def function.
+ * When a user function is deleted, clear the contents of any associated def
+ * function. The position in def_functions can be re-used.
*/
void
-delete_def_function(ufunc_T *ufunc)
+clear_def_function(ufunc_T *ufunc)
{
- if (ufunc->uf_dfunc_idx >= 0)
+ if (ufunc->uf_dfunc_idx > 0)
{
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
+ ufunc->uf_dfunc_idx;
delete_def_function_contents(dfunc);
+ ufunc->uf_def_status = UF_NOT_COMPILED;
}
}
int error;
int idx;
- if (ufunc->uf_dfunc_idx == UF_TO_BE_COMPILED
+ if (ufunc->uf_def_status == UF_TO_BE_COMPILED
&& compile_def_function(ufunc, FALSE, NULL) == FAIL)
return FAIL;
- if (ufunc->uf_dfunc_idx >= 0)
+ if (ufunc->uf_def_status == UF_COMPILED)
{
// The function has been compiled, can call it quickly. For a function
// that was defined later: we can call it directly next time.
// Like STACK_TV_VAR but use the outer scope
#define STACK_OUT_TV_VAR(idx) (((typval_T *)ectx.ec_outer_stack->ga_data) + ectx.ec_outer_frame + STACK_FRAME_SIZE + idx)
- if (ufunc->uf_dfunc_idx == UF_NOT_COMPILED
- || (ufunc->uf_dfunc_idx == UF_TO_BE_COMPILED
+ if (ufunc->uf_def_status == UF_NOT_COMPILED
+ || (ufunc->uf_def_status == UF_TO_BE_COMPILED
&& compile_def_function(ufunc, FALSE, NULL) == FAIL))
{
if (called_emsg == called_emsg_before)
semsg(_("E1061: Cannot find function %s"), eap->arg);
return;
}
- if (ufunc->uf_dfunc_idx == UF_TO_BE_COMPILED
+ if (ufunc->uf_def_status == UF_TO_BE_COMPILED
&& compile_def_function(ufunc, FALSE, NULL) == FAIL)
return;
- if (ufunc->uf_dfunc_idx < 0)
+ if (ufunc->uf_def_status != UF_COMPILED)
{
semsg(_("E1062: Function %s is not compiled"), eap->arg);
return;