0
# Syntax Tree Navigation
1
2
Navigate and inspect parsed syntax trees using Tree, Node, and TreeCursor objects. Trees are immutable data structures representing the parsed source code, with nodes providing detailed information about each element's position, type, and relationships.
3
4
## Capabilities
5
6
### Tree Access and Properties
7
8
Access the root node and tree-level properties including language information and included ranges.
9
10
```python { .api }
11
class Tree:
12
@property
13
def root_node(self) -> Node:
14
"""Root node of the syntax tree."""
15
16
@property
17
def included_ranges(self) -> list[Range]:
18
"""Byte ranges that were included during parsing."""
19
20
@property
21
def language(self) -> Language:
22
"""Language used for parsing this tree."""
23
24
def root_node_with_offset(
25
self,
26
offset_bytes: int,
27
offset_extent: Point | tuple[int, int],
28
) -> Node | None:
29
"""
30
Get root node with byte and extent offset applied.
31
32
Args:
33
offset_bytes: Byte offset to apply
34
offset_extent: Point offset to apply
35
36
Returns:
37
Root node with offset or None if invalid
38
"""
39
40
def copy(self) -> Tree:
41
"""Create a copy of this tree."""
42
43
def walk(self) -> TreeCursor:
44
"""Create a cursor for efficient tree traversal."""
45
46
def print_dot_graph(self, file) -> None:
47
"""
48
Print tree structure as DOT graph for visualization.
49
50
Args:
51
file: File object with fileno() method
52
"""
53
```
54
55
### Node Properties and Position
56
57
Access node properties including type, position, content, and structural relationships.
58
59
```python { .api }
60
class Node:
61
@property
62
def id(self) -> int:
63
"""Unique identifier for this node."""
64
65
@property
66
def kind_id(self) -> int:
67
"""Node kind ID from the grammar."""
68
69
@property
70
def grammar_id(self) -> int:
71
"""Grammar ID this node belongs to."""
72
73
@property
74
def grammar_name(self) -> str:
75
"""Grammar name this node belongs to."""
76
77
@property
78
def type(self) -> str:
79
"""Node type name (e.g., 'function_definition', 'identifier')."""
80
81
@property
82
def is_named(self) -> bool:
83
"""Whether this node represents a named language construct."""
84
85
@property
86
def is_extra(self) -> bool:
87
"""Whether this node represents extra content (comments, whitespace)."""
88
89
@property
90
def has_changes(self) -> bool:
91
"""Whether this node has been edited."""
92
93
@property
94
def has_error(self) -> bool:
95
"""Whether this node contains parse errors."""
96
97
@property
98
def is_error(self) -> bool:
99
"""Whether this node is an error node."""
100
101
@property
102
def is_missing(self) -> bool:
103
"""Whether this node represents missing required content."""
104
105
@property
106
def start_byte(self) -> int:
107
"""Starting byte position in source code."""
108
109
@property
110
def end_byte(self) -> int:
111
"""Ending byte position in source code."""
112
113
@property
114
def byte_range(self) -> tuple[int, int]:
115
"""Byte range as (start_byte, end_byte) tuple."""
116
117
@property
118
def range(self) -> Range:
119
"""Range object with byte and point information."""
120
121
@property
122
def start_point(self) -> Point:
123
"""Starting position as (row, column) point."""
124
125
@property
126
def end_point(self) -> Point:
127
"""Ending position as (row, column) point."""
128
129
@property
130
def text(self) -> bytes | None:
131
"""Text content of this node as bytes."""
132
133
@property
134
def parent(self) -> Node | None:
135
"""Parent node or None if this is the root."""
136
137
@property
138
def descendant_count(self) -> int:
139
"""Total number of descendant nodes."""
140
141
@property
142
def parse_state(self) -> int:
143
"""Parse state ID for this node."""
144
145
@property
146
def next_parse_state(self) -> int:
147
"""Next parse state ID for this node."""
148
149
def walk(self) -> TreeCursor:
150
"""Create a cursor for traversing from this node."""
151
```
152
153
### Child Node Access
154
155
Access child nodes by index, field name, or position within the source.
156
157
```python { .api }
158
class Node:
159
@property
160
def children(self) -> list[Node]:
161
"""All child nodes including unnamed nodes."""
162
163
@property
164
def child_count(self) -> int:
165
"""Total number of child nodes."""
166
167
@property
168
def named_children(self) -> list[Node]:
169
"""Named child nodes only."""
170
171
@property
172
def named_child_count(self) -> int:
173
"""Number of named child nodes."""
174
175
def child(self, index: int) -> Node | None:
176
"""
177
Get child node by index.
178
179
Args:
180
index: Child index (0-based)
181
182
Returns:
183
Child node or None if index is out of bounds
184
"""
185
186
def named_child(self, index: int) -> Node | None:
187
"""
188
Get named child node by index.
189
190
Args:
191
index: Named child index (0-based)
192
193
Returns:
194
Named child node or None if index is out of bounds
195
"""
196
197
def child_by_field_name(self, name: str) -> Node | None:
198
"""
199
Get child node by field name.
200
201
Args:
202
name: Field name (e.g., 'name', 'body', 'parameters')
203
204
Returns:
205
Child node with the given field name or None
206
"""
207
208
def child_by_field_id(self, id: int) -> Node | None:
209
"""
210
Get child node by field ID.
211
212
Args:
213
id: Field ID from the grammar
214
215
Returns:
216
Child node with the given field ID or None
217
"""
218
219
def children_by_field_name(self, name: str) -> list[Node]:
220
"""
221
Get all child nodes with the given field name.
222
223
Args:
224
name: Field name
225
226
Returns:
227
List of child nodes with the field name
228
"""
229
230
def children_by_field_id(self, id: int) -> list[Node]:
231
"""
232
Get all child nodes with the given field ID.
233
234
Args:
235
id: Field ID
236
237
Returns:
238
List of child nodes with the field ID
239
"""
240
241
def field_name_for_child(self, child_index: int) -> str | None:
242
"""
243
Get field name for child at the given index.
244
245
Args:
246
child_index: Child index (0-based)
247
248
Returns:
249
Field name for the child or None if no field name
250
"""
251
252
def field_name_for_named_child(self, child_index: int) -> str | None:
253
"""
254
Get field name for named child at the given index.
255
256
Args:
257
child_index: Named child index (0-based)
258
259
Returns:
260
Field name for the named child or None if no field name
261
"""
262
263
def first_child_for_byte(self, byte: int) -> Node | None:
264
"""
265
Get first child that contains the given byte position.
266
267
Args:
268
byte: Byte position in source
269
270
Returns:
271
First child containing the byte or None
272
"""
273
274
def first_named_child_for_byte(self, byte: int) -> Node | None:
275
"""
276
Get first named child that contains the given byte position.
277
278
Args:
279
byte: Byte position in source
280
281
Returns:
282
First named child containing the byte or None
283
"""
284
```
285
286
### Sibling Node Navigation
287
288
Navigate between sibling nodes at the same tree level.
289
290
```python { .api }
291
class Node:
292
@property
293
def next_sibling(self) -> Node | None:
294
"""Next sibling node or None if this is the last child."""
295
296
@property
297
def prev_sibling(self) -> Node | None:
298
"""Previous sibling node or None if this is the first child."""
299
300
@property
301
def next_named_sibling(self) -> Node | None:
302
"""Next named sibling node or None."""
303
304
@property
305
def prev_named_sibling(self) -> Node | None:
306
"""Previous named sibling node or None."""
307
```
308
309
### Descendant Search
310
311
Find descendant nodes by position ranges or relationships.
312
313
```python { .api }
314
class Node:
315
def descendant_for_byte_range(
316
self,
317
start_byte: int,
318
end_byte: int,
319
) -> Node | None:
320
"""
321
Get smallest descendant that spans the given byte range.
322
323
Args:
324
start_byte: Start of byte range
325
end_byte: End of byte range
326
327
Returns:
328
Descendant node spanning the range or None
329
"""
330
331
def named_descendant_for_byte_range(
332
self,
333
start_byte: int,
334
end_byte: int,
335
) -> Node | None:
336
"""
337
Get smallest named descendant that spans the given byte range.
338
339
Args:
340
start_byte: Start of byte range
341
end_byte: End of byte range
342
343
Returns:
344
Named descendant node spanning the range or None
345
"""
346
347
def descendant_for_point_range(
348
self,
349
start_point: Point | tuple[int, int],
350
end_point: Point | tuple[int, int],
351
) -> Node | None:
352
"""
353
Get smallest descendant that spans the given point range.
354
355
Args:
356
start_point: Start point (row, column)
357
end_point: End point (row, column)
358
359
Returns:
360
Descendant node spanning the range or None
361
"""
362
363
def named_descendant_for_point_range(
364
self,
365
start_point: Point | tuple[int, int],
366
end_point: Point | tuple[int, int],
367
) -> Node | None:
368
"""
369
Get smallest named descendant that spans the given point range.
370
371
Args:
372
start_point: Start point (row, column)
373
end_point: End point (row, column)
374
375
Returns:
376
Named descendant node spanning the range or None
377
"""
378
379
def child_with_descendant(self, descendant: Node) -> Node | None:
380
"""
381
Get child node that contains the given descendant.
382
383
Args:
384
descendant: Descendant node to find parent for
385
386
Returns:
387
Child node containing the descendant or None
388
"""
389
```
390
391
### Efficient Tree Traversal with TreeCursor
392
393
Use TreeCursor for efficient navigation of large syntax trees without creating intermediate Node objects.
394
395
```python { .api }
396
class TreeCursor:
397
@property
398
def node(self) -> Node | None:
399
"""Current node at cursor position."""
400
401
@property
402
def field_id(self) -> int | None:
403
"""Field ID of current position or None."""
404
405
@property
406
def field_name(self) -> str | None:
407
"""Field name of current position or None."""
408
409
@property
410
def depth(self) -> int:
411
"""Current depth in the tree."""
412
413
@property
414
def descendant_index(self) -> int:
415
"""Index of current node among all descendants."""
416
417
def copy(self) -> TreeCursor:
418
"""Create a copy of this cursor."""
419
420
def reset(self, node: Node) -> None:
421
"""
422
Reset cursor to the given node.
423
424
Args:
425
node: Node to reset cursor to
426
"""
427
428
def reset_to(self, cursor: TreeCursor) -> None:
429
"""
430
Reset cursor to match another cursor's position.
431
432
Args:
433
cursor: Cursor to copy position from
434
"""
435
436
def goto_first_child(self) -> bool:
437
"""
438
Move cursor to first child of current node.
439
440
Returns:
441
True if moved successfully, False if no children
442
"""
443
444
def goto_last_child(self) -> bool:
445
"""
446
Move cursor to last child of current node.
447
448
Returns:
449
True if moved successfully, False if no children
450
"""
451
452
def goto_parent(self) -> bool:
453
"""
454
Move cursor to parent of current node.
455
456
Returns:
457
True if moved successfully, False if at root
458
"""
459
460
def goto_next_sibling(self) -> bool:
461
"""
462
Move cursor to next sibling of current node.
463
464
Returns:
465
True if moved successfully, False if no next sibling
466
"""
467
468
def goto_previous_sibling(self) -> bool:
469
"""
470
Move cursor to previous sibling of current node.
471
472
Returns:
473
True if moved successfully, False if no previous sibling
474
"""
475
476
def goto_descendant(self, index: int) -> None:
477
"""
478
Move cursor to descendant at the given index.
479
480
Args:
481
index: Descendant index to move to
482
"""
483
484
def goto_first_child_for_byte(self, byte: int) -> int | None:
485
"""
486
Move cursor to first child that contains the given byte.
487
488
Args:
489
byte: Byte position to search for
490
491
Returns:
492
Child index if found, None otherwise
493
"""
494
495
def goto_first_child_for_point(self, point: Point | tuple[int, int]) -> int | None:
496
"""
497
Move cursor to first child that contains the given point.
498
499
Args:
500
point: Point (row, column) to search for
501
502
Returns:
503
Child index if found, None otherwise
504
"""
505
```
506
507
## Usage Examples
508
509
### Basic Node Navigation
510
511
```python
512
from tree_sitter import Language, Parser
513
import tree_sitter_python
514
515
# Setup and parse
516
language = Language(tree_sitter_python.language())
517
parser = Parser(language)
518
519
code = b'''
520
def calculate(x, y):
521
result = x + y
522
return result
523
'''
524
525
tree = parser.parse(code)
526
root = tree.root_node
527
528
# Navigate to function definition
529
function_def = root.children[0]
530
print(f"Function type: {function_def.type}")
531
print(f"Function position: {function_def.start_point} to {function_def.end_point}")
532
533
# Get function name
534
function_name = function_def.child_by_field_name("name")
535
print(f"Function name: {function_name.text}")
536
537
# Get parameters
538
parameters = function_def.child_by_field_name("parameters")
539
print(f"Parameter count: {parameters.named_child_count}")
540
541
# Get function body
542
body = function_def.child_by_field_name("body")
543
print(f"Body has {body.named_child_count} statements")
544
```
545
546
### TreeCursor for Efficient Traversal
547
548
```python
549
def traverse_tree(tree):
550
"""Efficiently traverse entire tree using cursor."""
551
cursor = tree.walk()
552
553
visited_children = False
554
while True:
555
if not visited_children:
556
print(f"Visiting {cursor.node.type} at depth {cursor.depth}")
557
if not cursor.goto_first_child():
558
visited_children = True
559
elif cursor.goto_next_sibling():
560
visited_children = False
561
elif not cursor.goto_parent():
562
break
563
564
traverse_tree(tree)
565
```
566
567
### Finding Nodes by Position
568
569
```python
570
# Find node at specific byte position
571
byte_pos = 25
572
node_at_pos = root.descendant_for_byte_range(byte_pos, byte_pos + 1)
573
print(f"Node at byte {byte_pos}: {node_at_pos.type}")
574
575
# Find node at specific line/column
576
point = (2, 4) # Line 2, column 4
577
node_at_point = root.descendant_for_point_range(point, point)
578
print(f"Node at {point}: {node_at_point.type}")
579
```
580
581
### Working with Field Names
582
583
```python
584
# Get field information
585
function_def = root.children[0]
586
587
# Iterate through children with field names
588
for i, child in enumerate(function_def.children):
589
field_name = function_def.field_name_for_child(i)
590
if field_name:
591
print(f"Child {i} ({child.type}) has field name: {field_name}")
592
else:
593
print(f"Child {i} ({child.type}) has no field name")
594
595
# Get all children with specific field
596
body_children = function_def.children_by_field_name("body")
597
print(f"Found {len(body_children)} body elements")
598
```