0
0
mirror of https://github.com/vim/vim.git synced 2025-07-26 11:04:33 -04:00

patch 8.2.0595: Vim9: not all commands using ends_excmd() tested

Problem:    Vim9: not all commands using ends_excmd() tested.
Solution:   Find # comment after regular commands. Add more tests.  Report
            error for where it was caused.
This commit is contained in:
Bram Moolenaar 2020-04-18 19:53:28 +02:00
parent b6fb0516ec
commit a26b9700d7
10 changed files with 122 additions and 15 deletions

View File

@ -2706,6 +2706,17 @@ common_function(typval_T *argvars, typval_T *rettv, int is_funcref)
TFN_INT | TFN_QUIET | TFN_NO_AUTOLOAD | TFN_NO_DEREF, NULL, NULL);
if (*name != NUL)
s = NULL;
else if (trans_name != NULL
&& ASCII_ISUPPER(*s)
&& current_sctx.sc_version == SCRIPT_VERSION_VIM9
&& find_func(trans_name, NULL) == NULL)
{
// With Vim9 script "MyFunc" can be script-local to the current
// script or global. The script-local name is not found, assume
// global.
vim_free(trans_name);
trans_name = vim_strsave(s);
}
}
if (s == NULL || *s == NUL || (use_string && VIM_ISDIGIT(*s))

View File

@ -1836,7 +1836,8 @@ do_one_cmd(
*/
if (*ea.cmd == NUL || *ea.cmd == '"'
#ifdef FEAT_EVAL
|| (*ea.cmd == '#' && !starts_with_colon && in_vim9script())
|| (*ea.cmd == '#' && ea.cmd[1] != '{'
&& !starts_with_colon && in_vim9script())
#endif
|| (ea.nextcmd = check_nextcmd(ea.cmd)) != NULL)
{
@ -4436,6 +4437,10 @@ separate_nextcmd(exarg_T *eap)
|| p != eap->arg)
&& (eap->cmdidx != CMD_redir
|| p != eap->arg + 1 || p[-1] != '@'))
#ifdef FEAT_EVAL
|| (*p == '#' && in_vim9script()
&& p[1] != '{' && p > eap->cmd && VIM_ISWHITE(p[-1]))
#endif
|| *p == '|' || *p == '\n')
{
/*
@ -4790,7 +4795,7 @@ ends_excmd2(char_u *cmd_start UNUSED, char_u *cmd)
int c = *cmd;
#ifdef FEAT_EVAL
if (c == '#' && (cmd == cmd_start || VIM_ISWHITE(cmd[-1])))
if (c == '#' && cmd[1] != '{' && (cmd == cmd_start || VIM_ISWHITE(cmd[-1])))
return in_vim9script();
#endif
return (c == NUL || c == '|' || c == '"' || c == '\n');

View File

@ -20,6 +20,7 @@ int call_callback(callback_T *callback, int len, typval_T *rettv, int argcount,
void user_func_error(int error, char_u *name);
int call_func(char_u *funcname, int len, typval_T *rettv, int argcount_in, typval_T *argvars_in, funcexe_T *funcexe);
char_u *trans_function_name(char_u **pp, int skip, int flags, funcdict_T *fdp, partial_T **partial);
char_u *untrans_function_name(char_u *name);
void ex_function(exarg_T *eap);
int eval_fname_script(char_u *p);
int translated_function_exists(char_u *name);

View File

@ -251,8 +251,8 @@ def Test_disassemble_pcall()
enddef
def FuncWithForwardCall(): string
return DefinedLater("yes")
def s:FuncWithForwardCall(): string
return g:DefinedLater("yes")
enddef
def DefinedLater(arg: string): string
@ -260,11 +260,11 @@ def DefinedLater(arg: string): string
enddef
def Test_disassemble_update_instr()
let res = execute('disass FuncWithForwardCall')
let res = execute('disass s:FuncWithForwardCall')
assert_match('FuncWithForwardCall.*' ..
'return DefinedLater("yes").*' ..
'return g:DefinedLater("yes").*' ..
'\d PUSHS "yes".*' ..
'\d UCALL DefinedLater(argc 1).*' ..
'\d UCALL g:DefinedLater(argc 1).*' ..
'\d CHECKTYPE string stack\[-1].*' ..
'\d RETURN.*',
res)
@ -272,9 +272,9 @@ def Test_disassemble_update_instr()
" Calling the function will change UCALL into the faster DCALL
assert_equal('yes', FuncWithForwardCall())
res = execute('disass FuncWithForwardCall')
res = execute('disass s:FuncWithForwardCall')
assert_match('FuncWithForwardCall.*' ..
'return DefinedLater("yes").*' ..
'return g:DefinedLater("yes").*' ..
'\d PUSHS "yes".*' ..
'\d DCALL DefinedLater(argc 1).*' ..
'\d CHECKTYPE string stack\[-1].*' ..

View File

@ -587,7 +587,7 @@ def Test_vim9script_fails()
CheckScriptFailure(['vim9script', 'export echo 134'], 'E1043:')
assert_fails('vim9script', 'E1038')
assert_fails('export something', 'E1042')
assert_fails('export something', 'E1043')
enddef
def Test_vim9script_reload()
@ -1098,6 +1098,27 @@ def Test_vim9_comment()
], 'E488:')
enddef
def Test_vim9_comment_not_compiled()
au TabEnter *.vim let g:entered = 1
au TabEnter *.x let g:entered = 2
edit test.vim
doautocmd TabEnter #comment
assert_equal(1, g:entered)
doautocmd TabEnter f.x
assert_equal(2, g:entered)
g:entered = 0
doautocmd TabEnter f.x #comment
assert_equal(2, g:entered)
assert_fails('doautocmd Syntax#comment', 'E216:')
au! TabEnter
unlet g:entered
enddef
" Keep this last, it messes up highlighting.
def Test_substitute_cmd()
new

View File

@ -1663,6 +1663,7 @@ do_ucmd(exarg_T *eap)
#ifdef FEAT_EVAL
current_sctx.sc_sid = cmd->uc_script_ctx.sc_sid;
current_sctx.sc_version = cmd->uc_script_ctx.sc_version;
#endif
(void)do_cmdline(buf, eap->getline, eap->cookie,
DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_KEYTYPED);

View File

@ -730,7 +730,8 @@ find_func_even_dead(char_u *name, cctx_T *cctx)
}
}
hi = hash_find(&func_hashtab, name);
hi = hash_find(&func_hashtab,
STRNCMP(name, "g:", 2) == 0 ? name + 2 : name);
if (!HASHITEM_EMPTY(hi))
return HI2UF(hi);
@ -1651,7 +1652,7 @@ free_all_functions(void)
/*
* Return TRUE if "name" looks like a builtin function name: starts with a
* lower case letter and doesn't contain AUTOLOAD_CHAR.
* lower case letter and doesn't contain AUTOLOAD_CHAR or ':'.
* "len" is the length of "name", or -1 for NUL terminated.
*/
int
@ -1659,7 +1660,7 @@ builtin_function(char_u *name, int len)
{
char_u *p;
if (!ASCII_ISLOWER(name[0]))
if (!ASCII_ISLOWER(name[0]) || name[1] == ':')
return FALSE;
p = vim_strchr(name, AUTOLOAD_CHAR);
return p == NULL || (len > 0 && p > name + len);
@ -1894,6 +1895,15 @@ call_func(
// loaded a package, search for the function again
fp = find_func(rfname, NULL);
}
if (fp == NULL)
{
char_u *p = untrans_function_name(rfname);
// If using Vim9 script try not local to the script.
// TODO: should not do this if the name started with "s:".
if (p != NULL)
fp = find_func(p, NULL);
}
if (fp != NULL && (fp->uf_flags & FC_DELETED))
error = FCERR_DELETED;
@ -2297,6 +2307,27 @@ theend:
return name;
}
/*
* Assuming "name" is the result of trans_function_name() and it was prefixed
* to use the script-local name, return the unmodified name (points into
* "name"). Otherwise return NULL.
* This can be used to first search for a script-local function and fall back
* to the global function if not found.
*/
char_u *
untrans_function_name(char_u *name)
{
char_u *p;
if (*name == K_SPECIAL && current_sctx.sc_version == SCRIPT_VERSION_VIM9)
{
p = vim_strchr(name, '_');
if (p != NULL)
return p + 1;
}
return NULL;
}
/*
* ":function"
*/
@ -2467,6 +2498,16 @@ ex_function(exarg_T *eap)
if (!eap->skip && !got_int)
{
fp = find_func(name, NULL);
if (fp == NULL && ASCII_ISUPPER(*eap->arg))
{
char_u *up = untrans_function_name(name);
// With Vim9 script the name was made script-local, if not
// found try again with the original name.
if (p != NULL)
fp = find_func(up, NULL);
}
if (fp != NULL)
{
list_func_head(fp, TRUE);
@ -2494,7 +2535,7 @@ ex_function(exarg_T *eap)
}
}
else
emsg_funcname(N_("E123: Undefined function: %s"), name);
emsg_funcname(N_("E123: Undefined function: %s"), eap->arg);
}
goto ret_free;
}

View File

@ -746,6 +746,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
595,
/**/
594,
/**/

View File

@ -2434,8 +2434,10 @@ compile_call(char_u **arg, size_t varlen, cctx_T *cctx, int argcount_init)
}
// If the name is a variable, load it and use PCALL.
// Not for g:Func(), we don't know if it is a variable or not.
p = namebuf;
if (compile_load(&p, namebuf + varlen, cctx, FALSE) == OK)
if (STRNCMP(namebuf, "g:", 2) != 0
&& compile_load(&p, namebuf + varlen, cctx, FALSE) == OK)
{
res = generate_PCALL(cctx, argcount, FALSE);
goto theend;

View File

@ -488,6 +488,7 @@ call_def_function(
int idx;
int ret = FAIL;
int defcount = ufunc->uf_args.ga_len - argc;
int save_sc_version = current_sctx.sc_version;
// Get pointer to item in the stack.
#define STACK_TV(idx) (((typval_T *)ectx.ec_stack.ga_data) + idx)
@ -565,6 +566,9 @@ call_def_function(
ectx.ec_instr = dfunc->df_instr;
}
// Commands behave like vim9script.
current_sctx.sc_version = SCRIPT_VERSION_VIM9;
// Decide where to start execution, handles optional arguments.
init_instr_idx(ufunc, argc, &ectx);
@ -582,6 +586,16 @@ call_def_function(
did_throw = TRUE;
}
if (did_emsg && msg_list != NULL && *msg_list != NULL)
{
// Turn an error message into an exception.
did_emsg = FALSE;
if (throw_exception(*msg_list, ET_ERROR, NULL) == FAIL)
goto failed;
did_throw = TRUE;
*msg_list = NULL;
}
if (did_throw && !ectx.ec_in_catch)
{
garray_T *trystack = &ectx.ec_trystack;
@ -1774,6 +1788,7 @@ failed:
while (ectx.ec_frame != initial_frame_ptr)
func_return(&ectx);
failed_early:
current_sctx.sc_version = save_sc_version;
for (idx = 0; idx < ectx.ec_stack.ga_len; ++idx)
clear_tv(STACK_TV(idx));
vim_free(ectx.ec_stack.ga_data);
@ -1807,6 +1822,14 @@ ex_disassemble(exarg_T *eap)
}
ufunc = find_func(fname, NULL);
if (ufunc == NULL)
{
char_u *p = untrans_function_name(fname);
if (p != NULL)
// Try again without making it script-local.
ufunc = find_func(p, NULL);
}
vim_free(fname);
if (ufunc == NULL)
{