mirror of
https://github.com/vim/vim.git
synced 2025-07-26 11:04:33 -04:00
patch 8.2.2124: Vim9: a range cannot be computed at runtime
Problem: Vim9: a range cannot be computed at runtime. Solution: Add the ISN_RANGE instruction.
This commit is contained in:
parent
d356fc65d2
commit
08597875b2
@ -614,6 +614,17 @@ def Test_put_command()
|
|||||||
assert_equal('above', getline(3))
|
assert_equal('above', getline(3))
|
||||||
assert_equal('below', getline(4))
|
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!
|
bwipe!
|
||||||
enddef
|
enddef
|
||||||
|
|
||||||
|
@ -133,6 +133,21 @@ def Test_disassemble_put_expr()
|
|||||||
res)
|
res)
|
||||||
enddef
|
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()
|
def s:ScriptFuncPush()
|
||||||
var localbool = true
|
var localbool = true
|
||||||
var localspec = v:none
|
var localspec = v:none
|
||||||
|
@ -750,6 +750,8 @@ static char *(features[]) =
|
|||||||
|
|
||||||
static int included_patches[] =
|
static int included_patches[] =
|
||||||
{ /* Add new patch number below this line */
|
{ /* Add new patch number below this line */
|
||||||
|
/**/
|
||||||
|
2124,
|
||||||
/**/
|
/**/
|
||||||
2123,
|
2123,
|
||||||
/**/
|
/**/
|
||||||
|
@ -18,6 +18,7 @@ typedef enum {
|
|||||||
ISN_EXECUTE, // execute Ex commands isn_arg.number 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_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_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
|
// get and set variables
|
||||||
ISN_LOAD, // push local variable isn_arg.number
|
ISN_LOAD, // push local variable isn_arg.number
|
||||||
@ -366,3 +367,8 @@ garray_T def_functions = {0, 0, sizeof(dfunc_T), 50, NULL};
|
|||||||
extern garray_T def_functions;
|
extern garray_T def_functions;
|
||||||
#endif
|
#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
|
||||||
|
@ -1888,6 +1888,26 @@ generate_EXECCONCAT(cctx_T *cctx, int count)
|
|||||||
return OK;
|
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
|
static int
|
||||||
generate_UNPACK(cctx_T *cctx, int var_count, int semicolon)
|
generate_UNPACK(cctx_T *cctx, int var_count, int semicolon)
|
||||||
{
|
{
|
||||||
@ -7098,6 +7118,22 @@ compile_mult_expr(char_u *arg, int cmdidx, cctx_T *cctx)
|
|||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 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 r
|
||||||
* :put ={expr}
|
* :put ={expr}
|
||||||
@ -7123,9 +7159,14 @@ compile_put(char_u *arg, exarg_T *eap, cctx_T *cctx)
|
|||||||
else if (eap->regname != NUL)
|
else if (eap->regname != NUL)
|
||||||
++line;
|
++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.
|
// "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)
|
if (parse_cmd_address(eap, &errormsg, FALSE) == FAIL)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (eap->addr_count == 0)
|
if (eap->addr_count == 0)
|
||||||
@ -7134,6 +7175,7 @@ compile_put(char_u *arg, exarg_T *eap, cctx_T *cctx)
|
|||||||
lnum = eap->line2;
|
lnum = eap->line2;
|
||||||
if (above)
|
if (above)
|
||||||
--lnum;
|
--lnum;
|
||||||
|
}
|
||||||
|
|
||||||
generate_PUT(cctx, eap->regname, lnum);
|
generate_PUT(cctx, eap->regname, lnum);
|
||||||
return line;
|
return line;
|
||||||
@ -7960,6 +8002,7 @@ delete_instr(isn_T *isn)
|
|||||||
case ISN_PUSHEXC:
|
case ISN_PUSHEXC:
|
||||||
case ISN_PUSHFUNC:
|
case ISN_PUSHFUNC:
|
||||||
case ISN_PUSHS:
|
case ISN_PUSHS:
|
||||||
|
case ISN_RANGE:
|
||||||
case ISN_STOREB:
|
case ISN_STOREB:
|
||||||
case ISN_STOREENV:
|
case ISN_STOREENV:
|
||||||
case ISN_STOREG:
|
case ISN_STOREG:
|
||||||
|
@ -2861,6 +2861,26 @@ call_def_function(
|
|||||||
}
|
}
|
||||||
break;
|
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:
|
case ISN_PUT:
|
||||||
{
|
{
|
||||||
int regname = iptr->isn_arg.put.put_regname;
|
int regname = iptr->isn_arg.put.put_regname;
|
||||||
@ -2880,7 +2900,16 @@ call_def_function(
|
|||||||
}
|
}
|
||||||
--ectx.ec_stack.ga_len;
|
--ectx.ec_stack.ga_len;
|
||||||
}
|
}
|
||||||
if (lnum == -2)
|
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
|
// :put! above cursor
|
||||||
dir = BACKWARD;
|
dir = BACKWARD;
|
||||||
else if (lnum >= 0)
|
else if (lnum >= 0)
|
||||||
@ -3690,8 +3719,18 @@ ex_disassemble(exarg_T *eap)
|
|||||||
case ISN_2STRING_ANY: smsg("%4d 2STRING_ANY stack[%lld]", current,
|
case ISN_2STRING_ANY: smsg("%4d 2STRING_ANY stack[%lld]", current,
|
||||||
(long long)(iptr->isn_arg.number));
|
(long long)(iptr->isn_arg.number));
|
||||||
break;
|
break;
|
||||||
|
case ISN_RANGE: smsg("%4d RANGE %s", current, iptr->isn_arg.string);
|
||||||
|
break;
|
||||||
case ISN_PUT:
|
case ISN_PUT:
|
||||||
smsg("%4d PUT %c %ld", current, iptr->isn_arg.put.put_regname,
|
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);
|
(long)iptr->isn_arg.put.put_lnum);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user