зеркало из https://github.com/mozilla/gecko-dev.git
Bug 760304: support defaults and rest parameters in Reflect.parse, r=dherman
This commit is contained in:
Родитель
8e8248a4d8
Коммит
9e83a37380
|
@ -374,6 +374,27 @@ class NodeBuilder
|
|||
setResult(node, dst);
|
||||
}
|
||||
|
||||
bool newNode(ASTType type, TokenPos *pos,
|
||||
const char *childName1, Value child1,
|
||||
const char *childName2, Value child2,
|
||||
const char *childName3, Value child3,
|
||||
const char *childName4, Value child4,
|
||||
const char *childName5, Value child5,
|
||||
const char *childName6, Value child6,
|
||||
const char *childName7, Value child7,
|
||||
Value *dst) {
|
||||
JSObject *node;
|
||||
return newNode(type, pos, &node) &&
|
||||
setProperty(node, childName1, child1) &&
|
||||
setProperty(node, childName2, child2) &&
|
||||
setProperty(node, childName3, child3) &&
|
||||
setProperty(node, childName4, child4) &&
|
||||
setProperty(node, childName5, child5) &&
|
||||
setProperty(node, childName6, child6) &&
|
||||
setProperty(node, childName7, child7) &&
|
||||
setResult(node, dst);
|
||||
}
|
||||
|
||||
bool listNode(ASTType type, const char *propName, NodeVector &elts, TokenPos *pos, Value *dst) {
|
||||
Value array;
|
||||
if (!newArray(elts, &array))
|
||||
|
@ -434,8 +455,9 @@ class NodeBuilder
|
|||
bool identifier(Value name, TokenPos *pos, Value *dst);
|
||||
|
||||
bool function(ASTType type, TokenPos *pos,
|
||||
Value id, NodeVector &args, Value body,
|
||||
bool isGenerator, bool isExpression, Value *dst);
|
||||
Value id, NodeVector &args, NodeVector &defaults,
|
||||
Value body, Value rest, bool isGenerator, bool isExpression,
|
||||
Value *dst);
|
||||
|
||||
bool variableDeclarator(Value id, Value init, TokenPos *pos, Value *dst);
|
||||
|
||||
|
@ -1327,13 +1349,16 @@ NodeBuilder::arrayPattern(NodeVector &elts, TokenPos *pos, Value *dst)
|
|||
|
||||
bool
|
||||
NodeBuilder::function(ASTType type, TokenPos *pos,
|
||||
Value id, NodeVector &args, Value body,
|
||||
Value id, NodeVector &args, NodeVector &defaults,
|
||||
Value body, Value rest,
|
||||
bool isGenerator, bool isExpression,
|
||||
Value *dst)
|
||||
{
|
||||
Value array;
|
||||
Value array, defarray;
|
||||
if (!newArray(args, &array))
|
||||
return false;
|
||||
if (!newArray(defaults, &defarray))
|
||||
return false;
|
||||
|
||||
Value cb = callbacks[type];
|
||||
if (!cb.isNull()) {
|
||||
|
@ -1344,7 +1369,9 @@ NodeBuilder::function(ASTType type, TokenPos *pos,
|
|||
return newNode(type, pos,
|
||||
"id", id,
|
||||
"params", array,
|
||||
"defaults", defarray,
|
||||
"body", body,
|
||||
"rest", rest,
|
||||
"generator", BooleanValue(isGenerator),
|
||||
"expression", BooleanValue(isExpression),
|
||||
dst);
|
||||
|
@ -1557,7 +1584,7 @@ class ASTSerializer
|
|||
bool xmls(ParseNode *pn, NodeVector &elts);
|
||||
bool leftAssociate(ParseNode *pn, Value *dst);
|
||||
bool functionArgs(ParseNode *pn, ParseNode *pnargs, ParseNode *pndestruct, ParseNode *pnbody,
|
||||
NodeVector &args);
|
||||
NodeVector &args, NodeVector &defaults, Value *rest);
|
||||
|
||||
bool sourceElement(ParseNode *pn, Value *dst);
|
||||
|
||||
|
@ -1612,7 +1639,8 @@ class ASTSerializer
|
|||
bool objectPattern(ParseNode *pn, VarDeclKind *pkind, Value *dst);
|
||||
|
||||
bool function(ParseNode *pn, ASTType type, Value *dst);
|
||||
bool functionArgsAndBody(ParseNode *pn, NodeVector &args, Value *body);
|
||||
bool functionArgsAndBody(ParseNode *pn, NodeVector &args, NodeVector &defaults,
|
||||
Value *body, Value *rest);
|
||||
bool functionBody(ParseNode *pn, TokenPos *pos, Value *dst);
|
||||
|
||||
bool comprehensionBlock(ParseNode *pn, Value *dst);
|
||||
|
@ -2935,18 +2963,26 @@ ASTSerializer::function(ParseNode *pn, ASTType type, Value *dst)
|
|||
return false;
|
||||
|
||||
NodeVector args(cx);
|
||||
NodeVector defaults(cx);
|
||||
|
||||
ParseNode *argsAndBody = pn->pn_body->isKind(PNK_UPVARS)
|
||||
? pn->pn_body->pn_tree
|
||||
: pn->pn_body;
|
||||
|
||||
Value body;
|
||||
return functionArgsAndBody(argsAndBody, args, &body) &&
|
||||
builder.function(type, &pn->pn_pos, id, args, body, isGenerator, isExpression, dst);
|
||||
Value rest;
|
||||
if (func->hasRest())
|
||||
rest.setUndefined();
|
||||
else
|
||||
rest.setNull();
|
||||
return functionArgsAndBody(argsAndBody, args, defaults, &body, &rest) &&
|
||||
builder.function(type, &pn->pn_pos, id, args, defaults, body,
|
||||
rest, isGenerator, isExpression, dst);
|
||||
}
|
||||
|
||||
bool
|
||||
ASTSerializer::functionArgsAndBody(ParseNode *pn, NodeVector &args, Value *body)
|
||||
ASTSerializer::functionArgsAndBody(ParseNode *pn, NodeVector &args,
|
||||
NodeVector &defaults, Value *body, Value *rest)
|
||||
{
|
||||
ParseNode *pnargs;
|
||||
ParseNode *pnbody;
|
||||
|
@ -2977,7 +3013,7 @@ ASTSerializer::functionArgsAndBody(ParseNode *pn, NodeVector &args, Value *body)
|
|||
/* Serialize the arguments and body. */
|
||||
switch (pnbody->getKind()) {
|
||||
case PNK_RETURN: /* expression closure, no destructured args */
|
||||
return functionArgs(pn, pnargs, NULL, pnbody, args) &&
|
||||
return functionArgs(pn, pnargs, NULL, pnbody, args, defaults, rest) &&
|
||||
expression(pnbody->pn_kid, body);
|
||||
|
||||
case PNK_SEQ: /* expression closure with destructured args */
|
||||
|
@ -2985,7 +3021,7 @@ ASTSerializer::functionArgsAndBody(ParseNode *pn, NodeVector &args, Value *body)
|
|||
ParseNode *pnstart = pnbody->pn_head->pn_next;
|
||||
LOCAL_ASSERT(pnstart && pnstart->isKind(PNK_RETURN));
|
||||
|
||||
return functionArgs(pn, pnargs, pndestruct, pnbody, args) &&
|
||||
return functionArgs(pn, pnargs, pndestruct, pnbody, args, defaults, rest) &&
|
||||
expression(pnstart->pn_kid, body);
|
||||
}
|
||||
|
||||
|
@ -2995,7 +3031,7 @@ ASTSerializer::functionArgsAndBody(ParseNode *pn, NodeVector &args, Value *body)
|
|||
? pnbody->pn_head->pn_next
|
||||
: pnbody->pn_head;
|
||||
|
||||
return functionArgs(pn, pnargs, pndestruct, pnbody, args) &&
|
||||
return functionArgs(pn, pnargs, pndestruct, pnbody, args, defaults, rest) &&
|
||||
functionBody(pnstart, &pnbody->pn_pos, body);
|
||||
}
|
||||
|
||||
|
@ -3006,7 +3042,8 @@ ASTSerializer::functionArgsAndBody(ParseNode *pn, NodeVector &args, Value *body)
|
|||
|
||||
bool
|
||||
ASTSerializer::functionArgs(ParseNode *pn, ParseNode *pnargs, ParseNode *pndestruct,
|
||||
ParseNode *pnbody, NodeVector &args)
|
||||
ParseNode *pnbody, NodeVector &args, NodeVector &defaults,
|
||||
Value *rest)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
ParseNode *arg = pnargs ? pnargs->pn_head : NULL;
|
||||
|
@ -3038,14 +3075,25 @@ ASTSerializer::functionArgs(ParseNode *pn, ParseNode *pnargs, ParseNode *pndestr
|
|||
* index in the formals list, so we rely on the ability to
|
||||
* ask destructuring args their index above.
|
||||
*/
|
||||
if (!identifier(arg, &node) || !args.append(node))
|
||||
if (!identifier(arg, &node))
|
||||
return false;
|
||||
if (rest->isUndefined() && arg->pn_next == pnbody)
|
||||
rest->setObject(node.toObject());
|
||||
else if (!args.append(node))
|
||||
return false;
|
||||
if (arg->pn_dflags & PND_DEFAULT) {
|
||||
ParseNode *expr = arg->isDefn() ? arg->expr() : arg->pn_kid->pn_right;
|
||||
Value def;
|
||||
if (!expression(expr, &def) || !defaults.append(def))
|
||||
return false;
|
||||
}
|
||||
arg = arg->pn_next;
|
||||
} else {
|
||||
LOCAL_NOT_REACHED("missing function argument");
|
||||
}
|
||||
++i;
|
||||
}
|
||||
JS_ASSERT(!rest->isUndefined());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -25,14 +25,18 @@ function returnStmt(expr) Pattern({ type: "ReturnStatement", argument: expr })
|
|||
function yieldExpr(expr) Pattern({ type: "YieldExpression", argument: expr })
|
||||
function lit(val) Pattern({ type: "Literal", value: val })
|
||||
var thisExpr = Pattern({ type: "ThisExpression" });
|
||||
function funDecl(id, params, body) Pattern({ type: "FunctionDeclaration",
|
||||
id: id,
|
||||
params: params,
|
||||
body: body,
|
||||
generator: false })
|
||||
function funDecl(id, params, body, defaults=[], rest=null) Pattern(
|
||||
{ type: "FunctionDeclaration",
|
||||
id: id,
|
||||
params: params,
|
||||
defaults: defaults,
|
||||
body: body,
|
||||
rest: rest,
|
||||
generator: false })
|
||||
function genFunDecl(id, params, body) Pattern({ type: "FunctionDeclaration",
|
||||
id: id,
|
||||
params: params,
|
||||
defaults: [],
|
||||
body: body,
|
||||
generator: true })
|
||||
function varDecl(decls) Pattern({ type: "VariableDeclaration", declarations: decls, kind: "var" })
|
||||
|
@ -213,6 +217,14 @@ assertDecl("function foo() { }",
|
|||
assertDecl("function foo() { return 42 }",
|
||||
funDecl(ident("foo"), [], blockStmt([returnStmt(lit(42))])));
|
||||
|
||||
assertDecl("function foo(...rest) { }",
|
||||
funDecl(ident("foo"), [], blockStmt([]), [], ident("rest")));
|
||||
|
||||
assertDecl("function foo(a=4) { }", funDecl(ident("foo"), [ident("a")], blockStmt([]), [lit(4)]));
|
||||
assertDecl("function foo(a, b=4) { }", funDecl(ident("foo"), [ident("a"), ident("b")], blockStmt([]), [lit(4)]));
|
||||
assertDecl("function foo(a, b=4, ...rest) { }",
|
||||
funDecl(ident("foo"), [ident("a"), ident("b")], blockStmt([]), [lit(4)], ident("rest")));
|
||||
|
||||
|
||||
// Bug 591437: rebound args have their defs turned into uses
|
||||
assertDecl("function f(a) { function a() { } }",
|
||||
|
|
Загрузка…
Ссылка в новой задаче