Patch 8.2.0823
Problem: Vim9: script reload test is disabled.
Solution: Compile a function in the context of the script where it was
defined. Set execution stack for compiled function. Add a test
that an error is reported for the right file/function.
Files: src/vim9compile.c, src/vim9execute.c, src/scriptfile.c,
src/proto/
scriptfile.pro, src/userfunc.c, src/globals.h,
src/structs.h, src/ex_docmd.c, src/ex_eval.c,
src/testdir/test_vim9_script.vim
*** ../vim-8.2.0822/src/vim9compile.c 2020-05-25 00:28:29.604712788 +0200
--- src/vim9compile.c 2020-05-25 21:43:32.142303773 +0200
***************
*** 2323,2330 ****
}
line = ((char_u **)cctx->ctx_ufunc->uf_lines.ga_data)[cctx->ctx_lnum];
cctx->ctx_line_start = line;
! SOURCING_LNUM = cctx->ctx_ufunc->uf_script_ctx.sc_lnum
! + cctx->ctx_lnum + 1;
} while (line == NULL || *skipwhite(line) == NUL);
return line;
}
--- 2323,2329 ----
}
line = ((char_u **)cctx->ctx_ufunc->uf_lines.ga_data)[cctx->ctx_lnum];
cctx->ctx_line_start = line;
! SOURCING_LNUM = cctx->ctx_lnum + 1;
} while (line == NULL || *skipwhite(line) == NUL);
return line;
}
***************
*** 6349,6362 ****
int called_emsg_before = called_emsg;
int ret = FAIL;
sctx_T save_current_sctx = current_sctx;
int emsg_before = called_emsg;
if (ufunc->uf_dfunc_idx >= 0)
{
- // Redefining a function that was compiled before.
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
+ ufunc->uf_dfunc_idx;
- // Free old instructions.
delete_def_function_contents(dfunc);
}
else if (add_def_function(ufunc) == FAIL)
--- 6348,6362 ----
int called_emsg_before = called_emsg;
int ret = FAIL;
sctx_T save_current_sctx = current_sctx;
+ int do_estack_push;
int emsg_before = called_emsg;
+ // 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)
{
dfunc_T *dfunc = ((dfunc_T *)def_functions.ga_data)
+ ufunc->uf_dfunc_idx;
delete_def_function_contents(dfunc);
}
else if (add_def_function(ufunc) == FAIL)
***************
*** 6373,6381 ****
ga_init2(&cctx.ctx_instr, sizeof(isn_T), 50);
instr = &cctx.ctx_instr;
! // Most modern script version.
current_sctx.sc_version = SCRIPT_VERSION_VIM9;
if (ufunc->uf_def_args.ga_len > 0)
{
int count = ufunc->uf_def_args.ga_len;
--- 6373,6389 ----
ga_init2(&cctx.ctx_instr, sizeof(isn_T), 50);
instr = &cctx.ctx_instr;
! // Set the context to the function, it may be compiled when called from
! // another script. Set the script version to the most modern one.
! // The line number will be set in next_line_from_context().
! current_sctx = ufunc->uf_script_ctx;
current_sctx.sc_version = SCRIPT_VERSION_VIM9;
+ // Make sure error messages are OK.
+ do_estack_push = !estack_top_is_ufunc(ufunc, 1);
+ if (do_estack_push)
+ estack_push_ufunc(ufunc, 1);
+
if (ufunc->uf_def_args.ga_len > 0)
{
int count = ufunc->uf_def_args.ga_len;
***************
*** 6795,6800 ****
--- 6803,6811 ----
}
current_sctx = save_current_sctx;
+ if (do_estack_push)
+ estack_pop();
+
free_imported(&cctx);
free_locals(&cctx);
ga_clear(&cctx.ctx_type_stack);
*** ../vim-8.2.0822/src/vim9execute.c 2020-05-24 23:00:06.444196001 +0200
--- src/vim9execute.c 2020-05-25 21:47:59.449426891 +0200
***************
*** 230,236 ****
// Set execution state to the start of the called function.
ectx->ec_dfunc_idx = cdf_idx;
ectx->ec_instr = dfunc->df_instr;
! estack_push_ufunc(ETYPE_UFUNC, dfunc->df_ufunc, 1);
// Decide where to start execution, handles optional arguments.
init_instr_idx(ufunc, argcount, ectx);
--- 230,236 ----
// Set execution state to the start of the called function.
ectx->ec_dfunc_idx = cdf_idx;
ectx->ec_instr = dfunc->df_instr;
! estack_push_ufunc(dfunc->df_ufunc, 1);
// Decide where to start execution, handles optional arguments.
init_instr_idx(ufunc, argcount, ectx);
***************
*** 656,661 ****
--- 656,662 ----
int defcount = ufunc->uf_args.ga_len - argc;
int save_sc_version = current_sctx.sc_version;
int breakcheck_count = 0;
+ int called_emsg_before = called_emsg;
// Get pointer to item in the stack.
#define STACK_TV(idx) (((typval_T *)ectx.ec_stack.ga_data) + idx)
***************
*** 673,679 ****
--- 674,686 ----
if (ufunc->uf_dfunc_idx == UF_NOT_COMPILED
|| (ufunc->uf_dfunc_idx == UF_TO_BE_COMPILED
&& compile_def_function(ufunc, FALSE, NULL) == FAIL))
+ {
+ if (called_emsg == called_emsg_before)
+ semsg(_("E1091: Function is not compiled: %s"),
+ ufunc->uf_name_exp == NULL
+ ? ufunc->uf_name : ufunc->uf_name_exp);
return FAIL;
+ }
{
// Check the function was really compiled.
*** ../vim-8.2.0822/src/scriptfile.c 2020-05-25 20:33:51.766542661 +0200
--- src/scriptfile.c 2020-05-25 21:40:41.370882220 +0200
***************
*** 69,82 ****
* Add a user function to the execution stack.
*/
void
! estack_push_ufunc(etype_T type, ufunc_T *ufunc, long lnum)
{
! estack_T *entry = estack_push(type,
ufunc->uf_name_exp != NULL
? ufunc->uf_name_exp : ufunc->uf_name, lnum);
if (entry != NULL)
entry->es_info.ufunc = ufunc;
}
#endif
/*
--- 69,99 ----
* Add a user function to the execution stack.
*/
void
! estack_push_ufunc(ufunc_T *ufunc, long lnum)
{
! estack_T *entry = estack_push(ETYPE_UFUNC,
ufunc->uf_name_exp != NULL
? ufunc->uf_name_exp : ufunc->uf_name, lnum);
if (entry != NULL)
entry->es_info.ufunc = ufunc;
}
+
+ /*
+ * Return TRUE if "ufunc" with "lnum" is already at the top of the exe stack.
+ */
+ int
+ estack_top_is_ufunc(ufunc_T *ufunc, long lnum)
+ {
+ estack_T *entry;
+
+ if (exestack.ga_len == 0)
+ return FALSE;
+ entry = ((estack_T *)exestack.ga_data) + exestack.ga_len - 1;
+ return entry->es_type == ETYPE_UFUNC
+ && STRCMP( entry->es_name, ufunc->uf_name_exp != NULL
+ ? ufunc->uf_name_exp : ufunc->uf_name) == 0
+ && entry->es_lnum == lnum;
+ }
#endif
/*
*** ../vim-8.2.0822/src/proto/
scriptfile.pro 2020-05-25 20:33:51.766542661 +0200
--- src/proto/
scriptfile.pro 2020-05-25 21:43:04.822395175 +0200
***************
*** 1,7 ****
/* scriptfile.c */
void estack_init(void);
estack_T *estack_push(etype_T type, char_u *name, long lnum);
! void estack_push_ufunc(etype_T type, ufunc_T *ufunc, long lnum);
void estack_pop(void);
char_u *estack_sfile(void);
void ex_runtime(exarg_T *eap);
--- 1,8 ----
/* scriptfile.c */
void estack_init(void);
estack_T *estack_push(etype_T type, char_u *name, long lnum);
! void estack_push_ufunc(ufunc_T *ufunc, long lnum);
! int estack_top_is_ufunc(ufunc_T *ufunc, long lnum);
void estack_pop(void);
char_u *estack_sfile(void);
void ex_runtime(exarg_T *eap);
*** ../vim-8.2.0822/src/userfunc.c 2020-05-24 23:45:20.529386094 +0200
--- src/userfunc.c 2020-05-25 21:43:27.258320081 +0200
***************
*** 1114,1124 ****
if (fp->uf_dfunc_idx != UF_NOT_COMPILED)
{
! estack_push_ufunc(ETYPE_UFUNC, fp, 1);
save_current_sctx = current_sctx;
current_sctx = fp->uf_script_ctx;
! // Execute the compiled function.
call_def_function(fp, argcount, argvars, funcexe->partial, rettv);
--depth;
current_funccal = fc->caller;
--- 1114,1124 ----
if (fp->uf_dfunc_idx != UF_NOT_COMPILED)
{
! estack_push_ufunc(fp, 1);
save_current_sctx = current_sctx;
current_sctx = fp->uf_script_ctx;
! // Execute the function, possibly compiling it first.
call_def_function(fp, argcount, argvars, funcexe->partial, rettv);
--depth;
current_funccal = fc->caller;
***************
*** 1288,1294 ****
++sandbox;
}
! estack_push_ufunc(ETYPE_UFUNC, fp, 1);
ESTACK_CHECK_SETUP
if (p_verbose >= 12)
{
--- 1288,1294 ----
++sandbox;
}
! estack_push_ufunc(fp, 1);
ESTACK_CHECK_SETUP
if (p_verbose >= 12)
{
*** ../vim-8.2.0822/src/globals.h 2020-05-24 17:23:41.834154785 +0200
--- src/globals.h 2020-05-25 22:13:26.909284260 +0200
***************
*** 344,350 ****
* field of a later list element, when the "emsg_severe" flag was set when the
* emsg() call was made.
*/
! EXTERN struct msglist **msg_list INIT(= NULL);
/*
* suppress_errthrow: When TRUE, don't convert an error to an exception. Used
--- 344,350 ----
* field of a later list element, when the "emsg_severe" flag was set when the
* emsg() call was made.
*/
! EXTERN msglist_T **msg_list INIT(= NULL);
/*
* suppress_errthrow: When TRUE, don't convert an error to an exception. Used
*** ../vim-8.2.0822/src/structs.h 2020-05-24 23:00:06.440196016 +0200
--- src/structs.h 2020-05-25 22:20:33.992326158 +0200
***************
*** 927,939 ****
* A list of error messages that can be converted to an exception. "throw_msg"
* is only set in the first element of the list. Usually, it points to the
* original message stored in that element, but sometimes it points to a later
! * message in the list. See cause_errthrow() below.
*/
struct msglist
{
! char *msg; // original message
! char *throw_msg; // msg to throw: usually original one
! struct msglist *next; // next of several messages in a row
};
/*
--- 927,942 ----
* A list of error messages that can be converted to an exception. "throw_msg"
* is only set in the first element of the list. Usually, it points to the
* original message stored in that element, but sometimes it points to a later
! * message in the list. See cause_errthrow().
*/
+ typedef struct msglist msglist_T;
struct msglist
{
! char *msg; // original message, allocated
! char *throw_msg; // msg to throw: usually original one
! char_u *sfile; // value from estack_sfile(), allocated
! long slnum; // line number for "sfile"
! msglist_T *next; // next of several messages in a row
};
/*
***************
*** 1516,1521 ****
--- 1519,1525 ----
#if defined(FEAT_EVAL) || defined(PROTO)
typedef struct funccall_S funccall_T;
+ // values used for "uf_dfunc_idx"
# define UF_NOT_COMPILED -2
# define UF_TO_BE_COMPILED -1
*** ../vim-8.2.0822/src/ex_docmd.c 2020-05-25 20:33:51.770542645 +0200
--- src/ex_docmd.c 2020-05-25 22:11:45.593473909 +0200
***************
*** 634,641 ****
int *dbg_tick = NULL; // ptr to dbg_tick field in cookie
struct dbg_stuff debug_saved; // saved things for debug mode
int initial_trylevel;
! struct msglist **saved_msg_list = NULL;
! struct msglist *private_msg_list;
// "fgetline" and "cookie" passed to do_one_cmd()
char_u *(*cmd_getline)(int, void *, int, int);
--- 634,641 ----
int *dbg_tick = NULL; // ptr to dbg_tick field in cookie
struct dbg_stuff debug_saved; // saved things for debug mode
int initial_trylevel;
! msglist_T **saved_msg_list = NULL;
! msglist_T *private_msg_list;
// "fgetline" and "cookie" passed to do_one_cmd()
char_u *(*cmd_getline)(int, void *, int, int);
***************
*** 1238,1244 ****
if (did_throw)
{
void *p = NULL;
! struct msglist *messages = NULL, *next;
/*
* If the uncaught exception is a user exception, report it as an
--- 1238,1244 ----
if (did_throw)
{
void *p = NULL;
! msglist_T *messages = NULL, *next;
/*
* If the uncaught exception is a user exception, report it as an
*** ../vim-8.2.0822/src/ex_eval.c 2020-05-14 22:41:10.225637575 +0200
--- src/ex_eval.c 2020-05-25 22:28:03.135166892 +0200
***************
*** 146,153 ****
int severe,
int *ignore)
{
! struct msglist *elem;
! struct msglist **plist;
/*
* Do nothing when displaying the interrupt message or reporting an
--- 146,153 ----
int severe,
int *ignore)
{
! msglist_T *elem;
! msglist_T **plist;
/*
* Do nothing when displaying the interrupt message or reporting an
***************
*** 251,257 ****
while (*plist != NULL)
plist = &(*plist)->next;
! elem = ALLOC_ONE(struct msglist);
if (elem == NULL)
{
suppress_errthrow = TRUE;
--- 251,257 ----
while (*plist != NULL)
plist = &(*plist)->next;
! elem = ALLOC_CLEAR_ONE(msglist_T);
if (elem == NULL)
{
suppress_errthrow = TRUE;
***************
*** 287,292 ****
--- 287,297 ----
else
(*msg_list)->throw_msg = tmsg;
}
+
+ // Get the source name and lnum now, it may change before
+ // reaching do_errthrow().
+ elem->sfile = estack_sfile();
+ elem->slnum = SOURCING_LNUM;
}
}
}
***************
*** 298,312 ****
* Free a "msg_list" and the messages it contains.
*/
static void
! free_msglist(struct msglist *l)
{
! struct msglist *messages, *next;
messages = l;
while (messages != NULL)
{
next = messages->next;
vim_free(messages->msg);
vim_free(messages);
messages = next;
}
--- 303,318 ----
* Free a "msg_list" and the messages it contains.
*/
static void
! free_msglist(msglist_T *l)
{
! msglist_T *messages, *next;
messages = l;
while (messages != NULL)
{
next = messages->next;
vim_free(messages->msg);
+ vim_free(messages->sfile);
vim_free(messages);
messages = next;
}
***************
*** 428,434 ****
if (type == ET_ERROR)
{
*should_free = TRUE;
! mesg = ((struct msglist *)value)->throw_msg;
if (cmdname != NULL && *cmdname != NUL)
{
cmdlen = (int)STRLEN(cmdname);
--- 434,440 ----
if (type == ET_ERROR)
{
*should_free = TRUE;
! mesg = ((msglist_T *)value)->throw_msg;
if (cmdname != NULL && *cmdname != NUL)
{
cmdlen = (int)STRLEN(cmdname);
***************
*** 526,548 ****
if (type == ET_ERROR)
// Store the original message and prefix the exception value with
// "Vim:" or, if a command name is given, "Vim(cmdname):".
! excp->messages = (struct msglist *)value;
excp->value = get_exception_string(value, type, cmdname, &should_free);
if (excp->value == NULL && should_free)
goto nomem;
excp->type = type;
! excp->throw_name = estack_sfile();
! if (excp->throw_name == NULL)
! excp->throw_name = vim_strsave((char_u *)"");
! if (excp->throw_name == NULL)
{
! if (should_free)
! vim_free(excp->value);
! goto nomem;
}
- excp->throw_lnum = SOURCING_LNUM;
if (p_verbose >= 13 || debug_break_level > 0)
{
--- 532,565 ----
if (type == ET_ERROR)
// Store the original message and prefix the exception value with
// "Vim:" or, if a command name is given, "Vim(cmdname):".
! excp->messages = (msglist_T *)value;
excp->value = get_exception_string(value, type, cmdname, &should_free);
if (excp->value == NULL && should_free)
goto nomem;
excp->type = type;
! if (type == ET_ERROR && ((msglist_T *)value)->sfile != NULL)
{
! msglist_T *entry = (msglist_T *)value;
!
! excp->throw_name = entry->sfile;
! entry->sfile = NULL;
! excp->throw_lnum = entry->slnum;
! }
! else
! {
! excp->throw_name = estack_sfile();
! if (excp->throw_name == NULL)
! excp->throw_name = vim_strsave((char_u *)"");
! if (excp->throw_name == NULL)
! {
! if (should_free)
! vim_free(excp->value);
! goto nomem;
! }
! excp->throw_lnum = SOURCING_LNUM;
}
if (p_verbose >= 13 || debug_break_level > 0)
{
*** ../vim-8.2.0822/src/testdir/test_vim9_script.vim 2020-05-24 23:00:06.444196001 +0200
--- src/testdir/test_vim9_script.vim 2020-05-25 22:30:21.946792717 +0200
***************
*** 745,753 ****
enddef
def Test_vim9script_reload_import()
- " TODO: make it work to compile when not in the script context anymore
- return
-
let lines =<< trim END
vim9script
const var = ''
--- 745,750 ----
***************
*** 797,805 ****
enddef
def Test_vim9script_reload_delfunc()
- " TODO: make it work to compile when not in the script context anymore
- return
-
let first_lines =<< trim END
vim9script
def FuncYes(): string
--- 794,799 ----
***************
*** 920,925 ****
--- 914,950 ----
delete('import', 'rf')
enddef
+ def Test_import_compile_error()
+ let export_lines = [
+ 'vim9script',
+ 'export def ExpFunc(): string',
+ ' return notDefined',
+ 'enddef',
+ ]
+ writefile(export_lines, 'Xexported.vim')
+
+ let import_lines = [
+ 'vim9script',
+ 'import ExpFunc from "./Xexported.vim"',
+ 'def ImpFunc()',
+ ' echo ExpFunc()',
+ 'enddef',
+ 'defcompile',
+ ]
+ writefile(import_lines, 'Ximport.vim')
+
+ try
+ source Ximport.vim
+ catch /E1001/
+ " Error should be fore the Xexported.vim file.
+ assert_match('E1001: variable not found: notDefined', v:exception)
+ assert_match('function <SNR>\d\+_ImpFunc\[1\]..<SNR>\d\+_ExpFunc, line 1', v:throwpoint)
+ endtry
+
+ delete('Xexported.vim')
+ delete('Ximport.vim')
+ enddef
+
def Test_fixed_size_list()
" will be allocated as one piece of memory, check that changes work
let l = [1, 2, 3, 4]
*** ../vim-8.2.0822/src/version.c 2020-05-25 20:33:51.770542645 +0200
--- src/version.c 2020-05-25 20:44:18.332277232 +0200
***************
*** 748,749 ****
--- 748,751 ----
{ /* Add new patch number below this line */
+ /**/
+ 823,
/**/
--
hundred-and-one symptoms of being an internet addict:
176. You lie, even to user-friends, about how long you were online yesterday.
/// Bram Moolenaar -- Br...@Moolenaar.net --
http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features --
http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language --
http://www.Zimbu.org ///
\\\ help me help AIDS victims --
http://ICCF-Holland.org ///