aboutsummaryrefslogtreecommitdiff
path: root/lib/ast.js
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ast.js')
-rw-r--r--lib/ast.js68
1 files changed, 46 insertions, 22 deletions
diff --git a/lib/ast.js b/lib/ast.js
index f319a42d..60e57385 100644
--- a/lib/ast.js
+++ b/lib/ast.js
@@ -207,15 +207,25 @@ var AST_EmptyStatement = DEFNODE("EmptyStatement", null, {
$documentation: "The empty statement (empty block or simply a semicolon)"
}, AST_Statement);
-function must_be_expression(node, prop) {
- if (!(node[prop] instanceof AST_Node)) throw new Error(prop + " must be AST_Node");
- if (node[prop] instanceof AST_Hole) throw new Error(prop + " cannot be AST_Hole");
- if (node[prop] instanceof AST_Spread) throw new Error(prop + " cannot be AST_Spread");
- if (node[prop] instanceof AST_Statement && !is_function(node[prop])) {
- throw new Error(prop + " cannot be AST_Statement");
+function validate_expression(value, prop, multiple, allow_spread, allow_hole) {
+ multiple = multiple ? "contain" : "be";
+ if (!(value instanceof AST_Node)) throw new Error(prop + " must " + multiple + " AST_Node");
+ if (value instanceof AST_DefaultValue) throw new Error(prop + " cannot " + multiple + " AST_DefaultValue");
+ if (value instanceof AST_Destructured) throw new Error(prop + " cannot " + multiple + " AST_Destructured");
+ if (value instanceof AST_Hole && !allow_hole) throw new Error(prop + " cannot " + multiple + " AST_Hole");
+ if (value instanceof AST_Spread && !allow_spread) throw new Error(prop + " cannot " + multiple + " AST_Spread");
+ if (value instanceof AST_Statement && !is_function(value)) {
+ throw new Error(prop + " cannot " + multiple + " AST_Statement");
+ }
+ if (value instanceof AST_SymbolDeclaration) {
+ throw new Error(prop + " cannot " + multiple + " AST_SymbolDeclaration");
}
}
+function must_be_expression(node, prop) {
+ validate_expression(node[prop], prop);
+}
+
var AST_SimpleStatement = DEFNODE("SimpleStatement", "body", {
$documentation: "A statement consisting of an expression, i.e. a = 1 + 2",
$propdoc: {
@@ -534,7 +544,7 @@ var AST_Lambda = DEFNODE("Lambda", "argnames length_read uses_arguments", {
this.argnames.forEach(function(node) {
validate_destructured(node, function(node) {
if (!(node instanceof AST_SymbolFunarg)) throw new Error("argnames must be AST_SymbolFunarg[]");
- });
+ }, true);
});
},
}, AST_Scope);
@@ -838,7 +848,6 @@ var AST_Const = DEFNODE("Const", null, {
validate_destructured(node.name, function(node) {
if (!(node instanceof AST_SymbolConst)) throw new Error("name must be AST_SymbolConst");
});
- if (node.value != null) must_be_expression(node, "value");
});
},
}, AST_Definitions);
@@ -851,7 +860,6 @@ var AST_Let = DEFNODE("Let", null, {
validate_destructured(node.name, function(node) {
if (!(node instanceof AST_SymbolLet)) throw new Error("name must be AST_SymbolLet");
});
- if (node.value != null) must_be_expression(node, "value");
});
},
}, AST_Definitions);
@@ -864,7 +872,6 @@ var AST_Var = DEFNODE("Var", null, {
validate_destructured(node.name, function(node) {
if (!(node instanceof AST_SymbolVar)) throw new Error("name must be AST_SymbolVar");
});
- if (node.value != null) must_be_expression(node, "value");
});
},
}, AST_Definitions);
@@ -873,7 +880,7 @@ var AST_VarDef = DEFNODE("VarDef", "name value", {
$documentation: "A variable declaration; only appears in a AST_Definitions node",
$propdoc: {
name: "[AST_Destructured|AST_SymbolVar] name of the variable",
- value: "[AST_Node?] initializer, or null of there's no initializer"
+ value: "[AST_Node?] initializer, or null of there's no initializer",
},
walk: function(visitor) {
var node = this;
@@ -882,18 +889,34 @@ var AST_VarDef = DEFNODE("VarDef", "name value", {
if (node.value) node.value.walk(visitor);
});
},
+ _validate: function() {
+ if (this.value != null) must_be_expression(this, "value");
+ },
});
/* -----[ OTHER ]----- */
+var AST_DefaultValue = DEFNODE("DefaultValue", "name value", {
+ $documentation: "A default value declaration",
+ $propdoc: {
+ name: "[AST_Destructured|AST_SymbolDeclaration] name of the variable",
+ value: "[AST_Node] value to assign if variable is `undefined`",
+ },
+ walk: function(visitor) {
+ var node = this;
+ visitor.visit(node, function() {
+ node.name.walk(visitor);
+ node.value.walk(visitor);
+ });
+ },
+ _validate: function() {
+ must_be_expression(this, "value");
+ },
+});
+
function must_be_expressions(node, prop, allow_spread, allow_hole) {
node[prop].forEach(function(node) {
- if (!(node instanceof AST_Node)) throw new Error(prop + " must be AST_Node[]");
- if (!allow_hole && node instanceof AST_Hole) throw new Error(prop + " cannot be AST_Hole");
- if (!allow_spread && node instanceof AST_Spread) throw new Error(prop + " cannot be AST_Spread");
- if (node instanceof AST_Statement && !is_function(node)) {
- throw new Error(prop + " cannot contain AST_Statement");
- }
+ validate_expression(node, prop, true, allow_spread, allow_hole);
});
}
@@ -1048,7 +1071,7 @@ var AST_Binary = DEFNODE("Binary", "operator left right", {
});
},
_validate: function() {
- must_be_expression(this, "left");
+ if (!(this instanceof AST_Assign)) must_be_expression(this, "left");
if (typeof this.operator != "string") throw new Error("operator must be string");
must_be_expression(this, "right");
},
@@ -1131,12 +1154,13 @@ var AST_Destructured = DEFNODE("Destructured", null, {
$documentation: "Base class for destructured literal",
});
-function validate_destructured(node, check) {
+function validate_destructured(node, check, allow_default) {
+ if (node instanceof AST_DefaultValue && allow_default) return validate_destructured(node.name, check);
if (node instanceof AST_DestructuredArray) return node.elements.forEach(function(node) {
- if (!(node instanceof AST_Hole)) validate_destructured(node, check);
+ if (!(node instanceof AST_Hole)) validate_destructured(node, check, true);
});
if (node instanceof AST_DestructuredObject) return node.properties.forEach(function(prop) {
- validate_destructured(prop.value, check);
+ validate_destructured(prop.value, check, true);
});
check(node);
}
@@ -1174,7 +1198,7 @@ var AST_DestructuredKeyVal = DEFNODE("DestructuredKeyVal", "key value", {
if (!(this.key instanceof AST_Node)) throw new Error("key must be string or AST_Node");
must_be_expression(this, "key");
}
- must_be_expression(this, "value");
+ if (!(this.value instanceof AST_Node)) throw new Error("value must be AST_Node");
},
});