Patch 8.1.0902
Problem: Incomplete set of assignment operators.
Solution: Add /=, *= and %=. (Ozaki Kiichi, closes #3931)
Files: runtime/doc/eval.txt src/eval.c src/testdir/test_vimscript.vim
*** ../vim-8.1.0901/runtime/doc/eval.txt 2019-02-10 23:18:49.034187552
+0100
--- runtime/doc/eval.txt 2019-02-12 22:21:20.627600700 +0100
***************
*** 10774,10782 ****
When the selected range of items is partly past the
end of the list, items will be added.
! *: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}".
These fail if {var} was not set yet and when the type
of {var} and {expr1} don't fit the operator.
--- 10836,10848 ----
When the selected range of items is partly past the
end of the list, items will be added.
! *: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.
*** ../vim-8.1.0901/src/eval.c 2019-02-12 20:48:06.646810620 +0100
--- src/eval.c 2019-02-12 22:25:01.466416885 +0100
***************
*** 1197,1202 ****
--- 1197,1205 ----
* ":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,1225 ****
argend = skip_var_list(arg, &var_count, &semicolon);
if (argend == NULL)
return;
! if (argend > arg && argend[-1] == '.') /* for var.='str' */
--argend;
expr = skipwhite(argend);
! if (*expr != '=' && !(vim_strchr((char_u *)"+-.", *expr) != NULL
&& expr[1] == '='))
{
/*
--- 1219,1228 ----
argend = skip_var_list(arg, &var_count, &semicolon);
if (argend == NULL)
return;
! if (argend > arg && argend[-1] == '.') // for var.='str'
--argend;
expr = skipwhite(argend);
! if (*expr != '=' && !(vim_strchr((char_u *)"+-*/%.", *expr) != NULL
&& expr[1] == '='))
{
/*
***************
*** 1249,1256 ****
op[1] = NUL;
if (*expr != '=')
{
! if (vim_strchr((char_u *)"+-.", *expr) != NULL)
! op[0] = *expr; /* +=, -= or .= */
expr = skipwhite(expr + 2);
}
else
--- 1252,1259 ----
op[1] = NUL;
if (*expr != '=')
{
! if (vim_strchr((char_u *)"+-*/%.", *expr) != NULL)
! op[0] = *expr; // +=, -=, *=, /=, %= or .=
expr = skipwhite(expr + 2);
}
else
***************
*** 1671,1677 ****
semsg(_(e_invarg2), name - 1);
else
{
! if (op != NULL && (*op == '+' || *op == '-'))
semsg(_(e_letwrong), op);
else if (endchars != NULL
&& vim_strchr(endchars, *skipwhite(arg)) == NULL)
--- 1674,1680 ----
semsg(_(e_invarg2), name - 1);
else
{
! if (op != NULL && vim_strchr((char_u *)"+-*/%", *op) != NULL)
semsg(_(e_letwrong), op);
else if (endchars != NULL
&& vim_strchr(endchars, *skipwhite(arg)) == NULL)
***************
*** 1744,1761 ****
|| (opt_type == 0 && *op != '.'))
{
semsg(_(e_letwrong), op);
! s = NULL; /* don't set the value */
}
else
{
! if (opt_type == 1) /* number */
{
! if (*op == '+')
! n = numval + n;
! else
! n = numval - n;
}
! else if (opt_type == 0 && stringval != NULL) /* string */
{
s = concat_str(stringval, s);
vim_free(stringval);
--- 1747,1768 ----
|| (opt_type == 0 && *op != '.'))
{
semsg(_(e_letwrong), op);
! s = NULL; // don't set the value
}
else
{
! if (opt_type == 1) // number
{
! 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
{
s = concat_str(stringval, s);
vim_free(stringval);
***************
*** 1779,1785 ****
else if (*arg == '@')
{
++arg;
! if (op != NULL && (*op == '+' || *op == '-'))
semsg(_(e_letwrong), op);
else if (endchars != NULL
&& vim_strchr(endchars, *skipwhite(arg + 1)) == NULL)
--- 1786,1792 ----
else if (*arg == '@')
{
++arg;
! 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,2260 ****
/*
* 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 "=".
*/
static void
set_var_lval(
--- 2261,2268 ----
/*
* 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 "*=", "/" for "/=",
! * "%" for "%=", "." for ".=" or "=" for "=".
*/
static void
set_var_lval(
***************
*** 2327,2333 ****
{
typval_T tv;
! /* handle +=, -= and .= */
di = NULL;
if (get_var_tv(lp->ll_name, (int)STRLEN(lp->ll_name),
&tv, &di, TRUE, FALSE) == OK)
--- 2335,2341 ----
{
typval_T tv;
! // handle +=, -=, *=, /=, %= and .=
di = NULL;
if (get_var_tv(lp->ll_name, (int)STRLEN(lp->ll_name),
&tv, &di, TRUE, FALSE) == OK)
***************
*** 2448,2454 ****
}
/*
! * Handle "tv1 += tv2", "tv1 -= tv2" and "tv1 .= tv2"
* Returns OK or FAIL.
*/
static int
--- 2456,2463 ----
}
/*
! * Handle "tv1 += tv2", "tv1 -= tv2", "tv1 *= tv2", "tv1 /= tv2", "tv1 %= tv2"
! * and "tv1 .= tv2"
* Returns OK or FAIL.
*/
static int
***************
*** 2490,2496 ****
case VAR_LIST:
if (*op != '+' || tv2->v_type != VAR_LIST)
break;
! /* 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,2505 ----
case VAR_LIST:
if (*op != '+' || tv2->v_type != VAR_LIST)
break;
! // 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,2517 ****
case VAR_STRING:
if (tv2->v_type == VAR_LIST)
break;
! if (*op == '+' || *op == '-')
{
! /* nr += nr or 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;
clear_tv(tv1);
tv1->v_type = VAR_FLOAT;
tv1->vval.v_float = f;
--- 2508,2531 ----
case VAR_STRING:
if (tv2->v_type == VAR_LIST)
break;
! if (vim_strchr((char_u *)"+-*/%", *op) != NULL)
{
! // 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 == '%')
! 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,2528 ****
else
#endif
{
! if (*op == '+')
! n += tv_get_number(tv2);
! else
! n -= tv_get_number(tv2);
clear_tv(tv1);
tv1->v_type = VAR_NUMBER;
tv1->vval.v_number = n;
--- 2533,2546 ----
else
#endif
{
! 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,2539 ****
if (tv2->v_type == VAR_FLOAT)
break;
! /* str .= str */
s = tv_get_string(tv1);
s = concat_str(s, tv_get_string_buf(tv2, numbuf));
clear_tv(tv1);
--- 2551,2557 ----
if (tv2->v_type == VAR_FLOAT)
break;
! // str .= str
s = tv_get_string(tv1);
s = concat_str(s, tv_get_string_buf(tv2, numbuf));
clear_tv(tv1);
***************
*** 2547,2553 ****
{
float_T f;
! if (*op == '.' || (tv2->v_type != VAR_FLOAT
&& tv2->v_type != VAR_NUMBER
&& tv2->v_type != VAR_STRING))
break;
--- 2565,2572 ----
{
float_T f;
! if (*op == '%' || *op == '.'
! || (tv2->v_type != VAR_FLOAT
&& tv2->v_type != VAR_NUMBER
&& tv2->v_type != VAR_STRING))
break;
***************
*** 2555,2564 ****
f = tv2->vval.v_float;
else
f = tv_get_number(tv2);
! if (*op == '+')
! tv1->vval.v_float += f;
! else
! tv1->vval.v_float -= f;
}
#endif
return OK;
--- 2574,2586 ----
f = tv2->vval.v_float;
else
f = tv_get_number(tv2);
! 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;
*** ../vim-8.1.0901/src/testdir/test_vimscript.vim 2019-01-09
23:00:58.001176090 +0100
--- src/testdir/test_vimscript.vim 2019-02-12 22:21:20.627600700 +0100
***************
*** 1441,1446 ****
--- 1441,1524 ----
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
*** ../vim-8.1.0901/src/version.c 2019-02-12 22:15:03.073282144 +0100
--- src/version.c 2019-02-12 22:22:34.399217184 +0100
***************
*** 785,786 ****
--- 785,788 ----
{ /* Add new patch number below this line */
+ /**/
+ 902,
/**/
--
This message contains 78% recycled characters.
/// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language -- http://www.Zimbu.org ///
\\\ help me help AIDS victims -- http://ICCF-Holland.org ///
--
--
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php
---
You received this message because you are subscribed to the Google Groups
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.