工作中需要将javascript的if语句描述进行一些规范化,将类似
if(test) value0else value1
的语句的全部统一成:
if (test) result = value0;else result = value1;
格式的,便于后续处理。
方法之一使用AST替换来完成,主要用到estools提供的javascript解析和代码生成工具。
主要操作如下
1) 安装node.js
2) mkdir convert
cd convertnpm install esprimanpm install estraversenpm install escodegen
3) 编写AST解析代码,并且查看生成的AST树
var ast = esprima.parse(code);console.log(JSON.stringify(ast,null,4));
4)编写遍历if语句的代码,如果不符合格式,就改变AST的节点。
ast = estraverse.replace(ast, { leave: function(node, parent) { modifiedNode = node; if (node.type === 'IfStatement') { if (node.consequent.type === 'ExpressionStatement') { if (node.consequent.expression.type === 'Literal'){ modifiedNode['consequent'] = { "type": "ExpressionStatement", "expression": { "type": "AssignmentExpression", "operator": "=", "left": { "type": "Identifier", "name": "result" }, "right": node.consequent.expression } } }; if (node.alternate != null && node.alternate.expression.type === 'Literal'){ modifiedNode['alternate'] = { "type": "ExpressionStatement", "expression": { "type":"AssignmentExpression", "operator": "=", "left": { "type": "Identifier", "name": "result" }, "right": node.alternate.expression } } }; } }; return modifiedNode; } });
5)修改好后的ast,生成源代码
var modifiedCode = escodegen.generate(ast);
6)运行
获得结果
$ node exc1.js test1.jsReading test1.js=============if (var1 > 2) result = 3;else result = 0;if(var2 < 3) 0else 1if (var3 === 9) 1;=============if (var1 > 2) result = 3;else result = 0;if (var2 < 3) result = 0;else result = 1;if (var3 === 9) result = 1;
7) 完整代码
exc1.js-----------/* */var fs = require('fs'), esprima = require('esprima'), estraverse = require('estraverse'), escodegen = require('escodegen');function analyzeCode(code) { var ast = esprima.parse(code); //console.log(JSON.stringify(ast,null,4)); ast = estraverse.replace(ast, { leave: function(node, parent) { modifiedNode = node; if (node.type === 'IfStatement') { if (node.consequent != null && node.consequent.type === 'ExpressionStatement') { if (node.consequent.expression.type === 'Literal'){ modifiedNode['consequent'] = { "type": "ExpressionStatement", "expression": { "type": "AssignmentExpression", "operator": "=", "left": { "type": "Identifier", "name": "result" }, "right": node.consequent.expression } } }; if (node.alternate != null && node.alternate.expression.type === 'Literal'){ modifiedNode['alternate'] = { "type": "ExpressionStatement", "expression": { "type": "AssignmentExpression", "operator": "=", "left": { "type": "Identifier", "name": "result" }, "right": node.alternate.expression } } }; } }; return modifiedNode; } }); var modifiedCode = escodegen.generate(ast); console.log('============='); console.log(modifiedCode); //console.log(JSON.stringify(ast,null,4));}if (process.argv.length < 3) { console.log('Usage: zz.js file.js'); process.exit(1);}var filename = process.argv[2];console.log('Reading ' + filename);var code = fs.readFileSync(filename);console.log('=============');console.log(''+code);analyzeCode(code);console.log('Done');--------------
test1.jsif (var1 > 2) result = 3;else result = 0;if(var2 < 3) 0else 1if (var3 === 9) 1
8)
各种语言用来修改ast语法树的一些方法收集见:
http://adamrehn.com/articles/ast-instrumentation-examples-by-language#sec___javascript