To: vim_dev@googlegroups.com Subject: Patch 8.2.3716 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 8.2.3716 Problem: Vim9: range without a command is not compiled. Solution: Add the ISN_EXECRANGE byte code. Files: src/ex_docmd.c, src/proto/ex_docmd.pro, src/vim9compile.c, src/vim9execute.c, src/vim9.h, src/testdir/test_vim9_disassemble.vim *** ../vim-8.2.3715/src/ex_docmd.c 2021-11-29 20:39:06.674101624 +0000 --- src/ex_docmd.c 2021-12-01 14:50:35.384211034 +0000 *************** *** 1977,2019 **** */ if (ea.skip) // skip this if inside :if goto doend; ! if ((*ea.cmd == '|' || (exmode_active && ea.line1 != ea.line2)) ! #ifdef FEAT_EVAL ! && !vim9script ! #endif ! ) ! { ! ea.cmdidx = CMD_print; ! ea.argt = EX_RANGE+EX_COUNT+EX_TRLBAR; ! if ((errormsg = invalid_range(&ea)) == NULL) ! { ! correct_range(&ea); ! ex_print(&ea); ! } ! } ! else if (ea.addr_count != 0) ! { ! if (ea.line2 > curbuf->b_ml.ml_line_count) ! { ! // With '-' in 'cpoptions' a line number past the file is an ! // error, otherwise put it at the end of the file. ! if (vim_strchr(p_cpo, CPO_MINUS) != NULL) ! ea.line2 = -1; ! else ! ea.line2 = curbuf->b_ml.ml_line_count; ! } ! ! if (ea.line2 < 0) ! errormsg = _(e_invalid_range); ! else ! { ! if (ea.line2 == 0) ! curwin->w_cursor.lnum = 1; ! else ! curwin->w_cursor.lnum = ea.line2; ! beginline(BL_SOL | BL_FIX); ! } ! } goto doend; } --- 1977,1983 ---- */ if (ea.skip) // skip this if inside :if goto doend; ! errormsg = ex_range_without_command(&ea); goto doend; } *************** *** 2708,2713 **** --- 2672,2726 ---- } /* + * Handle a range without a command. + * Returns an error message on failure. + */ + char * + ex_range_without_command(exarg_T *eap) + { + char *errormsg = NULL; + + if ((*eap->cmd == '|' || (exmode_active && eap->line1 != eap->line2)) + #ifdef FEAT_EVAL + && !in_vim9script() + #endif + ) + { + eap->cmdidx = CMD_print; + eap->argt = EX_RANGE+EX_COUNT+EX_TRLBAR; + if ((errormsg = invalid_range(eap)) == NULL) + { + correct_range(eap); + ex_print(eap); + } + } + else if (eap->addr_count != 0) + { + if (eap->line2 > curbuf->b_ml.ml_line_count) + { + // With '-' in 'cpoptions' a line number past the file is an + // error, otherwise put it at the end of the file. + if (vim_strchr(p_cpo, CPO_MINUS) != NULL) + eap->line2 = -1; + else + eap->line2 = curbuf->b_ml.ml_line_count; + } + + if (eap->line2 < 0) + errormsg = _(e_invalid_range); + else + { + if (eap->line2 == 0) + curwin->w_cursor.lnum = 1; + else + curwin->w_cursor.lnum = eap->line2; + beginline(BL_SOL | BL_FIX); + } + } + return errormsg; + } + + /* * Check for an Ex command with optional tail. * If there is a match advance "pp" to the argument and return TRUE. * If "noparen" is TRUE do not recognize the command followed by "(". *** ../vim-8.2.3715/src/proto/ex_docmd.pro 2021-08-10 18:52:57.474235537 +0100 --- src/proto/ex_docmd.pro 2021-12-01 14:50:06.320314008 +0000 *************** *** 7,12 **** --- 7,13 ---- void *getline_cookie(char_u *(*fgetline)(int, void *, int, getline_opt_T), void *cookie); char_u *getline_peek(char_u *(*fgetline)(int, void *, int, getline_opt_T), void *cookie); char *ex_errmsg(char *msg, char_u *arg); + char *ex_range_without_command(exarg_T *eap); int checkforcmd(char_u **pp, char *cmd, int len); int checkforcmd_noparen(char_u **pp, char *cmd, int len); int parse_command_modifiers(exarg_T *eap, char **errormsg, cmdmod_T *cmod, int skip_only); *************** *** 22,28 **** void f_fullcommand(typval_T *argvars, typval_T *rettv); cmdidx_T excmd_get_cmdidx(char_u *cmd, int len); long excmd_get_argt(cmdidx_T idx); ! char_u *skip_range(char_u *cmd, int skip_star, int *ctx); void ex_ni(exarg_T *eap); int expand_filename(exarg_T *eap, char_u **cmdlinep, char **errormsgp); void separate_nextcmd(exarg_T *eap); --- 23,29 ---- void f_fullcommand(typval_T *argvars, typval_T *rettv); cmdidx_T excmd_get_cmdidx(char_u *cmd, int len); long excmd_get_argt(cmdidx_T idx); ! char_u *skip_range(char_u *cmd_start, int skip_star, int *ctx); void ex_ni(exarg_T *eap); int expand_filename(exarg_T *eap, char_u **cmdlinep, char **errormsgp); void separate_nextcmd(exarg_T *eap); *** ../vim-8.2.3715/src/vim9compile.c 2021-12-01 10:09:12.404191464 +0000 --- src/vim9compile.c 2021-12-01 15:08:01.185162896 +0000 *************** *** 2275,2282 **** return OK; } static int ! generate_EXEC(cctx_T *cctx, isntype_T isntype, char_u *line) { isn_T *isn; --- 2275,2286 ---- return OK; } + /* + * Generate an EXEC instruction that takes a string argument. + * A copy is made of "line". + */ static int ! generate_EXEC_copy(cctx_T *cctx, isntype_T isntype, char_u *line) { isn_T *isn; *************** *** 2287,2292 **** --- 2291,2319 ---- return OK; } + /* + * Generate an EXEC instruction that takes a string argument. + * "str" must be allocated, it is consumed. + */ + static int + generate_EXEC(cctx_T *cctx, isntype_T isntype, char_u *str) + { + isn_T *isn; + + if (cctx->ctx_skip == SKIP_YES) + { + vim_free(str); + return OK; + } + if ((isn = generate_instr(cctx, isntype)) == NULL) + { + vim_free(str); + return FAIL; + } + isn->isn_arg.string = str; + return OK; + } + static int generate_LEGACY_EVAL(cctx_T *cctx, char_u *line) { *************** *** 7552,7558 **** vim_snprintf((char *)buf, len, "%s %s", eap->cmdidx == CMD_lockvar ? "lockvar" : "unlockvar", p); ! ret = generate_EXEC(cctx, isn, buf); vim_free(buf); *name_end = cc; --- 7579,7585 ---- vim_snprintf((char *)buf, len, "%s %s", eap->cmdidx == CMD_lockvar ? "lockvar" : "unlockvar", p); ! ret = generate_EXEC_copy(cctx, isn, buf); vim_free(buf); *name_end = cc; *************** *** 9248,9254 **** generate_EXECCONCAT(cctx, count); } else ! generate_EXEC(cctx, ISN_EXEC, line); theend: if (*nextcmd != NUL) --- 9275,9281 ---- generate_EXECCONCAT(cctx, count); } else ! generate_EXEC_copy(cctx, ISN_EXEC, line); theend: if (*nextcmd != NUL) *************** *** 9874,9883 **** if (ends_excmd2(line, ea.cmd)) { // A range without a command: jump to the line. ! // TODO: compile to a more efficient command, possibly ! // calling parse_cmd_address(). ! ea.cmdidx = CMD_SIZE; ! line = compile_exec(line, &ea, &cctx); goto nextline; } } --- 9901,9912 ---- if (ends_excmd2(line, ea.cmd)) { // A range without a command: jump to the line. ! line = skipwhite(line); ! while (*line == ':') ! ++line; ! generate_EXEC(&cctx, ISN_EXECRANGE, ! vim_strnsave(line, ea.cmd - line)); ! line = ea.cmd; goto nextline; } } *************** *** 10350,10355 **** --- 10379,10385 ---- { case ISN_DEF: case ISN_EXEC: + case ISN_EXECRANGE: case ISN_EXEC_SPLIT: case ISN_LEGACY_EVAL: case ISN_LOADAUTO: *** ../vim-8.2.3715/src/vim9execute.c 2021-11-29 10:36:15.916827518 +0000 --- src/vim9execute.c 2021-12-01 14:58:01.438798689 +0000 *************** *** 1774,1779 **** --- 1774,1801 ---- } break; + // execute Ex command line that is only a range + case ISN_EXECRANGE: + { + exarg_T ea; + char *error = NULL; + + CLEAR_FIELD(ea); + ea.cmdidx = CMD_SIZE; + ea.addr_type = ADDR_LINES; + ea.cmd = iptr->isn_arg.string; + parse_cmd_address(&ea, &error, FALSE); + if (error == NULL) + error = ex_range_without_command(&ea); + if (error != NULL) + { + SOURCING_LNUM = iptr->isn_lnum; + emsg(error); + goto on_error; + } + } + break; + // Evaluate an expression with legacy syntax, push it onto the // stack. case ISN_LEGACY_EVAL: *************** *** 5068,5073 **** --- 5090,5098 ---- case ISN_EXEC_SPLIT: smsg("%s%4d EXEC_SPLIT %s", pfx, current, iptr->isn_arg.string); break; + case ISN_EXECRANGE: + smsg("%s%4d EXECRANGE %s", pfx, current, iptr->isn_arg.string); + break; case ISN_LEGACY_EVAL: smsg("%s%4d EVAL legacy %s", pfx, current, iptr->isn_arg.string); *** ../vim-8.2.3715/src/vim9.h 2021-11-28 22:00:08.148081412 +0000 --- src/vim9.h 2021-12-01 14:37:00.840311433 +0000 *************** *** 15,20 **** --- 15,21 ---- ISN_EXEC, // execute Ex command line isn_arg.string ISN_EXECCONCAT, // execute Ex command from isn_arg.number items on stack ISN_EXEC_SPLIT, // execute Ex command from isn_arg.string split at NL + ISN_EXECRANGE, // execute EX command that is only a range ISN_LEGACY_EVAL, // evaluate expression isn_arg.string with legacy syntax. ISN_ECHO, // :echo with isn_arg.echo.echo_count items on top of stack ISN_EXECUTE, // :execute with isn_arg.number items on top of stack *** ../vim-8.2.3715/src/testdir/test_vim9_disassemble.vim 2021-11-30 20:57:34.561305257 +0000 --- src/testdir/test_vim9_disassemble.vim 2021-12-01 15:20:31.675255283 +0000 *************** *** 1999,2004 **** --- 1999,2023 ---- res) enddef + def s:OnlyRange() + :$ + :123 + :'m + enddef + + def Test_disassemble_range_only() + var res = execute('disass s:OnlyRange') + assert_match('\\d*_OnlyRange\_s*' .. + ':$\_s*' .. + '\d EXECRANGE $\_s*' .. + ':123\_s*' .. + '\d EXECRANGE 123\_s*' .. + ':''m\_s*' .. + '\d EXECRANGE ''m\_s*' .. + '\d\+ RETURN void', + res) + enddef + def s:Echomsg() echomsg 'some' 'message' echoconsole 'nothing' *** ../vim-8.2.3715/src/version.c 2021-12-01 12:41:25.079773508 +0000 --- src/version.c 2021-12-01 14:35:56.672820240 +0000 *************** *** 755,756 **** --- 755,758 ---- { /* Add new patch number below this line */ + /**/ + 3716, /**/ -- DENNIS: Look, strange women lying on their backs in ponds handing out swords ... that's no basis for a system of government. Supreme executive power derives from a mandate from the masses, not from some farcical aquatic ceremony. "Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// \\\ \\\ sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///