Skip to main content

Grammar DSL

The Tree-sitter grammar DSL provides a set of built-in functions for defining grammar rules. This page documents all available functions and grammar properties.

Core Concepts

The $ Symbol

Every grammar rule is written as a JavaScript function that takes a parameter conventionally called $. Use $.identifier to refer to another grammar symbol within a rule.
Avoid names starting with $.MISSING or $.UNEXPECTED as they have special meaning for the tree-sitter test command.

Terminal Symbols

Terminal symbols are described using JavaScript strings and regular expressions.
Tree-sitter doesn’t use JavaScript’s regex engine at runtime. It generates regex-matching logic based on Rust regex syntax as part of the parser.

Rule Functions

seq() - Sequences

Matches rules in order, one after another.
Analogous to: Writing symbols next to each other in EBNF notation

choice() - Alternatives

Matches one of a set of possible rules.
The order of arguments does not matter for parsing, but it affects the order in which alternatives are tried during error recovery.
Analogous to: The | (pipe) operator in EBNF notation

repeat() - Zero or More

Matches zero or more occurrences of a rule.
Analogous to: The {x} (curly brace) syntax in EBNF notation

repeat1() - One or More

Matches one or more occurrences of a rule.
Analogous to: The + operator in regex or EBNF

optional() - Zero or One

Matches zero or one occurrence of a rule.
Analogous to: The [x] (square bracket) syntax in EBNF notation

Precedence Functions

prec() - Numeric Precedence

Assigns a numerical precedence to resolve LR(1) conflicts.
The default precedence of all rules is zero. Higher numbers = higher precedence.

prec.left() - Left Associativity

Marks a rule as left-associative, optionally with precedence.
Effect: When parsing a + b + c, prefer matching (a + b) + c over a + (b + c)

prec.right() - Right Associativity

Marks a rule as right-associative.
Effect: When parsing a = b = c, prefer matching a = (b = c) over (a = b) = c

prec.dynamic() - Dynamic Precedence

Applies precedence at runtime instead of parser generation time.
Only use prec.dynamic() when handling genuine ambiguities declared in the conflicts field.

Token Functions

token() - Single Token

Marks a rule as producing a single token.
The token() function only accepts terminal rules (strings/regexes). token($.foo) will not work unless $.foo is a terminal.

token.immediate() - No Whitespace

Matches a token only if there is no whitespace before it.
Use case: When whitespace would change the meaning of the token

Naming Functions

alias() - Rename Nodes

Causes a rule to appear with a different name in the syntax tree.

field() - Named Fields

Assigns a field name to child nodes for easier access.
Use fields to make tree traversal code more readable and resilient to grammar changes.

reserved() - Contextual Keywords

Overrides the global reserved word set for contextual keywords.

Grammar Properties

name

The name of your language (required).

rules

The grammar rules (required). The first rule is the start symbol.

extras

Tokens that may appear anywhere in the language.
The default value of extras is [/\s/] (whitespace). To control whitespace explicitly, set extras: $ => [].

inline

Rules to remove by inlining their definition.
Effect: These rules won’t create syntax tree nodes; their contents appear directly in parent nodes.

conflicts

Declares intentional LR(1) conflicts.
Only declare conflicts when you have genuine ambiguities that should be resolved at runtime using GLR parsing.

externals

Tokens handled by an external scanner.
See External Scanners for details.

word

The token used for keyword extraction optimization.
Setting a word token makes the parser smaller and faster by optimizing keyword matching.

supertypes

Rules considered abstract supertypes.
Effect: These nodes are hidden in the parse tree but can be used in queries.

precedences

Named precedence levels.
Use with: prec('unary', ...) instead of prec(2, ...)

Complete Example

Here’s a complete grammar demonstrating many DSL features:
grammar.js

Next Steps

Now that you understand the grammar DSL, learn how to: