]> granicus.if.org Git - vim/commitdiff
patch 8.1.0902: incomplete set of assignment operators v8.1.0902
authorBram Moolenaar <Bram@vim.org>
Tue, 12 Feb 2019 21:28:33 +0000 (22:28 +0100)
committerBram Moolenaar <Bram@vim.org>
Tue, 12 Feb 2019 21:28:33 +0000 (22:28 +0100)
Problem:    Incomplete set of assignment operators.
Solution:   Add /=, *= and %=. (Ozaki Kiichi, closes #3931)

runtime/doc/eval.txt
src/eval.c
src/testdir/test_vimscript.vim
src/version.c

index c2150e5b90b801faaa0f48c3157211240e2cf309..535517d21d1a8553fe759dcff2b139749bd85701 100644 (file)
@@ -10836,9 +10836,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.
index 46d24ef78814c8294bad1e880dbba266356ffef0..56a26b1aeab4fad6f254153e66317b0bb9f916f3 100644 (file)
@@ -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;
index 9de0a620c1bd8cff0f6554aba697a835a58eeac5..41a1dda7db122095ed0e776e178b112b0cfc23b8 100644 (file)
@@ -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
index 998f259bad16f91c548dcf416e89c8f600d00b63..cadd46e4f4b7f12ed2cc210baf74dc53f8e3000b 100644 (file)
@@ -783,6 +783,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    902,
 /**/
     901,
 /**/