mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-23 18:26:15 +00:00
Set up let declarations properly by finding the correct JSStmtInfo (not missing try or catch
blocks). This required making the 'scope' statements have a bit instead of a statement type since we can now morph e.g. try statements. This patch also fixes the numbering for let blocks after the first let block. bug 344370, r=brendan
This commit is contained in:
parent
098829e91d
commit
07a112a37e
@ -237,13 +237,12 @@ const char js_finally_block_str[] = "finally block";
|
||||
const char js_script_str[] = "script";
|
||||
|
||||
static const char *statementName[] = {
|
||||
"block", /* BLOCK */
|
||||
"label statement", /* LABEL */
|
||||
"if statement", /* IF */
|
||||
"else statement", /* ELSE */
|
||||
"switch statement", /* SWITCH */
|
||||
"block", /* BLOCK */
|
||||
js_with_statement_str, /* WITH */
|
||||
"block scope", /* BLOCK_SCOPE */
|
||||
"catch block", /* CATCH */
|
||||
"try block", /* TRY */
|
||||
js_finally_block_str, /* FINALLY */
|
||||
@ -1230,12 +1229,7 @@ js_PushStatement(JSTreeContext *tc, JSStmtInfo *stmt, JSStmtType type,
|
||||
stmt->label = NULL;
|
||||
stmt->down = tc->topStmt;
|
||||
tc->topStmt = stmt;
|
||||
if (STMT_TYPE_IS_SCOPE(type)) {
|
||||
stmt->downScope = tc->topScopeStmt;
|
||||
tc->topScopeStmt = stmt;
|
||||
} else {
|
||||
stmt->downScope = NULL;
|
||||
}
|
||||
stmt->downScope = NULL;
|
||||
stmt->blockObj = NULL;
|
||||
}
|
||||
|
||||
@ -1243,8 +1237,11 @@ void
|
||||
js_PushBlockScope(JSTreeContext *tc, JSStmtInfo *stmt, JSObject *blockObj,
|
||||
ptrdiff_t top)
|
||||
{
|
||||
js_PushStatement(tc, stmt, STMT_BLOCK_SCOPE, top);
|
||||
js_PushStatement(tc, stmt, STMT_BLOCK, top);
|
||||
stmt->flags |= SIF_SCOPE;
|
||||
blockObj->slots[JSSLOT_PARENT] = OBJECT_TO_JSVAL(tc->blockChain);
|
||||
stmt->downScope = tc->topScopeStmt;
|
||||
tc->topScopeStmt = stmt;
|
||||
tc->blockChain = stmt->blockObj = blockObj;
|
||||
}
|
||||
|
||||
@ -1365,9 +1362,11 @@ EmitNonLocalJumpFixup(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *toStmt,
|
||||
return JS_FALSE;
|
||||
break;
|
||||
|
||||
default:;
|
||||
}
|
||||
|
||||
#if JS_HAS_BLOCK_SCOPE
|
||||
case STMT_BLOCK_SCOPE:
|
||||
{
|
||||
if (stmt->flags & SIF_SCOPE) {
|
||||
uintN i;
|
||||
|
||||
/* There is a Block object with locals on the stack to pop. */
|
||||
@ -1376,11 +1375,8 @@ EmitNonLocalJumpFixup(JSContext *cx, JSCodeGenerator *cg, JSStmtInfo *toStmt,
|
||||
i = OBJ_BLOCK_COUNT(cx, stmt->blockObj);
|
||||
EMIT_UINT16_IMM_OP(JSOP_LEAVEBLOCK, i);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
default:;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
cg->stackDepth = depth;
|
||||
@ -1441,14 +1437,12 @@ void
|
||||
js_PopStatement(JSTreeContext *tc)
|
||||
{
|
||||
JSStmtInfo *stmt;
|
||||
JSStmtType type;
|
||||
|
||||
stmt = tc->topStmt;
|
||||
tc->topStmt = stmt->down;
|
||||
type = stmt->type;
|
||||
if (STMT_TYPE_IS_SCOPE(type)) {
|
||||
if (STMT_IS_SCOPE(stmt)) {
|
||||
tc->topScopeStmt = stmt->downScope;
|
||||
if (type == STMT_BLOCK_SCOPE) {
|
||||
if (stmt->flags & SIF_SCOPE) {
|
||||
tc->blockChain =
|
||||
JSVAL_TO_OBJECT(stmt->blockObj->slots[JSSLOT_PARENT]);
|
||||
}
|
||||
@ -1523,7 +1517,7 @@ LexicalLookup(JSContext *cx, JSTreeContext *tc, JSAtom *atom, jsint *slotp)
|
||||
continue;
|
||||
}
|
||||
|
||||
JS_ASSERT(stmt->type == STMT_BLOCK_SCOPE);
|
||||
JS_ASSERT(stmt->flags & SIF_SCOPE);
|
||||
obj = stmt->blockObj;
|
||||
if (!js_LookupProperty(cx, obj, ATOM_TO_JSID(atom), &pobj, &prop))
|
||||
return NULL;
|
||||
@ -1880,7 +1874,7 @@ BindNameToSlot(JSContext *cx, JSTreeContext *tc, JSParseNode *pn)
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JS_ASSERT(stmt->type == STMT_BLOCK_SCOPE);
|
||||
JS_ASSERT(stmt->flags & SIF_SCOPE);
|
||||
JS_ASSERT(slot >= 0);
|
||||
op = pn->pn_op;
|
||||
switch (op) {
|
||||
|
@ -61,28 +61,30 @@ JS_BEGIN_EXTERN_C
|
||||
* Also remember to keep the statementName array in jsemit.c in sync.
|
||||
*/
|
||||
typedef enum JSStmtType {
|
||||
STMT_BLOCK = 0, /* compound statement: { s1[;... sN] } */
|
||||
STMT_LABEL = 1, /* labeled statement: L: s */
|
||||
STMT_IF = 2, /* if (then) statement */
|
||||
STMT_ELSE = 3, /* else clause of if statement */
|
||||
STMT_SWITCH = 4, /* switch statement */
|
||||
STMT_WITH = 5, /* with statement */
|
||||
STMT_BLOCK_SCOPE = 6, /* let block/expr or array comprehension */
|
||||
STMT_CATCH = 7, /* catch block */
|
||||
STMT_TRY = 8, /* try block */
|
||||
STMT_FINALLY = 9, /* finally block */
|
||||
STMT_SUBROUTINE = 10, /* gosub-target subroutine body */
|
||||
STMT_DO_LOOP = 11, /* do/while loop statement */
|
||||
STMT_FOR_LOOP = 12, /* for loop statement */
|
||||
STMT_FOR_IN_LOOP = 13, /* for/in loop statement */
|
||||
STMT_WHILE_LOOP = 14 /* while loop statement */
|
||||
STMT_LABEL, /* labeled statement: L: s */
|
||||
STMT_IF, /* if (then) statement */
|
||||
STMT_ELSE, /* else clause of if statement */
|
||||
STMT_SWITCH, /* switch statement */
|
||||
STMT_BLOCK, /* compound statement: { s1[;... sN] } */
|
||||
STMT_WITH, /* with statement */
|
||||
STMT_CATCH, /* catch block */
|
||||
STMT_TRY, /* try block */
|
||||
STMT_FINALLY, /* finally block */
|
||||
STMT_SUBROUTINE, /* gosub-target subroutine body */
|
||||
STMT_DO_LOOP, /* do/while loop statement */
|
||||
STMT_FOR_LOOP, /* for loop statement */
|
||||
STMT_FOR_IN_LOOP, /* for/in loop statement */
|
||||
STMT_WHILE_LOOP /* while loop statement */
|
||||
} JSStmtType;
|
||||
|
||||
#define STMT_TYPE_IS_SCOPE(type) \
|
||||
((uintN)((type) - STMT_WITH) <= (uintN)(STMT_CATCH - STMT_WITH))
|
||||
#define STMT_TYPE_MAYBE_SCOPE(type) \
|
||||
((type) >= STMT_BLOCK && (type) <= STMT_FINALLY)
|
||||
#define STMT_TYPE_IS_LOOP(type) ((type) >= STMT_DO_LOOP)
|
||||
|
||||
#define STMT_IS_SCOPE(stmt) STMT_TYPE_IS_SCOPE((stmt)->type)
|
||||
#define STMT_MAYBE_SCOPE(stmt) STMT_TYPE_MAYBE_SCOPE((stmt)->type)
|
||||
#define STMT_IS_SCOPE(stmt) \
|
||||
((uintN)(((stmt)->type) - STMT_WITH) <= (uintN)(STMT_CATCH - STMT_WITH) ||\
|
||||
((stmt)->flags & SIF_SCOPE))
|
||||
#define STMT_IS_LOOP(stmt) STMT_TYPE_IS_LOOP((stmt)->type)
|
||||
|
||||
typedef struct JSStmtInfo JSStmtInfo;
|
||||
@ -102,6 +104,7 @@ struct JSStmtInfo {
|
||||
};
|
||||
|
||||
#define SIF_BODY_BLOCK 0x0001 /* STMT_BLOCK type is a function body */
|
||||
#define SIF_SCOPE 0x0002 /* This statement contains a scope. */
|
||||
|
||||
#define AT_TOP_LEVEL(tc) \
|
||||
(!(tc)->topStmt || ((tc)->topStmt->flags & SIF_BODY_BLOCK))
|
||||
|
139
js/src/jsparse.c
139
js/src/jsparse.c
@ -2049,13 +2049,13 @@ ReturnOrYield(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
|
||||
#if JS_HAS_BLOCK_SCOPE
|
||||
|
||||
static JSStmtInfo *
|
||||
FindBlockStatement(JSTreeContext *tc)
|
||||
FindMaybeScopeStatement(JSTreeContext *tc)
|
||||
{
|
||||
JSStmtInfo *stmt;
|
||||
|
||||
stmt = tc->topStmt;
|
||||
while (stmt) {
|
||||
if (stmt->type == STMT_BLOCK || stmt->type == STMT_BLOCK_SCOPE)
|
||||
if (STMT_MAYBE_SCOPE(stmt))
|
||||
return stmt;
|
||||
stmt = stmt->down;
|
||||
}
|
||||
@ -2907,73 +2907,84 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
||||
JSObject *obj;
|
||||
JSAtom *atom;
|
||||
|
||||
/* Check for a let statement or let expression. */
|
||||
if (js_PeekToken(cx, ts) == TOK_LP) {
|
||||
pn = LetBlock(cx, ts, tc, JS_TRUE);
|
||||
if (!pn || !(pn->pn_extra & PNX_BLOCKEXPR))
|
||||
return pn;
|
||||
} else {
|
||||
/* Set up the block object. */
|
||||
stmt = FindBlockStatement(tc);
|
||||
if (stmt && stmt->type == STMT_BLOCK_SCOPE) {
|
||||
JS_ASSERT(stmt->blockObj);
|
||||
obj = stmt->blockObj;
|
||||
} else {
|
||||
if (stmt) {
|
||||
/* Convert the block statement into a scope statement. */
|
||||
obj = js_NewBlockObject(cx);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
JS_ASSERT(stmt->type == STMT_BLOCK);
|
||||
JS_ASSERT(stmt->downScope == NULL);
|
||||
stmt->type = STMT_BLOCK_SCOPE;
|
||||
stmt->downScope = tc->topScopeStmt;
|
||||
tc->topScopeStmt = stmt;
|
||||
obj->slots[JSSLOT_PARENT] = OBJECT_TO_JSVAL(tc->blockChain);
|
||||
tc->blockChain = stmt->blockObj = obj;
|
||||
} else {
|
||||
/*
|
||||
* XXX This is a hard case that requires more work. In
|
||||
* particular, in many cases, we're trying to emit code as
|
||||
* we go. However, this means that we haven't necessarily
|
||||
* finished processing all let declarations in the
|
||||
* implicit top-level block when we emit a reference to
|
||||
* one of them. For now, punt on this and pretend this is
|
||||
* a var declaration.
|
||||
*/
|
||||
CURRENT_TOKEN(ts).type = TOK_VAR;
|
||||
CURRENT_TOKEN(ts).t_op = JSOP_DEFVAR;
|
||||
|
||||
pn = Variables(cx, ts, tc);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
pn->pn_extra |= PNX_POPVAR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pn1 = tc->blockNode;
|
||||
if (!pn1 || pn1->pn_type != TOK_LEXICALSCOPE) {
|
||||
/* Create a new lexical scope node for these statements. */
|
||||
pn1 = NewParseNode(cx, ts, PN_NAME, tc);
|
||||
if (!pn1)
|
||||
return NULL;
|
||||
|
||||
atom = js_AtomizeObject(cx, obj, 0);
|
||||
if (!atom)
|
||||
return NULL;
|
||||
pn1->pn_type = TOK_LEXICALSCOPE;
|
||||
pn1->pn_atom = atom;
|
||||
pn1->pn_expr = tc->blockNode;
|
||||
pn1->pn_extra = 0;
|
||||
tc->blockNode = pn1;
|
||||
}
|
||||
|
||||
pn = Variables(cx, ts, tc);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
pn->pn_extra = PNX_POPVAR;
|
||||
/* Let expressions require automatic semicolon insertion. */
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a let declaration. We must convert the nearest JSStmtInfo
|
||||
* to be our scope statement. Further let declarations in this block
|
||||
* will find this scope statement and use the same block object. If we
|
||||
* are the first let declaration in this block (i.e., when the nearest
|
||||
* maybe-scope JSStmtInfo isn't a scope statement) then we also need
|
||||
* to set tc->blockNode to be our TOK_LEXICALSCOPE.
|
||||
*/
|
||||
stmt = FindMaybeScopeStatement(tc);
|
||||
if (stmt && (stmt->flags & SIF_SCOPE)) {
|
||||
JS_ASSERT(stmt->blockObj);
|
||||
obj = stmt->blockObj;
|
||||
} else {
|
||||
if (!stmt) {
|
||||
/*
|
||||
* XXX This is a hard case that requires more work. In
|
||||
* particular, in many cases, we're trying to emit code as
|
||||
* we go. However, this means that we haven't necessarily
|
||||
* finished processing all let declarations in the
|
||||
* implicit top-level block when we emit a reference to
|
||||
* one of them. For now, punt on this and pretend this is
|
||||
* a var declaration.
|
||||
*/
|
||||
CURRENT_TOKEN(ts).type = TOK_VAR;
|
||||
CURRENT_TOKEN(ts).t_op = JSOP_DEFVAR;
|
||||
|
||||
pn = Variables(cx, ts, tc);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
pn->pn_extra |= PNX_POPVAR;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Convert the block statement into a scope statement. */
|
||||
obj = js_NewBlockObject(cx);
|
||||
if (!obj)
|
||||
return NULL;
|
||||
JS_ASSERT(stmt->downScope == NULL);
|
||||
stmt->flags |= SIF_SCOPE;
|
||||
stmt->downScope = tc->topScopeStmt;
|
||||
tc->topScopeStmt = stmt;
|
||||
obj->slots[JSSLOT_PARENT] = OBJECT_TO_JSVAL(tc->blockChain);
|
||||
tc->blockChain = stmt->blockObj = obj;
|
||||
|
||||
pn1 = tc->blockNode;
|
||||
JS_ASSERT(!tc->blockNode ||
|
||||
tc->blockNode->pn_type != TOK_LEXICALSCOPE);
|
||||
|
||||
/* Create a new lexical scope node for these statements. */
|
||||
pn1 = NewParseNode(cx, ts, PN_NAME, tc);
|
||||
if (!pn1)
|
||||
return NULL;
|
||||
|
||||
atom = js_AtomizeObject(cx, obj, 0);
|
||||
if (!atom)
|
||||
return NULL;
|
||||
pn1->pn_type = TOK_LEXICALSCOPE;
|
||||
pn1->pn_pos = tc->blockNode->pn_pos;
|
||||
pn1->pn_atom = atom;
|
||||
pn1->pn_expr = tc->blockNode;
|
||||
pn1->pn_extra = 0;
|
||||
tc->blockNode = pn1;
|
||||
}
|
||||
|
||||
|
||||
pn = Variables(cx, ts, tc);
|
||||
if (!pn)
|
||||
return NULL;
|
||||
pn->pn_extra = PNX_POPVAR;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
@ -3172,7 +3183,7 @@ Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
|
||||
: JSPROP_PERMANENT;
|
||||
} else {
|
||||
args.obj = tc->topScopeStmt->blockObj;
|
||||
args.u.let.index = 0;
|
||||
args.u.let.index = OBJ_BLOCK_COUNT(cx, args.obj);
|
||||
args.u.let.overflow = JSMSG_TOO_MANY_FUN_VARS;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user