summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2019-02-12 22:28:33 +0100
committerBram Moolenaar <Bram@vim.org>2019-02-12 22:28:33 +0100
commitff697e6cef8ced7717a21fd525ab3200b2f1724f (patch)
tree168402d9118a9b7fd9844cfda8736b85fc70063d /src
parent57ee2b6e0b5b730d12ee9db00a8e2a577df9e374 (diff)
patch 8.1.0902: incomplete set of assignment operatorsv8.1.0902
Problem: Incomplete set of assignment operators. Solution: Add /=, *= and %=. (Ozaki Kiichi, closes #3931)
Diffstat (limited to 'src')
-rw-r--r--src/eval.c88
-rw-r--r--src/testdir/test_vimscript.vim78
-rw-r--r--src/version.c2
3 files changed, 135 insertions, 33 deletions
diff --git a/src/eval.c b/src/eval.c
index 46d24ef788..56a26b1aea 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -1197,6 +1197,9 @@ 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.
*/
@@ -1216,10 +1219,10 @@ ex_let(exarg_T *eap)
argend = skip_var_list(arg, &var_count, &semicolon);
if (argend == NULL)
return;
- if (argend > arg && argend[-1] == '.') /* for var.='str' */
+ if (argend > arg && argend[-1] == '.') // for var.='str'
--argend;
expr = skipwhite(argend);
- if (*expr != '=' && !(vim_strchr((char_u *)"+-.", *expr) != NULL
+ if (*expr != '=' && !(vim_strchr((char_u *)"+-*/%.", *expr) != NULL
&& expr[1] == '='))
{
/*
@@ -1249,8 +1252,8 @@ ex_let(exarg_T *eap)
op[1] = NUL;
if (*expr != '=')
{
- if (vim_strchr((char_u *)"+-.", *expr) != NULL)
- op[0] = *expr; /* +=, -= or .= */
+ if (vim_strchr((char_u *)"+-*/%.", *expr) != NULL)
+ op[0] = *expr; // +=, -=, *=, /=, %= or .=
expr = skipwhite(expr + 2);
}
else
@@ -1671,7 +1674,7 @@ ex_let_one(
semsg(_(e_invarg2), name - 1);
else
{
- if (op != NULL && (*op == '+' || *op == '-'))
+ if (op != NULL && vim_strchr((char_u *)"+-*/%", *op) != NULL)
semsg(_(e_letwrong), op);
else if (endchars != NULL
&& vim_strchr(endchars, *skipwhite(arg)) == NULL)
@@ -1744,18 +1747,22 @@ ex_let_one(
|| (opt_type == 0 && *op != '.'))
{
semsg(_(e_letwrong), op);
- s = NULL; /* don't set the value */
+ s = NULL; // don't set the value
}
else
{
- if (opt_type == 1) /* number */
+ 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 */
+ else if (opt_type == 0 && stringval != NULL) // string
{
s = concat_str(stringval, s);
vim_free(stringval);
@@ -1779,7 +1786,7 @@ ex_let_one(
else if (*arg == '@')
{
++arg;
- if (op != NULL && (*op == '+' || *op == '-'))
+ if (op != NULL && vim_strchr((char_u *)"+-*/%", *op) != NULL)
semsg(_(e_letwrong), op);
else if (endchars != NULL
&& vim_strchr(endchars, *skipwhite(arg + 1)) == NULL)
@@ -2254,7 +2261,8 @@ 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(
@@ -2327,7 +2335,7 @@ set_var_lval(
{
typval_T tv;
- /* handle +=, -= and .= */
+ // handle +=, -=, *=, /=, %= and .=
di = NULL;
if (get_var_tv(lp->ll_name, (int)STRLEN(lp->ll_name),
&tv, &di, TRUE, FALSE) == OK)
@@ -2448,7 +2456,8 @@ set_var_lval(
}
/*
- * Handle "tv1 += tv2", "tv1 -= tv2" and "tv1 .= tv2"
+ * Handle "tv1 += tv2", "tv1 -= tv2", "tv1 *= tv2", "tv1 /= tv2", "tv1 %= tv2"
+ * and "tv1 .= tv2"
* Returns OK or FAIL.
*/
static int
@@ -2490,7 +2499,7 @@ tv_op(typval_T *tv1, typval_T *tv2, char_u *op)
case VAR_LIST:
if (*op != '+' || tv2->v_type != VAR_LIST)
break;
- /* List += List */
+ // List += List
if (tv1->vval.v_list != NULL && tv2->vval.v_list != NULL)
list_extend(tv1->vval.v_list, tv2->vval.v_list, NULL);
return OK;
@@ -2499,19 +2508,24 @@ tv_op(typval_T *tv1, typval_T *tv2, char_u *op)
case VAR_STRING:
if (tv2->v_type == VAR_LIST)
break;
- if (*op == '+' || *op == '-')
+ if (vim_strchr((char_u *)"+-*/%", *op) != NULL)
{
- /* nr += nr or nr -= nr*/
+ // nr += nr , nr -= nr , nr *=nr , nr /= nr , nr %= nr
n = tv_get_number(tv1);
#ifdef FEAT_FLOAT
if (tv2->v_type == VAR_FLOAT)
{
float_T f = 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;
+ }
clear_tv(tv1);
tv1->v_type = VAR_FLOAT;
tv1->vval.v_float = f;
@@ -2519,10 +2533,14 @@ tv_op(typval_T *tv1, typval_T *tv2, char_u *op)
else
#endif
{
- 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;
+ }
clear_tv(tv1);
tv1->v_type = VAR_NUMBER;
tv1->vval.v_number = n;
@@ -2533,7 +2551,7 @@ tv_op(typval_T *tv1, typval_T *tv2, char_u *op)
if (tv2->v_type == VAR_FLOAT)
break;
- /* str .= str */
+ // str .= str
s = tv_get_string(tv1);
s = concat_str(s, tv_get_string_buf(tv2, numbuf));
clear_tv(tv1);
@@ -2547,7 +2565,8 @@ tv_op(typval_T *tv1, typval_T *tv2, char_u *op)
{
float_T f;
- if (*op == '.' || (tv2->v_type != VAR_FLOAT
+ if (*op == '%' || *op == '.'
+ || (tv2->v_type != VAR_FLOAT
&& tv2->v_type != VAR_NUMBER
&& tv2->v_type != VAR_STRING))
break;
@@ -2555,10 +2574,13 @@ tv_op(typval_T *tv1, typval_T *tv2, char_u *op)
f = tv2->vval.v_float;
else
f = 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;
+ }
}
#endif
return OK;
diff --git a/src/testdir/test_vimscript.vim b/src/testdir/test_vimscript.vim
index 9de0a620c1..41a1dda7db 100644
--- a/src/testdir/test_vimscript.vim
+++ b/src/testdir/test_vimscript.vim
@@ -1441,6 +1441,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
diff --git a/src/version.c b/src/version.c
index 998f259bad..cadd46e4f4 100644
--- a/src/version.c
+++ b/src/version.c
@@ -784,6 +784,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 902,
+/**/
901,
/**/
900,