]> granicus.if.org Git - vim/commitdiff
patch 8.2.0595: Vim9: not all commands using ends_excmd() tested v8.2.0595
authorBram Moolenaar <Bram@vim.org>
Sat, 18 Apr 2020 17:53:28 +0000 (19:53 +0200)
committerBram Moolenaar <Bram@vim.org>
Sat, 18 Apr 2020 17:53:28 +0000 (19:53 +0200)
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.

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

index 4b9b4ed5ae9e2db27407d67335375e09cdbc4bd8..8cd137a4dd6b9f5901c8e09a6821e66ef954ca3c 100644 (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))
index 25040df22ddcd3db9240cb1c5b9c99232e75107a..5c18b0bccc812a8ee1450f9ca609e52c819b98d0 100644 (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');
index 2ee3eef6ae8ab0f0cfcf2486debbe67ce9acdc75..19097fe2ecfacbd9109be065bd9f4934936bc3c1 100644 (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);
index f6de6858e1b68a2f073593f08bf433194b66717a..985c8ca4ebe02b5f6de37c84169e179ec08195eb 100644 (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].*' ..
index 58363baca005485be846ed34255a6604d31424af..1963c2e4cf609d13a70b34a3e4b6a61377b143be 100644 (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
index e903e6b4c3132fd033cad4549e945b31dfe088eb..fc14430b64ca00d8b1a74c8d42b96a5d4ec9277f 100644 (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);
index d5a0a777a36a39bba88a5cfcc8a281b883832944..44118b1375d1d5876c3c95d33273cd7ce25b1581 100644 (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;
     }
index 09dc67852151a0171141c07d8469f163440ce3c7..bd5bd0bfebe1621e97b8cf367aeea9cdd75c261e 100644 (file)
@@ -746,6 +746,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    595,
 /**/
     594,
 /**/
index e8e8598e6cbd0944aeff50aef0952dc6492df0f4..64f7dd59b1ddc0eb7d18bf05977b390ae5960169 100644 (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;
index cddb9d2137f9af66f6cbef7fda9e260831de8f7f..dbc5d22bae4bfb91e9e6f03367fe076aa8ea9381 100644 (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)
     {