最近在尝试用AST来玩下,我就试了下尝试把一个小案例中的复杂化平坦流来进行还原。
这是案例下载 链接:https://pan.baidu.com/s/1kZ_3m7Hn5xyMzttDOfikxA?pwd=bvf3
我希望可以用更加易懂的话来解释我的思路(大佬勿喷,纯粹是新人练手),下面是我的思路
我们首先是进行debugger来一步步调试,观察规律,可以看到是12开始
可以看到这是12最后进入要执行的部分条件是<13,不过这时候我们还看不出啥规律,继续
在12执行完后看到了f变成了4,然后继续单步
这时候能看到4是进入了条件是<5这块的,我们可以猜测有可能是会进入(f-1)的条件?,或者也有可能是巧合?继续
然后我们看到f这时候已经是15了,会如我们所愿吗?
会不会和上俩个情况一样进入条件是<16这块呢?
很遗憾,并不会,但我们可以再看看,为什么没有进入<16呢,这个先不知道,再多试几次
这时候神奇事情又发生了,又出现了我们猜测的情况,应该是这样了,那那个15是什么情况呢,在我们多试几次后会发现
f是25 不会进入f<25 而是进入他的else
我们可以进行总结下规律,f进入最后执行的情况要么是f<(f+1)的情况 要么是if条件是f<(f)的else
比如f=5的时候 会在if条件是f<(f)的else
比如f=8的时候,会在if条件是f<(f+1)的情况下进入
如果不相信可以多试几次,会发现这个规律是正确的
接下来就是如何用ast还原,这边我只是还原出if流程,因为思路才是最关键的
traverse(ast,{
"ForStatement":function (path) {
path.get('body').replaceWith(types.blockStatement([path.node.body],[]))
}
})
p=[]
traverse(ast,{
"IfStatement": {
'exit':function (path){
//条件为什么是这几个,不会有什么问题吗?
//首先path.node.alternate是为了防止else{}为空的情况 因为我们接下来要取他的body【0】防止取不到而报错的情况
//为什么是left.name==='f' 因为我们在之前可以看到他的条件判断一定是 if(f<xxx) 这种情况一定会携带f 是怕有别的比如出现if (s<xxx)的情况
if(path.node.alternate&&path.get('alternate.body').length
&&!types.isIfStatement(path.get('alternate.body.0'))&&
path.node.test.left.name==='f'
){
let left=path.node.test.left.name
let right=path.node.test.right.value
//创建continue是为了后面做准备这个可以暂时忽略
let continueStatement=types.continueStatement()
let consequent=path.get('consequent')
let alternate=path.get('alternate')
consequent.insertAfter(continueStatement)
alternate.insertAfter(continueStatement)
//这个是创建if语句 是做成比如 f=12 最后进入if(f<13)的情况,我之前图片有这样的
let elseState=types.ifStatement(
types.binaryExpression("===",
types.identifier(left),
types.identifier((right-1).toString()),
),consequent.node)
//这个也是是创建if语句 是做成比如 f=5 最后进入if(f<5)的else情况,我之前图片有这样的
let ifState=types.ifStatement(
types.binaryExpression("===",types.identifier(left),
types.identifier((right).toString())),alternate.node)
//p是个列表 里面存储了自己弄的ifStatement
/**
* 把这个最后变成
* if (f < 1) {
* var i = function (f) {
* var i = e || 0;
* for (; ;) return S(E(s(f), f.length * r))
* };
* f += 22
* } else {
* var l = function (f, i, l, s, r, n, t) {
* var o = e || 0;
* for (; ;) return a(i & l | ~i & s, f, i, r, n, t)
* };
* f += 22
* }
*
*
* 这种格式的
* if(f===0){
* var i = function (f) {
* var i = e || 0;
* for (; ;) return S(E(s(f), f.length * r))
* };
* f += 22
*
* }
*if(f===1)){
* var l = function (f, i, l, s, r, n, t) {
* var o = e || 0;
* for (; ;) return a(i & l | ~i & s, f, i, r, n, t)
* };
* f += 22
*
*
*}
*
*/
/
p.push(elseState)
p.push(ifState)
// console.log(path.scope.getBinding(left).path.parentPath.toString())
}
}
}
})
traverse(ast,{
'Program':function (path) {
let forstate=path.get("body.0.expression.callee.body.body.1")
let body=forstate.get('body.body')
body[0].replaceInline(p)
}
})