support default values (#4442)

This commit is contained in:
Alex Lam S.L
2020-12-23 22:22:55 +00:00
committed by GitHub
parent 56fce2131c
commit 2390fae5c4
10 changed files with 1430 additions and 208 deletions

View File

@@ -207,13 +207,23 @@ 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", {
@@ -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");
},
});