解析 AST

Visitors(访问者)

当我们谈及“进入”一个节点,实际上是说我们在访问它们。

访问者是一个用于 AST 遍历的跨语言的模式。简单的说它们就是一个对象,定义了用于在一个树状结构中获取具体节点的方法。

const visitor = {
  Identifier() {
    console.log("Called!");
  }
};

这是一个简单的访问者,把它用于遍历中时,每当在树中遇见一个 Identifier 的时候会调用 Identifier() 方法。

提示

Identifier() { ... }Identifier: { enter() { ... } } 的简写形式。

const visitor = {
  Identifier: {
    enter() {
      console.log("Entered!");
    },
    exit() {
      console.log("Exited!");
    }
  }
};

比如在下面一段代码中, Entered!Exited! 会交替打印 4 次:

function square(n) {
  return n * n;
}

其解析为 AST:

- FunctionDeclaration
  - Identifier (id)
  - Identifier (params[0])
  - BlockStatement (body)
    - ReturnStatement (body)
      - BinaryExpression (argument)
        - Identifier (left)
        - Identifier (right)

Paths(路径)

Path 是一个对象,它表示两个节点之间的连接。

举例来说如果我们有以下的节点和它的子节点:

{
  type: "FunctionDeclaration",
  id: {
    type: "Identifier",
    name: "square"
  },
  ...
}

将子节点 Identifier 表示为路径的话,看起来是这样的:

{
  "parent": {
    "type": "FunctionDeclaration",
    "id": {...},
    ....
  },
  "node": {
    "type": "Identifier",
    "name": "square"
  }
}

同时它还有关于该路径的附加元数据:

{
  "parent": {...},
  "node": {...},
  "hub": {...},
  "contexts": [],
  "data": {},
  "shouldSkip": false,
  "shouldStop": false,
  "removed": false,
  "state": null,
  "opts": null,
  "skipKeys": null,
  "parentPath": null,
  "context": null,
  "container": null,
  "listKey": null,
  "inList": false,
  "parentKey": null,
  "key": null,
  "scope": null,
  "type": null,
  "typeAnnotation": null
}

路径是对于节点在数中的位置以及其他各种信息的响应式表述。 当你调用一个方法更改了树的时候,这些信息也会更新。

Paths in Visitors(存在于访问者中的路径)

当你有一个拥有 Identifier() 方法的访问者时,你实际上是在访问路径而不是节点。 如此一来你可以操作节点的响应式表述(译注:即路径)而不是节点本身。

const MyVisitor = {
  Identifier(path) {
    console.log("Visiting: " + path.node.name);
  }
};

比如有以下语句:

a + b + c;

打印出:

Visiting: a
Visiting: b
Visiting: c

MIT Licensed | Copyright © 2018-present 滇ICP备16006294号

Design by Quanzaiyu | Power by VuePress