changeset 30705:12e6c7bae2a9 v9.0.0687

patch 9.0.0687: "export def" does not work in a nested block Commit: https://github.com/vim/vim/commit/5ab300195b0831cbdba3ce349416a0e6a218e4ef Author: Bram Moolenaar <Bram@vim.org> Date: Fri Oct 7 17:26:22 2022 +0100 patch 9.0.0687: "export def" does not work in a nested block 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)
author Bram Moolenaar <Bram@vim.org>
date Fri, 07 Oct 2022 18:30:06 +0200
parents 2721bdcfeadd
children ad50301e2d22
files src/ex_cmds.h src/ex_docmd.c src/testdir/test_vim9_import.vim src/version.c src/vim9script.c
diffstat 5 files changed, 61 insertions(+), 55 deletions(-) [+]
line wrap: on
line diff
--- a/src/ex_cmds.h
+++ b/src/ex_cmds.h
@@ -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_wrongmo
 	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
 	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,
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -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 (expand_filename(&ea, cmdlinep, &errormsg) == FAIL)
-	    goto doend;
-    }
+    if ((ea.argt & EX_XFILE)
+	    && expand_filename(&ea, cmdlinep, &errormsg) == FAIL)
+	goto doend;
+
+#ifdef FEAT_EVAL
+    if (is_export && (ea.argt & EX_EXPORT) == 0)
+    {
+	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);
--- a/src/testdir/test_vim9_import.vim
+++ b/src/testdir/test_vim9_import.vim
@@ -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()
--- a/src/version.c
+++ b/src/version.c
@@ -700,6 +700,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    687,
+/**/
     686,
 /**/
     685,
--- a/src/vim9script.c
+++ b/src/vim9script.c
@@ -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));
 }
 
 /*