Skip to content

Commit ff697e6

Browse files
committed
patch 8.1.0902: incomplete set of assignment operators
Problem: Incomplete set of assignment operators. Solution: Add /=, *= and %=. (Ozaki Kiichi, closes #3931)
1 parent 57ee2b6 commit ff697e6

File tree

4 files changed

+140
-34
lines changed

4 files changed

+140
-34
lines changed

runtime/doc/eval.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10836,9 +10836,13 @@ This does NOT work: >
1083610836
When the selected range of items is partly past the
1083710837
end of the list, items will be added.
1083810838

10839-
*:let+=* *:let-=* *:let.=* *E734*
10839+
*:let+=* *:let-=* *:letstar=*
10840+
*:let/=* *:let%=* *:let.=* *E734*
1084010841
:let {var} += {expr1} Like ":let {var} = {var} + {expr1}".
1084110842
:let {var} -= {expr1} Like ":let {var} = {var} - {expr1}".
10843+
:let {var} *= {expr1} Like ":let {var} = {var} * {expr1}".
10844+
:let {var} /= {expr1} Like ":let {var} = {var} / {expr1}".
10845+
:let {var} %= {expr1} Like ":let {var} = {var} % {expr1}".
1084210846
:let {var} .= {expr1} Like ":let {var} = {var} . {expr1}".
1084310847
These fail if {var} was not set yet and when the type
1084410848
of {var} and {expr1} don't fit the operator.

src/eval.c

Lines changed: 55 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1197,6 +1197,9 @@ eval_foldexpr(char_u *arg, int *cp)
11971197
* ":let var = expr" assignment command.
11981198
* ":let var += expr" assignment command.
11991199
* ":let var -= expr" assignment command.
1200+
* ":let var *= expr" assignment command.
1201+
* ":let var /= expr" assignment command.
1202+
* ":let var %= expr" assignment command.
12001203
* ":let var .= expr" assignment command.
12011204
* ":let [var1, var2] = expr" unpack list.
12021205
*/
@@ -1216,10 +1219,10 @@ ex_let(exarg_T *eap)
12161219
argend = skip_var_list(arg, &var_count, &semicolon);
12171220
if (argend == NULL)
12181221
return;
1219-
if (argend > arg && argend[-1] == '.') /* for var.='str' */
1222+
if (argend > arg && argend[-1] == '.') // for var.='str'
12201223
--argend;
12211224
expr = skipwhite(argend);
1222-
if (*expr != '=' && !(vim_strchr((char_u *)"+-.", *expr) != NULL
1225+
if (*expr != '=' && !(vim_strchr((char_u *)"+-*/%.", *expr) != NULL
12231226
&& expr[1] == '='))
12241227
{
12251228
/*
@@ -1249,8 +1252,8 @@ ex_let(exarg_T *eap)
12491252
op[1] = NUL;
12501253
if (*expr != '=')
12511254
{
1252-
if (vim_strchr((char_u *)"+-.", *expr) != NULL)
1253-
op[0] = *expr; /* +=, -= or .= */
1255+
if (vim_strchr((char_u *)"+-*/%.", *expr) != NULL)
1256+
op[0] = *expr; // +=, -=, *=, /=, %= or .=
12541257
expr = skipwhite(expr + 2);
12551258
}
12561259
else
@@ -1671,7 +1674,7 @@ ex_let_one(
16711674
semsg(_(e_invarg2), name - 1);
16721675
else
16731676
{
1674-
if (op != NULL && (*op == '+' || *op == '-'))
1677+
if (op != NULL && vim_strchr((char_u *)"+-*/%", *op) != NULL)
16751678
semsg(_(e_letwrong), op);
16761679
else if (endchars != NULL
16771680
&& vim_strchr(endchars, *skipwhite(arg)) == NULL)
@@ -1744,18 +1747,22 @@ ex_let_one(
17441747
|| (opt_type == 0 && *op != '.'))
17451748
{
17461749
semsg(_(e_letwrong), op);
1747-
s = NULL; /* don't set the value */
1750+
s = NULL; // don't set the value
17481751
}
17491752
else
17501753
{
1751-
if (opt_type == 1) /* number */
1754+
if (opt_type == 1) // number
17521755
{
1753-
if (*op == '+')
1754-
n = numval + n;
1755-
else
1756-
n = numval - n;
1756+
switch (*op)
1757+
{
1758+
case '+': n = numval + n; break;
1759+
case '-': n = numval - n; break;
1760+
case '*': n = numval * n; break;
1761+
case '/': n = numval / n; break;
1762+
case '%': n = numval % n; break;
1763+
}
17571764
}
1758-
else if (opt_type == 0 && stringval != NULL) /* string */
1765+
else if (opt_type == 0 && stringval != NULL) // string
17591766
{
17601767
s = concat_str(stringval, s);
17611768
vim_free(stringval);
@@ -1779,7 +1786,7 @@ ex_let_one(
17791786
else if (*arg == '@')
17801787
{
17811788
++arg;
1782-
if (op != NULL && (*op == '+' || *op == '-'))
1789+
if (op != NULL && vim_strchr((char_u *)"+-*/%", *op) != NULL)
17831790
semsg(_(e_letwrong), op);
17841791
else if (endchars != NULL
17851792
&& vim_strchr(endchars, *skipwhite(arg + 1)) == NULL)
@@ -2254,7 +2261,8 @@ clear_lval(lval_T *lp)
22542261
/*
22552262
* Set a variable that was parsed by get_lval() to "rettv".
22562263
* "endp" points to just after the parsed name.
2257-
* "op" is NULL, "+" for "+=", "-" for "-=", "." for ".=" or "=" for "=".
2264+
* "op" is NULL, "+" for "+=", "-" for "-=", "*" for "*=", "/" for "/=",
2265+
* "%" for "%=", "." for ".=" or "=" for "=".
22582266
*/
22592267
static void
22602268
set_var_lval(
@@ -2327,7 +2335,7 @@ set_var_lval(
23272335
{
23282336
typval_T tv;
23292337

2330-
/* handle +=, -= and .= */
2338+
// handle +=, -=, *=, /=, %= and .=
23312339
di = NULL;
23322340
if (get_var_tv(lp->ll_name, (int)STRLEN(lp->ll_name),
23332341
&tv, &di, TRUE, FALSE) == OK)
@@ -2448,7 +2456,8 @@ set_var_lval(
24482456
}
24492457

24502458
/*
2451-
* Handle "tv1 += tv2", "tv1 -= tv2" and "tv1 .= tv2"
2459+
* Handle "tv1 += tv2", "tv1 -= tv2", "tv1 *= tv2", "tv1 /= tv2", "tv1 %= tv2"
2460+
* and "tv1 .= tv2"
24522461
* Returns OK or FAIL.
24532462
*/
24542463
static int
@@ -2490,7 +2499,7 @@ tv_op(typval_T *tv1, typval_T *tv2, char_u *op)
24902499
case VAR_LIST:
24912500
if (*op != '+' || tv2->v_type != VAR_LIST)
24922501
break;
2493-
/* List += List */
2502+
// List += List
24942503
if (tv1->vval.v_list != NULL && tv2->vval.v_list != NULL)
24952504
list_extend(tv1->vval.v_list, tv2->vval.v_list, NULL);
24962505
return OK;
@@ -2499,30 +2508,39 @@ tv_op(typval_T *tv1, typval_T *tv2, char_u *op)
24992508
case VAR_STRING:
25002509
if (tv2->v_type == VAR_LIST)
25012510
break;
2502-
if (*op == '+' || *op == '-')
2511+
if (vim_strchr((char_u *)"+-*/%", *op) != NULL)
25032512
{
2504-
/* nr += nr or nr -= nr*/
2513+
// nr += nr , nr -= nr , nr *=nr , nr /= nr , nr %= nr
25052514
n = tv_get_number(tv1);
25062515
#ifdef FEAT_FLOAT
25072516
if (tv2->v_type == VAR_FLOAT)
25082517
{
25092518
float_T f = n;
25102519

2511-
if (*op == '+')
2512-
f += tv2->vval.v_float;
2513-
else
2514-
f -= tv2->vval.v_float;
2520+
if (*op == '%')
2521+
break;
2522+
switch (*op)
2523+
{
2524+
case '+': f += tv2->vval.v_float; break;
2525+
case '-': f -= tv2->vval.v_float; break;
2526+
case '*': f *= tv2->vval.v_float; break;
2527+
case '/': f /= tv2->vval.v_float; break;
2528+
}
25152529
clear_tv(tv1);
25162530
tv1->v_type = VAR_FLOAT;
25172531
tv1->vval.v_float = f;
25182532
}
25192533
else
25202534
#endif
25212535
{
2522-
if (*op == '+')
2523-
n += tv_get_number(tv2);
2524-
else
2525-
n -= tv_get_number(tv2);
2536+
switch (*op)
2537+
{
2538+
case '+': n += tv_get_number(tv2); break;
2539+
case '-': n -= tv_get_number(tv2); break;
2540+
case '*': n *= tv_get_number(tv2); break;
2541+
case '/': n /= tv_get_number(tv2); break;
2542+
case '%': n %= tv_get_number(tv2); break;
2543+
}
25262544
clear_tv(tv1);
25272545
tv1->v_type = VAR_NUMBER;
25282546
tv1->vval.v_number = n;
@@ -2533,7 +2551,7 @@ tv_op(typval_T *tv1, typval_T *tv2, char_u *op)
25332551
if (tv2->v_type == VAR_FLOAT)
25342552
break;
25352553

2536-
/* str .= str */
2554+
// str .= str
25372555
s = tv_get_string(tv1);
25382556
s = concat_str(s, tv_get_string_buf(tv2, numbuf));
25392557
clear_tv(tv1);
@@ -2547,18 +2565,22 @@ tv_op(typval_T *tv1, typval_T *tv2, char_u *op)
25472565
{
25482566
float_T f;
25492567

2550-
if (*op == '.' || (tv2->v_type != VAR_FLOAT
2568+
if (*op == '%' || *op == '.'
2569+
|| (tv2->v_type != VAR_FLOAT
25512570
&& tv2->v_type != VAR_NUMBER
25522571
&& tv2->v_type != VAR_STRING))
25532572
break;
25542573
if (tv2->v_type == VAR_FLOAT)
25552574
f = tv2->vval.v_float;
25562575
else
25572576
f = tv_get_number(tv2);
2558-
if (*op == '+')
2559-
tv1->vval.v_float += f;
2560-
else
2561-
tv1->vval.v_float -= f;
2577+
switch (*op)
2578+
{
2579+
case '+': tv1->vval.v_float += f; break;
2580+
case '-': tv1->vval.v_float -= f; break;
2581+
case '*': tv1->vval.v_float *= f; break;
2582+
case '/': tv1->vval.v_float /= f; break;
2583+
}
25622584
}
25632585
#endif
25642586
return OK;

src/testdir/test_vimscript.vim

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1441,6 +1441,84 @@ func Test_script_local_func()
14411441
enew! | close
14421442
endfunc
14431443

1444+
func Test_compound_assignment_operators()
1445+
" Test for number
1446+
let x = 1
1447+
let x += 10
1448+
call assert_equal(11, x)
1449+
let x -= 5
1450+
call assert_equal(6, x)
1451+
let x *= 4
1452+
call assert_equal(24, x)
1453+
let x /= 3
1454+
call assert_equal(8, x)
1455+
let x %= 3
1456+
call assert_equal(2, x)
1457+
let x .= 'n'
1458+
call assert_equal('2n', x)
1459+
1460+
" Test for string
1461+
let x = 'str'
1462+
let x .= 'ing'
1463+
call assert_equal('string', x)
1464+
let x += 1
1465+
call assert_equal(1, x)
1466+
let x -= 1.5
1467+
call assert_equal(-0.5, x)
1468+
1469+
if has('float')
1470+
" Test for float
1471+
let x = 0.5
1472+
let x += 4.5
1473+
call assert_equal(5.0, x)
1474+
let x -= 1.5
1475+
call assert_equal(3.5, x)
1476+
let x *= 3.0
1477+
call assert_equal(10.5, x)
1478+
let x /= 2.5
1479+
call assert_equal(4.2, x)
1480+
call assert_fails('let x %= 0.5', 'E734')
1481+
call assert_fails('let x .= "f"', 'E734')
1482+
endif
1483+
1484+
" Test for environment variable
1485+
let $FOO = 1
1486+
call assert_fails('let $FOO += 1', 'E734')
1487+
call assert_fails('let $FOO -= 1', 'E734')
1488+
call assert_fails('let $FOO *= 1', 'E734')
1489+
call assert_fails('let $FOO /= 1', 'E734')
1490+
call assert_fails('let $FOO %= 1', 'E734')
1491+
let $FOO .= 's'
1492+
call assert_equal('1s', $FOO)
1493+
unlet $FOO
1494+
1495+
" Test for option variable (type: number)
1496+
let &scrolljump = 1
1497+
let &scrolljump += 5
1498+
call assert_equal(6, &scrolljump)
1499+
let &scrolljump -= 2
1500+
call assert_equal(4, &scrolljump)
1501+
let &scrolljump *= 3
1502+
call assert_equal(12, &scrolljump)
1503+
let &scrolljump /= 2
1504+
call assert_equal(6, &scrolljump)
1505+
let &scrolljump %= 5
1506+
call assert_equal(1, &scrolljump)
1507+
call assert_fails('let &scrolljump .= "j"', 'E734')
1508+
set scrolljump&vim
1509+
1510+
" Test for register
1511+
let @/ = 1
1512+
call assert_fails('let @/ += 1', 'E734')
1513+
call assert_fails('let @/ -= 1', 'E734')
1514+
call assert_fails('let @/ *= 1', 'E734')
1515+
call assert_fails('let @/ /= 1', 'E734')
1516+
call assert_fails('let @/ %= 1', 'E734')
1517+
let @/ .= 's'
1518+
call assert_equal('1s', @/)
1519+
let @/ = ''
1520+
endfunc
1521+
14441522
"-------------------------------------------------------------------------------
14451523
" Modelines {{{1
14461524
" vim: ts=8 sw=4 tw=80 fdm=marker

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -783,6 +783,8 @@ static char *(features[]) =
783783

784784
static int included_patches[] =
785785
{ /* Add new patch number below this line */
786+
/**/
787+
902,
786788
/**/
787789
901,
788790
/**/

0 commit comments

Comments
 (0)