Fully implement ts_node_child_by_field_id

This commit is contained in:
Max Brunsfeld 2019-02-07 17:18:33 -08:00
parent bef80c162e
commit 1d1674811c
15 changed files with 455 additions and 181 deletions

View file

@ -108,7 +108,7 @@ static Iterator iterator_new(TreeCursor *cursor, const Subtree *tree, const TSLa
.subtree = tree,
.position = length_zero(),
.child_index = 0,
.child_info_offset = 0,
.structural_child_index = 0,
}));
return (Iterator) {
.cursor = *cursor,
@ -144,11 +144,15 @@ Length iterator_end_position(Iterator *self) {
static bool iterator_tree_is_visible(const Iterator *self) {
TreeCursorEntry entry = *array_back(&self->cursor.stack);
if (ts_subtree_visible(*entry.subtree)) return true;
if (entry.child_info_offset) {
return self->language->alias_sequences[entry.child_info_offset] != 0;
} else {
return false;
if (self->cursor.stack.size > 1) {
Subtree parent = *self->cursor.stack.contents[self->cursor.stack.size - 2].subtree;
const TSSymbol *alias_sequence = ts_language_alias_sequence(
self->language,
parent.ptr->child_info_id
);
return alias_sequence && alias_sequence[entry.structural_child_index] != 0;
}
return false;
}
static void iterator_get_visible_state(const Iterator *self, Subtree *tree,
@ -163,8 +167,15 @@ static void iterator_get_visible_state(const Iterator *self, Subtree *tree,
for (; i + 1 > 0; i--) {
TreeCursorEntry entry = self->cursor.stack.contents[i];
if (entry.child_info_offset) {
*alias_symbol = self->language->alias_sequences[entry.child_info_offset];
if (i > 0) {
const Subtree *parent = self->cursor.stack.contents[i - 1].subtree;
const TSSymbol *alias_sequence = ts_language_alias_sequence(
self->language,
parent->ptr->child_info_id
);
if (alias_sequence) {
*alias_symbol = alias_sequence[entry.structural_child_index];
}
}
if (ts_subtree_visible(*entry.subtree) || *alias_symbol) {
@ -190,9 +201,7 @@ static bool iterator_descend(Iterator *self, uint32_t goal_position) {
did_descend = false;
TreeCursorEntry entry = *array_back(&self->cursor.stack);
Length position = entry.position;
uint32_t child_info_offset =
self->language->max_child_info_production_length *
ts_subtree_child_info_sequence_id(*entry.subtree);
uint32_t structural_child_index = 0;
for (uint32_t i = 0, n = ts_subtree_child_count(*entry.subtree); i < n; i++) {
const Subtree *child = &entry.subtree->ptr->children[i];
Length child_left = length_add(position, ts_subtree_padding(*child));
@ -203,7 +212,7 @@ static bool iterator_descend(Iterator *self, uint32_t goal_position) {
.subtree = child,
.position = position,
.child_index = i,
.child_info_offset = child_info_offset,
.structural_child_index = structural_child_index,
}));
if (iterator_tree_is_visible(self)) {
@ -220,9 +229,7 @@ static bool iterator_descend(Iterator *self, uint32_t goal_position) {
}
position = child_right;
if (!ts_subtree_extra(*child) && child_info_offset) {
child_info_offset++;
}
if (!ts_subtree_extra(*child)) structural_child_index++;
}
} while (did_descend);
@ -249,17 +256,15 @@ static void iterator_advance(Iterator *self) {
uint32_t child_index = entry.child_index + 1;
if (ts_subtree_child_count(*parent) > child_index) {
Length position = length_add(entry.position, ts_subtree_total_size(*entry.subtree));
uint32_t child_info_offset = entry.child_info_offset;
if (child_info_offset && !ts_subtree_extra(*entry.subtree)) {
child_info_offset++;
}
uint32_t structural_child_index = entry.structural_child_index;
if (!ts_subtree_extra(*entry.subtree)) structural_child_index++;
const Subtree *next_child = &parent->ptr->children[child_index];
array_push(&self->cursor.stack, ((TreeCursorEntry){
.subtree = next_child,
.position = position,
.child_index = child_index,
.child_info_offset = child_info_offset,
.structural_child_index = structural_child_index,
}));
if (iterator_tree_is_visible(self)) {

View file

@ -81,12 +81,29 @@ ts_language_enabled_external_tokens(const TSLanguage *self,
}
static inline const TSSymbol *
ts_language_alias_sequence(const TSLanguage *self, unsigned id) {
return id > 0 ?
self->alias_sequences + id * self->max_child_info_production_length :
ts_language_alias_sequence(const TSLanguage *self, uint32_t child_info_id) {
return child_info_id > 0 ?
self->alias_sequences + child_info_id * self->max_child_info_production_length :
NULL;
}
static inline void ts_language_field_map(
const TSLanguage *self,
uint32_t child_info_id,
const TSFieldMapping **start,
const TSFieldMapping **end
) {
// To find the field mappings for a given child info id, first index
// into the field map using the child info id directly. This 'header'
// row contains two values:
// * the index where the field mappings start
// * the number of field mappings.
const TSFieldMapping *field_map = self->field_map;
TSFieldMapping header = field_map[child_info_id];
*start = &field_map[header.field_id];
*end = &field_map[header.field_id] + header.child_index;
}
#ifdef __cplusplus
}
#endif

View file

@ -8,8 +8,8 @@ typedef struct {
const TSTree *tree;
Length position;
uint32_t child_index;
uint32_t child_info_offset;
TSFieldId last_field_id;
uint32_t structural_child_index;
const TSSymbol *alias_sequence;
} NodeChildIterator;
// TSNode - constructors
@ -49,29 +49,35 @@ static inline Subtree ts_node__subtree(TSNode self) {
static inline NodeChildIterator ts_node_iterate_children(const TSNode *node) {
Subtree subtree = ts_node__subtree(*node);
if (ts_subtree_child_count(subtree) == 0) {
return (NodeChildIterator) {NULL_SUBTREE, node->tree, length_zero(), 0, 0, 0};
return (NodeChildIterator) {NULL_SUBTREE, node->tree, length_zero(), 0, 0, NULL};
}
uint32_t child_info_offset =
subtree.ptr->child_info_sequence_id *
node->tree->language->max_child_info_production_length;
const TSSymbol *alias_sequence = ts_language_alias_sequence(
node->tree->language,
subtree.ptr->child_info_id
);
return (NodeChildIterator) {
.tree = node->tree,
.parent = subtree,
.position = {ts_node_start_byte(*node), ts_node_start_point(*node)},
.child_index = 0,
.child_info_offset = child_info_offset,
.last_field_id = 0,
.structural_child_index = 0,
.alias_sequence = alias_sequence,
};
}
static inline bool ts_node_child_iterator_done(NodeChildIterator *self) {
return self->child_index == self->parent.ptr->child_count;
}
static inline bool ts_node_child_iterator_next(NodeChildIterator *self, TSNode *result) {
if (!self->parent.ptr || self->child_index == self->parent.ptr->child_count) return false;
if (!self->parent.ptr || ts_node_child_iterator_done(self)) return false;
const Subtree *child = &self->parent.ptr->children[self->child_index];
TSSymbol alias_symbol = 0;
if (!ts_subtree_extra(*child) && self->child_info_offset) {
alias_symbol = self->tree->language->alias_sequences[self->child_info_offset];
self->last_field_id = self->tree->language->field_sequences[self->child_info_offset];
self->child_info_offset++;
if (!ts_subtree_extra(*child)) {
if (self->alias_sequence) {
alias_symbol = self->alias_sequence[self->structural_child_index];
}
self->structural_child_index++;
}
if (self->child_index > 0) {
self->position = length_add(self->position, ts_subtree_padding(*child));
@ -452,15 +458,68 @@ TSNode ts_node_named_child(TSNode self, uint32_t child_index) {
}
TSNode ts_node_child_by_field_id(TSNode self, TSFieldId field_id) {
if (field_id) {
TSNode child;
NodeChildIterator iterator = ts_node_iterate_children(&self);
while (ts_node_child_iterator_next(&iterator, &child)) {
if (iterator.last_field_id == field_id) {
recur:
if (!field_id || ts_node_child_count(self) == 0) return ts_node__null();
const TSFieldMapping *field_map, *field_map_end;
ts_language_field_map(
self.tree->language,
ts_node__subtree(self).ptr->child_info_id,
&field_map,
&field_map_end
);
if (field_map == field_map_end) return ts_node__null();
// The field mappings are sorted by their field id. Scan all
// the mappings to find the ones for the given field id.
while (field_map->field_id < field_id) {
field_map++;
if (field_map == field_map_end) return ts_node__null();
}
while (field_map_end[-1].field_id > field_id) {
field_map_end--;
if (field_map == field_map_end) return ts_node__null();
}
TSNode child;
NodeChildIterator iterator = ts_node_iterate_children(&self);
while (ts_node_child_iterator_next(&iterator, &child)) {
if (!ts_subtree_extra(ts_node__subtree(child))) {
uint32_t index = iterator.structural_child_index - 1;
if (index < field_map->child_index) continue;
// Hidden nodes' fields are "inherited" by their visible parent.
if (field_map->inherited) {
// If this is the *last* possible child node for this field,
// then perform a tail call to avoid recursion.
if (field_map + 1 == field_map_end) {
self = child;
goto recur;
}
// Otherwise, descend into this child, but if that child doesn't
// contain the field, continue searching subsequent children.
else {
TSNode result = ts_node_child_by_field_id(child, field_id);
if (result.id) return result;
field_map++;
if (field_map == field_map_end) return ts_node__null();
}
}
else if (ts_node__is_relevant(child, true)) {
return child;
}
// If the field refers to a hidden node, return its first visible
// child.
else {
return ts_node_child(child, 0);
}
}
}
return ts_node__null();
}

View file

@ -675,7 +675,7 @@ static bool ts_parser__replace_children(TSParser *self, MutableSubtree *tree, Su
static StackVersion ts_parser__reduce(TSParser *self, StackVersion version, TSSymbol symbol,
uint32_t count, int dynamic_precedence,
uint16_t child_info_sequence_id, bool fragile) {
uint16_t child_info_id, bool fragile) {
uint32_t initial_version_count = ts_stack_version_count(self->stack);
uint32_t removed_version_count = 0;
StackSliceArray pop = ts_stack_pop_count(self->stack, version, count);
@ -709,7 +709,7 @@ static StackVersion ts_parser__reduce(TSParser *self, StackVersion version, TSSy
}
MutableSubtree parent = ts_subtree_new_node(&self->tree_pool,
symbol, &children, child_info_sequence_id, self->language
symbol, &children, child_info_id, self->language
);
// This pop operation may have caused multiple stack versions to collapse
@ -735,7 +735,7 @@ static StackVersion ts_parser__reduce(TSParser *self, StackVersion version, TSSy
}
parent.ptr->dynamic_precedence += dynamic_precedence;
parent.ptr->child_info_sequence_id = child_info_sequence_id;
parent.ptr->child_info_id = child_info_id;
TSStateId state = ts_stack_state(self->stack, slice_version);
TSStateId next_state = ts_language_next_state(self->language, state, symbol);
@ -791,7 +791,7 @@ static void ts_parser__accept(TSParser *self, StackVersion version, Subtree look
&self->tree_pool,
ts_subtree_symbol(child),
&trees,
child.ptr->child_info_sequence_id,
child.ptr->child_info_id,
self->language
));
ts_subtree_release(&self->tree_pool, child);
@ -867,7 +867,7 @@ static bool ts_parser__do_all_potential_reductions(TSParser *self,
.symbol = action.params.symbol,
.count = action.params.child_count,
.dynamic_precedence = action.params.dynamic_precedence,
.child_info_sequence_id = action.params.child_info_sequence_id,
.child_info_id = action.params.child_info_id,
});
default:
break;
@ -881,7 +881,7 @@ static bool ts_parser__do_all_potential_reductions(TSParser *self,
reduction_version = ts_parser__reduce(
self, version, action.symbol, action.count,
action.dynamic_precedence, action.child_info_sequence_id,
action.dynamic_precedence, action.child_info_id,
true
);
}
@ -1310,7 +1310,7 @@ static void ts_parser__advance(TSParser *self, StackVersion version, bool allow_
LOG("reduce sym:%s, child_count:%u", SYM_NAME(action.params.symbol), action.params.child_count);
StackVersion reduction_version = ts_parser__reduce(
self, version, action.params.symbol, action.params.child_count,
action.params.dynamic_precedence, action.params.child_info_sequence_id,
action.params.dynamic_precedence, action.params.child_info_id,
is_fragile
);
if (reduction_version != STACK_VERSION_NONE) {

View file

@ -12,7 +12,7 @@ typedef struct {
uint32_t count;
TSSymbol symbol;
int dynamic_precedence;
unsigned short child_info_sequence_id;
unsigned short child_info_id;
} ReduceAction;
typedef Array(ReduceAction) ReduceActionSet;

View file

@ -379,7 +379,7 @@ void ts_subtree_set_children(
self.ptr->dynamic_precedence = 0;
uint32_t non_extra_index = 0;
const TSSymbol *alias_sequence = ts_language_alias_sequence(language, self.ptr->child_info_sequence_id);
const TSSymbol *alias_sequence = ts_language_alias_sequence(language, self.ptr->child_info_id);
uint32_t lookahead_end_byte = 0;
for (uint32_t i = 0; i < self.ptr->child_count; i++) {
@ -474,7 +474,7 @@ void ts_subtree_set_children(
}
MutableSubtree ts_subtree_new_node(SubtreePool *pool, TSSymbol symbol,
SubtreeArray *children, unsigned child_info_sequence_id,
SubtreeArray *children, unsigned child_info_id,
const TSLanguage *language) {
TSSymbolMetadata metadata = ts_language_symbol_metadata(language, symbol);
bool fragile = symbol == ts_builtin_sym_error || symbol == ts_builtin_sym_error_repeat;
@ -482,7 +482,7 @@ MutableSubtree ts_subtree_new_node(SubtreePool *pool, TSSymbol symbol,
*data = (SubtreeHeapData) {
.ref_count = 1,
.symbol = symbol,
.child_info_sequence_id = child_info_sequence_id,
.child_info_id = child_info_id,
.visible = metadata.visible,
.named = metadata.named,
.has_changes = false,
@ -838,7 +838,7 @@ static size_t ts_subtree__write_to_string(Subtree self, char *string, size_t lim
}
if (ts_subtree_child_count(self)) {
const TSSymbol *alias_sequence = ts_language_alias_sequence(language, self.ptr->child_info_sequence_id);
const TSSymbol *alias_sequence = ts_language_alias_sequence(language, self.ptr->child_info_id);
uint32_t structural_child_index = 0;
for (uint32_t i = 0; i < self.ptr->child_count; i++) {
Subtree child = self.ptr->children[i];
@ -913,20 +913,17 @@ void ts_subtree__print_dot_graph(const Subtree *self, uint32_t start_offset,
fprintf(f, "\"]\n");
uint32_t child_start_offset = start_offset;
uint32_t structural_child_index = 0;
const TSSymbol *alias_sequence = ts_language_alias_sequence(
language,
ts_subtree_child_info_sequence_id(*self)
);
uint32_t child_info_offset =
language->max_child_info_production_length *
ts_subtree_child_info_id(*self);
for (uint32_t i = 0, n = ts_subtree_child_count(*self); i < n; i++) {
const Subtree *child = &self->ptr->children[i];
if (ts_subtree_extra(*child)) {
ts_subtree__print_dot_graph(child, child_start_offset, language, 0, f);
} else {
TSSymbol alias_symbol = alias_sequence ? alias_sequence[structural_child_index] : 0;
ts_subtree__print_dot_graph(child, child_start_offset, language, alias_symbol, f);
structural_child_index++;
TSSymbol alias_symbol = 0;
if (!ts_subtree_extra(*child) && child_info_offset) {
alias_symbol = language->alias_sequences[child_info_offset];
child_info_offset++;
}
ts_subtree__print_dot_graph(child, child_start_offset, language, alias_symbol, f);
fprintf(f, "tree_%p -> tree_%p [tooltip=%u]\n", self, child, i);
child_start_offset += ts_subtree_total_bytes(*child);
}

View file

@ -73,7 +73,7 @@ typedef struct {
uint32_t node_count;
uint32_t repeat_depth;
int32_t dynamic_precedence;
uint16_t child_info_sequence_id;
uint16_t child_info_id;
struct {
TSSymbol symbol;
TSStateId parse_state;
@ -229,9 +229,9 @@ static inline int32_t ts_subtree_dynamic_precedence(Subtree self) {
return (self.data.is_inline || self.ptr->child_count == 0) ? 0 : self.ptr->dynamic_precedence;
}
static inline uint16_t ts_subtree_child_info_sequence_id(Subtree self) {
static inline uint16_t ts_subtree_child_info_id(Subtree self) {
if (ts_subtree_child_count(self) > 0) {
return self.ptr->child_info_sequence_id;
return self.ptr->child_info_id;
} else {
return 0;
}

View file

@ -9,7 +9,8 @@ typedef struct {
const TSTree *tree;
Length position;
uint32_t child_index;
uint32_t child_info_offset;
uint32_t structural_child_index;
const TSSymbol *alias_sequence;
} CursorChildIterator;
// CursorChildIterator
@ -17,17 +18,19 @@ typedef struct {
static inline CursorChildIterator ts_tree_cursor_iterate_children(const TreeCursor *self) {
TreeCursorEntry *last_entry = array_back(&self->stack);
if (ts_subtree_child_count(*last_entry->subtree) == 0) {
return (CursorChildIterator) {NULL_SUBTREE, self->tree, length_zero(), 0, 0};
return (CursorChildIterator) {NULL_SUBTREE, self->tree, length_zero(), 0, 0, NULL};
}
uint32_t child_info_offset =
last_entry->subtree->ptr->child_info_sequence_id *
self->tree->language->max_child_info_production_length;
const TSSymbol *alias_sequence = ts_language_alias_sequence(
self->tree->language,
last_entry->subtree->ptr->child_info_id
);
return (CursorChildIterator) {
.tree = self->tree,
.parent = *last_entry->subtree,
.position = last_entry->position,
.child_index = 0,
.child_info_offset = child_info_offset,
.structural_child_index = 0,
.alias_sequence = alias_sequence,
};
}
@ -40,13 +43,13 @@ static inline bool ts_tree_cursor_child_iterator_next(CursorChildIterator *self,
.subtree = child,
.position = self->position,
.child_index = self->child_index,
.child_info_offset = self->child_info_offset,
.structural_child_index = self->structural_child_index,
};
*visible = ts_subtree_visible(*child);
bool extra = ts_subtree_extra(*child);
if (!extra && self->child_info_offset) {
*visible |= self->tree->language->alias_sequences[self->child_info_offset];
self->child_info_offset++;
if (!extra && self->alias_sequence) {
*visible |= self->alias_sequence[self->structural_child_index];
self->structural_child_index++;
}
self->position = length_add(self->position, ts_subtree_size(*child));
@ -82,7 +85,7 @@ void ts_tree_cursor_init(TreeCursor *self, TSNode node) {
ts_node_start_point(node)
},
.child_index = 0,
.child_info_offset = 0,
.structural_child_index = 0,
}));
}
@ -173,7 +176,7 @@ bool ts_tree_cursor_goto_next_sibling(TSTreeCursor *_self) {
TreeCursorEntry entry = array_pop(&self->stack);
CursorChildIterator iterator = ts_tree_cursor_iterate_children(self);
iterator.child_index = entry.child_index;
iterator.child_info_offset = entry.child_info_offset;
iterator.structural_child_index = entry.structural_child_index;
iterator.position = entry.position;
bool visible = false;
@ -204,9 +207,12 @@ bool ts_tree_cursor_goto_parent(TSTreeCursor *_self) {
TreeCursorEntry *entry = &self->stack.contents[i];
bool is_aliased = false;
if (i > 0) {
is_aliased =
entry->child_info_offset &&
self->tree->language->alias_sequences[entry->child_info_offset];
TreeCursorEntry *parent_entry = &self->stack.contents[i - 1];
const TSSymbol *alias_sequence = ts_language_alias_sequence(
self->tree->language,
parent_entry->subtree->ptr->child_info_id
);
is_aliased = alias_sequence && alias_sequence[entry->structural_child_index];
}
if (ts_subtree_visible(*entry->subtree) || is_aliased) {
self->stack.size = i + 1;
@ -220,8 +226,15 @@ TSNode ts_tree_cursor_current_node(const TSTreeCursor *_self) {
const TreeCursor *self = (const TreeCursor *)_self;
TreeCursorEntry *last_entry = array_back(&self->stack);
TSSymbol alias_symbol = 0;
if (last_entry->child_info_offset) {
alias_symbol = self->tree->language->alias_sequences[last_entry->child_info_offset];
if (self->stack.size > 1) {
TreeCursorEntry *parent_entry = &self->stack.contents[self->stack.size - 2];
const TSSymbol *alias_sequence = ts_language_alias_sequence(
self->tree->language,
parent_entry->subtree->ptr->child_info_id
);
if (alias_sequence && !ts_subtree_extra(*last_entry->subtree)) {
alias_symbol = alias_sequence[last_entry->structural_child_index];
}
}
return ts_node_new(
self->tree,
@ -233,12 +246,40 @@ TSNode ts_tree_cursor_current_node(const TSTreeCursor *_self) {
TSFieldId ts_tree_cursor_current_field_id(const TSTreeCursor *_self) {
const TreeCursor *self = (const TreeCursor *)_self;
TreeCursorEntry *entry = array_back(&self->stack);
if (entry->child_info_offset) {
return self->tree->language->field_sequences[entry->child_info_offset];
} else {
return 0;
// Walk up the tree, visiting the current node and its invisible ancestors.
for (unsigned i = self->stack.size - 1; i > 0; i--) {
TreeCursorEntry *entry = &self->stack.contents[i];
TreeCursorEntry *parent_entry = &self->stack.contents[i - 1];
// Stop walking up when another visible node is found.
if (i != self->stack.size - 1) {
if (ts_subtree_visible(*entry->subtree)) break;
const TSSymbol *alias_sequence = ts_language_alias_sequence(
self->tree->language,
parent_entry->subtree->ptr->child_info_id
);
if (alias_sequence && alias_sequence[entry->structural_child_index]) {
break;
}
}
const TSFieldMapping *field_map, *field_map_end;
ts_language_field_map(
self->tree->language,
parent_entry->subtree->ptr->child_info_id,
&field_map, &field_map_end
);
while (field_map < field_map_end) {
if (
!field_map->inherited &&
field_map->child_index == entry->structural_child_index
) return field_map->field_id;
field_map++;
}
}
return 0;
}
const char *ts_tree_cursor_current_field_name(const TSTreeCursor *_self) {

View file

@ -7,7 +7,7 @@ typedef struct {
const Subtree *subtree;
Length position;
uint32_t child_index;
uint32_t child_info_offset;
uint32_t structural_child_index;
} TreeCursorEntry;
typedef struct {