a LabeledStatement should be in fact a StatementWithBody

This fixes output for:

    if (foo) {
        moo: if (bar) {
            break moo;
        }
    } else {
        baz();
    }

(the labeled statement must be outputted inside brackets)
This commit is contained in:
Mihai Bazon
2012-09-03 12:05:10 +03:00
parent d6efa8b28d
commit d7c1dc6c05
5 changed files with 57 additions and 24 deletions

View File

@@ -41,6 +41,8 @@
***********************************************************************/
var NODE_HIERARCHY = {};
function DEFNODE(type, props, methods, base) {
if (arguments.length < 4) base = AST_Node;
if (!props) props = [];
@@ -73,6 +75,10 @@ function DEFNODE(type, props, methods, base) {
ctor.DEFMETHOD = function(name, method) {
this.prototype[name] = method;
};
NODE_HIERARCHY[type] = {
def: ctor,
base: base
};
return ctor;
};
@@ -108,16 +114,6 @@ var AST_Directive = DEFNODE("Directive", "value", {
/* -----[ loops ]----- */
var AST_LabeledStatement = DEFNODE("LabeledStatement", "label statement", {
$documentation: "Statement with a label",
_walk: function(visitor) {
return visitor._visit(this, function(){
this.label._walk(visitor);
this.statement._walk(visitor);
});
}
});
var AST_Statement = DEFNODE("Statement", "body", {
$documentation: "Base class of all statements",
_walk: function(visitor) {
@@ -153,6 +149,16 @@ var AST_StatementWithBody = DEFNODE("StatementWithBody", null, {
$documentation: "Base class for all statements that contain one nested body: `For`, `ForIn`, `Do`, `While`, `With`."
}, AST_Statement);
var AST_LabeledStatement = DEFNODE("LabeledStatement", "label", {
$documentation: "Statement with a label",
_walk: function(visitor) {
return visitor._visit(this, function(){
this.label._walk(visitor);
this.body._walk(visitor);
});
}
}, AST_StatementWithBody);
var AST_DWLoop = DEFNODE("DWLoop", "condition", {
$documentation: "Base class for do/while statements.",
_walk: function(visitor) {
@@ -434,9 +440,11 @@ var AST_Seq = DEFNODE("Seq", "first second", {
});
var AST_PropAccess = DEFNODE("PropAccess", "expression property", {
$documentation: "Base class for property access expressions, i.e. `a.foo` or `a[\"foo\"]`"
});
var AST_Dot = DEFNODE("Dot", null, {
$documentation: "A dotted property access expression",
_walk: function(visitor) {
return visitor._visit(this, function(){
this.expression._walk(visitor);
@@ -445,6 +453,7 @@ var AST_Dot = DEFNODE("Dot", null, {
}, AST_PropAccess);
var AST_Sub = DEFNODE("Sub", null, {
$documentation: "Index-style property access, i.e. `a[\"foo\"]`",
_walk: function(visitor) {
return visitor._visit(this, function(){
this.expression._walk(visitor);
@@ -454,6 +463,7 @@ var AST_Sub = DEFNODE("Sub", null, {
}, AST_PropAccess);
var AST_Unary = DEFNODE("Unary", "operator expression", {
$documentation: "Base class for unary expressions",
_walk: function(visitor) {
return visitor._visit(this, function(){
this.expression._walk(visitor);
@@ -462,12 +472,15 @@ var AST_Unary = DEFNODE("Unary", "operator expression", {
});
var AST_UnaryPrefix = DEFNODE("UnaryPrefix", null, {
$documentation: "Unary prefix expression, i.e. `typeof i` or `++i`"
}, AST_Unary);
var AST_UnaryPostfix = DEFNODE("UnaryPostfix", null, {
$documentation: "Unary postfix expression, i.e. `i++`"
}, AST_Unary);
var AST_Binary = DEFNODE("Binary", "left operator right", {
$documentation: "Binary expression, i.e. `a + b`",
_walk: function(visitor) {
return visitor._visit(this, function(){
this.left._walk(visitor);
@@ -477,6 +490,7 @@ var AST_Binary = DEFNODE("Binary", "left operator right", {
});
var AST_Conditional = DEFNODE("Conditional", "condition consequent alternative", {
$documentation: "Conditional expression using the ternary operator, i.e. `a ? b : c`",
_walk: function(visitor) {
return visitor._visit(this, function(){
this.condition._walk(visitor);
@@ -487,11 +501,13 @@ var AST_Conditional = DEFNODE("Conditional", "condition consequent alternative",
});
var AST_Assign = DEFNODE("Assign", "left operator right", {
$documentation: "An assignment expression — `a = b + 5`",
}, AST_Binary);
/* -----[ LITERALS ]----- */
var AST_Array = DEFNODE("Array", "elements", {
$documentation: "An array literal",
_walk: function(visitor) {
return visitor._visit(this, function(){
this.elements.forEach(function(el){
@@ -502,6 +518,7 @@ var AST_Array = DEFNODE("Array", "elements", {
});
var AST_Object = DEFNODE("Object", "properties", {
$documentation: "An object literal",
_walk: function(visitor) {
return visitor._visit(this, function(){
this.properties.forEach(function(prop){
@@ -512,6 +529,7 @@ var AST_Object = DEFNODE("Object", "properties", {
});
var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", {
$documentation: "Base class for literal object properties",
_walk: function(visitor) {
return visitor._visit(this, function(){
this.value._walk(visitor);
@@ -520,89 +538,104 @@ var AST_ObjectProperty = DEFNODE("ObjectProperty", "key value", {
});
var AST_ObjectKeyVal = DEFNODE("ObjectKeyval", null, {
$documentation: "A key: value object property",
}, AST_ObjectProperty);
var AST_ObjectSetter = DEFNODE("ObjectSetter", null, {
$documentation: "An object setter property",
}, AST_ObjectProperty);
var AST_ObjectGetter = DEFNODE("ObjectGetter", null, {
$documentation: "An object getter property",
}, AST_ObjectProperty);
var AST_Symbol = DEFNODE("Symbol", "scope name global undeclared", {
$documentation: "Base class for all symbols",
});
var AST_SymbolDeclaration = DEFNODE("SymbolDeclaration", "references", {
$documentation: "A declaration symbol (symbol in var/const, function name or argument, symbol in catch)",
}, AST_Symbol);
var AST_SymbolVar = DEFNODE("SymbolVar", null, {
$documentation: "Symbol defining a variable or constant"
$documentation: "Symbol defining a variable or constant",
}, AST_SymbolDeclaration);
var AST_SymbolFunarg = DEFNODE("SymbolFunarg", null, {
$documentation: "Symbol naming a function argument"
$documentation: "Symbol naming a function argument",
}, AST_SymbolVar);
var AST_SymbolDefun = DEFNODE("SymbolDefun", null, {
$documentation: "Symbol defining a function"
$documentation: "Symbol defining a function",
}, AST_SymbolDeclaration);
var AST_SymbolLambda = DEFNODE("SymbolLambda", null, {
$documentation: "Symbol naming a function expression"
$documentation: "Symbol naming a function expression",
}, AST_SymbolDeclaration);
var AST_SymbolCatch = DEFNODE("SymbolCatch", null, {
$documentation: "Symbol naming the exception in catch"
$documentation: "Symbol naming the exception in catch",
}, AST_SymbolDeclaration);
var AST_Label = DEFNODE("Label", null, {
$documentation: "Symbol naming a label (declaration)"
$documentation: "Symbol naming a label (declaration)",
}, AST_SymbolDeclaration);
var AST_SymbolRef = DEFNODE("SymbolRef", "symbol", {
$documentation: "Reference to some symbol (not definition/declaration)"
$documentation: "Reference to some symbol (not definition/declaration)",
}, AST_Symbol);
var AST_LabelRef = DEFNODE("LabelRef", null, {
$documentation: "Reference to a label symbol"
$documentation: "Reference to a label symbol",
}, AST_SymbolRef);
var AST_This = DEFNODE("This", null, {
$documentation: "The `this` symbol",
}, AST_Symbol);
var AST_Constant = DEFNODE("Constant", null, {
$documentation: "Base class for all constants",
getValue: function() {
return this.value;
}
});
var AST_String = DEFNODE("String", "value", {
$documentation: "A string literal",
}, AST_Constant);
var AST_Number = DEFNODE("Number", "value", {
$documentation: "A number literal",
}, AST_Constant);
var AST_RegExp = DEFNODE("Regexp", "pattern mods", {
$documentation: "A regexp literal",
initialize: function() {
this.value = new RegExp(this.pattern, this.mods);
}
}, AST_Constant);
var AST_Atom = DEFNODE("Atom", null, {
$documentation: "Base class for atoms",
}, AST_Constant);
var AST_Null = DEFNODE("Null", null, {
$documentation: "The `null` atom",
value: null
}, AST_Atom);
var AST_Undefined = DEFNODE("Undefined", null, {
$documentation: "The `undefined` value",
value: (function(){}())
}, AST_Atom);
var AST_False = DEFNODE("False", null, {
$documentation: "The `false` atom",
value: false
}, AST_Atom);
var AST_True = DEFNODE("True", null, {
$documentation: "The `true` atom",
value: true
}, AST_Atom);