aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/viml/parser/parser.h
blob: 231e43b4c77728bcf1631273e0f7b4a99378cda3 (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
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
#ifndef NVIM_VIML_PARSER_PARSER_H
#define NVIM_VIML_PARSER_PARSER_H

#include <stdbool.h>
#include <stddef.h>
#include <assert.h>

#include "nvim/lib/kvec.h"
#include "nvim/func_attr.h"
#include "nvim/mbyte.h"

/// One parsed line
typedef struct {
  const char *data;  ///< Parsed line pointer
  size_t size;  ///< Parsed line size
  bool allocated;  ///< True if line may be freed.
} ParserLine;

/// Line getter type for parser
///
/// Line getter must return {NULL, 0} for EOF.
typedef void (*ParserLineGetter)(void *cookie, ParserLine *ret_pline);

/// Parser position in the input
typedef struct {
  size_t line;  ///< Line index in ParserInputReader.lines.
  size_t col;  ///< Byte index in the line.
} ParserPosition;

/// Parser state item.
typedef struct {
  enum {
    kPTopStateParsingCommand = 0,
    kPTopStateParsingExpression,
  } type;
  union {
    struct {
      enum {
        kExprUnknown = 0,
      } type;
    } expr;
  } data;
} ParserStateItem;

/// Structure defining input reader
typedef struct {
  /// Function used to get next line.
  ParserLineGetter get_line;
  /// Data for get_line function.
  void *cookie;
  /// All lines obtained by get_line.
  kvec_withinit_t(ParserLine, 4) lines;
  /// Conversion, for :scriptencoding.
  vimconv_T conv;
} ParserInputReader;

/// Highlighted region definition
///
/// Note: one chunk may highlight only one line.
typedef struct {
  ParserPosition start;  ///< Start of the highlight: line and column.
  size_t end_col;  ///< End column, points to the start of the next character.
  const char *group;  ///< Highlight group.
} ParserHighlightChunk;

/// Highlighting defined by a parser
typedef kvec_withinit_t(ParserHighlightChunk, 16) ParserHighlight;

/// Structure defining parser state
typedef struct {
  /// Line reader.
  ParserInputReader reader;
  /// Position up to which input was parsed.
  ParserPosition pos;
  /// Parser state stack.
  kvec_withinit_t(ParserStateItem, 16) stack;
  /// Highlighting support.
  ParserHighlight *colors;
  /// True if line continuation can be used.
  bool can_continuate;
} ParserState;

static inline void viml_preader_get_line(ParserInputReader *const preader,
                                         ParserLine *const ret_pline)
  REAL_FATTR_NONNULL_ALL;

/// Get one line from ParserInputReader
static inline void viml_preader_get_line(ParserInputReader *const preader,
                                         ParserLine *const ret_pline)
{
  ParserLine pline;
  preader->get_line(preader->cookie, &pline);
  if (preader->conv.vc_type != CONV_NONE && pline.size) {
    ParserLine cpline = {
      .allocated = true,
      .size = pline.size,
    };
    cpline.data = (char *)string_convert(&preader->conv,
                                         (char_u *)pline.data,
                                         &cpline.size);
    if (pline.allocated) {
      xfree((void *)pline.data);
    }
    pline = cpline;
  }
  kvi_push(preader->lines, pline);
  *ret_pline = pline;
}

static inline bool viml_parser_get_remaining_line(ParserState *const pstate,
                                                  ParserLine *const ret_pline)
  REAL_FATTR_ALWAYS_INLINE REAL_FATTR_WARN_UNUSED_RESULT REAL_FATTR_NONNULL_ALL;

/// Get currently parsed line, shifted to pstate->pos.col
///
/// @param  pstate  Parser state to operate on.
///
/// @return True if there is a line, false in case of EOF.
static inline bool viml_parser_get_remaining_line(ParserState *const pstate,
                                                  ParserLine *const ret_pline)
{
  const size_t num_lines = kv_size(pstate->reader.lines);
  if (pstate->pos.line == num_lines) {
    viml_preader_get_line(&pstate->reader, ret_pline);
  } else {
    *ret_pline = kv_last(pstate->reader.lines);
  }
  assert(pstate->pos.line == kv_size(pstate->reader.lines) - 1);
  if (ret_pline->data != NULL) {
    ret_pline->data += pstate->pos.col;
    ret_pline->size -= pstate->pos.col;
  }
  return ret_pline->data != NULL;
}

static inline void viml_parser_advance(ParserState *const pstate,
                                       const size_t len)
  REAL_FATTR_ALWAYS_INLINE REAL_FATTR_NONNULL_ALL;

/// Advance position by a given number of bytes
///
/// At maximum advances to the next line.
///
/// @param  pstate  Parser state to advance.
/// @param[in]  len  Number of bytes to advance.
static inline void viml_parser_advance(ParserState *const pstate,
                                       const size_t len)
{
  assert(pstate->pos.line == kv_size(pstate->reader.lines) - 1);
  const ParserLine pline = kv_last(pstate->reader.lines);
  if (pstate->pos.col + len >= pline.size) {
    pstate->pos.line++;
    pstate->pos.col = 0;
  } else {
    pstate->pos.col += len;
  }
}

#endif  // NVIM_VIML_PARSER_PARSER_H