зеркало из https://github.com/mozilla/pjs.git
Fix let expressions in bracketed forms within for loop head (349605, r=mrbkap).
This commit is contained in:
Родитель
33e28721fe
Коммит
f13a7d3693
|
@ -1386,7 +1386,6 @@ EmitNonLocalJumpFixup(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *toStmt,
|
|||
default:;
|
||||
}
|
||||
|
||||
#if JS_HAS_BLOCK_SCOPE
|
||||
if (stmt->flags & SIF_SCOPE) {
|
||||
uintN i;
|
||||
|
||||
|
@ -1396,7 +1395,6 @@ EmitNonLocalJumpFixup(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *toStmt,
|
|||
i = OBJ_BLOCK_COUNT(cx, ATOM_TO_OBJECT(stmt->atom));
|
||||
EMIT_UINT16_IMM_OP(JSOP_LEAVEBLOCK, i);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
cg->stackDepth = depth;
|
||||
|
@ -3395,6 +3393,7 @@ EmitVariables(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
|
|||
JSTreeContext *tc;
|
||||
JSStmtInfo *stmt, *scopeStmt;
|
||||
JSObject *blockObj;
|
||||
uintN oldflags;
|
||||
#ifdef DEBUG
|
||||
JSBool varOrConst = (pn->pn_op != JSOP_NOP);
|
||||
#endif
|
||||
|
@ -3515,8 +3514,11 @@ EmitVariables(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
|
|||
}
|
||||
#endif
|
||||
|
||||
oldflags = cg->treeContext.flags;
|
||||
cg->treeContext.flags &= ~TCF_IN_FOR_INIT;
|
||||
if (!js_EmitTree(cx, cg, pn3))
|
||||
return JS_FALSE;
|
||||
cg->treeContext.flags = oldflags;
|
||||
|
||||
if (popScope) {
|
||||
tc->topStmt = stmt;
|
||||
|
@ -5185,6 +5187,8 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
}
|
||||
} else {
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
uintN oldflags;
|
||||
|
||||
case TOK_DBLCOLON:
|
||||
if (pn->pn_arity == PN_NAME) {
|
||||
if (!js_EmitTree(cx, cg, pn->pn_expr))
|
||||
|
@ -5193,12 +5197,24 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
return JS_FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Binary :: has a right operand that brackets arbitrary code,
|
||||
* possibly including a let (a = b) ... expression. We must clear
|
||||
* TCF_IN_FOR_INIT to avoid mis-compiling such beasts.
|
||||
*/
|
||||
oldflags = cg->treeContext.flags;
|
||||
cg->treeContext.flags &= ~TCF_IN_FOR_INIT;
|
||||
#endif
|
||||
|
||||
/* Binary operators that evaluate both operands unconditionally. */
|
||||
if (!js_EmitTree(cx, cg, pn->pn_left))
|
||||
return JS_FALSE;
|
||||
if (!js_EmitTree(cx, cg, pn->pn_right))
|
||||
return JS_FALSE;
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
cg->treeContext.flags = oldflags;
|
||||
#endif
|
||||
if (js_Emit1(cx, cg, pn->pn_op) < 0)
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
@ -5212,6 +5228,9 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
/* FALL THROUGH */
|
||||
#endif
|
||||
case TOK_UNARYOP:
|
||||
{
|
||||
uintN oldflags;
|
||||
|
||||
/* Unary op, including unary +/-. */
|
||||
pn2 = pn->pn_kid;
|
||||
op = pn->pn_op;
|
||||
|
@ -5221,8 +5240,11 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
if (pn3->pn_type != TOK_NAME)
|
||||
op = JSOP_TYPEOFEXPR;
|
||||
}
|
||||
oldflags = cg->treeContext.flags;
|
||||
cg->treeContext.flags &= ~TCF_IN_FOR_INIT;
|
||||
if (!js_EmitTree(cx, cg, pn2))
|
||||
return JS_FALSE;
|
||||
cg->treeContext.flags = oldflags;
|
||||
#if JS_HAS_XML_SUPPORT
|
||||
if (op == JSOP_XMLNAME &&
|
||||
js_NewSrcNote2(cx, cg, SRC_PCBASE,
|
||||
|
@ -5233,6 +5255,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
if (js_Emit1(cx, cg, op) < 0)
|
||||
return JS_FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
case TOK_INC:
|
||||
case TOK_DEC:
|
||||
|
@ -5447,7 +5470,6 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
return JS_FALSE;
|
||||
break;
|
||||
|
||||
#if JS_HAS_BLOCK_SCOPE
|
||||
case TOK_LEXICALSCOPE:
|
||||
{
|
||||
JSObject *obj;
|
||||
|
@ -5479,6 +5501,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
break;
|
||||
}
|
||||
|
||||
#if JS_HAS_BLOCK_SCOPE
|
||||
case TOK_LET:
|
||||
{
|
||||
JSBool popScope;
|
||||
|
@ -5681,16 +5704,23 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
#endif /* JS_HAS_SHARP_VARS */
|
||||
|
||||
case TOK_RP:
|
||||
{
|
||||
uintN oldflags;
|
||||
|
||||
/*
|
||||
* The node for (e) has e as its kid, enabling users who want to nest
|
||||
* assignment expressions in conditions to avoid the error correction
|
||||
* done by Condition (from x = y to x == y) by double-parenthesizing.
|
||||
*/
|
||||
oldflags = cg->treeContext.flags;
|
||||
cg->treeContext.flags &= ~TCF_IN_FOR_INIT;
|
||||
if (!js_EmitTree(cx, cg, pn->pn_kid))
|
||||
return JS_FALSE;
|
||||
cg->treeContext.flags = oldflags;
|
||||
if (js_Emit1(cx, cg, JSOP_GROUP) < 0)
|
||||
return JS_FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
case TOK_NAME:
|
||||
if (!BindNameToSlot(cx, &cg->treeContext, pn))
|
||||
|
|
|
@ -2609,9 +2609,7 @@ interrupt:
|
|||
|
||||
BEGIN_CASE(JSOP_FORARG)
|
||||
BEGIN_CASE(JSOP_FORVAR)
|
||||
#if JS_HAS_BLOCK_SCOPE
|
||||
BEGIN_CASE(JSOP_FORLOCAL)
|
||||
#endif
|
||||
/*
|
||||
* JSOP_FORARG and JSOP_FORVAR don't require any lval computation
|
||||
* here, because they address slots on the stack (in fp->args and
|
||||
|
@ -2853,7 +2851,6 @@ interrupt:
|
|||
fp->vars[slot] = rval;
|
||||
break;
|
||||
|
||||
#if JS_HAS_BLOCK_SCOPE
|
||||
case JSOP_FORLOCAL:
|
||||
slot = GET_UINT16(pc);
|
||||
JS_ASSERT(slot < (uintN)depth);
|
||||
|
@ -2861,7 +2858,6 @@ interrupt:
|
|||
GC_POKE(cx, *vp);
|
||||
*vp = rval;
|
||||
break;
|
||||
#endif
|
||||
|
||||
case JSOP_FORELEM:
|
||||
/* FORELEM is not a SET operation, it's more like BINDNAME. */
|
||||
|
@ -4264,9 +4260,7 @@ interrupt:
|
|||
case JSOP_XMLOBJECT: goto do_JSOP_XMLOBJECT;
|
||||
case JSOP_XMLPI: goto do_JSOP_XMLPI;
|
||||
#endif
|
||||
#if JS_HAS_BLOCK_SCOPE
|
||||
case JSOP_ENTERBLOCK: goto do_JSOP_ENTERBLOCK;
|
||||
#endif
|
||||
default: JS_ASSERT(0);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
|
@ -5887,7 +5881,6 @@ interrupt:
|
|||
END_CASE(JSOP_GETFUNNS)
|
||||
#endif /* JS_HAS_XML_SUPPORT */
|
||||
|
||||
#if JS_HAS_BLOCK_SCOPE
|
||||
BEGIN_LITOPX_CASE(JSOP_ENTERBLOCK, 0)
|
||||
obj = ATOM_TO_OBJECT(atom);
|
||||
JS_ASSERT(fp->spbase + OBJ_BLOCK_DEPTH(cx, obj) == sp);
|
||||
|
@ -6015,8 +6008,6 @@ interrupt:
|
|||
|
||||
#undef FAST_LOCAL_INCREMENT_OP
|
||||
|
||||
#endif /* JS_HAS_BLOCK_SCOPE */
|
||||
|
||||
#if JS_HAS_GENERATORS
|
||||
BEGIN_CASE(JSOP_STARTITER)
|
||||
/*
|
||||
|
@ -6102,19 +6093,6 @@ interrupt:
|
|||
END_CASE(JSOP_ARRAYPUSH)
|
||||
#endif /* JS_HAS_GENERATORS */
|
||||
|
||||
#if !JS_HAS_BLOCK_SCOPE
|
||||
L_JSOP_ENTERBLOCK:
|
||||
L_JSOP_LEAVEBLOCK:
|
||||
L_JSOP_LEAVEBLOCKEXPR:
|
||||
L_JSOP_GETLOCAL:
|
||||
L_JSOP_SETLOCAL:
|
||||
L_JSOP_INCLOCAL:
|
||||
L_JSOP_DECLOCAL:
|
||||
L_JSOP_LOCALINC:
|
||||
L_JSOP_LOCALDEC:
|
||||
L_JSOP_FORLOCAL:
|
||||
#endif
|
||||
|
||||
#if !JS_HAS_GENERATORS
|
||||
L_JSOP_STARTITER:
|
||||
L_JSOP_ENDITER:
|
||||
|
|
|
@ -216,9 +216,7 @@ js_Disassemble1(JSContext *cx, JSScript *script, jsbytecode *pc, uintN loc,
|
|||
break;
|
||||
|
||||
case JOF_UINT16:
|
||||
#if JS_HAS_BLOCK_SCOPE
|
||||
case JOF_LOCAL:
|
||||
#endif
|
||||
fprintf(fp, " %u", GET_UINT16(pc));
|
||||
break;
|
||||
|
||||
|
@ -1403,8 +1401,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
|
|||
js_printf(jp, "\t}\n");
|
||||
break;
|
||||
|
||||
#if JS_HAS_BLOCK_SCOPE
|
||||
case JSOP_ENTERBLOCK:
|
||||
BEGIN_LITOPX_CASE(JSOP_ENTERBLOCK)
|
||||
{
|
||||
JSAtom **atomv, *smallv[5];
|
||||
JSScopeProperty *sprop;
|
||||
|
@ -1483,8 +1480,8 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
|
|||
JS_free(cx, atomv);
|
||||
if (!ok)
|
||||
return JS_FALSE;
|
||||
break;
|
||||
}
|
||||
END_LITOPX_CASE
|
||||
|
||||
case JSOP_LEAVEBLOCK:
|
||||
case JSOP_LEAVEBLOCKEXPR:
|
||||
|
@ -1585,7 +1582,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
|
|||
lval = OFF2STR(&ss->sprinter, ss->offsets[i]);
|
||||
atom = NULL;
|
||||
goto do_forlvalinloop;
|
||||
#endif
|
||||
|
||||
case JSOP_SETRVAL:
|
||||
op = JSOP_RETURN;
|
||||
|
@ -2431,6 +2427,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb)
|
|||
case JSOP_XMLOBJECT: goto do_JSOP_XMLOBJECT;
|
||||
case JSOP_XMLPI: goto do_JSOP_XMLPI;
|
||||
#endif
|
||||
case JSOP_ENTERBLOCK: goto do_JSOP_ENTERBLOCK;
|
||||
default: JS_ASSERT(0);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
|
|
|
@ -1610,8 +1610,6 @@ ImportExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
}
|
||||
#endif /* JS_HAS_EXPORT_IMPORT */
|
||||
|
||||
#if JS_HAS_BLOCK_SCOPE
|
||||
|
||||
static JSBool
|
||||
BindLet(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc)
|
||||
{
|
||||
|
@ -1663,8 +1661,6 @@ BindLet(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc)
|
|||
NULL);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static JSBool
|
||||
BindVarOrConst(JSContext *cx, BindData *data, JSAtom *atom, JSTreeContext *tc)
|
||||
{
|
||||
|
@ -2302,8 +2298,6 @@ ReturnOrYield(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
|||
return pn;
|
||||
}
|
||||
|
||||
#if JS_HAS_BLOCK_SCOPE
|
||||
|
||||
static JSStmtInfo *
|
||||
FindMaybeScopeStatement(JSTreeContext *tc)
|
||||
{
|
||||
|
@ -2346,6 +2340,8 @@ PushLexicalScope(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
|||
return pn;
|
||||
}
|
||||
|
||||
#if JS_HAS_BLOCK_SCOPE
|
||||
|
||||
static JSParseNode *
|
||||
LetBlock(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, JSBool statement)
|
||||
{
|
||||
|
@ -2361,7 +2357,7 @@ LetBlock(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, JSBool statement)
|
|||
|
||||
MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_LET);
|
||||
|
||||
/* This is a let block of the form: let (a, b, c) { ... }. */
|
||||
/* This is a let block or expression of the form: let (a, b, c) .... */
|
||||
pnblock = PushLexicalScope(cx, ts, tc, &stmtInfo);
|
||||
if (!pnblock)
|
||||
return NULL;
|
||||
|
@ -2376,20 +2372,17 @@ LetBlock(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, JSBool statement)
|
|||
MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_LET);
|
||||
|
||||
if (statement && !js_MatchToken(cx, ts, TOK_LC)) {
|
||||
JSParseNode *pn1;
|
||||
|
||||
/*
|
||||
* If this is really an expression in let statement guise, then we
|
||||
* need to wrap the TOK_LET node in a TOK_SEMI node so that we pop
|
||||
* the return value of the expression.
|
||||
*/
|
||||
pn1 = NewParseNode(cx, ts, PN_UNARY, tc);
|
||||
if (!pn1)
|
||||
pn = NewParseNode(cx, ts, PN_UNARY, tc);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
pn1->pn_type = TOK_SEMI;
|
||||
pn1->pn_num = -1;
|
||||
pn1->pn_kid = pn;
|
||||
pn = pn1;
|
||||
pn->pn_type = TOK_SEMI;
|
||||
pn->pn_num = -1;
|
||||
pn->pn_kid = pnblock;
|
||||
|
||||
statement = JS_FALSE;
|
||||
}
|
||||
|
@ -2978,7 +2971,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
*/
|
||||
data.pn = NULL;
|
||||
data.ts = ts;
|
||||
data.obj = ATOM_TO_OBJECT(pnblock->pn_atom);
|
||||
data.obj = tc->blockChain;
|
||||
data.op = JSOP_NOP;
|
||||
data.binder = BindLet;
|
||||
data.u.let.index = 0;
|
||||
|
@ -3230,7 +3223,9 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
pn = LetBlock(cx, ts, tc, JS_TRUE);
|
||||
if (!pn || pn->pn_op == JSOP_LEAVEBLOCK)
|
||||
return pn;
|
||||
|
||||
/* Let expressions require automatic semicolon insertion. */
|
||||
JS_ASSERT(pn->pn_op == JSOP_LEAVEBLOCKEXPR);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -3244,8 +3239,8 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
*/
|
||||
stmt = FindMaybeScopeStatement(tc);
|
||||
if (stmt && (stmt->flags & SIF_SCOPE)) {
|
||||
JS_ASSERT(stmt->atom);
|
||||
obj = ATOM_TO_OBJECT(stmt->atom);
|
||||
JS_ASSERT(tc->blockChain == ATOM_TO_OBJECT(stmt->atom));
|
||||
obj = tc->blockChain;
|
||||
} else {
|
||||
if (!stmt) {
|
||||
/*
|
||||
|
@ -3312,7 +3307,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
pn->pn_extra = PNX_POPVAR;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
#endif /* JS_HAS_BLOCK_SCOPE */
|
||||
|
||||
case TOK_RETURN:
|
||||
pn = ReturnOrYield(cx, ts, tc, Expr);
|
||||
|
@ -3447,11 +3442,11 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
static JSParseNode *
|
||||
Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
||||
{
|
||||
BindData data;
|
||||
JSTokenType tt;
|
||||
JSBool let;
|
||||
BindData data;
|
||||
JSParseNode *pn, *pn2;
|
||||
JSStackFrame *fp;
|
||||
JSTokenType tt;
|
||||
JSAtom *atom;
|
||||
|
||||
/*
|
||||
|
@ -3460,9 +3455,9 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
* - TOK_LP: We are parsing the head of a let block.
|
||||
* - Otherwise, we're parsing var declarations.
|
||||
*/
|
||||
let = (CURRENT_TOKEN(ts).type == TOK_LET ||
|
||||
CURRENT_TOKEN(ts).type == TOK_LP);
|
||||
JS_ASSERT(let || CURRENT_TOKEN(ts).type == TOK_VAR);
|
||||
tt = CURRENT_TOKEN(ts).type;
|
||||
let = (tt == TOK_LET || tt == TOK_LP);
|
||||
JS_ASSERT(let || tt == TOK_VAR);
|
||||
|
||||
/* Make sure that Statement set the tree context up correctly. */
|
||||
JS_ASSERT(!let ||
|
||||
|
@ -3489,7 +3484,8 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
*/
|
||||
fp = cx->fp;
|
||||
if (let) {
|
||||
data.obj = ATOM_TO_OBJECT(tc->topScopeStmt->atom);
|
||||
JS_ASSERT(tc->blockChain == ATOM_TO_OBJECT(tc->topScopeStmt->atom));
|
||||
data.obj = tc->blockChain;
|
||||
data.u.let.index = OBJ_BLOCK_COUNT(cx, data.obj);
|
||||
data.u.let.overflow = JSMSG_TOO_MANY_FUN_VARS;
|
||||
} else {
|
||||
|
@ -5151,7 +5147,7 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
|||
|
||||
data.pn = NULL;
|
||||
data.ts = ts;
|
||||
data.obj = ATOM_TO_OBJECT(pntop->pn_atom);
|
||||
data.obj = tc->blockChain;
|
||||
data.op = JSOP_NOP;
|
||||
data.binder = BindLet;
|
||||
data.u.let.index = 0;
|
||||
|
@ -5274,7 +5270,7 @@ PrimaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
|||
if (!pn)
|
||||
return NULL;
|
||||
break;
|
||||
#endif /* JS_HAS_BLOCK_SCOPE */
|
||||
#endif
|
||||
|
||||
case TOK_LC:
|
||||
pn = NewParseNode(cx, ts, PN_LIST, tc);
|
||||
|
|
Загрузка…
Ссылка в новой задаче