converter.c (11166B)
1 #include <assert.h> 2 #include <lauxlib.h> 3 #include <stdbool.h> 4 #include <stddef.h> 5 #include <stdint.h> 6 7 #include "klib/kvec.h" 8 #include "nvim/api/private/converter.h" 9 #include "nvim/api/private/defs.h" 10 #include "nvim/api/private/helpers.h" 11 #include "nvim/assert_defs.h" 12 #include "nvim/eval/decode.h" 13 #include "nvim/eval/typval.h" 14 #include "nvim/eval/typval_defs.h" 15 #include "nvim/eval/userfunc.h" 16 #include "nvim/lua/executor.h" 17 #include "nvim/memory.h" 18 #include "nvim/memory_defs.h" 19 #include "nvim/types_defs.h" 20 #include "nvim/vim_defs.h" 21 22 /// Helper structure for vim_to_object 23 typedef struct { 24 kvec_withinit_t(Object, 2) stack; ///< Object stack. 25 Arena *arena; ///< arena where objects will be allocated 26 bool reuse_strdata; 27 } EncodedData; 28 29 #include "api/private/converter.c.generated.h" 30 31 #define TYPVAL_ENCODE_ALLOW_SPECIALS false 32 #define TYPVAL_ENCODE_CHECK_BEFORE 33 34 #define TYPVAL_ENCODE_CONV_NIL(tv) \ 35 kvi_push(edata->stack, NIL) 36 37 #define TYPVAL_ENCODE_CONV_BOOL(tv, num) \ 38 kvi_push(edata->stack, BOOLEAN_OBJ((Boolean)(num))) 39 40 #define TYPVAL_ENCODE_CONV_NUMBER(tv, num) \ 41 kvi_push(edata->stack, INTEGER_OBJ((Integer)(num))) 42 43 #define TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER TYPVAL_ENCODE_CONV_NUMBER 44 45 #define TYPVAL_ENCODE_CONV_FLOAT(tv, flt) \ 46 kvi_push(edata->stack, FLOAT_OBJ((Float)(flt))) 47 48 static Object typval_cbuf_to_obj(EncodedData *edata, const char *data, size_t len) 49 { 50 if (edata->reuse_strdata) { 51 return STRING_OBJ(cbuf_as_string((char *)(len ? data : ""), len)); 52 } else { 53 return CBUF_TO_ARENA_OBJ(edata->arena, data, len); 54 } 55 } 56 57 #define TYPVAL_ENCODE_CONV_STRING(tv, str, len) \ 58 do { \ 59 const size_t len_ = (size_t)(len); \ 60 const char *const str_ = (str); \ 61 assert(len_ == 0 || str_ != NULL); \ 62 kvi_push(edata->stack, typval_cbuf_to_obj(edata, str_, len_)); \ 63 } while (0) 64 65 #define TYPVAL_ENCODE_CONV_STR_STRING TYPVAL_ENCODE_CONV_STRING 66 67 #define TYPVAL_ENCODE_CONV_EXT_STRING(tv, str, len, type) \ 68 TYPVAL_ENCODE_CONV_NIL(tv) 69 70 #define TYPVAL_ENCODE_CONV_BLOB(tv, blob, len) \ 71 do { \ 72 const size_t len_ = (size_t)(len); \ 73 const blob_T *const blob_ = (blob); \ 74 kvi_push(edata->stack, typval_cbuf_to_obj(edata, len_ ? blob_->bv_ga.ga_data : "", len_)); \ 75 } while (0) 76 77 #define TYPVAL_ENCODE_CONV_FUNC_START(tv, fun, prefix) \ 78 do { \ 79 const char *const fun_ = (fun); \ 80 ufunc_T *fp; \ 81 if (fun_ != NULL && (fp = find_func(fun_)) != NULL && fp->uf_flags & FC_LUAREF) { \ 82 kvi_push(edata->stack, LUAREF_OBJ(api_new_luaref(fp->uf_luaref))); \ 83 } else { \ 84 TYPVAL_ENCODE_CONV_NIL(tv); \ 85 } \ 86 goto typval_encode_stop_converting_one_item; \ 87 } while (0) 88 89 #define TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS(tv, len) 90 #define TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF(tv, len) 91 #define TYPVAL_ENCODE_CONV_FUNC_END(tv) 92 93 #define TYPVAL_ENCODE_CONV_EMPTY_LIST(tv) \ 94 kvi_push(edata->stack, ARRAY_OBJ(((Array) { .capacity = 0, .size = 0 }))) 95 96 #define TYPVAL_ENCODE_CONV_EMPTY_DICT(tv, dict) \ 97 kvi_push(edata->stack, DICT_OBJ(((Dict) { .capacity = 0, .size = 0 }))) 98 99 static inline void typval_encode_list_start(EncodedData *const edata, const size_t len) 100 FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL 101 { 102 kvi_push(edata->stack, ARRAY_OBJ(arena_array(edata->arena, len))); 103 } 104 105 #define TYPVAL_ENCODE_CONV_LIST_START(tv, len) \ 106 typval_encode_list_start(edata, (size_t)(len)) 107 108 #define TYPVAL_ENCODE_CONV_REAL_LIST_AFTER_START(tv, mpsv) 109 110 static inline void typval_encode_between_list_items(EncodedData *const edata) 111 FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL 112 { 113 Object item = kv_pop(edata->stack); 114 Object *const list = &kv_last(edata->stack); 115 assert(list->type == kObjectTypeArray); 116 assert(list->data.array.size < list->data.array.capacity); 117 ADD_C(list->data.array, item); 118 } 119 120 #define TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS(tv) \ 121 typval_encode_between_list_items(edata) 122 123 static inline void typval_encode_list_end(EncodedData *const edata) 124 FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL 125 { 126 typval_encode_between_list_items(edata); 127 #ifndef NDEBUG 128 const Object *const list = &kv_last(edata->stack); 129 assert(list->data.array.size == list->data.array.capacity); 130 #endif 131 } 132 133 #define TYPVAL_ENCODE_CONV_LIST_END(tv) \ 134 typval_encode_list_end(edata) 135 136 static inline void typval_encode_dict_start(EncodedData *const edata, const size_t len) 137 FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL 138 { 139 kvi_push(edata->stack, DICT_OBJ(arena_dict(edata->arena, len))); 140 } 141 142 #define TYPVAL_ENCODE_CONV_DICT_START(tv, dict, len) \ 143 typval_encode_dict_start(edata, (size_t)(len)) 144 145 #define TYPVAL_ENCODE_CONV_REAL_DICT_AFTER_START(tv, dict, mpsv) 146 147 #define TYPVAL_ENCODE_SPECIAL_DICT_KEY_CHECK(label, kv_pair) 148 149 static inline void typval_encode_after_key(EncodedData *const edata) 150 FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL 151 { 152 Object key = kv_pop(edata->stack); 153 Object *const dict = &kv_last(edata->stack); 154 assert(dict->type == kObjectTypeDict); 155 assert(dict->data.dict.size < dict->data.dict.capacity); 156 if (key.type == kObjectTypeString) { 157 dict->data.dict.items[dict->data.dict.size].key 158 = key.data.string; 159 } else { 160 dict->data.dict.items[dict->data.dict.size].key 161 = STATIC_CSTR_AS_STRING("__INVALID_KEY__"); 162 } 163 } 164 165 #define TYPVAL_ENCODE_CONV_DICT_AFTER_KEY(tv, dict) \ 166 typval_encode_after_key(edata) 167 168 static inline void typval_encode_between_dict_items(EncodedData *const edata) 169 FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL 170 { 171 Object val = kv_pop(edata->stack); 172 Object *const dict = &kv_last(edata->stack); 173 assert(dict->type == kObjectTypeDict); 174 assert(dict->data.dict.size < dict->data.dict.capacity); 175 dict->data.dict.items[dict->data.dict.size++].value = val; 176 } 177 178 #define TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS(tv, dict) \ 179 typval_encode_between_dict_items(edata) 180 181 static inline void typval_encode_dict_end(EncodedData *const edata) 182 FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_NONNULL_ALL 183 { 184 typval_encode_between_dict_items(edata); 185 #ifndef NDEBUG 186 const Object *const dict = &kv_last(edata->stack); 187 assert(dict->data.dict.size == dict->data.dict.capacity); 188 #endif 189 } 190 191 #define TYPVAL_ENCODE_CONV_DICT_END(tv, dict) \ 192 typval_encode_dict_end(edata) 193 194 #define TYPVAL_ENCODE_CONV_RECURSE(val, conv_type) \ 195 TYPVAL_ENCODE_CONV_NIL(val) 196 197 #define TYPVAL_ENCODE_SCOPE static 198 #define TYPVAL_ENCODE_NAME object 199 #define TYPVAL_ENCODE_FIRST_ARG_TYPE EncodedData *const 200 #define TYPVAL_ENCODE_FIRST_ARG_NAME edata 201 #include "nvim/eval/typval_encode.c.h" 202 203 #undef TYPVAL_ENCODE_SCOPE 204 #undef TYPVAL_ENCODE_NAME 205 #undef TYPVAL_ENCODE_FIRST_ARG_TYPE 206 #undef TYPVAL_ENCODE_FIRST_ARG_NAME 207 208 #undef TYPVAL_ENCODE_CONV_STRING 209 #undef TYPVAL_ENCODE_CONV_STR_STRING 210 #undef TYPVAL_ENCODE_CONV_EXT_STRING 211 #undef TYPVAL_ENCODE_CONV_BLOB 212 #undef TYPVAL_ENCODE_CONV_NUMBER 213 #undef TYPVAL_ENCODE_CONV_FLOAT 214 #undef TYPVAL_ENCODE_CONV_FUNC_START 215 #undef TYPVAL_ENCODE_CONV_FUNC_BEFORE_ARGS 216 #undef TYPVAL_ENCODE_CONV_FUNC_BEFORE_SELF 217 #undef TYPVAL_ENCODE_CONV_FUNC_END 218 #undef TYPVAL_ENCODE_CONV_EMPTY_LIST 219 #undef TYPVAL_ENCODE_CONV_LIST_START 220 #undef TYPVAL_ENCODE_CONV_REAL_LIST_AFTER_START 221 #undef TYPVAL_ENCODE_CONV_EMPTY_DICT 222 #undef TYPVAL_ENCODE_CHECK_BEFORE 223 #undef TYPVAL_ENCODE_CONV_NIL 224 #undef TYPVAL_ENCODE_CONV_BOOL 225 #undef TYPVAL_ENCODE_CONV_UNSIGNED_NUMBER 226 #undef TYPVAL_ENCODE_CONV_DICT_START 227 #undef TYPVAL_ENCODE_CONV_REAL_DICT_AFTER_START 228 #undef TYPVAL_ENCODE_CONV_DICT_END 229 #undef TYPVAL_ENCODE_CONV_DICT_AFTER_KEY 230 #undef TYPVAL_ENCODE_CONV_DICT_BETWEEN_ITEMS 231 #undef TYPVAL_ENCODE_SPECIAL_DICT_KEY_CHECK 232 #undef TYPVAL_ENCODE_CONV_LIST_END 233 #undef TYPVAL_ENCODE_CONV_LIST_BETWEEN_ITEMS 234 #undef TYPVAL_ENCODE_CONV_RECURSE 235 #undef TYPVAL_ENCODE_ALLOW_SPECIALS 236 237 /// Convert a vim object to an `Object` instance, recursively converting 238 /// Arrays/Dictionaries. 239 /// 240 /// @param obj The source object 241 /// @param arena if NULL, use direct allocation 242 /// @param reuse_strdata when true, don't copy string data to Arena but reference 243 /// typval strings directly. takes no effect when arena is 244 /// NULL 245 /// @return The converted value 246 Object vim_to_object(typval_T *obj, Arena *arena, bool reuse_strdata) 247 { 248 EncodedData edata; 249 kvi_init(edata.stack); 250 edata.arena = arena; 251 edata.reuse_strdata = reuse_strdata; 252 const int evo_ret = encode_vim_to_object(&edata, obj, "vim_to_object argument"); 253 (void)evo_ret; 254 assert(evo_ret == OK); 255 Object ret = kv_A(edata.stack, 0); 256 assert(kv_size(edata.stack) == 1); 257 kvi_destroy(edata.stack); 258 return ret; 259 } 260 261 /// Converts from type Object to a Vimscript value. 262 /// 263 /// @param obj Object to convert from. 264 /// @param tv Conversion result is placed here. On failure member v_type is 265 /// set to VAR_UNKNOWN (no allocation was made for this variable). 266 /// @param err Error object. 267 void object_to_vim(Object obj, typval_T *tv, Error *err) 268 { 269 object_to_vim_take_luaref(&obj, tv, false, err); 270 } 271 272 /// same as object_to_vim but consumes all luarefs (nested) in `obj` 273 /// 274 /// useful when `obj` is allocated on an arena 275 void object_to_vim_take_luaref(Object *obj, typval_T *tv, bool take_luaref, Error *err) 276 { 277 tv->v_type = VAR_UNKNOWN; 278 tv->v_lock = VAR_UNLOCKED; 279 280 switch (obj->type) { 281 case kObjectTypeNil: 282 tv->v_type = VAR_SPECIAL; 283 tv->vval.v_special = kSpecialVarNull; 284 break; 285 286 case kObjectTypeBoolean: 287 tv->v_type = VAR_BOOL; 288 tv->vval.v_bool = obj->data.boolean ? kBoolVarTrue : kBoolVarFalse; 289 break; 290 291 case kObjectTypeBuffer: 292 case kObjectTypeWindow: 293 case kObjectTypeTabpage: 294 case kObjectTypeInteger: 295 STATIC_ASSERT(sizeof(obj->data.integer) <= sizeof(varnumber_T), 296 "Integer size must be <= Vimscript number size"); 297 tv->v_type = VAR_NUMBER; 298 tv->vval.v_number = (varnumber_T)obj->data.integer; 299 break; 300 301 case kObjectTypeFloat: 302 tv->v_type = VAR_FLOAT; 303 tv->vval.v_float = obj->data.floating; 304 break; 305 306 case kObjectTypeString: { 307 String s = obj->data.string; 308 *tv = decode_string(s.data, s.size, false, false); 309 break; 310 } 311 312 case kObjectTypeArray: { 313 list_T *const list = tv_list_alloc((ptrdiff_t)obj->data.array.size); 314 315 for (uint32_t i = 0; i < obj->data.array.size; i++) { 316 typval_T li_tv; 317 object_to_vim_take_luaref(&obj->data.array.items[i], &li_tv, take_luaref, err); 318 tv_list_append_owned_tv(list, li_tv); 319 } 320 tv_list_ref(list); 321 322 tv->v_type = VAR_LIST; 323 tv->vval.v_list = list; 324 break; 325 } 326 327 case kObjectTypeDict: { 328 dict_T *const dict = tv_dict_alloc(); 329 330 for (uint32_t i = 0; i < obj->data.dict.size; i++) { 331 KeyValuePair *item = &obj->data.dict.items[i]; 332 String key = item->key; 333 dictitem_T *const di = tv_dict_item_alloc(key.data); 334 object_to_vim_take_luaref(&item->value, &di->di_tv, take_luaref, err); 335 tv_dict_add(dict, di); 336 } 337 dict->dv_refcount++; 338 339 tv->v_type = VAR_DICT; 340 tv->vval.v_dict = dict; 341 break; 342 } 343 344 case kObjectTypeLuaRef: { 345 LuaRef ref = obj->data.luaref; 346 if (take_luaref) { 347 obj->data.luaref = LUA_NOREF; 348 } else { 349 ref = api_new_luaref(ref); 350 } 351 char *name = register_luafunc(ref); 352 tv->v_type = VAR_FUNC; 353 tv->vval.v_string = xstrdup(name); 354 break; 355 } 356 } 357 }