Track ES4 proposal by restricting let declaration to be direct child of block (408957, r=mrbkap).

This commit is contained in:
brendan@mozilla.org 2008-01-04 17:34:11 -08:00
parent 4a4b67cfc4
commit cfbfe3c2cd
5 changed files with 64 additions and 177 deletions

View File

@ -302,3 +302,4 @@ MSG_DEF(JSMSG_NON_LIST_XML_METHOD, 219, 2, JSEXN_TYPEERR, "cannot call {0} me
MSG_DEF(JSMSG_BAD_DELETE_OPERAND, 220, 0, JSEXN_SYNTAXERR, "invalid delete operand")
MSG_DEF(JSMSG_BAD_INCOP_OPERAND, 221, 0, JSEXN_SYNTAXERR, "invalid increment/decrement operand")
MSG_DEF(JSMSG_NULL_OR_UNDEFINED, 222, 2, JSEXN_TYPEERR, "{0} is {1}")
MSG_DEF(JSMSG_LET_DECL_NOT_IN_BLOCK, 223, 0, JSEXN_SYNTAXERR, "let declaration not directly within block")

View File

@ -56,7 +56,7 @@ JS_BEGIN_EXTERN_C
/*
* NB: If you add enumerators for scope statements, add them between STMT_WITH
* and STMT_CATCH, or you will break the STMT_TYPE_IS_SCOPE macro. If you add
* and STMT_CATCH, or you will break the STMT_TYPE_IS_SCOPE macro. If you add
* non-looping statement enumerators, add them before STMT_DO_LOOP or you will
* break the STMT_TYPE_IS_LOOP macro.
*
@ -66,10 +66,10 @@ typedef enum JSStmtType {
STMT_LABEL, /* labeled statement: L: s */
STMT_IF, /* if (then) statement */
STMT_ELSE, /* else clause of if statement */
STMT_SWITCH, /* switch statement */
STMT_BODY, /* synthetic body of function with
destructuring formal parameters */
STMT_BLOCK, /* compound statement: { s1[;... sN] } */
STMT_SWITCH, /* switch statement */
STMT_WITH, /* with statement */
STMT_CATCH, /* catch block */
STMT_TRY, /* try block */
@ -87,19 +87,17 @@ typedef enum JSStmtType {
* A comment on the encoding of the JSStmtType enum and type-testing macros:
*
* STMT_TYPE_MAYBE_SCOPE tells whether a statement type is always, or may
* become, a lexical scope. It therefore includes block and switch (the two
* low-numbered "maybe" scope types) and excludes with (with has dynamic scope
* pending the "reformed with" in ES4/JS2). It includes all try-catch-finally
* types, which are high-numbered maybe-scope types.
* become, a lexical scope. Per the proposed JS2/ES4 spec, it includes only
* syntactic blocks: block statements and try/catch/finally statements.
*
* STMT_TYPE_LINKS_SCOPE tells whether a JSStmtInfo of the given type eagerly
* links to other scoping statement info records. It excludes the two early
* "maybe" types, block and switch, as well as the try and both finally types,
* since try and the other trailing maybe-scope types don't need block scope
* unless they contain let declarations.
* links to other scoping statement info records. It excludes the the "maybe"
* type, block, as well as the try and both finally types, since try and the
* other trailing maybe-scope types don't need block scope unless they contain
* let declarations.
*
* We treat with as a static scope because it prevents lexical binding from
* continuing further up the static scope chain. With the "reformed with"
* We treat WITH as a static scope because it prevents lexical binding from
* continuing further up the static scope chain. With the "reformed with"
* proposal for JS2, we'll be able to model it statically, too.
*/
#define STMT_TYPE_MAYBE_SCOPE(type) \
@ -141,8 +139,8 @@ struct JSStmtInfo {
/*
* To reuse space in JSStmtInfo, rename breaks and continues for use during
* try/catch/finally code generation and backpatching. To match most common
* use cases, the macro argument is a struct, not a struct pointer. Only a
* try/catch/finally code generation and backpatching. To match most common
* use cases, the macro argument is a struct, not a struct pointer. Only a
* loop, switch, or label statement info record can have breaks and continues,
* and only a for loop has an update backpatch chain, so it's safe to overlay
* these for the "trying" JSStmtTypes.
@ -373,7 +371,7 @@ js_InitCodeGenerator(JSContext *cx, JSCodeGenerator *cg, JSParseContext *pc,
/*
* Release cg->codePool, cg->notePool, and cx->tempPool to marks set by
* js_InitCodeGenerator. Note that cgs are magic: they own the arena pool
* js_InitCodeGenerator. Note that cgs are magic: they own the arena pool
* "tops-of-stack" space above their codeMark, noteMark, and tempMark points.
* This means you cannot alloc from tempPool and save the pointer beyond the
* next JS_FinishCodeGenerator.
@ -445,7 +443,7 @@ js_PushStatement(JSTreeContext *tc, JSStmtInfo *stmt, JSStmtType type,
ptrdiff_t top);
/*
* Push a block scope statement and link blockObj into tc->blockChain. To pop
* Push a block scope statement and link blockObj into tc->blockChain. To pop
* this statement info record, use js_PopStatement as usual, or if appropriate
* (if generating code), js_PopStatementCG.
*/
@ -454,7 +452,7 @@ js_PushBlockScope(JSTreeContext *tc, JSStmtInfo *stmt, JSObject *blockObj,
ptrdiff_t top);
/*
* Pop tc->topStmt. If the top JSStmtInfo struct is not stack-allocated, it
* Pop tc->topStmt. If the top JSStmtInfo struct is not stack-allocated, it
* is up to the caller to free it.
*/
extern void
@ -472,10 +470,10 @@ js_PopStatementCG(JSContext *cx, JSCodeGenerator *cg);
* Define and lookup a primitive jsval associated with the const named by atom.
* js_DefineCompileTimeConstant analyzes the constant-folded initializer at pn
* and saves the const's value in cg->constList, if it can be used at compile
* time. It returns true unless an error occurred.
* time. It returns true unless an error occurred.
*
* If the initializer's value could not be saved, js_DefineCompileTimeConstant
* calls will return the undefined value. js_DefineCompileTimeConstant tries
* calls will return the undefined value. js_DefineCompileTimeConstant tries
* to find a const value memorized for atom, returning true with *vp set to a
* value other than undefined if the constant was found, true with *vp set to
* JSVAL_VOID if not found, and false on error.
@ -489,14 +487,14 @@ js_DefineCompileTimeConstant(JSContext *cx, JSCodeGenerator *cg, JSAtom *atom,
* comprehension) named by atom, looking in tc's compile-time scopes.
*
* If a WITH statement is reached along the scope stack, return its statement
* info record, so callers can tell that atom is ambiguous. If slotp is not
* info record, so callers can tell that atom is ambiguous. If slotp is not
* null, then if atom is found, set *slotp to its stack slot, otherwise to -1.
* This means that if slotp is not null, all the block objects on the lexical
* scope chain must have had their depth slots computed by the code generator,
* so the caller must be under js_EmitTree.
*
* In any event, directly return the statement info record in which atom was
* found. Otherwise return null.
* found. Otherwise return null.
*/
extern JSStmtInfo *
js_LexicalLookup(JSTreeContext *tc, JSAtom *atom, jsint *slotp,
@ -517,9 +515,9 @@ js_EmitFunctionScript(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body);
/*
* Source notes generated along with bytecode for decompiling and debugging.
* A source note is a uint8 with 5 bits of type and 3 of offset from the pc of
* the previous note. If 3 bits of offset aren't enough, extended delta notes
* the previous note. If 3 bits of offset aren't enough, extended delta notes
* (SRC_XDELTA) consisting of 2 set high order bits followed by 6 offset bits
* are emitted before the next note. Some notes have operand offsets encoded
* are emitted before the next note. Some notes have operand offsets encoded
* immediately after them, in note bytes or byte-triples.
*
* Source Note Extended Delta
@ -536,8 +534,8 @@ js_EmitFunctionScript(JSContext *cx, JSCodeGenerator *cg, JSParseNode *body);
* Note on adding new source notes: every pair of bytecodes (A, B) where A and
* B have disjoint sets of source notes that could apply to each bytecode may
* reuse the same note type value for two notes (snA, snB) that have the same
* arity, offsetBias, and isSpanDep initializers in js_SrcNoteSpec. This is
* why SRC_IF and SRC_INITPROP have the same value below. For bad historical
* arity, offsetBias, and isSpanDep initializers in js_SrcNoteSpec. This is
* why SRC_IF and SRC_INITPROP have the same value below. For bad historical
* reasons, some bytecodes below that could be overlayed have not been, but
* before using SRC_EXTENDED, consider compressing the existing note types.
*
@ -588,7 +586,7 @@ typedef enum JSSrcNoteType {
} JSSrcNoteType;
/*
* Constants for the SRC_DECL source note. Note that span-dependent bytecode
* Constants for the SRC_DECL source note. Note that span-dependent bytecode
* selection means that any SRC_DECL offset greater than SRC_DECL_LET may need
* to be adjusted, but these "offsets" are too small to span a span-dependent
* instruction, so can be used to denote distinct declaration syntaxes to the
@ -662,8 +660,8 @@ extern JS_FRIEND_API(uintN) js_SrcNoteLength(jssrcnote *sn);
/*
* Append a new source note of the given type (and therefore size) to cg's
* notes dynamic array, updating cg->noteCount. Return the new note's index
* within the array pointed at by cg->current->notes. Return -1 if out of
* notes dynamic array, updating cg->noteCount. Return the new note's index
* within the array pointed at by cg->current->notes. Return -1 if out of
* memory.
*/
extern intN
@ -696,11 +694,11 @@ js_SetSrcNoteOffset(JSContext *cx, JSCodeGenerator *cg, uintN index,
/*
* Finish taking source notes in cx's notePool, copying final notes to the new
* stable store allocated by the caller and passed in via notes. Return false
* stable store allocated by the caller and passed in via notes. Return false
* on malloc failure, which means this function reported an error.
*
* To compute the number of jssrcnotes to allocate and pass in via notes, use
* the CG_COUNT_FINAL_SRCNOTES macro. This macro knows a lot about details of
* the CG_COUNT_FINAL_SRCNOTES macro. This macro knows a lot about details of
* js_FinishTakingSrcNotes, SO DON'T CHANGE jsemit.c's js_FinishTakingSrcNotes
* FUNCTION WITHOUT CHECKING WHETHER THIS MACRO NEEDS CORRESPONDING CHANGES!
*/

View File

@ -607,14 +607,6 @@ js_QuoteString(JSContext *cx, JSString *str, jschar quote)
/************************************************************************/
#if JS_HAS_BLOCK_SCOPE
typedef enum JSBraceState {
ALWAYS_BRACE,
MAYBE_BRACE,
DONT_BRACE
} JSBraceState;
#endif
struct JSPrinter {
Sprinter sprinter; /* base class state */
JSArenaPool pool; /* string allocation pool */
@ -625,10 +617,6 @@ struct JSPrinter {
jsbytecode *dvgfence; /* js_DecompileValueGenerator fencepost */
JSFunction *fun; /* interpreted function */
JSAtom **localNames; /* argument and variable names */
#if JS_HAS_BLOCK_SCOPE
JSBraceState braceState; /* remove braces around let declaration */
ptrdiff_t spaceOffset; /* -1 or offset of space before maybe-{ */
#endif
};
/*
@ -655,10 +643,6 @@ JS_NEW_PRINTER(JSContext *cx, const char *name, JSFunction *fun,
jp->grouped = (indent & JS_IN_GROUP_CONTEXT) != 0;
jp->script = NULL;
jp->dvgfence = NULL;
#if JS_HAS_BLOCK_SCOPE
jp->braceState = ALWAYS_BRACE;
jp->spaceOffset = -1;
#endif
jp->fun = fun;
if (!fun || !FUN_INTERPRETED(fun) || fun->nargs + fun->u.i.nvars == 0) {
jp->localNames = NULL;
@ -712,55 +696,6 @@ VarPrefix(jssrcnote *sn)
return "";
}
#if !JS_HAS_BLOCK_SCOPE
# define SET_MAYBE_BRACE(jp) jp
# define CLEAR_MAYBE_BRACE(jp) jp
# define MAYBE_SET_DONT_BRACE(jp,pc,endpc,rval) /* nothing */
#else
# define SET_MAYBE_BRACE(jp) ((jp)->braceState = MAYBE_BRACE, (jp))
# define CLEAR_MAYBE_BRACE(jp) ((jp)->braceState = ALWAYS_BRACE, (jp))
# define MAYBE_SET_DONT_BRACE MaybeSetDontBrace
static void
SetDontBrace(JSPrinter *jp)
{
ptrdiff_t offset;
const char *bp;
/* When not pretty-printing, newline after brace is chopped. */
JS_ASSERT(jp->spaceOffset < 0);
offset = jp->sprinter.offset - (jp->pretty ? 3 : 2);
/* The shortest case is "if (x) {". */
JS_ASSERT(offset >= 6);
bp = jp->sprinter.base;
if (bp[offset+0] == ' ' && bp[offset+1] == '{') {
JS_ASSERT(!jp->pretty || bp[offset+2] == '\n');
jp->spaceOffset = offset;
jp->braceState = DONT_BRACE;
}
}
/*
* If a let declaration is the only child of a control structure that does not
* require braces, it must not be braced. If it were braced explicitly, then it
* would be bracketed by JSOP_ENTERBLOCK/JSOP_LEAVEBLOCK.
*/
static void
MaybeSetDontBrace(JSPrinter *jp, jsbytecode *pc, jsbytecode *endpc,
const char *rval)
{
JS_ASSERT(*pc == JSOP_POP || *pc == JSOP_POPV || *pc == JSOP_POPN);
if (jp->braceState == MAYBE_BRACE &&
pc + js_CodeSpec[*pc].length == endpc &&
!strncmp(rval, var_prefix[SRC_DECL_LET], 4) &&
rval[4] != '(') {
SetDontBrace(jp);
}
}
#endif
int
js_printf(JSPrinter *jp, const char *format, ...)
{
@ -776,46 +711,6 @@ js_printf(JSPrinter *jp, const char *format, ...)
/* If pretty-printing, expand magic tab into a run of jp->indent spaces. */
if (*format == '\t') {
format++;
#if JS_HAS_BLOCK_SCOPE
if (*format == '}' && jp->braceState != ALWAYS_BRACE) {
JSBraceState braceState;
braceState = jp->braceState;
jp->braceState = ALWAYS_BRACE;
if (braceState == DONT_BRACE) {
ptrdiff_t offset, delta, from;
JS_ASSERT(format[1] == '\n' || format[1] == ' ');
offset = jp->spaceOffset;
JS_ASSERT(offset >= 6);
/* Replace " {\n" at the end of jp->sprinter with "\n". */
bp = jp->sprinter.base;
if (bp[offset+0] == ' ' && bp[offset+1] == '{') {
delta = 2;
if (jp->pretty) {
/* If pretty, we don't have to worry about 'else'. */
JS_ASSERT(bp[offset+2] == '\n');
} else if (bp[offset-1] != ')') {
/* Must keep ' ' to avoid 'dolet' or 'elselet'. */
++offset;
delta = 1;
}
from = offset + delta;
memmove(bp + offset, bp + from, jp->sprinter.offset - from);
jp->sprinter.offset -= delta;
jp->spaceOffset = -1;
format += 2;
if (*format == '\0')
return 0;
}
}
}
#endif
if (jp->pretty && Sprint(&jp->sprinter, "%*s", jp->indent, "") < 0)
return -1;
}
@ -1081,7 +976,7 @@ DecompileSwitch(SprintStack *ss, TableEntry *table, uintN tableLength,
off = isCondSwitch ? GetOff(ss, ss->top-1) : PopOff(ss, JSOP_NOP);
lval = OFF2STR(&ss->sprinter, off);
js_printf(CLEAR_MAYBE_BRACE(jp), "\tswitch (%s) {\n", lval);
js_printf(jp, "\tswitch (%s) {\n", lval);
if (tableLength) {
diff = table[0].offset - defaultOffset;
@ -1970,7 +1865,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
tail = js_GetSrcNoteOffset(sn, 0) - 1;
LOCAL_ASSERT(pc[tail] == JSOP_IFNE ||
pc[tail] == JSOP_IFNEX);
js_printf(SET_MAYBE_BRACE(jp), "\tdo {\n");
js_printf(jp, "\tdo {\n");
jp->indent += 4;
DECOMPILE_CODE(pc, tail);
jp->indent -= 4;
@ -2012,7 +1907,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
}
/* Do the loop body. */
js_printf(SET_MAYBE_BRACE(jp), ") {\n");
js_printf(jp, ") {\n");
jp->indent += 4;
oplen = (cond) ? js_CodeSpec[pc[cond]].length : 0;
DECOMPILE_CODE(pc + cond + oplen, next - cond - oplen);
@ -2030,7 +1925,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
if (!rval)
return NULL;
RETRACT(&ss->sprinter, rval);
js_printf(CLEAR_MAYBE_BRACE(jp), "\t%s:\n", rval);
js_printf(jp, "\t%s:\n", rval);
jp->indent += 4;
break;
@ -2040,7 +1935,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
if (!rval)
return NULL;
RETRACT(&ss->sprinter, rval);
js_printf(CLEAR_MAYBE_BRACE(jp), "\t%s: {\n", rval);
js_printf(jp, "\t%s: {\n", rval);
jp->indent += 4;
break;
@ -2069,7 +1964,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
break;
case SRC_BRACE:
js_printf(CLEAR_MAYBE_BRACE(jp), "\t{\n");
js_printf(jp, "\t{\n");
jp->indent += 4;
len = js_GetSrcNoteOffset(sn, 0);
DECOMPILE_CODE(pc + oplen, len - oplen);
@ -2138,14 +2033,14 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
break;
case JSOP_TRY:
js_printf(CLEAR_MAYBE_BRACE(jp), "\ttry {\n");
js_printf(jp, "\ttry {\n");
jp->indent += 4;
todo = -2;
break;
case JSOP_FINALLY:
jp->indent -= 4;
js_printf(CLEAR_MAYBE_BRACE(jp), "\t} finally {\n");
js_printf(jp, "\t} finally {\n");
jp->indent += 4;
/*
@ -2296,10 +2191,8 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
* If control flow reaches this point with todo still -2,
* just print rval as an expression statement.
*/
if (todo == -2) {
MAYBE_SET_DONT_BRACE(jp, pc, endpc, rval);
if (todo == -2)
js_printf(jp, "\t%s;\n", rval);
}
end_popn:
break;
}
@ -2378,8 +2271,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
#endif
len = js_GetSrcNoteOffset(sn, 0);
if (pc[len] == JSOP_LEAVEBLOCK) {
js_printf(CLEAR_MAYBE_BRACE(jp), "\tlet (%s) {\n",
POP_STR());
js_printf(jp, "\tlet (%s) {\n", POP_STR());
jp->indent += 4;
DECOMPILE_CODE(pc, len);
jp->indent -= 4;
@ -2422,7 +2314,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
* not appear in the decompiler's output.
*/
if (*rval != '\0' && (rval[0] != '/' || rval[1] != '*')) {
MAYBE_SET_DONT_BRACE(jp, pc, endpc, rval);
js_printf(jp,
(*rval == '{' ||
(strncmp(rval, js_function_str, 8) == 0 &&
@ -2451,7 +2342,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
case JSOP_ENTERWITH:
LOCAL_ASSERT(!js_GetSrcNote(jp->script, pc));
rval = POP_STR();
js_printf(SET_MAYBE_BRACE(jp), "\twith (%s) {\n", rval);
js_printf(jp, "\twith (%s) {\n", rval);
jp->indent += 4;
todo = Sprint(&ss->sprinter, with_cookie);
break;
@ -2505,7 +2396,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
switch (sn ? SN_TYPE(sn) : SRC_NULL) {
#if JS_HAS_BLOCK_SCOPE
case SRC_BRACE:
js_printf(CLEAR_MAYBE_BRACE(jp), "\t{\n");
js_printf(jp, "\t{\n");
jp->indent += 4;
len = js_GetSrcNoteOffset(sn, 0);
ok = Decompile(ss, pc + oplen, len - oplen, JSOP_NOP)
@ -2519,7 +2410,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
case SRC_CATCH:
jp->indent -= 4;
js_printf(CLEAR_MAYBE_BRACE(jp), "\t} catch (");
js_printf(jp, "\t} catch (");
pc2 = pc;
pc += oplen;
@ -2862,7 +2753,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
tail = js_GetSrcNoteOffset(sn, 0);
DECOMPILE_CODE(pc + cond, tail - cond);
rval = POP_STR();
js_printf(SET_MAYBE_BRACE(jp), "\twhile (%s) {\n", rval);
js_printf(jp, "\twhile (%s) {\n", rval);
jp->indent += 4;
DECOMPILE_CODE(pc + oplen, cond - oplen);
jp->indent -= 4;
@ -2926,7 +2817,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
return NULL;
AddParenSlop(ss);
} else {
js_printf(SET_MAYBE_BRACE(jp),
js_printf(jp,
elseif ? " if (%s) {\n" : "\tif (%s) {\n",
rval);
jp->indent += 4;
@ -2961,7 +2852,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
goto if_again;
}
js_printf(SET_MAYBE_BRACE(jp), " {\n");
js_printf(jp, " {\n");
jp->indent += 4;
DECOMPILE_CODE(pc + oplen, len - oplen);
}
@ -3155,8 +3046,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
AddParenSlop(ss);
DECOMPILE_CODE(pc + oplen, tail - oplen);
} else {
js_printf(SET_MAYBE_BRACE(jp), "\t%s in %s) {\n",
lval, rval);
js_printf(jp, "\t%s in %s) {\n", lval, rval);
jp->indent += 4;
DECOMPILE_CODE(pc + oplen, tail - oplen);
jp->indent -= 4;

View File

@ -2254,7 +2254,7 @@ PushLexicalScope(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
{
JSParseNode *pn;
JSObject *obj;
JSParsedObjectBox *blockPob;
JSParsedObjectBox *blockpob;
pn = NewParseNode(cx, ts, PN_NAME, tc);
if (!pn)
@ -2264,14 +2264,14 @@ PushLexicalScope(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,
if (!obj)
return NULL;
blockPob = js_NewParsedObjectBox(cx, tc->parseContext, obj);
if (!blockPob)
blockpob = js_NewParsedObjectBox(cx, tc->parseContext, obj);
if (!blockpob)
return NULL;
js_PushBlockScope(tc, stmtInfo, obj, -1);
pn->pn_type = TOK_LEXICALSCOPE;
pn->pn_op = JSOP_LEAVEBLOCK;
pn->pn_pob = blockPob;
pn->pn_pob = blockpob;
pn->pn_slot = -1;
return pn;
}
@ -3174,9 +3174,8 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
#if JS_HAS_BLOCK_SCOPE
case TOK_LET:
{
JSStmtInfo **sip;
JSObject *obj;
JSParsedObjectBox *blockPob;
JSParsedObjectBox *blockpob;
/* Check for a let statement or let expression. */
if (js_PeekToken(cx, ts) == TOK_LP) {
@ -3199,12 +3198,11 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
* scope statement) then we also need to set tc->blockNode to be our
* TOK_LEXICALSCOPE.
*/
sip = &tc->topScopeStmt;
for (stmt = tc->topStmt; stmt; stmt = stmt->down) {
if (STMT_MAYBE_SCOPE(stmt))
break;
if (stmt == *sip)
sip = &stmt->downScope;
stmt = tc->topStmt;
if (stmt && !STMT_MAYBE_SCOPE(stmt)) {
js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,
JSMSG_LET_DECL_NOT_IN_BLOCK);
return NULL;
}
if (stmt && (stmt->flags & SIF_SCOPE)) {
@ -3236,8 +3234,8 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
obj = js_NewBlockObject(cx);
if (!obj)
return NULL;
blockPob = js_NewParsedObjectBox(cx, tc->parseContext, obj);
if (!blockPob)
blockpob = js_NewParsedObjectBox(cx, tc->parseContext, obj);
if (!blockpob)
return NULL;
/*
@ -3248,14 +3246,13 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
*/
JS_ASSERT(!(stmt->flags & SIF_SCOPE));
stmt->flags |= SIF_SCOPE;
if (stmt != *sip) {
if (stmt != tc->topScopeStmt) {
JS_ASSERT(!stmt->downScope);
JS_ASSERT(stmt->type == STMT_BLOCK ||
stmt->type == STMT_SWITCH ||
stmt->type == STMT_TRY ||
stmt->type == STMT_FINALLY);
stmt->downScope = *sip;
*sip = stmt;
stmt->downScope = tc->topScopeStmt;
tc->topScopeStmt = stmt;
} else {
JS_ASSERT(stmt->type == STMT_CATCH);
JS_ASSERT(stmt->downScope);
@ -3278,7 +3275,7 @@ Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc)
pn1->pn_type = TOK_LEXICALSCOPE;
pn1->pn_op = JSOP_LEAVEBLOCK;
pn1->pn_pos = tc->blockNode->pn_pos;
pn1->pn_pob = blockPob;
pn1->pn_pob = blockpob;
pn1->pn_expr = tc->blockNode;
pn1->pn_slot = -1;
tc->blockNode = pn1;

View File

@ -560,7 +560,8 @@ js_ReportCompileErrorNumber(JSContext *cx, JSTokenStream *ts, JSParseNode *pn,
goto report;
tp = &pn->pn_pos;
} else {
tp = &ts->tokens[(ts->cursor+ts->lookahead) & NTOKENS_MASK].pos;
/* Point to the current token, not the next one to get. */
tp = &ts->tokens[ts->cursor].pos;
}
report.lineno = ts->lineno;
linelength = PTRDIFF(ts->linebuf.limit, ts->linebuf.base, jschar);