This commit is contained in:
Mihai Bazon
2012-08-15 13:32:37 +03:00
parent 861e26a666
commit c0ba9e2986
5 changed files with 112 additions and 419 deletions

View File

@@ -8,6 +8,8 @@ function DEFNODE(type, props, methods, base) {
for (var i = props.length; --i >= 0;) {
code += "this." + props[i] + " = props." + props[i] + ";";
}
if (methods && methods.initialize)
code += "this.initialize();"
code += " } }";
var ctor = new Function(code)();
if (base) {
@@ -29,11 +31,15 @@ var AST_Token = DEFNODE("Token", "type value line col pos endpos nlb comments_be
}, null);
var AST_Node = DEFNODE("Node", "start end", {
renew: function(args) {
var ctor = this.CTOR, props = ctor.props;
for (var i in props) if (!HOP(args, i)) args[i] = this[i];
return new ctor(args);
clone: function() {
return new this.CTOR(this);
},
// XXX: what was this for?
// renew: function(args) {
// var ctor = this.CTOR, props = ctor.props;
// for (var i in props) if (!HOP(args, i)) args[i] = this[i];
// return new ctor(args);
// },
walk: function(w) {
w._visit(this);
}
@@ -75,41 +81,50 @@ Used for bodies of FUNCTION/TRY/CATCH/THROW/SWITCH.",
/* -----[ loops ]----- */
var AST_LabeledStatement = DEFNODE("LabeledStatement", "label body", {
var AST_Statement = DEFNODE("Statement", "label body", {
walk: function(w) {
w._visit(this, function(){
if (this.label) this.label.walk(w);
if (this.body) {
if (this.body instanceof Array)
AST_Bracketed.prototype.walk.call(this, w);
else
if (this.body instanceof AST_Node)
this.body.walk(w);
else
this.walk_array(w);
}
});
}
},
walk_array: AST_Bracketed.prototype.walk
});
var AST_Statement = DEFNODE("Statement", null, {
var AST_SimpleStatement = DEFNODE("SimpleStatement", null, {
}, AST_LabeledStatement);
}, AST_Statement);
var AST_BlockStatement = DEFNODE("BlockStatement", null, {
}, AST_Statement);
var AST_EmptyStatement = DEFNODE("EmptyStatement", null, {
}, AST_Statement);
var AST_Do = DEFNODE("Do", "condition", {
walk: function(w) {
w._visit(this, function(){
this.condition.walk(w);
AST_LabeledStatement.prototype.walk.call(this, w);
AST_Statement.prototype.walk.call(this, w);
});
}
}, AST_LabeledStatement);
}, AST_Statement);
var AST_While = DEFNODE("While", "condition", {
walk: function(w) {
w._visit(this, function(){
this.condition.walk(w);
AST_LabeledStatement.prototype.walk.call(this, w);
AST_Statement.prototype.walk.call(this, w);
});
}
}, AST_LabeledStatement);
}, AST_Statement);
var AST_For = DEFNODE("For", "init condition step", {
walk: function(w) {
@@ -117,42 +132,42 @@ var AST_For = DEFNODE("For", "init condition step", {
if (this.init) this.init.walk(w);
if (this.condition) this.condition.walk(w);
if (this.step) this.step.walk(w);
AST_LabeledStatement.prototype.walk.call(this, w);
AST_Statement.prototype.walk.call(this, w);
});
}
}, AST_LabeledStatement);
}, AST_Statement);
var AST_ForIn = DEFNODE("ForIn", "init name object", {
walk: function(w) {
w._visit(this, function(){
if (this.init) this.init.walk(w);
this.object.walk(w);
AST_LabeledStatement.prototype.walk.call(this, w);
AST_Statement.prototype.walk.call(this, w);
});
}
}, AST_LabeledStatement);
}, AST_Statement);
var AST_With = DEFNODE("With", "expression body", {
var AST_With = DEFNODE("With", "expression", {
walk: function(w) {
w._visit(this, function(){
this.expression.walk(w);
AST_LabeledStatement.prototype.walk.call(this, w);
AST_Statement.prototype.walk.call(this, w);
});
}
});
}, AST_Statement);
/* -----[ functions ]----- */
var AST_Scope = DEFNODE("Scope", "identifiers body", {
var AST_Scope = DEFNODE("Scope", "identifiers", {
walk: function(w) {
w._visit(this, function(){
if (this.identifiers) this.identifiers.forEach(function(el){
el.walk(w);
});
AST_LabeledStatement.prototype.walk.call(this, w);
AST_Statement.prototype.walk.call(this, w);
});
}
});
}, AST_Statement);
var AST_Toplevel = DEFNODE("Toplevel", null, {
@@ -234,25 +249,23 @@ var AST_Switch = DEFNODE("Switch", "expression", {
walk: function(w) {
w._visit(this, function(){
this.expression.walk(w);
AST_LabeledStatement.prototype.walk.call(this, w);
});
}
}, AST_LabeledStatement);
var AST_SwitchBlock = DEFNODE("SwitchBlock", null, {
}, AST_Bracketed);
var AST_SwitchBranch = DEFNODE("SwitchBranch", "body", {
});
var AST_Default = DEFNODE("Default", null, {
walk: function(w) {
w._visit(this, function(){
AST_Statement.prototype.walk.call(this, w);
});
}
}, AST_Statement);
var AST_SwitchBlock = DEFNODE("SwitchBlock", null, {
walk : AST_Statement.prototype.walk,
walk_array : AST_Bracketed.prototype.walk
}, AST_Bracketed);
var AST_SwitchBranch = DEFNODE("SwitchBranch", "body", {
walk : AST_Statement.prototype.walk,
walk_array : AST_Bracketed.prototype.walk
});
var AST_Default = DEFNODE("Default", null, {
}, AST_SwitchBranch);
var AST_Case = DEFNODE("Case", "expression", {
@@ -482,10 +495,8 @@ var AST_Number = DEFNODE("Number", "value", {
}, AST_Constant);
var AST_RegExp = DEFNODE("Regexp", "pattern mods", {
getValue: function() {
return this._regexp || (
this._regexp = new RegExp(this.pattern, this.mods)
);
initialize: function() {
this.value = new RegExp(this.pattern, this.mods);
}
}, AST_Constant);
@@ -494,17 +505,45 @@ var AST_Atom = DEFNODE("Atom", null, {
}, AST_Constant);
var AST_Null = DEFNODE("Null", null, {
getValue: function() { return null }
value: null
}, AST_Atom);
var AST_Undefined = DEFNODE("Undefined", null, {
getValue: function() { return (function(){}()) }
value: (function(){}())
}, AST_Atom);
var AST_False = DEFNODE("False", null, {
getValue: function() { return false }
value: false
}, AST_Atom);
var AST_True = DEFNODE("True", null, {
getValue: function() { return true }
value: true
}, AST_Atom);
/* -----[ Walker ]----- */
function TreeWalker(visitor) {
this.stack = [];
if (visitor) this.visit = visitor;
};
TreeWalker.prototype = {
visit: function(node){},
parent: function(n) {
if (n == null) n = 1;
return this.stack[this.stack.length - n];
},
find_parent: function(type) {
for (var a = this.stack, i = a.length; --i >= 0;)
if (a[i] instanceof type) return a[i];
return null;
},
_visit: function(node, descend) {
this.visit(node);
if (descend) {
this.stack.push(node);
descend.call(node);
this.stack.pop();
}
}
};