To: vim_dev@googlegroups.com Subject: Patch 8.2.0595 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.0595 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. Files: src/ex_docmd.c, src/vim9compile.c, src/vim9execute.c, src/usercmd.c, src/evalfunc.c, src/userfunc.c, src/proto/userfunc.pro, src/testdir/test_vim9_script.vim, src/testdir/test_vim9_disassemble.vim *** ../vim-8.2.0594/src/ex_docmd.c 2020-04-18 17:45:34.702165051 +0200 --- src/ex_docmd.c 2020-04-18 18:25:46.854499776 +0200 *************** *** 1836,1842 **** */ if (*ea.cmd == NUL || *ea.cmd == '"' #ifdef FEAT_EVAL ! || (*ea.cmd == '#' && !starts_with_colon && in_vim9script()) #endif || (ea.nextcmd = check_nextcmd(ea.cmd)) != NULL) { --- 1836,1843 ---- */ if (*ea.cmd == NUL || *ea.cmd == '"' #ifdef FEAT_EVAL ! || (*ea.cmd == '#' && ea.cmd[1] != '{' ! && !starts_with_colon && in_vim9script()) #endif || (ea.nextcmd = check_nextcmd(ea.cmd)) != NULL) { *************** *** 4436,4441 **** --- 4437,4446 ---- || 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,4796 **** int c = *cmd; #ifdef FEAT_EVAL ! if (c == '#' && (cmd == cmd_start || VIM_ISWHITE(cmd[-1]))) return in_vim9script(); #endif return (c == NUL || c == '|' || c == '"' || c == '\n'); --- 4795,4801 ---- int c = *cmd; #ifdef FEAT_EVAL ! if (c == '#' && cmd[1] != '{' && (cmd == cmd_start || VIM_ISWHITE(cmd[-1]))) return in_vim9script(); #endif return (c == NUL || c == '|' || c == '"' || c == '\n'); *** ../vim-8.2.0594/src/vim9compile.c 2020-04-16 22:10:42.656733692 +0200 --- src/vim9compile.c 2020-04-18 17:08:18.107125630 +0200 *************** *** 2434,2441 **** } // If the name is a variable, load it and use PCALL. p = namebuf; ! if (compile_load(&p, namebuf + varlen, cctx, FALSE) == OK) { res = generate_PCALL(cctx, argcount, FALSE); goto theend; --- 2434,2443 ---- } // 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 (STRNCMP(namebuf, "g:", 2) != 0 ! && compile_load(&p, namebuf + varlen, cctx, FALSE) == OK) { res = generate_PCALL(cctx, argcount, FALSE); goto theend; *** ../vim-8.2.0594/src/vim9execute.c 2020-04-12 23:09:20.789245505 +0200 --- src/vim9execute.c 2020-04-18 19:49:36.788105227 +0200 *************** *** 488,493 **** --- 488,494 ---- 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,570 **** --- 566,574 ---- 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,587 **** --- 586,601 ---- 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,1779 **** --- 1788,1794 ---- 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,1812 **** --- 1822,1835 ---- } 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) { *** ../vim-8.2.0594/src/usercmd.c 2020-04-13 21:16:18.039292270 +0200 --- src/usercmd.c 2020-04-18 16:52:26.374111296 +0200 *************** *** 1663,1668 **** --- 1663,1669 ---- #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); *** ../vim-8.2.0594/src/evalfunc.c 2020-04-12 19:37:13.510297280 +0200 --- src/evalfunc.c 2020-04-18 18:47:01.087249505 +0200 *************** *** 2706,2711 **** --- 2706,2722 ---- 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)) *** ../vim-8.2.0594/src/userfunc.c 2020-04-14 20:15:45.288566185 +0200 --- src/userfunc.c 2020-04-18 19:52:50.431952039 +0200 *************** *** 730,736 **** } } ! hi = hash_find(&func_hashtab, name); if (!HASHITEM_EMPTY(hi)) return HI2UF(hi); --- 730,737 ---- } } ! hi = hash_find(&func_hashtab, ! STRNCMP(name, "g:", 2) == 0 ? name + 2 : name); if (!HASHITEM_EMPTY(hi)) return HI2UF(hi); *************** *** 1651,1657 **** /* * Return TRUE if "name" looks like a builtin function name: starts with a ! * lower case letter and doesn't contain AUTOLOAD_CHAR. * "len" is the length of "name", or -1 for NUL terminated. */ int --- 1652,1658 ---- /* * Return TRUE if "name" looks like a builtin function name: starts with a ! * lower case letter and doesn't contain AUTOLOAD_CHAR or ':'. * "len" is the length of "name", or -1 for NUL terminated. */ int *************** *** 1659,1665 **** { char_u *p; ! if (!ASCII_ISLOWER(name[0])) return FALSE; p = vim_strchr(name, AUTOLOAD_CHAR); return p == NULL || (len > 0 && p > name + len); --- 1660,1666 ---- { char_u *p; ! if (!ASCII_ISLOWER(name[0]) || name[1] == ':') return FALSE; p = vim_strchr(name, AUTOLOAD_CHAR); return p == NULL || (len > 0 && p > name + len); *************** *** 1894,1899 **** --- 1895,1909 ---- // 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; *************** *** 2298,2303 **** --- 2308,2334 ---- } /* + * 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" */ void *************** *** 2467,2472 **** --- 2498,2513 ---- 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,2500 **** } } else ! emsg_funcname(N_("E123: Undefined function: %s"), name); } goto ret_free; } --- 2535,2541 ---- } } else ! emsg_funcname(N_("E123: Undefined function: %s"), eap->arg); } goto ret_free; } *** ../vim-8.2.0594/src/proto/userfunc.pro 2020-04-12 21:52:56.875998374 +0200 --- src/proto/userfunc.pro 2020-04-18 19:37:47.565103410 +0200 *************** *** 20,25 **** --- 20,26 ---- 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); *** ../vim-8.2.0594/src/testdir/test_vim9_script.vim 2020-04-16 22:54:28.723107683 +0200 --- src/testdir/test_vim9_script.vim 2020-04-18 19:46:28.312098513 +0200 *************** *** 587,593 **** CheckScriptFailure(['vim9script', 'export echo 134'], 'E1043:') assert_fails('vim9script', 'E1038') ! assert_fails('export something', 'E1042') enddef def Test_vim9script_reload() --- 587,593 ---- CheckScriptFailure(['vim9script', 'export echo 134'], 'E1043:') assert_fails('vim9script', 'E1038') ! assert_fails('export something', 'E1043') enddef def Test_vim9script_reload() *************** *** 1098,1103 **** --- 1098,1124 ---- ], '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 *** ../vim-8.2.0594/src/testdir/test_vim9_disassemble.vim 2020-04-13 17:20:56.174130307 +0200 --- src/testdir/test_vim9_disassemble.vim 2020-04-18 19:45:34.364059270 +0200 *************** *** 251,258 **** enddef ! def FuncWithForwardCall(): string ! return DefinedLater("yes") enddef def DefinedLater(arg: string): string --- 251,258 ---- enddef ! def s:FuncWithForwardCall(): string ! return g:DefinedLater("yes") enddef def DefinedLater(arg: string): string *************** *** 260,270 **** enddef def Test_disassemble_update_instr() ! let res = execute('disass FuncWithForwardCall') assert_match('FuncWithForwardCall.*' .. ! 'return DefinedLater("yes").*' .. '\d PUSHS "yes".*' .. ! '\d UCALL DefinedLater(argc 1).*' .. '\d CHECKTYPE string stack\[-1].*' .. '\d RETURN.*', res) --- 260,270 ---- enddef def Test_disassemble_update_instr() ! let res = execute('disass s:FuncWithForwardCall') assert_match('FuncWithForwardCall.*' .. ! 'return g:DefinedLater("yes").*' .. '\d PUSHS "yes".*' .. ! '\d UCALL g:DefinedLater(argc 1).*' .. '\d CHECKTYPE string stack\[-1].*' .. '\d RETURN.*', res) *************** *** 272,280 **** " Calling the function will change UCALL into the faster DCALL assert_equal('yes', FuncWithForwardCall()) ! res = execute('disass FuncWithForwardCall') assert_match('FuncWithForwardCall.*' .. ! 'return DefinedLater("yes").*' .. '\d PUSHS "yes".*' .. '\d DCALL DefinedLater(argc 1).*' .. '\d CHECKTYPE string stack\[-1].*' .. --- 272,280 ---- " Calling the function will change UCALL into the faster DCALL assert_equal('yes', FuncWithForwardCall()) ! res = execute('disass s:FuncWithForwardCall') assert_match('FuncWithForwardCall.*' .. ! 'return g:DefinedLater("yes").*' .. '\d PUSHS "yes".*' .. '\d DCALL DefinedLater(argc 1).*' .. '\d CHECKTYPE string stack\[-1].*' .. *** ../vim-8.2.0594/src/version.c 2020-04-18 18:24:13.110776118 +0200 --- src/version.c 2020-04-18 19:48:17.460124539 +0200 *************** *** 748,749 **** --- 748,751 ---- { /* Add new patch number below this line */ + /**/ + 595, /**/ -- Your company is doomed if your primary product is overhead transparencies. (Scott Adams - The Dilbert principle) /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///