From fb146e80aa1ead96518f38b9684e39249bc83485 Mon Sep 17 00:00:00 2001 From: ZyX Date: Tue, 26 Jul 2016 23:16:23 +0300 Subject: eval: Split eval.c into smaller files --- src/nvim/eval/typval.h | 285 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 285 insertions(+) create mode 100644 src/nvim/eval/typval.h (limited to 'src/nvim/eval/typval.h') diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h new file mode 100644 index 0000000000..cf83904ffc --- /dev/null +++ b/src/nvim/eval/typval.h @@ -0,0 +1,285 @@ +#ifndef NVIM_EVAL_TYPVAL_H +#define NVIM_EVAL_TYPVAL_H + +#include +#include +#include + +#include "nvim/hashtab.h" +#include "nvim/garray.h" +#include "nvim/mbyte.h" +#include "nvim/lib/queue.h" +#include "nvim/profile.h" // for proftime_T +#include "nvim/pos.h" // for linenr_T + +/// Type used for VimL VAR_NUMBER values +typedef int varnumber_T; + +/// Type used for VimL VAR_FLOAT values +typedef double float_T; + +/// Maximal possible value of varnumber_T variable +#define VARNUMBER_MAX INT_MAX + +/// Mimimal possible value of varnumber_T variable +#define VARNUMBER_MIN INT_MIN + +/// %d printf format specifier for varnumber_T +#define PRIdVARNUMBER "d" + +typedef struct listvar_S list_T; +typedef struct dictvar_S dict_T; +typedef struct partial_S partial_T; + +/// Special variable values +typedef enum { + kSpecialVarFalse, ///< v:false + kSpecialVarTrue, ///< v:true + kSpecialVarNull, ///< v:null +} SpecialVarValue; + +/// Variable lock status for typval_T.v_lock +typedef enum { + VAR_UNLOCKED = 0, ///< Not locked. + VAR_LOCKED = 1, ///< User lock, can be unlocked. + VAR_FIXED = 2, ///< Locked forever. +} VarLockStatus; + +/// VimL variable types, for use in typval_T.v_type +typedef enum { + VAR_UNKNOWN = 0, ///< Unknown (unspecified) value. + VAR_NUMBER, ///< Number, .v_number is used. + VAR_STRING, ///< String, .v_string is used. + VAR_FUNC, ///< Function reference, .v_string is used as function name. + VAR_LIST, ///< List, .v_list is used. + VAR_DICT, ///< Dictionary, .v_dict is used. + VAR_FLOAT, ///< Floating-point value, .v_float is used. + VAR_SPECIAL, ///< Special value (true, false, null), .v_special + ///< is used. + VAR_PARTIAL, ///< Partial, .v_partial is used. +} VarType; + +/// Structure that holds an internal variable value +typedef struct { + VarType v_type; ///< Variable type. + VarLockStatus v_lock; ///< Variable lock status. + union typval_vval_union { + varnumber_T v_number; ///< Number, for VAR_NUMBER. + SpecialVarValue v_special; ///< Special value, for VAR_SPECIAL. + float_T v_float; ///< Floating-point number, for VAR_FLOAT. + char_u *v_string; ///< String, for VAR_STRING and VAR_FUNC, can be NULL. + list_T *v_list; ///< List for VAR_LIST, can be NULL. + dict_T *v_dict; ///< Dictionary for VAR_DICT, can be NULL. + partial_T *v_partial; ///< Closure: function with args. + } vval; ///< Actual value. +} typval_T; + +/// Values for (struct dictvar_S).dv_scope +typedef enum { + VAR_NO_SCOPE = 0, ///< Not a scope dictionary. + VAR_SCOPE = 1, ///< Scope dictionary which requires prefix (a:, v:, …). + VAR_DEF_SCOPE = 2, ///< Scope dictionary which may be accessed without prefix + ///< (l:, g:). +} ScopeType; + +/// Structure to hold an item of a list +typedef struct listitem_S listitem_T; + +struct listitem_S { + listitem_T *li_next; ///< Next item in list. + listitem_T *li_prev; ///< Previous item in list. + typval_T li_tv; ///< Item value. +}; + +/// Structure used by those that are using an item in a list +typedef struct listwatch_S listwatch_T; + +struct listwatch_S { + listitem_T *lw_item; ///< Item being watched. + listwatch_T *lw_next; ///< Next watcher. +}; + +/// Structure to hold info about a list +struct listvar_S { + listitem_T *lv_first; ///< First item, NULL if none. + listitem_T *lv_last; ///< Last item, NULL if none. + int lv_refcount; ///< Reference count. + int lv_len; ///< Number of items. + listwatch_T *lv_watch; ///< First watcher, NULL if none. + int lv_idx; ///< Index of a cached item, used for optimising repeated l[idx]. + listitem_T *lv_idx_item; ///< When not NULL item at index "lv_idx". + int lv_copyID; ///< ID used by deepcopy(). + list_T *lv_copylist; ///< Copied list used by deepcopy(). + VarLockStatus lv_lock; ///< Zero, VAR_LOCKED, VAR_FIXED. + list_T *lv_used_next; ///< next list in used lists list. + list_T *lv_used_prev; ///< Previous list in used lists list. +}; + +// Static list with 10 items. Use init_static_list() to initialize. +typedef struct { + list_T sl_list; // must be first + listitem_T sl_items[10]; +} staticList10_T; + +// Structure to hold an item of a Dictionary. +// Also used for a variable. +// The key is copied into "di_key" to avoid an extra alloc/free for it. +struct dictitem_S { + typval_T di_tv; ///< type and value of the variable + char_u di_flags; ///< flags (only used for variable) + char_u di_key[1]; ///< key (actually longer!) +}; + +#define TV_DICTITEM_STRUCT(KEY_LEN) \ + struct { \ + typval_T di_tv; /* Structure that holds scope dictionary itself. */ \ + uint8_t di_flags; /* Flags. */ \ + char_u di_key[KEY_LEN]; /* NUL. */ \ + } + +/// Structure to hold a scope dictionary +/// +/// @warning Must be compatible with dictitem_T. +/// +/// For use in find_var_in_ht to pretend that it found dictionary item when it +/// finds scope dictionary. +typedef TV_DICTITEM_STRUCT(1) ScopeDictDictItem; + +/// Structure to hold an item of a Dictionary +/// +/// @warning Must be compatible with ScopeDictDictItem. +/// +/// Also used for a variable. +typedef TV_DICTITEM_STRUCT() dictitem_T; + +/// Flags for dictitem_T.di_flags +typedef enum { + DI_FLAGS_RO = 1, ///< Read-only value + DI_FLAGS_RO_SBX = 2, ///< Value, read-only in the sandbox + DI_FLAGS_FIX = 4, ///< Fixed value: cannot be :unlet or remove()d. + DI_FLAGS_LOCK = 8, ///< Locked value. + DI_FLAGS_ALLOC = 16, ///< Separately allocated. +} DictItemFlags; + +/// Structure representing a Dictionary +struct dictvar_S { + VarLockStatus dv_lock; ///< Whole dictionary lock status. + ScopeType dv_scope; ///< Non-zero (#VAR_SCOPE, #VAR_DEF_SCOPE) if + ///< dictionary represents a scope (i.e. g:, l: …). + int dv_refcount; ///< Reference count. + int dv_copyID; ///< ID used when recursivery traversing a value. + hashtab_T dv_hashtab; ///< Hashtab containing all items. + dict_T *dv_copydict; ///< Copied dict used by deepcopy(). + dict_T *dv_used_next; ///< Next dictionary in used dictionaries list. + dict_T *dv_used_prev; ///< Previous dictionary in used dictionaries list. + QUEUE watchers; ///< Dictionary key watchers set by user code. +}; + +/// Type used for script ID +typedef int scid_T; + +// Structure to hold info for a function that is currently being executed. +typedef struct funccall_S funccall_T; + +// Structure to hold info for a user function. +typedef struct ufunc ufunc_T; + +struct ufunc { + int uf_varargs; ///< variable nr of arguments + int uf_flags; + int uf_calls; ///< nr of active calls + bool uf_cleared; ///< func_clear() was already called + garray_T uf_args; ///< arguments + garray_T uf_lines; ///< function lines + int uf_profiling; ///< true when func is being profiled + // Profiling the function as a whole. + int uf_tm_count; ///< nr of calls + proftime_T uf_tm_total; ///< time spent in function + children + proftime_T uf_tm_self; ///< time spent in function itself + proftime_T uf_tm_children; ///< time spent in children this call + // Profiling the function per line. + int *uf_tml_count; ///< nr of times line was executed + proftime_T *uf_tml_total; ///< time spent in a line + children + proftime_T *uf_tml_self; ///< time spent in a line itself + proftime_T uf_tml_start; ///< start time for current line + proftime_T uf_tml_children; ///< time spent in children for this line + proftime_T uf_tml_wait; ///< start wait time for current line + int uf_tml_idx; ///< index of line being timed; -1 if none + int uf_tml_execed; ///< line being timed was executed + scid_T uf_script_ID; ///< ID of script where function was defined, + // used for s: variables + int uf_refcount; ///< reference count, see func_name_refcount() + funccall_T *uf_scoped; ///< l: local variables for closure + char_u uf_name[1]; ///< name of function (actually longer); can + // start with 123_ ( is K_SPECIAL + // KS_EXTRA KE_SNR) +}; + +/// Maximum number of function arguments +#define MAX_FUNC_ARGS 20 + +struct partial_S { + int pt_refcount; ///< Reference count. + char_u *pt_name; ///< Function name; when NULL use pt_func->name. + ufunc_T *pt_func; ///< Function pointer; when NULL lookup function with + ///< pt_name. + bool pt_auto; ///< When true the partial was created by using dict.member + ///< in handle_subscript(). + int pt_argc; ///< Number of arguments. + typval_T *pt_argv; ///< Arguments in allocated array. + dict_T *pt_dict; ///< Dict for "self". +}; + +/// Structure used for explicit stack while garbage collecting hash tables +typedef struct ht_stack_S { + hashtab_T *ht; + struct ht_stack_S *prev; +} ht_stack_T; + +/// Structure used for explicit stack while garbage collecting lists +typedef struct list_stack_S { + list_T *list; + struct list_stack_S *prev; +} list_stack_T; + +// In a hashtab item "hi_key" points to "di_key" in a dictitem. +// This avoids adding a pointer to the hashtab item. + +/// Convert a dictitem pointer to a hashitem key pointer +#define DI2HIKEY(di) ((di)->di_key) + +/// Convert a hashitem key pointer to a dictitem pointer +#define HIKEY2DI(p) ((dictitem_T *)(p - offsetof(dictitem_T, di_key))) + +/// Convert a hashitem value pointer to a dictitem pointer +#define HIVAL2DI(p) \ + ((dictitem_T *)(((char *)p) - offsetof(dictitem_T, di_tv))) + +/// Convert a hashitem pointer to a dictitem pointer +#define HI2DI(hi) HIKEY2DI((hi)->hi_key) + +/// Get the number of items in a list +/// +/// @param[in] l List to check. +static inline long tv_list_len(list_T *const l) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT +{ + if (l == NULL) { + return 0; + } + return l->lv_len; +} + +/// Empty string +/// +/// Needed for hack which allows not allocating empty string and still not +/// crashing when freeing it. +extern const char *const tv_empty_string; + +/// Specifies that free_unref_items() function has (not) been entered +extern bool tv_in_free_unref_items; + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "eval/typval.h.generated.h" +#endif +#endif // NVIM_EVAL_TYPVAL_H -- cgit From e18a5783080f7c94f408ec5f53dedffdb69789e1 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sat, 20 Aug 2016 22:24:34 +0300 Subject: *: Move some dictionary functions to typval.h and use char* Also fixes buffer reusage in setmatches() and complete(). --- src/nvim/eval/typval.h | 128 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 109 insertions(+), 19 deletions(-) (limited to 'src/nvim/eval/typval.h') diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h index cf83904ffc..6183397d12 100644 --- a/src/nvim/eval/typval.h +++ b/src/nvim/eval/typval.h @@ -8,6 +8,7 @@ #include "nvim/hashtab.h" #include "nvim/garray.h" #include "nvim/mbyte.h" +#include "nvim/func_attr.h" #include "nvim/lib/queue.h" #include "nvim/profile.h" // for proftime_T #include "nvim/pos.h" // for linenr_T @@ -31,6 +32,31 @@ typedef struct listvar_S list_T; typedef struct dictvar_S dict_T; typedef struct partial_S partial_T; +typedef struct ufunc ufunc_T; + +typedef enum { + kCallbackNone, + kCallbackFuncref, + kCallbackPartial, +} CallbackType; + +typedef struct { + union { + char_u *funcref; + partial_T *partial; + } data; + CallbackType type; +} Callback; +#define CALLBACK_NONE ((Callback){ .type = kCallbackNone }) + +/// Structure holding dictionary watcher +typedef struct dict_watcher { + Callback callback; + char *key_pattern; + QUEUE node; + bool busy; // prevent recursion if the dict is changed in the callback +} DictWatcher; + /// Special variable values typedef enum { kSpecialVarFalse, ///< v:false @@ -134,7 +160,7 @@ struct dictitem_S { struct { \ typval_T di_tv; /* Structure that holds scope dictionary itself. */ \ uint8_t di_flags; /* Flags. */ \ - char_u di_key[KEY_LEN]; /* NUL. */ \ + char_u di_key[KEY_LEN]; /* Key value. */ \ } /// Structure to hold a scope dictionary @@ -181,9 +207,7 @@ typedef int scid_T; // Structure to hold info for a function that is currently being executed. typedef struct funccall_S funccall_T; -// Structure to hold info for a user function. -typedef struct ufunc ufunc_T; - +/// Structure to hold info for a user function. struct ufunc { int uf_varargs; ///< variable nr of arguments int uf_flags; @@ -207,12 +231,12 @@ struct ufunc { int uf_tml_idx; ///< index of line being timed; -1 if none int uf_tml_execed; ///< line being timed was executed scid_T uf_script_ID; ///< ID of script where function was defined, - // used for s: variables + ///< used for s: variables int uf_refcount; ///< reference count, see func_name_refcount() funccall_T *uf_scoped; ///< l: local variables for closure char_u uf_name[1]; ///< name of function (actually longer); can - // start with 123_ ( is K_SPECIAL - // KS_EXTRA KE_SNR) + ///< start with 123_ ( is K_SPECIAL + ///< KS_EXTRA KE_SNR) }; /// Maximum number of function arguments @@ -245,24 +269,17 @@ typedef struct list_stack_S { // In a hashtab item "hi_key" points to "di_key" in a dictitem. // This avoids adding a pointer to the hashtab item. -/// Convert a dictitem pointer to a hashitem key pointer -#define DI2HIKEY(di) ((di)->di_key) - -/// Convert a hashitem key pointer to a dictitem pointer -#define HIKEY2DI(p) ((dictitem_T *)(p - offsetof(dictitem_T, di_key))) - -/// Convert a hashitem value pointer to a dictitem pointer -#define HIVAL2DI(p) \ - ((dictitem_T *)(((char *)p) - offsetof(dictitem_T, di_tv))) - /// Convert a hashitem pointer to a dictitem pointer -#define HI2DI(hi) HIKEY2DI((hi)->hi_key) +#define TV_DICT_HI2DI(hi) \ + ((dictitem_T *)((hi)->hi_key - offsetof(dictitem_T, di_key))) + +static inline long tv_list_len(list_T *const l) + REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT; /// Get the number of items in a list /// /// @param[in] l List to check. static inline long tv_list_len(list_T *const l) - FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { if (l == NULL) { return 0; @@ -270,6 +287,64 @@ static inline long tv_list_len(list_T *const l) return l->lv_len; } +static inline long tv_dict_len(const dict_T *const d) + REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT; + +/// Get the number of items in a Dictionary +/// +/// @param[in] d Dictionary to check. +static inline long tv_dict_len(const dict_T *const d) +{ + if (d == NULL) { + return 0L; + } + return (long)d->dv_hashtab.ht_used; +} + +static inline bool tv_dict_is_watched(const dict_T *const d) + REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT; + +/// Check if dictionary is watched +/// +/// @param[in] d Dictionary to check. +/// +/// @return true if there is at least one watcher. +static inline bool tv_dict_is_watched(const dict_T *const d) +{ + return d && !QUEUE_EMPTY(&d->watchers); +} + +static inline DictWatcher *tv_dict_watcher_node_data(QUEUE *q) + REAL_FATTR_NONNULL_ALL REAL_FATTR_NONNULL_RET REAL_FATTR_PURE + REAL_FATTR_WARN_UNUSED_RESULT; + +/// Compute the `DictWatcher` address from a QUEUE node. +/// +/// This only exists for .asan-blacklist (ASAN doesn't handle QUEUE_DATA pointer +/// arithmetic). +static inline DictWatcher *tv_dict_watcher_node_data(QUEUE *q) +{ + return QUEUE_DATA(q, DictWatcher, node); +} + +/// Initialize VimL object +/// +/// Initializes to unlocked VAR_UNKNOWN object. +/// +/// @param[out] tv Object to initialize. +static inline void tv_init(typval_T *const tv) +{ + if (tv != NULL) { + memset(tv, 0, sizeof(*tv)); + } +} + +#define TV_INITIAL_VALUE \ + ((typval_T) { \ + .v_type = VAR_UNKNOWN, \ + .v_lock = VAR_UNLOCKED, \ + }) + /// Empty string /// /// Needed for hack which allows not allocating empty string and still not @@ -279,6 +354,21 @@ extern const char *const tv_empty_string; /// Specifies that free_unref_items() function has (not) been entered extern bool tv_in_free_unref_items; +/// Iterate over a dictionary +/// +/// @param[in] d Dictionary to iterate over. +/// @param di Name of the variable with current dictitem_T entry. +/// @param code Cycle body. +#define TV_DICT_ITER(d, di, code) \ + HASHTAB_ITER(&(d)->dv_hashtab, di##hi_, { \ + { \ + dictitem_T *const di = TV_DICT_HI2DI(di##hi_); \ + { \ + code \ + } \ + } \ + }) + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "eval/typval.h.generated.h" #endif -- cgit From 2dcfc439b2ec2be4d830826061e89860977516be Mon Sep 17 00:00:00 2001 From: ZyX Date: Sat, 20 Aug 2016 23:56:49 +0300 Subject: eval: Split and move dict_add_nr_str to typval.c Function was split into tv_dict_add_nr() and tv_dict_add_str(). --- src/nvim/eval/typval.h | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/eval/typval.h') diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h index 6183397d12..6929e37e43 100644 --- a/src/nvim/eval/typval.h +++ b/src/nvim/eval/typval.h @@ -4,6 +4,7 @@ #include #include #include +#include #include "nvim/hashtab.h" #include "nvim/garray.h" -- cgit From 5cdf7177ec71e4b9b3295ead93bedf7ff226a2b2 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 21 Aug 2016 00:20:01 +0300 Subject: eval: Move get_float_arg to typval.h Assuming `inline` is there for a reason, so it is kept and function was moved to typval.h and not to typval.c which does not have problems with #including message.h. --- src/nvim/eval/typval.h | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) (limited to 'src/nvim/eval/typval.h') diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h index 6929e37e43..0eef2ddaac 100644 --- a/src/nvim/eval/typval.h +++ b/src/nvim/eval/typval.h @@ -13,6 +13,7 @@ #include "nvim/lib/queue.h" #include "nvim/profile.h" // for proftime_T #include "nvim/pos.h" // for linenr_T +#include "nvim/gettext.h" /// Type used for VimL VAR_NUMBER values typedef int varnumber_T; @@ -370,6 +371,32 @@ extern bool tv_in_free_unref_items; } \ }) +static inline bool tv_get_float(const typval_T *const tv, float_T *const ret_f) + REAL_FATTR_NONNULL_ALL REAL_FATTR_WARN_UNUSED_RESULT; + +// FIXME circular dependency, cannot import message.h. +bool emsgf(const char *const fmt, ...); + +/// Get the float value +/// +/// @param[in] tv VimL object to get value from. +/// @param[out] ret_f Location where resulting float is stored. +/// +/// @return true in case of success, false if tv is not a number or float. +static inline bool tv_get_float(const typval_T *const tv, float_T *const ret_f) +{ + if (tv->v_type == VAR_FLOAT) { + *ret_f = tv->vval.v_float; + return true; + } + if (tv->v_type == VAR_NUMBER) { + *ret_f = (float_T)tv->vval.v_number; + return true; + } + emsgf(_("E808: Number or Float required")); + return false; +} + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "eval/typval.h.generated.h" #endif -- cgit From 28dafe3ff0b0dc082fb62b2251fd64a167ce7188 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 21 Aug 2016 08:16:47 +0300 Subject: eval,*: Move get_tv_string to typval.c Function was renamed and changed to return `const char *`. --- src/nvim/eval/typval.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/nvim/eval/typval.h') diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h index 0eef2ddaac..5645772124 100644 --- a/src/nvim/eval/typval.h +++ b/src/nvim/eval/typval.h @@ -205,6 +205,8 @@ struct dictvar_S { /// Type used for script ID typedef int scid_T; +/// Format argument for scid_T +#define PRIdSCID "d" // Structure to hold info for a function that is currently being executed. typedef struct funccall_S funccall_T; -- cgit From 7ee5cc7429017a4a08a8b62b628bea156fea0008 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 28 Aug 2016 08:09:29 +0300 Subject: eval: Move get_tv_lnum and get_tv_float to eval/typval.h Additionally - Rename former tv_get_float to tv_get_float_chk due to name conflict (former get_tv_float is better suited for being tv_get_float). - Add E907 error to get_tv_float() and test that it is being raised when appropriate. --- src/nvim/eval/typval.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src/nvim/eval/typval.h') diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h index 5645772124..3c294b45b8 100644 --- a/src/nvim/eval/typval.h +++ b/src/nvim/eval/typval.h @@ -14,6 +14,7 @@ #include "nvim/profile.h" // for proftime_T #include "nvim/pos.h" // for linenr_T #include "nvim/gettext.h" +#include "nvim/message.h" /// Type used for VimL VAR_NUMBER values typedef int varnumber_T; @@ -373,7 +374,8 @@ extern bool tv_in_free_unref_items; } \ }) -static inline bool tv_get_float(const typval_T *const tv, float_T *const ret_f) +static inline bool tv_get_float_chk(const typval_T *const tv, + float_T *const ret_f) REAL_FATTR_NONNULL_ALL REAL_FATTR_WARN_UNUSED_RESULT; // FIXME circular dependency, cannot import message.h. @@ -381,11 +383,14 @@ bool emsgf(const char *const fmt, ...); /// Get the float value /// +/// Raises an error if object is not number or floating-point. +/// /// @param[in] tv VimL object to get value from. /// @param[out] ret_f Location where resulting float is stored. /// /// @return true in case of success, false if tv is not a number or float. -static inline bool tv_get_float(const typval_T *const tv, float_T *const ret_f) +static inline bool tv_get_float_chk(const typval_T *const tv, + float_T *const ret_f) { if (tv->v_type == VAR_FLOAT) { *ret_f = tv->vval.v_float; -- cgit From c8e63a8db84e9d9f7bd855085a87d93631504fc7 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 4 Sep 2016 02:25:24 +0300 Subject: eval: Move remaining get_tv_string* functions to eval/typval.c --- src/nvim/eval/typval.h | 1 + 1 file changed, 1 insertion(+) (limited to 'src/nvim/eval/typval.h') diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h index 3c294b45b8..42581939e3 100644 --- a/src/nvim/eval/typval.h +++ b/src/nvim/eval/typval.h @@ -27,6 +27,7 @@ typedef double float_T; /// Mimimal possible value of varnumber_T variable #define VARNUMBER_MIN INT_MIN +#define PRIdVARNUMBER "d" /// %d printf format specifier for varnumber_T #define PRIdVARNUMBER "d" -- cgit From 86fc4580b83f20211d7f85566e84a0e1dad0a136 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 4 Sep 2016 18:40:19 +0300 Subject: eval: Fix max_min functions Found two bugs: 1. Multiple unneeded error messages, vim/vim#1039. 2. Unformatted error string, vim/vim#1040. --- src/nvim/eval/typval.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/nvim/eval/typval.h') diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h index 42581939e3..3b41314b46 100644 --- a/src/nvim/eval/typval.h +++ b/src/nvim/eval/typval.h @@ -279,13 +279,13 @@ typedef struct list_stack_S { #define TV_DICT_HI2DI(hi) \ ((dictitem_T *)((hi)->hi_key - offsetof(dictitem_T, di_key))) -static inline long tv_list_len(list_T *const l) +static inline long tv_list_len(const list_T *const l) REAL_FATTR_PURE REAL_FATTR_WARN_UNUSED_RESULT; /// Get the number of items in a list /// /// @param[in] l List to check. -static inline long tv_list_len(list_T *const l) +static inline long tv_list_len(const list_T *const l) { if (l == NULL) { return 0; -- cgit From a32db8ed19c35847373d4a7fd56d7797a5a26897 Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 11 Sep 2016 03:54:13 +0300 Subject: eval/typval: Add missing includes, also add a script to find them Contains unfinished attempt to integrate IWYU (ref #549). To finish it different job should be done, specifically: - Instead of feeding IWYU with modified file a mirror source tree should be created with the help of CMake which will contain modified sources. This solves the problem with IWYU thinking that `*.generated.h` headers should be included in place of `*` headers. - Build IWYU as all other third-party utilities. - Make modified sources avoid problems with `nvim/func_attr.h` includes and various related tricks. Current script may only be used for manual checks like this: ./scripts/check-includes.py \ --generated-includes-dir build/include \ --generated-includes-dir build/src/nvim/auto \ --file src/nvim/eval/typval.c \ -- -Isrc -Ibuild/include -Ibuild/src/nvim/auto \ -DINCLUDE_GENERATED_DECLARATIONS (it is also somewhat fine with `--file src/nvim/eval/typval.h`). I have no idea why (I mean, why developer think that these lines are needed, why they are suggested is pretty obvious: because there is typedef which mentions them before structs are defined), but for typval.h it reports, among other things, that it should add lines struct dictvar_S; struct listitem_S; struct listvar_S; struct listwatch_S; --- src/nvim/eval/typval.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/nvim/eval/typval.h') diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h index 3b41314b46..791b191009 100644 --- a/src/nvim/eval/typval.h +++ b/src/nvim/eval/typval.h @@ -3,9 +3,11 @@ #include #include -#include +#include #include +#include +#include "nvim/types.h" #include "nvim/hashtab.h" #include "nvim/garray.h" #include "nvim/mbyte.h" -- cgit From 1e3e302dc2bdced563ecd2c3fb101af31f72b3df Mon Sep 17 00:00:00 2001 From: ZyX Date: Sun, 4 Dec 2016 21:58:19 +0300 Subject: eval: Move part of dictwatcher* functions to eval/typval --- src/nvim/eval/typval.h | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) (limited to 'src/nvim/eval/typval.h') diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h index 791b191009..fa0105197f 100644 --- a/src/nvim/eval/typval.h +++ b/src/nvim/eval/typval.h @@ -59,6 +59,7 @@ typedef struct { typedef struct dict_watcher { Callback callback; char *key_pattern; + size_t key_pattern_len; QUEUE node; bool busy; // prevent recursion if the dict is changed in the callback } DictWatcher; @@ -322,19 +323,6 @@ static inline bool tv_dict_is_watched(const dict_T *const d) return d && !QUEUE_EMPTY(&d->watchers); } -static inline DictWatcher *tv_dict_watcher_node_data(QUEUE *q) - REAL_FATTR_NONNULL_ALL REAL_FATTR_NONNULL_RET REAL_FATTR_PURE - REAL_FATTR_WARN_UNUSED_RESULT; - -/// Compute the `DictWatcher` address from a QUEUE node. -/// -/// This only exists for .asan-blacklist (ASAN doesn't handle QUEUE_DATA pointer -/// arithmetic). -static inline DictWatcher *tv_dict_watcher_node_data(QUEUE *q) -{ - return QUEUE_DATA(q, DictWatcher, node); -} - /// Initialize VimL object /// /// Initializes to unlocked VAR_UNKNOWN object. @@ -407,6 +395,19 @@ static inline bool tv_get_float_chk(const typval_T *const tv, return false; } +static inline DictWatcher *tv_dict_watcher_node_data(QUEUE *q) + REAL_FATTR_NONNULL_ALL REAL_FATTR_NONNULL_RET REAL_FATTR_PURE + REAL_FATTR_WARN_UNUSED_RESULT REAL_FATTR_ALWAYS_INLINE; + +/// Compute the `DictWatcher` address from a QUEUE node. +/// +/// This only exists for .asan-blacklist (ASAN doesn't handle QUEUE_DATA pointer +/// arithmetic). +static inline DictWatcher *tv_dict_watcher_node_data(QUEUE *q) +{ + return QUEUE_DATA(q, DictWatcher, node); +} + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "eval/typval.h.generated.h" #endif -- cgit From 43e9fad1c8835a3136f4db53c82608e034df2a5e Mon Sep 17 00:00:00 2001 From: ZyX Date: Mon, 13 Mar 2017 13:43:01 +0300 Subject: eval: Use tv_is_func in place of ==VAR_FUNC||==VAR_PARTIAL Also fixes same error as in vim/vim#1557 --- src/nvim/eval/typval.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'src/nvim/eval/typval.h') diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h index fa0105197f..7eab22bc12 100644 --- a/src/nvim/eval/typval.h +++ b/src/nvim/eval/typval.h @@ -408,6 +408,21 @@ static inline DictWatcher *tv_dict_watcher_node_data(QUEUE *q) return QUEUE_DATA(q, DictWatcher, node); } +static inline bool tv_is_func(const typval_T tv) + FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_CONST; + +/// Check whether given typval_T contains a function +/// +/// That is, whether it contains VAR_FUNC or VAR_PARTIAL. +/// +/// @param[in] tv Typval to check. +/// +/// @return True if it is a function or a partial, false otherwise. +static inline bool tv_is_func(const typval_T tv) +{ + return tv.v_type == VAR_FUNC || tv.v_type == VAR_PARTIAL; +} + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "eval/typval.h.generated.h" #endif -- cgit From b2942d1e729c4cfa8ec9d3bedcdc7ad838a689ef Mon Sep 17 00:00:00 2001 From: ZyX Date: Thu, 13 Apr 2017 19:16:32 +0300 Subject: eval: Change the point at which arg_errmsg and its length are changed Ref #6437 --- src/nvim/eval/typval.h | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'src/nvim/eval/typval.h') diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h index 7eab22bc12..df46222067 100644 --- a/src/nvim/eval/typval.h +++ b/src/nvim/eval/typval.h @@ -423,6 +423,17 @@ static inline bool tv_is_func(const typval_T tv) return tv.v_type == VAR_FUNC || tv.v_type == VAR_PARTIAL; } +/// Specify that argument needs to be translated +/// +/// Used for size_t length arguments to avoid calling gettext() and strlen() +/// unless needed. +#define TV_TRANSLATE (SIZE_MAX) + +/// Specify that argument is a NUL-terminated C string +/// +/// Used for size_t length arguments to avoid calling strlen() unless needed. +#define TV_CSTRING (SIZE_MAX - 1) + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "eval/typval.h.generated.h" #endif -- cgit From b54e5c220f0b1bff31ce65c6988f70cbb9780b5e Mon Sep 17 00:00:00 2001 From: ZyX Date: Fri, 14 Apr 2017 00:12:05 +0300 Subject: unittests: Add a test for TV_CSTRING MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Not using enum{} because SIZE_MAX exceeds integer and I do not really like how enum definition is described in C99: 1. Even though all values must fit into the chosen type (6.7.2.2, p 4) the type to choose is still implementation-defined. 2. 6.4.4.3 explicitly states that “an identifier declared as an enumeration constant has type `int`”. So it looks like “no matter what type was chosen for enumeration, constants will be integers”. Yet the following simple program: #include #include #include enum { X=SIZE_MAX }; int main(int argc, char **argv) { printf("x:%zu m:%zu t:%zu v:%zu", sizeof(X), sizeof(SIZE_MAX), sizeof(size_t), (size_t)X); } yields one of the following using different compilers: - clang/gcc/pathcc: `x:8 m:8 t:8 v:18446744073709551615` - pcc/tcc: `x:4 m:8 t:8 v:1844674407370955161` If I remove the cast of X to size_t then pcc/tcc both yield `x:4 m:8 t:8 v:4294967295`, other compilers’ output does not change. All compilers were called with `$compiler -std=c99 -xc -` (feeding program from echo), except for `tcc` which has missing `-std=c99`. `pcc` seems to ignore the argument though: it is perfectly fine with `-std=c1000`. --- src/nvim/eval/typval.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'src/nvim/eval/typval.h') diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h index df46222067..0f659727ee 100644 --- a/src/nvim/eval/typval.h +++ b/src/nvim/eval/typval.h @@ -17,6 +17,7 @@ #include "nvim/pos.h" // for linenr_T #include "nvim/gettext.h" #include "nvim/message.h" +#include "nvim/macros.h" /// Type used for VimL VAR_NUMBER values typedef int varnumber_T; @@ -434,6 +435,12 @@ static inline bool tv_is_func(const typval_T tv) /// Used for size_t length arguments to avoid calling strlen() unless needed. #define TV_CSTRING (SIZE_MAX - 1) +#ifdef UNIT_TESTING +// Do not use enum constants, see commit message. +EXTERN const size_t kTVCstring INIT(= TV_CSTRING); +EXTERN const size_t kTVTranslate INIT(= TV_TRANSLATE); +#endif + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "eval/typval.h.generated.h" #endif -- cgit From 81be7358be00d3d75453659bcdc7efc69207ca8e Mon Sep 17 00:00:00 2001 From: James McCoy Date: Wed, 16 Nov 2016 11:09:04 -0500 Subject: vim-patch:7.4.1976 Problem: Number variables are not 64 bits while they could be. Solution: Add the num64 feature. (Ken Takata) https://github.com/vim/vim/commit/22fcfad29276bd5f317faf516637dcd491b96a12 --- src/nvim/eval/typval.h | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'src/nvim/eval/typval.h') diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h index 0f659727ee..3f8ed3b3f9 100644 --- a/src/nvim/eval/typval.h +++ b/src/nvim/eval/typval.h @@ -1,7 +1,7 @@ #ifndef NVIM_EVAL_TYPVAL_H #define NVIM_EVAL_TYPVAL_H -#include +#include #include #include #include @@ -20,20 +20,21 @@ #include "nvim/macros.h" /// Type used for VimL VAR_NUMBER values -typedef int varnumber_T; +typedef int64_t varnumber_T; +typedef uint64_t uvarnumber_T; /// Type used for VimL VAR_FLOAT values typedef double float_T; /// Maximal possible value of varnumber_T variable -#define VARNUMBER_MAX INT_MAX +#define VARNUMBER_MAX INT64_MAX +#define UVARNUMBER_MAX UINT64_MAX /// Mimimal possible value of varnumber_T variable -#define VARNUMBER_MIN INT_MIN -#define PRIdVARNUMBER "d" +#define VARNUMBER_MIN INT64_MIN /// %d printf format specifier for varnumber_T -#define PRIdVARNUMBER "d" +#define PRIdVARNUMBER PRId64 typedef struct listvar_S list_T; typedef struct dictvar_S dict_T; -- cgit From 3a923ad2db87b2bece89616b28a14ab9826d569a Mon Sep 17 00:00:00 2001 From: ZyX Date: Mon, 17 Jul 2017 02:33:18 +0300 Subject: ex_getln: Replace global with entry in save_ccline --- src/nvim/eval/typval.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/nvim/eval/typval.h') diff --git a/src/nvim/eval/typval.h b/src/nvim/eval/typval.h index 3f8ed3b3f9..c44b85644d 100644 --- a/src/nvim/eval/typval.h +++ b/src/nvim/eval/typval.h @@ -43,7 +43,7 @@ typedef struct partial_S partial_T; typedef struct ufunc ufunc_T; typedef enum { - kCallbackNone, + kCallbackNone = 0, kCallbackFuncref, kCallbackPartial, } CallbackType; -- cgit