feat: add Supertype API

Introduces a new function that takes in a supertype symbol and returns
all associated subtypes. Can be used by query.c to give better errors
for invalid subtypes, as well as downstream applications like the query
LSP to give better diagnostics.
This commit is contained in:
Riley Bruins 2024-11-12 11:43:00 -08:00 committed by Amaan Qureshi
parent 07c08432ca
commit 19482834bd
11 changed files with 459 additions and 78 deletions

View file

@ -24,6 +24,31 @@ 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 (self->version >= LANGUAGE_VERSION_WITH_RESERVED_WORDS) {
*length = self->supertype_count;
return self->supertype_symbols;
} else {
*length = 0;
return NULL;
}
}
const TSSymbol *ts_language_subtypes(
const TSLanguage *self,
TSSymbol supertype,
uint32_t *length
) {
if (self->version < LANGUAGE_VERSION_WITH_RESERVED_WORDS || !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_version(const TSLanguage *self) {
return self->version;
}

View file

@ -236,7 +236,7 @@ static inline void ts_language_field_map(
return;
}
TSFieldMapSlice slice = self->field_map_slices[production_id];
TSMapSlice slice = self->field_map_slices[production_id];
*start = &self->field_map_entries[slice.index];
*end = &self->field_map_entries[slice.index] + slice.length;
}

View file

@ -26,10 +26,11 @@ typedef struct {
bool inherited;
} TSFieldMapEntry;
// Used to index the field and supertype maps.
typedef struct {
uint16_t index;
uint16_t length;
} TSFieldMapSlice;
} TSMapSlice;
typedef struct {
bool visible;
@ -115,7 +116,7 @@ struct TSLanguage {
const TSParseActionEntry *parse_actions;
const char * const *symbol_names;
const char * const *field_names;
const TSFieldMapSlice *field_map_slices;
const TSMapSlice *field_map_slices;
const TSFieldMapEntry *field_map_entries;
const TSSymbolMetadata *symbol_metadata;
const TSSymbol *public_symbol_map;
@ -138,6 +139,10 @@ struct TSLanguage {
const char *name;
const TSSymbol *reserved_words;
uint16_t max_reserved_word_set_size;
uint32_t supertype_count;
const TSSymbol *supertype_symbols;
const TSMapSlice *supertype_map_slices;
const TSSymbol *supertype_map_entries;
};
static inline bool set_contains(const TSCharacterRange *ranges, uint32_t len, int32_t lookahead) {

View file

@ -156,6 +156,10 @@ typedef struct {
int32_t name;
int32_t reserved_words;
uint16_t max_reserved_word_set_size;
uint32_t supertype_count;
int32_t supertype_symbols;
int32_t supertype_map_slices;
int32_t supertype_map_entries;
} LanguageInWasmMemory;
// LexerInWasmMemory - The memory layout of a `TSLexer` when compiled to wasm32.
@ -1234,6 +1238,9 @@ const TSLanguage *ts_wasm_store_load_language(
wasm_language.primary_state_ids,
wasm_language.name,
wasm_language.reserved_words,
wasm_language.supertype_symbols,
wasm_language.supertype_map_entries,
wasm_language.supertype_map_slices,
wasm_language.external_token_count > 0 ? wasm_language.external_scanner.states : 0,
wasm_language.external_token_count > 0 ? wasm_language.external_scanner.symbol_map : 0,
wasm_language.external_token_count > 0 ? wasm_language.external_scanner.create : 0,
@ -1260,6 +1267,7 @@ const TSLanguage *ts_wasm_store_load_language(
.large_state_count = wasm_language.large_state_count,
.production_id_count = wasm_language.production_id_count,
.field_count = wasm_language.field_count,
.supertype_count = wasm_language.supertype_count,
.max_alias_sequence_length = wasm_language.max_alias_sequence_length,
.keyword_capture_token = wasm_language.keyword_capture_token,
.parse_table = copy(
@ -1295,14 +1303,14 @@ const TSLanguage *ts_wasm_store_load_language(
if (language->field_count > 0 && language->production_id_count > 0) {
language->field_map_slices = copy(
&memory[wasm_language.field_map_slices],
wasm_language.production_id_count * sizeof(TSFieldMapSlice)
wasm_language.production_id_count * sizeof(TSMapSlice)
);
// Determine the number of field map entries by finding the greatest index
// in any of the slices.
uint32_t field_map_entry_count = 0;
for (uint32_t i = 0; i < wasm_language.production_id_count; i++) {
TSFieldMapSlice slice = language->field_map_slices[i];
TSMapSlice slice = language->field_map_slices[i];
uint32_t slice_end = slice.index + slice.length;
if (slice_end > field_map_entry_count) {
field_map_entry_count = slice_end;
@ -1321,6 +1329,37 @@ const TSLanguage *ts_wasm_store_load_language(
);
}
if (language->supertype_count > 0) {
language->supertype_symbols = copy(
&memory[wasm_language.supertype_symbols],
wasm_language.supertype_count * sizeof(TSSymbol)
);
// Determine the number of supertype map slices by finding the greatest
// supertype ID.
int largest_supertype = 0;
for (unsigned i = 0; i < language->supertype_count; i++) {
TSSymbol supertype = language->supertype_symbols[i];
if (supertype > largest_supertype) {
largest_supertype = supertype;
}
}
language->supertype_map_slices = copy(
&memory[wasm_language.supertype_map_slices],
(largest_supertype + 1) * sizeof(TSMapSlice)
);
TSSymbol last_supertype = language->supertype_symbols[language->supertype_count - 1];
TSMapSlice last_slice = language->supertype_map_slices[last_supertype];
uint32_t supertype_map_entry_count = last_slice.index + last_slice.length;
language->supertype_map_entries = copy(
&memory[wasm_language.supertype_map_entries],
supertype_map_entry_count * sizeof(char *)
);
}
if (language->max_alias_sequence_length > 0 && language->production_id_count > 0) {
// The alias map contains symbols, alias counts, and aliases, terminated by a null symbol.
int32_t alias_map_size = 0;
@ -1752,6 +1791,9 @@ void ts_wasm_language_release(const TSLanguage *self) {
ts_free((void *)self->external_scanner.symbol_map);
ts_free((void *)self->field_map_entries);
ts_free((void *)self->field_map_slices);
ts_free((void *)self->supertype_symbols);
ts_free((void *)self->supertype_map_entries);
ts_free((void *)self->supertype_map_slices);
ts_free((void *)self->field_names);
ts_free((void *)self->lex_modes);
ts_free((void *)self->name);