Patch 8.2.2124
Problem: Vim9: a range cannot be computed at runtime.
Solution: Add the ISN_RANGE instruction.
Files: src/vim9.h, src/vim9compile.c, src/vim9execute.c,
src/testdir/test_vim9_cmd.vim,
src/testdir/test_vim9_disassemble.vim
*** ../vim-8.2.2123/src/vim9.h 2020-11-23 08:31:14.097789125 +0100
--- src/vim9.h 2020-12-09 19:36:11.914988439 +0100
***************
*** 18,23 ****
--- 18,24 ----
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
+ ISN_RANGE, // compute range from isn_arg.string, push to stack
// get and set variables
ISN_LOAD, // push local variable isn_arg.number
***************
*** 366,368 ****
--- 367,374 ----
extern garray_T def_functions;
#endif
+ // Used for "lnum" when a range is to be taken from the stack.
+ #define LNUM_VARIABLE_RANGE -999
+
+ // Used for "lnum" when a range is to be taken from the stack and "!" is used.
+ #define LNUM_VARIABLE_RANGE_ABOVE -888
*** ../vim-8.2.2123/src/vim9compile.c 2020-12-08 22:08:47.672125693 +0100
--- src/vim9compile.c 2020-12-10 19:42:52.365297164 +0100
***************
*** 1888,1893 ****
--- 1888,1913 ----
return OK;
}
+ /*
+ * Generate ISN_RANGE. Consumes "range". Return OK/FAIL.
+ */
+ static int
+ generate_RANGE(cctx_T *cctx, char_u *range)
+ {
+ isn_T *isn;
+ garray_T *stack = &cctx->ctx_type_stack;
+
+ if ((isn = generate_instr(cctx, ISN_RANGE)) == NULL)
+ return FAIL;
+ isn->isn_arg.string = range;
+
+ if (ga_grow(stack, 1) == FAIL)
+ return FAIL;
+ ((type_T **)stack->ga_data)[stack->ga_len] = &t_number;
+ ++stack->ga_len;
+ return OK;
+ }
+
static int
generate_UNPACK(cctx_T *cctx, int var_count, int semicolon)
{
***************
*** 7099,7104 ****
--- 7119,7140 ----
}
/*
+ * If "eap" has a range that is not a contstant generate an ISN_RANGE
+ * instruction to compute it and return OK.
+ * Otherwise return FAIL, the caller must deal with any range.
+ */
+ static int
+ compile_variable_range(exarg_T *eap, cctx_T *cctx)
+ {
+ char_u *range_end = skip_range(eap->cmd, TRUE, NULL);
+ char_u *p = skipdigits(eap->cmd);
+
+ if (p == range_end)
+ return FAIL;
+ return generate_RANGE(cctx, vim_strnsave(eap->cmd, range_end - eap->cmd));
+ }
+
+ /*
* :put r
* :put ={expr}
*/
***************
*** 7123,7139 ****
else if (eap->regname != NUL)
++line;
! // "errormsg" will not be set because the range is ADDR_LINES.
! // TODO: if the range contains something like "$" or "." need to evaluate
! // at runtime
! if (parse_cmd_address(eap, &errormsg, FALSE) == FAIL)
! return NULL;
! if (eap->addr_count == 0)
! lnum = -1;
else
! lnum = eap->line2;
! if (above)
! --lnum;
generate_PUT(cctx, eap->regname, lnum);
return line;
--- 7159,7181 ----
else if (eap->regname != NUL)
++line;
! if (compile_variable_range(eap, cctx) == OK)
! {
! lnum = above ? LNUM_VARIABLE_RANGE_ABOVE : LNUM_VARIABLE_RANGE;
! }
else
! {
! // Either no range or a number.
! // "errormsg" will not be set because the range is ADDR_LINES.
! if (parse_cmd_address(eap, &errormsg, FALSE) == FAIL)
! return NULL;
! if (eap->addr_count == 0)
! lnum = -1;
! else
! lnum = eap->line2;
! if (above)
! --lnum;
! }
generate_PUT(cctx, eap->regname, lnum);
return line;
***************
*** 7960,7965 ****
--- 8002,8008 ----
case ISN_PUSHEXC:
case ISN_PUSHFUNC:
case ISN_PUSHS:
+ case ISN_RANGE:
case ISN_STOREB:
case ISN_STOREENV:
case ISN_STOREG:
*** ../vim-8.2.2123/src/vim9execute.c 2020-12-05 21:22:03.626811733 +0100
--- src/vim9execute.c 2020-12-09 21:47:43.623141586 +0100
***************
*** 2861,2866 ****
--- 2861,2886 ----
}
break;
+ case ISN_RANGE:
+ {
+ exarg_T ea;
+ char *errormsg;
+
+ if (GA_GROW(&ectx.ec_stack, 1) == FAIL)
+ goto failed;
+ ++ectx.ec_stack.ga_len;
+ tv = STACK_TV_BOT(-1);
+ ea.addr_type = ADDR_LINES;
+ ea.cmd = iptr->isn_arg.string;
+ if (parse_cmd_address(&ea, &errormsg, FALSE) == FAIL)
+ goto failed;
+ if (ea.addr_count == 0)
+ tv->vval.v_number = curwin->w_cursor.lnum;
+ else
+ tv->vval.v_number = ea.line2;
+ }
+ break;
+
case ISN_PUT:
{
int regname = iptr->isn_arg.put.put_regname;
***************
*** 2880,2886 ****
}
--ectx.ec_stack.ga_len;
}
! if (lnum == -2)
// :put! above cursor
dir = BACKWARD;
else if (lnum >= 0)
--- 2900,2915 ----
}
--ectx.ec_stack.ga_len;
}
! if (lnum < -2)
! {
! // line number was put on the stack by ISN_RANGE
! tv = STACK_TV_BOT(-1);
! curwin->w_cursor.lnum = tv->vval.v_number;
! if (lnum == LNUM_VARIABLE_RANGE_ABOVE)
! dir = BACKWARD;
! --ectx.ec_stack.ga_len;
! }
! else if (lnum == -2)
// :put! above cursor
dir = BACKWARD;
else if (lnum >= 0)
***************
*** 3690,3697 ****
case ISN_2STRING_ANY: smsg("%4d 2STRING_ANY stack[%lld]", current,
(long long)(iptr->isn_arg.number));
break;
case ISN_PUT:
! smsg("%4d PUT %c %ld", current, iptr->isn_arg.put.put_regname,
(long)iptr->isn_arg.put.put_lnum);
break;
--- 3719,3736 ----
case ISN_2STRING_ANY: smsg("%4d 2STRING_ANY stack[%lld]", current,
(long long)(iptr->isn_arg.number));
break;
+ case ISN_RANGE: smsg("%4d RANGE %s", current, iptr->isn_arg.string);
+ break;
case ISN_PUT:
! if (iptr->isn_arg.put.put_lnum == LNUM_VARIABLE_RANGE_ABOVE)
! smsg("%4d PUT %c above range",
! current, iptr->isn_arg.put.put_regname);
! else if (iptr->isn_arg.put.put_lnum == LNUM_VARIABLE_RANGE)
! smsg("%4d PUT %c range",
! current, iptr->isn_arg.put.put_regname);
! else
! smsg("%4d PUT %c %ld", current,
! iptr->isn_arg.put.put_regname,
(long)iptr->isn_arg.put.put_lnum);
break;
*** ../vim-8.2.2123/src/testdir/test_vim9_cmd.vim 2020-12-05
17:11:09.241679401 +0100
--- src/testdir/test_vim9_cmd.vim 2020-12-09 22:02:08.095304957 +0100
***************
*** 614,619 ****
--- 614,630 ----
assert_equal('above', getline(3))
assert_equal('below', getline(4))
+ # compute range at runtime
+ setline(1, range(1, 8))
+ @a = 'aaa'
+ :$-2put a
+ assert_equal('aaa', getline(7))
+
+ setline(1, range(1, 8))
+ :2
+ :+2put! a
+ assert_equal('aaa', getline(4))
+
bwipe!
enddef
*** ../vim-8.2.2123/src/testdir/test_vim9_disassemble.vim 2020-12-02
17:36:49.173409740 +0100
--- src/testdir/test_vim9_disassemble.vim 2020-12-09 21:57:08.792637746
+0100
***************
*** 133,138 ****
--- 133,153 ----
res)
enddef
+ def s:PutRange()
+ :$-2put a
+ enddef
+
+ def Test_disassemble_put_range()
+ var res = execute('disass s:PutRange')
+ assert_match('<SNR>\d*_PutRange.*' ..
+ ' :$-2put a\_s*' ..
+ '\d RANGE $-2\_s*' ..
+ '\d PUT a range\_s*' ..
+ '\d PUSHNR 0\_s*' ..
+ '\d RETURN',
+ res)
+ enddef
+
def s:ScriptFuncPush()
var localbool = true
var localspec = v:none
*** ../vim-8.2.2123/src/version.c 2020-12-09 18:13:40.713680179 +0100
--- src/version.c 2020-12-10 19:40:03.325837051 +0100
***************
*** 752,753 ****
--- 752,755 ----
{ /* Add new patch number below this line */
+ /**/
+ 2124,
/**/
--
Behold the warranty! The bold print giveth and the fine print taketh.
/// Bram Moolenaar -- [email protected] -- 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 ///
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/vim_dev/202012101844.0BAIiM7q2270698%40masaka.moolenaar.net.