or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

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

tree-navigation.mddocs/

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

```