]> granicus.if.org Git - vim/commitdiff
patch 9.0.0687: "export def" does not work in a nested block v9.0.0687
authorBram Moolenaar <Bram@vim.org>
Fri, 7 Oct 2022 16:26:22 +0000 (17:26 +0100)
committerBram Moolenaar <Bram@vim.org>
Fri, 7 Oct 2022 16:26:22 +0000 (17:26 +0100)
Problem:    "export def" does not work in a nested block.
Solution:   Do not handle "export" with a separate function but in the same
            command stack. (closes #11304)

src/ex_cmds.h
src/ex_docmd.c
src/testdir/test_vim9_import.vim
src/version.c
src/vim9script.c

index ca7f292c9d6cf45fd171155a5a171f8143017480..ed954efc0dff73f8a16740c94e93a96df695bfb2 100644 (file)
@@ -59,6 +59,7 @@
 #define EX_KEEPSCRIPT  0x4000000  // keep sctx of where command was invoked
 #define EX_EXPR_ARG    0x8000000  // argument is an expression
 #define EX_WHOLE      0x10000000  // command name cannot be shortened in Vim9
+#define EX_EXPORT     0x20000000  // command can be used after :export
 
 #define EX_FILES (EX_XFILE | EX_EXTRA) // multiple extra files allowed
 #define EX_FILE1 (EX_FILES | EX_NOSPC) // 1 file, defaults to current file
@@ -354,7 +355,7 @@ EXCMD(CMD_clast,    "clast",        ex_cc,
        EX_RANGE|EX_COUNT|EX_TRLBAR|EX_BANG,
        ADDR_UNSIGNED),
 EXCMD(CMD_class,       "class",        ex_ni,
-       EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
+       EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK|EX_EXPORT,
        ADDR_NONE),
 EXCMD(CMD_close,       "close",        ex_close,
        EX_BANG|EX_RANGE|EX_COUNT|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
@@ -414,7 +415,7 @@ EXCMD(CMD_confirm,  "confirm",      ex_wrongmodifier,
        EX_NEEDARG|EX_EXTRA|EX_NOTRLCOM|EX_CMDWIN|EX_LOCK_OK,
        ADDR_NONE),
 EXCMD(CMD_const,       "const",        ex_let,
-       EX_EXTRA|EX_BANG|EX_NOTRLCOM|EX_EXPR_ARG|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK|EX_WHOLE,
+       EX_EXTRA|EX_BANG|EX_NOTRLCOM|EX_EXPR_ARG|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK|EX_WHOLE|EX_EXPORT,
        ADDR_NONE),
 EXCMD(CMD_copen,       "copen",        ex_copen,
        EX_RANGE|EX_COUNT|EX_TRLBAR,
@@ -462,7 +463,7 @@ EXCMD(CMD_debuggreedy,      "debuggreedy",  ex_debuggreedy,
        EX_RANGE|EX_ZEROR|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
        ADDR_OTHER),
 EXCMD(CMD_def,         "def",          ex_function,
-       EX_EXTRA|EX_BANG|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK,
+       EX_EXTRA|EX_BANG|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK|EX_EXPORT,
        ADDR_NONE),
 EXCMD(CMD_defcompile,  "defcompile",   ex_defcompile,
        EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK|EX_TRLBAR|EX_EXTRA,
@@ -594,7 +595,7 @@ EXCMD(CMD_enew,             "enew",         ex_edit,
        EX_BANG|EX_TRLBAR,
        ADDR_NONE),
 EXCMD(CMD_enum,                "enum",         ex_ni,
-       EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
+       EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK|EX_EXPORT,
        ADDR_NONE),
 EXCMD(CMD_eval,                "eval",         ex_eval,
        EX_EXTRA|EX_NOTRLCOM|EX_EXPR_ARG|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK,
@@ -630,7 +631,7 @@ EXCMD(CMD_find,             "find",         ex_find,
        EX_RANGE|EX_BANG|EX_FILE1|EX_CMDARG|EX_ARGOPT|EX_TRLBAR|EX_NEEDARG,
        ADDR_OTHER),
 EXCMD(CMD_final,       "final",        ex_let,
-       EX_EXTRA|EX_NOTRLCOM|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK|EX_WHOLE,
+       EX_EXTRA|EX_NOTRLCOM|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK|EX_WHOLE|EX_EXPORT,
        ADDR_NONE),
 EXCMD(CMD_finally,     "finally",      ex_finally,
        EX_TRLBAR|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK|EX_WHOLE,
@@ -663,7 +664,7 @@ EXCMD(CMD_for,              "for",          ex_while,
        EX_EXTRA|EX_NOTRLCOM|EX_EXPR_ARG|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK,
        ADDR_NONE),
 EXCMD(CMD_function,    "function",     ex_function,
-       EX_EXTRA|EX_BANG|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK,
+       EX_EXTRA|EX_BANG|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK|EX_EXPORT,
        ADDR_NONE),
 EXCMD(CMD_global,      "global",       ex_global,
        EX_RANGE|EX_WHOLEFOLD|EX_BANG|EX_EXTRA|EX_DFLALL|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK|EX_NONWHITE_OK,
@@ -1665,7 +1666,7 @@ EXCMD(CMD_tunmap, "tunmap",       ex_unmap,
        EX_EXTRA|EX_TRLBAR|EX_NOTRLCOM|EX_CTRLV|EX_CMDWIN|EX_LOCK_OK,
        ADDR_NONE),
 EXCMD(CMD_type,                "type",         ex_ni,
-       EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
+       EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK|EX_EXPORT,
        ADDR_NONE),
 EXCMD(CMD_undo,                "undo",         ex_undo,
        EX_RANGE|EX_COUNT|EX_ZEROR|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
@@ -1704,7 +1705,7 @@ EXCMD(CMD_vglobal,        "vglobal",      ex_global,
        EX_RANGE|EX_WHOLEFOLD|EX_EXTRA|EX_DFLALL|EX_CMDWIN|EX_LOCK_OK|EX_NONWHITE_OK,
        ADDR_LINES),
 EXCMD(CMD_var,         "var",          ex_var,
-       EX_EXTRA|EX_NOTRLCOM|EX_EXPR_ARG|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK|EX_WHOLE,
+       EX_EXTRA|EX_NOTRLCOM|EX_EXPR_ARG|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK|EX_WHOLE|EX_EXPORT,
        ADDR_NONE),
 EXCMD(CMD_version,     "version",      ex_version,
        EX_EXTRA|EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
index a7047d49ca5ac5fc637e8012662251931a49f0c6..3ffbf2b9064c203f16f4511a2585629ee7b154f1 100644 (file)
@@ -1820,6 +1820,15 @@ do_one_cmd(
     if (may_have_range)
        ea.cmd = skip_range(ea.cmd, TRUE, NULL);
 
+#ifdef FEAT_EVAL
+    // Handle ":export" - it functions almost like a command modifier.
+    // ":export var Name: type"
+    // ":export def Name(..."
+    // etc.
+    if (vim9script && checkforcmd_noparen(&ea.cmd, "export", 6))
+       is_export = TRUE;
+#endif
+
     if (vim9script && !may_have_range)
     {
        if (ea.cmd == cmd + 1 && *cmd == '$')
@@ -2496,11 +2505,17 @@ do_one_cmd(
     }
 #endif
 
-    if (ea.argt & EX_XFILE)
+    if ((ea.argt & EX_XFILE)
+           && expand_filename(&ea, cmdlinep, &errormsg) == FAIL)
+       goto doend;
+
+#ifdef FEAT_EVAL
+    if (is_export && (ea.argt & EX_EXPORT) == 0)
     {
-       if (expand_filename(&ea, cmdlinep, &errormsg) == FAIL)
-           goto doend;
+       emsg(_(e_invalid_command_after_export));
+       goto doend;
     }
+#endif
 
     /*
      * Accept buffer name.  Cannot be used at the same time with a buffer
@@ -2557,13 +2572,21 @@ do_one_cmd(
        /*
         * Call the function to execute the builtin command.
         */
-       ea.errmsg = NULL;
        (cmdnames[ea.cmdidx].cmd_func)(&ea);
        if (ea.errmsg != NULL)
            errormsg = ea.errmsg;
     }
 
 #ifdef FEAT_EVAL
+    // A command will reset "is_export" when exporting an item.  If it is still
+    // set something went wrong.
+    if (is_export)
+    {
+       if (errormsg == NULL)
+           errormsg = _(e_export_with_invalid_argument);
+       is_export = FALSE;
+    }
+
     // Set flag that any command was executed, used by ex_vim9script().
     // Not if this was a command that wasn't executed or :endif.
     if (sourcing_a_script(&ea)
@@ -2620,6 +2643,7 @@ doend:
 
     if (did_set_expr_line)
        set_expr_line(NULL, NULL);
+    is_export = FALSE;
 #endif
 
     undo_cmdmod(&cmdmod);
index e844d4a0827fb8807997bb5de615d0ba17f02ec4..d509007d5e851ec5b05119b46b5a86ae86828c4a 100644 (file)
@@ -452,6 +452,21 @@ def Test_import_funcref()
   delete('Xlib.vim')
 enddef
 
+def Test_export_closure()
+  # tests that the closure in block can be compiled, not the import part
+  var lines =<< trim END
+      vim9script
+      {
+        var foo = 42
+        export def Bar(): number
+          return foo
+        enddef
+      }
+      assert_equal(42, Bar())
+  END
+  v9.CheckScriptSuccess(lines)
+enddef
+
 def Test_import_duplicate_function()
   # Function Hover() exists in both scripts, partial should refer to the right
   # one.
@@ -1513,7 +1528,7 @@ def Test_export_fails()
   v9.CheckScriptFailure(['vim9script', 'export echo 134'], 'E1043:')
   v9.CheckScriptFailure(['vim9script', 'export function /a1b2c3'], 'E1044:')
 
-  assert_fails('export something', 'E1043:')
+  assert_fails('export echo 1', 'E1043:')
 enddef
 
 func Test_import_fails_without_script()
index c6c01976c77f6fd921fed4c326f45c7712dd0f58..7330eebcfc94a69682ae6dca0266ca8509ceef31 100644 (file)
@@ -699,6 +699,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    687,
 /**/
     686,
 /**/
index f6c8c49a2891a21af991a42e1ebb00b623e49860..557892cf8cb3cdc47887c24d279e3ad2d958bd65 100644 (file)
@@ -246,49 +246,13 @@ ex_incdec(exarg_T *eap)
 }
 
 /*
- * ":export let Name: type"
- * ":export const Name: type"
- * ":export def Name(..."
- * ":export class Name ..."
+ * ":export cmd"
  */
     void
-ex_export(exarg_T *eap)
+ex_export(exarg_T *eap UNUSED)
 {
-    int            prev_did_emsg = did_emsg;
-
-    if (!in_vim9script())
-    {
-       emsg(_(e_export_can_only_be_used_in_vim9script));
-       return;
-    }
-
-    eap->cmd = eap->arg;
-    (void)find_ex_command(eap, NULL, lookup_scriptitem, NULL);
-    switch (eap->cmdidx)
-    {
-       case CMD_var:
-       case CMD_final:
-       case CMD_const:
-       case CMD_def:
-       case CMD_function:
-       // case CMD_class:
-           is_export = TRUE;
-           do_cmdline(eap->cmd, eap->getline, eap->cookie,
-                                               DOCMD_VERBOSE + DOCMD_NOWAIT);
-
-           // The command will reset "is_export" when exporting an item.
-           if (is_export)
-           {
-               if (did_emsg == prev_did_emsg)
-                   emsg(_(e_export_with_invalid_argument));
-               is_export = FALSE;
-           }
-           break;
-       default:
-           if (did_emsg == prev_did_emsg)
-               emsg(_(e_invalid_command_after_export));
-           break;
-    }
+    // can only get here when "export" wasn't caught in do_cmdline()
+    emsg(_(e_export_can_only_be_used_in_vim9script));
 }
 
 /*