homunculus
Advanced tools
Comparing version 0.0.10 to 0.0.11
@@ -17,2 +17,5 @@ var Lexer = require('./src/lexer/Lexer'); | ||
var JsContext = require('./src/parser/js/Context'); | ||
var JsEnv = require('./src/parser/js/Env'); | ||
exports.getClass = function(type, lan) { | ||
@@ -63,2 +66,24 @@ type = (type || '').toLowerCase(); | ||
break; | ||
case 'context': | ||
switch(lan) { | ||
case 'js': | ||
case 'javascript': | ||
case 'es': | ||
case 'ecmascript': | ||
return JsContext; | ||
default: | ||
throw new Error('Unsupport Language Context: ' + lan); | ||
} | ||
break; | ||
case 'env': | ||
switch(lan) { | ||
case 'js': | ||
case 'javascript': | ||
case 'es': | ||
case 'ecmascript': | ||
return JsEnv; | ||
default: | ||
throw new Error('Unsupport Language Env: ' + lan); | ||
} | ||
break; | ||
case 'token': | ||
@@ -108,2 +133,15 @@ return Token; | ||
} | ||
}; | ||
exports.getContext = function(lan) { | ||
lan = lan.toLowerCase(); | ||
switch(lan) { | ||
case 'js': | ||
case 'javascript': | ||
case 'es': | ||
case 'ecmascript': | ||
return new JsContext(); | ||
default: | ||
throw new Error('Unsupport Language Context: ' + lan); | ||
} | ||
}; |
{ | ||
"name": "homunculus", | ||
"version": "0.0.10", | ||
"version": "0.0.11", | ||
"description": "A lexer&parser by Javascript", | ||
@@ -5,0 +5,0 @@ "maintainers": [ |
var Class = require('../../util/Class'); | ||
var character = require('../../util/character'); | ||
var Lexer = require('../../lexer/Lexer'); | ||
var JsNode = require('./Node'); | ||
var Token = require('../../lexer/Token'); | ||
var Node = require('./Node'); | ||
var Context = Class(function() { | ||
var Parser = require('./Parser'); | ||
var id = 0; | ||
var Context = Class(function(parent, name) { | ||
this.id = id++; | ||
this.parser = new Parser(); | ||
this.parent = parent || null; //父上下文,如果是全局则为空 | ||
this.name = name || null; //上下文名称,即函数名,函数表达式为空,全局也为空 | ||
this.thisIs = null; //上下文环境中this的值,函数表达式中可能会赋值 | ||
this.children = []; //函数声明或函数表达式所产生的上下文 | ||
this.childrenMap = {}; //键是函数名,值是上下文,匿名函数表达式键为cid | ||
this.vars = []; //变量var声明 | ||
this.varsMap = {}; //键为id字面量,值是它的token的节点 | ||
this.params = []; //形参,函数上下文才有,即全局无 | ||
this.paramsMap = {}; //键为id字面量,值是它的token的节点 | ||
this.aParams = []; //实参,函数表达式才有 | ||
this.vids = []; //上下文环境里用到的变量id | ||
this.vidsMap = {}; //键为id字面量,值是它的token的节点 | ||
this.returns = []; //上下文环境里return语句 | ||
if(!this.isTop()) { | ||
this.parent.addChild(this); | ||
} | ||
}).methods({ | ||
parse: function(code) { | ||
var ast; | ||
if(code instanceof JsNode) { | ||
ast = code; | ||
} | ||
else { | ||
ast = this.parser.parse(code); | ||
} | ||
recursion(ast, this); | ||
return this; | ||
}, | ||
getId: function() { | ||
return this.id; | ||
}, | ||
getName: function() { | ||
return this.name; | ||
}, | ||
getParent: function() { | ||
return this.parent; | ||
}, | ||
getThis: function() { | ||
return this.thisIs; | ||
}, | ||
setThis: function(t) { | ||
this.thisIs = t; | ||
return this; | ||
}, | ||
isTop: function() { | ||
return !this.parent; | ||
}, | ||
isFnexpr: function() { | ||
return !this.isTop() && !this.name; | ||
}, | ||
hasParam: function(p) { | ||
return this.paramsMap.hasOwnProperty(p); | ||
}, | ||
getParams: function() { | ||
return this.params; | ||
}, | ||
addParam: function(p) { | ||
//形参不可能重复,无需判断 | ||
this.paramsMap[p] = this.params.length; | ||
this.params.push(p); | ||
return this; | ||
}, | ||
getAParams: function() { | ||
return this.aParams; | ||
}, | ||
addAParam: function(ap) { | ||
this.aParams.push(ap); | ||
return this; | ||
}, | ||
getChild: function(name) { | ||
return this.childrenMap[name]; | ||
}, | ||
getChildren: function() { | ||
return this.children; | ||
}, | ||
//通过name查找函数声明,id查找表达式 | ||
hasChild: function(name) { | ||
return this.childrenMap.hasOwnProperty(name); | ||
}, | ||
addChild: function(child) { | ||
var name = child.getName(); | ||
//函数表达式名字为空用id删除 | ||
if(name) { | ||
this.delChild(name); | ||
} | ||
else { | ||
this.delChild(child.getId()); | ||
} | ||
name = name || child.getId(); | ||
this.childrenMap[name] = child; | ||
this.children.push(child); | ||
return this; | ||
}, | ||
//name函数声明,id表达式 | ||
delChild: function(name) { | ||
if(this.hasChild(name)) { | ||
var i = this.children.indexOf(this.childrenMap[name]); | ||
this.children.splice(i, 1); | ||
delete this.childrenMap[name]; | ||
} | ||
return this; | ||
}, | ||
hasVar: function(v) { | ||
return this.varsMap.hasOwnProperty(v); | ||
}, | ||
addVar: function(node, assign) { | ||
var v = node.leaves()[0].token().content(); | ||
//赋值拥有最高优先级,会覆盖掉之前的函数声明和var | ||
if(assign) { | ||
this.delVar(v); | ||
this.delChild(v); | ||
} | ||
//仅仅是var声明无赋值,且已有过声明或函数,忽略之 | ||
else if(this.hasVar(v) || this.hasChild(v)) { | ||
return this; | ||
} | ||
this.varsMap[v] = node; | ||
this.vars.push(node); | ||
return this; | ||
}, | ||
delVar: function(v) { | ||
if(this.hasVar(v)) { | ||
var i = this.vars.indexOf(this.varsMap[v]); | ||
this.vars.splice(i, 1); | ||
delete this.varsMap[v]; | ||
} | ||
return this; | ||
}, | ||
getVars: function() { | ||
return this.vars; | ||
}, | ||
addReturn: function(node) { | ||
this.returns.push(node); | ||
return this; | ||
}, | ||
getReturns: function() { | ||
return this.returns; | ||
}, | ||
hasVid: function(v) { | ||
return this.vidsMap.hasOwnProperty(v); | ||
}, | ||
addVid: function(node) { | ||
var v = node.token().content(); | ||
if(this.vidsMap.hasOwnProperty(v)) { | ||
return; | ||
} | ||
this.vids.push(node); | ||
this.vidsMap[v] = node; | ||
return this; | ||
}, | ||
getVids: function() { | ||
return this.vids; | ||
} | ||
}); | ||
}); | ||
function recursion(node, context) { | ||
var isToken = node.name() == JsNode.TOKEN; | ||
var isVirtual = isToken && node.token().type() == Token.VIRTUAL; | ||
if(isToken) { | ||
if(!isVirtual) { | ||
var token = node.token(); | ||
var s = token.content(); | ||
if(s == 'return') { | ||
context.addReturn(node); | ||
} | ||
} | ||
} | ||
else { | ||
if(node.name() == JsNode.VARDECL) { | ||
vardecl(node, context); | ||
} | ||
else if(node.name() == JsNode.FNDECL) { | ||
context = fndecl(node, context); | ||
} | ||
else if(node.name() == JsNode.FNEXPR) { | ||
context = fnexpr(node, context); | ||
} | ||
else if(node.name() == JsNode.PRMREXPR) { | ||
prmrexpr(node, context); | ||
} | ||
node.leaves().forEach(function(leaf, i) { | ||
recursion(leaf, context); | ||
}); | ||
} | ||
} | ||
function vardecl(node, context) { | ||
var leaves = node.leaves(); | ||
var assign = !!leaves[1]; | ||
context.addVar(node, assign); | ||
} | ||
function fndecl(node, context) { | ||
var v = node.leaves()[1].leaves().content(); | ||
var child = new Context(context, v); | ||
var params = node.leaves()[3]; | ||
if(params.name() == JsNode.FNPARAMS) { | ||
addParam(params, child); | ||
} | ||
return child; | ||
} | ||
function fnexpr(node, context) { | ||
//函数表达式name为空 | ||
var child = new Context(context); | ||
//记录形参 | ||
var params; | ||
var v = node.leaves()[1]; | ||
if(v.name() == JsNode.TOKEN) { | ||
params = node.leaves()[3]; | ||
} | ||
else { | ||
params = node.leaves()[2]; | ||
} | ||
if(params.name() == JsNode.FNPARAMS) { | ||
addParam(params, child); | ||
} | ||
//匿名函数检查实参传入情况 | ||
var next = node.next(); | ||
//!function(){}()形式 | ||
if(next && next.name() == JsNode.ARGS) { | ||
var leaves = next.leaves(); | ||
//长度2为()空参数,长度3有参数,第2个节点 | ||
if(leaves.length == 3) { | ||
addAParam(leaves[1], child); | ||
} | ||
} | ||
//(function(){})()形式 | ||
else { | ||
var prmr = node.parent(); | ||
var prev = node.prev(); | ||
if(prmr.name() == JsNode.PRMREXPR && prev && prev.name() == JsNode.TOKEN && prev.token().content() == '(') { | ||
next = prmr.next(); | ||
if(next && next.name() == JsNode.ARGS) { | ||
var leaves = next.leaves(); | ||
//长度2为()空参数,长度3有参数,第2个节点 | ||
if(leaves.length == 3) { | ||
addAParam(leaves[1], child); | ||
} | ||
} | ||
} | ||
} | ||
return child; | ||
} | ||
//支持es6 | ||
function addParam(params, child) { | ||
params.leaves().forEach(function(leaf, i) { | ||
if(leaf.name() == JsNode.TOKEN && leaf.token().content() != ',') { | ||
child.addParam(leaf.token().content()); | ||
} | ||
else if(leaf.name() == JsNode.RESTPARAM) { | ||
child.addParam(leaf.leaves()[1].token().content()); | ||
} | ||
}); | ||
} | ||
function addAParam(params, child) { | ||
params.leaves().forEach(function(leaf, i) { | ||
if(i % 2 == 0) { | ||
child.addAParam(leaf); | ||
} | ||
}); | ||
} | ||
function prmrexpr(node, context) { | ||
var first = node.leaves()[0]; | ||
if(first.name() == JsNode.TOKEN) { | ||
var token = first.token(); | ||
if(token.type() == Token.ID) { | ||
context.addVid(first); | ||
} | ||
} | ||
} | ||
module.exports = Context; |
var Class = require('../../util/Class'); | ||
var character = require('../../util/character'); | ||
var Lexer = require('../../lexer/Lexer'); | ||
var Rule = require('../../lexer/rule/EcmascriptRule'); | ||
var Token = require('../../lexer/Token'); | ||
@@ -9,10 +10,13 @@ var Node = require('./Node'); | ||
var Parser = Class(function(lexer) { | ||
this.lexer = lexer; | ||
this.init(true); | ||
this.init(lexer); | ||
}).methods({ | ||
parse: function(code) { | ||
this.lexer.parse(code); | ||
return this.program(); | ||
this.tree = this.program(); | ||
return this.tree; | ||
}, | ||
init: function(first) { | ||
ast: function() { | ||
return this.tree; | ||
}, | ||
init: function(lexer) { | ||
this.look = null; | ||
@@ -29,5 +33,12 @@ this.tokens = null; | ||
this.hasMoveLine = false; | ||
if(!first) { | ||
this.tree = {}; | ||
if(lexer) { | ||
this.lexer = lexer; | ||
} | ||
else if(this.lexer) { | ||
this.lexer.init(); | ||
} | ||
else { | ||
this.lexer = new Lexer(new Rule()); | ||
} | ||
}, | ||
@@ -119,3 +130,3 @@ program: function() { | ||
var token = this.tokens[i]; | ||
if(S[token.type()]) { | ||
if(!S[token.type()]) { | ||
if(token.content() == ':') { | ||
@@ -128,5 +139,2 @@ return this.labstmt(); | ||
} | ||
else { | ||
break; | ||
} | ||
} | ||
@@ -1145,3 +1153,3 @@ } | ||
case 'false': | ||
return this.match(); | ||
node.add(this.match()); | ||
break; | ||
@@ -1152,6 +1160,6 @@ case '(': | ||
case '[': | ||
return this.arrltr(); | ||
node.add(this.arrltr()); | ||
break; | ||
case '{': | ||
return this.objltr(); | ||
node.add(this.objltr()); | ||
break; | ||
@@ -1158,0 +1166,0 @@ default: |
@@ -12,2 +12,4 @@ var homunculus = require('../homunculus'); | ||
var Token = require('../src/lexer/Token'); | ||
var JsContext = require('../src/parser/js/Context'); | ||
var JsEnv = require('../src/parser/js/Env'); | ||
@@ -40,2 +42,12 @@ describe('api of homunculus', function() { | ||
expect(homunculus.getClass('token')).to.be(Token); | ||
expect(homunculus.getClass('context', 'js')).to.be(JsContext); | ||
expect(homunculus.getClass('context', 'javascript')).to.be(JsContext); | ||
expect(homunculus.getClass('context', 'es')).to.be(JsContext); | ||
expect(homunculus.getClass('context', 'ecmascript')).to.be(JsContext); | ||
expect(homunculus.getClass('env', 'js')).to.be(JsEnv); | ||
expect(homunculus.getClass('env', 'javascript')).to.be(JsEnv); | ||
expect(homunculus.getClass('env', 'es')).to.be(JsEnv); | ||
expect(homunculus.getClass('env', 'ecmascript')).to.be(JsEnv); | ||
}); | ||
@@ -60,2 +72,8 @@ it('#getLexer', function() { | ||
}); | ||
it('#getContext', function() { | ||
expect(homunculus.getContext('js')).to.be.a(JsContext); | ||
expect(homunculus.getContext('javascript')).to.be.a(JsContext); | ||
expect(homunculus.getContext('es')).to.be.a(JsContext); | ||
expect(homunculus.getContext('ecmascript')).to.be.a(JsContext); | ||
}); | ||
}); |
@@ -107,14 +107,2 @@ var homunculus = require('../homunculus'); | ||
}); | ||
it('tokens index 1', function() { | ||
expect(tokens[0].tid()).to.eql(0); | ||
}); | ||
it('tokens index 2', function() { | ||
expect(tokens[1].tid()).to.eql(1); | ||
}); | ||
it('tokens index 3', function() { | ||
expect(tokens[6].tid()).to.eql(6); | ||
}); | ||
it('tokens index 4', function() { | ||
expect(tokens[13].tid()).to.eql(13); | ||
}); | ||
it('tokens sIndex 1', function() { | ||
@@ -121,0 +109,0 @@ expect(tokens[0].sIndex()).to.eql(0); |
@@ -134,2 +134,112 @@ var homunculus = require('../homunculus'); | ||
}); | ||
it('postfixexpr 1', function() { | ||
var parser = homunculus.getParser('js'); | ||
var node = parser.parse('a++ + b'); | ||
expect(tree(node)).to.eql([JsNode.PROGRAM, [JsNode.STMT, [JsNode.ADDEXPR, [JsNode.POSTFIXEXPR, [JsNode.PRMREXPR, ['a'], '++'], '+', JsNode.PRMREXPR, ['b']]]]]); | ||
}); | ||
it('postfixexpr 2', function() { | ||
var parser = homunculus.getParser('js'); | ||
var node = parser.parse('a\nb++'); | ||
expect(tree(node)).to.eql([JsNode.PROGRAM, [JsNode.STMT, [JsNode.PRMREXPR, ['a']], JsNode.STMT, [JsNode.POSTFIXEXPR, [JsNode.PRMREXPR, ['b'], '++']]]]); | ||
}); | ||
it('postfixexpr 3', function() { | ||
var parser = homunculus.getParser('js'); | ||
var node = parser.parse('a/*\n*/b++'); | ||
expect(tree(node)).to.eql([JsNode.PROGRAM, [JsNode.STMT, [JsNode.PRMREXPR, ['a']], JsNode.STMT, [JsNode.POSTFIXEXPR, [JsNode.PRMREXPR, ['b'], '++']]]]); | ||
}); | ||
it('fndecl', function() { | ||
var parser = homunculus.getParser('js'); | ||
var node = parser.parse('function a() {}'); | ||
expect(tree(node)).to.eql([JsNode.PROGRAM, [JsNode.FNDECL, ['function', 'a', '(', ')', '{', JsNode.FNBODY, [], '}']]]); | ||
}); | ||
it('fndecl with params', function() { | ||
var parser = homunculus.getParser('js'); | ||
var node = parser.parse('function a(b, c = 1, ...d) {}'); | ||
expect(tree(node)).to.eql([JsNode.PROGRAM, [JsNode.FNDECL, ['function', 'a', '(', JsNode.FNPARAMS, ['b', ',', 'c', JsNode.BINDELEMENT, ['=', JsNode.PRMREXPR, ['1']], ',', JsNode.RESTPARAM, ['...', 'd']], ')', '{', JsNode.FNBODY, [], '}']]]); | ||
}); | ||
it('fnexpr 1', function() { | ||
var parser = homunculus.getParser('js'); | ||
var node = parser.parse('~function() {}()'); | ||
expect(tree(node)).to.eql([JsNode.PROGRAM, [JsNode.STMT, [JsNode.UNARYEXPR, ['~', JsNode.CALLEXPR, [JsNode.FNEXPR, ['function', '(', ')', '{', JsNode.FNBODY, [], '}'], JsNode.ARGS, ['(', ')']]]]]]); | ||
}); | ||
it('fnexpr 2', function() { | ||
var parser = homunculus.getParser('js'); | ||
var node = parser.parse('(function() {})()'); | ||
expect(tree(node)).to.eql([JsNode.PROGRAM, [JsNode.STMT, [JsNode.CALLEXPR, [JsNode.PRMREXPR, ['(', JsNode.FNEXPR, ['function', '(', ')', '{', JsNode.FNBODY, [], '}'], ')'], JsNode.ARGS, ['(', ')']]]]]); | ||
}); | ||
it('labelstmt', function() { | ||
var parser = homunculus.getParser('js'); | ||
var node = parser.parse('label:;'); | ||
expect(tree(node)).to.eql([JsNode.PROGRAM, [JsNode.LABSTMT, ['label', ':', JsNode.EMPTSTMT, [';']]]]); | ||
}); | ||
it('prmrexpr 1', function() { | ||
var parser = homunculus.getParser('js'); | ||
var node = parser.parse('a'); | ||
expect(tree(node)).to.eql([JsNode.PROGRAM, [JsNode.STMT, [JsNode.PRMREXPR, ['a']]]]); | ||
}); | ||
it('prmrexpr 2', function() { | ||
var parser = homunculus.getParser('js'); | ||
var node = parser.parse('true'); | ||
expect(tree(node)).to.eql([JsNode.PROGRAM, [JsNode.STMT, [JsNode.PRMREXPR, ['true']]]]); | ||
}); | ||
it('prmrexpr 3', function() { | ||
var parser = homunculus.getParser('js'); | ||
var node = parser.parse('null'); | ||
expect(tree(node)).to.eql([JsNode.PROGRAM, [JsNode.STMT, [JsNode.PRMREXPR, ['null']]]]); | ||
}); | ||
it('prmrexpr 4', function() { | ||
var parser = homunculus.getParser('js'); | ||
var node = parser.parse('this'); | ||
expect(tree(node)).to.eql([JsNode.PROGRAM, [JsNode.STMT, [JsNode.PRMREXPR, ['this']]]]); | ||
}); | ||
it('prmrexpr 5', function() { | ||
var parser = homunculus.getParser('js'); | ||
var node = parser.parse('false'); | ||
expect(tree(node)).to.eql([JsNode.PROGRAM, [JsNode.STMT, [JsNode.PRMREXPR, ['false']]]]); | ||
}); | ||
it('prmrexpr 6', function() { | ||
var parser = homunculus.getParser('js'); | ||
var node = parser.parse('[]'); | ||
expect(tree(node)).to.eql([JsNode.PROGRAM, [JsNode.STMT, [JsNode.PRMREXPR, [JsNode.ARRLTR, ['[', ']']]]]]); | ||
}); | ||
it('prmrexpr 7', function() { | ||
var parser = homunculus.getParser('js'); | ||
var node = parser.parse('!{}'); | ||
expect(tree(node)).to.eql([JsNode.PROGRAM, [JsNode.STMT, [JsNode.UNARYEXPR, ['!', JsNode.PRMREXPR, [JsNode.OBJLTR, ['{', '}']]]]]]); | ||
}); | ||
it('mmbexpr 1', function() { | ||
var parser = homunculus.getParser('js'); | ||
var node = parser.parse('a.b'); | ||
expect(tree(node)).to.eql([JsNode.PROGRAM, [JsNode.STMT, [JsNode.MMBEXPR, [JsNode.PRMREXPR, ['a'], '.', 'b']]]]); | ||
}); | ||
it('mmbexpr 2', function() { | ||
var parser = homunculus.getParser('js'); | ||
var node = parser.parse('a[2]'); | ||
expect(tree(node)).to.eql([JsNode.PROGRAM, [JsNode.STMT, [JsNode.MMBEXPR, [JsNode.PRMREXPR, ['a'], '[', JsNode.PRMREXPR, ['2'], ']']]]]); | ||
}); | ||
it('callexpr 1', function() { | ||
var parser = homunculus.getParser('js'); | ||
var node = parser.parse('a()'); | ||
expect(tree(node)).to.eql([JsNode.PROGRAM, [JsNode.STMT, [JsNode.CALLEXPR, [JsNode.PRMREXPR, ['a'], JsNode.ARGS, ['(', ')']]]]]) | ||
}); | ||
it('callexpr 2', function() { | ||
var parser = homunculus.getParser('js'); | ||
var node = parser.parse('a.b()'); | ||
expect(tree(node)).to.eql([JsNode.PROGRAM, [JsNode.STMT, [JsNode.CALLEXPR, [JsNode.MMBEXPR, [JsNode.PRMREXPR, ['a'], '.', 'b'], JsNode.ARGS, ['(', ')']]]]]) | ||
}); | ||
it('callexpr 3', function() { | ||
var parser = homunculus.getParser('js'); | ||
var node = parser.parse('new A().f()'); | ||
expect(tree(node)).to.eql([JsNode.PROGRAM, [JsNode.STMT, [JsNode.CALLEXPR, [JsNode.MMBEXPR, [JsNode.NEWEXPR, ['new', JsNode.PRMREXPR, ['A'], JsNode.ARGS, ['(', ')']], '.', 'f'], JsNode.ARGS, ['(', ')']]]]]) | ||
}); | ||
it('unaryexpr 1', function() { | ||
var parser = homunculus.getParser('js'); | ||
var node = parser.parse('typeof a'); | ||
expect(tree(node)).to.eql([JsNode.PROGRAM, [JsNode.STMT, [JsNode.UNARYEXPR, ['typeof', JsNode.PRMREXPR, ['a']]]]]); | ||
}); | ||
it('unaryexpr 2', function() { | ||
var parser = homunculus.getParser('js'); | ||
var node = parser.parse('!!0'); | ||
expect(tree(node)).to.eql([JsNode.PROGRAM, [JsNode.STMT, [JsNode.UNARYEXPR, ['!', JsNode.UNARYEXPR, ['!', JsNode.PRMREXPR, ['0']]]]]]); | ||
}); | ||
it('node parent,prev,next', function() { | ||
@@ -136,0 +246,0 @@ var parser = homunculus.getParser('js'); |
define(function(require, exports, module) { | ||
var Class = require('../../util/Class'); | ||
var character = require('../../util/character'); | ||
var Lexer = require('../../lexer/Lexer'); | ||
var JsNode = require('./Node'); | ||
var Token = require('../../lexer/Token'); | ||
var Node = require('./Node'); | ||
var Context = Class(function() { | ||
var Parser = require('./Parser'); | ||
var id = 0; | ||
var Context = Class(function(parent, name) { | ||
this.id = id++; | ||
this.parser = new Parser(); | ||
this.parent = parent || null; //父上下文,如果是全局则为空 | ||
this.name = name || null; //上下文名称,即函数名,函数表达式为空,全局也为空 | ||
this.thisIs = null; //上下文环境中this的值,函数表达式中可能会赋值 | ||
this.children = []; //函数声明或函数表达式所产生的上下文 | ||
this.childrenMap = {}; //键是函数名,值是上下文,匿名函数表达式键为cid | ||
this.vars = []; //变量var声明 | ||
this.varsMap = {}; //键为id字面量,值是它的token的节点 | ||
this.params = []; //形参,函数上下文才有,即全局无 | ||
this.paramsMap = {}; //键为id字面量,值是它的token的节点 | ||
this.aParams = []; //实参,函数表达式才有 | ||
this.vids = []; //上下文环境里用到的变量id | ||
this.vidsMap = {}; //键为id字面量,值是它的token的节点 | ||
this.returns = []; //上下文环境里return语句 | ||
if(!this.isTop()) { | ||
this.parent.addChild(this); | ||
} | ||
}).methods({ | ||
parse: function(code) { | ||
var ast; | ||
if(code instanceof JsNode) { | ||
ast = code; | ||
} | ||
else { | ||
ast = this.parser.parse(code); | ||
} | ||
recursion(ast, this); | ||
return this; | ||
}, | ||
getId: function() { | ||
return this.id; | ||
}, | ||
getName: function() { | ||
return this.name; | ||
}, | ||
getParent: function() { | ||
return this.parent; | ||
}, | ||
getThis: function() { | ||
return this.thisIs; | ||
}, | ||
setThis: function(t) { | ||
this.thisIs = t; | ||
return this; | ||
}, | ||
isTop: function() { | ||
return !this.parent; | ||
}, | ||
isFnexpr: function() { | ||
return !this.isTop() && !this.name; | ||
}, | ||
hasParam: function(p) { | ||
return this.paramsMap.hasOwnProperty(p); | ||
}, | ||
getParams: function() { | ||
return this.params; | ||
}, | ||
addParam: function(p) { | ||
//形参不可能重复,无需判断 | ||
this.paramsMap[p] = this.params.length; | ||
this.params.push(p); | ||
return this; | ||
}, | ||
getAParams: function() { | ||
return this.aParams; | ||
}, | ||
addAParam: function(ap) { | ||
this.aParams.push(ap); | ||
return this; | ||
}, | ||
getChild: function(name) { | ||
return this.childrenMap[name]; | ||
}, | ||
getChildren: function() { | ||
return this.children; | ||
}, | ||
//通过name查找函数声明,id查找表达式 | ||
hasChild: function(name) { | ||
return this.childrenMap.hasOwnProperty(name); | ||
}, | ||
addChild: function(child) { | ||
var name = child.getName(); | ||
//函数表达式名字为空用id删除 | ||
if(name) { | ||
this.delChild(name); | ||
} | ||
else { | ||
this.delChild(child.getId()); | ||
} | ||
name = name || child.getId(); | ||
this.childrenMap[name] = child; | ||
this.children.push(child); | ||
return this; | ||
}, | ||
//name函数声明,id表达式 | ||
delChild: function(name) { | ||
if(this.hasChild(name)) { | ||
var i = this.children.indexOf(this.childrenMap[name]); | ||
this.children.splice(i, 1); | ||
delete this.childrenMap[name]; | ||
} | ||
return this; | ||
}, | ||
hasVar: function(v) { | ||
return this.varsMap.hasOwnProperty(v); | ||
}, | ||
addVar: function(node, assign) { | ||
var v = node.leaves()[0].token().content(); | ||
//赋值拥有最高优先级,会覆盖掉之前的函数声明和var | ||
if(assign) { | ||
this.delVar(v); | ||
this.delChild(v); | ||
} | ||
//仅仅是var声明无赋值,且已有过声明或函数,忽略之 | ||
else if(this.hasVar(v) || this.hasChild(v)) { | ||
return this; | ||
} | ||
this.varsMap[v] = node; | ||
this.vars.push(node); | ||
return this; | ||
}, | ||
delVar: function(v) { | ||
if(this.hasVar(v)) { | ||
var i = this.vars.indexOf(this.varsMap[v]); | ||
this.vars.splice(i, 1); | ||
delete this.varsMap[v]; | ||
} | ||
return this; | ||
}, | ||
getVars: function() { | ||
return this.vars; | ||
}, | ||
addReturn: function(node) { | ||
this.returns.push(node); | ||
return this; | ||
}, | ||
getReturns: function() { | ||
return this.returns; | ||
}, | ||
hasVid: function(v) { | ||
return this.vidsMap.hasOwnProperty(v); | ||
}, | ||
addVid: function(node) { | ||
var v = node.token().content(); | ||
if(this.vidsMap.hasOwnProperty(v)) { | ||
return; | ||
} | ||
this.vids.push(node); | ||
this.vidsMap[v] = node; | ||
return this; | ||
}, | ||
getVids: function() { | ||
return this.vids; | ||
} | ||
}); | ||
}); | ||
function recursion(node, context) { | ||
var isToken = node.name() == JsNode.TOKEN; | ||
var isVirtual = isToken && node.token().type() == Token.VIRTUAL; | ||
if(isToken) { | ||
if(!isVirtual) { | ||
var token = node.token(); | ||
var s = token.content(); | ||
if(s == 'return') { | ||
context.addReturn(node); | ||
} | ||
} | ||
} | ||
else { | ||
if(node.name() == JsNode.VARDECL) { | ||
vardecl(node, context); | ||
} | ||
else if(node.name() == JsNode.FNDECL) { | ||
context = fndecl(node, context); | ||
} | ||
else if(node.name() == JsNode.FNEXPR) { | ||
context = fnexpr(node, context); | ||
} | ||
else if(node.name() == JsNode.PRMREXPR) { | ||
prmrexpr(node, context); | ||
} | ||
node.leaves().forEach(function(leaf, i) { | ||
recursion(leaf, context); | ||
}); | ||
} | ||
} | ||
function vardecl(node, context) { | ||
var leaves = node.leaves(); | ||
var assign = !!leaves[1]; | ||
context.addVar(node, assign); | ||
} | ||
function fndecl(node, context) { | ||
var v = node.leaves()[1].leaves().content(); | ||
var child = new Context(context, v); | ||
var params = node.leaves()[3]; | ||
if(params.name() == JsNode.FNPARAMS) { | ||
addParam(params, child); | ||
} | ||
return child; | ||
} | ||
function fnexpr(node, context) { | ||
//函数表达式name为空 | ||
var child = new Context(context); | ||
//记录形参 | ||
var params; | ||
var v = node.leaves()[1]; | ||
if(v.name() == JsNode.TOKEN) { | ||
params = node.leaves()[3]; | ||
} | ||
else { | ||
params = node.leaves()[2]; | ||
} | ||
if(params.name() == JsNode.FNPARAMS) { | ||
addParam(params, child); | ||
} | ||
//匿名函数检查实参传入情况 | ||
var next = node.next(); | ||
//!function(){}()形式 | ||
if(next && next.name() == JsNode.ARGS) { | ||
var leaves = next.leaves(); | ||
//长度2为()空参数,长度3有参数,第2个节点 | ||
if(leaves.length == 3) { | ||
addAParam(leaves[1], child); | ||
} | ||
} | ||
//(function(){})()形式 | ||
else { | ||
var prmr = node.parent(); | ||
var prev = node.prev(); | ||
if(prmr.name() == JsNode.PRMREXPR && prev && prev.name() == JsNode.TOKEN && prev.token().content() == '(') { | ||
next = prmr.next(); | ||
if(next && next.name() == JsNode.ARGS) { | ||
var leaves = next.leaves(); | ||
//长度2为()空参数,长度3有参数,第2个节点 | ||
if(leaves.length == 3) { | ||
addAParam(leaves[1], child); | ||
} | ||
} | ||
} | ||
} | ||
return child; | ||
} | ||
//支持es6 | ||
function addParam(params, child) { | ||
params.leaves().forEach(function(leaf, i) { | ||
if(leaf.name() == JsNode.TOKEN && leaf.token().content() != ',') { | ||
child.addParam(leaf.token().content()); | ||
} | ||
else if(leaf.name() == JsNode.RESTPARAM) { | ||
child.addParam(leaf.leaves()[1].token().content()); | ||
} | ||
}); | ||
} | ||
function addAParam(params, child) { | ||
params.leaves().forEach(function(leaf, i) { | ||
if(i % 2 == 0) { | ||
child.addAParam(leaf); | ||
} | ||
}); | ||
} | ||
function prmrexpr(node, context) { | ||
var first = node.leaves()[0]; | ||
if(first.name() == JsNode.TOKEN) { | ||
var token = first.token(); | ||
if(token.type() == Token.ID) { | ||
context.addVid(first); | ||
} | ||
} | ||
} | ||
module.exports = Context; | ||
}); |
@@ -5,2 +5,3 @@ define(function(require, exports, module) { | ||
var Lexer = require('../../lexer/Lexer'); | ||
var Rule = require('../../lexer/rule/EcmascriptRule'); | ||
var Token = require('../../lexer/Token'); | ||
@@ -11,10 +12,13 @@ var Node = require('./Node'); | ||
var Parser = Class(function(lexer) { | ||
this.lexer = lexer; | ||
this.init(true); | ||
this.init(lexer); | ||
}).methods({ | ||
parse: function(code) { | ||
this.lexer.parse(code); | ||
return this.program(); | ||
this.tree = this.program(); | ||
return this.tree; | ||
}, | ||
init: function(first) { | ||
ast: function() { | ||
return this.tree; | ||
}, | ||
init: function(lexer) { | ||
this.look = null; | ||
@@ -31,5 +35,12 @@ this.tokens = null; | ||
this.hasMoveLine = false; | ||
if(!first) { | ||
this.tree = {}; | ||
if(lexer) { | ||
this.lexer = lexer; | ||
} | ||
else if(this.lexer) { | ||
this.lexer.init(); | ||
} | ||
else { | ||
this.lexer = new Lexer(new Rule()); | ||
} | ||
}, | ||
@@ -121,3 +132,3 @@ program: function() { | ||
var token = this.tokens[i]; | ||
if(S[token.type()]) { | ||
if(!S[token.type()]) { | ||
if(token.content() == ':') { | ||
@@ -130,5 +141,2 @@ return this.labstmt(); | ||
} | ||
else { | ||
break; | ||
} | ||
} | ||
@@ -1147,3 +1155,3 @@ } | ||
case 'false': | ||
return this.match(); | ||
node.add(this.match()); | ||
break; | ||
@@ -1154,6 +1162,6 @@ case '(': | ||
case '[': | ||
return this.arrltr(); | ||
node.add(this.arrltr()); | ||
break; | ||
case '{': | ||
return this.objltr(); | ||
node.add(this.objltr()); | ||
break; | ||
@@ -1160,0 +1168,0 @@ default: |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
935591
74
24612