0
# Pattern Matching and Queries
1
2
Tree-sitter's query system enables powerful pattern matching against syntax trees using a specialized query language. Queries can find specific code patterns, extract information, and perform structural analysis across parsed source code.
3
4
## Capabilities
5
6
### Query Creation and Introspection
7
8
Create queries from query strings and inspect their structure including patterns, captures, and strings.
9
10
```python { .api }
11
class Query:
12
def __init__(self, language: Language, source: str) -> None:
13
"""
14
Create a query from query source string.
15
16
Args:
17
language: Language to create query for
18
source: Query string in Tree-sitter query syntax
19
20
Raises:
21
QueryError: If query syntax is invalid
22
"""
23
24
def pattern_count(self) -> int:
25
"""Number of patterns in this query."""
26
27
def capture_count(self) -> int:
28
"""Number of captures defined in this query."""
29
30
def string_count(self) -> int:
31
"""Number of string literals in this query."""
32
33
def start_byte_for_pattern(self, index: int) -> int:
34
"""
35
Get start byte position of pattern in query source.
36
37
Args:
38
index: Pattern index
39
40
Returns:
41
Start byte position of pattern
42
"""
43
44
def end_byte_for_pattern(self, index: int) -> int:
45
"""
46
Get end byte position of pattern in query source.
47
48
Args:
49
index: Pattern index
50
51
Returns:
52
End byte position of pattern
53
"""
54
55
def capture_name(self, index: int) -> str:
56
"""
57
Get capture name by index.
58
59
Args:
60
index: Capture index
61
62
Returns:
63
Capture name
64
"""
65
66
def capture_quantifier(
67
self,
68
pattern_index: int,
69
capture_index: int,
70
) -> str:
71
"""
72
Get capture quantifier for pattern and capture.
73
74
Args:
75
pattern_index: Pattern index
76
capture_index: Capture index within pattern
77
78
Returns:
79
Quantifier string: "", "?", "*", or "+"
80
"""
81
82
def string_value(self, index: int) -> str:
83
"""
84
Get string literal value by index.
85
86
Args:
87
index: String index
88
89
Returns:
90
String literal value
91
"""
92
```
93
94
### Query Pattern Analysis
95
96
Analyze pattern properties and behavior including root status and locality.
97
98
```python { .api }
99
class Query:
100
def is_pattern_rooted(self, index: int) -> bool:
101
"""
102
Check if pattern is rooted (starts at tree root).
103
104
Args:
105
index: Pattern index
106
107
Returns:
108
True if pattern must start at root
109
"""
110
111
def is_pattern_non_local(self, index: int) -> bool:
112
"""
113
Check if pattern is non-local (can match across subtrees).
114
115
Args:
116
index: Pattern index
117
118
Returns:
119
True if pattern is non-local
120
"""
121
122
def is_pattern_guaranteed_at_step(self, index: int) -> bool:
123
"""
124
Check if pattern has guaranteed matches at step.
125
126
Args:
127
index: Pattern index
128
129
Returns:
130
True if pattern has guaranteed step matches
131
"""
132
133
def pattern_settings(self, index: int) -> dict[str, str | None]:
134
"""
135
Get pattern settings as key-value pairs.
136
137
Args:
138
index: Pattern index
139
140
Returns:
141
Dictionary of pattern settings
142
"""
143
144
def pattern_assertions(self, index: int) -> dict[str, tuple[str | None, bool]]:
145
"""
146
Get pattern assertions.
147
148
Args:
149
index: Pattern index
150
151
Returns:
152
Dictionary mapping assertion names to (value, negated) tuples
153
"""
154
```
155
156
### Query Modification
157
158
Disable specific captures or patterns to customize query behavior.
159
160
```python { .api }
161
class Query:
162
def disable_capture(self, name: str) -> None:
163
"""
164
Disable capture by name.
165
166
Args:
167
name: Capture name to disable
168
"""
169
170
def disable_pattern(self, index: int) -> None:
171
"""
172
Disable pattern by index.
173
174
Args:
175
index: Pattern index to disable
176
"""
177
```
178
179
### Query Execution with QueryCursor
180
181
Execute queries against syntax trees and retrieve matches or captures.
182
183
```python { .api }
184
class QueryCursor:
185
def __init__(
186
self,
187
query: Query,
188
*,
189
match_limit: int = 0xFFFFFFFF,
190
) -> None:
191
"""
192
Create query cursor for executing queries.
193
194
Args:
195
query: Query to execute
196
match_limit: Maximum number of matches to return
197
"""
198
199
@property
200
def match_limit(self) -> int:
201
"""Maximum number of matches (can be get/set/deleted)."""
202
203
@match_limit.setter
204
def match_limit(self, limit: int) -> None: ...
205
206
@match_limit.deleter
207
def match_limit(self) -> None: ...
208
209
@property
210
def did_exceed_match_limit(self) -> bool:
211
"""Whether the last query execution exceeded match limit."""
212
213
def set_max_start_depth(self, depth: int) -> None:
214
"""
215
Set maximum depth to start matching patterns.
216
217
Args:
218
depth: Maximum starting depth
219
"""
220
221
def set_byte_range(self, start: int, end: int) -> None:
222
"""
223
Limit query execution to specific byte range.
224
225
Args:
226
start: Start byte position
227
end: End byte position
228
"""
229
230
def set_point_range(
231
self,
232
start: Point | tuple[int, int],
233
end: Point | tuple[int, int],
234
) -> None:
235
"""
236
Limit query execution to specific point range.
237
238
Args:
239
start: Start point (row, column)
240
end: End point (row, column)
241
"""
242
```
243
244
### Capture Extraction
245
246
Extract all captures from query execution, grouped by capture name.
247
248
```python { .api }
249
class QueryCursor:
250
def captures(
251
self,
252
node: Node,
253
predicate: QueryPredicate | None = None,
254
progress_callback: Callable[[int], bool] | None = None,
255
) -> dict[str, list[Node]]:
256
"""
257
Execute query and return all captures grouped by name.
258
259
Args:
260
node: Root node to search from
261
predicate: Custom predicate function for filtering
262
progress_callback: Progress monitoring callback
263
264
Returns:
265
Dictionary mapping capture names to lists of matching nodes
266
"""
267
```
268
269
### Match Extraction
270
271
Extract complete matches with pattern information and grouped captures.
272
273
```python { .api }
274
class QueryCursor:
275
def matches(
276
self,
277
node: Node,
278
predicate: QueryPredicate | None = None,
279
progress_callback: Callable[[int], bool] | None = None,
280
) -> list[tuple[int, dict[str, list[Node]]]]:
281
"""
282
Execute query and return complete matches.
283
284
Args:
285
node: Root node to search from
286
predicate: Custom predicate function for filtering
287
progress_callback: Progress monitoring callback
288
289
Returns:
290
List of (pattern_index, captures) tuples where captures
291
is a dictionary mapping capture names to lists of nodes
292
"""
293
```
294
295
### Custom Query Predicates
296
297
Implement custom logic for query filtering using the QueryPredicate protocol.
298
299
```python { .api }
300
class QueryPredicate:
301
def __call__(
302
self,
303
predicate: str,
304
args: list[tuple[str, str]],
305
pattern_index: int,
306
captures: dict[str, list[Node]],
307
) -> bool:
308
"""
309
Custom predicate function for query filtering.
310
311
Args:
312
predicate: Predicate name used in query
313
args: List of (value, type) argument tuples
314
pattern_index: Index of current pattern being matched
315
captures: Current captures for this pattern
316
317
Returns:
318
True if predicate matches, False otherwise
319
"""
320
```
321
322
### Query Errors
323
324
Handle query syntax and execution errors.
325
326
```python { .api }
327
class QueryError(ValueError):
328
"""Raised when query syntax is invalid or execution fails."""
329
```
330
331
## Usage Examples
332
333
### Basic Query Usage
334
335
```python
336
from tree_sitter import Language, Parser, Query, QueryCursor
337
import tree_sitter_python
338
339
# Setup
340
language = Language(tree_sitter_python.language())
341
parser = Parser(language)
342
343
code = b'''
344
def calculate(x, y):
345
result = x + y
346
return result
347
348
def process(data):
349
value = data * 2
350
return value
351
'''
352
353
tree = parser.parse(code)
354
355
# Create query to find function definitions
356
query = Query(language, '''
357
(function_definition
358
name: (identifier) @function.name
359
parameters: (parameters) @function.params
360
body: (block) @function.body)
361
''')
362
363
# Execute query
364
cursor = QueryCursor(query)
365
captures = cursor.captures(tree.root_node)
366
367
print(f"Found {len(captures['function.name'])} functions:")
368
for func_name in captures['function.name']:
369
print(f" - {func_name.text.decode()}")
370
```
371
372
### Complex Query Patterns
373
374
```python
375
# Query for variable assignments within functions
376
assignment_query = Query(language, '''
377
(function_definition
378
name: (identifier) @func.name
379
body: (block
380
(expression_statement
381
(assignment
382
left: (identifier) @var.name
383
right: (_) @var.value))))
384
''')
385
386
cursor = QueryCursor(assignment_query)
387
matches = cursor.matches(tree.root_node)
388
389
for pattern_idx, match_captures in matches:
390
func_name = match_captures['func.name'][0].text.decode()
391
var_name = match_captures['var.name'][0].text.decode()
392
print(f"In function {func_name}, variable {var_name} is assigned")
393
```
394
395
### Query with Predicates
396
397
```python
398
# Query with string matching predicate
399
predicate_query = Query(language, '''
400
(call
401
function: (identifier) @func.name
402
arguments: (argument_list
403
(string) @arg.string))
404
405
(#eq? @func.name "print")
406
''')
407
408
# Custom predicate function
409
def custom_predicate(predicate, args, pattern_index, captures):
410
if predicate == "eq?":
411
capture_name, expected_value = args[0][0], args[1][0]
412
if capture_name in captures:
413
actual_value = captures[capture_name][0].text.decode()
414
return actual_value == expected_value
415
return False
416
417
cursor = QueryCursor(predicate_query)
418
matches = cursor.matches(tree.root_node, predicate=custom_predicate)
419
```
420
421
### Query Optimization
422
423
```python
424
# Configure cursor for performance
425
cursor = QueryCursor(query, match_limit=100)
426
cursor.set_max_start_depth(3) # Don't start matching too deep
427
cursor.set_byte_range(0, 500) # Limit to first 500 bytes
428
429
# Check if limit was exceeded
430
captures = cursor.captures(tree.root_node)
431
if cursor.did_exceed_match_limit:
432
print("Query hit match limit - results may be incomplete")
433
```
434
435
### Query Introspection
436
437
```python
438
# Analyze query structure
439
print(f"Query has {query.pattern_count()} patterns")
440
print(f"Query has {query.capture_count()} captures")
441
442
for i in range(query.capture_count()):
443
capture_name = query.capture_name(i)
444
print(f"Capture {i}: @{capture_name}")
445
446
# Check pattern properties
447
for i in range(query.pattern_count()):
448
print(f"Pattern {i}:")
449
print(f" Rooted: {query.is_pattern_rooted(i)}")
450
print(f" Non-local: {query.is_pattern_non_local(i)}")
451
print(f" Settings: {query.pattern_settings(i)}")
452
```
453
454
### Progress Monitoring
455
456
```python
457
def progress_callback(current_step):
458
"""Progress callback that can cancel long-running queries."""
459
print(f"Query progress: step {current_step}")
460
# Return False to cancel query execution
461
return current_step < 1000
462
463
cursor = QueryCursor(query)
464
captures = cursor.captures(
465
tree.root_node,
466
progress_callback=progress_callback
467
)
468
```
469
470
## Query Language Reference
471
472
Tree-sitter queries use S-expression syntax to match tree structures:
473
474
- `(node_type)` - Match nodes of specific type
475
- `@capture.name` - Capture matched nodes with a name
476
- `field: (pattern)` - Match nodes in specific fields
477
- `"literal"` - Match literal text content
478
- `(_)` - Match any node type
479
- `(#predicate? @capture "value")` - Apply predicates to filter matches
480
481
Quantifiers:
482
- `pattern?` - Optional (0 or 1 matches)
483
- `pattern*` - Zero or more matches
484
- `pattern+` - One or more matches
485
486
Advanced features:
487
- `(#eq? @capture "value")` - String equality predicate
488
- `(#match? @capture "regex")` - Regex matching predicate
489
- `(#set! key "value")` - Set pattern metadata