JS生成AST及CFG

JS生成AST

AST:抽象语法树。通过对源码进行词法分析、语法分析生成抽象语法树。

JavaScript生成AST有许多工具,这里主要介绍一种 Esprima 的使用.

npm install esprima开始使用
esprima文档

基础

esprima.parse(input, config, delegate)
详情
AST节点类型

  • input is the string representing the program to be parsed
  • config is an object used to customize the parsing behavior (optional)
  • delegate is a callback function invoked for every single node (optional)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
//  使用
const esprima = require('esprima');

const code = `function foo() {
let a = 1;
console.log(a)
}`
// 配置信息
const options = {
loc: true, // 位置信息
range: false, // 位置信息
jsx: false, // 支持jsx语法
tolerant: false,
tokens: false,
comment: false
}
// 回调函数里的 node 包含节点类型等信息,metadata 包含该节点位置等信息
const ast = esprima.parse(code, options, function (node, metadata) {
console.log(node.type);
});

生成的ast长成这样:
ast

AST结构

总体结构有两种

1
2
3
4
5
6
7
8
9
10
11
interface Program {
type: 'Program';
sourceType: 'script';
body: StatementListItem[];
}

interface Program {
type: 'Program';
sourceType: 'module';
body: ModuleItem[];
}

StatementListItem && ModuleItem

    其中 ModuleItem 只是比 StatementListItem 多了导入和导出两个module才会用到的类型,这两个类型用的少,所以只用关心 StatementListItem

1
2
type StatementListItem = Declaration | Statement;
type ModuleItem = ImportDeclaration | ExportDeclaration | StatementListItem;

StatementListItem 包含 Declaration(变量声明) 和 Statement(执行语句)

Declaration变量声明

变量声明的类型包括:

1
type Declaration = ClassDeclaration | FunctionDeclaration | VariableDeclaration;
Statement执行语句

执行语句包括:

1
2
3
4
5
6
7
type Statement = BlockStatement | BreakStatement | ContinueStatement |
DebuggerStatement | DoWhileStatement | EmptyStatement |
ExpressionStatement | ForStatement | ForInStatement |
ForOfStatement | FunctionDeclaration | IfStatement |
LabeledStatement | ReturnStatement | SwitchStatement |
ThrowStatement | TryStatement | VariableDeclaration |
WhileStatement | WithStatement;
ExpressionStatement

ExpressionStatement最为复杂:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
interface ExpressionStatement {
type: 'ExpressionStatement';
expression: Expression;
directive: string;
}
// Expression 类型
type Expression = ThisExpression | Identifier | Literal |
ArrayExpression | ObjectExpression | FunctionExpression |
ArrowFunctionExpression | ClassExpression |
TaggedTemplateExpression | MemberExpression |
Super | MetaProperty | NewExpression | CallExpression | UpdateExpression |
AwaitExpression | UnaryExpression |
BinaryExpression | LogicalExpression | ConditionalExpression |
YieldExpression | AssignmentExpression | SequenceExpression;

总结

ast树主要包括两种结构带有module的 moduleItem 和正常的 StatementListItem
StatementListItem结构包括两种 变量声明执行语句

  • 变量声明(Declaration)包括函数,变量,类的声明
  • 执行语句(Statement)分为两大类:
    1. 关键字组成的 statement,如 IfStatement, ForStatement等,这里面的BlockStatement有些特殊,因为其body又是StatementListItem,产生递归。
    2. 运算语句(赋值、计算之类的操作)组成的 ExpressionStatement。

AST生成CFG

使用Styx

npm github

1
2
3
4
5
6
7
8
9
import Esprima from "esprima";
import * as Styx from "styx";

var code = "var x = 2 + 2;";
var ast = Esprima.parse(code);
var flowProgram = Styx.parse(ast);
var json = Styx.exportAsJson(flowProgram);

console.log(json);