or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

incremental-parsing.mdindex.mdlanguage-parser.mdqueries.mdtree-navigation.md

queries.mddocs/

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