diff options
Diffstat (limited to 'lib/ast.js')
-rw-r--r-- | lib/ast.js | 68 |
1 files changed, 46 insertions, 22 deletions
@@ -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"); }, }); |