AST交互-非连续判断三元表达式转if语句
Reading Time:The full text has 995 words, estimated reading time: 5 minutes
Creation Date:2022-08-21
Previous Article:kotlin学习-数据类型
Next Article:AST交互-三元表达式转switch语句
BEGIN
通常使用三元表达式转switch语句
的代码可以完成大部分的三元表达式代码美化需求,但是如果三元表达式的判断条件不是连续数字时,此时更适合转为if/else语句,如代码:
function _$du() {
var _$$I;
_$$I = _$gf[++_$f1];
_$$I <= 37
? _$$I <= 24
? (_$fx = _$jA[--_$g3], _$cR = _$jA[--_$g3])
: _$$I <= 27
? (_$kC = _$gf[++_$f1], _$fx = _$gf[++_$f1], _$cR = _$dz[_$kC])
: _$$I <= 33
? (_$fx = _$gf[++_$f1], _$cR = _$gD)
: (_$gf[_$f1] = 92, _$fx = _$f3[_$gf[++_$f1]], _$gf[_$f1] = _$fx, _$cR = _$jA[--_$g3])
: _$$I <= 92
? _$$I <= 54
? (_$fx = _$gf[++_$f1], _$cR = _$cL)
: _$$I <= 62
? (_$fx = _$gf[++_$f1], _$cR = _$fs)
: _$$I <= 63
? (_$fx = _$gf[++_$f1], _$cR = _$aG)
: (_$fx = _$gf[++_$f1], _$cR = _$jA[--_$g3])
: _$$I <= 99
? (_$gf[_$f1] = 92, _$fx = _$j4[_$gf[++_$f1]], _$gf[_$f1] = _$fx, _$cR = _$jA[--_$g3])
: _$$I <= 104
? (_$kC = _$gf[++_$f1], _$fx = _$gf[++_$f1], _$cR = _$ko[_$kC])
: (--_$g3, _$cR = _$jA, _$fx = _$g3)
}
碰到非连续判断条件的三元表达式,我们需要转换后的格式是这样的:
function _$du() {
var _$$I;
_$$I = _$gf[++_$f1];
if (_$$I <= 24) {
_$fx = _$jA[--_$g3];
_$cR = _$jA[--_$g3];
} else if (_$$I > 24 && _$$I <= 27) {
_$kC = _$gf[++_$f1];
_$fx = _$gf[++_$f1];
_$cR = _$dz[_$kC];
} else if (_$$I > 27 && _$$I <= 33) {
_$fx = _$gf[++_$f1];
_$cR = _$gD;
} else if (_$$I > 33 && _$$I <= 37) {
_$gf[_$f1] = 92;
_$fx = _$f3[_$gf[++_$f1]];
_$gf[_$f1] = _$fx;
_$cR = _$jA[--_$g3];
} else if (_$$I > 37 && _$$I <= 54) {
_$fx = _$gf[++_$f1];
_$cR = _$cL;
} else if (_$$I > 54 && _$$I <= 62) {
_$fx = _$gf[++_$f1];
_$cR = _$fs;
} else if (_$$I > 62 && _$$I <= 63) {
_$fx = _$gf[++_$f1];
_$cR = _$aG;
} else if (_$$I > 63 && _$$I <= 92) {
_$fx = _$gf[++_$f1];
_$cR = _$jA[--_$g3];
} else if (_$$I > 92 && _$$I <= 99) {
_$gf[_$f1] = 92;
_$fx = _$j4[_$gf[++_$f1]];
_$gf[_$f1] = _$fx;
_$cR = _$jA[--_$g3];
} else if (_$$I > 99 && _$$I <= 104) {
_$kC = _$gf[++_$f1];
_$fx = _$gf[++_$f1];
_$cR = _$ko[_$kC];
} else {
--_$g3;
_$cR = _$jA;
_$fx = _$g3;
}
}
修改前面三元表达式转switch语句
的getIfNode
的代码:
function getIfNode(node, ans={}, opt = {}, historys = [], keytype=null) {
const testValue = getIfTestValue(node?.test)
if (testValue === false) return
if (!opt.name) { Object.assign(opt, testValue) }
if (testValue.name !== opt.name) return
if (historys.length > 0 && keytype) {
historys[historys.length - 1][keytype] = false
}
historys.push({ ...testValue, consequent: true, alternate: true })
;['consequent', 'alternate'].forEach(key => {
const nextNode = getNode(node[key])
const idx = key === 'consequent' ? testValue.value : getPreValue(historys, testValue.value)
ans[idx] = nextNode
// console.log(key, idx)
nextNode?.forEach(item => getIfNode(item, ans, opt, historys, key))
})
return [opt.name, ans]
}
可以看到将存数据的数组改成的对象,并且新增了historys数组和keytype变量来辅助编码,historys数据用于记录历史节点的值,并使用consequent和alternate判断是否赋值,值为true表示完成,false表示步完成,然后在三元表达式的否语句节点上通过调用getPreValue(historys, testValue.value)
方法返回当前节点需要存储的下标,getPreValue
方法定义如下:
function getPreValue(historys, val) {
let len = historys.length
while(len--) {
const his = historys[len]
if (!his.consequent && his.value > val) return his.value
}
return 'else'
}
最后将判断的键名与代码匹配对象返回出来,代码匹配对象就是三元表达式的判断值与对应执行代码的匹配关系。格式如:
{
24: [...],
27: [...],
...
92: [...],
...
104: [...],
else: [...]
}
拿到代码匹配对象后接下来需要生成ast并替换掉,其中traverse代码如下:
const visitor = {
ConditionalExpression(path) {
const [key, data] = getIfNode(path.node) || []
const newNode = grenIfAst(0, key, Object.keys(data), data)
path.replaceWithMultiple([newNode])
path.skip()
},
}
traverse(ast, visitor)
可以看到key为键名,data为代码匹配对象,最后通过grenIfAst
方法生成AST树再通过replaceWithMultiple
方法替换掉原来的节点,grenIfAst
方法代码如下:
function grenIfAst(current, key, idxs, data) {
if (current >= idxs.length) return undefined
const statements = data[idxs[current]]?.reduce((ans, item) =>
([...ans, (t.isStatement(item) ? item : t.expressionStatement(item))])
, []) || []
if (idxs[current] === 'else') return t.blockStatement(statements)
const node = grenIfAst(current + 1, key, idxs, data)
if (current === 0) {
return t.ifStatement(
t.binaryExpression('<=', t.identifier(key), t.numericLiteral(Number(idxs[current]))),
t.blockStatement(statements),
node
)
} else {
return t.ifStatement(
t.logicalExpression(
'&&',
t.binaryExpression('>', t.identifier(key), t.numericLiteral(Number(idxs[current - 1]))),
t.binaryExpression('<=', t.identifier(key), t.numericLiteral(Number(idxs[current])))
),
t.blockStatement(statements),
node
)
}
}
这样三元表达式转if/else
表达式的代码美化就完成了,作者在开发当中发现替换节点时使用replaceWith
方法就不行,使用replaceWithMultiple
方法才可以,暂不知道啥原因,有空再看。
FINISH
Previous Article:kotlin学习-数据类型
Next Article:AST交互-三元表达式转switch语句