Fix let expressions in bracketed forms within for loop head (349605, r=mrbkap).

This commit is contained in:
brendan%mozilla.org 2006-08-23 00:41:59 +00:00
Родитель 33e28721fe
Коммит f13a7d3693
4 изменённых файлов: 59 добавлений и 58 удалений

Просмотреть файл

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