nilTREE_SITTER_LANGUAGE_VERSION: integerTREE_SITTER_MIN_COMPATIBLE_LANGUAGE_VERSION: integerload: function(file_name: string, language_name: string): Language, string.so, .dll, or .dynlib extension
On Unix this uses dlopen, on Windows this uses LoadLibrary so if a path without a path separator is given, these functions have their own path's that they will search for your file in.
So if in doubt use a file path like
local my_language = ltreesitter.load("./my_parser.so", "my_language")
require: function(library_file_name: string, language_name?: string): Language, stringpackage.cpath for a parser with the filename library_file_name.so or parsers/library_file_name.so (or .dll on Windows) and try to load the symbol tree_sitter_'language_name'
language_name is optional and will be set to library_file_name if not provided.
So if you want to load a Lua parser from a file named lua.so then use ltreesitter.require("lua")
But if you want to load a Lua parser from a file named parser.so then use ltreesitter.require("parser", "lua")
Like the regular require, this will error if the parser is not found or the symbol couldn't be loaded. Use either pcall or ltreesitter.load to not error out on failure.
Returns the language and the path it was loaded from.
local my_language, loaded_from = ltreesitter.require("my_language")
print(my_language:name(), loaded_from) -- "my_language", /home/user/.luarocks/lib/lua/5.4/parsers/my_language.so
-- etc.
tree_sitter_version: stringversion: stringLanguage.abi_version: function(Language): integerLanguage.field_count: function(Language): integerLanguage.field_id_for_name: function(Language, string): FieldIdLanguage.metadata: function(Language): LanguageMetadatatree-sitter.json
May return nilLanguage.name: function(Language): stringLanguage.name_for_field_id: function(Language, FieldId): stringLanguage.next_state: function(Language, StateId, Symbol): StateIdLanguage.parser: function(Language): ParserLanguage.query: function(Language, string): QueryLanguage.state_count: function(Language): integerLanguage.subtypes: function(Language, supertype: Symbol): {Symbol}Language.supertypes: function(Language): {Symbol}Language.symbol_count: function(Language): integerLanguage.symbol_for_name: function(Language, string, is_named: boolean): SymbolLanguage.symbol_name: function(Language, Symbol): stringLanguage.symbol_type: function(Language, Symbol): SymbolTypeNode.child: function(Node, zero_index: integer): Nodezero_index'th child (0-indexed)Node.child_by_field_id: function(Node, FieldId): NodeNode.child_by_field_name: function(Node, string): NodeNode.child_count: function(Node): integerNode.child_with_descendant: function(Node, descendant: Node): Nodedescendant. Can return descendant itselfNode.children: function(Node): function(): NodeNode.create_cursor: function(Node): TreeCursorNode.descendant_count: function(Node): integerNode.descendant_for_byte_range: function(Node, start_byte: integer, end_byte: integer): NodeNode.descendant_for_point_range: function(Node, start_point: Point, end_point: Point): NodeNode.edit: function(
Node,
start_byte: integer,
old_end_byte: integer,
new_end_byte: integer,
start_point_row: integer,
start_point_col: integer,
old_end_point_row: integer,
old_end_point_col: integer,
new_end_point_row: integer,
new_end_point_col: integer
)Node.edit: function(Node, Edit)Node.edit_p: function(
Node,
start_byte: integer,
old_end_byte: integer,
new_end_byte: integer,
start_point_row: integer,
start_point_col: integer,
old_end_point_row: integer,
old_end_point_col: integer,
new_end_point_row: integer,
new_end_point_col: integer
)Node.edit_s: function(Node, Edit)Node.end_byte_offset: function(Node): integerNode.end_index: function(Node): integerNode.end_point: function(Node): PointNode.field_name_for_child: function(Node, child_zero_index: integer): stringNode.field_name_for_named_child: function(Node, child_zero_index: integer): stringNode.first_child_for_byte: function(Node, byte_offset: integer): NodeNode.first_named_child_for_byte: function(Node, byte_offset: integer): NodeNode.grammar_symbol: function(Node): SymbolParser:language_next_state() instead of Node:symbolNode.grammar_type: function(Node): stringNode.has_changes: function(Node): booleanNode.has_error: function(Node): booleanNode.is_extra: function(Node): booleanNode.is_missing: function(Node): booleanNode.is_named: function(Node): booleanNode.language: function(Node): LanguageNode.named_child: function(Node, zero_index: integer): Nodezero_index'th named childNode.named_child_count: function(Node): integerNode.named_children: function(Node): function(): NodeNode.named_descendant_for_byte_range: function(Node): NodeNode.named_descendant_for_point_range: function(Node): NodeNode.next_named_sibling: function(Node): NodeNode.next_parse_state: function(Node): StateIdNode.next_sibling: function(Node): NodeNode.parent: function(Node): NodeNode.child_with_descendant for iterating over
ancestorsNode.parse_state: function(Node): StateIdNode.prev_named_sibling: function(Node): NodeNode.prev_sibling: function(Node): NodeNode.source: function(Node): stringNodeNode.start_byte_offset: function(Node): integerNode.start_index: function(Node): integerNode.start_point: function(Node): PointNode.symbol: function(Node): SymbolNode.type: function(Node): stringParser.get_ranges: function(Parser): {Range}Parser.language: function(Parser): LanguageParser.parse_string: function(Parser, string, ?Encoding, ?Tree): TreeTree is provided then it will be used to create a new updated tree
(but it is the responsibility of the programmer to make the correct Tree:edit calls)Parser.parse_with: function(
Parser,
reader: (function(integer, Point): string),
progress_callback?: (function(has_error: boolean, byte_offset: integer): boolean),
encoding?: Encoding,
old_tree?: Tree
): Tree
reader should be a function that takes a byte index
and a Point and returns the text at that point. The
function should return either nil or an empty string
to signal that there is no more text.
progress_callback should be a function that takes a boolean
signalling if an error has occurred, and an integer byte offset. This
function will be called intermittently while parsing and may return true
to cancel parsing.
A Tree can be provided to reuse parts of it for parsing,
provided that Tree:edit has been called previously
encoding defaults to "utf-8" when not provided.
May return nil if the progress callback cancelled parsing.
Parser.print_dot_graphs: function(Parser, ?FILE)Parser.reset: function(Parser)Parser.set_ranges: function(Parser, {Range}): booleanParser will include when parsing, so you don't have to parse an entire document, but the ranges in the tree will still match the document.
The array of Ranges must satisfy the following relationship: for a positive integer i within the length of ranges: {Range}:
ranges[i].end_byte <= ranges[i + 1].start_bytereturns whether or not setting the range succeeded
Query.capture: function(
Query,
Node,
predicates?: {string:Predicate},
start?: integer | Point,
end_?: integer | Point
): function(): (Node, string)Node, name pairs.start and end are optional.local q = parser:query[[ (comment) @my_match ]] for capture, name in q:capture(node) do print(capture, name) -- => (comment), "my_match" end
Query.capture_count: function(Query): integerQuery.cursor: function(Query, Node): QueryCursorQuery.disable_capture: function(Query, name: string)Query.disable_pattern: function(Query, pattern_zero_index: integer)Query.end_byte_for_pattern: function(Query, pattern_zero_index: integer): integerQuery.exec: function(
Query,
Node,
predicates?: {string:Predicate},
start?: integer | Point,
end_?: integer | Point
)
This is intended to be used with predicates that have side effects,
i.e. for when you would use Query.match or
Query.capture, but do nothing in the for loop.
start and end are optional.
local parser = ltreesitter.require("teal"):parser()
-- grab a node to query against
local root_node = parser:parse_string[[
local x: string = "foo"
local y: string = "bar"
]]:root()
parser
:query[[(
(var_declaration
(var) @var-name
(string) @value)
(#set! @var-name @value)
)]]
:exec(root_node, {["set!"] = function(a, b) _G[a] = b:sub(2, -2) end})
print(x) -- => foo
print(y) -- => bar
If you'd like to interact with the matches/captures of a query, see the
Query.match and Query.capture iteratorsQuery.is_pattern_guaranteed_at_step: function(Query, pattern_zero_index: integer): booleanQuery.is_pattern_non_local: function(Query, pattern_zero_index: integer): booleanQuery.is_pattern_rooted: function(Query, pattern_zero_index: integer): booleanQuery.match: function(
Query,
Node,
predicates?: {string:Predicate},
start?: integer | Point,
end_?: integer | Point
): function(): Matchstart and end are optional.
They must be passed together with the same type, describing either two bytes or two points.
If passed, the query will be executed within the range denoted.
If not passed, the default behaviour is to execute the query through the entire range of the node.
interface Match
id: integer
pattern_index: integer
capture_count: integer
captures: {string:Node|{Node}}
end
If a capture can only contain at most one node (as is the case with regular (node) @capture-name patterns and (node)? @capture-name patterns),
it will either be nil or that Node.
If a capture can contain multiple nodes (as is the case with (node)* @capture-name and (node)+ @capture-name patterns)
it will either be nil or an array of Node
Example:
local q = parser:query[[ (comment) @my_match ]] for match in q:match(node) do print(match.captures.my_match) end
predicates is a map of functions to determine whether a query matches and/or execute side effects
Predicates that end in a '?' character will be seen as conditions that must be met for the pattern to be matched.
Predicates that don't will be seen just as functions to be executed given the matches provided.
Additionally, you will not have access to the return values of these functions, if you'd like to keep the results of a computation, make your functions have side-effects to write somewhere you can access.
By default the following predicates are provided.
(#eq? ...) will match if all arguments provided are equal (#not-eq? a b) will match if the two arguments provided are not equal (#match? text pattern) will match the provided text matches the given pattern. Matches are determined by Lua's standard string.match function. (#not-match? text pattern) inverse of match? (#find? text substring) will match if text contains substring. The substring is found with Lua's standard string.find, but the search always starts from the beginning, and pattern matching is disabled. This is equivalent to string.find(text, substring, 0, true) (#not-find? text substring) inverse of find?
Since predicates that end with a ? affect whether a node
matches, these are run first, in the order they appear in the query's
source. Once all ? queries are run, all the
non-? queries are run in the order they appear in the query's
source.
local parser = ltreesitter.require("lua"):parser()
-- grab a node to query against
local root_node = parser:parse_string[[
---@Doc this does stuff
local function stuff_doer()
do_stuff()
end
]]:root()
for match in parser
:query[[(
(comment) @the-comment
.
(function_definition
(function_name) @the-function-name)
(#is-doc-comment? @the-comment)
)]]
:match(root_node, {
["is-doc-comment?"] = function(str)
return str:source():sub(1, 4) == "---@"
end
})
do
print("Function: " .. match.captures["the-function-name"] .. " has documentation")
print(" " .. match.captures["the-comment"])
end
Query.pattern_count: function(Query): integerQuery.predicates_for_pattern: function(Query, pattern_index: integer): {{string | Capture}}capture_name field, representing a
@capture in the predicate.
e.g. Given a (c) query like with source:
local q = c:query [[ ((_ declarator: (identifier) @name) (#match? @name "[a-z]+") (#set! @name true)) ]]
q:predicates_for_pattern(0) would return:
{
{ "match?", { capture_name = "name" }, "[a-z]+" },
{ "set!", { capture_name = "name" }, "true" },
}
Query.start_byte_for_pattern: function(Query, pattern_zero_index: integer): integerQuery.string_count: function(Query): integerQueryCursor.did_exceed_match_limit: function(QueryCursor): booleanset_match_limit and match_limitQueryCursor.match_limit: function(QueryCursor): integerset_match_limit and
did_exceed_match_limitQueryCursor.next_capture_without_executing_predicates: function(QueryCursor): Node, stringQuery.predicates_for_pattern or
Query.capture for executing predicates.QueryCursor.next_match_without_executing_predicates: function(QueryCursor): MatchQuery.predicates_for_pattern or
Query.match for executing predicates.QueryCursor.remove_match: function(QueryCursor, match_id: integer)QueryCursor.set_byte_range: function(QueryCursor, start_byte: integer, end_byte: integer): booleanQueryCursor.set_containing_byte_range: function(
QueryCursor,
start_byte: integer,
end_byte: integer
): booleanQueryCursor.set_containing_point_range: function(
QueryCursor,
start_point: Point,
end_point: Point
): booleanQueryCursor.set_match_limit: function(QueryCursor, integer)QueryCursor.set_max_start_depth: function(QueryCursor, integer)QueryCursor.set_point_range: function(QueryCursor, start: Point, end_: Point): booleanTree.copy: function(Tree): TreeTree.edit: function(
Tree,
start_byte: integer,
old_end_byte: integer,
new_end_byte: integer,
start_point_row: integer,
start_point_col: integer,
old_end_point_row: integer,
old_end_point_col: integer,
new_end_point_row: integer,
new_end_point_col: integer
)Tree.edit: function(Tree, Edit)Tree.edit_p: function(
Tree,
start_byte: integer,
old_end_byte: integer,
new_end_byte: integer,
start_point_row: integer,
start_point_col: integer,
old_end_point_row: integer,
old_end_point_col: integer,
new_end_point_row: integer,
new_end_point_col: integer
)Tree.edit_s: function(Tree, Edit)Tree.get_changed_ranges: function(old: Tree, new: Tree): {Range}Tree.edit(_s) and Parser.parse_{string,with}Tree.included_ranges: function(Tree): {Range}Tree.language: function(Tree): LanguageTree.print_dot_graph: function(Tree, ?FILE)Tree.root: function(Tree): NodeTree.root_with_offset: function(Tree, offset_bytes: integer, offset_extent: Point): NodeTreeCursor.copy: function(TreeCursor): TreeCursorTreeCursor.current_depth: function(TreeCursor): integerTreeCursor.current_descendant_index: function(TreeCursor): integerTreeCursor.current_field_id: function(TreeCursor): FieldIdTreeCursor.current_field_name: function(TreeCursor): stringTreeCursor.current_node: function(TreeCursor): NodeTreeCursor.goto_descendant: function(TreeCursor, offset: integer)TreeCursor.goto_first_child: function(TreeCursor): booleanTreeCursor.goto_first_child_for_byte: function(TreeCursor, integer): integerTreeCursor.goto_first_child_for_point: function(TreeCursor, Point): integerTreeCursor.goto_last_child: function(TreeCursor): booleanTreeCursor.goto_next_sibling: function(TreeCursor): booleanTreeCursor.goto_parent: function(TreeCursor): booleanTreeCursor.goto_previous_sibling: function(TreeCursor): booleanTreeCursor.reset: function(TreeCursor, Node)TreeCursor.reset_to: function(TreeCursor, TreeCursor)