Technicalarticles
const a =1console.log(a)
{ "type":"Program", "start":0, "end":26, "body":[ { "type":"VariableDeclaration", "start":0, "end":11, "declarations":[ { "type":"VariableDeclarator", "start":6, "end":11, "id":{ "type":"Identifier", "start":6, "end":7, "name":"a" }, "init":{ "type":"Literal", "start":10, "end":11, "value":1, "raw":"1" } } ], "kind":"const" }, { "type":"ExpressionStatement", "start":12, "end":26, "expression":{ "type":"CallExpression", "start":12, "end":26, "callee":{ "type":"MemberExpression", "start":12, "end":23, "object":{ "type":"Identifier", "start":12, "end":19, "name":"console" }, "property":{ "type":"Identifier", "start":20, "end":23, "name":"log" }, "computed":false }, "arguments":[ { "type":"Identifier", "start":24, "end":25, "name":"a" } ] } } ], "sourceType":"module"}
常见的JS编译器有babylon,acorn等等,感兴趣的同学可以在AST explorer这个网站自行体验。
1+2+3
1 PUSH 12 PUSH 23 ADD4 PUSH 35 ADD
const nodeHandler ={ Program(){}, VariableDeclaration(){}, ExpressionStatement(){}, MemberExpression(){}, CallExpression(){}, Identifier(){}}
classNodeIterator{
constructor (node){
this.node = node
this.nodeHandler = nodeHandler
}
traverse (node){
// 根据节点类型找到节点处理器当中对应的函数
const _eval =this.nodeHandler[node.type]
// 若找不到则报错
if(!_eval){
thrownewError(`canjs: Unknown node type "${node.type}".`)
}
// 运行处理函数
return _eval(node)
}}
VariableDeclaration(node){ for(const declaration of node.declarations){ const{ name }= declaration.id const value = declaration.init ? traverse(declaration.init):undefined // 问题来了,拿到了变量的名称和值,然后把它保存到哪里去呢? // ... } },
classNodeIterator{
constructor (node, scope ={}){
this.node = node
this.scope = scope
this.nodeHandler = nodeHandler
}
traverse (node, options ={}){
const scope = options.scope ||this.scope
const nodeIterator =newNodeIterator(node, scope)
const _eval =this.nodeHandler[node.type]
if(!_eval){
thrownewError(`canjs: Unknown node type "${node.type}".`)
}
return _eval(nodeIterator)
}
createScope (blockType ='block'){
returnnewScope(blockType,this.scope)
}}
VariableDeclaration(nodeIterator){ const kind = nodeIterator.node.kind for(const declaration of nodeIterator.node.declarations){ const{ name }= declaration.id const value = declaration.init ? nodeIterator.traverse(declaration.init):undefined // 在作用域当中定义变量 // 如果当前是块级作用域且变量用var定义,则定义到父级作用域 if(nodeIterator.scope.type ==='block'&& kind ==='var'){ nodeIterator.scope.parentScope.declare(name, value, kind) }else{ nodeIterator.scope.declare(name, value, kind) } } },
const a =1{ const b =2 console.log(a)}console.log(b)
classScope{
constructor (type, parentScope){
// 作用域类型,区分函数作用域function和块级作用域block
this.type = type
// 父级作用域
this.parentScope = parentScope
// 全局作用域
this.globalDeclaration = standardMap
// 当前作用域的变量空间
this.declaration =Object.create(null)
}
/*
* get/set方法用于获取/设置当前作用域中对应name的变量值
符合JS语法规则,优先从当前作用域去找,若找不到则到父级作用域去找,然后到全局作用域找。
如果都没有,就报错
*/
get(name){
if(this.declaration[name]){
returnthis.declaration[name]
}elseif(this.parentScope){
returnthis.parentScope.get(name)
}elseif(this.globalDeclaration[name]){
returnthis.globalDeclaration[name]
}
thrownewReferenceError(`${name} is not defined`)
}
set(name, value){
if(this.declaration[name]){
this.declaration[name]= value
}elseif(this.parentScope[name]){
this.parentScope.set(name, value)
}else{
thrownewReferenceError(`${name} is not defined`)
}
}
/**
* 根据变量的kind调用不同的变量定义方法
*/
declare (name, value, kind ='var'){
if(kind ==='var'){
returnthis.varDeclare(name, value)
}elseif(kind ==='let'){
returnthis.letDeclare(name, value)
}elseif(kind ==='const'){
returnthis.constDeclare(name, value)
}else{
thrownewError(`canjs: Invalid Variable Declaration Kind of "${kind}"`)
}
}
varDeclare (name, value){
let scope =this
// 若当前作用域存在非函数类型的父级作用域时,就把变量定义到父级作用域
while(scope.parentScope && scope.type !=='function'){
scope = scope.parentScope
}
this.declaration[name]=newSimpleValue(value,'var')
returnthis.declaration[name]
}
letDeclare (name, value){
// 不允许重复定义
if(this.declaration[name]){
thrownewSyntaxError(`Identifier ${name} has already been declared`)
}
this.declaration[name]=newSimpleValue(value,'let')
returnthis.declaration[name]
}
constDeclare (name, value){
// 不允许重复定义
if(this.declaration[name]){
thrownewSyntaxError(`Identifier ${name} has already been declared`)
}
this.declaration[name]=newSimpleValue(value,'const')
returnthis.declaration[name]
}}
classSimpleValue{
constructor (value, kind =''){
this.value = value
this.kind = kind
}
set(value){
// 禁止重新对const类型变量赋值
if(this.kind ==='const'){
thrownewTypeError('Assignment to constant variable')
}else{
this.value = value
}
}
get(){
returnthis.value
}}
const standardMap ={ console:newSimpleValue(console)}
classSignal{
constructor (type, value){
this.type = type
this.value = value
}
staticReturn(value){
returnnewSignal('return', value)
}
staticBreak(label =null){
returnnewSignal('break', label)
}
staticContinue(label){
returnnewSignal('continue', label)
}
static isReturn(signal){
return signal instanceofSignal&& signal.type ==='return'
}
static isContinue(signal){
return signal instanceofSignal&& signal.type ==='continue'
}
static isBreak(signal){
return signal instanceofSignal&& signal.type ==='break'
}
static isSignal (signal){
return signal instanceofSignal
}}
VariableDeclaration(nodeIterator){ const kind = nodeIterator.node.kind for(const declaration of nodeIterator.node.declarations){ const{ name }= declaration.id const value = declaration.init ? nodeIterator.traverse(declaration.init):undefined // 在作用域当中定义变量 // 若为块级作用域且关键字为var,则需要做全局污染 if(nodeIterator.scope.type ==='block'&& kind ==='var'){ nodeIterator.scope.parentScope.declare(name, value, kind) }else{ nodeIterator.scope.declare(name, value, kind) } } },
Identifier(nodeIterator){ if(nodeIterator.node.name ==='undefined'){ returnundefined } return nodeIterator.scope.get(nodeIterator.node.name).value },
Literal(nodeIterator){ return nodeIterator.node.value }
CallExpression(nodeIterator){
// 遍历callee获取函数体
const func = nodeIterator.traverse(nodeIterator.node.callee)
// 获取参数
const args = nodeIterator.node.arguments.map(arg => nodeIterator.traverse(arg))
let value
if(nodeIterator.node.callee.type ==='MemberExpression'){
value = nodeIterator.traverse(nodeIterator.node.callee.object)
}
// 返回函数运行结果
return func.apply(value, args)
},
MemberExpression(nodeIterator){ // 获取对象,如console const obj = nodeIterator.traverse(nodeIterator.node.object) // 获取对象的方法,如log const name = nodeIterator.node.property.name // 返回表达式,如console.log return obj[name] }
BlockStatement(nodeIterator){
// 先定义一个块级作用域
let scope = nodeIterator.createScope('block')
// 处理块级节点内的每一个节点
for(const node of nodeIterator.node.body){
if(node.type ==='VariableDeclaration'&& node.kind ==='var'){
for(const declaration of node.declarations){
scope.declare(declaration.id.name, declaration.init.value, node.kind)
}
}elseif(node.type ==='FunctionDeclaration'){
nodeIterator.traverse(node,{ scope })
}
}
// 提取关键字(return, break, continue)
for(const node of nodeIterator.node.body){
if(node.type ==='FunctionDeclaration'){
continue
}
const signal = nodeIterator.traverse(node,{ scope })
if(Signal.isSignal(signal)){
return signal
}
}
}
FunctionDeclaration(nodeIterator){ const fn =NodeHandler.FunctionExpression(nodeIterator) nodeIterator.scope.varDeclare(nodeIterator.node.id.name, fn) return fn }
FunctionExpression(nodeIterator){
const node = nodeIterator.node
/**
* 1、定义函数需要先为其定义一个函数作用域,且允许继承父级作用域
* 2、注册`this`, `arguments`和形参到作用域的变量空间
* 3、检查return关键字
* 4、定义函数名和长度
*/
const fn =function(){
const scope = nodeIterator.createScope('function')
scope.constDeclare('this',this)
scope.constDeclare('arguments', arguments)
node.params.forEach((param, index)=>{
const name = param.name
scope.varDeclare(name, arguments[index])
})
const signal = nodeIterator.traverse(node.body,{ scope })
if(Signal.isReturn(signal)){
return signal.value
}
}
Object.defineProperties(fn,{
name:{ value: node.id ? node.id.name :''},
length:{ value: node.params.length }
})
return fn
}
ThisExpression(nodeIterator){ const value = nodeIterator.scope.get('this') return value ? value.value :null }
NewExpression(nodeIterator){ const func = nodeIterator.traverse(nodeIterator.node.callee) const args = nodeIterator.node.arguments.map(arg => nodeIterator.traverse(arg)) returnnew(func.bind(null,...args)) }
ForStatement(nodeIterator){
const node = nodeIterator.node
let scope = nodeIterator.scope
if(node.init && node.init.type ==='VariableDeclaration'&& node.init.kind !=='var'){
scope = nodeIterator.createScope('block')
}
for(
node.init && nodeIterator.traverse(node.init,{ scope });
node.test ? nodeIterator.traverse(node.test,{ scope }):true;
node.update && nodeIterator.traverse(node.update,{ scope })
){
const signal = nodeIterator.traverse(node.body,{ scope })
if(Signal.isBreak(signal)){
break
}elseif(Signal.isContinue(signal)){
continue
}elseif(Signal.isReturn(signal)){
return signal
}
}
}
IfStatement(nodeIterator){ if(nodeIterator.traverse(nodeIterator.node.test)){ return nodeIterator.traverse(nodeIterator.node.consequent) }elseif(nodeIterator.node.alternate){ return nodeIterator.traverse(nodeIterator.node.alternate) } }
const{Parser}=require('acorn')constNodeIterator=require('./iterator')constScope=require('./scope')classCanjs{
constructor (code ='', extraDeclaration ={}){
this.code = code
this.extraDeclaration = extraDeclaration
this.ast =Parser.parse(code)
this.nodeIterator =null
this.init()
}
init (){
// 定义全局作用域,该作用域类型为函数作用域
const globalScope =newScope('function')
// 根据入参定义标准库之外的全局变量
Object.keys(this.extraDeclaration).forEach((key)=>{
globalScope.addDeclaration(key,this.extraDeclaration[key])
})
this.nodeIterator =newNodeIterator(null, globalScope)
}
run (){
returnthis.nodeIterator.traverse(this.ast)
}}
DO U LIKE?