diff options
author | Mihai Bazon <mihai@bazon.net> | 2012-08-15 13:32:37 +0300 |
---|---|---|
committer | Mihai Bazon <mihai@bazon.net> | 2012-08-15 14:50:27 +0300 |
commit | c0ba9e29861ab08ad8a5131705f421e96d634f4b (patch) | |
tree | 9e81de966f75e5f8205c23b220f950589688c037 /lib/ast.js | |
parent | 861e26a66639ca61eab2af53de45760370c4d534 (diff) | |
download | tracifyjs-c0ba9e29861ab08ad8a5131705f421e96d634f4b.tar.gz tracifyjs-c0ba9e29861ab08ad8a5131705f421e96d634f4b.zip |
WIP
Diffstat (limited to 'lib/ast.js')
-rw-r--r-- | lib/ast.js | 123 |
1 files changed, 81 insertions, 42 deletions
@@ -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_Statement); -}, AST_LabeledStatement); +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_Statement.prototype.walk.call(this, w); }); } -}, AST_LabeledStatement); +}, 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, { - walk: function(w) { - w._visit(this, function(){ - AST_Statement.prototype.walk.call(this, w); - }); - } + }, 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(); + } + } +}; |