Tweak query interface
* Rename TSQueryContext -> TSQueryCursor * Remove the permanent association between the cursor and its query. The cursor can now be used again for a different query.
This commit is contained in:
parent
c8c75782e3
commit
c71de5bd81
9 changed files with 142 additions and 147 deletions
|
|
@ -1,9 +1,8 @@
|
|||
use clap::{App, AppSettings, Arg, SubCommand};
|
||||
use error::Error;
|
||||
use std::io::Read;
|
||||
use std::path::Path;
|
||||
use std::process::exit;
|
||||
use std::{env, fs, io, u64};
|
||||
use std::{env, fs, u64};
|
||||
use tree_sitter::Language;
|
||||
use tree_sitter_cli::{
|
||||
config, error, generate, highlight, loader, logger, parse, query, test, wasm, web_ui,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ use super::error::{Error, Result};
|
|||
use std::fs;
|
||||
use std::io::{self, Write};
|
||||
use std::path::Path;
|
||||
use tree_sitter::{Language, Parser, Query};
|
||||
use tree_sitter::{Language, Parser, Query, QueryCursor};
|
||||
|
||||
pub fn query_files_at_paths(
|
||||
language: Language,
|
||||
|
|
@ -18,7 +18,7 @@ pub fn query_files_at_paths(
|
|||
let query = Query::new(language, &query_source)
|
||||
.map_err(|e| Error::new(format!("Query compilation failed: {:?}", e)))?;
|
||||
|
||||
let query_context = query.context();
|
||||
let mut query_cursor = QueryCursor::new();
|
||||
|
||||
let mut parser = Parser::new();
|
||||
parser.set_language(language).map_err(|e| e.to_string())?;
|
||||
|
|
@ -32,7 +32,7 @@ pub fn query_files_at_paths(
|
|||
|
||||
let tree = parser.parse(&source_code, None).unwrap();
|
||||
|
||||
for mat in query_context.exec(tree.root_node()) {
|
||||
for mat in query_cursor.exec(&query, tree.root_node()) {
|
||||
writeln!(&mut stdout, " pattern: {}", mat.pattern_index())?;
|
||||
for (capture_id, node) in mat.captures() {
|
||||
writeln!(
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use super::helpers::allocations;
|
||||
use super::helpers::fixtures::get_language;
|
||||
use tree_sitter::{Parser, Query, QueryError, QueryMatch};
|
||||
use tree_sitter::{Parser, Query, QueryCursor, QueryError, QueryMatch};
|
||||
|
||||
#[test]
|
||||
fn test_query_errors_on_invalid_syntax() {
|
||||
|
|
@ -77,8 +77,8 @@ fn test_query_exec_with_simple_pattern() {
|
|||
parser.set_language(language).unwrap();
|
||||
let tree = parser.parse(source, None).unwrap();
|
||||
|
||||
let context = query.context();
|
||||
let matches = context.exec(tree.root_node());
|
||||
let mut cursor = QueryCursor::new();
|
||||
let matches = cursor.exec(&query, tree.root_node());
|
||||
|
||||
assert_eq!(
|
||||
collect_matches(matches, &query, source),
|
||||
|
|
@ -117,8 +117,8 @@ fn test_query_exec_with_multiple_matches_same_root() {
|
|||
let mut parser = Parser::new();
|
||||
parser.set_language(language).unwrap();
|
||||
let tree = parser.parse(source, None).unwrap();
|
||||
let context = query.context();
|
||||
let matches = context.exec(tree.root_node());
|
||||
let mut cursor = QueryCursor::new();
|
||||
let matches = cursor.exec(&query, tree.root_node());
|
||||
|
||||
assert_eq!(
|
||||
collect_matches(matches, &query, source),
|
||||
|
|
@ -164,8 +164,8 @@ fn test_query_exec_multiple_patterns_different_roots() {
|
|||
let mut parser = Parser::new();
|
||||
parser.set_language(language).unwrap();
|
||||
let tree = parser.parse(source, None).unwrap();
|
||||
let context = query.context();
|
||||
let matches = context.exec(tree.root_node());
|
||||
let mut cursor = QueryCursor::new();
|
||||
let matches = cursor.exec(&query, tree.root_node());
|
||||
|
||||
assert_eq!(
|
||||
collect_matches(matches, &query, source),
|
||||
|
|
@ -206,8 +206,8 @@ fn test_query_exec_multiple_patterns_same_root() {
|
|||
let mut parser = Parser::new();
|
||||
parser.set_language(language).unwrap();
|
||||
let tree = parser.parse(source, None).unwrap();
|
||||
let context = query.context();
|
||||
let matches = context.exec(tree.root_node());
|
||||
let mut cursor = QueryCursor::new();
|
||||
let matches = cursor.exec(&query, tree.root_node());
|
||||
|
||||
assert_eq!(
|
||||
collect_matches(matches, &query, source),
|
||||
|
|
@ -243,8 +243,8 @@ fn test_query_exec_nested_matches_without_fields() {
|
|||
let mut parser = Parser::new();
|
||||
parser.set_language(language).unwrap();
|
||||
let tree = parser.parse(source, None).unwrap();
|
||||
let context = query.context();
|
||||
let matches = context.exec(tree.root_node());
|
||||
let mut cursor = QueryCursor::new();
|
||||
let matches = cursor.exec(&query, tree.root_node());
|
||||
|
||||
assert_eq!(
|
||||
collect_matches(matches, &query, source),
|
||||
|
|
@ -269,8 +269,8 @@ fn test_query_exec_many_matches() {
|
|||
let mut parser = Parser::new();
|
||||
parser.set_language(language).unwrap();
|
||||
let tree = parser.parse(&source, None).unwrap();
|
||||
let context = query.context();
|
||||
let matches = context.exec(tree.root_node());
|
||||
let mut cursor = QueryCursor::new();
|
||||
let matches = cursor.exec(&query, tree.root_node());
|
||||
|
||||
assert_eq!(
|
||||
collect_matches(matches, &query, source.as_str()),
|
||||
|
|
@ -298,8 +298,8 @@ fn test_query_exec_too_many_match_permutations_to_track() {
|
|||
let mut parser = Parser::new();
|
||||
parser.set_language(language).unwrap();
|
||||
let tree = parser.parse(&source, None).unwrap();
|
||||
let context = query.context();
|
||||
let matches = context.exec(tree.root_node());
|
||||
let mut cursor = QueryCursor::new();
|
||||
let matches = cursor.exec(&query, tree.root_node());
|
||||
|
||||
// For this pathological query, some match permutations will be dropped.
|
||||
// Just check that a subset of the results are returned, and crash or
|
||||
|
|
@ -329,8 +329,8 @@ fn test_query_exec_with_anonymous_tokens() {
|
|||
let mut parser = Parser::new();
|
||||
parser.set_language(language).unwrap();
|
||||
let tree = parser.parse(&source, None).unwrap();
|
||||
let context = query.context();
|
||||
let matches = context.exec(tree.root_node());
|
||||
let mut cursor = QueryCursor::new();
|
||||
let matches = cursor.exec(&query, tree.root_node());
|
||||
|
||||
assert_eq!(
|
||||
collect_matches(matches, &query, source),
|
||||
|
|
@ -354,8 +354,8 @@ fn test_query_exec_within_byte_range() {
|
|||
parser.set_language(language).unwrap();
|
||||
let tree = parser.parse(&source, None).unwrap();
|
||||
|
||||
let mut context = query.context();
|
||||
let matches = context.set_byte_range(5, 15).exec(tree.root_node());
|
||||
let mut cursor = QueryCursor::new();
|
||||
let matches = cursor.set_byte_range(5, 15).exec(&query, tree.root_node());
|
||||
|
||||
assert_eq!(
|
||||
collect_matches(matches, &query, source),
|
||||
|
|
@ -420,8 +420,8 @@ fn test_query_comments() {
|
|||
let mut parser = Parser::new();
|
||||
parser.set_language(language).unwrap();
|
||||
let tree = parser.parse(source, None).unwrap();
|
||||
let context = query.context();
|
||||
let matches = context.exec(tree.root_node());
|
||||
let mut cursor = QueryCursor::new();
|
||||
let matches = cursor.exec(&query, tree.root_node());
|
||||
assert_eq!(
|
||||
collect_matches(matches, &query, source),
|
||||
&[(0, vec![("fn-name", "one")]),],
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ pub struct TSQuery {
|
|||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct TSQueryContext {
|
||||
pub struct TSQueryCursor {
|
||||
_unused: [u8; 0],
|
||||
}
|
||||
pub const TSInputEncoding_TSInputEncodingUTF8: TSInputEncoding = 0;
|
||||
|
|
@ -604,56 +604,52 @@ extern "C" {
|
|||
) -> ::std::os::raw::c_int;
|
||||
}
|
||||
extern "C" {
|
||||
#[doc = " Create a new context for executing a given query."]
|
||||
#[doc = " Create a new cursor for executing a given query."]
|
||||
#[doc = ""]
|
||||
#[doc = " The context stores the state that is needed to iteratively search"]
|
||||
#[doc = " for matches. To use the query context:"]
|
||||
#[doc = " 1. First call `ts_query_context_exec` to start running the query"]
|
||||
#[doc = " on a particular syntax node."]
|
||||
#[doc = " 2. Then repeatedly call `ts_query_context_next` to iterate over"]
|
||||
#[doc = " the matches."]
|
||||
#[doc = " 3. After each successful call to `ts_query_context_next`, you can call"]
|
||||
#[doc = " `ts_query_context_matched_pattern_index` to determine which pattern"]
|
||||
#[doc = " matched. You can also call `ts_query_context_matched_captures` to"]
|
||||
#[doc = " determine which nodes were captured by which capture names."]
|
||||
#[doc = " The cursor stores the state that is needed to iteratively search"]
|
||||
#[doc = " for matches. To use the query cursor:"]
|
||||
#[doc = " 1. First call `ts_query_cursor_exec` to start running a given query on"]
|
||||
#[doc = "a given syntax node."]
|
||||
#[doc = " 2. Then repeatedly call `ts_query_cursor_next` to iterate over the matches."]
|
||||
#[doc = " This will return `false` when there are no more matches left."]
|
||||
#[doc = " 3. After each successful call to `ts_query_cursor_next`, you can call"]
|
||||
#[doc = " `ts_query_cursor_matched_pattern_index` to determine which pattern"]
|
||||
#[doc = " matched. You can also call `ts_query_cursor_matched_captures` to"]
|
||||
#[doc = " determine which nodes were captured, and by which capture names."]
|
||||
#[doc = ""]
|
||||
#[doc = " If you don\'t care about finding all of the matches, you can stop calling"]
|
||||
#[doc = " `ts_query_context_next` at any point. And you can start executing the"]
|
||||
#[doc = " query against a different node by calling `ts_query_context_exec` again."]
|
||||
pub fn ts_query_context_new(arg1: *const TSQuery) -> *mut TSQueryContext;
|
||||
#[doc = " `ts_query_cursor_next` at any point. And you can start executing another"]
|
||||
#[doc = " query on another node by calling `ts_query_cursor_exec` again."]
|
||||
pub fn ts_query_cursor_new() -> *mut TSQueryCursor;
|
||||
}
|
||||
extern "C" {
|
||||
#[doc = " Delete a query context, freeing all of the memory that it used."]
|
||||
pub fn ts_query_context_delete(arg1: *mut TSQueryContext);
|
||||
#[doc = " Delete a query cursor, freeing all of the memory that it used."]
|
||||
pub fn ts_query_cursor_delete(arg1: *mut TSQueryCursor);
|
||||
}
|
||||
extern "C" {
|
||||
#[doc = " Start running a query on a given node."]
|
||||
pub fn ts_query_context_exec(arg1: *mut TSQueryContext, arg2: TSNode);
|
||||
#[doc = " Start running a given query on a given node."]
|
||||
pub fn ts_query_cursor_exec(arg1: *mut TSQueryCursor, arg2: *const TSQuery, arg3: TSNode);
|
||||
}
|
||||
extern "C" {
|
||||
#[doc = " Set the range of bytes or (row, column) positions in which the query"]
|
||||
#[doc = " will be executed."]
|
||||
pub fn ts_query_context_set_byte_range(arg1: *mut TSQueryContext, arg2: u32, arg3: u32);
|
||||
pub fn ts_query_cursor_set_byte_range(arg1: *mut TSQueryCursor, arg2: u32, arg3: u32);
|
||||
}
|
||||
extern "C" {
|
||||
pub fn ts_query_context_set_point_range(
|
||||
arg1: *mut TSQueryContext,
|
||||
arg2: TSPoint,
|
||||
arg3: TSPoint,
|
||||
);
|
||||
pub fn ts_query_cursor_set_point_range(arg1: *mut TSQueryCursor, arg2: TSPoint, arg3: TSPoint);
|
||||
}
|
||||
extern "C" {
|
||||
#[doc = " Advance to the next match of the currently running query."]
|
||||
pub fn ts_query_context_next(arg1: *mut TSQueryContext) -> bool;
|
||||
pub fn ts_query_cursor_next(arg1: *mut TSQueryCursor) -> bool;
|
||||
}
|
||||
extern "C" {
|
||||
#[doc = " Check which pattern matched."]
|
||||
pub fn ts_query_context_matched_pattern_index(arg1: *const TSQueryContext) -> u32;
|
||||
pub fn ts_query_cursor_matched_pattern_index(arg1: *const TSQueryCursor) -> u32;
|
||||
}
|
||||
extern "C" {
|
||||
#[doc = " Check which pattern matched."]
|
||||
pub fn ts_query_context_matched_captures(
|
||||
arg1: *const TSQueryContext,
|
||||
pub fn ts_query_cursor_matched_captures(
|
||||
arg1: *const TSQueryCursor,
|
||||
arg2: *mut u32,
|
||||
) -> *const TSQueryCapture;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -142,9 +142,9 @@ pub struct Query {
|
|||
capture_names: Vec<String>,
|
||||
}
|
||||
|
||||
pub struct QueryContext<'a>(*mut ffi::TSQueryContext, PhantomData<&'a ()>);
|
||||
pub struct QueryCursor(*mut ffi::TSQueryCursor);
|
||||
|
||||
pub struct QueryMatch<'a>(&'a QueryContext<'a>);
|
||||
pub struct QueryMatch<'a>(*mut ffi::TSQueryCursor, PhantomData<&'a ()>);
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum QueryError<'a> {
|
||||
|
|
@ -989,22 +989,21 @@ impl Query {
|
|||
pub fn capture_names(&self) -> &[String] {
|
||||
&self.capture_names
|
||||
}
|
||||
|
||||
pub fn context(&self) -> QueryContext {
|
||||
let context = unsafe { ffi::ts_query_context_new(self.ptr) };
|
||||
QueryContext(context, PhantomData)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> QueryContext<'a> {
|
||||
pub fn exec(&'a self, node: Node<'a>) -> impl Iterator<Item = QueryMatch<'a>> + 'a {
|
||||
impl QueryCursor {
|
||||
pub fn new() -> Self {
|
||||
QueryCursor(unsafe { ffi::ts_query_cursor_new() })
|
||||
}
|
||||
|
||||
pub fn exec<'a>(&'a mut self, query: &'a Query, node: Node<'a>) -> impl Iterator<Item = QueryMatch<'a>> + 'a {
|
||||
unsafe {
|
||||
ffi::ts_query_context_exec(self.0, node.0);
|
||||
ffi::ts_query_cursor_exec(self.0, query.ptr, node.0);
|
||||
}
|
||||
std::iter::from_fn(move || -> Option<QueryMatch<'a>> {
|
||||
unsafe {
|
||||
if ffi::ts_query_context_next(self.0) {
|
||||
Some(QueryMatch(self))
|
||||
if ffi::ts_query_cursor_next(self.0) {
|
||||
Some(QueryMatch(self.0, PhantomData))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
@ -1014,14 +1013,14 @@ impl<'a> QueryContext<'a> {
|
|||
|
||||
pub fn set_byte_range(&mut self, start: usize, end: usize) -> &mut Self {
|
||||
unsafe {
|
||||
ffi::ts_query_context_set_byte_range(self.0, start as u32, end as u32);
|
||||
ffi::ts_query_cursor_set_byte_range(self.0, start as u32, end as u32);
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_point_range(&mut self, start: Point, end: Point) -> &mut Self {
|
||||
unsafe {
|
||||
ffi::ts_query_context_set_point_range(self.0, start.into(), end.into());
|
||||
ffi::ts_query_cursor_set_point_range(self.0, start.into(), end.into());
|
||||
}
|
||||
self
|
||||
}
|
||||
|
|
@ -1029,14 +1028,14 @@ impl<'a> QueryContext<'a> {
|
|||
|
||||
impl<'a> QueryMatch<'a> {
|
||||
pub fn pattern_index(&self) -> usize {
|
||||
unsafe { ffi::ts_query_context_matched_pattern_index((self.0).0) as usize }
|
||||
unsafe { ffi::ts_query_cursor_matched_pattern_index(self.0) as usize }
|
||||
}
|
||||
|
||||
pub fn captures(&self) -> impl ExactSizeIterator<Item = (usize, Node)> {
|
||||
unsafe {
|
||||
let mut capture_count = 0u32;
|
||||
let captures =
|
||||
ffi::ts_query_context_matched_captures((self.0).0, &mut capture_count as *mut u32);
|
||||
ffi::ts_query_cursor_matched_captures(self.0, &mut capture_count as *mut u32);
|
||||
let captures = slice::from_raw_parts(captures, capture_count as usize);
|
||||
captures
|
||||
.iter()
|
||||
|
|
@ -1057,9 +1056,9 @@ impl Drop for Query {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Drop for QueryContext<'a> {
|
||||
impl Drop for QueryCursor {
|
||||
fn drop(&mut self) {
|
||||
unsafe { ffi::ts_query_context_delete(self.0) }
|
||||
unsafe { ffi::ts_query_cursor_delete(self.0) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -306,6 +306,7 @@ void ts_tree_cursor_current_node_wasm(const TSTree *tree) {
|
|||
/******************/
|
||||
|
||||
static TSTreeCursor scratch_cursor = {0};
|
||||
static TSQueryCursor *scratch_query_cursor = NULL;
|
||||
|
||||
uint16_t ts_node_symbol_wasm(const TSTree *tree) {
|
||||
TSNode node = unmarshal_node(tree);
|
||||
|
|
@ -566,24 +567,22 @@ int ts_node_is_missing_wasm(const TSTree *tree) {
|
|||
/* Section - Query */
|
||||
/******************/
|
||||
|
||||
void ts_query_exec_wasm(
|
||||
const TSQuery *self,
|
||||
TSQueryContext *context,
|
||||
const TSTree *tree
|
||||
) {
|
||||
void ts_query_exec_wasm(const TSQuery *self, const TSTree *tree) {
|
||||
if (!scratch_query_cursor) scratch_query_cursor = ts_query_cursor_new();
|
||||
|
||||
TSNode node = unmarshal_node(tree);
|
||||
|
||||
Array(const void *) result = array_new();
|
||||
|
||||
unsigned index = 0;
|
||||
unsigned match_count = 0;
|
||||
ts_query_context_exec(context, node);
|
||||
while (ts_query_context_next(context)) {
|
||||
ts_query_cursor_exec(scratch_query_cursor, self, node);
|
||||
while (ts_query_cursor_next(scratch_query_cursor)) {
|
||||
match_count++;
|
||||
uint32_t pattern_index = ts_query_context_matched_pattern_index(context);
|
||||
uint32_t pattern_index = ts_query_cursor_matched_pattern_index(scratch_query_cursor);
|
||||
uint32_t capture_count;
|
||||
const TSQueryCapture *captures = ts_query_context_matched_captures(
|
||||
context,
|
||||
const TSQueryCapture *captures = ts_query_cursor_matched_captures(
|
||||
scratch_query_cursor,
|
||||
&capture_count
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -677,7 +677,6 @@ class Language {
|
|||
TRANSFER_BUFFER + SIZE_OF_INT
|
||||
);
|
||||
if (address) {
|
||||
const contextAddress = C._ts_query_context_new(address);
|
||||
const captureCount = C._ts_query_capture_count(address);
|
||||
const captureNames = new Array(captureCount);
|
||||
for (let i = 0; i < captureCount; i++) {
|
||||
|
|
@ -689,7 +688,7 @@ class Language {
|
|||
const nameLength = getValue(TRANSFER_BUFFER, 'i32');
|
||||
captureNames[i] = UTF8ToString(nameAddress, nameLength);
|
||||
}
|
||||
return new Query(INTERNAL, address, contextAddress, captureNames);
|
||||
return new Query(INTERNAL, address, captureNames);
|
||||
} else {
|
||||
const errorId = getValue(TRANSFER_BUFFER + SIZE_OF_INT, 'i32');
|
||||
const utf8ErrorOffset = getValue(TRANSFER_BUFFER, 'i32');
|
||||
|
|
@ -743,22 +742,20 @@ class Language {
|
|||
}
|
||||
|
||||
class Query {
|
||||
constructor(internal, address, contextAddress, captureNames) {
|
||||
constructor(internal, address, captureNames) {
|
||||
assertInternal(internal);
|
||||
this[0] = address;
|
||||
this[1] = contextAddress;
|
||||
this.captureNames = captureNames;
|
||||
}
|
||||
|
||||
delete() {
|
||||
C._ts_query_delete(this[0]);
|
||||
C._ts_query_context_delete(this[0]);
|
||||
}
|
||||
|
||||
exec(queryNode) {
|
||||
marshalNode(queryNode);
|
||||
|
||||
C._ts_query_exec_wasm(this[0], this[1], queryNode.tree[0]);
|
||||
C._ts_query_exec_wasm(this[0], queryNode.tree[0]);
|
||||
|
||||
const matchCount = getValue(TRANSFER_BUFFER, 'i32');
|
||||
const nodesAddress = getValue(TRANSFER_BUFFER + SIZE_OF_INT, 'i32');
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ typedef struct TSLanguage TSLanguage;
|
|||
typedef struct TSParser TSParser;
|
||||
typedef struct TSTree TSTree;
|
||||
typedef struct TSQuery TSQuery;
|
||||
typedef struct TSQueryContext TSQueryContext;
|
||||
typedef struct TSQueryCursor TSQueryCursor;
|
||||
|
||||
typedef enum {
|
||||
TSInputEncodingUTF8,
|
||||
|
|
@ -670,57 +670,57 @@ int ts_query_capture_id_for_name(
|
|||
);
|
||||
|
||||
/**
|
||||
* Create a new context for executing a given query.
|
||||
* Create a new cursor for executing a given query.
|
||||
*
|
||||
* The context stores the state that is needed to iteratively search
|
||||
* for matches. To use the query context:
|
||||
* 1. First call `ts_query_context_exec` to start running the query
|
||||
* on a particular syntax node.
|
||||
* 2. Then repeatedly call `ts_query_context_next` to iterate over
|
||||
* the matches.
|
||||
* 3. After each successful call to `ts_query_context_next`, you can call
|
||||
* `ts_query_context_matched_pattern_index` to determine which pattern
|
||||
* matched. You can also call `ts_query_context_matched_captures` to
|
||||
* determine which nodes were captured by which capture names.
|
||||
* The cursor stores the state that is needed to iteratively search
|
||||
* for matches. To use the query cursor:
|
||||
* 1. First call `ts_query_cursor_exec` to start running a given query on
|
||||
a given syntax node.
|
||||
* 2. Then repeatedly call `ts_query_cursor_next` to iterate over the matches.
|
||||
* This will return `false` when there are no more matches left.
|
||||
* 3. After each successful call to `ts_query_cursor_next`, you can call
|
||||
* `ts_query_cursor_matched_pattern_index` to determine which pattern
|
||||
* matched. You can also call `ts_query_cursor_matched_captures` to
|
||||
* determine which nodes were captured, and by which capture names.
|
||||
*
|
||||
* If you don't care about finding all of the matches, you can stop calling
|
||||
* `ts_query_context_next` at any point. And you can start executing the
|
||||
* query against a different node by calling `ts_query_context_exec` again.
|
||||
* `ts_query_cursor_next` at any point. And you can start executing another
|
||||
* query on another node by calling `ts_query_cursor_exec` again.
|
||||
*/
|
||||
TSQueryContext *ts_query_context_new(const TSQuery *);
|
||||
TSQueryCursor *ts_query_cursor_new();
|
||||
|
||||
/**
|
||||
* Delete a query context, freeing all of the memory that it used.
|
||||
* Delete a query cursor, freeing all of the memory that it used.
|
||||
*/
|
||||
void ts_query_context_delete(TSQueryContext *);
|
||||
void ts_query_cursor_delete(TSQueryCursor *);
|
||||
|
||||
/**
|
||||
* Start running a query on a given node.
|
||||
* Start running a given query on a given node.
|
||||
*/
|
||||
void ts_query_context_exec(TSQueryContext *, TSNode);
|
||||
void ts_query_cursor_exec(TSQueryCursor *, const TSQuery *, TSNode);
|
||||
|
||||
/**
|
||||
* Set the range of bytes or (row, column) positions in which the query
|
||||
* will be executed.
|
||||
*/
|
||||
void ts_query_context_set_byte_range(TSQueryContext *, uint32_t, uint32_t);
|
||||
void ts_query_context_set_point_range(TSQueryContext *, TSPoint, TSPoint);
|
||||
void ts_query_cursor_set_byte_range(TSQueryCursor *, uint32_t, uint32_t);
|
||||
void ts_query_cursor_set_point_range(TSQueryCursor *, TSPoint, TSPoint);
|
||||
|
||||
/**
|
||||
* Advance to the next match of the currently running query.
|
||||
*/
|
||||
bool ts_query_context_next(TSQueryContext *);
|
||||
bool ts_query_cursor_next(TSQueryCursor *);
|
||||
|
||||
/**
|
||||
* Check which pattern matched.
|
||||
*/
|
||||
uint32_t ts_query_context_matched_pattern_index(const TSQueryContext *);
|
||||
uint32_t ts_query_cursor_matched_pattern_index(const TSQueryCursor *);
|
||||
|
||||
/**
|
||||
* Check which pattern matched.
|
||||
*/
|
||||
const TSQueryCapture *ts_query_context_matched_captures(
|
||||
const TSQueryContext *,
|
||||
const TSQueryCapture *ts_query_cursor_matched_captures(
|
||||
const TSQueryCursor *,
|
||||
uint32_t *
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ typedef struct {
|
|||
|
||||
/*
|
||||
* QueryState - The state of an in-progress match of a particular pattern
|
||||
* in a query. While executing, a QueryContext must keep track of a number
|
||||
* in a query. While executing, a `TSQueryCursor` must keep track of a number
|
||||
* of possible in-progress matches. Each of those possible matches is
|
||||
* represented as one of these states.
|
||||
*/
|
||||
|
|
@ -69,15 +69,14 @@ typedef struct {
|
|||
* parts of the shared array are currently in use by a QueryState.
|
||||
*/
|
||||
typedef struct {
|
||||
TSQueryCapture *contents;
|
||||
uint32_t list_size;
|
||||
Array(TSQueryCapture) list;
|
||||
uint32_t usage_map;
|
||||
} CaptureListPool;
|
||||
|
||||
/*
|
||||
* TSQuery - A tree query, compiled from a string of S-expressions. The query
|
||||
* itself is immutable. The mutable state used in the process of executing the
|
||||
* query is stored in a `TSQueryContext`.
|
||||
* query is stored in a `TSQueryCursor`.
|
||||
*/
|
||||
struct TSQuery {
|
||||
Array(QueryStep) steps;
|
||||
|
|
@ -90,9 +89,9 @@ struct TSQuery {
|
|||
};
|
||||
|
||||
/*
|
||||
* TSQueryContext - A stateful struct used to execute a query on a tree.
|
||||
* TSQueryCursor - A stateful struct used to execute a query on a tree.
|
||||
*/
|
||||
struct TSQueryContext {
|
||||
struct TSQueryCursor {
|
||||
const TSQuery *query;
|
||||
TSTreeCursor cursor;
|
||||
Array(QueryState) states;
|
||||
|
|
@ -185,24 +184,26 @@ static void stream_scan_identifier(Stream *stream) {
|
|||
* CaptureListPool
|
||||
******************/
|
||||
|
||||
static CaptureListPool capture_list_pool_new(uint16_t list_size) {
|
||||
static CaptureListPool capture_list_pool_new() {
|
||||
return (CaptureListPool) {
|
||||
.contents = ts_calloc(MAX_STATE_COUNT * list_size, sizeof(TSQueryCapture)),
|
||||
.list_size = list_size,
|
||||
.list = array_new(),
|
||||
.usage_map = UINT32_MAX,
|
||||
};
|
||||
}
|
||||
|
||||
static void capture_list_pool_clear(CaptureListPool *self) {
|
||||
static void capture_list_pool_reset(CaptureListPool *self, uint16_t list_size) {
|
||||
self->usage_map = UINT32_MAX;
|
||||
uint32_t total_size = MAX_STATE_COUNT * list_size;
|
||||
array_reserve(&self->list, total_size);
|
||||
self->list.size = total_size;
|
||||
}
|
||||
|
||||
static void capture_list_pool_delete(CaptureListPool *self) {
|
||||
ts_free(self->contents);
|
||||
array_delete(&self->list);
|
||||
}
|
||||
|
||||
static TSQueryCapture *capture_list_pool_get(CaptureListPool *self, uint16_t id) {
|
||||
return &self->contents[id * self->list_size];
|
||||
return &self->list.contents[id * (self->list.size / MAX_STATE_COUNT)];
|
||||
}
|
||||
|
||||
static inline uint32_t capture_list_bitmask_for_id(uint16_t id) {
|
||||
|
|
@ -599,17 +600,16 @@ int ts_query_capture_id_for_name(
|
|||
}
|
||||
|
||||
/***************
|
||||
* QueryContext
|
||||
* QueryCursor
|
||||
***************/
|
||||
|
||||
TSQueryContext *ts_query_context_new(const TSQuery *query) {
|
||||
TSQueryContext *self = ts_malloc(sizeof(TSQueryContext));
|
||||
*self = (TSQueryContext) {
|
||||
.query = query,
|
||||
TSQueryCursor *ts_query_cursor_new() {
|
||||
TSQueryCursor *self = ts_malloc(sizeof(TSQueryCursor));
|
||||
*self = (TSQueryCursor) {
|
||||
.ascending = false,
|
||||
.states = array_new(),
|
||||
.finished_states = array_new(),
|
||||
.capture_list_pool = capture_list_pool_new(query->max_capture_count),
|
||||
.capture_list_pool = capture_list_pool_new(),
|
||||
.start_byte = 0,
|
||||
.end_byte = UINT32_MAX,
|
||||
.start_point = {0, 0},
|
||||
|
|
@ -618,7 +618,7 @@ TSQueryContext *ts_query_context_new(const TSQuery *query) {
|
|||
return self;
|
||||
}
|
||||
|
||||
void ts_query_context_delete(TSQueryContext *self) {
|
||||
void ts_query_cursor_delete(TSQueryCursor *self) {
|
||||
array_delete(&self->states);
|
||||
array_delete(&self->finished_states);
|
||||
ts_tree_cursor_delete(&self->cursor);
|
||||
|
|
@ -626,17 +626,22 @@ void ts_query_context_delete(TSQueryContext *self) {
|
|||
ts_free(self);
|
||||
}
|
||||
|
||||
void ts_query_context_exec(TSQueryContext *self, TSNode node) {
|
||||
void ts_query_cursor_exec(
|
||||
TSQueryCursor *self,
|
||||
const TSQuery *query,
|
||||
TSNode node
|
||||
) {
|
||||
array_clear(&self->states);
|
||||
array_clear(&self->finished_states);
|
||||
ts_tree_cursor_reset(&self->cursor, node);
|
||||
capture_list_pool_clear(&self->capture_list_pool);
|
||||
capture_list_pool_reset(&self->capture_list_pool, query->max_capture_count);
|
||||
self->depth = 0;
|
||||
self->ascending = false;
|
||||
self->query = query;
|
||||
}
|
||||
|
||||
void ts_query_context_set_byte_range(
|
||||
TSQueryContext *self,
|
||||
void ts_query_cursor_set_byte_range(
|
||||
TSQueryCursor *self,
|
||||
uint32_t start_byte,
|
||||
uint32_t end_byte
|
||||
) {
|
||||
|
|
@ -648,8 +653,8 @@ void ts_query_context_set_byte_range(
|
|||
self->end_byte = end_byte;
|
||||
}
|
||||
|
||||
void ts_query_context_set_point_range(
|
||||
TSQueryContext *self,
|
||||
void ts_query_cursor_set_point_range(
|
||||
TSQueryCursor *self,
|
||||
TSPoint start_point,
|
||||
TSPoint end_point
|
||||
) {
|
||||
|
|
@ -661,8 +666,8 @@ void ts_query_context_set_point_range(
|
|||
self->end_point = end_point;
|
||||
}
|
||||
|
||||
static QueryState *ts_query_context_copy_state(
|
||||
TSQueryContext *self,
|
||||
static QueryState *ts_query_cursor_copy_state(
|
||||
TSQueryCursor *self,
|
||||
QueryState *state
|
||||
) {
|
||||
uint32_t new_list_id = capture_list_pool_acquire(&self->capture_list_pool);
|
||||
|
|
@ -682,7 +687,7 @@ static QueryState *ts_query_context_copy_state(
|
|||
return new_state;
|
||||
}
|
||||
|
||||
bool ts_query_context_next(TSQueryContext *self) {
|
||||
bool ts_query_cursor_next(TSQueryCursor *self) {
|
||||
if (self->finished_states.size > 0) {
|
||||
QueryState state = array_pop(&self->finished_states);
|
||||
capture_list_pool_release(&self->capture_list_pool, state.capture_list_id);
|
||||
|
|
@ -853,7 +858,7 @@ bool ts_query_context_next(TSQueryContext *self) {
|
|||
// siblings.
|
||||
QueryState *next_state = state;
|
||||
if (step->depth > 0 && (!step->field || field_occurs_in_later_sibling)) {
|
||||
QueryState *copy = ts_query_context_copy_state(self, state);
|
||||
QueryState *copy = ts_query_cursor_copy_state(self, state);
|
||||
if (copy) next_state = copy;
|
||||
}
|
||||
|
||||
|
|
@ -873,7 +878,7 @@ bool ts_query_context_next(TSQueryContext *self) {
|
|||
};
|
||||
}
|
||||
|
||||
// If the pattern is now done, then populate the query context's
|
||||
// If the pattern is now done, then populate the query cursor's
|
||||
// finished state.
|
||||
next_state->step_index++;
|
||||
QueryStep *next_step = step + 1;
|
||||
|
|
@ -902,7 +907,7 @@ bool ts_query_context_next(TSQueryContext *self) {
|
|||
return true;
|
||||
}
|
||||
|
||||
uint32_t ts_query_context_matched_pattern_index(const TSQueryContext *self) {
|
||||
uint32_t ts_query_cursor_matched_pattern_index(const TSQueryCursor *self) {
|
||||
if (self->finished_states.size > 0) {
|
||||
QueryState *state = array_back(&self->finished_states);
|
||||
return state->pattern_index;
|
||||
|
|
@ -910,8 +915,8 @@ uint32_t ts_query_context_matched_pattern_index(const TSQueryContext *self) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
const TSQueryCapture *ts_query_context_matched_captures(
|
||||
const TSQueryContext *self,
|
||||
const TSQueryCapture *ts_query_cursor_matched_captures(
|
||||
const TSQueryCursor *self,
|
||||
uint32_t *count
|
||||
) {
|
||||
if (self->finished_states.size > 0) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue