#ifndef TREE_SITTER_LANGUAGE_H_
#define TREE_SITTER_LANGUAGE_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "./subtree.h"
#include "./parser.h"
#define ts_builtin_sym_error_repeat (ts_builtin_sym_error - 1)
#define SMALL_STATE_BITMAP_FLAG 0x40000000u
#define SMALL_STATE_PAIR_FLAG 0x80000000u
#define SMALL_STATE_SET_FLAG (SMALL_STATE_BITMAP_FLAG | SMALL_STATE_PAIR_FLAG)
typedef struct {
const TSParseAction *actions;
uint32_t action_count;
bool is_reusable;
} TableEntry;
typedef enum {
LookaheadFresh, LookaheadPositioned, LookaheadDone, } LookaheadPhase;
typedef struct {
const TSLanguage *language;
const uint16_t *data;
const uint16_t *group_end;
const uint16_t *set_data;
uint32_t set_bits;
uint32_t set_symbol;
uint16_t table_value;
uint16_t group_count;
bool is_small_state;
bool is_pair_state;
bool is_bitmap_state;
bool is_set_state;
TSStateId state;
LookaheadPhase phase;
const TSParseAction *actions;
TSSymbol symbol;
TSStateId next_state;
uint16_t action_count;
} LookaheadIterator;
static inline bool ts_language_has_supported_abi(const TSLanguage *self) {
return self->abi_version == TREE_SITTER_LANGUAGE_VERSION;
}
static inline uint32_t ts_language__count_ones(uint32_t bits);
static inline uint32_t ts_language__trailing_zeros(uint32_t bits);
uint16_t ts_language_lookup_small_compact(const TSLanguage *self, uint32_t index, TSSymbol symbol);
void ts_language_table_entry(const TSLanguage *self, TSStateId state, TSSymbol symbol, TableEntry *result);
TSLexerMode ts_language_lex_mode_for_state(const TSLanguage *self, TSStateId state);
bool ts_language_is_reserved_word(const TSLanguage *self, TSStateId state, TSSymbol symbol);
TSSymbolMetadata ts_language_symbol_metadata(const TSLanguage *self, TSSymbol symbol);
TSSymbol ts_language_public_symbol(const TSLanguage *self, TSSymbol symbol);
const TSLanguage *ts_language_copy_without_callbacks(const TSLanguage *self);
#ifdef __wasm__
uint32_t ts_language_current_context_id(void);
#endif
static inline const TSParseAction *ts_language_actions(
const TSLanguage *self,
TSStateId state,
TSSymbol symbol,
uint32_t *count
) {
TableEntry entry;
ts_language_table_entry(self, state, symbol, &entry);
*count = entry.action_count;
return entry.actions;
}
static inline bool ts_parse_action_is_reduce(const TSParseAction *action) {
return action->type == TSParseActionTypeReduce || action->type == TSParseActionTypeReduceExtra;
}
static inline bool ts_table_entry_has_reduce_action(const TableEntry *entry) {
for (unsigned i = 0; i < entry->action_count; i++) {
if (ts_parse_action_is_reduce(&entry->actions[i])) return true;
}
return false;
}
static inline bool ts_language_has_reduce_action(
const TSLanguage *self,
TSStateId state,
TSSymbol symbol
) {
TableEntry entry;
ts_language_table_entry(self, state, symbol, &entry);
return ts_table_entry_has_reduce_action(&entry);
}
static inline uint16_t ts_language_lookup(
const TSLanguage *self,
TSStateId state,
TSSymbol symbol
) {
if (state >= self->large_state_count) {
uint32_t index = self->small_parse_table_map[state - self->large_state_count];
uint16_t value = ts_language_lookup_small_compact(self, index, symbol);
if (symbol >= self->token_count && value == UINT16_MAX && self->state_count <= UINT16_MAX) return state;
return value;
} else {
return self->parse_table[state * self->symbol_count + symbol];
}
}
static inline bool ts_language_has_actions(
const TSLanguage *self,
TSStateId state,
TSSymbol symbol
) {
return ts_language_lookup(self, state, symbol) != 0;
}
static inline LookaheadIterator ts_language_lookaheads(
const TSLanguage *self,
TSStateId state
) {
bool is_small_state = state >= self->large_state_count;
const uint16_t *data;
const uint16_t *group_end = NULL;
uint16_t group_count = 0;
bool is_pair_state = false;
bool is_bitmap_state = false;
bool is_set_state = false;
if (is_small_state) {
uint32_t index = self->small_parse_table_map[state - self->large_state_count];
uint32_t encoding = index & SMALL_STATE_SET_FLAG;
is_pair_state = encoding == SMALL_STATE_PAIR_FLAG;
is_bitmap_state = encoding == SMALL_STATE_BITMAP_FLAG;
is_set_state = encoding == SMALL_STATE_SET_FLAG;
uint32_t offset = index & ~(SMALL_STATE_PAIR_FLAG | SMALL_STATE_BITMAP_FLAG);
data = &self->small_parse_table[offset];
group_end = data + 1;
group_count = *data;
if (is_pair_state || is_set_state) data++;
if (is_set_state) group_end = NULL;
} else {
data = &self->parse_table[state * self->symbol_count];
}
return (LookaheadIterator) {
.language = self,
.data = data,
.group_end = group_end,
.group_count = group_count,
.is_small_state = is_small_state,
.is_pair_state = is_pair_state,
.is_bitmap_state = is_bitmap_state,
.is_set_state = is_set_state,
.state = state,
.phase = LookaheadFresh,
.symbol = UINT16_MAX,
.next_state = 0,
};
}
static inline bool ts_lookahead_iterator__next_set(LookaheadIterator *self);
static inline bool ts_lookahead_iterator__next_bitmap(LookaheadIterator *self);
static inline bool ts_lookahead_iterator__next_group(LookaheadIterator *self);
static inline bool ts_lookahead_iterator__next(LookaheadIterator *self) {
if (self->phase == LookaheadDone) return false;
bool advanced;
if (self->is_set_state) {
advanced = ts_lookahead_iterator__next_set(self);
} else if (self->is_bitmap_state) {
advanced = ts_lookahead_iterator__next_bitmap(self);
} else if (self->is_pair_state) {
advanced = self->group_count != 0;
if (advanced) {
self->group_count--;
self->symbol = *(self->data++);
self->table_value = *(self->data++);
}
} else if (self->is_small_state) {
if (self->phase == LookaheadPositioned && self->data + 1 < self->group_end) {
self->symbol = *(++self->data);
return true;
}
advanced = ts_lookahead_iterator__next_group(self);
} else {
uint32_t symbol = self->phase == LookaheadFresh ? 0 : self->symbol + 1;
while (symbol < self->language->symbol_count && !self->data[symbol]) symbol++;
advanced = symbol < self->language->symbol_count;
if (advanced) {
self->symbol = symbol;
self->table_value = self->data[symbol];
}
}
if (!advanced) {
self->phase = LookaheadDone;
return false;
}
if (self->symbol < self->language->token_count) {
const TSParseActionEntry *entry = &self->language->parse_actions[self->table_value];
self->action_count = entry->entry.count;
self->actions = (const TSParseAction *)(entry + 1);
self->next_state = 0;
} else {
self->action_count = 0;
self->next_state = self->table_value;
if (self->is_small_state &&
self->table_value == UINT16_MAX && self->language->state_count <= UINT16_MAX) {
self->next_state = self->state;
}
}
self->phase = LookaheadPositioned;
return true;
}
static inline bool ts_lookahead_iterator__next_set(LookaheadIterator *self) {
while (!self->set_bits) {
if (self->set_data != self->group_end) {
self->set_bits = *(self->set_data++);
self->set_symbol += 16;
} else if (self->group_count) {
self->group_count--;
self->table_value = *(self->data++);
uint32_t offset = self->data[0] | ((uint32_t)self->data[1] << 16);
self->data += 2;
const uint16_t *set = &self->language->small_parse_table[offset];
self->set_symbol = set[0] * 16u - 16;
self->set_data = set + 2;
self->group_end = self->set_data + set[1];
} else {
return false;
}
}
self->symbol = self->set_symbol + ts_language__trailing_zeros(self->set_bits);
self->set_bits &= self->set_bits - 1;
return true;
}
static inline bool ts_lookahead_iterator__next_bitmap(LookaheadIterator *self) {
uint32_t symbol = self->phase == LookaheadFresh ? 0 : self->symbol + 1;
uint32_t blocks = (self->language->symbol_count + 15) / 16;
uint32_t block = symbol / 16;
uint32_t bits = block < blocks ? self->data[block * 2] & (0xffffu << (symbol % 16)) : 0;
while (!bits && ++block < blocks) bits = self->data[block * 2];
if (block >= blocks) return false;
self->symbol = block * 16 + ts_language__trailing_zeros(bits);
uint32_t rank = self->data[block * 2 + 1] + ts_language__count_ones(
self->data[block * 2] & ((1u << (self->symbol % 16)) - 1)
);
self->table_value = self->data[blocks * 2 + rank];
return true;
}
static inline bool ts_lookahead_iterator__next_group(LookaheadIterator *self) {
if (self->group_count == 0) return false;
self->data++;
self->group_count--;
self->table_value = *(self->data++);
unsigned symbol_count = *(self->data++);
self->group_end = self->data + symbol_count;
self->symbol = *self->data;
return true;
}
static inline bool ts_language_state_is_primary(
const TSLanguage *self,
TSStateId state
) {
return state == self->primary_state_ids[state];
}
static inline uint32_t ts_language_external_state_stride(const TSLanguage *self) {
return self->external_state_stride ? self->external_state_stride : self->external_token_count;
}
static inline const bool *ts_language_enabled_external_tokens(
const TSLanguage *self,
unsigned external_scanner_state
) {
if (external_scanner_state == 0) {
return NULL;
} else {
return self->external_scanner.states + ts_language_external_state_stride(self) * external_scanner_state;
}
}
static inline uint32_t ts_language_alias_sequence_offset(const TSLanguage *self, uint32_t production_id) {
if (self->alias_sequence_offsets) {
return self->alias_sequence_offsets[production_id];
}
return production_id * self->max_alias_sequence_length;
}
static inline const TSSymbol *ts_language_alias_sequence(const TSLanguage *self, uint32_t production_id) {
uint32_t offset = ts_language_alias_sequence_offset(self, production_id);
return offset ? self->alias_sequences + offset : NULL;
}
static inline TSSymbol ts_language_alias_at(const TSLanguage *self, uint32_t production_id, uint32_t child_index) {
uint32_t offset = ts_language_alias_sequence_offset(self, production_id);
return offset ? self->alias_sequences[offset + child_index] : 0;
}
static inline void ts_language_field_map(
const TSLanguage *self,
uint32_t production_id,
const TSFieldMapEntry **start,
const TSFieldMapEntry **end
) {
if (self->field_count == 0) {
*start = NULL;
*end = NULL;
return;
}
TSMapSlice slice = self->field_map_slices[production_id];
*start = &self->field_map_entries[slice.index];
*end = &self->field_map_entries[slice.index] + slice.length;
}
static inline void ts_language_aliases_for_symbol(
const TSLanguage *self,
TSSymbol original_symbol,
const TSSymbol **start,
const TSSymbol **end
) {
*start = &self->public_symbol_map[original_symbol];
*end = *start + 1;
unsigned idx = 0;
for (;;) {
TSSymbol symbol = self->alias_map[idx++];
if (symbol == 0 || symbol > original_symbol) break;
uint16_t count = self->alias_map[idx++];
if (symbol == original_symbol) {
*start = &self->alias_map[idx];
*end = &self->alias_map[idx + count];
break;
}
idx += count;
}
}
static inline void ts_language_write_symbol_as_dot_string(
const TSLanguage *self,
FILE *f,
TSSymbol symbol
) {
const char *name = ts_language_symbol_name(self, symbol);
for (const char *chr = name; *chr; chr++) {
switch (*chr) {
case '"':
case '\\':
fputc('\\', f);
fputc(*chr, f);
break;
case '\n':
fputs("\\n", f);
break;
case '\t':
fputs("\\t", f);
break;
default:
fputc(*chr, f);
break;
}
}
}
static inline uint32_t ts_language__count_ones(uint32_t bits) {
#if defined(__clang__) || defined(__GNUC__)
return __builtin_popcount(bits);
#else
bits -= (bits >> 1) & 0x5555u;
bits = (bits & 0x3333u) + ((bits >> 2) & 0x3333u);
bits = (bits + (bits >> 4)) & 0x0f0fu;
return ((bits * 0x0101u) >> 8) & 0x1fu;
#endif
}
static inline uint32_t ts_language__trailing_zeros(uint32_t bits) {
#if defined(__clang__) || defined(__GNUC__)
return __builtin_ctz(bits);
#else
uint32_t count = 0;
while (!(bits & 1)) {
bits >>= 1;
count++;
}
return count;
#endif
}
#ifdef __cplusplus
}
#endif
#endif