From 08597875b2a1e7d118b0346c652a96e7527e7d8b Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Thu, 10 Dec 2020 19:43:40 +0100 Subject: 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. --- src/vim9compile.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 53 insertions(+), 10 deletions(-) (limited to 'src/vim9compile.c') diff --git a/src/vim9compile.c b/src/vim9compile.c index da069f405..ac8fb846a 100644 --- a/src/vim9compile.c +++ b/src/vim9compile.c @@ -1888,6 +1888,26 @@ generate_EXECCONCAT(cctx_T *cctx, int count) 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) { @@ -7098,6 +7118,22 @@ compile_mult_expr(char_u *arg, int cmdidx, cctx_T *cctx) 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 ={expr} @@ -7123,17 +7159,23 @@ compile_put(char_u *arg, exarg_T *eap, cctx_T *cctx) 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; + if (compile_variable_range(eap, cctx) == OK) + { + lnum = above ? LNUM_VARIABLE_RANGE_ABOVE : LNUM_VARIABLE_RANGE; + } else - lnum = eap->line2; - if (above) - --lnum; + { + // 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,6 +8002,7 @@ delete_instr(isn_T *isn) case ISN_PUSHEXC: case ISN_PUSHFUNC: case ISN_PUSHS: + case ISN_RANGE: case ISN_STOREB: case ISN_STOREENV: case ISN_STOREG: -- cgit v1.2.1