Merge #10086 'vim-patch:8.1.{902,1114}'

This commit is contained in:
Justin M. Keyes
2019-06-02 23:32:28 +02:00
5 changed files with 208 additions and 59 deletions

View File

@@ -1442,7 +1442,11 @@ int 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 var ..= expr" assignment command.
* ":let [var1, var2] = expr" unpack list.
*/
void ex_let(exarg_T *eap)
@@ -1465,8 +1469,8 @@ void ex_let(exarg_T *eap)
argend--;
}
expr = skipwhite(argend);
if (*expr != '=' && !(vim_strchr((char_u *)"+-.", *expr) != NULL
&& expr[1] == '=')) {
if (*expr != '=' && !((vim_strchr((char_u *)"+-*/%.", *expr) != NULL
&& expr[1] == '=') || STRNCMP(expr, "..=", 3) == 0)) {
// ":let" without "=": list variables
if (*arg == '[') {
EMSG(_(e_invarg));
@@ -1488,8 +1492,11 @@ void ex_let(exarg_T *eap)
op[0] = '=';
op[1] = NUL;
if (*expr != '=') {
if (vim_strchr((char_u *)"+-.", *expr) != NULL) {
op[0] = *expr; // +=, -=, .=
if (vim_strchr((char_u *)"+-*/%.", *expr) != NULL) {
op[0] = *expr; // +=, -=, *=, /=, %= or .=
if (expr[0] == '.' && expr[1] == '.') { // ..=
expr++;
}
}
expr = skipwhite(expr + 2);
} else {
@@ -1864,7 +1871,7 @@ static char_u *ex_let_one(char_u *arg, typval_T *const tv,
if (len == 0) {
EMSG2(_(e_invarg2), name - 1);
} else {
if (op != NULL && (*op == '+' || *op == '-')) {
if (op != NULL && vim_strchr((char_u *)"+-*/%", *op) != NULL) {
EMSG2(_(e_letwrong), op);
} else if (endchars != NULL
&& vim_strchr(endchars, *skipwhite(arg)) == NULL) {
@@ -1927,10 +1934,12 @@ static char_u *ex_let_one(char_u *arg, typval_T *const tv,
s = NULL; // don't set the value
} else {
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
char *const oldstringval = stringval;
@@ -1951,7 +1960,7 @@ static char_u *ex_let_one(char_u *arg, typval_T *const tv,
// ":let @r = expr": Set register contents.
} else if (*arg == '@') {
arg++;
if (op != NULL && (*op == '+' || *op == '-')) {
if (op != NULL && vim_strchr((char_u *)"+-*/%", *op) != NULL) {
emsgf(_(e_letwrong), op);
} else if (endchars != NULL
&& vim_strchr(endchars, *skipwhite(arg + 1)) == NULL) {
@@ -2350,7 +2359,8 @@ static void 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(lval_T *lp, char_u *endp, typval_T *rettv,
int copy, const char_u *op)
@@ -2365,7 +2375,7 @@ static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv,
if (op != NULL && *op != '=') {
typval_T tv;
// handle +=, -= and .=
// handle +=, -=, *=, /=, %= and .=
di = NULL;
if (get_var_tv((const char *)lp->ll_name, (int)STRLEN(lp->ll_name),
&tv, &di, true, false) == OK) {
@@ -3783,6 +3793,7 @@ static int eval4(char_u **arg, typval_T *rettv, int evaluate)
* + number addition
* - number subtraction
* . string concatenation
* .. string concatenation
*
* "arg" must point to the first non-white of the expression.
* "arg" is advanced to the next non-white after the recognized expression.
@@ -3830,6 +3841,9 @@ static int eval5(char_u **arg, typval_T *rettv, int evaluate)
/*
* Get the second variable.
*/
if (op == '.' && *(*arg + 1) == '.') { // ..string concatenation
(*arg)++;
}
*arg = skipwhite(*arg + 1);
if (eval6(arg, &var2, evaluate, op == '.') == FAIL) {
tv_clear(rettv);

View File

@@ -16,7 +16,7 @@ static char *e_letwrong = N_("E734: Wrong variable type for %s=");
char *e_listidx = N_("E684: list index out of range: %" PRId64);
/// Hanle tv1 += tv2, -=, .=
/// Hanle tv1 += tv2, -=, *=, /=, %=, .=
///
/// @param[in,out] tv1 First operand, modified typval.
/// @param[in] tv2 Second operand.
@@ -51,25 +51,31 @@ int eexe_mod_op(typval_T *const tv1, const typval_T *const tv2,
if (tv2->v_type == VAR_LIST) {
break;
}
if (*op == '+' || *op == '-') {
// nr += nr or nr -= nr
if (vim_strchr((char_u *)"+-*/%", *op) != NULL) {
// nr += nr or nr -= nr, nr *= nr, nr /= nr, nr %= nr
varnumber_T n = tv_get_number(tv1);
if (tv2->v_type == VAR_FLOAT) {
float_T f = (float_T)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;
}
tv_clear(tv1);
tv1->v_type = VAR_FLOAT;
tv1->vval.v_float = f;
} else {
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;
}
tv_clear(tv1);
tv1->v_type = VAR_NUMBER;
@@ -92,18 +98,20 @@ int eexe_mod_op(typval_T *const tv1, const typval_T *const tv2,
return OK;
}
case VAR_FLOAT: {
if (*op == '.' || (tv2->v_type != VAR_FLOAT
&& tv2->v_type != VAR_NUMBER
&& tv2->v_type != VAR_STRING)) {
if (*op == '%' || *op == '.'
|| (tv2->v_type != VAR_FLOAT
&& tv2->v_type != VAR_NUMBER
&& tv2->v_type != VAR_STRING)) {
break;
}
const float_T f = (tv2->v_type == VAR_FLOAT
? tv2->vval.v_float
: (float_T)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;
}
return OK;
}

View File

@@ -49,3 +49,32 @@ func Test_line_continuation()
"\ and some more
call assert_equal([5, 6], array)
endfunc
func Test_string_concatenation()
call assert_equal('ab', 'a'.'b')
call assert_equal('ab', 'a' .'b')
call assert_equal('ab', 'a'. 'b')
call assert_equal('ab', 'a' . 'b')
call assert_equal('ab', 'a'..'b')
call assert_equal('ab', 'a' ..'b')
call assert_equal('ab', 'a'.. 'b')
call assert_equal('ab', 'a' .. 'b')
let a = 'a'
let b = 'b'
let a .= b
call assert_equal('ab', a)
let a = 'a'
let a.=b
call assert_equal('ab', a)
let a = 'a'
let a ..= b
call assert_equal('ab', a)
let a = 'a'
let a..=b
call assert_equal('ab', a)
endfunc

View File

@@ -1294,6 +1294,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