mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
perf(treesitter): do not use tree cursors with a small lifetime
Problem: Tree cursors can only be efficient when they are re-used. Short-lived cursors are very slow. Solution: Reimplement functions that use short-lived cursors.
This commit is contained in:
parent
cc300e553b
commit
c6abc97006
@ -39,7 +39,6 @@
|
|||||||
#define TS_META_QUERY "treesitter_query"
|
#define TS_META_QUERY "treesitter_query"
|
||||||
#define TS_META_QUERYCURSOR "treesitter_querycursor"
|
#define TS_META_QUERYCURSOR "treesitter_querycursor"
|
||||||
#define TS_META_QUERYMATCH "treesitter_querymatch"
|
#define TS_META_QUERYMATCH "treesitter_querymatch"
|
||||||
#define TS_META_TREECURSOR "treesitter_treecursor"
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
LuaRef cb;
|
LuaRef cb;
|
||||||
@ -802,20 +801,6 @@ static int tree_root(lua_State *L)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TSTreeCursor
|
|
||||||
|
|
||||||
static struct luaL_Reg treecursor_meta[] = {
|
|
||||||
{ "__gc", treecursor_gc },
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
static int treecursor_gc(lua_State *L)
|
|
||||||
{
|
|
||||||
TSTreeCursor *cursor = luaL_checkudata(L, 1, TS_META_TREECURSOR);
|
|
||||||
ts_tree_cursor_delete(cursor);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TSNode
|
// TSNode
|
||||||
static struct luaL_Reg node_meta[] = {
|
static struct luaL_Reg node_meta[] = {
|
||||||
{ "__tostring", node_tostring },
|
{ "__tostring", node_tostring },
|
||||||
@ -1006,23 +991,14 @@ static int node_field(lua_State *L)
|
|||||||
size_t name_len;
|
size_t name_len;
|
||||||
const char *field_name = luaL_checklstring(L, 2, &name_len);
|
const char *field_name = luaL_checklstring(L, 2, &name_len);
|
||||||
|
|
||||||
TSTreeCursor cursor = ts_tree_cursor_new(node);
|
|
||||||
|
|
||||||
lua_newtable(L); // [table]
|
lua_newtable(L); // [table]
|
||||||
size_t curr_index = 0;
|
|
||||||
|
|
||||||
if (ts_tree_cursor_goto_first_child(&cursor)) {
|
TSNode field = ts_node_child_by_field_name(node, field_name, (uint32_t)name_len);
|
||||||
do {
|
if (!ts_node_is_null(field)) {
|
||||||
const char *current_field = ts_tree_cursor_current_field_name(&cursor);
|
push_node(L, field, 1); // [table, node]
|
||||||
|
lua_rawseti(L, -2, 1);
|
||||||
if (current_field != NULL && !strcmp(field_name, current_field)) {
|
|
||||||
push_node(L, ts_tree_cursor_current_node(&cursor), 1); // [table, node]
|
|
||||||
lua_rawseti(L, -2, (int)++curr_index);
|
|
||||||
}
|
|
||||||
} while (ts_tree_cursor_goto_next_sibling(&cursor));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ts_tree_cursor_delete(&cursor);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1118,45 +1094,35 @@ static int node_named_descendant_for_range(lua_State *L)
|
|||||||
|
|
||||||
static int node_next_child(lua_State *L)
|
static int node_next_child(lua_State *L)
|
||||||
{
|
{
|
||||||
TSTreeCursor *cursor = luaL_checkudata(L, lua_upvalueindex(1), TS_META_TREECURSOR);
|
uint32_t *child_index = lua_touserdata(L, lua_upvalueindex(1));
|
||||||
TSNode source = node_check(L, lua_upvalueindex(2));
|
TSNode source = node_check(L, lua_upvalueindex(2));
|
||||||
|
|
||||||
// First call should return first child
|
if (*child_index >= ts_node_child_count(source)) {
|
||||||
if (ts_node_eq(source, ts_tree_cursor_current_node(cursor))) {
|
|
||||||
if (ts_tree_cursor_goto_first_child(cursor)) {
|
|
||||||
goto push;
|
|
||||||
} else {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ts_tree_cursor_goto_next_sibling(cursor)) {
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
push:
|
TSNode child = ts_node_child(source, *child_index);
|
||||||
push_node(L, ts_tree_cursor_current_node(cursor), lua_upvalueindex(2)); // [node]
|
push_node(L, child, lua_upvalueindex(2));
|
||||||
|
|
||||||
const char *field = ts_tree_cursor_current_field_name(cursor);
|
|
||||||
|
|
||||||
|
const char *field = ts_node_field_name_for_child(source, *child_index);
|
||||||
if (field != NULL) {
|
if (field != NULL) {
|
||||||
lua_pushstring(L, ts_tree_cursor_current_field_name(cursor));
|
lua_pushstring(L, field);
|
||||||
} else {
|
} else {
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
} // [node, field_name_or_nil]
|
} // [node, field_name_or_nil]
|
||||||
|
|
||||||
|
(*child_index)++;
|
||||||
|
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int node_iter_children(lua_State *L)
|
static int node_iter_children(lua_State *L)
|
||||||
{
|
{
|
||||||
TSNode node = node_check(L, 1);
|
node_check(L, 1);
|
||||||
|
uint32_t *child_index = lua_newuserdata(L, sizeof(uint32_t)); // [source_node,..., udata]
|
||||||
|
*child_index = 0;
|
||||||
|
|
||||||
TSTreeCursor *ud = lua_newuserdata(L, sizeof(TSTreeCursor)); // [udata]
|
lua_pushvalue(L, 1); // [source_node, ..., udata, source_node]
|
||||||
*ud = ts_tree_cursor_new(node);
|
|
||||||
|
|
||||||
lua_getfield(L, LUA_REGISTRYINDEX, TS_META_TREECURSOR); // [udata, mt]
|
|
||||||
lua_setmetatable(L, -2); // [udata]
|
|
||||||
lua_pushvalue(L, 1); // [udata, source_node]
|
|
||||||
lua_pushcclosure(L, node_next_child, 2);
|
lua_pushcclosure(L, node_next_child, 2);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
@ -1248,22 +1214,19 @@ static int node_prev_named_sibling(lua_State *L)
|
|||||||
static int node_named_children(lua_State *L)
|
static int node_named_children(lua_State *L)
|
||||||
{
|
{
|
||||||
TSNode source = node_check(L, 1);
|
TSNode source = node_check(L, 1);
|
||||||
TSTreeCursor cursor = ts_tree_cursor_new(source);
|
|
||||||
|
|
||||||
lua_newtable(L);
|
lua_newtable(L);
|
||||||
int curr_index = 0;
|
int curr_index = 0;
|
||||||
|
|
||||||
if (ts_tree_cursor_goto_first_child(&cursor)) {
|
uint32_t n = ts_node_child_count(source);
|
||||||
do {
|
for (uint32_t i = 0; i < n; i++) {
|
||||||
TSNode node = ts_tree_cursor_current_node(&cursor);
|
TSNode child = ts_node_child(source, i);
|
||||||
if (ts_node_is_named(node)) {
|
if (ts_node_is_named(child)) {
|
||||||
push_node(L, node, 1);
|
push_node(L, child, 1);
|
||||||
lua_rawseti(L, -2, ++curr_index);
|
lua_rawseti(L, -2, ++curr_index);
|
||||||
}
|
}
|
||||||
} while (ts_tree_cursor_goto_next_sibling(&cursor));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ts_tree_cursor_delete(&cursor);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1673,7 +1636,6 @@ void tslua_init(lua_State *L)
|
|||||||
build_meta(L, TS_META_QUERY, query_meta);
|
build_meta(L, TS_META_QUERY, query_meta);
|
||||||
build_meta(L, TS_META_QUERYCURSOR, querycursor_meta);
|
build_meta(L, TS_META_QUERYCURSOR, querycursor_meta);
|
||||||
build_meta(L, TS_META_QUERYMATCH, querymatch_meta);
|
build_meta(L, TS_META_QUERYMATCH, querymatch_meta);
|
||||||
build_meta(L, TS_META_TREECURSOR, treecursor_meta);
|
|
||||||
|
|
||||||
ts_set_allocator(xmalloc, xcalloc, xrealloc, xfree);
|
ts_set_allocator(xmalloc, xcalloc, xrealloc, xfree);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user