diff options
author | Bram Moolenaar <Bram@vim.org> | 2020-12-10 19:43:40 +0100 |
---|---|---|
committer | Bram Moolenaar <Bram@vim.org> | 2020-12-10 19:43:40 +0100 |
commit | 08597875b2a1e7d118b0346c652a96e7527e7d8b (patch) | |
tree | 0bb1d04eadfe4110a7962e9fcbfd361452677205 /src/vim9compile.c | |
parent | d356fc65d273959efa9b05bfa0f07ce1c9ff85a4 (diff) | |
download | vim-git-08597875b2a1e7d118b0346c652a96e7527e7d8b.tar.gz |
patch 8.2.2124: Vim9: a range cannot be computed at runtimev8.2.2124
Problem: Vim9: a range cannot be computed at runtime.
Solution: Add the ISN_RANGE instruction.
Diffstat (limited to 'src/vim9compile.c')
-rw-r--r-- | src/vim9compile.c | 63 |
1 files changed, 53 insertions, 10 deletions
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) { @@ -7099,6 +7119,22 @@ compile_mult_expr(char_u *arg, int cmdidx, cctx_T *cctx) } /* + * 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: |