cleaned up usage of AST_BlockStatement

The following nodes were instances of AST_BlockStatement: AST_Scope,
AST_SwitchBlock, AST_SwitchBranch.  Also, AST_Try, AST_Catch, AST_Finally
were having a body instanceof AST_BlockStatement.

Overloading the meaning of AST_BlockStatement this way turned out to be a
mess; we now have an AST_Block class that is the base class for things
having a block of statements (might or might not be bracketed).  The
`this.body` of AST_Scope, AST_Try, AST_Catch, AST_Finally is now an array of
statements (as they inherit from AST_Block).

Avoiding calling superclass's _walk function in walkers (turns out we walked
a node multiple times).
This commit is contained in:
Mihai Bazon
2012-09-05 11:31:02 +03:00
parent 1b5183dd5e
commit 8633b0073f
6 changed files with 61 additions and 60 deletions

View File

@@ -127,7 +127,7 @@ var AST_SimpleStatement = DEFNODE("SimpleStatement", null, {
$documentation: "A statement consisting of an expression, i.e. a = 1 + 2."
}, AST_Statement);
var AST_BlockStatement = DEFNODE("BlockStatement", "required", {
var AST_BlockStatement = DEFNODE("BlockStatement", null, {
$documentation: "A block statement.",
_walk: function(visitor) {
return visitor._visit(this, function(){
@@ -138,6 +138,21 @@ var AST_BlockStatement = DEFNODE("BlockStatement", "required", {
}
}, AST_Statement);
function walk_body(node, visitor) {
if (node.body instanceof Array) node.body.forEach(function(stat){
stat._walk(visitor);
}); else node.body._walk(visitor);
};
var AST_Block = DEFNODE("Block", null, {
$documentation: "A block of statements (usually always bracketed)",
_walk: function(visitor) {
return visitor._visit(this, function(){
walk_body(this, visitor);
});
}
}, AST_Statement);
var AST_EmptyStatement = DEFNODE("EmptyStatement", null, {
$documentation: "The empty statement (empty block or simply a semicolon).",
_walk: function(visitor) {
@@ -213,8 +228,8 @@ var AST_With = DEFNODE("With", "expression", {
/* -----[ scope and functions ]----- */
var AST_Scope = DEFNODE("Scope", "variables functions uses_with uses_eval parent_scope enclosed cname", {
$documentation: "Base class for all statements introducing a lexical scope"
}, AST_BlockStatement);
$documentation: "Base class for all statements introducing a lexical scope",
}, AST_Block);
var AST_Toplevel = DEFNODE("Toplevel", null, {
initialize: function() {
@@ -231,7 +246,7 @@ var AST_Lambda = DEFNODE("Lambda", "name argnames uses_arguments", {
this.argnames.forEach(function(arg){
arg._walk(visitor);
});
this.body._walk(visitor);
walk_body(this, visitor);
});
}
}, AST_Scope);
@@ -311,25 +326,14 @@ var AST_Switch = DEFNODE("Switch", "expression", {
var AST_SwitchBlock = DEFNODE("SwitchBlock", null, {
$documentation: "The switch block is somewhat special, hence a special node for it",
initialize: function() {
this.required = true;
},
}, AST_BlockStatement);
}, AST_Block);
var AST_SwitchBranch = DEFNODE("SwitchBranch", null, {
$documentation: "Base class for `switch` branches",
initialize: function() {
this.required = true;
},
}, AST_BlockStatement);
}, AST_Block);
var AST_Default = DEFNODE("Default", null, {
$documentation: "A `default` switch branch",
_walk: function(visitor) {
return visitor._visit(this, function(){
AST_BlockStatement.prototype._walk.call(this, visitor);
});
}
}, AST_SwitchBranch);
var AST_Case = DEFNODE("Case", "expression", {
@@ -337,23 +341,23 @@ var AST_Case = DEFNODE("Case", "expression", {
_walk: function(visitor) {
return visitor._visit(this, function(){
this.expression._walk(visitor);
AST_BlockStatement.prototype._walk.call(this, visitor);
walk_body(this, visitor);
});
}
}, AST_SwitchBranch);
/* -----[ EXCEPTIONS ]----- */
var AST_Try = DEFNODE("Try", "btry bcatch bfinally", {
var AST_Try = DEFNODE("Try", "bcatch bfinally", {
$documentation: "A `try` statement",
_walk: function(visitor) {
return visitor._visit(this, function(){
this.btry._walk(visitor);
walk_body(this, visitor);
if (this.bcatch) this.bcatch._walk(visitor);
if (this.bfinally) this.bfinally._walk(visitor);
});
}
}, AST_Statement);
}, AST_Block);
// XXX: this is wrong according to ECMA-262 (12.4). the catch block
// should introduce another scope, as the argname should be visible
@@ -361,24 +365,19 @@ var AST_Try = DEFNODE("Try", "btry bcatch bfinally", {
// IE which simply introduces the name in the surrounding scope. If
// we ever want to fix this then AST_Catch should inherit from
// AST_Scope.
var AST_Catch = DEFNODE("Catch", "argname body", {
var AST_Catch = DEFNODE("Catch", "argname", {
$documentation: "A `catch` node; only makes sense as part of a `try` statement",
_walk: function(visitor) {
return visitor._visit(this, function(){
this.argname._walk(visitor);
this.body._walk(visitor);
walk_body(this, visitor);
});
}
});
}, AST_Block);
var AST_Finally = DEFNODE("Finally", "body", {
$documentation: "A `finally` node; only makes sense as part of a `try` statement",
_walk: function(visitor) {
return visitor._visit(this, function(){
this.body._walk(visitor);
});
}
});
var AST_Finally = DEFNODE("Finally", null, {
$documentation: "A `finally` node; only makes sense as part of a `try` statement"
}, AST_Block);
/* -----[ VAR/CONST ]----- */