diff options
Diffstat (limited to 'src/nvim/eval')
-rw-r--r-- | src/nvim/eval/funcs.c | 8 | ||||
-rw-r--r-- | src/nvim/eval/userfunc.c | 35 | ||||
-rw-r--r-- | src/nvim/eval/userfunc.h | 6 |
3 files changed, 34 insertions, 15 deletions
diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 217490ad10..ac28e3c3e0 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -7219,7 +7219,7 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv, FunPtr fptr) uint8_t *save_sourcing_name, *save_autocmd_fname, *save_autocmd_match; linenr_T save_sourcing_lnum; int save_autocmd_bufnr; - void *save_funccalp; + funccal_entry_T funccal_entry; if (l_provider_call_nesting) { // If this is called from a provider function, restore the scope @@ -7230,7 +7230,7 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv, FunPtr fptr) save_autocmd_fname = autocmd_fname; save_autocmd_match = autocmd_match; save_autocmd_bufnr = autocmd_bufnr; - save_funccalp = save_funccal(); + save_funccal(&funccal_entry); current_sctx = provider_caller_scope.script_ctx; sourcing_name = provider_caller_scope.sourcing_name; @@ -7238,7 +7238,7 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv, FunPtr fptr) autocmd_fname = provider_caller_scope.autocmd_fname; autocmd_match = provider_caller_scope.autocmd_match; autocmd_bufnr = provider_caller_scope.autocmd_bufnr; - restore_funccal(provider_caller_scope.funccalp); + set_current_funccal((funccall_T *)(provider_caller_scope.funccalp)); } @@ -7256,7 +7256,7 @@ static void f_rpcrequest(typval_T *argvars, typval_T *rettv, FunPtr fptr) autocmd_fname = save_autocmd_fname; autocmd_match = save_autocmd_match; autocmd_bufnr = save_autocmd_bufnr; - restore_funccal(save_funccalp); + restore_funccal(); } if (ERROR_SET(&err)) { diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index ae8557a8bc..9e123e505f 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -1106,21 +1106,26 @@ static bool func_name_refcount(char_u *name) return isdigit(*name) || *name == '<'; } -/* - * 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; +static funccal_entry_T *funccal_stack = NULL; +// Save the current function call pointer, and set it to NULL. +// Used when executing autocommands and for ":source". +void save_funccal(funccal_entry_T *entry) +{ + entry->top_funccal = current_funccal; + entry->next = funccal_stack; + funccal_stack = entry; current_funccal = NULL; - return (void *)fc; } -void restore_funccal(void *vfc) +void restore_funccal(void) { - current_funccal = (funccall_T *)vfc; + if (funccal_stack == NULL) { + IEMSG("INTERNAL: restore_funccal()"); + } else { + current_funccal = funccal_stack->top_funccal; + funccal_stack = funccal_stack->next; + } } funccall_T *get_current_funccal(void) @@ -1128,6 +1133,11 @@ funccall_T *get_current_funccal(void) return current_funccal; } +void set_current_funccal(funccall_T *fc) +{ + current_funccal = fc; +} + #if defined(EXITFREE) void free_all_functions(void) { @@ -1137,10 +1147,13 @@ void free_all_functions(void) uint64_t todo = 1; uint64_t used; - // Clean up the call stack. + // Clean up the current_funccal chain and the funccal stack. while (current_funccal != NULL) { tv_clear(current_funccal->rettv); cleanup_function_call(current_funccal); + if (current_funccal == NULL && funccal_stack != NULL) { + restore_funccal(); + } } // First clear what the functions contain. Since this may lower the diff --git a/src/nvim/eval/userfunc.h b/src/nvim/eval/userfunc.h index ad8e071548..e8ad0bf1da 100644 --- a/src/nvim/eval/userfunc.h +++ b/src/nvim/eval/userfunc.h @@ -11,6 +11,12 @@ typedef struct { dictitem_T *fd_di; ///< Dictionary item used. } funcdict_T; +typedef struct funccal_entry funccal_entry_T; +struct funccal_entry { + void *top_funccal; + funccal_entry_T *next; +}; + /// errors for when calling a function typedef enum { ERROR_UNKNOWN = 0, |