1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
#include "nvim/eval/typval.h"
#include "nvim/eval/executor.h"
#include "nvim/eval.h"
#include "nvim/message.h"
#include "nvim/vim.h"
#include "nvim/globals.h"
#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "eval/executor.c.generated.h"
#endif
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, -=, .=
///
/// @param[in,out] tv1 First operand, modified typval.
/// @param[in] tv2 Second operand.
/// @param[in] op Used operator.
///
/// @return OK or FAIL.
int eexe_mod_op(typval_T *const tv1, const typval_T *const tv2,
const char *const op)
FUNC_ATTR_NONNULL_ALL
{
// Can't do anything with a Funcref, a Dict or special value on the right.
if (tv2->v_type != VAR_FUNC && tv2->v_type != VAR_DICT) {
switch (tv1->v_type) {
case VAR_DICT:
case VAR_FUNC:
case VAR_PARTIAL:
case VAR_SPECIAL: {
break;
}
case VAR_LIST: {
if (*op != '+' || tv2->v_type != VAR_LIST) {
break;
}
// List += List
if (tv1->vval.v_list != NULL && tv2->vval.v_list != NULL) {
tv_list_extend(tv1->vval.v_list, tv2->vval.v_list, NULL);
}
return OK;
}
case VAR_NUMBER:
case VAR_STRING: {
if (tv2->v_type == VAR_LIST) {
break;
}
if (*op == '+' || *op == '-') {
// nr += nr or nr -= nr
varnumber_T n = get_tv_number(tv1);
if (tv2->v_type == VAR_FLOAT) {
float_T f = n;
if (*op == '+') {
f += tv2->vval.v_float;
} else {
f -= tv2->vval.v_float;
}
tv_clear(tv1);
tv1->v_type = VAR_FLOAT;
tv1->vval.v_float = f;
} else {
if (*op == '+') {
n += get_tv_number(tv2);
} else {
n -= get_tv_number(tv2);
}
tv_clear(tv1);
tv1->v_type = VAR_NUMBER;
tv1->vval.v_number = n;
}
} else {
// str .= str
if (tv2->v_type == VAR_FLOAT) {
break;
}
char *s = (char *)get_tv_string(tv1);
char numbuf[NUMBUFLEN];
s = (char *)concat_str((char_u *)s,
get_tv_string_buf(tv2, (char_u *)numbuf));
tv_clear(tv1);
tv1->v_type = VAR_STRING;
tv1->vval.v_string = (char_u *)s;
}
return OK;
}
case VAR_FLOAT: {
if (*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
: get_tv_number(tv2));
if (*op == '+') {
tv1->vval.v_float += f;
} else {
tv1->vval.v_float -= f;
}
return OK;
}
case VAR_UNKNOWN: {
assert(false);
}
}
}
EMSG2(_(e_letwrong), op);
return FAIL;
}
|