mirror of
https://github.com/neovim/neovim.git
synced 2025-09-29 06:28:35 +00:00
treesitter: separate tree and parser
While this might sound silly, it is needed for further improvements.
This commit is contained in:
@@ -74,6 +74,9 @@ Tree methods *lua-treesitter-tree*
|
|||||||
tstree:root() *tstree:root()*
|
tstree:root() *tstree:root()*
|
||||||
Return the root node of this tree.
|
Return the root node of this tree.
|
||||||
|
|
||||||
|
tstree:copy() *tstree:copy()*
|
||||||
|
Returns a copy of the `tstree`.
|
||||||
|
|
||||||
|
|
||||||
Node methods *lua-treesitter-node*
|
Node methods *lua-treesitter-node*
|
||||||
|
|
||||||
|
@@ -18,11 +18,13 @@ Parser.__index = Parser
|
|||||||
-- @returns If the tree changed with this call, the changed ranges
|
-- @returns If the tree changed with this call, the changed ranges
|
||||||
function Parser:parse()
|
function Parser:parse()
|
||||||
if self.valid then
|
if self.valid then
|
||||||
return self.tree
|
return self._tree_immutable
|
||||||
end
|
end
|
||||||
local changes
|
local changes
|
||||||
|
|
||||||
self.tree, changes = self._parser:parse(self:input_source())
|
self._tree, changes = self._parser:parse(self._tree, self:input_source())
|
||||||
|
|
||||||
|
self._tree_immutable = self._tree:copy()
|
||||||
|
|
||||||
self.valid = true
|
self.valid = true
|
||||||
|
|
||||||
@@ -32,7 +34,7 @@ function Parser:parse()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return self.tree, changes
|
return self._tree_immutable, changes
|
||||||
end
|
end
|
||||||
|
|
||||||
function Parser:input_source()
|
function Parser:input_source()
|
||||||
@@ -45,7 +47,7 @@ function Parser:_on_bytes(bufnr, changed_tick,
|
|||||||
new_row, new_col, new_byte)
|
new_row, new_col, new_byte)
|
||||||
local old_end_col = old_col + ((old_row == 0) and start_col or 0)
|
local old_end_col = old_col + ((old_row == 0) and start_col or 0)
|
||||||
local new_end_col = new_col + ((new_row == 0) and start_col or 0)
|
local new_end_col = new_col + ((new_row == 0) and start_col or 0)
|
||||||
self._parser:edit(start_byte,start_byte+old_byte,start_byte+new_byte,
|
self._tree:edit(start_byte,start_byte+old_byte,start_byte+new_byte,
|
||||||
start_row, start_col,
|
start_row, start_col,
|
||||||
start_row+old_row, old_end_col,
|
start_row+old_row, old_end_col,
|
||||||
start_row+new_row, new_end_col)
|
start_row+new_row, new_end_col)
|
||||||
|
@@ -22,11 +22,6 @@
|
|||||||
#include "nvim/memline.h"
|
#include "nvim/memline.h"
|
||||||
#include "nvim/buffer.h"
|
#include "nvim/buffer.h"
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
TSParser *parser;
|
|
||||||
TSTree *tree; // internal tree, used for editing/reparsing
|
|
||||||
} TSLua_parser;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
TSQueryCursor *cursor;
|
TSQueryCursor *cursor;
|
||||||
int predicated_match;
|
int predicated_match;
|
||||||
@@ -40,8 +35,6 @@ static struct luaL_Reg parser_meta[] = {
|
|||||||
{ "__gc", parser_gc },
|
{ "__gc", parser_gc },
|
||||||
{ "__tostring", parser_tostring },
|
{ "__tostring", parser_tostring },
|
||||||
{ "parse", parser_parse },
|
{ "parse", parser_parse },
|
||||||
{ "edit", parser_edit },
|
|
||||||
{ "tree", parser_tree },
|
|
||||||
{ "set_included_ranges", parser_set_ranges },
|
{ "set_included_ranges", parser_set_ranges },
|
||||||
{ "included_ranges", parser_get_ranges },
|
{ "included_ranges", parser_get_ranges },
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
@@ -51,6 +44,8 @@ static struct luaL_Reg tree_meta[] = {
|
|||||||
{ "__gc", tree_gc },
|
{ "__gc", tree_gc },
|
||||||
{ "__tostring", tree_tostring },
|
{ "__tostring", tree_tostring },
|
||||||
{ "root", tree_root },
|
{ "root", tree_root },
|
||||||
|
{ "edit", tree_edit },
|
||||||
|
{ "copy", tree_copy },
|
||||||
{ NULL, NULL }
|
{ NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -247,39 +242,32 @@ int tslua_push_parser(lua_State *L)
|
|||||||
return luaL_error(L, "no such language: %s", lang_name);
|
return luaL_error(L, "no such language: %s", lang_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
TSParser *parser = ts_parser_new();
|
TSParser **parser = lua_newuserdata(L, sizeof(TSParser *));
|
||||||
|
*parser = ts_parser_new();
|
||||||
|
|
||||||
if (!ts_parser_set_language(parser, lang)) {
|
if (!ts_parser_set_language(*parser, lang)) {
|
||||||
ts_parser_delete(parser);
|
ts_parser_delete(*parser);
|
||||||
return luaL_error(L, "Failed to load language : %s", lang_name);
|
return luaL_error(L, "Failed to load language : %s", lang_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
TSLua_parser *p = lua_newuserdata(L, sizeof(TSLua_parser)); // [udata]
|
|
||||||
p->parser = parser;
|
|
||||||
p->tree = NULL;
|
|
||||||
|
|
||||||
lua_getfield(L, LUA_REGISTRYINDEX, "treesitter_parser"); // [udata, meta]
|
lua_getfield(L, LUA_REGISTRYINDEX, "treesitter_parser"); // [udata, meta]
|
||||||
lua_setmetatable(L, -2); // [udata]
|
lua_setmetatable(L, -2); // [udata]
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static TSLua_parser *parser_check(lua_State *L)
|
static TSParser ** parser_check(lua_State *L, uint16_t index)
|
||||||
{
|
{
|
||||||
return luaL_checkudata(L, 1, "treesitter_parser");
|
return luaL_checkudata(L, index, "treesitter_parser");
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parser_gc(lua_State *L)
|
static int parser_gc(lua_State *L)
|
||||||
{
|
{
|
||||||
TSLua_parser *p = parser_check(L);
|
TSParser **p = parser_check(L, 1);
|
||||||
if (!p) {
|
if (!p) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ts_parser_delete(p->parser);
|
ts_parser_delete(*p);
|
||||||
if (p->tree) {
|
|
||||||
ts_tree_delete(p->tree);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -344,11 +332,17 @@ static void push_ranges(lua_State *L,
|
|||||||
|
|
||||||
static int parser_parse(lua_State *L)
|
static int parser_parse(lua_State *L)
|
||||||
{
|
{
|
||||||
TSLua_parser *p = parser_check(L);
|
TSParser **p = parser_check(L, 1);
|
||||||
if (!p) {
|
if (!p || !(*p)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TSTree *old_tree = NULL;
|
||||||
|
if (!lua_isnil(L, 2)) {
|
||||||
|
TSTree **tmp = tree_check(L, 2);
|
||||||
|
old_tree = tmp ? *tmp : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
TSTree *new_tree = NULL;
|
TSTree *new_tree = NULL;
|
||||||
size_t len;
|
size_t len;
|
||||||
const char *str;
|
const char *str;
|
||||||
@@ -358,14 +352,14 @@ static int parser_parse(lua_State *L)
|
|||||||
|
|
||||||
// This switch is necessary because of the behavior of lua_isstring, that
|
// This switch is necessary because of the behavior of lua_isstring, that
|
||||||
// consider numbers as strings...
|
// consider numbers as strings...
|
||||||
switch (lua_type(L, 2)) {
|
switch (lua_type(L, 3)) {
|
||||||
case LUA_TSTRING:
|
case LUA_TSTRING:
|
||||||
str = lua_tolstring(L, 2, &len);
|
str = lua_tolstring(L, 3, &len);
|
||||||
new_tree = ts_parser_parse_string(p->parser, p->tree, str, len);
|
new_tree = ts_parser_parse_string(*p, old_tree, str, len);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LUA_TNUMBER:
|
case LUA_TNUMBER:
|
||||||
bufnr = lua_tointeger(L, 2);
|
bufnr = lua_tointeger(L, 3);
|
||||||
buf = handle_get_buffer(bufnr);
|
buf = handle_get_buffer(bufnr);
|
||||||
|
|
||||||
if (!buf) {
|
if (!buf) {
|
||||||
@@ -373,7 +367,7 @@ static int parser_parse(lua_State *L)
|
|||||||
}
|
}
|
||||||
|
|
||||||
input = (TSInput){ (void *)buf, input_cb, TSInputEncodingUTF8 };
|
input = (TSInput){ (void *)buf, input_cb, TSInputEncodingUTF8 };
|
||||||
new_tree = ts_parser_parse(p->parser, p->tree, input);
|
new_tree = ts_parser_parse(*p, old_tree, input);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -387,46 +381,42 @@ static int parser_parse(lua_State *L)
|
|||||||
return luaL_error(L, "An error occured when parsing.");
|
return luaL_error(L, "An error occured when parsing.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The new tree will be pushed to the stack, without copy, owwership is now to
|
||||||
|
// the lua GC.
|
||||||
|
// Old tree is still owned by the lua GC.
|
||||||
uint32_t n_ranges = 0;
|
uint32_t n_ranges = 0;
|
||||||
TSRange *changed = p->tree ? ts_tree_get_changed_ranges(p->tree, new_tree,
|
TSRange *changed = old_tree ? ts_tree_get_changed_ranges(
|
||||||
&n_ranges) : NULL;
|
old_tree, new_tree, &n_ranges) : NULL;
|
||||||
if (p->tree) {
|
|
||||||
ts_tree_delete(p->tree);
|
|
||||||
}
|
|
||||||
p->tree = new_tree;
|
|
||||||
|
|
||||||
tslua_push_tree(L, p->tree);
|
tslua_push_tree(L, new_tree, false); // [tree]
|
||||||
|
|
||||||
push_ranges(L, changed, n_ranges);
|
push_ranges(L, changed, n_ranges); // [tree, ranges]
|
||||||
|
|
||||||
xfree(changed);
|
xfree(changed);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parser_tree(lua_State *L)
|
static int tree_copy(lua_State *L)
|
||||||
{
|
{
|
||||||
TSLua_parser *p = parser_check(L);
|
TSTree **tree = tree_check(L, 1);
|
||||||
if (!p) {
|
if (!(*tree)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
tslua_push_tree(L, p->tree);
|
tslua_push_tree(L, *tree, true); // [tree]
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parser_edit(lua_State *L)
|
static int tree_edit(lua_State *L)
|
||||||
{
|
{
|
||||||
if (lua_gettop(L) < 10) {
|
if (lua_gettop(L) < 10) {
|
||||||
lua_pushstring(L, "not enough args to parser:edit()");
|
lua_pushstring(L, "not enough args to tree:edit()");
|
||||||
return lua_error(L);
|
return lua_error(L);
|
||||||
}
|
}
|
||||||
|
|
||||||
TSLua_parser *p = parser_check(L);
|
TSTree **tree = tree_check(L, 1);
|
||||||
if (!p) {
|
if (!(*tree)) {
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!p->tree) {
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -440,7 +430,7 @@ static int parser_edit(lua_State *L)
|
|||||||
TSInputEdit edit = { start_byte, old_end_byte, new_end_byte,
|
TSInputEdit edit = { start_byte, old_end_byte, new_end_byte,
|
||||||
start_point, old_end_point, new_end_point };
|
start_point, old_end_point, new_end_point };
|
||||||
|
|
||||||
ts_tree_edit(p->tree, &edit);
|
ts_tree_edit(*tree, &edit);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -453,8 +443,8 @@ static int parser_set_ranges(lua_State *L)
|
|||||||
"not enough args to parser:set_included_ranges()");
|
"not enough args to parser:set_included_ranges()");
|
||||||
}
|
}
|
||||||
|
|
||||||
TSLua_parser *p = parser_check(L);
|
TSParser **p = parser_check(L, 1);
|
||||||
if (!p || !p->tree) {
|
if (!p) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -490,7 +480,7 @@ static int parser_set_ranges(lua_State *L)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This memcpies ranges, thus we can free it afterwards
|
// This memcpies ranges, thus we can free it afterwards
|
||||||
ts_parser_set_included_ranges(p->parser, ranges, tbl_len);
|
ts_parser_set_included_ranges(*p, ranges, tbl_len);
|
||||||
xfree(ranges);
|
xfree(ranges);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -498,16 +488,15 @@ static int parser_set_ranges(lua_State *L)
|
|||||||
|
|
||||||
static int parser_get_ranges(lua_State *L)
|
static int parser_get_ranges(lua_State *L)
|
||||||
{
|
{
|
||||||
TSLua_parser *p = parser_check(L);
|
TSParser **p = parser_check(L, 1);
|
||||||
if (!p || !p->parser) {
|
if (!p) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int len;
|
unsigned int len;
|
||||||
const TSRange *ranges = ts_parser_included_ranges(p->parser, &len);
|
const TSRange *ranges = ts_parser_included_ranges(*p, &len);
|
||||||
|
|
||||||
push_ranges(L, ranges, len);
|
push_ranges(L, ranges, len);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -517,14 +506,20 @@ static int parser_get_ranges(lua_State *L)
|
|||||||
/// push tree interface on lua stack.
|
/// push tree interface on lua stack.
|
||||||
///
|
///
|
||||||
/// This makes a copy of the tree, so ownership of the argument is unaffected.
|
/// This makes a copy of the tree, so ownership of the argument is unaffected.
|
||||||
void tslua_push_tree(lua_State *L, TSTree *tree)
|
void tslua_push_tree(lua_State *L, TSTree *tree, bool do_copy)
|
||||||
{
|
{
|
||||||
if (tree == NULL) {
|
if (tree == NULL) {
|
||||||
lua_pushnil(L);
|
lua_pushnil(L);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
TSTree **ud = lua_newuserdata(L, sizeof(TSTree *)); // [udata]
|
TSTree **ud = lua_newuserdata(L, sizeof(TSTree *)); // [udata]
|
||||||
*ud = ts_tree_copy(tree);
|
|
||||||
|
if (do_copy) {
|
||||||
|
*ud = ts_tree_copy(tree);
|
||||||
|
} else {
|
||||||
|
*ud = tree;
|
||||||
|
}
|
||||||
|
|
||||||
lua_getfield(L, LUA_REGISTRYINDEX, "treesitter_tree"); // [udata, meta]
|
lua_getfield(L, LUA_REGISTRYINDEX, "treesitter_tree"); // [udata, meta]
|
||||||
lua_setmetatable(L, -2); // [udata]
|
lua_setmetatable(L, -2); // [udata]
|
||||||
|
|
||||||
@@ -537,20 +532,20 @@ void tslua_push_tree(lua_State *L, TSTree *tree)
|
|||||||
lua_setfenv(L, -2); // [udata]
|
lua_setfenv(L, -2); // [udata]
|
||||||
}
|
}
|
||||||
|
|
||||||
static TSTree *tree_check(lua_State *L)
|
static TSTree **tree_check(lua_State *L, uint16_t index)
|
||||||
{
|
{
|
||||||
TSTree **ud = luaL_checkudata(L, 1, "treesitter_tree");
|
TSTree **ud = luaL_checkudata(L, index, "treesitter_tree");
|
||||||
return *ud;
|
return ud;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tree_gc(lua_State *L)
|
static int tree_gc(lua_State *L)
|
||||||
{
|
{
|
||||||
TSTree *tree = tree_check(L);
|
TSTree **tree = tree_check(L, 1);
|
||||||
if (!tree) {
|
if (!tree) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
ts_tree_delete(tree);
|
ts_tree_delete(*tree);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -562,11 +557,11 @@ static int tree_tostring(lua_State *L)
|
|||||||
|
|
||||||
static int tree_root(lua_State *L)
|
static int tree_root(lua_State *L)
|
||||||
{
|
{
|
||||||
TSTree *tree = tree_check(L);
|
TSTree **tree = tree_check(L, 1);
|
||||||
if (!tree) {
|
if (!tree) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
TSNode root = ts_tree_root_node(tree);
|
TSNode root = ts_tree_root_node(*tree);
|
||||||
push_node(L, root, 1);
|
push_node(L, root, 1);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user