mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 710932 - Create ?: conditional expressions using a constructor that doesn't examine the token stream. r=jorendorff
--HG-- extra : rebase_source : cf8d22e47436d543a46115171460a4bfeae10971
This commit is contained in:
parent
4ac1f980e9
commit
d87cdbf3d5
@ -6772,16 +6772,16 @@ EmitSyntheticStatements(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn, ptrd
|
||||
}
|
||||
|
||||
static bool
|
||||
EmitConditionalExpression(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
||||
EmitConditionalExpression(JSContext *cx, BytecodeEmitter *bce, ConditionalExpression &conditional)
|
||||
{
|
||||
/* Emit the condition, then branch if false to the else part. */
|
||||
if (!EmitTree(cx, bce, pn->pn_kid1))
|
||||
if (!EmitTree(cx, bce, &conditional.condition()))
|
||||
return false;
|
||||
ptrdiff_t noteIndex = NewSrcNote(cx, bce, SRC_COND);
|
||||
if (noteIndex < 0)
|
||||
return false;
|
||||
ptrdiff_t beq = EmitJump(cx, bce, JSOP_IFEQ, 0);
|
||||
if (beq < 0 || !EmitTree(cx, bce, pn->pn_kid2))
|
||||
if (beq < 0 || !EmitTree(cx, bce, &conditional.thenExpression()))
|
||||
return false;
|
||||
|
||||
/* Jump around else, fixup the branch, emit else, fixup jump. */
|
||||
@ -6802,7 +6802,7 @@ EmitConditionalExpression(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
||||
*/
|
||||
JS_ASSERT(bce->stackDepth > 0);
|
||||
bce->stackDepth--;
|
||||
if (!EmitTree(cx, bce, pn->pn_kid3))
|
||||
if (!EmitTree(cx, bce, &conditional.elseExpression()))
|
||||
return false;
|
||||
CHECK_AND_SET_JUMP_OFFSET_AT(cx, bce, jmp);
|
||||
return SetSrcNoteOffset(cx, bce, noteIndex, 0, jmp - beq);
|
||||
@ -7227,8 +7227,8 @@ frontend::EmitTree(JSContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
||||
return false;
|
||||
break;
|
||||
|
||||
case PNK_HOOK:
|
||||
ok = EmitConditionalExpression(cx, bce, pn);
|
||||
case PNK_CONDITIONAL:
|
||||
ok = EmitConditionalExpression(cx, bce, pn->asConditionalExpression());
|
||||
break;
|
||||
|
||||
case PNK_OR:
|
||||
|
@ -558,7 +558,7 @@ js::FoldConstants(JSContext *cx, ParseNode *pn, TreeContext *tc, bool inCond)
|
||||
break;
|
||||
/* FALL THROUGH */
|
||||
|
||||
case PNK_HOOK:
|
||||
case PNK_CONDITIONAL:
|
||||
/* Reduce 'if (C) T; else E' into T for true C, E for false. */
|
||||
switch (pn1->getKind()) {
|
||||
case PNK_NUMBER:
|
||||
@ -593,8 +593,8 @@ js::FoldConstants(JSContext *cx, ParseNode *pn, TreeContext *tc, bool inCond)
|
||||
* False condition and no else, or an empty then-statement was
|
||||
* moved up over pn. Either way, make pn an empty block (not an
|
||||
* empty statement, which does not decompile, even when labeled).
|
||||
* NB: pn must be a PNK_IF as PNK_HOOK can never have a null kid
|
||||
* or an empty statement for a child.
|
||||
* NB: pn must be a PNK_IF as PNK_CONDITIONAL can never have a null
|
||||
* kid or an empty statement for a child.
|
||||
*/
|
||||
pn->setKind(PNK_STATEMENTLIST);
|
||||
pn->setArity(PN_LIST);
|
||||
|
@ -41,6 +41,8 @@
|
||||
#ifndef ParseNode_h__
|
||||
#define ParseNode_h__
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
#include "jsscript.h"
|
||||
|
||||
#include "frontend/ParseMaps.h"
|
||||
@ -61,7 +63,7 @@ namespace js {
|
||||
enum ParseNodeKind {
|
||||
PNK_SEMI,
|
||||
PNK_COMMA,
|
||||
PNK_HOOK,
|
||||
PNK_CONDITIONAL,
|
||||
PNK_COLON,
|
||||
PNK_OR,
|
||||
PNK_AND,
|
||||
@ -313,7 +315,8 @@ enum ParseNodeKind {
|
||||
* PNK_MULASSIGN,
|
||||
* PNK_DIVASSIGN,
|
||||
* PNK_MODASSIGN
|
||||
* PNK_HOOK ternary pn_kid1: cond, pn_kid2: then, pn_kid3: else
|
||||
* PNK_CONDITIONAL ternary (cond ? trueExpr : falseExpr)
|
||||
* pn_kid1: cond, pn_kid2: then, pn_kid3: else
|
||||
* PNK_OR binary pn_left: first in || chain, pn_right: rest of chain
|
||||
* PNK_AND binary pn_left: first in && chain, pn_right: rest of chain
|
||||
* PNK_BITOR binary pn_left: left-assoc | expr, pn_right: ^ expr
|
||||
@ -486,6 +489,7 @@ class LoopControlStatement;
|
||||
class BreakStatement;
|
||||
class ContinueStatement;
|
||||
class XMLProcessingInstruction;
|
||||
class ConditionalExpression;
|
||||
|
||||
struct ParseNode {
|
||||
private:
|
||||
@ -496,6 +500,8 @@ struct ParseNode {
|
||||
pn_used : 1, /* name node is on a use-chain */
|
||||
pn_defn : 1; /* this node is a Definition */
|
||||
|
||||
void operator=(const ParseNode &other) MOZ_DELETE;
|
||||
|
||||
public:
|
||||
ParseNode(ParseNodeKind kind, JSOp op, ParseNodeArity arity)
|
||||
: pn_type(kind), pn_op(op), pn_arity(arity), pn_parens(0), pn_used(0), pn_defn(0),
|
||||
@ -927,6 +933,7 @@ struct ParseNode {
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
inline XMLProcessingInstruction &asXMLProcessingInstruction();
|
||||
#endif
|
||||
inline ConditionalExpression &asConditionalExpression();
|
||||
};
|
||||
|
||||
struct NullaryNode : public ParseNode {
|
||||
@ -1098,6 +1105,42 @@ ParseNode::asXMLProcessingInstruction()
|
||||
}
|
||||
#endif
|
||||
|
||||
class ConditionalExpression : public ParseNode {
|
||||
public:
|
||||
ConditionalExpression(ParseNode *condition, ParseNode *thenExpr, ParseNode *elseExpr)
|
||||
: ParseNode(PNK_CONDITIONAL, JSOP_NOP, PN_TERNARY,
|
||||
TokenPos::make(condition->pn_pos.begin, elseExpr->pn_pos.end))
|
||||
{
|
||||
JS_ASSERT(condition);
|
||||
JS_ASSERT(thenExpr);
|
||||
JS_ASSERT(elseExpr);
|
||||
pn_u.ternary.kid1 = condition;
|
||||
pn_u.ternary.kid2 = thenExpr;
|
||||
pn_u.ternary.kid3 = elseExpr;
|
||||
}
|
||||
|
||||
ParseNode &condition() const {
|
||||
return *pn_u.ternary.kid1;
|
||||
}
|
||||
|
||||
ParseNode &thenExpression() const {
|
||||
return *pn_u.ternary.kid2;
|
||||
}
|
||||
|
||||
ParseNode &elseExpression() const {
|
||||
return *pn_u.ternary.kid3;
|
||||
}
|
||||
};
|
||||
|
||||
inline ConditionalExpression &
|
||||
ParseNode::asConditionalExpression()
|
||||
{
|
||||
JS_ASSERT(isKind(PNK_CONDITIONAL));
|
||||
JS_ASSERT(isOp(JSOP_NOP));
|
||||
JS_ASSERT(pn_arity == PN_TERNARY);
|
||||
return *static_cast<ConditionalExpression *>(this);
|
||||
}
|
||||
|
||||
ParseNode *
|
||||
CloneLeftHandSide(ParseNode *opn, TreeContext *tc);
|
||||
|
||||
|
@ -4643,37 +4643,30 @@ Parser::orExpr1()
|
||||
JS_ALWAYS_INLINE ParseNode *
|
||||
Parser::condExpr1()
|
||||
{
|
||||
ParseNode *pn = orExpr1();
|
||||
if (pn && tokenStream.isCurrentTokenType(TOK_HOOK)) {
|
||||
ParseNode *pn1 = pn;
|
||||
pn = TernaryNode::create(PNK_HOOK, tc);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
ParseNode *condition = orExpr1();
|
||||
if (!condition || !tokenStream.isCurrentTokenType(TOK_HOOK))
|
||||
return condition;
|
||||
|
||||
/*
|
||||
* Always accept the 'in' operator in the middle clause of a ternary,
|
||||
* where it's unambiguous, even if we might be parsing the init of a
|
||||
* for statement.
|
||||
*/
|
||||
uintN oldflags = tc->flags;
|
||||
tc->flags &= ~TCF_IN_FOR_INIT;
|
||||
ParseNode *pn2 = assignExpr();
|
||||
tc->flags = oldflags | (tc->flags & TCF_FUN_FLAGS);
|
||||
/*
|
||||
* Always accept the 'in' operator in the middle clause of a ternary,
|
||||
* where it's unambiguous, even if we might be parsing the init of a
|
||||
* for statement.
|
||||
*/
|
||||
uintN oldflags = tc->flags;
|
||||
tc->flags &= ~TCF_IN_FOR_INIT;
|
||||
ParseNode *thenExpr = assignExpr();
|
||||
tc->flags = oldflags | (tc->flags & TCF_FUN_FLAGS);
|
||||
if (!thenExpr)
|
||||
return NULL;
|
||||
|
||||
if (!pn2)
|
||||
return NULL;
|
||||
MUST_MATCH_TOKEN(TOK_COLON, JSMSG_COLON_IN_COND);
|
||||
ParseNode *pn3 = assignExpr();
|
||||
if (!pn3)
|
||||
return NULL;
|
||||
pn->pn_pos.begin = pn1->pn_pos.begin;
|
||||
pn->pn_pos.end = pn3->pn_pos.end;
|
||||
pn->pn_kid1 = pn1;
|
||||
pn->pn_kid2 = pn2;
|
||||
pn->pn_kid3 = pn3;
|
||||
tokenStream.getToken(); /* need to read one token past the end */
|
||||
}
|
||||
return pn;
|
||||
MUST_MATCH_TOKEN(TOK_COLON, JSMSG_COLON_IN_COND);
|
||||
|
||||
ParseNode *elseExpr = assignExpr();
|
||||
if (!elseExpr)
|
||||
return NULL;
|
||||
|
||||
tokenStream.getToken(); /* read one token past the end */
|
||||
return new_<ConditionalExpression>(condition, thenExpr, elseExpr);
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -2402,7 +2402,7 @@ ASTSerializer::expression(ParseNode *pn, Value *dst)
|
||||
builder.sequenceExpression(exprs, &pn->pn_pos, dst);
|
||||
}
|
||||
|
||||
case PNK_HOOK:
|
||||
case PNK_CONDITIONAL:
|
||||
{
|
||||
Value test, cons, alt;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user