mirror of
https://github.com/tree-sitter/tree-sitter.git
synced 2026-09-10 15:36:29 -04:00
`QueryMatches` and `QueryCaptures` retain query cursor options while they are being iterated. However, their types did not preserve the lifetime of the options' progress callback, allowing the callback to be dropped while it was still referenced by the cursor. Add an explicit options lifetime to both iterator types and propagate it through `matches_with_options` and `captures_with_options`. Use a static options lifetime for iterators created without options. |
||
|---|---|---|
| .. | ||
| bindings.rs | ||
| build.rs | ||
| ffi.rs | ||
| lib.rs | ||
| README.md | ||
| util.rs | ||
| wasm_language.rs | ||
Rust Tree-sitter
Rust bindings to the Tree-sitter parsing library.
Basic Usage
First, create a parser:
use tree_sitter::{InputEdit, Language, Parser, Point};
let mut parser = Parser::new();
Then, add a language as a dependency:
[dependencies]
tree-sitter = "0.24"
tree-sitter-rust = "0.23"
To use a language, you assign them to the parser.
parser.set_language(&tree_sitter_rust::LANGUAGE.into()).expect("Error loading Rust grammar");
Now you can parse source code:
let source_code = "fn test() {}";
let mut tree = parser.parse(source_code, None).unwrap();
let root_node = tree.root_node();
assert_eq!(root_node.kind(), "source_file");
assert_eq!(root_node.start_position().column, 0);
assert_eq!(root_node.end_position().column, 12);
Editing
Once you have a syntax tree, you can update it when your source code changes.
Passing in the previous edited tree makes parse run much more quickly:
let new_source_code = "fn test(a: u32) {}";
tree.edit(&InputEdit {
start_byte: 8,
old_end_byte: 8,
new_end_byte: 14,
start_position: Point::new(0, 8),
old_end_position: Point::new(0, 8),
new_end_position: Point::new(0, 14),
});
let new_tree = parser.parse(new_source_code, Some(&tree));
Text Input
The source code to parse can be provided either as a string, a slice, a vector, or as a function that returns a slice. The text can be encoded as either UTF8 or UTF16:
// Store some source code in an array of lines.
let lines = &[
"pub fn foo() {",
" 1",
"}",
];
// Parse the source code using a custom callback. The callback is called
// with both a byte offset and a row/column offset.
let tree = parser.parse_with(&mut |_byte: usize, position: Point| -> &[u8] {
let row = position.row as usize;
let column = position.column as usize;
if row < lines.len() {
if column < lines[row].as_bytes().len() {
&lines[row].as_bytes()[column..]
} else {
b"\n"
}
} else {
&[]
}
}, None).unwrap();
assert_eq!(
tree.root_node().to_sexp(),
"(source_file (function_item (visibility_modifier) (identifier) (parameters) (block (number_literal))))"
);
Using Wasm Grammar Files
Requires the feature wasm to be enabled.
First, create a parser with a Wasm store:
use tree_sitter::{wasmtime::Engine, Parser, WasmStore};
let engine = Engine::default();
let store = WasmStore::new(&engine).unwrap();
let mut parser = Parser::new();
parser.set_wasm_store(store).unwrap();
Then, load the language from a Wasm file:
const JAVASCRIPT_GRAMMAR: &[u8] = include_bytes!("path/to/tree-sitter-javascript.wasm");
let mut store = WasmStore::new(&engine).unwrap();
let javascript = store
.load_language("javascript", JAVASCRIPT_GRAMMAR)
.unwrap();
// The language may be loaded from a different WasmStore than the one set on
// the parser but it must use the same underlying WasmEngine.
parser.set_language(&javascript).unwrap();
Now you can parse source code:
let source_code = "let x = 1;";
let tree = parser.parse(source_code, None).unwrap();
assert_eq!(
tree.root_node().to_sexp(),
"(program (lexical_declaration (variable_declarator name: (identifier) value: (number))))"
);
Features
- std - This feature is enabled by default and allows
tree-sitterto use the standard library.- Error types implement the
std::error:Errortrait. regexperformance optimizations are enabled.- The DOT graph methods are enabled.
- Error types implement the
- wasm - This feature allows
tree-sitterto be built for Wasm targets using thewasmtime-c-apicrate.