mirror of
https://repo.dactyloidae.xyz/Dactyloidae/UXP.git
synced 2026-10-24 16:17:29 +09:00
Issue #2097 - Implement logical assignment operators
Based-on: 1629106/1, 1684020
This commit is contained in:
parent
ba9647a12a
commit
10951a169c
9 changed files with 302 additions and 6 deletions
|
|
@ -53,6 +53,8 @@ enum AssignmentOperator {
|
||||||
AOP_LSH, AOP_RSH, AOP_URSH,
|
AOP_LSH, AOP_RSH, AOP_URSH,
|
||||||
/* binary */
|
/* binary */
|
||||||
AOP_BITOR, AOP_BITXOR, AOP_BITAND,
|
AOP_BITOR, AOP_BITXOR, AOP_BITAND,
|
||||||
|
/* short-circuit */
|
||||||
|
AOP_COALESCE, AOP_OR, AOP_AND,
|
||||||
|
|
||||||
AOP_LIMIT
|
AOP_LIMIT
|
||||||
};
|
};
|
||||||
|
|
@ -122,6 +124,9 @@ static const char* const aopNames[] = {
|
||||||
"|=", /* AOP_BITOR */
|
"|=", /* AOP_BITOR */
|
||||||
"^=", /* AOP_BITXOR */
|
"^=", /* AOP_BITXOR */
|
||||||
"&=" /* AOP_BITAND */
|
"&=" /* AOP_BITAND */
|
||||||
|
"\?\?=", /* AOP_COALESCE */
|
||||||
|
"||=", /* AOP_OR */
|
||||||
|
"&&=", /* AOP_AND */
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char* const binopNames[] = {
|
static const char* const binopNames[] = {
|
||||||
|
|
@ -1974,6 +1979,12 @@ ASTSerializer::aop(JSOp op)
|
||||||
return AOP_BITXOR;
|
return AOP_BITXOR;
|
||||||
case JSOP_BITAND:
|
case JSOP_BITAND:
|
||||||
return AOP_BITAND;
|
return AOP_BITAND;
|
||||||
|
case JSOP_COALESCE:
|
||||||
|
return AOP_COALESCE;
|
||||||
|
case JSOP_OR:
|
||||||
|
return AOP_OR;
|
||||||
|
case JSOP_AND:
|
||||||
|
return AOP_AND;
|
||||||
default:
|
default:
|
||||||
return AOP_ERR;
|
return AOP_ERR;
|
||||||
}
|
}
|
||||||
|
|
@ -3103,6 +3114,9 @@ ASTSerializer::expression(ParseNode* pn, MutableHandleValue dst)
|
||||||
case PNK_ASSIGN:
|
case PNK_ASSIGN:
|
||||||
case PNK_ADDASSIGN:
|
case PNK_ADDASSIGN:
|
||||||
case PNK_SUBASSIGN:
|
case PNK_SUBASSIGN:
|
||||||
|
case PNK_COALESCEASSIGN:
|
||||||
|
case PNK_ORASSIGN:
|
||||||
|
case PNK_ANDASSIGN:
|
||||||
case PNK_BITORASSIGN:
|
case PNK_BITORASSIGN:
|
||||||
case PNK_BITXORASSIGN:
|
case PNK_BITXORASSIGN:
|
||||||
case PNK_BITANDASSIGN:
|
case PNK_BITANDASSIGN:
|
||||||
|
|
|
||||||
|
|
@ -517,6 +517,17 @@ BytecodeEmitter::emitPopN(unsigned n)
|
||||||
return emitUint16Operand(JSOP_POPN, n);
|
return emitUint16Operand(JSOP_POPN, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
BytecodeEmitter::emitUnpickN(unsigned n)
|
||||||
|
{
|
||||||
|
MOZ_ASSERT(n != 0);
|
||||||
|
|
||||||
|
if (n == 1)
|
||||||
|
return emit1(JSOP_SWAP);
|
||||||
|
|
||||||
|
return emit2(JSOP_UNPICK, n);
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
BytecodeEmitter::emitCheckIsObj(CheckIsObjectKind kind)
|
BytecodeEmitter::emitCheckIsObj(CheckIsObjectKind kind)
|
||||||
{
|
{
|
||||||
|
|
@ -1221,6 +1232,9 @@ BytecodeEmitter::checkSideEffects(ParseNode* pn, bool* answer)
|
||||||
case PNK_ASSIGN:
|
case PNK_ASSIGN:
|
||||||
case PNK_ADDASSIGN:
|
case PNK_ADDASSIGN:
|
||||||
case PNK_SUBASSIGN:
|
case PNK_SUBASSIGN:
|
||||||
|
case PNK_COALESCEASSIGN:
|
||||||
|
case PNK_ORASSIGN:
|
||||||
|
case PNK_ANDASSIGN:
|
||||||
case PNK_BITORASSIGN:
|
case PNK_BITORASSIGN:
|
||||||
case PNK_BITXORASSIGN:
|
case PNK_BITXORASSIGN:
|
||||||
case PNK_BITANDASSIGN:
|
case PNK_BITANDASSIGN:
|
||||||
|
|
@ -3977,6 +3991,225 @@ BytecodeEmitter::emitAssignmentOrInit(ParseNodeKind kind, JSOp compoundOp,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
BytecodeEmitter::emitShortCircuitAssignment(ParseNodeKind kind, JSOp op,
|
||||||
|
ParseNode* lhs, ParseNode* rhs)
|
||||||
|
{
|
||||||
|
TDZCheckCache tdzCache(this);
|
||||||
|
|
||||||
|
// |name| is used within NameOpEmitter, so its lifetime must surpass |noe|.
|
||||||
|
RootedAtom name(cx);
|
||||||
|
|
||||||
|
// Select the appropriate emitter based on the left-hand side.
|
||||||
|
Maybe<NameOpEmitter> noe;
|
||||||
|
Maybe<PropOpEmitter> poe;
|
||||||
|
Maybe<ElemOpEmitter> eoe;
|
||||||
|
|
||||||
|
int32_t startDepth = stackDepth;
|
||||||
|
|
||||||
|
// Number of values pushed onto the stack in addition to the lhs value.
|
||||||
|
int32_t numPushed;
|
||||||
|
|
||||||
|
// Evaluate the left-hand side expression and compute any stack values needed
|
||||||
|
// for the assignment.
|
||||||
|
switch (lhs->getKind()) {
|
||||||
|
case PNK_NAME: {
|
||||||
|
name = lhs->as<NameNode>().name();
|
||||||
|
noe.emplace(this, name, NameOpEmitter::Kind::CompoundAssignment);
|
||||||
|
|
||||||
|
if (!noe->prepareForRhs()) {
|
||||||
|
// [stack] ENV? LHS
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
numPushed = noe->emittedBindOp();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PNK_DOT: {
|
||||||
|
PropertyAccess* prop = &lhs->as<PropertyAccess>();
|
||||||
|
bool isSuper = prop->isSuper();
|
||||||
|
|
||||||
|
poe.emplace(this, PropOpEmitter::Kind::CompoundAssignment,
|
||||||
|
isSuper ? PropOpEmitter::ObjKind::Super
|
||||||
|
: PropOpEmitter::ObjKind::Other);
|
||||||
|
|
||||||
|
if (!poe->prepareForObj())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (isSuper) {
|
||||||
|
UnaryNode* base = &prop->expression().as<UnaryNode>();
|
||||||
|
if (!emitGetThisForSuperBase(base)) {
|
||||||
|
// [stack] THIS SUPERBASE
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!emitTree(&prop->expression())) {
|
||||||
|
// [stack] OBJ
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!poe->emitGet(prop->key().atom())) {
|
||||||
|
// [stack] # if Super
|
||||||
|
// [stack] THIS SUPERBASE LHS
|
||||||
|
// [stack] # otherwise
|
||||||
|
// [stack] OBJ LHS
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!poe->prepareForRhs()) {
|
||||||
|
// [stack] # if Super
|
||||||
|
// [stack] THIS SUPERBASE LHS
|
||||||
|
// [stack] # otherwise
|
||||||
|
// [stack] OBJ LHS
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
numPushed = 1 + isSuper;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PNK_ELEM: {
|
||||||
|
PropertyByValue* elem = &lhs->as<PropertyByValue>();
|
||||||
|
bool isSuper = elem->isSuper();
|
||||||
|
|
||||||
|
eoe.emplace(this, ElemOpEmitter::Kind::CompoundAssignment,
|
||||||
|
isSuper ? ElemOpEmitter::ObjKind::Super
|
||||||
|
: ElemOpEmitter::ObjKind::Other);
|
||||||
|
|
||||||
|
if (!emitElemObjAndKey(elem, isSuper, *eoe)) {
|
||||||
|
// [stack] # if Super
|
||||||
|
// [stack] THIS KEY
|
||||||
|
// [stack] # otherwise
|
||||||
|
// [stack] OBJ KEY
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!eoe->emitGet()) {
|
||||||
|
// [stack] # if Super
|
||||||
|
// [stack] THIS KEY SUPERBASE LHS
|
||||||
|
// [stack] # otherwise
|
||||||
|
// [stack] OBJ KEY LHS
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!eoe->prepareForRhs()) {
|
||||||
|
// [stack] # if Super
|
||||||
|
// [stack] THIS KEY SUPERBASE LHS
|
||||||
|
// [stack] # otherwise
|
||||||
|
// [stack] OBJ KEY LHS
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
numPushed = 2 + isSuper;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
MOZ_CRASH();
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_ASSERT(stackDepth == startDepth + numPushed + 1);
|
||||||
|
|
||||||
|
// Test for the short-circuit condition.
|
||||||
|
JumpList jump;
|
||||||
|
if (!emitJump(op, &jump)) {
|
||||||
|
// [stack] ... LHS
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The short-circuit condition wasn't fulfilled, pop the left-hand side value
|
||||||
|
// which was kept on the stack.
|
||||||
|
if (!emit1(JSOP_POP)) {
|
||||||
|
// [stack] ...
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Open spec issue about setting inferred function names.
|
||||||
|
// <https://github.com/tc39/proposal-logical-assignment/issues/23>
|
||||||
|
if (!emitTree(rhs)) {
|
||||||
|
// [stack] ... RHS
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform the actual assignment.
|
||||||
|
switch (lhs->getKind()) {
|
||||||
|
case PNK_NAME: {
|
||||||
|
if (!noe->emitAssignment()) {
|
||||||
|
// [stack] RHS
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PNK_DOT: {
|
||||||
|
PropertyAccess* prop = &lhs->as<PropertyAccess>();
|
||||||
|
|
||||||
|
if (!poe->emitAssignment(prop->key().atom())) {
|
||||||
|
// [stack] RHS
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case PNK_ELEM: {
|
||||||
|
if (!eoe->emitAssignment()) {
|
||||||
|
// [stack] RHS
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
MOZ_CRASH();
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_ASSERT(stackDepth == startDepth + 1);
|
||||||
|
|
||||||
|
// Join with the short-circuit jump and pop anything left on the stack.
|
||||||
|
if (numPushed > 0) {
|
||||||
|
JumpList jumpAroundPop;
|
||||||
|
if (!emitJump(JSOP_GOTO, &jumpAroundPop)) {
|
||||||
|
// [stack] RHS
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!emitJumpTargetAndPatch(jump)) {
|
||||||
|
// [stack] ... LHS
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reconstruct the stack depth after the jump.
|
||||||
|
stackDepth = startDepth + 1 + numPushed;
|
||||||
|
|
||||||
|
// Move the left-hand side value to the bottom and pop the rest.
|
||||||
|
if (!emitUnpickN(numPushed)) {
|
||||||
|
// [stack] LHS ...
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!emitPopN(numPushed)) {
|
||||||
|
// [stack] LHS
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!emitJumpTargetAndPatch(jumpAroundPop)) {
|
||||||
|
// [stack] LHS | RHS
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (!emitJumpTargetAndPatch(jump)) {
|
||||||
|
// [stack] LHS | RHS
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MOZ_ASSERT(stackDepth == startDepth + 1);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
ParseNode::getConstantValue(ExclusiveContext* cx, AllowConstantObjects allowObjects,
|
ParseNode::getConstantValue(ExclusiveContext* cx, AllowConstantObjects allowObjects,
|
||||||
MutableHandleValue vp, Value* compare, size_t ncompare,
|
MutableHandleValue vp, Value* compare, size_t ncompare,
|
||||||
|
|
@ -9074,6 +9307,17 @@ BytecodeEmitter::emitTree(ParseNode* pn, ValueUsage valueUsage /* = ValueUsage::
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case PNK_COALESCEASSIGN:
|
||||||
|
case PNK_ORASSIGN:
|
||||||
|
case PNK_ANDASSIGN: {
|
||||||
|
BinaryNode* assignNode = &pn->as<BinaryNode>();
|
||||||
|
if (!emitShortCircuitAssignment(assignNode->getKind(), assignNode->getOp(),
|
||||||
|
assignNode->left(), assignNode->right())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case PNK_CONDITIONAL:
|
case PNK_CONDITIONAL:
|
||||||
if (!emitConditionalExpression(pn->as<ConditionalExpression>(), valueUsage))
|
if (!emitConditionalExpression(pn->as<ConditionalExpression>(), valueUsage))
|
||||||
return false;
|
return false;
|
||||||
|
|
|
||||||
|
|
@ -457,6 +457,9 @@ struct MOZ_STACK_CLASS BytecodeEmitter
|
||||||
// Helper to emit JSOP_POP or JSOP_POPN.
|
// Helper to emit JSOP_POP or JSOP_POPN.
|
||||||
MOZ_MUST_USE bool emitPopN(unsigned n);
|
MOZ_MUST_USE bool emitPopN(unsigned n);
|
||||||
|
|
||||||
|
// Helper to emit JSOP_SWAP or JSOP_UNPICK.
|
||||||
|
MOZ_MUST_USE bool emitUnpickN(unsigned n);
|
||||||
|
|
||||||
// Helper to emit JSOP_CHECKISOBJ.
|
// Helper to emit JSOP_CHECKISOBJ.
|
||||||
MOZ_MUST_USE bool emitCheckIsObj(CheckIsObjectKind kind);
|
MOZ_MUST_USE bool emitCheckIsObj(CheckIsObjectKind kind);
|
||||||
|
|
||||||
|
|
@ -701,6 +704,8 @@ struct MOZ_STACK_CLASS BytecodeEmitter
|
||||||
MOZ_MUST_USE bool emitTemplateString(ListNode* templateString);
|
MOZ_MUST_USE bool emitTemplateString(ListNode* templateString);
|
||||||
MOZ_MUST_USE bool emitAssignmentOrInit(ParseNodeKind kind, JSOp compoundOp,
|
MOZ_MUST_USE bool emitAssignmentOrInit(ParseNodeKind kind, JSOp compoundOp,
|
||||||
ParseNode* lhs, ParseNode* rhs);
|
ParseNode* lhs, ParseNode* rhs);
|
||||||
|
MOZ_MUST_USE bool emitShortCircuitAssignment(ParseNodeKind kind, JSOp op,
|
||||||
|
ParseNode* lhs, ParseNode* rhs);
|
||||||
|
|
||||||
MOZ_MUST_USE bool emitReturn(UnaryNode* returnNode);
|
MOZ_MUST_USE bool emitReturn(UnaryNode* returnNode);
|
||||||
MOZ_MUST_USE bool emitStatement(UnaryNode* exprStmt);
|
MOZ_MUST_USE bool emitStatement(UnaryNode* exprStmt);
|
||||||
|
|
|
||||||
|
|
@ -355,6 +355,9 @@ ContainsHoistedDeclaration(ExclusiveContext* cx, ParseNode* node, bool* result)
|
||||||
case PNK_ASSIGN:
|
case PNK_ASSIGN:
|
||||||
case PNK_ADDASSIGN:
|
case PNK_ADDASSIGN:
|
||||||
case PNK_SUBASSIGN:
|
case PNK_SUBASSIGN:
|
||||||
|
case PNK_COALESCEASSIGN:
|
||||||
|
case PNK_ORASSIGN:
|
||||||
|
case PNK_ANDASSIGN:
|
||||||
case PNK_BITORASSIGN:
|
case PNK_BITORASSIGN:
|
||||||
case PNK_BITXORASSIGN:
|
case PNK_BITXORASSIGN:
|
||||||
case PNK_BITANDASSIGN:
|
case PNK_BITANDASSIGN:
|
||||||
|
|
@ -1884,6 +1887,9 @@ Fold(ExclusiveContext* cx, ParseNode** pnp, Parser<FullParseHandler>& parser, bo
|
||||||
case PNK_ASSIGN:
|
case PNK_ASSIGN:
|
||||||
case PNK_ADDASSIGN:
|
case PNK_ADDASSIGN:
|
||||||
case PNK_SUBASSIGN:
|
case PNK_SUBASSIGN:
|
||||||
|
case PNK_COALESCEASSIGN:
|
||||||
|
case PNK_ORASSIGN:
|
||||||
|
case PNK_ANDASSIGN:
|
||||||
case PNK_BITORASSIGN:
|
case PNK_BITORASSIGN:
|
||||||
case PNK_BITANDASSIGN:
|
case PNK_BITANDASSIGN:
|
||||||
case PNK_BITXORASSIGN:
|
case PNK_BITXORASSIGN:
|
||||||
|
|
|
||||||
|
|
@ -262,6 +262,9 @@ PushNodeChildren(ParseNode* pn, NodeStack* stack)
|
||||||
case PNK_ASSIGN:
|
case PNK_ASSIGN:
|
||||||
case PNK_ADDASSIGN:
|
case PNK_ADDASSIGN:
|
||||||
case PNK_SUBASSIGN:
|
case PNK_SUBASSIGN:
|
||||||
|
case PNK_COALESCEASSIGN:
|
||||||
|
case PNK_ORASSIGN:
|
||||||
|
case PNK_ANDASSIGN:
|
||||||
case PNK_BITORASSIGN:
|
case PNK_BITORASSIGN:
|
||||||
case PNK_BITXORASSIGN:
|
case PNK_BITXORASSIGN:
|
||||||
case PNK_BITANDASSIGN:
|
case PNK_BITANDASSIGN:
|
||||||
|
|
|
||||||
|
|
@ -176,6 +176,9 @@ class ObjectBox;
|
||||||
F(ASSIGN) \
|
F(ASSIGN) \
|
||||||
F(ADDASSIGN) \
|
F(ADDASSIGN) \
|
||||||
F(SUBASSIGN) \
|
F(SUBASSIGN) \
|
||||||
|
F(COALESCEASSIGN) \
|
||||||
|
F(ORASSIGN) \
|
||||||
|
F(ANDASSIGN) \
|
||||||
F(BITORASSIGN) \
|
F(BITORASSIGN) \
|
||||||
F(BITXORASSIGN) \
|
F(BITXORASSIGN) \
|
||||||
F(BITANDASSIGN) \
|
F(BITANDASSIGN) \
|
||||||
|
|
@ -395,8 +398,10 @@ IsTypeofKind(ParseNodeKind kind)
|
||||||
* PNK_ASSIGN (AssignmentNode)
|
* PNK_ASSIGN (AssignmentNode)
|
||||||
* left: target of assignment
|
* left: target of assignment
|
||||||
* right: value to assign
|
* right: value to assign
|
||||||
* PNK_ADDASSIGN, PNK_SUBASSIGN, PNK_BITORASSIGN, PNK_BITXORASSIGN,
|
* PNK_ADDASSIGN, PNK_SUBASSIGN,
|
||||||
* PNK_BITANDASSIGN, PNK_LSHASSIGN, PNK_RSHASSIGN, PNK_URSHASSIGN,
|
* PNK_COALESCEASSIGN, PNK_ORASSIGN, PNK_ANDASSIGN,
|
||||||
|
* PNK_BITORASSIGN, PNK_BITXORASSIGN, PNK_BITANDASSIGN,
|
||||||
|
* PNK_LSHASSIGN, PNK_RSHASSIGN, PNK_URSHASSIGN,
|
||||||
* PNK_MULASSIGN, PNK_DIVASSIGN, PNK_MODASSIGN, PNK_POWASSIGN (AssignmentNode)
|
* PNK_MULASSIGN, PNK_DIVASSIGN, PNK_MODASSIGN, PNK_POWASSIGN (AssignmentNode)
|
||||||
* left: target of assignment
|
* left: target of assignment
|
||||||
* right: value to assign
|
* right: value to assign
|
||||||
|
|
|
||||||
|
|
@ -9150,6 +9150,9 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
|
||||||
case TOK_ASSIGN: kind = PNK_ASSIGN; op = JSOP_NOP; break;
|
case TOK_ASSIGN: kind = PNK_ASSIGN; op = JSOP_NOP; break;
|
||||||
case TOK_ADDASSIGN: kind = PNK_ADDASSIGN; op = JSOP_ADD; break;
|
case TOK_ADDASSIGN: kind = PNK_ADDASSIGN; op = JSOP_ADD; break;
|
||||||
case TOK_SUBASSIGN: kind = PNK_SUBASSIGN; op = JSOP_SUB; break;
|
case TOK_SUBASSIGN: kind = PNK_SUBASSIGN; op = JSOP_SUB; break;
|
||||||
|
case TOK_COALESCEASSIGN: kind = PNK_COALESCEASSIGN; op = JSOP_COALESCE; break;
|
||||||
|
case TOK_ORASSIGN: kind = PNK_ORASSIGN; op = JSOP_OR; break;
|
||||||
|
case TOK_ANDASSIGN: kind = PNK_ANDASSIGN; op = JSOP_AND; break;
|
||||||
case TOK_BITORASSIGN: kind = PNK_BITORASSIGN; op = JSOP_BITOR; break;
|
case TOK_BITORASSIGN: kind = PNK_BITORASSIGN; op = JSOP_BITOR; break;
|
||||||
case TOK_BITXORASSIGN: kind = PNK_BITXORASSIGN; op = JSOP_BITXOR; break;
|
case TOK_BITXORASSIGN: kind = PNK_BITXORASSIGN; op = JSOP_BITXOR; break;
|
||||||
case TOK_BITANDASSIGN: kind = PNK_BITANDASSIGN; op = JSOP_BITAND; break;
|
case TOK_BITANDASSIGN: kind = PNK_BITANDASSIGN; op = JSOP_BITAND; break;
|
||||||
|
|
@ -9279,6 +9282,17 @@ Parser<ParseHandler>::assignExpr(InHandling inHandling, YieldHandling yieldHandl
|
||||||
} else if (handler.isPropertyAccess(lhs)) {
|
} else if (handler.isPropertyAccess(lhs)) {
|
||||||
// Permitted: no additional testing/fixup needed.
|
// Permitted: no additional testing/fixup needed.
|
||||||
} else if (handler.isFunctionCall(lhs)) {
|
} else if (handler.isFunctionCall(lhs)) {
|
||||||
|
// We don't have to worry about backward compatibility issues with the new
|
||||||
|
// compound assignment operators, so we always throw here. Also that way we
|
||||||
|
// don't have to worry if |f() &&= expr| should always throw an error or
|
||||||
|
// only if |f()| returns true.
|
||||||
|
if (kind == PNK_COALESCEASSIGN ||
|
||||||
|
kind == PNK_ORASSIGN ||
|
||||||
|
kind == PNK_ADDASSIGN) {
|
||||||
|
errorAt(exprPos.begin, JSMSG_BAD_LEFTSIDE_OF_ASS);
|
||||||
|
return null();
|
||||||
|
}
|
||||||
|
|
||||||
if (!strictModeErrorAt(exprPos.begin, JSMSG_BAD_LEFTSIDE_OF_ASS))
|
if (!strictModeErrorAt(exprPos.begin, JSMSG_BAD_LEFTSIDE_OF_ASS))
|
||||||
return null();
|
return null();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -219,6 +219,9 @@
|
||||||
range(ASSIGNMENT_START, ASSIGN) \
|
range(ASSIGNMENT_START, ASSIGN) \
|
||||||
macro(ADDASSIGN, "'+='") \
|
macro(ADDASSIGN, "'+='") \
|
||||||
macro(SUBASSIGN, "'-='") \
|
macro(SUBASSIGN, "'-='") \
|
||||||
|
macro(COALESCEASSIGN, "'\?\?='") /* avoid trigraphs warning */ \
|
||||||
|
macro(ORASSIGN, "'||='") \
|
||||||
|
macro(ANDASSIGN, "'&&='") \
|
||||||
macro(BITORASSIGN, "'|='") \
|
macro(BITORASSIGN, "'|='") \
|
||||||
macro(BITXORASSIGN, "'^='") \
|
macro(BITXORASSIGN, "'^='") \
|
||||||
macro(BITANDASSIGN, "'&='") \
|
macro(BITANDASSIGN, "'&='") \
|
||||||
|
|
|
||||||
|
|
@ -1876,7 +1876,7 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier)
|
||||||
|
|
||||||
case '|':
|
case '|':
|
||||||
if (matchChar('|'))
|
if (matchChar('|'))
|
||||||
tp->type = TOK_OR;
|
tp->type = matchChar('=') ? TOK_ORASSIGN : TOK_OR;
|
||||||
else
|
else
|
||||||
tp->type = matchChar('=') ? TOK_BITORASSIGN : TOK_BITOR;
|
tp->type = matchChar('=') ? TOK_BITORASSIGN : TOK_BITOR;
|
||||||
goto out;
|
goto out;
|
||||||
|
|
@ -1887,7 +1887,7 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier)
|
||||||
|
|
||||||
case '&':
|
case '&':
|
||||||
if (matchChar('&'))
|
if (matchChar('&'))
|
||||||
tp->type = TOK_AND;
|
tp->type = matchChar('=') ? TOK_ANDASSIGN : TOK_AND;
|
||||||
else
|
else
|
||||||
tp->type = matchChar('=') ? TOK_BITANDASSIGN : TOK_BITAND;
|
tp->type = matchChar('=') ? TOK_BITANDASSIGN : TOK_BITAND;
|
||||||
goto out;
|
goto out;
|
||||||
|
|
@ -1906,8 +1906,10 @@ TokenStream::getTokenInternal(TokenKind* ttp, Modifier modifier)
|
||||||
ungetCharIgnoreEOL(c);
|
ungetCharIgnoreEOL(c);
|
||||||
tp->type = TOK_OPTCHAIN;
|
tp->type = TOK_OPTCHAIN;
|
||||||
}
|
}
|
||||||
} else {
|
} else if (matchChar('?')) {
|
||||||
tp->type = matchChar('?') ? TOK_COALESCE : TOK_HOOK;
|
tp->type = matchChar('=') ? TOK_COALESCEASSIGN : TOK_COALESCE;
|
||||||
|
} else {
|
||||||
|
tp->type = TOK_HOOK;
|
||||||
}
|
}
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue