]> granicus.if.org Git - vim/commitdiff
patch 8.2.2033: Vim9: :def without argument gives compilation error v8.2.2033
authorBram Moolenaar <Bram@vim.org>
Sun, 22 Nov 2020 17:15:44 +0000 (18:15 +0100)
committerBram Moolenaar <Bram@vim.org>
Sun, 22 Nov 2020 17:15:44 +0000 (18:15 +0100)
Problem:    Vim9: :def without argument gives compilation error.
Solution:   Add the DEF instruction. (closes #7344)

src/ex_docmd.c
src/proto/userfunc.pro
src/testdir/test_vim9_disassemble.vim
src/testdir/test_vim9_func.vim
src/userfunc.c
src/version.c
src/vim9.h
src/vim9compile.c
src/vim9execute.c

index 2c35c8ef21944439cc010d44873e03b6352a0bd7..44e113d53b79aab250e405a10591cf007973afd8 100644 (file)
@@ -274,7 +274,6 @@ static void ex_tag_cmd(exarg_T *eap, char_u *name);
 # define ex_continue           ex_ni
 # define ex_debug              ex_ni
 # define ex_debuggreedy                ex_ni
-# define ex_def                        ex_ni
 # define ex_defcompile         ex_ni
 # define ex_delfunction                ex_ni
 # define ex_disassemble                ex_ni
index 7ee36dbc1856bb7a9741d10bd74ceebd0691aee6..0029dab0d9b232aede60bbce3c03cbd48516e6cd 100644 (file)
@@ -33,6 +33,7 @@ int call_func(char_u *funcname, int len, typval_T *rettv, int argcount_in, typva
 char_u *printable_func_name(ufunc_T *fp);
 char_u *trans_function_name(char_u **pp, int *is_global, int skip, int flags, funcdict_T *fdp, partial_T **partial);
 char_u *untrans_function_name(char_u *name);
+void list_functions(regmatch_T *regmatch);
 ufunc_T *define_function(exarg_T *eap, char_u *name_arg);
 void ex_function(exarg_T *eap);
 void ex_defcompile(exarg_T *eap);
index 06fb77b0b5128435ec44131ad634984dc8b991d2..12a3c8269159c13cebb3d7d01476132c75eaf6cd 100644 (file)
@@ -905,6 +905,29 @@ def Test_nested_func()
         instr)
 enddef
 
+def NestedDefList()
+  def
+  def Info
+  def /Info
+  def /Info/
+enddef
+
+def Test_nested_def_list()
+   var instr = execute('disassemble NestedDefList')
+   assert_match('NestedDefList\_s*' ..
+        'def\_s*' ..
+        '\d DEF \_s*' ..
+        'def Info\_s*' ..
+        '\d DEF Info\_s*' ..
+        'def /Info\_s*' ..
+        '\d DEF /Info\_s*' ..
+        'def /Info/\_s*' ..
+        '\d DEF /Info/\_s*' ..
+        '\d PUSHNR 0\_s*' ..
+        '\d RETURN',
+        instr)
+enddef
+
 def AndOr(arg: any): string
   if arg == 1 && arg != 2 || arg == 4
     return 'yes'
index dd2f576ddced684d57d711e7b02d149f1812faba..80d564e3e247429fbc34ccce3519a0e6ae3725bc 100644 (file)
@@ -288,6 +288,33 @@ def Test_nested_global_function()
   CheckScriptFailure(lines, "E1073:")
 enddef
 
+def DefListAll()
+  def
+enddef
+
+def DefListOne()
+  def DefListOne
+enddef
+
+def DefListMatches()
+  def /DefList
+enddef
+
+def Test_nested_def_list()
+  var funcs = split(execute('call DefListAll()'), "\n")
+  assert_true(len(funcs) > 10)
+  assert_true(funcs->index('def DefListAll()') >= 0)
+
+  funcs = split(execute('call DefListOne()'), "\n")
+  assert_equal(['   def DefListOne()', '1    def DefListOne', '   enddef'], funcs)
+
+  funcs = split(execute('call DefListMatches()'), "\n")
+  assert_true(len(funcs) >= 3)
+  assert_true(funcs->index('def DefListAll()') >= 0)
+  assert_true(funcs->index('def DefListOne()') >= 0)
+  assert_true(funcs->index('def DefListMatches()') >= 0)
+enddef
+
 def Test_global_local_function()
   var lines =<< trim END
       vim9script
index 7a306b1b7f5a3e766be1c8ab62be337c5f73b9fd..70bbf33e13af3b897886758818a678ab6610074b 100644 (file)
@@ -2748,7 +2748,7 @@ untrans_function_name(char_u *name)
  * List functions.  When "regmatch" is NULL all of then.
  * Otherwise functions matching "regmatch".
  */
-    static void
+    void
 list_functions(regmatch_T *regmatch)
 {
     int                changed = func_hashtab.ht_changed;
index 97c1e11cecc1810a44ec1d398fe75d98d751c01c..380710166dff5efcc7f8c16817fa9dcc8b6170a0 100644 (file)
@@ -750,6 +750,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2033,
 /**/
     2032,
 /**/
index 60699f994ab38c73311a235dbbd91a88fd8bfe21..9685b9d571d4baae0fc0bb0845aa17051718df2d 100644 (file)
@@ -82,6 +82,7 @@ typedef enum {
     ISN_RETURN,            // return, result is on top of stack
     ISN_FUNCREF,    // push a function ref to dfunc isn_arg.funcref
     ISN_NEWFUNC,    // create a global function from a lambda function
+    ISN_DEF,       // list functions
 
     // expression operations
     ISN_JUMP,      // jump if condition is matched isn_arg.jump
index 7102d488f040bfdbf306bccdce080d9661e11b1b..b870023ea52a0c436717edb3aafc14681eae8757 100644 (file)
@@ -1432,6 +1432,26 @@ generate_NEWFUNC(cctx_T *cctx, char_u *lambda_name, char_u *func_name)
     return OK;
 }
 
+/*
+ * Generate an ISN_DEF instruction: list functions
+ */
+    static int
+generate_DEF(cctx_T *cctx, char_u *name, size_t len)
+{
+    isn_T      *isn;
+
+    RETURN_OK_IF_SKIP(cctx);
+    if ((isn = generate_instr(cctx, ISN_DEF)) == NULL)
+       return FAIL;
+    if (len > 0)
+    {
+       isn->isn_arg.string = vim_strnsave(name, len);
+       if (isn->isn_arg.string == NULL)
+           return FAIL;
+    }
+    return OK;
+}
+
 /*
  * Generate an ISN_JUMP instruction.
  */
@@ -4801,6 +4821,27 @@ compile_nested_function(exarg_T *eap, cctx_T *cctx)
        return NULL;
     }
 
+    if (*name_start == '/')
+    {
+       name_end = skip_regexp(name_start + 1, '/', TRUE);
+       if (*name_end == '/')
+           ++name_end;
+       eap->nextcmd = check_nextcmd(name_end);
+    }
+    if (name_end == name_start || *skipwhite(name_end) != '(')
+    {
+       if (!ends_excmd2(name_start, name_end))
+       {
+           semsg(_(e_invalid_command_str), eap->cmd);
+           return NULL;
+       }
+
+       // "def" or "def Name": list functions
+       if (generate_DEF(cctx, name_start, name_end - name_start) == FAIL)
+           return NULL;
+       return eap->nextcmd == NULL ? (char_u *)"" : eap->nextcmd;
+    }
+
     // Only g:Func() can use a namespace.
     if (name_start[1] == ':' && !is_global)
     {
@@ -7736,22 +7777,23 @@ delete_instr(isn_T *isn)
 {
     switch (isn->isn_type)
     {
+       case ISN_DEF:
        case ISN_EXEC:
+       case ISN_LOADB:
        case ISN_LOADENV:
        case ISN_LOADG:
-       case ISN_LOADB:
-       case ISN_LOADW:
-       case ISN_LOADT:
        case ISN_LOADOPT:
-       case ISN_STRINGMEMBER:
+       case ISN_LOADT:
+       case ISN_LOADW:
        case ISN_PUSHEXC:
+       case ISN_PUSHFUNC:
        case ISN_PUSHS:
+       case ISN_STOREB:
        case ISN_STOREENV:
        case ISN_STOREG:
-       case ISN_STOREB:
-       case ISN_STOREW:
        case ISN_STORET:
-       case ISN_PUSHFUNC:
+       case ISN_STOREW:
+       case ISN_STRINGMEMBER:
            vim_free(isn->isn_arg.string);
            break;
 
index f154249073a2257cf9c907d38773ea8816df3404..8b614bfdc8c0810f9a0d8384e8f40c571565247c 100644 (file)
@@ -1970,6 +1970,20 @@ call_def_function(
                }
                break;
 
+           // List functions
+           case ISN_DEF:
+               if (iptr->isn_arg.string == NULL)
+                   list_functions(NULL);
+               else
+               {
+                   exarg_T ea;
+
+                   CLEAR_FIELD(ea);
+                   ea.cmd = ea.arg = iptr->isn_arg.string;
+                   define_function(&ea, NULL);
+               }
+               break;
+
            // jump if a condition is met
            case ISN_JUMP:
                {
@@ -3371,6 +3385,15 @@ ex_disassemble(exarg_T *eap)
                }
                break;
 
+           case ISN_DEF:
+               {
+                   char_u *name = iptr->isn_arg.string;
+
+                   smsg("%4d DEF %s", current,
+                                          name == NULL ? (char_u *)"" : name);
+               }
+               break;
+
            case ISN_JUMP:
                {
                    char *when = "?";