1#ifndef NVIM_EVAL_TYPVAL_H
2#define NVIM_EVAL_TYPVAL_H
3
4#include <inttypes.h>
5#include <stddef.h>
6#include <string.h>
7#include <stdbool.h>
8#include <assert.h>
9
10#include "nvim/types.h"
11#include "nvim/hashtab.h"
12#include "nvim/garray.h"
13#include "nvim/mbyte.h"
14#include "nvim/func_attr.h"
15#include "nvim/lib/queue.h"
16#include "nvim/profile.h" // for proftime_T
17#include "nvim/pos.h" // for linenr_T
18#include "nvim/gettext.h"
19#include "nvim/message.h"
20#include "nvim/macros.h"
21#ifdef LOG_LIST_ACTIONS
22# include "nvim/memory.h"
23#endif
24
25/// Type used for VimL VAR_NUMBER values
26typedef int64_t varnumber_T;
27typedef uint64_t uvarnumber_T;
28
29/// Type used for VimL VAR_FLOAT values
30typedef double float_T;
31
32/// Refcount for dict or list that should not be freed
33enum { DO_NOT_FREE_CNT = (INT_MAX / 2) };
34
35/// Additional values for tv_list_alloc() len argument
36enum {
37 /// List length is not known in advance
38 ///
39 /// To be used when there is neither a way to know how many elements will be
40 /// needed nor are any educated guesses.
41 kListLenUnknown = -1,
42 /// List length *should* be known, but is actually not
43 ///
44 /// All occurrences of this value should be eventually removed. This is for
45 /// the case when the only reason why list length is not known is that it
46 /// would be hard to code without refactoring, but refactoring is needed.
47 kListLenShouldKnow = -2,
48 /// List length may be known in advance, but it requires too much effort
49 ///
50 /// To be used when it looks impractical to determine list length.
51 kListLenMayKnow = -3,
52} ListLenSpecials;
53
54/// Maximal possible value of varnumber_T variable
55#define VARNUMBER_MAX INT64_MAX
56#define UVARNUMBER_MAX UINT64_MAX
57
58/// Mimimal possible value of varnumber_T variable
59#define VARNUMBER_MIN INT64_MIN
60
61/// %d printf format specifier for varnumber_T
62#define PRIdVARNUMBER PRId64
63
64typedef struct listvar_S list_T;
65typedef struct dictvar_S dict_T;
66typedef struct partial_S partial_T;
67
68typedef struct ufunc ufunc_T;
69
70typedef enum {
71 kCallbackNone = 0,
72 kCallbackFuncref,
73 kCallbackPartial,
74} CallbackType;
75
76typedef struct {
77 union {
78 char_u *funcref;
79 partial_T *partial;
80 } data;
81 CallbackType type;
82} Callback;
83#define CALLBACK_NONE ((Callback){ .type = kCallbackNone })
84
85/// Structure holding dictionary watcher
86typedef struct dict_watcher {
87 Callback callback;
88 char *key_pattern;
89 size_t key_pattern_len;
90 QUEUE node;
91 bool busy; // prevent recursion if the dict is changed in the callback
92} DictWatcher;
93
94/// Special variable values
95typedef enum {
96 kSpecialVarFalse, ///< v:false
97 kSpecialVarTrue, ///< v:true
98 kSpecialVarNull, ///< v:null
99} SpecialVarValue;
100
101/// Variable lock status for typval_T.v_lock
102typedef enum {
103 VAR_UNLOCKED = 0, ///< Not locked.
104 VAR_LOCKED = 1, ///< User lock, can be unlocked.
105 VAR_FIXED = 2, ///< Locked forever.
106} VarLockStatus;
107
108/// VimL variable types, for use in typval_T.v_type
109typedef enum {
110 VAR_UNKNOWN = 0, ///< Unknown (unspecified) value.
111 VAR_NUMBER, ///< Number, .v_number is used.
112 VAR_STRING, ///< String, .v_string is used.
113 VAR_FUNC, ///< Function reference, .v_string is used as function name.
114 VAR_LIST, ///< List, .v_list is used.
115 VAR_DICT, ///< Dictionary, .v_dict is used.
116 VAR_FLOAT, ///< Floating-point value, .v_float is used.
117 VAR_SPECIAL, ///< Special value (true, false, null), .v_special
118 ///< is used.
119 VAR_PARTIAL, ///< Partial, .v_partial is used.
120} VarType;
121
122/// Structure that holds an internal variable value
123typedef struct {
124 VarType v_type; ///< Variable type.
125 VarLockStatus v_lock; ///< Variable lock status.
126 union typval_vval_union {
127 varnumber_T v_number; ///< Number, for VAR_NUMBER.
128 SpecialVarValue v_special; ///< Special value, for VAR_SPECIAL.
129 float_T v_float; ///< Floating-point number, for VAR_FLOAT.
130 char_u *v_string; ///< String, for VAR_STRING and VAR_FUNC, can be NULL.
131 list_T *v_list; ///< List for VAR_LIST, can be NULL.
132 dict_T *v_dict; ///< Dictionary for VAR_DICT, can be NULL.
133 partial_T *v_partial; ///< Closure: function with args.
134 } vval; ///< Actual value.
135} typval_T;
136
137/// Values for (struct dictvar_S).dv_scope
138typedef enum {
139 VAR_NO_SCOPE = 0, ///< Not a scope dictionary.
140 VAR_SCOPE = 1, ///< Scope dictionary which requires prefix (a:, v:, …).
141 VAR_DEF_SCOPE = 2, ///< Scope dictionary which may be accessed without prefix
142 ///< (l:, g:).
143} ScopeType;
144
145/// Structure to hold an item of a list
146typedef struct listitem_S listitem_T;
147
148struct listitem_S {
149 listitem_T *li_next; ///< Next item in list.
150 listitem_T *li_prev; ///< Previous item in list.
151 typval_T li_tv; ///< Item value.
152};
153
154/// Structure used by those that are using an item in a list
155typedef struct listwatch_S listwatch_T;
156
157struct listwatch_S {
158 listitem_T *lw_item; ///< Item being watched.
159 listwatch_T *lw_next; ///< Next watcher.
160};
161
162/// Structure to hold info about a list
163/// Order of members is optimized to reduce padding.
164struct listvar_S {
165 listitem_T *lv_first; ///< First item, NULL if none.
166 listitem_T *lv_last; ///< Last item, NULL if none.
167 listwatch_T *lv_watch; ///< First watcher, NULL if none.
168 listitem_T *lv_idx_item; ///< When not NULL item at index "lv_idx".
169 list_T *lv_copylist; ///< Copied list used by deepcopy().
170 list_T *lv_used_next; ///< next list in used lists list.
171 list_T *lv_used_prev; ///< Previous list in used lists list.
172 int lv_refcount; ///< Reference count.
173 int lv_len; ///< Number of items.
174 int lv_idx; ///< Index of a cached item, used for optimising repeated l[idx].
175 int lv_copyID; ///< ID used by deepcopy().
176 VarLockStatus lv_lock; ///< Zero, VAR_LOCKED, VAR_FIXED.
177};
178
179// Static list with 10 items. Use tv_list_init_static10() to initialize.
180typedef struct {
181 list_T sl_list; // must be first
182 listitem_T sl_items[10];
183} staticList10_T;
184
185#define TV_LIST_STATIC10_INIT { \
186 .sl_list = { \
187 .lv_first = NULL, \
188 .lv_last = NULL, \
189 .lv_refcount = 0, \
190 .lv_len = 0, \
191 .lv_watch = NULL, \
192 .lv_idx_item = NULL, \
193 .lv_lock = VAR_FIXED, \
194 .lv_used_next = NULL, \
195 .lv_used_prev = NULL, \
196 }, \
197 }
198
199#define TV_DICTITEM_STRUCT(...) \
200 struct { \
201 typval_T di_tv; /* Structure that holds scope dictionary itself. */ \
202 uint8_t di_flags; /* Flags. */ \
203 char_u di_key[__VA_ARGS__]; /* Key value. */ \
204 }
205
206/// Structure to hold a scope dictionary
207///
208/// @warning Must be compatible with dictitem_T.
209///
210/// For use in find_var_in_ht to pretend that it found dictionary item when it
211/// finds scope dictionary.
212typedef TV_DICTITEM_STRUCT(1) ScopeDictDictItem;
213
214/// Structure to hold an item of a Dictionary
215///
216/// @warning Must be compatible with ScopeDictDictItem.
217///
218/// Also used for a variable.
219typedef TV_DICTITEM_STRUCT() dictitem_T;
220
221/// Flags for dictitem_T.di_flags
222typedef enum {
223 DI_FLAGS_RO = 1, ///< Read-only value
224 DI_FLAGS_RO_SBX = 2, ///< Value, read-only in the sandbox
225 DI_FLAGS_FIX = 4, ///< Fixed value: cannot be :unlet or remove()d.
226 DI_FLAGS_LOCK = 8, ///< Locked value.
227 DI_FLAGS_ALLOC = 16, ///< Separately allocated.
228} DictItemFlags;
229
230/// Structure representing a Dictionary
231struct dictvar_S {
232 VarLockStatus dv_lock; ///< Whole dictionary lock status.
233 ScopeType dv_scope; ///< Non-zero (#VAR_SCOPE, #VAR_DEF_SCOPE) if
234 ///< dictionary represents a scope (i.e. g:, l: …).
235 int dv_refcount; ///< Reference count.
236 int dv_copyID; ///< ID used when recursivery traversing a value.
237 hashtab_T dv_hashtab; ///< Hashtab containing all items.
238 dict_T *dv_copydict; ///< Copied dict used by deepcopy().
239 dict_T *dv_used_next; ///< Next dictionary in used dictionaries list.
240 dict_T *dv_used_prev; ///< Previous dictionary in used dictionaries list.
241 QUEUE watchers; ///< Dictionary key watchers set by user code.
242};
243
244/// Type used for script ID
245typedef int scid_T;
246/// Format argument for scid_T
247#define PRIdSCID "d"
248
249// SCript ConteXt (SCTX): identifies a script script line.
250// When sourcing a script "sc_lnum" is zero, "sourcing_lnum" is the current
251// line number. When executing a user function "sc_lnum" is the line where the
252// function was defined, "sourcing_lnum" is the line number inside the
253// function. When stored with a function, mapping, option, etc. "sc_lnum" is
254// the line number in the script "sc_sid".
255typedef struct {
256 scid_T sc_sid; // script ID
257 int sc_seq; // sourcing sequence number
258 linenr_T sc_lnum; // line number
259} sctx_T;
260
261// Structure to hold info for a function that is currently being executed.
262typedef struct funccall_S funccall_T;
263
264/// Structure to hold info for a user function.
265struct ufunc {
266 int uf_varargs; ///< variable nr of arguments
267 int uf_flags;
268 int uf_calls; ///< nr of active calls
269 bool uf_cleared; ///< func_clear() was already called
270 garray_T uf_args; ///< arguments
271 garray_T uf_lines; ///< function lines
272 int uf_profiling; ///< true when func is being profiled
273 int uf_prof_initialized;
274 // Profiling the function as a whole.
275 int uf_tm_count; ///< nr of calls
276 proftime_T uf_tm_total; ///< time spent in function + children
277 proftime_T uf_tm_self; ///< time spent in function itself
278 proftime_T uf_tm_children; ///< time spent in children this call
279 // Profiling the function per line.
280 int *uf_tml_count; ///< nr of times line was executed
281 proftime_T *uf_tml_total; ///< time spent in a line + children
282 proftime_T *uf_tml_self; ///< time spent in a line itself
283 proftime_T uf_tml_start; ///< start time for current line
284 proftime_T uf_tml_children; ///< time spent in children for this line
285 proftime_T uf_tml_wait; ///< start wait time for current line
286 int uf_tml_idx; ///< index of line being timed; -1 if none
287 int uf_tml_execed; ///< line being timed was executed
288 sctx_T uf_script_ctx; ///< SCTX where function was defined,
289 ///< used for s: variables
290 int uf_refcount; ///< reference count, see func_name_refcount()
291 funccall_T *uf_scoped; ///< l: local variables for closure
292 char_u uf_name[]; ///< Name of function; can start with <SNR>123_
293 ///< (<SNR> is K_SPECIAL KS_EXTRA KE_SNR)
294};
295
296/// Maximum number of function arguments
297#define MAX_FUNC_ARGS 20
298
299struct partial_S {
300 int pt_refcount; ///< Reference count.
301 char_u *pt_name; ///< Function name; when NULL use pt_func->name.
302 ufunc_T *pt_func; ///< Function pointer; when NULL lookup function with
303 ///< pt_name.
304 bool pt_auto; ///< When true the partial was created by using dict.member
305 ///< in handle_subscript().
306 int pt_argc; ///< Number of arguments.
307 typval_T *pt_argv; ///< Arguments in allocated array.
308 dict_T *pt_dict; ///< Dict for "self".
309};
310
311/// Structure used for explicit stack while garbage collecting hash tables
312typedef struct ht_stack_S {
313 hashtab_T *ht;
314 struct ht_stack_S *prev;
315} ht_stack_T;
316
317/// Structure used for explicit stack while garbage collecting lists
318typedef struct list_stack_S {
319 list_T *list;
320 struct list_stack_S *prev;
321} list_stack_T;
322
323/// Structure representing one list item, used for sort array.
324typedef struct {
325 listitem_T *item; ///< Sorted list item.
326 int idx; ///< Sorted list item index.
327} ListSortItem;
328
329typedef int (*ListSorter)(const void *, const void *);
330
331#ifdef LOG_LIST_ACTIONS
332
333/// List actions log entry
334typedef struct {
335 uintptr_t l; ///< List log entry belongs to.
336 uintptr_t li1; ///< First list item log entry belongs to, if applicable.
337 uintptr_t li2; ///< Second list item log entry belongs to, if applicable.
338 int len; ///< List length when log entry was created.
339 const char *action; ///< Logged action.
340} ListLogEntry;
341
342typedef struct list_log ListLog;
343
344/// List actions log
345struct list_log {
346 ListLog *next; ///< Next chunk or NULL.
347 size_t capacity; ///< Number of entries in current chunk.
348 size_t size; ///< Current chunk size.
349 ListLogEntry entries[]; ///< Actual log entries.
350};
351
352extern ListLog *list_log_first; ///< First list log chunk, NULL if missing
353extern ListLog *list_log_last; ///< Last list log chunk
354
355static inline ListLog *list_log_alloc(const size_t size)
356 REAL_FATTR_ALWAYS_INLINE REAL_FATTR_WARN_UNUSED_RESULT;
357
358/// Allocate a new log chunk and update globals
359///
360/// @param[in] size Number of entries in a new chunk.
361///
362/// @return [allocated] Newly allocated chunk.
363static inline ListLog *list_log_new(const size_t size)
364{
365 ListLog *ret = xmalloc(offsetof(ListLog, entries)
366 + size * sizeof(ret->entries[0]));
367 ret->size = 0;
368 ret->capacity = size;
369 ret->next = NULL;
370 if (list_log_first == NULL) {
371 list_log_first = ret;
372 } else {
373 list_log_last->next = ret;
374 }
375 list_log_last = ret;
376 return ret;
377}
378
379static inline void list_log(const list_T *const l,
380 const listitem_T *const li1,
381 const listitem_T *const li2,
382 const char *const action)
383 REAL_FATTR_ALWAYS_INLINE;
384
385/// Add new entry to log
386///
387/// If last chunk was filled it uses twice as much memory to allocate the next
388/// chunk.
389///
390/// @param[in] l List to which entry belongs.
391/// @param[in] li1 List item 1.
392/// @param[in] li2 List item 2, often used for integers and not list items.
393/// @param[in] action Logged action.
394static inline void list_log(const list_T *const l,
395 const listitem_T *const li1,
396 const listitem_T *const li2,
397 const char *const action)
398{
399 ListLog *tgt;
400 if (list_log_first == NULL) {
401 tgt = list_log_new(128);
402 } else if (list_log_last->size == list_log_last->capacity) {
403 tgt = list_log_new(list_log_last->capacity * 2);
404 } else {
405 tgt = list_log_last;
406 }
407 tgt->entries[tgt->size++] = (ListLogEntry) {
408 .l = (uintptr_t)l,
409 .li1 = (uintptr_t)li1,
410 .li2 = (uintptr_t)li2,
411 .len = (l == NULL ? 0 : l->lv_len),
412 .action = action,
413 };
414}
415#else
416# define list_log(...)
417# define list_write_log(...)
418# define list_free_log()
419#endif
420
421// In a hashtab item "hi_key" points to "di_key" in a dictitem.
422// This avoids adding a pointer to the hashtab item.
423
424/// Convert a hashitem pointer to a dictitem pointer
425#define TV_DICT_HI2DI(hi) \
426 ((dictitem_T *)((hi)->hi_key - offsetof(dictitem_T, di_key)))
427
428static inline void tv_list_ref(list_T *const l)
429 REAL_FATTR_ALWAYS_INLINE;
430
431/// Increase reference count for a given list
432///
433/// Does nothing for NULL lists.
434///
435/// @param[in,out] l List to modify.
436static inline void tv_list_ref(list_T *const l)
437{
438 if (l == NULL) {
439 return;
440 }
441 l->lv_refcount++;
442}
443
444static inline void tv_list_set_ret(typval_T *const tv, list_T *const l)
445 REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ARG(1);
446
447/// Set a list as the return value
448///
449/// @param[out] tv Object to receive the list
450/// @param[in,out] l List to pass to the object
451static inline void tv_list_set_ret(typval_T *const tv, list_T *const l)
452{
453 tv->v_type = VAR_LIST;
454 tv->vval.v_list = l;
455 tv_list_ref(l);
456}
457
458static inline VarLockStatus tv_list_locked(const list_T *const l)
459 REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
460
461/// Get list lock status
462///
463/// Returns VAR_FIXED for NULL lists.
464///
465/// @param[in] l List to check.
466static inline VarLockStatus tv_list_locked(const list_T *const l)
467{
468 if (l == NULL) {
469 return VAR_FIXED;
470 }
471 return l->lv_lock;
472}
473
474/// Set list lock status
475///
476/// May only “set” VAR_FIXED for NULL lists.
477///
478/// @param[out] l List to modify.
479/// @param[in] lock New lock status.
480static inline void tv_list_set_lock(list_T *const l,
481 const VarLockStatus lock)
482{
483 if (l == NULL) {
484 assert(lock == VAR_FIXED);
485 return;
486 }
487 l->lv_lock = lock;
488}
489
490/// Set list copyID
491///
492/// Does not expect NULL list, be careful.
493///
494/// @param[out] l List to modify.
495/// @param[in] copyid New copyID.
496static inline void tv_list_set_copyid(list_T *const l,
497 const int copyid)
498 FUNC_ATTR_NONNULL_ALL
499{
500 l->lv_copyID = copyid;
501}
502
503static inline int tv_list_len(const list_T *const l)
504 REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
505
506/// Get the number of items in a list
507///
508/// @param[in] l List to check.
509static inline int tv_list_len(const list_T *const l)
510{
511 list_log(l, NULL, NULL, "len");
512 if (l == NULL) {
513 return 0;
514 }
515 return l->lv_len;
516}
517
518static inline int tv_list_copyid(const list_T *const l)
519 REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT REAL_FATTR_NONNULL_ALL;
520
521/// Get list copyID
522///
523/// Does not expect NULL list, be careful.
524///
525/// @param[in] l List to check.
526static inline int tv_list_copyid(const list_T *const l)
527{
528 return l->lv_copyID;
529}
530
531static inline list_T *tv_list_latest_copy(const list_T *const l)
532 REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT REAL_FATTR_NONNULL_ALL;
533
534/// Get latest list copy
535///
536/// Gets lv_copylist field assigned by tv_list_copy() earlier.
537///
538/// Does not expect NULL list, be careful.
539///
540/// @param[in] l List to check.
541static inline list_T *tv_list_latest_copy(const list_T *const l)
542{
543 return l->lv_copylist;
544}
545
546static inline int tv_list_uidx(const list_T *const l, int n)
547 REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
548
549/// Normalize index: that is, return either -1 or non-negative index
550///
551/// @param[in] l List to index. Used to get length.
552/// @param[in] n List index, possibly negative.
553///
554/// @return -1 or list index in range [0, tv_list_len(l)).
555static inline int tv_list_uidx(const list_T *const l, int n)
556{
557 // Negative index is relative to the end.
558 if (n < 0) {
559 n += tv_list_len(l);
560 }
561
562 // Check for index out of range.
563 if (n < 0 || n >= tv_list_len(l)) {
564 return -1;
565 }
566 return n;
567}
568
569static inline bool tv_list_has_watchers(const list_T *const l)
570 REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
571
572/// Check whether list has watchers
573///
574/// E.g. is referenced by a :for loop.
575///
576/// @param[in] l List to check.
577///
578/// @return true if there are watchers, false otherwise.
579static inline bool tv_list_has_watchers(const list_T *const l)
580{
581 return l && l->lv_watch;
582}
583
584static inline listitem_T *tv_list_first(const list_T *const l)
585 REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
586
587/// Get first list item
588///
589/// @param[in] l List to get item from.
590///
591/// @return List item or NULL in case of an empty list.
592static inline listitem_T *tv_list_first(const list_T *const l)
593{
594 if (l == NULL) {
595 list_log(l, NULL, NULL, "first");
596 return NULL;
597 }
598 list_log(l, l->lv_first, NULL, "first");
599 return l->lv_first;
600}
601
602static inline listitem_T *tv_list_last(const list_T *const l)
603 REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
604
605/// Get last list item
606///
607/// @param[in] l List to get item from.
608///
609/// @return List item or NULL in case of an empty list.
610static inline listitem_T *tv_list_last(const list_T *const l)
611{
612 if (l == NULL) {
613 list_log(l, NULL, NULL, "last");
614 return NULL;
615 }
616 list_log(l, l->lv_last, NULL, "last");
617 return l->lv_last;
618}
619
620static inline void tv_dict_set_ret(typval_T *const tv, dict_T *const d)
621 REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ARG(1);
622
623/// Set a dictionary as the return value
624///
625/// @param[out] tv Object to receive the dictionary
626/// @param[in,out] d Dictionary to pass to the object
627static inline void tv_dict_set_ret(typval_T *const tv, dict_T *const d)
628{
629 tv->v_type = VAR_DICT;
630 tv->vval.v_dict = d;
631 if (d != NULL) {
632 d->dv_refcount++;
633 }
634}
635
636static inline long tv_dict_len(const dict_T *const d)
637 REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
638
639/// Get the number of items in a Dictionary
640///
641/// @param[in] d Dictionary to check.
642static inline long tv_dict_len(const dict_T *const d)
643{
644 if (d == NULL) {
645 return 0L;
646 }
647 return (long)d->dv_hashtab.ht_used;
648}
649
650static inline bool tv_dict_is_watched(const dict_T *const d)
651 REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT;
652
653/// Check if dictionary is watched
654///
655/// @param[in] d Dictionary to check.
656///
657/// @return true if there is at least one watcher.
658static inline bool tv_dict_is_watched(const dict_T *const d)
659{
660 return d && !QUEUE_EMPTY(&d->watchers);
661}
662
663/// Initialize VimL object
664///
665/// Initializes to unlocked VAR_UNKNOWN object.
666///
667/// @param[out] tv Object to initialize.
668static inline void tv_init(typval_T *const tv)
669{
670 if (tv != NULL) {
671 memset(tv, 0, sizeof(*tv));
672 }
673}
674
675#define TV_INITIAL_VALUE \
676 ((typval_T) { \
677 .v_type = VAR_UNKNOWN, \
678 .v_lock = VAR_UNLOCKED, \
679 })
680
681/// Empty string
682///
683/// Needed for hack which allows not allocating empty string and still not
684/// crashing when freeing it.
685extern const char *const tv_empty_string;
686
687/// Specifies that free_unref_items() function has (not) been entered
688extern bool tv_in_free_unref_items;
689
690/// Iterate over a list
691///
692/// @param modifier Modifier: expected to be const or nothing, volatile should
693/// also work if you have any uses for the volatile list.
694/// @param[in] l List to iterate over.
695/// @param li Name of the variable with current listitem_T entry.
696/// @param code Cycle body.
697#define _TV_LIST_ITER_MOD(modifier, l, li, code) \
698 do { \
699 modifier list_T *const l_ = (l); \
700 list_log(l_, NULL, NULL, "iter" #modifier); \
701 if (l_ != NULL) { \
702 for (modifier listitem_T *li = l_->lv_first; \
703 li != NULL; li = li->li_next) { \
704 code \
705 } \
706 } \
707 } while (0)
708
709/// Iterate over a list
710///
711/// To be used when you need to modify list or values you iterate over, use
712/// #TV_LIST_ITER_CONST if you don’t.
713///
714/// @param[in] l List to iterate over.
715/// @param li Name of the variable with current listitem_T entry.
716/// @param code Cycle body.
717#define TV_LIST_ITER(l, li, code) \
718 _TV_LIST_ITER_MOD(, l, li, code)
719
720/// Iterate over a list
721///
722/// To be used when you don’t need to modify list or values you iterate over,
723/// use #TV_LIST_ITER if you do.
724///
725/// @param[in] l List to iterate over.
726/// @param li Name of the variable with current listitem_T entry.
727/// @param code Cycle body.
728#define TV_LIST_ITER_CONST(l, li, code) \
729 _TV_LIST_ITER_MOD(const, l, li, code)
730
731// Below macros are macros to avoid duplicating code for functionally identical
732// const and non-const function variants.
733
734/// Get typval_T out of list item
735///
736/// @param[in] li List item to get typval_T from, must not be NULL.
737///
738/// @return Pointer to typval_T.
739#define TV_LIST_ITEM_TV(li) (&(li)->li_tv)
740
741/// Get next list item given the current one
742///
743/// @param[in] l List to get item from.
744/// @param[in] li List item to get typval_T from.
745///
746/// @return Pointer to the next item or NULL.
747#define TV_LIST_ITEM_NEXT(l, li) ((li)->li_next)
748
749/// Get previous list item given the current one
750///
751/// @param[in] l List to get item from.
752/// @param[in] li List item to get typval_T from.
753///
754/// @return Pointer to the previous item or NULL.
755#define TV_LIST_ITEM_PREV(l, li) ((li)->li_prev)
756// List argument is not used currently, but it is a must for lists implemented
757// as a pair (size(in list), array) without terminator - basically for lists on
758// top of kvec.
759
760/// Iterate over a dictionary
761///
762/// @param[in] d Dictionary to iterate over.
763/// @param di Name of the variable with current dictitem_T entry.
764/// @param code Cycle body.
765#define TV_DICT_ITER(d, di, code) \
766 HASHTAB_ITER(&(d)->dv_hashtab, di##hi_, { \
767 { \
768 dictitem_T *const di = TV_DICT_HI2DI(di##hi_); \
769 { \
770 code \
771 } \
772 } \
773 })
774
775static inline bool tv_get_float_chk(const typval_T *const tv,
776 float_T *const ret_f)
777 REAL_FATTR_NONNULL_ALL REAL_FATTR_WARN_UNUSED_RESULT;
778
779// FIXME circular dependency, cannot import message.h.
780bool emsgf(const char *const fmt, ...);
781
782/// Get the float value
783///
784/// Raises an error if object is not number or floating-point.
785///
786/// @param[in] tv VimL object to get value from.
787/// @param[out] ret_f Location where resulting float is stored.
788///
789/// @return true in case of success, false if tv is not a number or float.
790static inline bool tv_get_float_chk(const typval_T *const tv,
791 float_T *const ret_f)
792{
793 if (tv->v_type == VAR_FLOAT) {
794 *ret_f = tv->vval.v_float;
795 return true;
796 }
797 if (tv->v_type == VAR_NUMBER) {
798 *ret_f = (float_T)tv->vval.v_number;
799 return true;
800 }
801 emsgf(_("E808: Number or Float required"));
802 return false;
803}
804
805static inline DictWatcher *tv_dict_watcher_node_data(QUEUE *q)
806 REAL_FATTR_NONNULL_ALL REAL_FATTR_NONNULL_RET REAL_FATTR_PURE
807 REAL_FATTR_WARN_UNUSED_RESULT REAL_FATTR_ALWAYS_INLINE;
808
809/// Compute the `DictWatcher` address from a QUEUE node.
810///
811/// This only exists for .asan-blacklist (ASAN doesn't handle QUEUE_DATA pointer
812/// arithmetic).
813static inline DictWatcher *tv_dict_watcher_node_data(QUEUE *q)
814{
815 return QUEUE_DATA(q, DictWatcher, node);
816}
817
818static inline bool tv_is_func(const typval_T tv)
819 FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_CONST;
820
821/// Check whether given typval_T contains a function
822///
823/// That is, whether it contains VAR_FUNC or VAR_PARTIAL.
824///
825/// @param[in] tv Typval to check.
826///
827/// @return True if it is a function or a partial, false otherwise.
828static inline bool tv_is_func(const typval_T tv)
829{
830 return tv.v_type == VAR_FUNC || tv.v_type == VAR_PARTIAL;
831}
832
833/// Specify that argument needs to be translated
834///
835/// Used for size_t length arguments to avoid calling gettext() and strlen()
836/// unless needed.
837#define TV_TRANSLATE (SIZE_MAX)
838
839/// Specify that argument is a NUL-terminated C string
840///
841/// Used for size_t length arguments to avoid calling strlen() unless needed.
842#define TV_CSTRING (SIZE_MAX - 1)
843
844#ifdef UNIT_TESTING
845// Do not use enum constants, see commit message.
846EXTERN const size_t kTVCstring INIT(= TV_CSTRING);
847EXTERN const size_t kTVTranslate INIT(= TV_TRANSLATE);
848#endif
849
850#ifdef INCLUDE_GENERATED_DECLARATIONS
851# include "eval/typval.h.generated.h"
852#endif
853#endif // NVIM_EVAL_TYPVAL_H
854