1#ifndef TREE_SITTER_LANGUAGE_H_
  2#define TREE_SITTER_LANGUAGE_H_
  3
  4#ifdef __cplusplus
  5extern "C" {
  6#endif
  7
  8#include "./subtree.h"
  9#include "tree_sitter/parser.h"
 10
 11#define ts_builtin_sym_error_repeat (ts_builtin_sym_error - 1)
 12
 13typedef struct {
 14  const TSParseAction *actions;
 15  uint32_t action_count;
 16  bool is_reusable;
 17} TableEntry;
 18
 19typedef struct {
 20  const TSLanguage *language;
 21  const uint16_t *data;
 22  const uint16_t *group_end;
 23  TSStateId state;
 24  uint16_t table_value;
 25  uint16_t section_index;
 26  uint16_t group_count;
 27  bool is_small_state;
 28
 29  const TSParseAction *actions;
 30  TSSymbol symbol;
 31  TSStateId next_state;
 32  uint16_t action_count;
 33} LookaheadIterator;
 34
 35void ts_language_table_entry(const TSLanguage *, TSStateId, TSSymbol, TableEntry *);
 36
 37TSSymbolMetadata ts_language_symbol_metadata(const TSLanguage *, TSSymbol);
 38
 39TSSymbol ts_language_public_symbol(const TSLanguage *, TSSymbol);
 40
 41TSStateId ts_language_next_state(const TSLanguage *self, TSStateId state, TSSymbol symbol);
 42
 43static inline bool ts_language_is_symbol_external(const TSLanguage *self, TSSymbol symbol) {
 44  return 0 < symbol && symbol < self->external_token_count + 1;
 45}
 46
 47static inline const TSParseAction *ts_language_actions(
 48  const TSLanguage *self,
 49  TSStateId state,
 50  TSSymbol symbol,
 51  uint32_t *count
 52) {
 53  TableEntry entry;
 54  ts_language_table_entry(self, state, symbol, &entry);
 55  *count = entry.action_count;
 56  return entry.actions;
 57}
 58
 59static inline bool ts_language_has_reduce_action(
 60  const TSLanguage *self,
 61  TSStateId state,
 62  TSSymbol symbol
 63) {
 64  TableEntry entry;
 65  ts_language_table_entry(self, state, symbol, &entry);
 66  return entry.action_count > 0 && entry.actions[0].type == TSParseActionTypeReduce;
 67}
 68
 69// Lookup the table value for a given symbol and state.
 70//
 71// For non-terminal symbols, the table value represents a successor state.
 72// For terminal symbols, it represents an index in the actions table.
 73// For 'large' parse states, this is a direct lookup. For 'small' parse
 74// states, this requires searching through the symbol groups to find
 75// the given symbol.
 76static inline uint16_t ts_language_lookup(
 77  const TSLanguage *self,
 78  TSStateId state,
 79  TSSymbol symbol
 80) {
 81  if (state >= self->large_state_count) {
 82    uint32_t index = self->small_parse_table_map[state - self->large_state_count];
 83    const uint16_t *data = &self->small_parse_table[index];
 84    uint16_t group_count = *(data++);
 85    for (unsigned i = 0; i < group_count; i++) {
 86      uint16_t section_value = *(data++);
 87      uint16_t symbol_count = *(data++);
 88      for (unsigned j = 0; j < symbol_count; j++) {
 89        if (*(data++) == symbol) return section_value;
 90      }
 91    }
 92    return 0;
 93  } else {
 94    return self->parse_table[state * self->symbol_count + symbol];
 95  }
 96}
 97
 98static inline bool ts_language_has_actions(
 99  const TSLanguage *self,
100  TSStateId state,
101  TSSymbol symbol
102) {
103  return ts_language_lookup(self, state, symbol) != 0;
104}
105
106// Iterate over all of the symbols that are valid in the given state.
107//
108// For 'large' parse states, this just requires iterating through
109// all possible symbols and checking the parse table for each one.
110// For 'small' parse states, this exploits the structure of the
111// table to only visit the valid symbols.
112static inline LookaheadIterator ts_language_lookaheads(
113  const TSLanguage *self,
114  TSStateId state
115) {
116  bool is_small_state = state >= self->large_state_count;
117  const uint16_t *data;
118  const uint16_t *group_end = NULL;
119  uint16_t group_count = 0;
120  if (is_small_state) {
121    uint32_t index = self->small_parse_table_map[state - self->large_state_count];
122    data = &self->small_parse_table[index];
123    group_end = data + 1;
124    group_count = *data;
125  } else {
126    data = &self->parse_table[state * self->symbol_count] - 1;
127  }
128  return (LookaheadIterator) {
129    .language = self,
130    .data = data,
131    .group_end = group_end,
132    .group_count = group_count,
133    .is_small_state = is_small_state,
134    .symbol = UINT16_MAX,
135    .next_state = 0,
136  };
137}
138
139static inline bool ts_lookahead_iterator__next(LookaheadIterator *self) {
140  // For small parse states, valid symbols are listed explicitly,
141  // grouped by their value. There's no need to look up the actions
142  // again until moving to the next group.
143  if (self->is_small_state) {
144    self->data++;
145    if (self->data == self->group_end) {
146      if (self->group_count == 0) return false;
147      self->group_count--;
148      self->table_value = *(self->data++);
149      unsigned symbol_count = *(self->data++);
150      self->group_end = self->data + symbol_count;
151      self->symbol = *self->data;
152    } else {
153      self->symbol = *self->data;
154      return true;
155    }
156  }
157
158  // For large parse states, iterate through every symbol until one
159  // is found that has valid actions.
160  else {
161    do {
162      self->data++;
163      self->symbol++;
164      if (self->symbol >= self->language->symbol_count) return false;
165      self->table_value = *self->data;
166    } while (!self->table_value);
167  }
168
169  // Depending on if the symbols is terminal or non-terminal, the table value either
170  // represents a list of actions or a successor state.
171  if (self->symbol < self->language->token_count) {
172    const TSParseActionEntry *entry = &self->language->parse_actions[self->table_value];
173    self->action_count = entry->entry.count;
174    self->actions = (const TSParseAction *)(entry + 1);
175    self->next_state = 0;
176  } else {
177    self->action_count = 0;
178    self->next_state = self->table_value;
179  }
180  return true;
181}
182
183// Whether the state is a "primary state". If this returns false, it indicates that there exists
184// another state that behaves identically to this one with respect to query analysis.
185static inline bool ts_language_state_is_primary(
186  const TSLanguage *self,
187  TSStateId state
188) {
189  if (self->version >= 14) {
190    return state == self->primary_state_ids[state];
191  } else {
192    return true;
193  }
194}
195
196static inline const bool *ts_language_enabled_external_tokens(
197  const TSLanguage *self,
198  unsigned external_scanner_state
199) {
200  if (external_scanner_state == 0) {
201    return NULL;
202  } else {
203    return self->external_scanner.states + self->external_token_count * external_scanner_state;
204  }
205}
206
207static inline const TSSymbol *ts_language_alias_sequence(
208  const TSLanguage *self,
209  uint32_t production_id
210) {
211  return production_id ?
212    &self->alias_sequences[production_id * self->max_alias_sequence_length] :
213    NULL;
214}
215
216static inline TSSymbol ts_language_alias_at(
217  const TSLanguage *self,
218  uint32_t production_id,
219  uint32_t child_index
220) {
221  return production_id ?
222    self->alias_sequences[production_id * self->max_alias_sequence_length + child_index] :
223    0;
224}
225
226static inline void ts_language_field_map(
227  const TSLanguage *self,
228  uint32_t production_id,
229  const TSFieldMapEntry **start,
230  const TSFieldMapEntry **end
231) {
232  if (self->field_count == 0) {
233    *start = NULL;
234    *end = NULL;
235    return;
236  }
237
238  TSFieldMapSlice slice = self->field_map_slices[production_id];
239  *start = &self->field_map_entries[slice.index];
240  *end = &self->field_map_entries[slice.index] + slice.length;
241}
242
243static inline void ts_language_aliases_for_symbol(
244  const TSLanguage *self,
245  TSSymbol original_symbol,
246  const TSSymbol **start,
247  const TSSymbol **end
248) {
249  *start = &self->public_symbol_map[original_symbol];
250  *end = *start + 1;
251
252  unsigned idx = 0;
253  for (;;) {
254    TSSymbol symbol = self->alias_map[idx++];
255    if (symbol == 0 || symbol > original_symbol) break;
256    uint16_t count = self->alias_map[idx++];
257    if (symbol == original_symbol) {
258      *start = &self->alias_map[idx];
259      *end = &self->alias_map[idx + count];
260      break;
261    }
262    idx += count;
263  }
264}
265
266static inline void ts_language_write_symbol_as_dot_string(
267  const TSLanguage *self,
268  FILE *f,
269  TSSymbol symbol
270) {
271  const char *name = ts_language_symbol_name(self, symbol);
272  for (const char *chr = name; *chr; chr++) {
273    switch (*chr) {
274      case '"':
275      case '\\':
276        fputc('\\', f);
277        fputc(*chr, f);
278        break;
279      case '\n':
280        fputs("\\n", f);
281        break;
282      case '\t':
283        fputs("\\t", f);
284        break;
285      default:
286        fputc(*chr, f);
287        break;
288    }
289  }
290}
291
292#ifdef __cplusplus
293}
294#endif
295
296#endif  // TREE_SITTER_LANGUAGE_H_