Bug 760304: support defaults and rest parameters in Reflect.parse, r=dherman

This commit is contained in:
Benjamin Peterson 2012-06-09 15:15:12 -07:00
parent 26fd21bca3
commit 74b6b66bb7
2 changed files with 79 additions and 19 deletions

View File

@ -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;
}

View File

@ -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() { } }",