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?