Acorn ECMAScript Parser

repository·master·Indexed 11 days ago

https://github.com/acornjs/acorn

A tiny, fast JavaScript parser that produces ESTree-compatible syntax trees. The ecosystem includes the core acorn parser (v8.18.0), acorn-loose for error-tolerant parsing of invalid code, and acorn-walk for traversing the resulting AST. It features a plugin system via Parser.extend() to support custom dialects like JSX or BigInt.

Tokens
13.3K
Snippets
45
Records
67
Agent score
95%

What's inside Acorn

  1. Understand the Acorn package ecosystem

    master

    The Acorn repository consists of three primary packages:

    • acorn: The main JavaScript parser.
    • acorn-loose: An error-tolerant parser designed to handle non-standard or broken syntax.
    • acorn-walk: A utility for walking the syntax tree (AST).
  2. How the acorn-walk interface works

    master
    The walker uses an algorithm stored as an object where each property corresponds to a node type in the ESTree spec. These properties hold functions that are called when the walker encounters that specific node type. You can use different walking strategies depending on whether you need to track ancestors, control recursion manually, or simply visit every node.
  3. Extend the Parser with plugins

    master

    Acorn supports plugins that can redefine parser behavior, add new token types, or extend tokenizer contexts.

    A plugin is a function that takes a parser class and returns an extended parser class. To use multiple plugins, use the Parser.extend static method, which accepts any number of plugin functions as arguments.

    Best Practice: Create the extended parser class once and reuse it for multiple parse calls to help the JavaScript engine's optimizer.

    const {Parser} = require("acorn")
    
    const MyParser = Parser.extend(
      require("acorn-jsx")(),
      require("acorn-bigint")
    )
    console.log(MyParser.parse("// Some bigint + JSX code"))
  4. Import Acorn in ESM or CommonJS

    master

    Acorn supports both ESM and CommonJS. ESM is preferred as it provides better editor auto-completion via TypeScript support.

    // ESM (Preferred)
    import * as acorn from "acorn"
    
    // CommonJS
    let acorn = require("acorn")
  5. Create a custom Acorn plugin

    master

    To create a plugin, write a function that accepts a Parser class and returns a new class that extends it. You can override existing methods (like readToken) to implement additional functionality.

    It is recommended that plugin packages export their plugin function as the default export, or export a constructor function if the plugin requires configuration parameters.

    module.exports = function noisyReadToken(Parser) {
      return class extends Parser {
        readToken(code) {
          console.log("Reading a token!")
          super.readToken(code)
        }
      }
    }
  6. Understand the AST Node structure

    master

    Every node in the Acorn AST implements the Node interface. All nodes contain:

    • start: The character offset where the node begins.
    • end: The character offset where the node ends.
    • type: A string identifying the node type (e.g., 'Identifier', 'Literal', 'IfStatement').
    • range?: An optional [number, number] array of start and end offsets (enabled via ranges: true).
    • loc?: An optional SourceLocation object containing line and column information (enabled via locations: true).
  7. Understand TokenType properties

    master

    The TokenType class contains several boolean and configuration properties used by the parser to disambiguate syntax:

    • beforeExpr: Set on tokens that can be followed by an expression. This is used to distinguish between division (/) and regular expressions.
    • startsExpr: Set on tokens that either start an expression (like a quote) or continue one (like the body of a string). This is used to check if a token ends a yield expression.
    • isLoop: Marks keywords that start a loop (e.g., for, while), which helps the parser manage continue jumps to labels.
    • isAssign: Marks tokens that act as assignment operators (e.g., =, +=).
    • prefix / postfix: Marks unary operators as prefix or postfix.
    • binop: Specifies that a token is a binary operator and carries its precedence value.
  8. How different walk types work together

    master

    The acorn-walk module provides several ways to traverse an ESTree-compatible AST, ranging from high-level convenience to low-level control:

    1. simple(): Best for most tasks. You just provide a map of node types to callbacks. It uses a default traversal logic.
    2. ancestor(): Use this when your logic depends on the context (e.g., "is this identifier inside a function declaration?"). It provides the path of nodes from the root.
    3. recursive(): Use this when you need to change how the tree is traversed (e.g., skipping certain branches or visiting nodes in a non-standard order). You control the recursion by calling the third argument c in your visitor.
    4. full() / fullAncestor(): Use these when you want to perform an action on every node without specifying types.
    5. find...(): Specialized utility functions for locating nodes based on character offsets (start, end) or positions (pos).

    All these functions can accept a baseVisitor to customize the underlying traversal logic.