FFI
NAME
TreeSitter::Native::FFI - raw NativeCall bindings for libtreesitter-native
DESCRIPTION
One Raku sub per exported tsn_* function in src/ts_shim.h, plus
the handle types they traffic in. Nothing here has an opinion: no RAII,
no encoding, no null checks beyond what the shim already does. Reach for
TreeSitter::Native and TreeSitter::Native::Query unless you are
implementing something they do not cover.
src/ts_shim.h is the contract. If a signature here and a declaration
there disagree, the header wins and this file is a bug.
Nodes cross as buffers
tree-sitter returns TSNode by value everywhere, and NativeCall cannot
express that. The shim takes a caller-allocated 32-byte buffer instead ā
const void * going in, void * coming out ā and memcpys through
it. TSNodeBuf is that buffer: a CStruct whose only job is to be
exactly sizeof(TSNode) bytes of writable memory.
Allocate a fresh one for every node you want to keep. They are plain
memory with no lifetime of their own, but the TSTree whose bytes they
hold must outlive them, which is why TreeSitter::Native's Node
keeps a reference to its Tree.
use TreeSitter::Native::FFI;
my $parser = tsn_parser_new;
tsn_parser_set_language($parser, tsn_lang_python);
my Blob $src = "def f(): pass".encode('utf-8');
my $tree = tsn_parser_parse_utf8($parser, TSTree, $src, $src.elems);
my $root = TSNodeBuf.new;
tsn_tree_root_node($tree, $root);
say tsn_node_type($root); # module
tsn_tree_delete($tree);
tsn_parser_delete($parser);
Out-params
Anything the C API returns by value as a pair of scalars ā points, query
errors, predicate steps ā comes back through is rw parameters:
my uint32 ($row, $col);
tsn_node_start_point($root, $row, $col);
Strings
Borrowed const char * returns are declared -- Str> and are copied
into a Raku Str by NativeCall; nothing needs freeing. The two that may
contain embedded NULs (capture names, query string literals) and the one
that is malloc'd (tsn_node_string) are declared -- Pointer[uint8]>
instead, because Str would truncate at the first NUL and would give
you nothing to hand back to tsn_free_string. Decode them with
tsn-borrowed-str and tsn-owned-str.