Syntax trees - mattacosta/php-parser GitHub Wiki

Structure

A syntax tree is composed of three primary components. Together, they represent all of the information in a source file, including whitespace and comments.

  • SyntaxNode
    • Nodes represent language constructs such as statements, expressions, or clauses.
    • Nodes are also used to create the actual syntax tree, and may contain child nodes or tokens.
  • SyntaxToken
    • Tokens represent the significant portions of text that is parsed. This includes keywords, variables, operators, and punctuation.
    • Trivia is also attached to tokens (but not as children).
  • SyntaxTrivia
    • Trivia represents the insignificant portions of text that is parsed. This includes whitespace and comments.

Navigation

Properties

A syntax tree can be manually navigated using the properties of the nodes that make up the tree.

Example:

// $a = $b + 1;
let statement = <ExpressionStatementSyntaxNode>statements[0];
// $a = $b + 1
let assignmentExpr = <AssignmentSyntaxNode>statement.expression;

// $a
let variable = <LocalVariableSyntaxNode>assignmentExpr.leftOperand;
// $b + 1
let binaryExpr = <BinarySyntaxNode>assignmentExpr.rightOperand;

// $b
let left = <LocalVariableSyntaxNode>binaryExpr.leftOperand;
// 1
let right = <LiteralSyntaxNode>binaryExpr.rightOperand;

Query methods

Every class derived from a SyntaxNode also inherits methods that can be used to explore the syntax tree.

These methods include, but are not limited to:

  • firstAncestorOrSelf()
  • firstToken()
  • getAncestors()
  • getAncestorsAndSelf()
  • getChildNodes()
  • getChildTokens()
  • lastToken()

Syntax visitors

SyntaxNode objects also implement a visitor pattern, which allows a SyntaxVisitor or SyntaxTransform to process an element of the syntax tree without knowing its structure beforehand. For example, the SyntaxWalker class (which is a specific kind of SyntaxVisitor) can be used to recursively navigate every node and its children.

Example:

/**
 * Usage:
 *   let collector = new UseDeclarationCollector();
 *   collector.visit(root);
 */
class UseDeclarationCollector extends SyntaxWalker {

  protected imports: UseDeclarationSyntaxNode[] = [];

  /**
   * Overrides `SyntaxWalker.visitUseDeclaration()`.
   */
  public visitUseDeclaration(node: UseDeclarationSyntaxNode) {
    imports.push(node);
  }

}