treesitter: allow to iterate over node children

This commit is contained in:
Thomas Vigouroux
2020-08-08 23:26:40 +02:00
parent 24b5f69a49
commit e123fd0a5d
3 changed files with 106 additions and 1 deletions

View File

@@ -73,6 +73,7 @@ static struct luaL_Reg node_meta[] = {
{ "descendant_for_range", node_descendant_for_range },
{ "named_descendant_for_range", node_named_descendant_for_range },
{ "parent", node_parent },
{ "iter_children", node_iter_children },
{ "_rawquery", node_rawquery },
{ NULL, NULL }
};
@@ -84,12 +85,17 @@ static struct luaL_Reg query_meta[] = {
{ NULL, NULL }
};
// cursor is not exposed, but still needs garbage collection
// cursors are not exposed, but still needs garbage collection
static struct luaL_Reg querycursor_meta[] = {
{ "__gc", querycursor_gc },
{ NULL, NULL }
};
static struct luaL_Reg treecursor_meta[] = {
{ "__gc", treecursor_gc },
{ NULL, NULL }
};
static PMap(cstr_t) *langs;
static void build_meta(lua_State *L, const char *tname, const luaL_Reg *meta)
@@ -116,6 +122,7 @@ void tslua_init(lua_State *L)
build_meta(L, "treesitter_node", node_meta);
build_meta(L, "treesitter_query", query_meta);
build_meta(L, "treesitter_querycursor", querycursor_meta);
build_meta(L, "treesitter_treecursor", treecursor_meta);
}
int tslua_has_language(lua_State *L)
@@ -746,6 +753,74 @@ static int node_named_descendant_for_range(lua_State *L)
return 1;
}
static int node_next_child(lua_State *L)
{
TSTreeCursor *ud = luaL_checkudata(
L, lua_upvalueindex(1), "treesitter_treecursor");
if (!ud) {
return 0;
}
TSNode source;
if (!node_check(L, lua_upvalueindex(2), &source)) {
return 0;
}
// First call should return first child
if (ts_node_eq(source, ts_tree_cursor_current_node(ud))) {
if (ts_tree_cursor_goto_first_child(ud)) {
goto push;
} else {
goto end;
}
}
if (ts_tree_cursor_goto_next_sibling(ud)) {
push:
push_node(
L,
ts_tree_cursor_current_node(ud),
lua_upvalueindex(2)); // [node]
const char * field = ts_tree_cursor_current_field_name(ud);
if (field != NULL) {
lua_pushstring(L, ts_tree_cursor_current_field_name(ud));
} else {
lua_pushnil(L);
} // [node, field_name_or_nil]
return 2;
}
end:
return 0;
}
static int node_iter_children(lua_State *L)
{
TSNode source;
if (!node_check(L, 1, &source)) {
return 0;
}
TSTreeCursor *ud = lua_newuserdata(L, sizeof(TSTreeCursor)); // [udata]
*ud = ts_tree_cursor_new(source);
lua_getfield(L, LUA_REGISTRYINDEX, "treesitter_treecursor"); // [udata, mt]
lua_setmetatable(L, -2); // [udata]
lua_pushvalue(L, 1); // [udata, source_node]
lua_pushcclosure(L, node_next_child, 2);
return 1;
}
static int treecursor_gc(lua_State *L)
{
TSTreeCursor *ud = luaL_checkudata(L, 1, "treesitter_treecursor");
ts_tree_cursor_delete(ud);
return 0;
}
static int node_parent(lua_State *L)
{
TSNode node;