Mercurial > vim
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 } |