$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(){
}
}, 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) {
/* -----[ 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() {
this.argnames.forEach(function(arg){
arg._walk(visitor);
});
- this.body._walk(visitor);
+ walk_body(this, visitor);
});
}
}, AST_Scope);
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", {
_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
// 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 ]----- */
self.body.print(output);
output.semicolon();
});
- DEFPRINT(AST_BlockStatement, function(self, output){
- var body = self.body;
+ function print_bracketed(body, output) {
if (body.length > 0) output.with_block(function(){
display_body(body, false, output);
});
else output.print("{}");
+ };
+ DEFPRINT(AST_BlockStatement, function(self, output){
+ print_bracketed(self.body, output);
});
DEFPRINT(AST_EmptyStatement, function(self, output){
output.semicolon();
});
});
output.space();
- self.body.print(output);
+ print_bracketed(self.body, output);
});
DEFPRINT(AST_Lambda, function(self, output){
self._do_print(output);
DEFPRINT(AST_Try, function(self, output){
output.print("try");
output.space();
- self.btry.print(output);
+ print_bracketed(self.body, output);
if (self.bcatch) {
output.space();
self.bcatch.print(output);
self.argname.print(output);
});
output.space();
- self.body.print(output);
+ print_bracketed(self.body, output);
});
DEFPRINT(AST_Finally, function(self, output){
output.print("finally");
output.space();
- self.body.print(output);
+ print_bracketed(self.body, output);
});
/* -----[ var/const ]----- */