willbooster-tree-sitter 2.0.23

WillBooster's fork of the Tree-sitter parsing library, with Rust bindings
Documentation
#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

typedef struct {
  const TSParseAction *actions;
  uint32_t action_count;
  bool is_reusable;
} TableEntry;

typedef enum {
  LookaheadFresh,      // no `next()` yet
  LookaheadPositioned, // last `next()` returned true
  LookaheadDone,       // last `next()` returned false
} LookaheadPhase;

typedef struct {
  const TSLanguage *language;
  const uint16_t *data;
  const uint16_t *group_end;
  uint16_t table_value;
  uint16_t group_count;
  bool is_small_state;
  bool is_pair_state;
  bool is_bitmap_state;
  TSStateId state;
  LookaheadPhase phase;

  const TSParseAction *actions;
  TSSymbol symbol;
  TSStateId next_state;
  uint16_t action_count;
} LookaheadIterator;

// Languages with another ABI version lack `primary_state_ids` and the fields after it or lay them out differently,
// so the accessors that work on a language before a parser or a query has accepted it must not read them.
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_language_has_reduce_action(
  const TSLanguage *self,
  TSStateId state,
  TSSymbol symbol
) {
  TableEntry entry;
  ts_language_table_entry(self, state, symbol, &entry);
  return entry.action_count > 0 && entry.actions[0].type == TSParseActionTypeReduce;
}

// Lookup the table value for a given symbol and state.
//
// For non-terminal symbols, the table value represents a successor state.
// For terminal symbols, it represents an index in the actions table.
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;
}

// Iterate over all of the symbols that are valid in the given state.
//
// For 'large' parse states, this just requires iterating through
// all possible symbols and checking the parse table for each one.
// For 'small' parse states, this exploits the structure of the
// table to only visit the valid symbols.
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;
  if (is_small_state) {
    uint32_t index = self->small_parse_table_map[state - self->large_state_count];
    is_pair_state = index & SMALL_STATE_PAIR_FLAG;
    is_bitmap_state = index & SMALL_STATE_BITMAP_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) data++;
  } 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,
    .state = state,
    .phase = LookaheadFresh,
    .symbol = UINT16_MAX,
    .next_state = 0,
  };
}

static inline bool ts_lookahead_iterator__next(LookaheadIterator *self) {
  if (self->phase == LookaheadDone) return false;

  if (self->is_small_state) {
    if (self->is_bitmap_state) {
      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) {
        self->phase = LookaheadDone;
        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];
    } else if (self->is_pair_state) {
      if (self->group_count == 0) {
        self->phase = LookaheadDone;
        return false;
      }
      self->group_count--;
      self->symbol = *(self->data++);
      self->table_value = *(self->data++);
    } else {
      self->data++;
      if (self->data == self->group_end) {
        if (self->group_count == 0) {
          self->phase = LookaheadDone;
          return false;
        }
        self->group_count--;
        self->table_value = *(self->data++);
        unsigned symbol_count = *(self->data++);
        self->group_end = self->data + symbol_count;
        self->symbol = *self->data;
      } else {
        self->symbol = *self->data;
        self->phase = LookaheadPositioned;
        return true;
      }
    }
  }

  // For large parse states, iterate through every symbol until one
  // is found that has valid actions.
  else {
    const uint16_t *row = self->data;
    TSSymbol symbol = self->phase == LookaheadFresh ? 0 : self->symbol + 1;
    while (symbol < self->language->symbol_count && !row[symbol]) symbol++;
    if (symbol >= self->language->symbol_count) {
      self->phase = LookaheadDone;
      return false;
    }
    self->symbol = symbol;
    self->table_value = row[symbol];
  }

  // Depending on if the symbol is terminal or non-terminal, the table value either
  // represents a list of actions or a successor state.
  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;
}

// Whether the state is a "primary state". If this returns false, it indicates that there exists
// another state that behaves identically to this one with respect to query analysis.
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  // TREE_SITTER_LANGUAGE_H_