From 5ab300195b0831cbdba3ce349416a0e6a218e4ef Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Fri, 7 Oct 2022 17:26:22 +0100 Subject: 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) --- src/ex_cmds.h | 17 ++++++++-------- src/ex_docmd.c | 32 +++++++++++++++++++++++++---- src/testdir/test_vim9_import.vim | 17 +++++++++++++++- src/version.c | 2 ++ src/vim9script.c | 44 ++++------------------------------------ 5 files changed, 59 insertions(+), 53 deletions(-) diff --git a/src/ex_cmds.h b/src/ex_cmds.h index ca7f292c9..ed954efc0 100644 --- 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_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, diff --git a/src/ex_docmd.c b/src/ex_docmd.c index a7047d49c..3ffbf2b90 100644 --- 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 ((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); diff --git a/src/testdir/test_vim9_import.vim b/src/testdir/test_vim9_import.vim index e844d4a08..d509007d5 100644 --- 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() diff --git a/src/version.c b/src/version.c index c6c01976c..7330eebcf 100644 --- a/src/version.c +++ b/src/version.c @@ -699,6 +699,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 687, /**/ 686, /**/ diff --git a/src/vim9script.c b/src/vim9script.c index f6c8c49a2..557892cf8 100644 --- 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)); } /* -- cgit v1.2.1