Last active
May 16, 2019 02:41
Star
You must be signed in to star a gist
基本版的 JS 解析器
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const babylon = require("babylon"); | |
const types = require("babel-types"); | |
const visitors = { | |
File(node, scope) { | |
evaluate(node.program, scope); | |
}, | |
Program(program, scope) { | |
for (const node of program.body) { | |
evaluate(node, scope); | |
} | |
}, | |
ExpressionStatement(node, scope) { | |
return evaluate(node.expression, scope); | |
}, | |
CallExpression(node, scope) { | |
// 获取调用者对象 | |
const func = evaluate(node.callee, scope); | |
// 获取函数的参数 | |
const funcArguments = node.arguments.map(arg => evaluate(arg, scope)); | |
// 如果是获取属性的话: console.log | |
if (types.isMemberExpression(node.callee)) { | |
const object = evaluate(node.callee.object, scope); | |
return func.apply(object, funcArguments); | |
} else if (types.isIdentifier(node.callee)) { | |
func.apply(scope, funcArguments); | |
} | |
}, | |
MemberExpression(node, scope) { | |
const {object, property} = node; | |
// 找到对应的属性名 | |
const propertyName = property.name; | |
// 找对对应的对象 | |
const obj = evaluate(object, scope); | |
// 获取对应的值 | |
const target = obj[propertyName]; | |
// 返回这个值,如果这个值是function的话,那么应该绑定上下文this | |
return typeof target === "function" ? target.bind(obj) : target; | |
}, | |
Identifier(node, scope) { | |
// 获取变量的值 | |
return scope[node.name]; | |
}, | |
StringLiteral(node) { | |
return node.value; | |
}, | |
NumericLiteral(node) { | |
return node.value; | |
}, | |
VariableDeclaration(node, scope) { | |
const kind = node.kind; | |
for (const declartor of node.declarations) { | |
const {name} = declartor.id; | |
const value = declartor.init | |
? evaluate(declartor.init, scope) | |
: undefined; | |
scope[name] = value; | |
} | |
}, | |
VariableDeclarator(node, scope) { | |
scope[node.id.name] = evaluate(node.init, scope); | |
}, | |
BlockStatement(block, scope) { | |
for (const node of block.body) { | |
// 执行代码块中的内容 | |
evaluate(node, scope); | |
} | |
}, | |
FunctionDeclaration(node, scope) { | |
// 获取function | |
const func = visitors.FunctionExpression(node, scope); | |
// 在作用域中定义function | |
scope[node.id.name] = func; | |
}, | |
FunctionExpression(node, scope) { | |
// 自己构造一个function | |
const func = function() { | |
// TODO: 获取函数的参数 | |
// 执行代码块中的内容 | |
evaluate(node.body, scope); | |
}; | |
// 返回这个function | |
return func; | |
} | |
}; | |
function evaluate(node, scope) { | |
const _evalute = visitors[node.type]; | |
if (!_evalute) { | |
throw new Error(`Unknown visitors of ${node.type}`); | |
} | |
// 递归调用 | |
return _evalute(node, scope); | |
} | |
const code = ` | |
function test(){ | |
var name = "hello world"; | |
console.log(name); | |
} | |
test(); | |
`; | |
// 生成AST树 | |
const ast = babylon.parse(code); | |
// 解析AST | |
// 需要传入执行上下文,否则找不到``console``对象 | |
evaluate(ast, {console, Math}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment