comparison src/eval.c @ 15790:05d836c8f1c4 v8.1.0902

patch 8.1.0902: incomplete set of assignment operators commit https://github.com/vim/vim/commit/ff697e6cef8ced7717a21fd525ab3200b2f1724f Author: Bram Moolenaar <Bram@vim.org> Date: Tue Feb 12 22:28:33 2019 +0100 patch 8.1.0902: incomplete set of assignment operators Problem: Incomplete set of assignment operators. Solution: Add /=, *= and %=. (Ozaki Kiichi, closes https://github.com/vim/vim/issues/3931)
author Bram Moolenaar <Bram@vim.org>
date Tue, 12 Feb 2019 22:30:08 +0100
parents 703220741ed1
children 7fad90423bd2
comparison
equal deleted inserted replaced
15789:9b7a86acea77 15790:05d836c8f1c4
1195 * ":let" list all variable values 1195 * ":let" list all variable values
1196 * ":let var1 var2" list variable values 1196 * ":let var1 var2" list variable values
1197 * ":let var = expr" assignment command. 1197 * ":let var = expr" assignment command.
1198 * ":let var += expr" assignment command. 1198 * ":let var += expr" assignment command.
1199 * ":let var -= expr" assignment command. 1199 * ":let var -= expr" assignment command.
1200 * ":let var *= expr" assignment command.
1201 * ":let var /= expr" assignment command.
1202 * ":let var %= expr" assignment command.
1200 * ":let var .= expr" assignment command. 1203 * ":let var .= expr" assignment command.
1201 * ":let [var1, var2] = expr" unpack list. 1204 * ":let [var1, var2] = expr" unpack list.
1202 */ 1205 */
1203 void 1206 void
1204 ex_let(exarg_T *eap) 1207 ex_let(exarg_T *eap)
1214 int first = TRUE; 1217 int first = TRUE;
1215 1218
1216 argend = skip_var_list(arg, &var_count, &semicolon); 1219 argend = skip_var_list(arg, &var_count, &semicolon);
1217 if (argend == NULL) 1220 if (argend == NULL)
1218 return; 1221 return;
1219 if (argend > arg && argend[-1] == '.') /* for var.='str' */ 1222 if (argend > arg && argend[-1] == '.') // for var.='str'
1220 --argend; 1223 --argend;
1221 expr = skipwhite(argend); 1224 expr = skipwhite(argend);
1222 if (*expr != '=' && !(vim_strchr((char_u *)"+-.", *expr) != NULL 1225 if (*expr != '=' && !(vim_strchr((char_u *)"+-*/%.", *expr) != NULL
1223 && expr[1] == '=')) 1226 && expr[1] == '='))
1224 { 1227 {
1225 /* 1228 /*
1226 * ":let" without "=": list variables 1229 * ":let" without "=": list variables
1227 */ 1230 */
1247 { 1250 {
1248 op[0] = '='; 1251 op[0] = '=';
1249 op[1] = NUL; 1252 op[1] = NUL;
1250 if (*expr != '=') 1253 if (*expr != '=')
1251 { 1254 {
1252 if (vim_strchr((char_u *)"+-.", *expr) != NULL) 1255 if (vim_strchr((char_u *)"+-*/%.", *expr) != NULL)
1253 op[0] = *expr; /* +=, -= or .= */ 1256 op[0] = *expr; // +=, -=, *=, /=, %= or .=
1254 expr = skipwhite(expr + 2); 1257 expr = skipwhite(expr + 2);
1255 } 1258 }
1256 else 1259 else
1257 expr = skipwhite(expr + 1); 1260 expr = skipwhite(expr + 1);
1258 1261
1669 len = get_env_len(&arg); 1672 len = get_env_len(&arg);
1670 if (len == 0) 1673 if (len == 0)
1671 semsg(_(e_invarg2), name - 1); 1674 semsg(_(e_invarg2), name - 1);
1672 else 1675 else
1673 { 1676 {
1674 if (op != NULL && (*op == '+' || *op == '-')) 1677 if (op != NULL && vim_strchr((char_u *)"+-*/%", *op) != NULL)
1675 semsg(_(e_letwrong), op); 1678 semsg(_(e_letwrong), op);
1676 else if (endchars != NULL 1679 else if (endchars != NULL
1677 && vim_strchr(endchars, *skipwhite(arg)) == NULL) 1680 && vim_strchr(endchars, *skipwhite(arg)) == NULL)
1678 emsg(_(e_letunexp)); 1681 emsg(_(e_letunexp));
1679 else if (!check_secure()) 1682 else if (!check_secure())
1742 &stringval, opt_flags); 1745 &stringval, opt_flags);
1743 if ((opt_type == 1 && *op == '.') 1746 if ((opt_type == 1 && *op == '.')
1744 || (opt_type == 0 && *op != '.')) 1747 || (opt_type == 0 && *op != '.'))
1745 { 1748 {
1746 semsg(_(e_letwrong), op); 1749 semsg(_(e_letwrong), op);
1747 s = NULL; /* don't set the value */ 1750 s = NULL; // don't set the value
1748 } 1751 }
1749 else 1752 else
1750 { 1753 {
1751 if (opt_type == 1) /* number */ 1754 if (opt_type == 1) // number
1752 { 1755 {
1753 if (*op == '+') 1756 switch (*op)
1754 n = numval + n; 1757 {
1755 else 1758 case '+': n = numval + n; break;
1756 n = numval - n; 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 }
1757 } 1764 }
1758 else if (opt_type == 0 && stringval != NULL) /* string */ 1765 else if (opt_type == 0 && stringval != NULL) // string
1759 { 1766 {
1760 s = concat_str(stringval, s); 1767 s = concat_str(stringval, s);
1761 vim_free(stringval); 1768 vim_free(stringval);
1762 stringval = s; 1769 stringval = s;
1763 } 1770 }
1777 * ":let @r = expr": Set register contents. 1784 * ":let @r = expr": Set register contents.
1778 */ 1785 */
1779 else if (*arg == '@') 1786 else if (*arg == '@')
1780 { 1787 {
1781 ++arg; 1788 ++arg;
1782 if (op != NULL && (*op == '+' || *op == '-')) 1789 if (op != NULL && vim_strchr((char_u *)"+-*/%", *op) != NULL)
1783 semsg(_(e_letwrong), op); 1790 semsg(_(e_letwrong), op);
1784 else if (endchars != NULL 1791 else if (endchars != NULL
1785 && vim_strchr(endchars, *skipwhite(arg + 1)) == NULL) 1792 && vim_strchr(endchars, *skipwhite(arg + 1)) == NULL)
1786 emsg(_(e_letunexp)); 1793 emsg(_(e_letunexp));
1787 else 1794 else
2252 } 2259 }
2253 2260
2254 /* 2261 /*
2255 * Set a variable that was parsed by get_lval() to "rettv". 2262 * Set a variable that was parsed by get_lval() to "rettv".
2256 * "endp" points to just after the parsed name. 2263 * "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 "=".
2258 */ 2266 */
2259 static void 2267 static void
2260 set_var_lval( 2268 set_var_lval(
2261 lval_T *lp, 2269 lval_T *lp,
2262 char_u *endp, 2270 char_u *endp,
2325 } 2333 }
2326 else if (op != NULL && *op != '=') 2334 else if (op != NULL && *op != '=')
2327 { 2335 {
2328 typval_T tv; 2336 typval_T tv;
2329 2337
2330 /* handle +=, -= and .= */ 2338 // handle +=, -=, *=, /=, %= and .=
2331 di = NULL; 2339 di = NULL;
2332 if (get_var_tv(lp->ll_name, (int)STRLEN(lp->ll_name), 2340 if (get_var_tv(lp->ll_name, (int)STRLEN(lp->ll_name),
2333 &tv, &di, TRUE, FALSE) == OK) 2341 &tv, &di, TRUE, FALSE) == OK)
2334 { 2342 {
2335 if ((di == NULL 2343 if ((di == NULL
2446 } 2454 }
2447 } 2455 }
2448 } 2456 }
2449 2457
2450 /* 2458 /*
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"
2452 * Returns OK or FAIL. 2461 * Returns OK or FAIL.
2453 */ 2462 */
2454 static int 2463 static int
2455 tv_op(typval_T *tv1, typval_T *tv2, char_u *op) 2464 tv_op(typval_T *tv1, typval_T *tv2, char_u *op)
2456 { 2465 {
2488 return OK; 2497 return OK;
2489 2498
2490 case VAR_LIST: 2499 case VAR_LIST:
2491 if (*op != '+' || tv2->v_type != VAR_LIST) 2500 if (*op != '+' || tv2->v_type != VAR_LIST)
2492 break; 2501 break;
2493 /* List += List */ 2502 // List += List
2494 if (tv1->vval.v_list != NULL && tv2->vval.v_list != NULL) 2503 if (tv1->vval.v_list != NULL && tv2->vval.v_list != NULL)
2495 list_extend(tv1->vval.v_list, tv2->vval.v_list, NULL); 2504 list_extend(tv1->vval.v_list, tv2->vval.v_list, NULL);
2496 return OK; 2505 return OK;
2497 2506
2498 case VAR_NUMBER: 2507 case VAR_NUMBER:
2499 case VAR_STRING: 2508 case VAR_STRING:
2500 if (tv2->v_type == VAR_LIST) 2509 if (tv2->v_type == VAR_LIST)
2501 break; 2510 break;
2502 if (*op == '+' || *op == '-') 2511 if (vim_strchr((char_u *)"+-*/%", *op) != NULL)
2503 { 2512 {
2504 /* nr += nr or nr -= nr*/ 2513 // nr += nr , nr -= nr , nr *=nr , nr /= nr , nr %= nr
2505 n = tv_get_number(tv1); 2514 n = tv_get_number(tv1);
2506 #ifdef FEAT_FLOAT 2515 #ifdef FEAT_FLOAT
2507 if (tv2->v_type == VAR_FLOAT) 2516 if (tv2->v_type == VAR_FLOAT)
2508 { 2517 {
2509 float_T f = n; 2518 float_T f = n;
2510 2519
2511 if (*op == '+') 2520 if (*op == '%')
2512 f += tv2->vval.v_float; 2521 break;
2513 else 2522 switch (*op)
2514 f -= tv2->vval.v_float; 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 }
2515 clear_tv(tv1); 2529 clear_tv(tv1);
2516 tv1->v_type = VAR_FLOAT; 2530 tv1->v_type = VAR_FLOAT;
2517 tv1->vval.v_float = f; 2531 tv1->vval.v_float = f;
2518 } 2532 }
2519 else 2533 else
2520 #endif 2534 #endif
2521 { 2535 {
2522 if (*op == '+') 2536 switch (*op)
2523 n += tv_get_number(tv2); 2537 {
2524 else 2538 case '+': n += tv_get_number(tv2); break;
2525 n -= tv_get_number(tv2); 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 }
2526 clear_tv(tv1); 2544 clear_tv(tv1);
2527 tv1->v_type = VAR_NUMBER; 2545 tv1->v_type = VAR_NUMBER;
2528 tv1->vval.v_number = n; 2546 tv1->vval.v_number = n;
2529 } 2547 }
2530 } 2548 }
2531 else 2549 else
2532 { 2550 {
2533 if (tv2->v_type == VAR_FLOAT) 2551 if (tv2->v_type == VAR_FLOAT)
2534 break; 2552 break;
2535 2553
2536 /* str .= str */ 2554 // str .= str
2537 s = tv_get_string(tv1); 2555 s = tv_get_string(tv1);
2538 s = concat_str(s, tv_get_string_buf(tv2, numbuf)); 2556 s = concat_str(s, tv_get_string_buf(tv2, numbuf));
2539 clear_tv(tv1); 2557 clear_tv(tv1);
2540 tv1->v_type = VAR_STRING; 2558 tv1->v_type = VAR_STRING;
2541 tv1->vval.v_string = s; 2559 tv1->vval.v_string = s;
2545 case VAR_FLOAT: 2563 case VAR_FLOAT:
2546 #ifdef FEAT_FLOAT 2564 #ifdef FEAT_FLOAT
2547 { 2565 {
2548 float_T f; 2566 float_T f;
2549 2567
2550 if (*op == '.' || (tv2->v_type != VAR_FLOAT 2568 if (*op == '%' || *op == '.'
2569 || (tv2->v_type != VAR_FLOAT
2551 && tv2->v_type != VAR_NUMBER 2570 && tv2->v_type != VAR_NUMBER
2552 && tv2->v_type != VAR_STRING)) 2571 && tv2->v_type != VAR_STRING))
2553 break; 2572 break;
2554 if (tv2->v_type == VAR_FLOAT) 2573 if (tv2->v_type == VAR_FLOAT)
2555 f = tv2->vval.v_float; 2574 f = tv2->vval.v_float;
2556 else 2575 else
2557 f = tv_get_number(tv2); 2576 f = tv_get_number(tv2);
2558 if (*op == '+') 2577 switch (*op)
2559 tv1->vval.v_float += f; 2578 {
2560 else 2579 case '+': tv1->vval.v_float += f; break;
2561 tv1->vval.v_float -= f; 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 }
2562 } 2584 }
2563 #endif 2585 #endif
2564 return OK; 2586 return OK;
2565 } 2587 }
2566 } 2588 }