executor.c (5395B)
1 #include <inttypes.h> 2 #include <stdlib.h> 3 4 #include "nvim/errors.h" 5 #include "nvim/eval.h" 6 #include "nvim/eval/executor.h" 7 #include "nvim/eval/typval.h" 8 #include "nvim/eval/typval_defs.h" 9 #include "nvim/garray.h" 10 #include "nvim/gettext_defs.h" 11 #include "nvim/message.h" 12 #include "nvim/strings.h" 13 #include "nvim/types_defs.h" 14 #include "nvim/vim_defs.h" 15 16 #include "eval/executor.c.generated.h" 17 18 /// Handle "blob1 += blob2". 19 /// Returns OK or FAIL. 20 static int tv_op_blob(typval_T *tv1, const typval_T *tv2, const char *op) 21 FUNC_ATTR_NONNULL_ALL 22 { 23 if (*op != '+' || tv2->v_type != VAR_BLOB) { 24 return FAIL; 25 } 26 27 // Blob += Blob 28 if (tv2->vval.v_blob == NULL) { 29 return OK; 30 } 31 32 if (tv1->vval.v_blob == NULL) { 33 tv1->vval.v_blob = tv2->vval.v_blob; 34 tv1->vval.v_blob->bv_refcount++; 35 return OK; 36 } 37 38 blob_T *const b1 = tv1->vval.v_blob; 39 blob_T *const b2 = tv2->vval.v_blob; 40 const int len = tv_blob_len(b2); 41 42 for (int i = 0; i < len; i++) { 43 ga_append(&b1->bv_ga, tv_blob_get(b2, i)); 44 } 45 46 return OK; 47 } 48 49 /// Handle "list1 += list2". 50 /// Returns OK or FAIL. 51 static int tv_op_list(typval_T *tv1, const typval_T *tv2, const char *op) 52 FUNC_ATTR_NONNULL_ALL 53 { 54 if (*op != '+' || tv2->v_type != VAR_LIST) { 55 return FAIL; 56 } 57 58 // List += List 59 if (tv2->vval.v_list == NULL) { 60 return OK; 61 } 62 63 if (tv1->vval.v_list == NULL) { 64 tv1->vval.v_list = tv2->vval.v_list; 65 tv_list_ref(tv1->vval.v_list); 66 } else { 67 tv_list_extend(tv1->vval.v_list, tv2->vval.v_list, NULL); 68 } 69 70 return OK; 71 } 72 73 /// Handle number operations: 74 /// nr += nr , nr -= nr , nr *=nr , nr /= nr , nr %= nr 75 /// 76 /// Returns OK or FAIL. 77 static int tv_op_number(typval_T *tv1, const typval_T *tv2, const char *op) 78 FUNC_ATTR_NONNULL_ALL 79 { 80 varnumber_T n = tv_get_number(tv1); 81 if (tv2->v_type == VAR_FLOAT) { 82 float_T f = (float_T)n; 83 if (*op == '%') { 84 return FAIL; 85 } 86 switch (*op) { 87 case '+': 88 f += tv2->vval.v_float; break; 89 case '-': 90 f -= tv2->vval.v_float; break; 91 case '*': 92 f *= tv2->vval.v_float; break; 93 case '/': 94 f /= tv2->vval.v_float; break; 95 } 96 tv_clear(tv1); 97 tv1->v_type = VAR_FLOAT; 98 tv1->vval.v_float = f; 99 } else { 100 switch (*op) { 101 case '+': 102 n += tv_get_number(tv2); break; 103 case '-': 104 n -= tv_get_number(tv2); break; 105 case '*': 106 n *= tv_get_number(tv2); break; 107 case '/': 108 n = num_divide(n, tv_get_number(tv2)); break; 109 case '%': 110 n = num_modulus(n, tv_get_number(tv2)); break; 111 } 112 tv_clear(tv1); 113 tv1->v_type = VAR_NUMBER; 114 tv1->vval.v_number = n; 115 } 116 117 return OK; 118 } 119 120 /// Handle "str1 .= str2" 121 /// Returns OK or FAIL. 122 static int tv_op_string(typval_T *tv1, const typval_T *tv2, const char *op) 123 FUNC_ATTR_NONNULL_ALL 124 { 125 if (tv2->v_type == VAR_FLOAT) { 126 return FAIL; 127 } 128 129 // str .= str 130 const char *tvs = tv_get_string(tv1); 131 char numbuf[NUMBUFLEN]; 132 char *const s = concat_str(tvs, tv_get_string_buf(tv2, numbuf)); 133 tv_clear(tv1); 134 tv1->v_type = VAR_STRING; 135 tv1->vval.v_string = s; 136 137 return OK; 138 } 139 140 /// Handle "tv1 += tv2", "tv1 -= tv2", "tv1 *= tv2", "tv1 /= tv2", "tv1 %= tv2" 141 /// and "tv1 .= tv2" 142 /// Returns OK or FAIL. 143 static int tv_op_nr_or_string(typval_T *tv1, const typval_T *tv2, const char *op) 144 FUNC_ATTR_NONNULL_ALL 145 { 146 if (tv2->v_type == VAR_LIST) { 147 return FAIL; 148 } 149 150 if (vim_strchr("+-*/%", (uint8_t)(*op)) != NULL) { 151 return tv_op_number(tv1, tv2, op); 152 } 153 154 return tv_op_string(tv1, tv2, op); 155 } 156 157 /// Handle "f1 += f2", "f1 -= f2", "f1 *= f2", "f1 /= f2". 158 /// Returns OK or FAIL. 159 static int tv_op_float(typval_T *tv1, const typval_T *tv2, const char *op) 160 FUNC_ATTR_NONNULL_ALL 161 { 162 if (*op == '%' || *op == '.' 163 || (tv2->v_type != VAR_FLOAT 164 && tv2->v_type != VAR_NUMBER 165 && tv2->v_type != VAR_STRING)) { 166 return FAIL; 167 } 168 169 const float_T f = (tv2->v_type == VAR_FLOAT 170 ? tv2->vval.v_float 171 : (float_T)tv_get_number(tv2)); 172 switch (*op) { 173 case '+': 174 tv1->vval.v_float += f; break; 175 case '-': 176 tv1->vval.v_float -= f; break; 177 case '*': 178 tv1->vval.v_float *= f; break; 179 case '/': 180 tv1->vval.v_float /= f; break; 181 } 182 183 return OK; 184 } 185 186 /// Handle tv1 += tv2, -=, *=, /=, %=, .= 187 /// 188 /// @param[in,out] tv1 First operand, modified typval. 189 /// @param[in] tv2 Second operand. 190 /// @param[in] op Used operator. 191 /// 192 /// @return OK or FAIL. 193 int eexe_mod_op(typval_T *const tv1, const typval_T *const tv2, const char *const op) 194 FUNC_ATTR_NONNULL_ALL 195 { 196 // Can't do anything with a Funcref or Dict on the right. 197 // v:true and friends only work with "..=". 198 if (tv2->v_type == VAR_FUNC || tv2->v_type == VAR_DICT 199 || ((tv2->v_type == VAR_BOOL || tv2->v_type == VAR_SPECIAL) && *op == '.')) { 200 semsg(_(e_letwrong), op); 201 return FAIL; 202 } 203 204 int retval = FAIL; 205 206 switch (tv1->v_type) { 207 case VAR_DICT: 208 case VAR_FUNC: 209 case VAR_PARTIAL: 210 case VAR_BOOL: 211 case VAR_SPECIAL: 212 break; 213 case VAR_BLOB: 214 retval = tv_op_blob(tv1, tv2, op); 215 break; 216 case VAR_LIST: 217 retval = tv_op_list(tv1, tv2, op); 218 break; 219 case VAR_NUMBER: 220 case VAR_STRING: 221 retval = tv_op_nr_or_string(tv1, tv2, op); 222 break; 223 case VAR_FLOAT: 224 retval = tv_op_float(tv1, tv2, op); 225 break; 226 case VAR_UNKNOWN: 227 abort(); 228 } 229 230 if (retval != OK) { 231 semsg(_(e_letwrong), op); 232 } 233 234 return retval; 235 }