Skip to content

Commit 82f3d32

Browse files
authored
Merge pull request tree-sitter#1127 from dcreager/query-mempool
query: Allow unlimited pending matches
2 parents 0c7b37a + cc20708 commit 82f3d32

File tree

9 files changed

+141
-89
lines changed

9 files changed

+141
-89
lines changed

cli/src/tests/query_test.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1645,6 +1645,7 @@ fn test_query_matches_with_too_many_permutations_to_track() {
16451645
parser.set_language(language).unwrap();
16461646
let tree = parser.parse(&source, None).unwrap();
16471647
let mut cursor = QueryCursor::new();
1648+
cursor.set_match_limit(32);
16481649
let matches = cursor.matches(&query, tree.root_node(), to_callback(&source));
16491650

16501651
// For this pathological query, some match permutations will be dropped.
@@ -1686,6 +1687,7 @@ fn test_query_matches_with_alternatives_and_too_many_permutations_to_track() {
16861687
parser.set_language(language).unwrap();
16871688
let tree = parser.parse(&source, None).unwrap();
16881689
let mut cursor = QueryCursor::new();
1690+
cursor.set_match_limit(32);
16891691
let matches = cursor.matches(&query, tree.root_node(), to_callback(&source));
16901692

16911693
assert_eq!(
@@ -2765,6 +2767,7 @@ fn test_query_captures_with_too_many_nested_results() {
27652767
parser.set_language(language).unwrap();
27662768
let tree = parser.parse(&source, None).unwrap();
27672769
let mut cursor = QueryCursor::new();
2770+
cursor.set_match_limit(32);
27682771
let captures = cursor.captures(&query, tree.root_node(), to_callback(&source));
27692772
let captures = collect_captures(captures, &query, &source);
27702773

lib/binding_rust/bindings.rs

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -726,15 +726,27 @@ extern "C" {
726726
pub fn ts_query_cursor_exec(arg1: *mut TSQueryCursor, arg2: *const TSQuery, arg3: TSNode);
727727
}
728728
extern "C" {
729-
#[doc = " Check if this cursor has exceeded its maximum number of in-progress"]
730-
#[doc = " matches."]
729+
#[doc = " Manage the maximum number of in-progress matches allowed by this query"]
730+
#[doc = " cursor."]
731731
#[doc = ""]
732-
#[doc = " Currently, query cursors have a fixed capacity for storing lists"]
733-
#[doc = " of in-progress captures. If this capacity is exceeded, then the"]
734-
#[doc = " earliest-starting match will silently be dropped to make room for"]
735-
#[doc = " further matches."]
732+
#[doc = " Query cursors have a maximum capacity for storing lists of in-progress"]
733+
#[doc = " captures. If this capacity is exceeded, then the earliest-starting match will"]
734+
#[doc = " silently be dropped to make room for further matches."]
735+
#[doc = ""]
736+
#[doc = " By default, this limit is 65,536 pending matches, which is effectively"]
737+
#[doc = " unlimited for most queries and syntax trees. You can optionally set this to a"]
738+
#[doc = " lower number if you want to have (and check) a tighter bound on query"]
739+
#[doc = " complexity."]
740+
#[doc = ""]
741+
#[doc = " If you update the match limit, it must be > 0 and <= 65536."]
736742
pub fn ts_query_cursor_did_exceed_match_limit(arg1: *const TSQueryCursor) -> bool;
737743
}
744+
extern "C" {
745+
pub fn ts_query_cursor_match_limit(arg1: *const TSQueryCursor) -> u32;
746+
}
747+
extern "C" {
748+
pub fn ts_query_cursor_set_match_limit(arg1: *mut TSQueryCursor, arg2: u32);
749+
}
738750
extern "C" {
739751
#[doc = " Set the range of bytes or (row, column) positions in which the query"]
740752
#[doc = " will be executed."]

lib/binding_rust/lib.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1598,6 +1598,19 @@ impl<'a> QueryCursor {
15981598
QueryCursor(unsafe { NonNull::new_unchecked(ffi::ts_query_cursor_new()) })
15991599
}
16001600

1601+
/// Return the maximum number of in-progress matches for this cursor.
1602+
pub fn match_limit(&self) -> u32 {
1603+
unsafe { ffi::ts_query_cursor_match_limit(self.0.as_ptr()) }
1604+
}
1605+
1606+
/// Set the maximum number of in-progress matches for this cursor. The limit must be > 0 and
1607+
/// <= 65536.
1608+
pub fn set_match_limit(&mut self, limit: u32) {
1609+
unsafe {
1610+
ffi::ts_query_cursor_set_match_limit(self.0.as_ptr(), limit);
1611+
}
1612+
}
1613+
16011614
/// Check if, on its last execution, this cursor exceeded its maximum number of
16021615
/// in-progress matches.
16031616
pub fn did_exceed_match_limit(&self) -> bool {

lib/binding_web/binding.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -594,9 +594,15 @@ void ts_query_matches_wasm(
594594
uint32_t start_row,
595595
uint32_t start_column,
596596
uint32_t end_row,
597-
uint32_t end_column
597+
uint32_t end_column,
598+
uint32_t match_limit
598599
) {
599600
if (!scratch_query_cursor) scratch_query_cursor = ts_query_cursor_new();
601+
if (match_limit == 0) {
602+
ts_query_cursor_set_match_limit(scratch_query_cursor, UINT32_MAX);
603+
} else {
604+
ts_query_cursor_set_match_limit(scratch_query_cursor, match_limit);
605+
}
600606

601607
TSNode node = unmarshal_node(tree);
602608
TSPoint start_point = {start_row, code_unit_to_byte(start_column)};
@@ -635,9 +641,15 @@ void ts_query_captures_wasm(
635641
uint32_t start_row,
636642
uint32_t start_column,
637643
uint32_t end_row,
638-
uint32_t end_column
644+
uint32_t end_column,
645+
uint32_t match_limit
639646
) {
640647
if (!scratch_query_cursor) scratch_query_cursor = ts_query_cursor_new();
648+
if (match_limit == 0) {
649+
ts_query_cursor_set_match_limit(scratch_query_cursor, UINT32_MAX);
650+
} else {
651+
ts_query_cursor_set_match_limit(scratch_query_cursor, match_limit);
652+
}
641653

642654
TSNode node = unmarshal_node(tree);
643655
TSPoint start_point = {start_row, code_unit_to_byte(start_column)};

lib/binding_web/binding.js

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -953,9 +953,17 @@ class Query {
953953
this[0] = 0;
954954
}
955955

956-
matches(node, startPosition, endPosition) {
956+
matches(node, startPosition, endPosition, options) {
957957
if (!startPosition) startPosition = ZERO_POINT;
958958
if (!endPosition) endPosition = ZERO_POINT;
959+
if (!options) options = {};
960+
961+
let matchLimit = options.matchLimit;
962+
if (typeof matchLimit === 'undefined') {
963+
matchLimit = 0;
964+
} else if (typeof matchLimit !== 'number') {
965+
throw new Error('Arguments must be numbers');
966+
}
959967

960968
marshalNode(node);
961969

@@ -965,7 +973,8 @@ class Query {
965973
startPosition.row,
966974
startPosition.column,
967975
endPosition.row,
968-
endPosition.column
976+
endPosition.column,
977+
matchLimit
969978
);
970979

971980
const rawCount = getValue(TRANSFER_BUFFER, 'i32');
@@ -1000,9 +1009,17 @@ class Query {
10001009
return result;
10011010
}
10021011

1003-
captures(node, startPosition, endPosition) {
1012+
captures(node, startPosition, endPosition, options) {
10041013
if (!startPosition) startPosition = ZERO_POINT;
10051014
if (!endPosition) endPosition = ZERO_POINT;
1015+
if (!options) options = {};
1016+
1017+
let matchLimit = options.matchLimit;
1018+
if (typeof matchLimit === 'undefined') {
1019+
matchLimit = 0;
1020+
} else if (typeof matchLimit !== 'number') {
1021+
throw new Error('Arguments must be numbers');
1022+
}
10061023

10071024
marshalNode(node);
10081025

@@ -1012,7 +1029,8 @@ class Query {
10121029
startPosition.row,
10131030
startPosition.column,
10141031
endPosition.row,
1015-
endPosition.column
1032+
endPosition.column,
1033+
matchLimit
10161034
);
10171035

10181036
const count = getValue(TRANSFER_BUFFER, 'i32');

lib/binding_web/test/query-test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ describe("Query", () => {
256256
(array (identifier) @pre (identifier) @post)
257257
`);
258258

259-
const captures = query.captures(tree.rootNode);
259+
const captures = query.captures(tree.rootNode, null, null, {matchLimit: 32});
260260
assert.ok(query.didExceedMatchLimit());
261261
});
262262
});

lib/include/tree_sitter/api.h

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -798,15 +798,19 @@ void ts_query_cursor_delete(TSQueryCursor *);
798798
void ts_query_cursor_exec(TSQueryCursor *, const TSQuery *, TSNode);
799799

800800
/**
801-
* Check if this cursor has exceeded its maximum number of in-progress
802-
* matches.
801+
* Manage the maximum number of in-progress matches allowed by this query
802+
* cursor.
803803
*
804-
* Currently, query cursors have a fixed capacity for storing lists
805-
* of in-progress captures. If this capacity is exceeded, then the
806-
* earliest-starting match will silently be dropped to make room for
807-
* further matches.
804+
* Query cursors have an optional maximum capacity for storing lists of
805+
* in-progress captures. If this capacity is exceeded, then the
806+
* earliest-starting match will silently be dropped to make room for further
807+
* matches. This maximum capacity is optional — by default, query cursors allow
808+
* any number of pending matches, dynamically allocating new space for them as
809+
* needed as the query is executed.
808810
*/
809811
bool ts_query_cursor_did_exceed_match_limit(const TSQueryCursor *);
812+
uint32_t ts_query_cursor_match_limit(const TSQueryCursor *);
813+
void ts_query_cursor_set_match_limit(TSQueryCursor *, uint32_t);
810814

811815
/**
812816
* Set the range of bytes or (row, column) positions in which the query

lib/src/bits.h

Lines changed: 0 additions & 42 deletions
This file was deleted.

0 commit comments

Comments
 (0)