Skip to content

Commit

Permalink
Bug 1610447 - Update Reflect.parse for OptionalChain; r=arai
Browse files Browse the repository at this point in the history
Differential Revision: https://phabricator.services.mozilla.com/D60490

--HG--
extra : moz-landing-system : lando
  • Loading branch information
codehag committed Jan 21, 2020
1 parent bf8cd36 commit 2d3f3c7
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 14 deletions.
59 changes: 45 additions & 14 deletions js/src/builtin/ReflectParse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ static const char* const unopNames[] = {
"~", /* UNOP_BITNOT */
"typeof", /* UNOP_TYPEOF */
"void", /* UNOP_VOID */
"await" /* UNOP_AWAIT */
"await", /* UNOP_AWAIT */
};

static const char* const nodeTypeNames[] = {
Expand Down Expand Up @@ -651,11 +651,13 @@ class NodeBuilder {
TokenPos* pos, MutableHandleValue dst);

MOZ_MUST_USE bool callExpression(HandleValue callee, NodeVector& args,
TokenPos* pos, MutableHandleValue dst);
TokenPos* pos, MutableHandleValue dst,
bool isOptional = false);

MOZ_MUST_USE bool memberExpression(bool computed, HandleValue expr,
HandleValue member, TokenPos* pos,
MutableHandleValue dst);
MutableHandleValue dst,
bool isOptional = false);

MOZ_MUST_USE bool arrayExpression(NodeVector& elts, TokenPos* pos,
MutableHandleValue dst);
Expand All @@ -672,6 +674,9 @@ class NodeBuilder {
MOZ_MUST_USE bool spreadExpression(HandleValue expr, TokenPos* pos,
MutableHandleValue dst);

MOZ_MUST_USE bool optionalExpression(HandleValue expr, TokenPos* pos,
MutableHandleValue dst);

MOZ_MUST_USE bool computedName(HandleValue name, TokenPos* pos,
MutableHandleValue dst);

Expand Down Expand Up @@ -1156,7 +1161,8 @@ bool NodeBuilder::sequenceExpression(NodeVector& elts, TokenPos* pos,
}

bool NodeBuilder::callExpression(HandleValue callee, NodeVector& args,
TokenPos* pos, MutableHandleValue dst) {
TokenPos* pos, MutableHandleValue dst,
bool isOptional) {
RootedValue array(cx);
if (!newArray(args, &array)) {
return false;
Expand All @@ -1167,7 +1173,8 @@ bool NodeBuilder::callExpression(HandleValue callee, NodeVector& args,
return callback(cb, callee, array, pos, dst);
}

return newNode(AST_CALL_EXPR, pos, "callee", callee, "arguments", array, dst);
return newNode(isOptional ? AST_OPT_CALL_EXPR : AST_CALL_EXPR, pos, "callee",
callee, "arguments", array, dst);
}

bool NodeBuilder::newExpression(HandleValue callee, NodeVector& args,
Expand All @@ -1187,16 +1194,18 @@ bool NodeBuilder::newExpression(HandleValue callee, NodeVector& args,

bool NodeBuilder::memberExpression(bool computed, HandleValue expr,
HandleValue member, TokenPos* pos,
MutableHandleValue dst) {
MutableHandleValue dst,
bool isOptional /* = false */) {
RootedValue computedVal(cx, BooleanValue(computed));

RootedValue cb(cx, callbacks[AST_MEMBER_EXPR]);
if (!cb.isNull()) {
return callback(cb, computedVal, expr, member, pos, dst);
}

return newNode(AST_MEMBER_EXPR, pos, "object", expr, "property", member,
"computed", computedVal, dst);
return newNode(isOptional ? AST_OPT_MEMBER_EXPR : AST_MEMBER_EXPR, pos,
"object", expr, "property", member, "computed", computedVal,
dst);
}

bool NodeBuilder::arrayExpression(NodeVector& elts, TokenPos* pos,
Expand Down Expand Up @@ -1246,6 +1255,11 @@ bool NodeBuilder::spreadExpression(HandleValue expr, TokenPos* pos,
return newNode(AST_SPREAD_EXPR, pos, "expression", expr, dst);
}

bool NodeBuilder::optionalExpression(HandleValue expr, TokenPos* pos,
MutableHandleValue dst) {
return newNode(AST_OPTIONAL_EXPR, pos, "expression", expr, dst);
}

bool NodeBuilder::propertyPattern(HandleValue key, HandleValue patt,
bool isShorthand, TokenPos* pos,
MutableHandleValue dst) {
Expand Down Expand Up @@ -2808,9 +2822,16 @@ bool ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst) {
builder.unaryExpression(op, expr, &unaryNode->pn_pos, dst);
}

case ParseNodeKind::OptionalChain: {
RootedValue expr(cx);
return expression(pn->as<UnaryNode>().kid(), &expr) &&
builder.optionalExpression(expr, &pn->pn_pos, dst);
}

case ParseNodeKind::NewExpr:
case ParseNodeKind::TaggedTemplateExpr:
case ParseNodeKind::CallExpr:
case ParseNodeKind::OptionalCallExpr:
case ParseNodeKind::SuperCallExpr: {
BinaryNode* node = &pn->as<BinaryNode>();
ParseNode* calleeNode = node->left();
Expand Down Expand Up @@ -2848,14 +2869,18 @@ bool ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst) {
return builder.taggedTemplate(callee, args, &node->pn_pos, dst);
}

bool isOptional = node->isKind(ParseNodeKind::OptionalCallExpr);

// SUPERCALL is Call(super, args)
return node->isKind(ParseNodeKind::NewExpr)
? builder.newExpression(callee, args, &node->pn_pos, dst)
: builder.callExpression(callee, args, &node->pn_pos, dst);
: builder.callExpression(callee, args, &node->pn_pos, dst,
isOptional);
}

case ParseNodeKind::OptionalDotExpr:
case ParseNodeKind::DotExpr: {
PropertyAccess* prop = &pn->as<PropertyAccess>();
PropertyAccessBase* prop = &pn->as<PropertyAccessBase>();
MOZ_ASSERT(prop->pn_pos.encloses(prop->expression().pn_pos));

RootedValue expr(cx);
Expand All @@ -2872,13 +2897,16 @@ bool ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst) {
}
}

bool isOptional = prop->isKind(ParseNodeKind::OptionalDotExpr);

return identifier(pnAtom, nullptr, &propname) &&
builder.memberExpression(false, expr, propname, &prop->pn_pos,
dst);
builder.memberExpression(false, expr, propname, &prop->pn_pos, dst,
isOptional);
}

case ParseNodeKind::OptionalElemExpr:
case ParseNodeKind::ElemExpr: {
PropertyByValue* elem = &pn->as<PropertyByValue>();
PropertyByValueBase* elem = &pn->as<PropertyByValueBase>();
MOZ_ASSERT(elem->pn_pos.encloses(elem->expression().pn_pos));
MOZ_ASSERT(elem->pn_pos.encloses(elem->key().pn_pos));

Expand All @@ -2894,8 +2922,11 @@ bool ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst) {
}
}

bool isOptional = elem->isKind(ParseNodeKind::OptionalElemExpr);

return expression(&elem->key(), &key) &&
builder.memberExpression(true, expr, key, &elem->pn_pos, dst);
builder.memberExpression(true, expr, key, &elem->pn_pos, dst,
isOptional);
}

case ParseNodeKind::CallSiteObj: {
Expand Down
3 changes: 3 additions & 0 deletions js/src/jsast.tbl
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,13 @@ ASTDEF(AST_LOGICAL_EXPR, "LogicalExpression", "logicalExpr
ASTDEF(AST_UPDATE_EXPR, "UpdateExpression", "updateExpression")
ASTDEF(AST_NEW_EXPR, "NewExpression", "newExpression")
ASTDEF(AST_CALL_EXPR, "CallExpression", "callExpression")
ASTDEF(AST_OPT_CALL_EXPR, "OptionalCallExpression", "optionalCallExpression")
ASTDEF(AST_MEMBER_EXPR, "MemberExpression", "memberExpression")
ASTDEF(AST_OPT_MEMBER_EXPR, "OptionalMemberExpression", "optionalMemberExpression")
ASTDEF(AST_FUNC_EXPR, "FunctionExpression", "functionExpression")
ASTDEF(AST_ARROW_EXPR, "ArrowFunctionExpression", "arrowFunctionExpression")
ASTDEF(AST_ARRAY_EXPR, "ArrayExpression", "arrayExpression")
ASTDEF(AST_OPTIONAL_EXPR, "OptionalExpression", "optionalExpression")
ASTDEF(AST_SPREAD_EXPR, "SpreadExpression", "spreadExpression")
ASTDEF(AST_OBJECT_EXPR, "ObjectExpression", "objectExpression")
ASTDEF(AST_THIS_EXPR, "ThisExpression", "thisExpression")
Expand Down
12 changes: 12 additions & 0 deletions js/src/tests/non262/reflect-parse/PatternBuilders.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ function comp(name) {
function spread(val) {
return Pattern({ type: "SpreadExpression", expression: val});
}
function optExpr(val) {
return Pattern({ type: "OptionalExpression", expression: val});
}
var thisExpr = Pattern({ type: "ThisExpression" });
function funDecl(id, params, body, defaults=[], rest=null) {
return Pattern({ type: "FunctionDeclaration",
Expand Down Expand Up @@ -74,6 +77,12 @@ function dotExpr(obj, id) {
function memExpr(obj, id) {
return Pattern({ type: "MemberExpression", computed: true, object: obj, property: id });
}
function optDotExpr(obj, id) {
return Pattern({ type: "OptionalMemberExpression", computed: false, object: obj, property: id });
}
function optMemExpr(obj, id) {
return Pattern({ type: "OptionalMemberExpression", computed: true, object: obj, property: id });
}
function forStmt(init, test, update, body) {
return Pattern({ type: "ForStatement", init: init, test: test, update: update, body: body });
}
Expand Down Expand Up @@ -233,6 +242,9 @@ function newExpr(callee, args) {
function callExpr(callee, args) {
return Pattern({ type: "CallExpression", callee: callee, arguments: args });
}
function optCallExpr(callee, args) {
return Pattern({ type: "OptionalCallExpression", callee: callee, arguments: args });
}
function superCallExpr(args) {
return callExpr({ type: "Super" }, args);
}
Expand Down
21 changes: 21 additions & 0 deletions js/src/tests/non262/reflect-parse/expression.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,18 @@ assertExpr("foo[bar]", memExpr(ident("foo"), ident("bar")));
assertExpr("foo['bar']", memExpr(ident("foo"), lit("bar")));
assertExpr("foo[42]", memExpr(ident("foo"), lit(42)));

// optional member expressions
assertExpr("foo?.bar", optExpr(optDotExpr(ident("foo"), ident("bar"))));
assertExpr("foo?.bar.baz", optExpr(dotExpr(optDotExpr(ident("foo"), ident("bar")), ident("baz"))));
assertExpr("foo.bar?.baz", optExpr(optDotExpr(dotExpr(ident("foo"), ident("bar")), ident("baz"))));
assertExpr("foo?.bar?.baz", optExpr(optDotExpr(optDotExpr(ident("foo"), ident("bar")), ident("baz"))));
assertExpr("foo?.[bar].baz", optExpr(dotExpr(optMemExpr(ident("foo"), ident("bar")), ident("baz"))));
assertExpr("foo.bar?.[baz]", optExpr(optMemExpr(dotExpr(ident("foo"), ident("bar")), ident("baz"))));
assertExpr("foo[bar]?.[baz]", optExpr(optMemExpr(memExpr(ident("foo"), ident("bar")), ident("baz"))));
assertExpr("foo?.[bar][baz]", optExpr(memExpr(optMemExpr(ident("foo"), ident("bar")), ident("baz"))));
assertExpr("foo?.['bar']?.['baz']", optExpr(optMemExpr(optMemExpr(ident("foo"), lit("bar")), lit("baz"))));
assertExpr("foo?.[bar]?.baz", optExpr(optDotExpr(optMemExpr(ident("foo"), ident("bar")), ident("baz"))));

// function expressions
assertExpr("(function(){})", funExpr(null, [], blockStmt([])));
assertExpr("(function f() {})", funExpr(ident("f"), [], blockStmt([])));
Expand Down Expand Up @@ -107,6 +119,15 @@ assertExpr("(String())", callExpr(ident("String"), []));
assertExpr("(String(42))", callExpr(ident("String"), [lit(42)]));
assertExpr("(String(1,2,3))", callExpr(ident("String"), [lit(1),lit(2),lit(3)]));

// Optional Call expressions
assertExpr("(String?.())", optExpr(optCallExpr(ident("String"), [])));
assertExpr("(String?.(42))", optExpr(optCallExpr(ident("String"), [lit(42)])));
assertExpr("(String?.(1,2,3))", optExpr(optCallExpr(ident("String"), [lit(1),lit(2),lit(3)])));
assertExpr("(String?.foo?.())", optExpr(optCallExpr(optDotExpr(ident("String"), ident("foo")), [])));
assertExpr("(String.foo?.())", optExpr(optCallExpr(dotExpr(ident("String"), ident("foo")), [])));
assertExpr("(String?.foo)()", callExpr(optExpr(optDotExpr(ident("String"), ident("foo"))), []));
assertExpr("(String?.foo)?.()", optExpr(optCallExpr(optExpr(optDotExpr(ident("String"), ident("foo"))), [])));

// Array expressions
assertExpr("[]", arrExpr([]));
assertExpr("[1]", arrExpr([lit(1)]));
Expand Down

0 comments on commit 2d3f3c7

Please sign in to comment.