зеркало из https://github.com/mozilla/pjs.git
Bug 408271: check for missing return when parsing a function body in one place. r,a=brendan
This commit is contained in:
Родитель
cb4075c49b
Коммит
8ddf830a10
|
@ -89,7 +89,6 @@ js_InitCodeGenerator(JSContext *cx, JSCodeGenerator *cg, JSParseContext *pc,
|
|||
{
|
||||
memset(cg, 0, sizeof *cg);
|
||||
TREE_CONTEXT_INIT(&cg->treeContext, pc);
|
||||
cg->treeContext.flags |= TCF_COMPILING;
|
||||
cg->codePool = codePool;
|
||||
cg->notePool = notePool;
|
||||
cg->codeMark = JS_ARENA_MARK(codePool);
|
||||
|
@ -1842,9 +1841,10 @@ EmitSlotIndexOp(JSContext *cx, JSOp op, uintN slot, uintN index,
|
|||
* in js_EmitTree.
|
||||
*/
|
||||
static JSBool
|
||||
BindNameToSlot(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
|
||||
BindNameToSlot(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
|
||||
uintN decltype)
|
||||
{
|
||||
JSTreeContext *tc;
|
||||
JSAtom *atom;
|
||||
JSStmtInfo *stmt;
|
||||
jsint slot;
|
||||
|
@ -1869,6 +1869,7 @@ BindNameToSlot(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
|
|||
* as this node. FIXME: we should be able to optimize catch vars to be
|
||||
* block-locals.
|
||||
*/
|
||||
tc = &cg->treeContext;
|
||||
atom = pn->pn_atom;
|
||||
if (decltype != VAR_DECL &&
|
||||
(stmt = js_LexicalLookup(tc, atom, &slot, decltype))) {
|
||||
|
@ -1960,8 +1961,7 @@ BindNameToSlot(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
|
|||
constOp = (ALE_JSOP(ale) == JSOP_DEFCONST);
|
||||
|
||||
/* Index atom so we can map fast global number to name. */
|
||||
JS_ASSERT(tc->flags & TCF_COMPILING);
|
||||
ale = js_IndexAtom(cx, atom, &((JSCodeGenerator *) tc)->atomList);
|
||||
ale = js_IndexAtom(cx, atom, &cg->atomList);
|
||||
if (!ale)
|
||||
return JS_FALSE;
|
||||
|
||||
|
@ -2071,7 +2071,7 @@ BindNameToSlot(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
|
|||
* pop bytecode.
|
||||
*/
|
||||
static JSBool
|
||||
CheckSideEffects(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
|
||||
CheckSideEffects(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
|
||||
JSBool *answer)
|
||||
{
|
||||
JSBool ok;
|
||||
|
@ -2120,14 +2120,14 @@ CheckSideEffects(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
|
|||
*answer = JS_TRUE;
|
||||
} else {
|
||||
for (pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next)
|
||||
ok &= CheckSideEffects(cx, tc, pn2, answer);
|
||||
ok &= CheckSideEffects(cx, cg, pn2, answer);
|
||||
}
|
||||
break;
|
||||
|
||||
case PN_TERNARY:
|
||||
ok = CheckSideEffects(cx, tc, pn->pn_kid1, answer) &&
|
||||
CheckSideEffects(cx, tc, pn->pn_kid2, answer) &&
|
||||
CheckSideEffects(cx, tc, pn->pn_kid3, answer);
|
||||
ok = CheckSideEffects(cx, cg, pn->pn_kid1, answer) &&
|
||||
CheckSideEffects(cx, cg, pn->pn_kid2, answer) &&
|
||||
CheckSideEffects(cx, cg, pn->pn_kid3, answer);
|
||||
break;
|
||||
|
||||
case PN_BINARY:
|
||||
|
@ -2145,9 +2145,9 @@ CheckSideEffects(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
|
|||
if (pn2->pn_type != TOK_NAME) {
|
||||
*answer = JS_TRUE;
|
||||
} else {
|
||||
if (!BindNameToSlot(cx, tc, pn2, 0))
|
||||
if (!BindNameToSlot(cx, cg, pn2, 0))
|
||||
return JS_FALSE;
|
||||
if (!CheckSideEffects(cx, tc, pn->pn_right, answer))
|
||||
if (!CheckSideEffects(cx, cg, pn->pn_right, answer))
|
||||
return JS_FALSE;
|
||||
if (!*answer &&
|
||||
(pn->pn_op != JSOP_NOP ||
|
||||
|
@ -2168,7 +2168,7 @@ CheckSideEffects(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
|
|||
case PN_UNARY:
|
||||
switch (pn->pn_type) {
|
||||
case TOK_RP:
|
||||
ok = CheckSideEffects(cx, tc, pn->pn_kid, answer);
|
||||
ok = CheckSideEffects(cx, cg, pn->pn_kid, answer);
|
||||
break;
|
||||
|
||||
case TOK_DELETE:
|
||||
|
@ -2187,7 +2187,7 @@ CheckSideEffects(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
|
|||
*answer = JS_TRUE;
|
||||
break;
|
||||
default:
|
||||
ok = CheckSideEffects(cx, tc, pn2, answer);
|
||||
ok = CheckSideEffects(cx, cg, pn2, answer);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -2211,7 +2211,7 @@ CheckSideEffects(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
|
|||
* defaulted to JSOP_NOP).
|
||||
*/
|
||||
if (pn->pn_type == TOK_NAME && pn->pn_op != JSOP_NOP) {
|
||||
if (!BindNameToSlot(cx, tc, pn, 0))
|
||||
if (!BindNameToSlot(cx, cg, pn, 0))
|
||||
return JS_FALSE;
|
||||
if (pn->pn_slot < 0 && pn->pn_op != JSOP_ARGUMENTS) {
|
||||
/*
|
||||
|
@ -2223,10 +2223,8 @@ CheckSideEffects(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
|
|||
}
|
||||
pn2 = pn->pn_expr;
|
||||
if (pn->pn_type == TOK_DOT) {
|
||||
if (pn2->pn_type == TOK_NAME &&
|
||||
!BindNameToSlot(cx, tc, pn2, 0)) {
|
||||
if (pn2->pn_type == TOK_NAME && !BindNameToSlot(cx, cg, pn2, 0))
|
||||
return JS_FALSE;
|
||||
}
|
||||
if (!(pn2->pn_op == JSOP_ARGUMENTS &&
|
||||
pn->pn_atom == cx->runtime->atomState.lengthAtom)) {
|
||||
/*
|
||||
|
@ -2236,7 +2234,7 @@ CheckSideEffects(JSContext *cx, JSTreeContext *tc, JSParseNode *pn,
|
|||
*answer = JS_TRUE;
|
||||
}
|
||||
}
|
||||
ok = CheckSideEffects(cx, tc, pn2, answer);
|
||||
ok = CheckSideEffects(cx, cg, pn2, answer);
|
||||
break;
|
||||
|
||||
case PN_NULLARY:
|
||||
|
@ -2253,7 +2251,7 @@ EmitNameOp(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
|
|||
{
|
||||
JSOp op;
|
||||
|
||||
if (!BindNameToSlot(cx, &cg->treeContext, pn, 0))
|
||||
if (!BindNameToSlot(cx, cg, pn, 0))
|
||||
return JS_FALSE;
|
||||
op = PN_OP(pn);
|
||||
|
||||
|
@ -2349,7 +2347,7 @@ EmitPropOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg,
|
|||
* - varname.prop into JSOP_GETVARPROP
|
||||
* - localname.prop into JSOP_GETLOCALPROP
|
||||
*/
|
||||
if (!BindNameToSlot(cx, &cg->treeContext, pn2, 0))
|
||||
if (!BindNameToSlot(cx, cg, pn2, 0))
|
||||
return JS_FALSE;
|
||||
switch (pn2->pn_op) {
|
||||
case JSOP_ARGUMENTS:
|
||||
|
@ -2461,7 +2459,7 @@ EmitElemOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg)
|
|||
* one or more index expression and JSOP_GETELEM op pairs.
|
||||
*/
|
||||
if (left->pn_type == TOK_NAME && next->pn_type == TOK_NUMBER) {
|
||||
if (!BindNameToSlot(cx, &cg->treeContext, left, 0))
|
||||
if (!BindNameToSlot(cx, cg, left, 0))
|
||||
return JS_FALSE;
|
||||
if (left->pn_op == JSOP_ARGUMENTS &&
|
||||
JSDOUBLE_IS_INT(next->pn_dval, slot) &&
|
||||
|
@ -2536,7 +2534,7 @@ EmitElemOp(JSContext *cx, JSParseNode *pn, JSOp op, JSCodeGenerator *cg)
|
|||
if (op == JSOP_GETELEM &&
|
||||
left->pn_type == TOK_NAME &&
|
||||
right->pn_type == TOK_NUMBER) {
|
||||
if (!BindNameToSlot(cx, &cg->treeContext, left, 0))
|
||||
if (!BindNameToSlot(cx, cg, left, 0))
|
||||
return JS_FALSE;
|
||||
if (left->pn_op == JSOP_ARGUMENTS &&
|
||||
JSDOUBLE_IS_INT(right->pn_dval, slot) &&
|
||||
|
@ -3273,13 +3271,12 @@ static JSBool
|
|||
EmitDestructuringDecl(JSContext *cx, JSCodeGenerator *cg, JSOp prologOp,
|
||||
JSParseNode *pn)
|
||||
{
|
||||
JSOp decltype;
|
||||
|
||||
JS_ASSERT(pn->pn_type == TOK_NAME);
|
||||
if (!BindNameToSlot(cx, &cg->treeContext, pn,
|
||||
(prologOp == JSOP_NOP)
|
||||
? LET_DECL
|
||||
: VAR_DECL)) {
|
||||
decltype = (prologOp == JSOP_NOP) ? LET_DECL : VAR_DECL;
|
||||
if (!BindNameToSlot(cx, cg, pn, decltype))
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
JS_ASSERT(pn->pn_op != JSOP_ARGUMENTS);
|
||||
return MaybeEmitVarDecl(cx, cg, prologOp, pn, NULL);
|
||||
|
@ -3340,10 +3337,8 @@ EmitDestructuringLHS(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
if (js_Emit1(cx, cg, JSOP_POP) < 0)
|
||||
return JS_FALSE;
|
||||
} else {
|
||||
if (pn->pn_type == TOK_NAME &&
|
||||
!BindNameToSlot(cx, &cg->treeContext, pn, 0)) {
|
||||
if (pn->pn_type == TOK_NAME && !BindNameToSlot(cx, cg, pn, 0))
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
switch (pn->pn_op) {
|
||||
case JSOP_SETNAME:
|
||||
|
@ -3715,7 +3710,7 @@ EmitVariables(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
|
|||
JSBool useful = JS_FALSE;
|
||||
|
||||
JS_ASSERT(pn->pn_count == 1);
|
||||
if (!CheckSideEffects(cx, tc, pn2->pn_right, &useful))
|
||||
if (!CheckSideEffects(cx, cg, pn2->pn_right, &useful))
|
||||
return JS_FALSE;
|
||||
if (!useful)
|
||||
return JS_TRUE;
|
||||
|
@ -3762,8 +3757,7 @@ EmitVariables(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
|
|||
JS_ASSERT(pn2->pn_type == TOK_NAME);
|
||||
#endif
|
||||
|
||||
if (!BindNameToSlot(cx, &cg->treeContext, pn2,
|
||||
let ? LET_DECL : VAR_DECL))
|
||||
if (!BindNameToSlot(cx, cg, pn2, let ? LET_DECL : VAR_DECL))
|
||||
return JS_FALSE;
|
||||
JS_ASSERT(pn2->pn_slot >= 0 || !let);
|
||||
|
||||
|
@ -3790,7 +3784,7 @@ EmitVariables(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn,
|
|||
JSBool useful = JS_FALSE;
|
||||
|
||||
JS_ASSERT(pn->pn_count == 1);
|
||||
if (!CheckSideEffects(cx, tc, pn3, &useful))
|
||||
if (!CheckSideEffects(cx, cg, pn3, &useful))
|
||||
return JS_FALSE;
|
||||
if (!useful)
|
||||
return JS_TRUE;
|
||||
|
@ -4409,7 +4403,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
}
|
||||
} else {
|
||||
pn3->pn_op = JSOP_FORNAME;
|
||||
if (!BindNameToSlot(cx, &cg->treeContext, pn3, 0))
|
||||
if (!BindNameToSlot(cx, cg, pn3, 0))
|
||||
return JS_FALSE;
|
||||
op = PN_OP(pn3);
|
||||
}
|
||||
|
@ -4428,10 +4422,8 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
|
||||
case TOK_DOT:
|
||||
useful = JS_FALSE;
|
||||
if (!CheckSideEffects(cx, &cg->treeContext, pn3->pn_expr,
|
||||
&useful)) {
|
||||
if (!CheckSideEffects(cx, cg, pn3->pn_expr, &useful))
|
||||
return JS_FALSE;
|
||||
}
|
||||
if (!useful) {
|
||||
if (!EmitPropOp(cx, pn3, JSOP_FORPROP, cg, JS_FALSE))
|
||||
return JS_FALSE;
|
||||
|
@ -5194,7 +5186,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
*/
|
||||
useful = wantval = !(cg->treeContext.flags & TCF_IN_FUNCTION);
|
||||
if (!useful) {
|
||||
if (!CheckSideEffects(cx, &cg->treeContext, pn2, &useful))
|
||||
if (!CheckSideEffects(cx, cg, pn2, &useful))
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
|
@ -5308,7 +5300,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
atomIndex = (jsatomid) -1; /* quell GCC overwarning */
|
||||
switch (pn2->pn_type) {
|
||||
case TOK_NAME:
|
||||
if (!BindNameToSlot(cx, &cg->treeContext, pn2, 0))
|
||||
if (!BindNameToSlot(cx, cg, pn2, 0))
|
||||
return JS_FALSE;
|
||||
if (pn2->pn_slot >= 0) {
|
||||
atomIndex = (jsatomid) pn2->pn_slot;
|
||||
|
@ -5681,7 +5673,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
switch (pn2->pn_type) {
|
||||
case TOK_NAME:
|
||||
pn2->pn_op = op;
|
||||
if (!BindNameToSlot(cx, &cg->treeContext, pn2, 0))
|
||||
if (!BindNameToSlot(cx, cg, pn2, 0))
|
||||
return JS_FALSE;
|
||||
op = PN_OP(pn2);
|
||||
if (pn2->pn_slot >= 0) {
|
||||
|
@ -5754,7 +5746,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
switch (pn2->pn_type) {
|
||||
case TOK_NAME:
|
||||
pn2->pn_op = JSOP_DELNAME;
|
||||
if (!BindNameToSlot(cx, &cg->treeContext, pn2, 0))
|
||||
if (!BindNameToSlot(cx, cg, pn2, 0))
|
||||
return JS_FALSE;
|
||||
op = PN_OP(pn2);
|
||||
if (op == JSOP_FALSE) {
|
||||
|
@ -5797,7 +5789,7 @@ js_EmitTree(JSContext *cx, JSCodeGenerator *cg, JSParseNode *pn)
|
|||
* also JSOP_GROUP for correctly parenthesized decompilation).
|
||||
*/
|
||||
useful = JS_FALSE;
|
||||
if (!CheckSideEffects(cx, &cg->treeContext, pn2, &useful))
|
||||
if (!CheckSideEffects(cx, cg, pn2, &useful))
|
||||
return JS_FALSE;
|
||||
if (!useful) {
|
||||
off = noteIndex = -1;
|
||||
|
|
|
@ -175,24 +175,34 @@ struct JSTreeContext { /* tree context for semantic checks */
|
|||
names when flags & TCF_IN_FUNCTION */
|
||||
};
|
||||
|
||||
#define TCF_COMPILING 0x01 /* generating bytecode; this tc is a cg */
|
||||
#define TCF_IN_FUNCTION 0x02 /* parsing inside function body */
|
||||
#define TCF_RETURN_EXPR 0x04 /* function has 'return expr;' */
|
||||
#define TCF_RETURN_VOID 0x08 /* function has 'return;' */
|
||||
#define TCF_RETURN_FLAGS 0x0C /* propagate these out of blocks */
|
||||
#define TCF_IN_FOR_INIT 0x10 /* parsing init expr of for; exclude 'in' */
|
||||
#define TCF_FUN_CLOSURE_VS_VAR 0x20 /* function and var with same name */
|
||||
#define TCF_FUN_USES_NONLOCALS 0x40 /* function refers to non-local names */
|
||||
#define TCF_FUN_HEAVYWEIGHT 0x80 /* function needs Call object per call */
|
||||
#define TCF_FUN_IS_GENERATOR 0x100 /* parsed yield statement in function */
|
||||
#define TCF_FUN_FLAGS 0x1E0 /* flags to propagate from FunctionBody */
|
||||
#define TCF_HAS_DEFXMLNS 0x200 /* default xml namespace = ...; parsed */
|
||||
#define TCF_HAS_FUNCTION_STMT 0x400 /* block contains a function statement */
|
||||
#define TCF_GENEXP_LAMBDA 0x800 /* flag lambda from generator expression */
|
||||
#define TCF_COMPILE_N_GO 0x1000 /* compiler-and-go mode of script, can
|
||||
#define TCF_IN_FUNCTION 0x01 /* parsing inside function body */
|
||||
#define TCF_RETURN_EXPR 0x02 /* function has 'return expr;' */
|
||||
#define TCF_RETURN_VOID 0x04 /* function has 'return;' */
|
||||
#define TCF_IN_FOR_INIT 0x08 /* parsing init expr of for; exclude 'in' */
|
||||
#define TCF_FUN_CLOSURE_VS_VAR 0x10 /* function and var with same name */
|
||||
#define TCF_FUN_USES_NONLOCALS 0x20 /* function refers to non-local names */
|
||||
#define TCF_FUN_HEAVYWEIGHT 0x40 /* function needs Call object per call */
|
||||
#define TCF_FUN_IS_GENERATOR 0x80 /* parsed yield statement in function */
|
||||
#define TCF_HAS_DEFXMLNS 0x100 /* default xml namespace = ...; parsed */
|
||||
#define TCF_HAS_FUNCTION_STMT 0x200 /* block contains a function statement */
|
||||
#define TCF_GENEXP_LAMBDA 0x400 /* flag lambda from generator expression */
|
||||
#define TCF_COMPILE_N_GO 0x800 /* compiler-and-go mode of script, can
|
||||
optimize name references based on scope
|
||||
chain */
|
||||
|
||||
/*
|
||||
* Flags to propagate out of the blocks.
|
||||
*/
|
||||
#define TCF_RETURN_FLAGS (TCF_RETURN_EXPR | TCF_RETURN_VOID)
|
||||
|
||||
/*
|
||||
* Flags to propagate from FunctionBody.
|
||||
*/
|
||||
#define TCF_FUN_FLAGS (TCF_FUN_IS_GENERATOR | \
|
||||
TCF_FUN_HEAVYWEIGHT | \
|
||||
TCF_FUN_USES_NONLOCALS | \
|
||||
TCF_FUN_CLOSURE_VS_VAR)
|
||||
|
||||
#define TREE_CONTEXT_INIT(tc, pc) \
|
||||
((tc)->flags = (tc)->ngvars = 0, \
|
||||
(tc)->globalUses = (tc)->loopyGlobalUses = 0, \
|
||||
|
|
|
@ -567,6 +567,7 @@ js_CompileScript(JSContext *cx, JSObject *obj, JSPrincipals *principals,
|
|||
JSStackFrame *fp, frame;
|
||||
JSArenaPool codePool, notePool;
|
||||
JSCodeGenerator cg;
|
||||
JSTokenType tt;
|
||||
JSParseNode *pn;
|
||||
JSScript *script;
|
||||
#ifdef METER_PARSENODES
|
||||
|
@ -599,17 +600,42 @@ js_CompileScript(JSContext *cx, JSObject *obj, JSPrincipals *principals,
|
|||
|
||||
/* From this point the control must flow via the label out. */
|
||||
cg.treeContext.flags |= tcflags;
|
||||
pn = Statements(cx, &pc.tokenStream, &cg.treeContext);
|
||||
if (!pn) {
|
||||
script = NULL;
|
||||
goto out;
|
||||
}
|
||||
if (!js_MatchToken(cx, &pc.tokenStream, TOK_EOF)) {
|
||||
js_ReportCompileErrorNumber(cx, &pc.tokenStream, NULL, JSREPORT_ERROR,
|
||||
JSMSG_SYNTAX_ERROR);
|
||||
script = NULL;
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Inline Statements() to emit as we go to save space.
|
||||
*/
|
||||
for (;;) {
|
||||
pc.tokenStream.flags |= TSF_OPERAND;
|
||||
tt = js_PeekToken(cx, &pc.tokenStream);
|
||||
pc.tokenStream.flags &= ~TSF_OPERAND;
|
||||
if (tt <= TOK_EOF) {
|
||||
if (tt == TOK_EOF)
|
||||
break;
|
||||
JS_ASSERT(tt == TOK_ERROR);
|
||||
script = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
pn = Statement(cx, &pc.tokenStream, &cg.treeContext);
|
||||
if (!pn) {
|
||||
script = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME bug 346749: let declarations at the top level in a script are
|
||||
* turned into var declarations and do not introduce block nodes.
|
||||
*/
|
||||
JS_ASSERT(!cg.treeContext.blockNode);
|
||||
|
||||
if (!js_FoldConstants(cx, pn, &cg.treeContext) ||
|
||||
!js_EmitTree(cx, &cg, pn)) {
|
||||
script = NULL;
|
||||
goto out;
|
||||
}
|
||||
RecycleTree(pn, &cg.treeContext);
|
||||
}
|
||||
|
||||
#ifdef METER_PARSENODES
|
||||
printf("Parser growth: %d (%u nodes, %u max, %u unrecycled)\n",
|
||||
(char *)sbrk(0) - (char *)before,
|
||||
|
@ -620,16 +646,9 @@ js_CompileScript(JSContext *cx, JSObject *obj, JSPrincipals *principals,
|
|||
#endif
|
||||
|
||||
/*
|
||||
* No need to emit bytecode here -- Statements already has, for each
|
||||
* statement in turn. Search for TCF_COMPILING in Statements, below.
|
||||
* That flag is set for every tc == &cg->treeContext, and it implies
|
||||
* that the tc can be downcast to a cg and used to emit code during
|
||||
* parsing, rather than at the end of the parse phase.
|
||||
*
|
||||
* Nowadays the threaded interpreter needs a stop instruction, so we
|
||||
* do have to emit that here.
|
||||
*/
|
||||
JS_ASSERT(cg.treeContext.flags & TCF_COMPILING);
|
||||
if (js_Emit1(cx, &cg, JSOP_STOP) < 0) {
|
||||
script = NULL;
|
||||
goto out;
|
||||
|
@ -1420,50 +1439,24 @@ Statements(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
|||
tc->blockNode = pn;
|
||||
PN_INIT_LIST(pn);
|
||||
|
||||
ts->flags |= TSF_OPERAND;
|
||||
while ((tt = js_PeekToken(cx, ts)) > TOK_EOF && tt != TOK_RC) {
|
||||
for (;;) {
|
||||
ts->flags |= TSF_OPERAND;
|
||||
tt = js_PeekToken(cx, ts);
|
||||
ts->flags &= ~TSF_OPERAND;
|
||||
if (tt <= TOK_EOF || tt == TOK_RC)
|
||||
break;
|
||||
pn2 = Statement(cx, ts, tc);
|
||||
if (!pn2) {
|
||||
if (ts->flags & TSF_EOF)
|
||||
ts->flags |= TSF_UNEXPECTED_EOF;
|
||||
return NULL;
|
||||
}
|
||||
ts->flags |= TSF_OPERAND;
|
||||
|
||||
/* Detect a function statement for the TOK_LC case in Statement. */
|
||||
if (pn2->pn_type == TOK_FUNCTION && !AT_TOP_LEVEL(tc))
|
||||
tc->flags |= TCF_HAS_FUNCTION_STMT;
|
||||
|
||||
/* If compiling top-level statements, emit as we go to save space. */
|
||||
if (!tc->topStmt && (tc->flags & TCF_COMPILING)) {
|
||||
if (JS_HAS_STRICT_OPTION(cx) && (tc->flags & TCF_RETURN_EXPR)) {
|
||||
/*
|
||||
* Check pn2 for lack of a final return statement if it is the
|
||||
* last statement in the block.
|
||||
*/
|
||||
tt = js_PeekToken(cx, ts);
|
||||
if ((tt == TOK_EOF || tt == TOK_RC) &&
|
||||
!CheckFinalReturn(cx, tc, pn2)) {
|
||||
tt = TOK_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear TCF_RETURN_EXPR so FunctionBody doesn't try to
|
||||
* CheckFinalReturn again.
|
||||
*/
|
||||
tc->flags &= ~TCF_RETURN_EXPR;
|
||||
}
|
||||
if (!js_FoldConstants(cx, pn2, tc) ||
|
||||
!js_EmitTree(cx, (JSCodeGenerator *)tc, pn2)) {
|
||||
tt = TOK_ERROR;
|
||||
break;
|
||||
}
|
||||
RecycleTree(pn2, tc);
|
||||
} else {
|
||||
PN_APPEND(pn, pn2);
|
||||
}
|
||||
PN_APPEND(pn, pn2);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
Загрузка…
Ссылка в новой задаче