AST学习-还原简单的 CallExpression 类型

还原简单的 CallExpression 类型

目标

1
2
3
4
5
6
var Xor = function (p,q)
{
return p ^ q;
}

let a = Xor(996,250);

转化为如下形式

1
2
3
4
5
6
var Xor = function (p,q)
{
return p ^ q;
}

let a = 996 ^ 250;

思路

遍历 VariableDeclarator 路径,对参数及函数主体进行判断校验,筛选出符合条件的节点

遍历函数定义作用域,当 CallExpression 与函数名相同时执行替换

完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
// 将 JS 源码转换成语法树的函数
const parser = require("@babel/parser")
// 遍历 AST 的函数
const traverse = require("@babel/traverse").default
// 操作节点的函数
const t = require("@babel/types")
// 将语法书转换成源代码的函数
const generator = require("@babel/generator").default

jscode = "var Xor = function (p,q)\n" +
"{\n" +
" return p ^ q;\n" +
"}\n" +
"\n" +
"let a = Xor(996,250);"

function call2express(path){
// 获取函数名及初始化节点
const {init, id} = path.node;
const name = id.name;
const params = init.params;

// 判断行参是否为两个
if (!params.length === 2) return;

// 获取行参名
let first_name = params[0].name;
let second_name = params[1].name;

let func_body = init.body
// 校验函数主体内容
if (!func_body.body || !func_body.body.length === 1) return;

let return_body = func_body.body[0];
let arguments = return_body.argument;
let {operator, left, right} = arguments;

// 判断ReturnStatement节点内容
if (!t.isReturnStatement(return_body) || !t.isBinaryExpression(arguments)) return;

// 判断return语句和行参是否一致
if (!t.isIdentifier(left, {name:first_name}) || !t.isIdentifier(right, {name:second_name})) return;

// 校验完毕,开始执行替换
// 获取函数定义作用域
const scope = path.scope;

traverse(scope.block, {
// CallExpression: function (_path) {
// node = _path.node;
// if (!t.isIdentifier(node.callee, {name:name})) return;
// args = node.arguments;
//
// _path.replaceWith(t.BinaryExpression(operator, args[0], args[1]));
// }
CallExpression:{
enter: [
function (_path) {
node = _path.node;
if (!t.isIdentifier(node.callee, {name:name})) return;
args = node.arguments;

_path.replaceWith(t.BinaryExpression(operator, args[0], args[1]));
}
]
}
})

}

const vistor = {
VariableDeclarator(path){
let init = path.get('init');
if (init.isFunctionExpression()){
call2express(path);
}
}
}

const ast = parser.parse(jscode)
traverse(ast, vistor)

let {code} = generator(ast);
console.log(code)

查看执行结果