#include "./language.h"
#include "./atomic.h"
#include "./wasm_store.h"
#include "tree_sitter/api.h"
#include <stddef.h>
#include <string.h>
#ifdef __wasm__
typedef struct {
TSLanguage language;
volatile uint32_t ref_count;
} TSUnparseableLanguage;
static volatile uint32_t ts_language_next_context_id;
__asm__(
".globaltype ts_language_context_id, i32\n"
"ts_language_context_id:\n"
);
static inline TSUnparseableLanguage *ts_language__unparseable(const TSLanguage *self) {
return (TSUnparseableLanguage *)((char *)self - offsetof(TSUnparseableLanguage, language));
}
static inline bool ts_language__is_unparseable(const TSLanguage *self) {
return (
self &&
!self->lex_fn &&
self->external_scanner.states == (const bool *)self
);
}
uint32_t ts_language_current_context_id(void) {
uint32_t result;
__asm__(
"global.get ts_language_context_id\n"
"local.set %0\n"
: "=r"(result)
);
if (!result) {
result = atomic_inc(&ts_language_next_context_id);
__asm__(
"local.get %0\n"
"global.set ts_language_context_id\n"
:
: "r"(result)
);
}
return result;
}
#endif
const TSLanguage *ts_language_copy(const TSLanguage *self) {
#ifdef __wasm__
if (ts_language__is_unparseable(self)) {
atomic_inc(&ts_language__unparseable(self)->ref_count);
} else
#endif
if (self && ts_language_is_wasm(self)) {
ts_wasm_language_retain(self);
}
return self;
}
void ts_language_delete(const TSLanguage *self) {
#ifdef __wasm__
if (ts_language__is_unparseable(self)) {
TSUnparseableLanguage *language = ts_language__unparseable(self);
if (atomic_dec(&language->ref_count) == 0) {
ts_free(language);
}
} else
#endif
if (self && ts_language_is_wasm(self)) {
ts_wasm_language_release(self);
}
}
bool ts_language_is_parseable(const TSLanguage *self) {
return self && self->lex_fn;
}
const TSLanguage *ts_language_copy_without_callbacks(const TSLanguage *self) {
#ifdef __wasm__
if (self && ts_language_is_parseable(self)) {
TSUnparseableLanguage *result = ts_calloc(1, sizeof(TSUnparseableLanguage));
memcpy(&result->language, self, sizeof(TSLanguage));
result->language.lex_fn = NULL;
result->language.keyword_lex_fn = NULL;
result->language.keyword_lookup_fn = NULL;
result->language.external_scanner.states = (const bool *)&result->language;
result->language.external_scanner.create = NULL;
result->language.external_scanner.destroy = NULL;
result->language.external_scanner.scan = NULL;
result->language.external_scanner.serialize = NULL;
result->language.external_scanner.deserialize = NULL;
result->ref_count = 1;
return &result->language;
}
#endif
return ts_language_copy(self);
}
uint32_t ts_language_symbol_count(const TSLanguage *self) {
return self->symbol_count + self->alias_count;
}
uint32_t ts_language_state_count(const TSLanguage *self) {
return self->state_count;
}
const TSSymbol *ts_language_supertypes(const TSLanguage *self, uint32_t *length) {
if (!ts_language_has_supported_abi(self)) {
*length = 0;
return NULL;
}
*length = self->supertype_count;
return self->supertype_symbols;
}
const TSSymbol *ts_language_subtypes(
const TSLanguage *self,
TSSymbol supertype,
uint32_t *length
) {
if (!ts_language_has_supported_abi(self) || supertype >= ts_language_symbol_count(self)) {
*length = 0;
return NULL;
}
supertype = ts_language_public_symbol(self, supertype);
if (!ts_language_symbol_metadata(self, supertype).supertype) {
*length = 0;
return NULL;
}
TSMapSlice slice = self->supertype_map_slices[supertype];
*length = slice.length;
return &self->supertype_map_entries[slice.index];
}
uint32_t ts_language_abi_version(const TSLanguage *self) {
return self->abi_version;
}
const TSLanguageMetadata *ts_language_metadata(const TSLanguage *self) {
return ts_language_has_supported_abi(self) ? &self->metadata : NULL;
}
const char *ts_language_name(const TSLanguage *self) {
return ts_language_has_supported_abi(self) ? self->name : NULL;
}
uint32_t ts_language_field_count(const TSLanguage *self) {
return self->field_count;
}
void ts_language_table_entry(
const TSLanguage *self,
TSStateId state,
TSSymbol symbol,
TableEntry *result
) {
if (symbol == ts_builtin_sym_error || symbol == ts_builtin_sym_error_repeat) {
result->action_count = 0;
result->is_reusable = false;
result->actions = NULL;
} else {
ts_assert(symbol < self->token_count);
uint32_t action_index = ts_language_lookup(self, state, symbol);
const TSParseActionEntry *entry = &self->parse_actions[action_index];
result->action_count = entry->entry.count;
result->is_reusable = entry->entry.reusable;
result->actions = (const TSParseAction *)(entry + 1);
}
}
static uint16_t ts_language_lookup_shared_set(const TSLanguage *self, uint32_t index, TSSymbol symbol);
static uint16_t ts_language_lookup_grouped(const uint16_t *data, TSSymbol symbol);
uint16_t ts_language_lookup_small_compact(
const TSLanguage *self,
uint32_t index,
TSSymbol symbol
) {
if ((index & SMALL_STATE_SET_FLAG) == SMALL_STATE_SET_FLAG) {
return ts_language_lookup_shared_set(self, index, symbol);
}
if (index & SMALL_STATE_BITMAP_FLAG) {
if (symbol >= self->symbol_count) return 0;
const uint16_t *data = &self->small_parse_table[index & ~SMALL_STATE_BITMAP_FLAG];
uint32_t block = symbol / 16;
uint32_t bit = 1u << (symbol % 16);
uint32_t bits = data[block * 2];
if (!(bits & bit)) return 0;
uint32_t rank = data[block * 2 + 1] + ts_language__count_ones(bits & (bit - 1));
return data[2 * ((self->symbol_count + 15) / 16) + rank];
}
if (index & SMALL_STATE_PAIR_FLAG) {
const uint16_t *pairs = &self->small_parse_table[index & ~SMALL_STATE_PAIR_FLAG];
uint32_t low = 0, high = *(pairs++);
while (low < high) {
uint32_t mid = low + (high - low) / 2;
TSSymbol candidate = pairs[mid * 2];
if (candidate < symbol) low = mid + 1;
else if (candidate > symbol) high = mid;
else return pairs[mid * 2 + 1];
}
return 0;
}
return ts_language_lookup_grouped(&self->small_parse_table[index], symbol);
}
static uint16_t ts_language_lookup_grouped(const uint16_t *data, TSSymbol symbol) {
uint16_t group_count = *(data++);
for (unsigned i = 0; i < group_count; i++) {
uint16_t section_value = *(data++);
uint16_t symbol_count = *(data++);
if (symbol_count >= 16) {
uint32_t low = 0, high = symbol_count;
while (low < high) {
uint32_t mid = low + (high - low) / 2;
if (data[mid] < symbol) low = mid + 1;
else if (data[mid] > symbol) high = mid;
else return section_value;
}
data += symbol_count;
continue;
}
while (symbol_count >= 4) {
bool matches = data[0] == symbol;
matches |= data[1] == symbol;
matches |= data[2] == symbol;
matches |= data[3] == symbol;
if (matches) return section_value;
data += 4;
symbol_count -= 4;
}
for (unsigned j = 0; j < symbol_count; j++) {
if (*(data++) == symbol) return section_value;
}
}
return 0;
}
static uint16_t ts_language_lookup_shared_set(const TSLanguage *self, uint32_t index, TSSymbol symbol) {
const uint16_t *data = &self->small_parse_table[index & ~SMALL_STATE_SET_FLAG];
uint32_t count = *(data++);
uint32_t block = symbol / 16;
uint32_t bit = 1u << (symbol % 16);
for (uint32_t i = 0; i < count; i++, data += 3) {
uint32_t offset = data[1] | ((uint32_t)data[2] << 16);
const uint16_t *set = &self->small_parse_table[offset];
uint32_t word = block - set[0];
if (word < set[1] && (set[word + 2] & bit)) return data[0];
}
return 0;
}
TSLexerMode ts_language_lex_mode_for_state(
const TSLanguage *self,
TSStateId state
) {
if (self->lex_mode_ids) state = self->lex_mode_ids[state];
return self->lex_modes[state];
}
bool ts_language_is_reserved_word(
const TSLanguage *self,
TSStateId state,
TSSymbol symbol
) {
TSLexerMode lex_mode = ts_language_lex_mode_for_state(self, state);
if (lex_mode.reserved_word_set_id > 0) {
unsigned start = lex_mode.reserved_word_set_id * self->max_reserved_word_set_size;
unsigned end = start + self->max_reserved_word_set_size;
if (self->reserved_word_slices) {
TSMapSlice slice = self->reserved_word_slices[lex_mode.reserved_word_set_id];
start = slice.index;
end = start + slice.length;
}
for (unsigned i = start; i < end; i++) {
if (self->reserved_words[i] == symbol) return true;
if (self->reserved_words[i] == 0) break;
}
}
return false;
}
TSSymbolMetadata ts_language_symbol_metadata(
const TSLanguage *self,
TSSymbol symbol
) {
if (symbol == ts_builtin_sym_error) {
return (TSSymbolMetadata) {.visible = true, .named = true};
} else if (symbol == ts_builtin_sym_error_repeat) {
return (TSSymbolMetadata) {.visible = false, .named = false};
} else {
return self->symbol_metadata[symbol];
}
}
TSSymbol ts_language_public_symbol(
const TSLanguage *self,
TSSymbol symbol
) {
if (symbol == ts_builtin_sym_error) return symbol;
return self->public_symbol_map[symbol];
}
TSStateId ts_language_next_state(
const TSLanguage *self,
TSStateId state,
TSSymbol symbol
) {
if (
symbol == ts_builtin_sym_error ||
symbol == ts_builtin_sym_error_repeat ||
symbol >= self->symbol_count ||
state >= self->state_count
) {
return 0;
} else if (symbol < self->token_count) {
uint32_t count;
const TSParseAction *actions = ts_language_actions(self, state, symbol, &count);
if (count > 0) {
TSParseAction action = actions[count - 1];
if (action.type == TSParseActionTypeShift) {
return action.shift.extra ? state : action.shift.state;
}
}
return 0;
} else {
return ts_language_lookup(self, state, symbol);
}
}
const char *ts_language_symbol_name(
const TSLanguage *self,
TSSymbol symbol
) {
if (symbol == ts_builtin_sym_error) {
return "ERROR";
} else if (symbol == ts_builtin_sym_error_repeat) {
return "_ERROR";
} else if (symbol < ts_language_symbol_count(self)) {
return self->symbol_names[symbol];
} else {
return NULL;
}
}
TSSymbol ts_language_symbol_for_name(
const TSLanguage *self,
const char *string,
uint32_t length,
bool is_named
) {
if (is_named && length == 5 && !strncmp(string, "ERROR", length)) return ts_builtin_sym_error;
uint16_t count = (uint16_t)ts_language_symbol_count(self);
for (TSSymbol i = 0; i < count; i++) {
TSSymbolMetadata metadata = ts_language_symbol_metadata(self, i);
if ((!metadata.visible && !metadata.supertype) || metadata.named != is_named) continue;
const char *symbol_name = self->symbol_names[i];
if (!strncmp(symbol_name, string, length) && !symbol_name[length]) {
return self->public_symbol_map[i];
}
}
return 0;
}
TSSymbolType ts_language_symbol_type(
const TSLanguage *self,
TSSymbol symbol
) {
TSSymbolMetadata metadata = ts_language_symbol_metadata(self, symbol);
if (metadata.named && metadata.visible) {
return TSSymbolTypeRegular;
} else if (metadata.visible) {
return TSSymbolTypeAnonymous;
} else if (metadata.supertype) {
return TSSymbolTypeSupertype;
} else {
return TSSymbolTypeAuxiliary;
}
}
const char *ts_language_field_name_for_id(
const TSLanguage *self,
TSFieldId id
) {
uint32_t count = ts_language_field_count(self);
if (count && id <= count) {
return self->field_names[id];
} else {
return NULL;
}
}
TSFieldId ts_language_field_id_for_name(
const TSLanguage *self,
const char *name,
uint32_t name_length
) {
uint16_t count = (uint16_t)ts_language_field_count(self);
for (TSSymbol i = 1; i < count + 1; i++) {
switch (strncmp(name, self->field_names[i], name_length)) {
case 0:
if (self->field_names[i][name_length] == 0) return i;
break;
case -1:
return 0;
default:
break;
}
}
return 0;
}
TSLookaheadIterator *ts_lookahead_iterator_new(const TSLanguage *self, TSStateId state) {
if (state >= self->state_count) return NULL;
LookaheadIterator *iterator = ts_malloc(sizeof(LookaheadIterator));
*iterator = ts_language_lookaheads(ts_language_copy(self), state);
return (TSLookaheadIterator *)iterator;
}
void ts_lookahead_iterator_delete(TSLookaheadIterator *self) {
if (!self) return;
LookaheadIterator *iterator = (LookaheadIterator *)self;
ts_language_delete(iterator->language);
ts_free(iterator);
}
bool ts_lookahead_iterator_reset_state(TSLookaheadIterator * self, TSStateId state) {
LookaheadIterator *iterator = (LookaheadIterator *)self;
if (state >= iterator->language->state_count) return false;
*iterator = ts_language_lookaheads(iterator->language, state);
return true;
}
const TSLanguage *ts_lookahead_iterator_language(const TSLookaheadIterator *self) {
const LookaheadIterator *iterator = (const LookaheadIterator *)self;
return iterator->language;
}
bool ts_lookahead_iterator_reset(TSLookaheadIterator *self, const TSLanguage *language, TSStateId state) {
if (state >= language->state_count) return false;
LookaheadIterator *iterator = (LookaheadIterator *)self;
const TSLanguage *previous = iterator->language;
*iterator = ts_language_lookaheads(ts_language_copy(language), state);
ts_language_delete(previous);
return true;
}
bool ts_lookahead_iterator_next(TSLookaheadIterator *self) {
LookaheadIterator *iterator = (LookaheadIterator *)self;
return ts_lookahead_iterator__next(iterator);
}
TSSymbol ts_lookahead_iterator_current_symbol(const TSLookaheadIterator *self) {
const LookaheadIterator *iterator = (const LookaheadIterator *)self;
return iterator->symbol;
}
const char *ts_lookahead_iterator_current_symbol_name(const TSLookaheadIterator *self) {
const LookaheadIterator *iterator = (const LookaheadIterator *)self;
if (iterator->phase != LookaheadPositioned) return NULL;
return ts_language_symbol_name(iterator->language, iterator->symbol);
}