changeset 20079:336483164ca6 v8.2.0595

patch 8.2.0595: Vim9: not all commands using ends_excmd() tested Commit: https://github.com/vim/vim/commit/a26b9700d73ebccd6c5459d0d66032a4249f6b72 Author: Bram Moolenaar <Bram@vim.org> Date: Sat Apr 18 19:53:28 2020 +0200 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.
author Bram Moolenaar <Bram@vim.org>
date Sat, 18 Apr 2020 20:00:04 +0200
parents 61222b5d173d
children bcec8cadb7f7
files src/evalfunc.c src/ex_docmd.c src/proto/userfunc.pro src/testdir/test_vim9_disassemble.vim src/testdir/test_vim9_script.vim src/usercmd.c src/userfunc.c src/version.c src/vim9compile.c src/vim9execute.c
diffstat 10 files changed, 122 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -2706,6 +2706,17 @@ common_function(typval_T *argvars, typva
 	     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))
--- 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, ch
     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');
--- a/src/proto/userfunc.pro
+++ b/src/proto/userfunc.pro
@@ -20,6 +20,7 @@ int call_callback(callback_T *callback, 
 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);
--- 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].*' ..
--- 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
--- 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);
--- a/src/userfunc.c
+++ b/src/userfunc.c
@@ -730,7 +730,8 @@ find_func_even_dead(char_u *name, cctx_T
 	}
     }
 
-    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;
     }
--- 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,
--- a/src/vim9compile.c
+++ b/src/vim9compile.c
@@ -2434,8 +2434,10 @@ compile_call(char_u **arg, size_t varlen
     }
 
     // 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;
--- 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)
     {