diff options
author | erw7 <erw7.github@gmail.com> | 2019-05-29 09:33:43 +0900 |
---|---|---|
committer | erw7 <erw7.github@gmail.com> | 2019-05-29 12:05:56 +0900 |
commit | d46aaa074640ef92382e5800297b7c76ed7574da (patch) | |
tree | 2cad825bacdc78bda76b9cd77362ee75a0a59081 | |
parent | f8f63393c12da88799cb480086922431de60ca0a (diff) | |
download | rneovim-d46aaa074640ef92382e5800297b7c76ed7574da.tar.gz rneovim-d46aaa074640ef92382e5800297b7c76ed7574da.tar.bz2 rneovim-d46aaa074640ef92382e5800297b7c76ed7574da.zip |
vim-patch:8.1.0902: incomplete set of assignment operators
Problem: Incomplete set of assignment operators.
Solution: Add /=, *= and %=. (Ozaki Kiichi, closes vim/vim#3931)
https://github.com/vim/vim/commit/ff697e6cef8ced7717a21fd525ab3200b2f1724f
-rw-r--r-- | runtime/doc/eval.txt | 6 | ||||
-rw-r--r-- | src/nvim/eval.c | 28 | ||||
-rw-r--r-- | src/nvim/eval/executor.c | 44 | ||||
-rw-r--r-- | src/nvim/testdir/test_vimscript.vim | 78 |
4 files changed, 126 insertions, 30 deletions
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt index c96f51772d..f035c754c0 100644 --- a/runtime/doc/eval.txt +++ b/runtime/doc/eval.txt @@ -9459,9 +9459,13 @@ This does NOT work: > When the selected range of items is partly past the end of the list, items will be added. - *:let+=* *:let-=* *:let.=* *E734* + *:let+=* *:let-=* *:letstar=* + *:let/=* *:let%=* *:let.=* *E734* :let {var} += {expr1} Like ":let {var} = {var} + {expr1}". :let {var} -= {expr1} Like ":let {var} = {var} - {expr1}". +:let {var} *= {expr1} Like ":let {var} = {var} * {expr1}". +:let {var} /= {expr1} Like ":let {var} = {var} / {expr1}". +:let {var} %= {expr1} Like ":let {var} = {var} % {expr1}". :let {var} .= {expr1} Like ":let {var} = {var} . {expr1}". These fail if {var} was not set yet and when the type of {var} and {expr1} don't fit the operator. diff --git a/src/nvim/eval.c b/src/nvim/eval.c index deaed17926..7d7c2d3f33 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -1442,6 +1442,9 @@ int eval_foldexpr(char_u *arg, int *cp) * ":let var = expr" assignment command. * ":let var += expr" assignment command. * ":let var -= expr" assignment command. + * ":let var *= expr" assignment command. + * ":let var /= expr" assignment command. + * ":let var %= expr" assignment command. * ":let var .= expr" assignment command. * ":let [var1, var2] = expr" unpack list. */ @@ -1465,7 +1468,7 @@ void ex_let(exarg_T *eap) argend--; } expr = skipwhite(argend); - if (*expr != '=' && !(vim_strchr((char_u *)"+-.", *expr) != NULL + if (*expr != '=' && !(vim_strchr((char_u *)"+-*/%.", *expr) != NULL && expr[1] == '=')) { // ":let" without "=": list variables if (*arg == '[') { @@ -1488,8 +1491,8 @@ void ex_let(exarg_T *eap) op[0] = '='; op[1] = NUL; if (*expr != '=') { - if (vim_strchr((char_u *)"+-.", *expr) != NULL) { - op[0] = *expr; // +=, -=, .= + if (vim_strchr((char_u *)"+-*/%.", *expr) != NULL) { + op[0] = *expr; // +=, -=, *=, /=, %= or .= } expr = skipwhite(expr + 2); } else { @@ -1864,7 +1867,7 @@ static char_u *ex_let_one(char_u *arg, typval_T *const tv, if (len == 0) { EMSG2(_(e_invarg2), name - 1); } else { - if (op != NULL && (*op == '+' || *op == '-')) { + if (op != NULL && vim_strchr((char_u *)"+-*/%", *op) != NULL) { EMSG2(_(e_letwrong), op); } else if (endchars != NULL && vim_strchr(endchars, *skipwhite(arg)) == NULL) { @@ -1927,10 +1930,12 @@ static char_u *ex_let_one(char_u *arg, typval_T *const tv, s = NULL; // don't set the value } else { if (opt_type == 1) { // number - if (*op == '+') { - n = numval + n; - } else { - n = numval - n; + switch (*op) { + case '+': n = numval + n; break; + case '-': n = numval - n; break; + case '*': n = numval * n; break; + case '/': n = numval / n; break; + case '%': n = numval % n; break; } } else if (opt_type == 0 && stringval != NULL) { // string char *const oldstringval = stringval; @@ -1951,7 +1956,7 @@ static char_u *ex_let_one(char_u *arg, typval_T *const tv, // ":let @r = expr": Set register contents. } else if (*arg == '@') { arg++; - if (op != NULL && (*op == '+' || *op == '-')) { + if (op != NULL && vim_strchr((char_u *)"+-*/%", *op) != NULL) { emsgf(_(e_letwrong), op); } else if (endchars != NULL && vim_strchr(endchars, *skipwhite(arg + 1)) == NULL) { @@ -2350,7 +2355,8 @@ static void clear_lval(lval_T *lp) /* * Set a variable that was parsed by get_lval() to "rettv". * "endp" points to just after the parsed name. - * "op" is NULL, "+" for "+=", "-" for "-=", "." for ".=" or "=" for "=". + * "op" is NULL, "+" for "+=", "-" for "-=", "*" for "*=", "/" for "/=", + * "%" for "%=", "." for ".=" or "=" for "=". */ static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, int copy, const char_u *op) @@ -2365,7 +2371,7 @@ static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, if (op != NULL && *op != '=') { typval_T tv; - // handle +=, -= and .= + // handle +=, -=, *=, /=, %= and .= di = NULL; if (get_var_tv((const char *)lp->ll_name, (int)STRLEN(lp->ll_name), &tv, &di, true, false) == OK) { diff --git a/src/nvim/eval/executor.c b/src/nvim/eval/executor.c index 99298cbbcf..e972c506dd 100644 --- a/src/nvim/eval/executor.c +++ b/src/nvim/eval/executor.c @@ -16,7 +16,7 @@ static char *e_letwrong = N_("E734: Wrong variable type for %s="); char *e_listidx = N_("E684: list index out of range: %" PRId64); -/// Hanle tv1 += tv2, -=, .= +/// Hanle tv1 += tv2, -=, *=, /=, %=, .= /// /// @param[in,out] tv1 First operand, modified typval. /// @param[in] tv2 Second operand. @@ -51,25 +51,31 @@ int eexe_mod_op(typval_T *const tv1, const typval_T *const tv2, if (tv2->v_type == VAR_LIST) { break; } - if (*op == '+' || *op == '-') { - // nr += nr or nr -= nr + if (vim_strchr((char_u *)"+-*/%", *op) != NULL) { + // nr += nr or nr -= nr, nr *= nr, nr /= nr, nr %= nr varnumber_T n = tv_get_number(tv1); if (tv2->v_type == VAR_FLOAT) { float_T f = (float_T)n; - if (*op == '+') { - f += tv2->vval.v_float; - } else { - f -= tv2->vval.v_float; + if (*op == '%') { + break; + } + switch (*op) { + case '+': f += tv2->vval.v_float; break; + case '-': f -= tv2->vval.v_float; break; + case '*': f *= tv2->vval.v_float; break; + case '/': f /= tv2->vval.v_float; break; } tv_clear(tv1); tv1->v_type = VAR_FLOAT; tv1->vval.v_float = f; } else { - if (*op == '+') { - n += tv_get_number(tv2); - } else { - n -= tv_get_number(tv2); + switch (*op) { + case '+': n += tv_get_number(tv2); break; + case '-': n -= tv_get_number(tv2); break; + case '*': n *= tv_get_number(tv2); break; + case '/': n /= tv_get_number(tv2); break; + case '%': n %= tv_get_number(tv2); break; } tv_clear(tv1); tv1->v_type = VAR_NUMBER; @@ -92,18 +98,20 @@ int eexe_mod_op(typval_T *const tv1, const typval_T *const tv2, return OK; } case VAR_FLOAT: { - if (*op == '.' || (tv2->v_type != VAR_FLOAT - && tv2->v_type != VAR_NUMBER - && tv2->v_type != VAR_STRING)) { + if (*op == '%' || *op == '.' + || (tv2->v_type != VAR_FLOAT + && tv2->v_type != VAR_NUMBER + && tv2->v_type != VAR_STRING)) { break; } const float_T f = (tv2->v_type == VAR_FLOAT ? tv2->vval.v_float : (float_T)tv_get_number(tv2)); - if (*op == '+') { - tv1->vval.v_float += f; - } else { - tv1->vval.v_float -= f; + switch (*op) { + case '+': tv1->vval.v_float += f; break; + case '-': tv1->vval.v_float -= f; break; + case '*': tv1->vval.v_float *= f; break; + case '/': tv1->vval.v_float /= f; break; } return OK; } diff --git a/src/nvim/testdir/test_vimscript.vim b/src/nvim/testdir/test_vimscript.vim index 5b16f6d205..05abf04d65 100644 --- a/src/nvim/testdir/test_vimscript.vim +++ b/src/nvim/testdir/test_vimscript.vim @@ -1294,6 +1294,84 @@ func Test_script_local_func() enew! | close endfunc +func Test_compound_assignment_operators() + " Test for number + let x = 1 + let x += 10 + call assert_equal(11, x) + let x -= 5 + call assert_equal(6, x) + let x *= 4 + call assert_equal(24, x) + let x /= 3 + call assert_equal(8, x) + let x %= 3 + call assert_equal(2, x) + let x .= 'n' + call assert_equal('2n', x) + + " Test for string + let x = 'str' + let x .= 'ing' + call assert_equal('string', x) + let x += 1 + call assert_equal(1, x) + let x -= 1.5 + call assert_equal(-0.5, x) + + if has('float') + " Test for float + let x = 0.5 + let x += 4.5 + call assert_equal(5.0, x) + let x -= 1.5 + call assert_equal(3.5, x) + let x *= 3.0 + call assert_equal(10.5, x) + let x /= 2.5 + call assert_equal(4.2, x) + call assert_fails('let x %= 0.5', 'E734') + call assert_fails('let x .= "f"', 'E734') + endif + + " Test for environment variable + let $FOO = 1 + call assert_fails('let $FOO += 1', 'E734') + call assert_fails('let $FOO -= 1', 'E734') + call assert_fails('let $FOO *= 1', 'E734') + call assert_fails('let $FOO /= 1', 'E734') + call assert_fails('let $FOO %= 1', 'E734') + let $FOO .= 's' + call assert_equal('1s', $FOO) + unlet $FOO + + " Test for option variable (type: number) + let &scrolljump = 1 + let &scrolljump += 5 + call assert_equal(6, &scrolljump) + let &scrolljump -= 2 + call assert_equal(4, &scrolljump) + let &scrolljump *= 3 + call assert_equal(12, &scrolljump) + let &scrolljump /= 2 + call assert_equal(6, &scrolljump) + let &scrolljump %= 5 + call assert_equal(1, &scrolljump) + call assert_fails('let &scrolljump .= "j"', 'E734') + set scrolljump&vim + + " Test for register + let @/ = 1 + call assert_fails('let @/ += 1', 'E734') + call assert_fails('let @/ -= 1', 'E734') + call assert_fails('let @/ *= 1', 'E734') + call assert_fails('let @/ /= 1', 'E734') + call assert_fails('let @/ %= 1', 'E734') + let @/ .= 's' + call assert_equal('1s', @/) + let @/ = '' +endfunc + "------------------------------------------------------------------------------- " Modelines {{{1 " vim: ts=8 sw=4 tw=80 fdm=marker |