summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2020-04-18 19:53:28 +0200
committerBram Moolenaar <Bram@vim.org>2020-04-18 19:53:28 +0200
commita26b9700d73ebccd6c5459d0d66032a4249f6b72 (patch)
tree2b7c7a0dfe64a8c707f36ce107dab9660adca200
parentb6fb0516ec862a18fdffe06c9400d507a7193835 (diff)
downloadvim-git-a26b9700d73ebccd6c5459d0d66032a4249f6b72.tar.gz
patch 8.2.0595: Vim9: not all commands using ends_excmd() testedv8.2.0595
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.
-rw-r--r--src/evalfunc.c11
-rw-r--r--src/ex_docmd.c9
-rw-r--r--src/proto/userfunc.pro1
-rw-r--r--src/testdir/test_vim9_disassemble.vim14
-rw-r--r--src/testdir/test_vim9_script.vim23
-rw-r--r--src/usercmd.c1
-rw-r--r--src/userfunc.c49
-rw-r--r--src/version.c2
-rw-r--r--src/vim9compile.c4
-rw-r--r--src/vim9execute.c23
10 files changed, 122 insertions, 15 deletions
diff --git a/src/evalfunc.c b/src/evalfunc.c
index 4b9b4ed5a..8cd137a4d 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -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))
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index 25040df22..5c18b0bcc 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -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');
diff --git a/src/proto/userfunc.pro b/src/proto/userfunc.pro
index 2ee3eef6a..19097fe2e 100644
--- a/src/proto/userfunc.pro
+++ b/src/proto/userfunc.pro
@@ -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);
diff --git a/src/testdir/test_vim9_disassemble.vim b/src/testdir/test_vim9_disassemble.vim
index f6de6858e..985c8ca4e 100644
--- a/src/testdir/test_vim9_disassemble.vim
+++ b/src/testdir/test_vim9_disassemble.vim
@@ -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].*' ..
diff --git a/src/testdir/test_vim9_script.vim b/src/testdir/test_vim9_script.vim
index 58363baca..1963c2e4c 100644
--- a/src/testdir/test_vim9_script.vim
+++ b/src/testdir/test_vim9_script.vim
@@ -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
diff --git a/src/usercmd.c b/src/usercmd.c
index e903e6b4c..fc14430b6 100644
--- a/src/usercmd.c
+++ b/src/usercmd.c
@@ -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);
diff --git a/src/userfunc.c b/src/userfunc.c
index d5a0a777a..44118b137 100644
--- a/src/userfunc.c
+++ b/src/userfunc.c
@@ -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;
@@ -2298,6 +2308,27 @@ theend:
}
/*
+ * 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"
*/
void
@@ -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;
}
diff --git a/src/version.c b/src/version.c
index 09dc67852..bd5bd0bfe 100644
--- a/src/version.c
+++ b/src/version.c
@@ -747,6 +747,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 595,
+/**/
594,
/**/
593,
diff --git a/src/vim9compile.c b/src/vim9compile.c
index e8e8598e6..64f7dd59b 100644
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -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;
diff --git a/src/vim9execute.c b/src/vim9execute.c
index cddb9d213..dbc5d22ba 100644
--- a/src/vim9execute.c
+++ b/src/vim9execute.c
@@ -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)
{