aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/eval/typval_encode.h
blob: 854778321371e4eac5d278775a841db1dd571df9 (plain) (blame)
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/// @file eval/typval_encode.h
///
/// Contains common definitions for eval/typval_encode.c.h. Most of time should
/// not be included directly.
#pragma once

#include <assert.h>
#include <inttypes.h>
#include <stddef.h>
#include <string.h>

#include "klib/kvec.h"
#include "nvim/eval/typval_defs.h"

#ifdef INCLUDE_GENERATED_DECLARATIONS
# include "eval/typval_encode.h.inline.generated.h"
#endif

/// Type of the stack entry
typedef enum {
  kMPConvDict,  ///< Convert dict_T *dictionary.
  kMPConvList,  ///< Convert list_T *list.
  kMPConvPairs,  ///< Convert mapping represented as a list_T* of pairs.
  kMPConvPartial,  ///< Convert partial_T* partial.
  kMPConvPartialList,  ///< Convert argc/argv pair coming from a partial.
} MPConvStackValType;

/// Stage at which partial is being converted
typedef enum {
  kMPConvPartialArgs,  ///< About to convert arguments.
  kMPConvPartialSelf,  ///< About to convert self dictionary.
  kMPConvPartialEnd,  ///< Already converted everything.
} MPConvPartialStage;

/// Structure representing current Vimscript to messagepack conversion state
typedef struct {
  MPConvStackValType type;  ///< Type of the stack entry.
  typval_T *tv;  ///< Currently converted typval_T.
  int saved_copyID;  ///< copyID item used to have.
  union {
    struct {
      dict_T *dict;    ///< Currently converted dictionary.
      dict_T **dictp;  ///< Location where that dictionary is stored.
                       ///< Normally it is &.tv->vval.v_dict, but not when
                       ///< converting partials.
      hashitem_T *hi;  ///< Currently converted dictionary item.
      size_t todo;     ///< Amount of items left to process.
    } d;  ///< State of dictionary conversion.
    struct {
      list_T *list;    ///< Currently converted list.
      listitem_T *li;  ///< Currently converted list item.
    } l;  ///< State of list or generic mapping conversion.
    struct {
      MPConvPartialStage stage;  ///< Stage at which partial is being converted.
      partial_T *pt;  ///< Currently converted partial.
    } p;  ///< State of partial conversion.
    struct {
      typval_T *arg;    ///< Currently converted argument.
      typval_T *argv;    ///< Start of the argument list.
      size_t todo;  ///< Number of items left to process.
    } a;  ///< State of list or generic mapping conversion.
  } data;  ///< Data to convert.
} MPConvStackVal;

/// Stack used to convert Vimscript values to messagepack.
typedef kvec_withinit_t(MPConvStackVal, 8) MPConvStack;

/// Length of the string stored in typval_T
///
/// @param[in]  tv  String for which to compute length for. Must be typval_T
///                 with VAR_STRING.
///
/// @return Length of the string stored in typval_T, including 0 for NULL
///         string.
static inline size_t tv_strlen(const typval_T *const tv)
  FUNC_ATTR_ALWAYS_INLINE FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT
  FUNC_ATTR_NONNULL_ALL
{
  assert(tv->v_type == VAR_STRING);
  return (tv->vval.v_string == NULL ? 0 : strlen(tv->vval.v_string));
}

/// Code for checking whether container references itself
///
/// @param[in,out]  val  Container to check.
/// @param  copyID_attr  Name of the container attribute that holds copyID.
///                      After checking whether value of this attribute is
///                      copyID (variable) it is set to copyID.
/// @param[in]  copyID  CopyID used by the caller.
/// @param  conv_type  Type of the conversion, @see MPConvStackValType.
#define TYPVAL_ENCODE_DO_CHECK_SELF_REFERENCE(val, copyID_attr, copyID, \
                                              conv_type) \
  do { \
    const int te_csr_ret = TYPVAL_ENCODE_CHECK_SELF_REFERENCE(TYPVAL_ENCODE_FIRST_ARG_NAME, \
                                                              (val), &(val)->copyID_attr, mpstack, \
                                                              copyID, conv_type, objname); \
    if (te_csr_ret != NOTDONE) { \
      return te_csr_ret; \
    } \
  } while (0)

#define TYPVAL_ENCODE_FUNC_NAME_INNER_2(pref, name, suf) \
  pref##name##suf
#define TYPVAL_ENCODE_FUNC_NAME_INNER(pref, name, suf) \
  TYPVAL_ENCODE_FUNC_NAME_INNER_2(pref, name, suf)

/// Construct function name, possibly using macros
///
/// Is used to expand macros that may appear in arguments.
///
/// @note Expands all arguments, even if only one is needed.
///
/// @param[in]  pref  Prefix.
/// @param[in]  suf  Suffix.
///
/// @return Concat: pref + #TYPVAL_ENCODE_NAME + suf.
#define TYPVAL_ENCODE_FUNC_NAME(pref, suf) \
  TYPVAL_ENCODE_FUNC_NAME_INNER(pref, TYPVAL_ENCODE_NAME, suf)

/// Self reference checker function name
#define TYPVAL_ENCODE_CHECK_SELF_REFERENCE \
  TYPVAL_ENCODE_FUNC_NAME(_typval_encode_, _check_self_reference)

/// Entry point function name
#define TYPVAL_ENCODE_ENCODE \
  TYPVAL_ENCODE_FUNC_NAME(encode_vim_to_, )

/// Name of the …convert_one_value function
#define TYPVAL_ENCODE_CONVERT_ONE_VALUE \
  TYPVAL_ENCODE_FUNC_NAME(_typval_encode_, _convert_one_value)

/// Name of the dummy const dict_T *const variable
#define TYPVAL_ENCODE_NODICT_VAR \
  TYPVAL_ENCODE_FUNC_NAME(_typval_encode_, _nodict_var)