WIP
This commit is contained in:
137
lib/ast.js
137
lib/ast.js
@@ -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();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user