To: vim_dev@googlegroups.com Subject: Patch 8.2.0626 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.0626 Problem: Vim9: wrong syntax of function in Vim9 script. Solution: Give error for missing space. Implement :echomsg and :echoerr. (closes #5670) Files: src/vim9compile.c, src/vim9execute.c, src/vim9.h, src/userfunc.c, src/eval.c, src/globals.h, src/testdir/test_vim9_func.vim, src/testdir/test_vim9_disassemble.vim src/testdir/test_vim9_script.vim *** ../vim-8.2.0625/src/vim9compile.c 2020-04-23 18:13:18.035179330 +0200 --- src/vim9compile.c 2020-04-23 22:10:43.744079897 +0200 *************** *** 1401,1414 **** } /* ! * Generate an ISN_EXECUTE instruction. */ static int ! generate_EXECUTE(cctx_T *cctx, int count) { isn_T *isn; ! if ((isn = generate_instr_drop(cctx, ISN_EXECUTE, count)) == NULL) return FAIL; isn->isn_arg.number = count; --- 1401,1414 ---- } /* ! * Generate an ISN_EXECUTE/ISN_ECHOMSG/ISN_ECHOERR instruction. */ static int ! generate_MULT_EXPR(cctx_T *cctx, isntype_T isn_type, int count) { isn_T *isn; ! if ((isn = generate_instr_drop(cctx, isn_type, count)) == NULL) return FAIL; isn->isn_arg.number = count; *************** *** 1427,1437 **** return OK; } - static char e_white_both[] = - N_("E1004: white space required before and after '%s'"); - static char e_white_after[] = N_("E1069: white space required after '%s'"); - static char e_no_white_before[] = N_("E1068: No white space allowed before '%s'"); - /* * Reserve space for a local variable. * Return the index or -1 if it failed. --- 1427,1432 ---- *************** *** 4203,4208 **** --- 4198,4208 ---- goto theend; } } + else if (name[1] == ':' && name[2] != NUL) + { + semsg(_("E1082: Cannot use a namespaced variable: %s"), name); + goto theend; + } } } *************** *** 4211,4216 **** --- 4211,4221 ---- if (is_decl && *p == ':') { // parse optional type: "let var: type = expr" + if (!VIM_ISWHITE(p[1])) + { + semsg(_(e_white_after), ":"); + goto theend; + } p = skipwhite(p + 1); type = parse_type(&p, cctx->ctx_type_list); has_type = TRUE; *************** *** 5768,5799 **** /* * compile "echo expr" ! */ ! static char_u * ! compile_echo(char_u *arg, int with_white, cctx_T *cctx) ! { ! char_u *p = arg; ! int count = 0; ! ! for (;;) ! { ! if (compile_expr1(&p, cctx) == FAIL) ! return NULL; ! ++count; ! p = skipwhite(p); ! if (ends_excmd(*p)) ! break; ! } ! ! generate_ECHO(cctx, with_white, count); ! return p; ! } ! ! /* * compile "execute expr" */ static char_u * ! compile_execute(char_u *arg, cctx_T *cctx) { char_u *p = arg; int count = 0; --- 5773,5784 ---- /* * compile "echo expr" ! * compile "echomsg expr" ! * compile "echoerr expr" * compile "execute expr" */ static char_u * ! compile_mult_expr(char_u *arg, int cmdidx, cctx_T *cctx) { char_u *p = arg; int count = 0; *************** *** 5808,5815 **** break; } ! generate_EXECUTE(cctx, count); ! return p; } --- 5793,5806 ---- break; } ! if (cmdidx == CMD_echo || cmdidx == CMD_echon) ! generate_ECHO(cctx, cmdidx == CMD_echo, count); ! else if (cmdidx == CMD_execute) ! generate_MULT_EXPR(cctx, ISN_EXECUTE, count); ! else if (cmdidx == CMD_echomsg) ! generate_MULT_EXPR(cctx, ISN_ECHOMSG, count); ! else ! generate_MULT_EXPR(cctx, ISN_ECHOERR, count); return p; } *************** *** 6184,6203 **** break; case CMD_echo: - line = compile_echo(p, TRUE, &cctx); - break; case CMD_echon: - line = compile_echo(p, FALSE, &cctx); - break; case CMD_execute: ! line = compile_execute(p, &cctx); break; default: // Not recognized, execute with do_cmdline_cmd(). ! // TODO: ! // CMD_echomsg ! // etc. generate_EXEC(&cctx, line); line = (char_u *)""; break; --- 6175,6190 ---- break; case CMD_echo: case CMD_echon: case CMD_execute: ! case CMD_echomsg: ! case CMD_echoerr: ! line = compile_mult_expr(p, ea.cmdidx, &cctx); break; default: // Not recognized, execute with do_cmdline_cmd(). ! // TODO: other commands with an expression argument generate_EXEC(&cctx, line); line = (char_u *)""; break; *************** *** 6415,6420 **** --- 6402,6409 ---- case ISN_DROP: case ISN_ECHO: case ISN_EXECUTE: + case ISN_ECHOMSG: + case ISN_ECHOERR: case ISN_ENDTRY: case ISN_FOR: case ISN_FUNCREF: *** ../vim-8.2.0625/src/vim9execute.c 2020-04-23 18:13:18.035179330 +0200 --- src/vim9execute.c 2020-04-23 20:07:30.202219955 +0200 *************** *** 668,675 **** } break; ! // execute :execute {string} ... case ISN_EXECUTE: { int count = iptr->isn_arg.number; garray_T ga; --- 668,679 ---- } break; ! // :execute {string} ... ! // :echomsg {string} ... ! // :echoerr {string} ... case ISN_EXECUTE: + case ISN_ECHOMSG: + case ISN_ECHOERR: { int count = iptr->isn_arg.number; garray_T ga; *************** *** 705,711 **** ectx.ec_stack.ga_len -= count; if (!failed && ga.ga_data != NULL) ! do_cmdline_cmd((char_u *)ga.ga_data); ga_clear(&ga); } break; --- 709,738 ---- ectx.ec_stack.ga_len -= count; if (!failed && ga.ga_data != NULL) ! { ! if (iptr->isn_type == ISN_EXECUTE) ! do_cmdline_cmd((char_u *)ga.ga_data); ! else ! { ! msg_sb_eol(); ! if (iptr->isn_type == ISN_ECHOMSG) ! { ! msg_attr(ga.ga_data, echo_attr); ! out_flush(); ! } ! else ! { ! int save_did_emsg = did_emsg; ! ! SOURCING_LNUM = iptr->isn_lnum; ! emsg(ga.ga_data); ! if (!force_abort) ! // We don't want to abort following ! // commands, restore did_emsg. ! did_emsg = save_did_emsg; ! } ! } ! } ga_clear(&ga); } break; *************** *** 1947,1952 **** --- 1974,1987 ---- smsg("%4d EXECUTE %lld", current, (long long)(iptr->isn_arg.number)); break; + case ISN_ECHOMSG: + smsg("%4d ECHOMSG %lld", current, + (long long)(iptr->isn_arg.number)); + break; + case ISN_ECHOERR: + smsg("%4d ECHOERR %lld", current, + (long long)(iptr->isn_arg.number)); + break; case ISN_LOAD: if (iptr->isn_arg.number < 0) smsg("%4d LOAD arg[%lld]", current, *** ../vim-8.2.0625/src/vim9.h 2020-04-19 18:27:20.791953204 +0200 --- src/vim9.h 2020-04-23 19:58:50.011283264 +0200 *************** *** 15,20 **** --- 15,22 ---- ISN_EXEC, // execute Ex command line isn_arg.string ISN_ECHO, // echo isn_arg.echo.echo_count items on top of stack ISN_EXECUTE, // execute Ex commands isn_arg.number items on top of stack + ISN_ECHOMSG, // echo Ex commands isn_arg.number items on top of stack + ISN_ECHOERR, // echo Ex commands isn_arg.number items on top of stack // get and set variables ISN_LOAD, // push local variable isn_arg.number *** ../vim-8.2.0625/src/userfunc.c 2020-04-23 17:07:26.972434270 +0200 --- src/userfunc.c 2020-04-23 19:13:18.049810945 +0200 *************** *** 128,134 **** } if (*p == ':') { ! type = skipwhite(p + 1); p = skip_type(type); type = vim_strnsave(type, p - type); } --- 128,140 ---- } if (*p == ':') { ! ++p; ! if (!VIM_ISWHITE(*p)) ! { ! semsg(_(e_white_after), ":"); ! return arg; ! } ! type = skipwhite(p); p = skip_type(type); type = vim_strnsave(type, p - type); } *** ../vim-8.2.0625/src/eval.c 2020-04-23 13:37:59.494978699 +0200 --- src/eval.c 2020-04-23 20:00:50.815050222 +0200 *************** *** 34,41 **** */ static int current_copyID = 0; - static int echo_attr = 0; // attributes used for ":echo" - /* * Info used by a ":for" loop. */ --- 34,39 ---- *************** *** 6145,6151 **** char_u *p; garray_T ga; int len; - int save_did_emsg; ga_init2(&ga, 1, 80); --- 6143,6148 ---- *************** *** 6213,6220 **** } else if (eap->cmdidx == CMD_echoerr) { // We don't want to abort following commands, restore did_emsg. - save_did_emsg = did_emsg; emsg(ga.ga_data); if (!force_abort) did_emsg = save_did_emsg; --- 6210,6218 ---- } else if (eap->cmdidx == CMD_echoerr) { + int save_did_emsg = did_emsg; + // We don't want to abort following commands, restore did_emsg. emsg(ga.ga_data); if (!force_abort) did_emsg = save_did_emsg; *** ../vim-8.2.0625/src/globals.h 2020-04-21 22:01:11.089499502 +0200 --- src/globals.h 2020-04-23 20:01:32.770966838 +0200 *************** *** 1750,1755 **** --- 1750,1759 ---- EXTERN char e_continue[] INIT(= N_("E586: :continue without :while or :for")); EXTERN char e_break[] INIT(= N_("E587: :break without :while or :for")); EXTERN char e_nowhitespace[] INIT(= N_("E274: No white space allowed before parenthesis")); + EXTERN char e_white_both[] INIT(= N_("E1004: white space required before and after '%s'")); + EXTERN char e_white_after[] INIT(= N_("E1069: white space required after '%s'")); + EXTERN char e_no_white_before[] INIT(= N_("E1068: No white space allowed before '%s'")); + EXTERN char e_lock_unlock[] INIT(= N_("E940: Cannot lock or unlock variable %s")); #endif *************** *** 1819,1824 **** --- 1823,1830 ---- #ifdef FEAT_EVAL EXTERN time_T time_for_testing INIT(= 0); + EXTERN int echo_attr INIT(= 0); // attributes used for ":echo" + // Abort conversion to string after a recursion error. EXTERN int did_echo_string_emsg INIT(= FALSE); *** ../vim-8.2.0625/src/testdir/test_vim9_func.vim 2020-04-23 18:13:18.035179330 +0200 --- src/testdir/test_vim9_func.vim 2020-04-23 19:12:38.101898056 +0200 *************** *** 259,264 **** --- 259,265 ---- def Test_arg_type_wrong() CheckScriptFailure(['def Func3(items: list)', 'echo "a"', 'enddef'], 'E1008: Missing ') CheckScriptFailure(['def Func4(...)', 'echo "a"', 'enddef'], 'E1055: Missing name after ...') + CheckScriptFailure(['def Func5(items:string)', 'echo "a"'], 'E1069:') CheckScriptFailure(['def Func5(items)', 'echo "a"'], 'E1077:') enddef *************** *** 390,395 **** --- 391,410 ---- delfunc! Func2 enddef + def Test_vim9script_func() + let lines =<< trim END + vim9script + func Func(arg) + echo a:arg + endfunc + Func('text') + END + writefile(lines, 'XVim9Func') + so XVim9Func + + delete('XVim9Func') + enddef + " Test for internal functions returning different types func Test_InternalFuncRetType() let lines =<< trim END *** ../vim-8.2.0625/src/testdir/test_vim9_disassemble.vim 2020-04-19 18:27:20.791953204 +0200 --- src/testdir/test_vim9_disassemble.vim 2020-04-23 22:01:42.965251911 +0200 *************** *** 919,924 **** --- 919,946 ---- res) enddef + def s:Echomsg() + echomsg 'some' 'message' + echoerr 'went' .. 'wrong' + enddef + + def Test_disassemble_echomsg() + let res = execute('disass s:Echomsg') + assert_match('\\d*_Echomsg.*' .. + "echomsg 'some' 'message'.*" .. + '\d PUSHS "some".*' .. + '\d PUSHS "message".*' .. + '\d ECHOMSG 2.*' .. + "echoerr 'went' .. 'wrong'.*" .. + '\d PUSHS "went".*' .. + '\d PUSHS "wrong".*' .. + '\d CONCAT.*' .. + '\d ECHOERR 1.*' .. + '\d PUSHNR 0.*' .. + '\d RETURN', + res) + enddef + def SomeStringArg(arg: string) echo arg enddef *** ../vim-8.2.0625/src/testdir/test_vim9_script.vim 2020-04-23 17:07:26.972434270 +0200 --- src/testdir/test_vim9_script.vim 2020-04-23 22:11:18.600003740 +0200 *************** *** 54,59 **** --- 54,63 ---- let dict4: dict = #{one: 1, two: '2'} let dict5: dict = #{one: 0z01, tw: 0z02} + call CheckDefFailure(['let x:string'], 'E1069:') + call CheckDefFailure(['let x:string = "x"'], 'E1069:') + call CheckDefFailure(['let a:string = "x"'], 'E1082:') + let a: number = 6 assert_equal(6, a) *************** *** 976,981 **** --- 980,999 ---- call CheckDefFailure(['echo "xxx"# comment'], 'E488:') enddef + def Test_echomsg_cmd() + echomsg 'some' 'more' # comment + assert_match('^some more$', Screenline(&lines)) + echo 'clear' + 1messages + assert_match('^some more$', Screenline(&lines)) + + call CheckDefFailure(['echomsg "xxx"# comment'], 'E488:') + enddef + + def Test_echoerr_cmd() + # TODO: write this test + enddef + def Test_for_outside_of_function() let lines =<< trim END vim9script *** ../vim-8.2.0625/src/version.c 2020-04-23 18:13:18.035179330 +0200 --- src/version.c 2020-04-23 22:15:23.843462260 +0200 *************** *** 748,749 **** --- 748,751 ---- { /* Add new patch number below this line */ + /**/ + 626, /**/ -- hundred-and-one symptoms of being an internet addict: 5. You find yourself brainstorming for new subjects to search. /// 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 ///