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:
69
lib/ast.js
69
lib/ast.js
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user