Skip to content

Understanding Trees โ€‹

What you'll learn โ€‹

  • What a concrete syntax tree contains and how to read one.
  • Named vs anonymous nodes, byte ranges, and points.

The tree for a * (b + 2) โ€‹

Parsing with the bundled expression grammar (examples/tree_walk.zig) prints:

text
program [0, 11] named=true
  expression [0, 11] named=true
    term [0, 11] named=true
      term [0, 1] named=true
        factor [0, 1] named=true
          identifier [0, 1] named=true
      * [2, 3] named=false
      factor [4, 11] named=true
        ( [4, 5] named=false
        expression [5, 10] named=true
          ...
        ) [10, 11] named=false

How it works โ€‹

  • The root is always the grammar's start symbol (program here). tree.rootNode() returns it.
  • Named nodes (identifier, expression) carry the language's structure. Anonymous nodes (+, (, )) are punctuation tokens โ€” visible in the tree but isNamed() is false.
  • Every node records an exact byte range plus row/column points. Bytes are the source of truth; columns count bytes per line in the same way the reference runtime does.
  • Nodes are pooled inside the Tree: a Node is just a (tree, index) handle, so reading metadata never allocates.

What you receive โ€‹

text
Source
  โ†“
Parser
  โ†“
Tree (owns pool + source copy)
  โ†“
Root Node (handle)
  โ†“
Child Nodes (handles)
  โ†“
Application

API used โ€‹

  • Tree โ€” rootNode, hasError, nodeCount, sourceText.
  • Node โ€” nodeType, isNamed, startByte, endByte, text.

Released under the MIT License.