Fix handling of aliases in TreeCursor
This commit is contained in:
parent
5cb4b953e5
commit
c0763c69c4
2 changed files with 101 additions and 25 deletions
|
|
@ -29,17 +29,27 @@ void ts_tree_cursor_delete(TSTreeCursor *_self) {
|
|||
bool ts_tree_cursor_goto_first_child(TSTreeCursor *_self) {
|
||||
TreeCursor *self = (TreeCursor *)_self;
|
||||
TreeCursorEntry *last_entry = array_back(&self->stack);
|
||||
const Subtree *tree = last_entry->subtree;
|
||||
const Subtree *subtree = last_entry->subtree;
|
||||
if (subtree->children.size == 0 || subtree->visible_child_count == 0) return false;
|
||||
Length position = last_entry->position;
|
||||
|
||||
bool did_descend;
|
||||
do {
|
||||
did_descend = false;
|
||||
|
||||
const TSSymbol *alias_sequence = ts_language_alias_sequence(
|
||||
self->tree->language,
|
||||
subtree->alias_sequence_id
|
||||
);
|
||||
uint32_t structural_child_index = 0;
|
||||
for (uint32_t i = 0; i < tree->children.size; i++) {
|
||||
const Subtree *child = tree->children.contents[i];
|
||||
if (child->visible || child->visible_child_count > 0) {
|
||||
for (uint32_t i = 0; i < subtree->children.size; i++) {
|
||||
const Subtree *child = subtree->children.contents[i];
|
||||
bool visible = child->visible;
|
||||
if (!child->extra) {
|
||||
visible |= alias_sequence && alias_sequence[structural_child_index];
|
||||
}
|
||||
|
||||
if (visible || (child->children.size > 0 && child->visible_child_count > 0)) {
|
||||
array_push(&self->stack, ((TreeCursorEntry) {
|
||||
.subtree = child,
|
||||
.child_index = i,
|
||||
|
|
@ -47,10 +57,10 @@ bool ts_tree_cursor_goto_first_child(TSTreeCursor *_self) {
|
|||
.position = position,
|
||||
}));
|
||||
|
||||
if (child->visible) {
|
||||
if (visible) {
|
||||
return true;
|
||||
} else {
|
||||
tree = child;
|
||||
subtree = child;
|
||||
did_descend = true;
|
||||
break;
|
||||
}
|
||||
|
|
@ -67,7 +77,7 @@ int64_t ts_tree_cursor_goto_first_child_for_byte(TSTreeCursor *_self, uint32_t g
|
|||
TreeCursor *self = (TreeCursor *)_self;
|
||||
uint32_t initial_size = self->stack.size;
|
||||
TreeCursorEntry *last_entry = array_back(&self->stack);
|
||||
const Subtree *tree = last_entry->subtree;
|
||||
const Subtree *subtree = last_entry->subtree;
|
||||
Length position = last_entry->position;
|
||||
uint32_t visible_child_index = 0;
|
||||
|
||||
|
|
@ -75,14 +85,25 @@ int64_t ts_tree_cursor_goto_first_child_for_byte(TSTreeCursor *_self, uint32_t g
|
|||
do {
|
||||
did_descend = false;
|
||||
|
||||
const TSSymbol *alias_sequence = ts_language_alias_sequence(
|
||||
self->tree->language,
|
||||
subtree->alias_sequence_id
|
||||
);
|
||||
uint32_t structural_child_index = 0;
|
||||
for (uint32_t i = 0; i < tree->children.size; i++) {
|
||||
const Subtree *child = tree->children.contents[i];
|
||||
for (uint32_t i = 0; i < subtree->children.size; i++) {
|
||||
const Subtree *child = subtree->children.contents[i];
|
||||
Length next_position = length_add(position, ts_subtree_total_size(child));
|
||||
bool at_goal = next_position.bytes > goal_byte;
|
||||
|
||||
bool visible = child->visible;
|
||||
if (!child->extra) {
|
||||
visible |= alias_sequence && alias_sequence[structural_child_index];
|
||||
}
|
||||
|
||||
uint32_t visible_child_count = child->children.size > 0 ? child->visible_child_count : 0;
|
||||
|
||||
if (at_goal) {
|
||||
if (child->visible || child->visible_child_count > 0) {
|
||||
if (visible || visible_child_count > 0) {
|
||||
array_push(&self->stack, ((TreeCursorEntry) {
|
||||
.subtree = child,
|
||||
.child_index = i,
|
||||
|
|
@ -90,19 +111,19 @@ int64_t ts_tree_cursor_goto_first_child_for_byte(TSTreeCursor *_self, uint32_t g
|
|||
.position = position,
|
||||
}));
|
||||
|
||||
if (child->visible) {
|
||||
if (visible) {
|
||||
return visible_child_index;
|
||||
} else {
|
||||
tree = child;
|
||||
subtree = child;
|
||||
did_descend = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (child->visible) {
|
||||
if (visible) {
|
||||
visible_child_index++;
|
||||
} else {
|
||||
visible_child_index += child->visible_child_count;
|
||||
visible_child_index += visible_child_count;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -127,13 +148,22 @@ bool ts_tree_cursor_goto_next_sibling(TSTreeCursor *_self) {
|
|||
uint32_t structural_child_index = child_entry->structural_child_index;
|
||||
Length position = child_entry->position;
|
||||
const Subtree *child = parent->children.contents[child_index];
|
||||
const TSSymbol *alias_sequence = ts_language_alias_sequence(
|
||||
self->tree->language,
|
||||
parent->alias_sequence_id
|
||||
);
|
||||
|
||||
while (++child_index < parent->children.size) {
|
||||
if (!child->extra) structural_child_index++;
|
||||
position = length_add(position, ts_subtree_total_size(child));
|
||||
child = parent->children.contents[child_index];
|
||||
|
||||
if (child->visible || child->visible_child_count > 0) {
|
||||
bool visible = child->visible;
|
||||
if (!child->extra) {
|
||||
visible |= alias_sequence && alias_sequence[structural_child_index];
|
||||
}
|
||||
|
||||
if (visible || (child->children.size > 0 && child->visible_child_count > 0)) {
|
||||
self->stack.contents[i + 1] = (TreeCursorEntry) {
|
||||
.subtree = child,
|
||||
.child_index = child_index,
|
||||
|
|
@ -142,7 +172,7 @@ bool ts_tree_cursor_goto_next_sibling(TSTreeCursor *_self) {
|
|||
};
|
||||
self->stack.size = i + 2;
|
||||
|
||||
if (child->visible) {
|
||||
if (visible) {
|
||||
return true;
|
||||
} else {
|
||||
ts_tree_cursor_goto_first_child(_self);
|
||||
|
|
@ -180,7 +210,7 @@ TSNode ts_tree_cursor_current_node(const TSTreeCursor *_self) {
|
|||
self->tree->language,
|
||||
parent_entry->subtree->alias_sequence_id
|
||||
);
|
||||
if (alias_sequence) {
|
||||
if (alias_sequence && !last_entry->subtree->extra) {
|
||||
alias_symbol = alias_sequence[last_entry->structural_child_index];
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,15 +52,28 @@ string grammar_with_aliases_and_extras = R"JSON({
|
|||
"named": true,
|
||||
"content": {"type": "SYMBOL", "name": "b"}
|
||||
},
|
||||
{"type": "SYMBOL", "name": "b"}
|
||||
{
|
||||
"type": "ALIAS",
|
||||
"value": "C",
|
||||
"named": true,
|
||||
"content": {"type": "SYMBOL", "name": "_c"}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
"b": {"type": "STRING", "value": "b"},
|
||||
|
||||
"_c": {"type": "STRING", "value": "c"},
|
||||
|
||||
"comment": {"type": "STRING", "value": "..."}
|
||||
}
|
||||
})JSON";
|
||||
|
||||
const TSLanguage *language_with_aliases_and_extras = load_test_language(
|
||||
"aliases_and_extras",
|
||||
ts_compile_grammar(grammar_with_aliases_and_extras.c_str())
|
||||
);
|
||||
|
||||
describe("Node", [&]() {
|
||||
TSParser *parser;
|
||||
TSTree *tree;
|
||||
|
|
@ -163,16 +176,13 @@ describe("Node", [&]() {
|
|||
});
|
||||
|
||||
it("works correctly when the node contains aliased children and extras", [&]() {
|
||||
TSCompileResult compile_result = ts_compile_grammar(grammar_with_aliases_and_extras.c_str());
|
||||
const TSLanguage *language = load_test_language("aliases_and_extras", compile_result);
|
||||
ts_parser_set_language(parser, language);
|
||||
|
||||
ts_parser_set_language(parser, language_with_aliases_and_extras);
|
||||
ts_tree_delete(tree);
|
||||
tree = ts_parser_parse_string(parser, nullptr, "b ... b ... b", 13);
|
||||
tree = ts_parser_parse_string(parser, nullptr, "b ... b ... c", 13);
|
||||
root_node = ts_tree_root_node(tree);
|
||||
|
||||
char *node_string = ts_node_string(root_node);
|
||||
AssertThat(node_string, Equals("(a (b) (comment) (B) (comment) (b))"));
|
||||
AssertThat(node_string, Equals("(a (b) (comment) (B) (comment) (C))"));
|
||||
ts_free(node_string);
|
||||
|
||||
AssertThat(ts_node_named_child_count(root_node), Equals(5u));
|
||||
|
|
@ -180,7 +190,7 @@ describe("Node", [&]() {
|
|||
AssertThat(ts_node_type(ts_node_named_child(root_node, 1)), Equals("comment"));
|
||||
AssertThat(ts_node_type(ts_node_named_child(root_node, 2)), Equals("B"));
|
||||
AssertThat(ts_node_type(ts_node_named_child(root_node, 3)), Equals("comment"));
|
||||
AssertThat(ts_node_type(ts_node_named_child(root_node, 4)), Equals("b"));
|
||||
AssertThat(ts_node_type(ts_node_named_child(root_node, 4)), Equals("C"));
|
||||
|
||||
AssertThat(
|
||||
ts_node_symbol(ts_node_named_child(root_node, 0)),
|
||||
|
|
@ -700,6 +710,42 @@ describe("TreeCursor", [&]() {
|
|||
AssertThat(ts_node_start_byte(node), Equals(array_index));
|
||||
AssertThat(child_index, Equals(-1));
|
||||
});
|
||||
|
||||
it("walks the tree correctly when the node contains aliased children and extras", [&]() {
|
||||
ts_parser_set_language(parser, language_with_aliases_and_extras);
|
||||
ts_tree_cursor_delete(&cursor);
|
||||
ts_tree_delete(tree);
|
||||
|
||||
tree = ts_parser_parse_string(parser, nullptr, "b ... b ... c", 13);
|
||||
cursor = ts_tree_cursor_new(tree);
|
||||
|
||||
TSNode node = ts_tree_cursor_current_node(&cursor);
|
||||
AssertThat(ts_node_type(node), Equals("a"));
|
||||
|
||||
AssertThat(ts_tree_cursor_goto_first_child(&cursor), IsTrue());
|
||||
node = ts_tree_cursor_current_node(&cursor);
|
||||
AssertThat(ts_node_type(node), Equals("b"));
|
||||
|
||||
AssertThat(ts_tree_cursor_goto_next_sibling(&cursor), IsTrue());
|
||||
node = ts_tree_cursor_current_node(&cursor);
|
||||
AssertThat(ts_node_type(node), Equals("comment"));
|
||||
|
||||
AssertThat(ts_tree_cursor_goto_next_sibling(&cursor), IsTrue());
|
||||
node = ts_tree_cursor_current_node(&cursor);
|
||||
AssertThat(ts_node_type(node), Equals("B"));
|
||||
|
||||
AssertThat(ts_tree_cursor_goto_next_sibling(&cursor), IsTrue());
|
||||
node = ts_tree_cursor_current_node(&cursor);
|
||||
AssertThat(ts_node_type(node), Equals("comment"));
|
||||
|
||||
AssertThat(ts_tree_cursor_goto_next_sibling(&cursor), IsTrue());
|
||||
node = ts_tree_cursor_current_node(&cursor);
|
||||
AssertThat(ts_node_type(node), Equals("C"));
|
||||
|
||||
AssertThat(ts_tree_cursor_goto_next_sibling(&cursor), IsFalse());
|
||||
AssertThat(ts_tree_cursor_goto_parent(&cursor), IsTrue());
|
||||
AssertThat(ts_tree_cursor_goto_first_child_for_byte(&cursor, 0), Equals(0));
|
||||
});
|
||||
});
|
||||
|
||||
END_TEST
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue