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
Родитель 810fc6c19f
Коммит 9744f8528f
5 изменённых файлов: 64 добавлений и 177 удалений

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

@ -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_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_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_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")

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

@ -56,7 +56,7 @@ JS_BEGIN_EXTERN_C
/* /*
* NB: If you add enumerators for scope statements, add them between STMT_WITH * 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 * non-looping statement enumerators, add them before STMT_DO_LOOP or you will
* break the STMT_TYPE_IS_LOOP macro. * break the STMT_TYPE_IS_LOOP macro.
* *
@ -66,10 +66,10 @@ typedef enum JSStmtType {
STMT_LABEL, /* labeled statement: L: s */ STMT_LABEL, /* labeled statement: L: s */
STMT_IF, /* if (then) statement */ STMT_IF, /* if (then) statement */
STMT_ELSE, /* else clause of if statement */ STMT_ELSE, /* else clause of if statement */
STMT_SWITCH, /* switch statement */
STMT_BODY, /* synthetic body of function with STMT_BODY, /* synthetic body of function with
destructuring formal parameters */ destructuring formal parameters */
STMT_BLOCK, /* compound statement: { s1[;... sN] } */ STMT_BLOCK, /* compound statement: { s1[;... sN] } */
STMT_SWITCH, /* switch statement */
STMT_WITH, /* with statement */ STMT_WITH, /* with statement */
STMT_CATCH, /* catch block */ STMT_CATCH, /* catch block */
STMT_TRY, /* try 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: * 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 * 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 * become, a lexical scope. Per the proposed JS2/ES4 spec, it includes only
* low-numbered "maybe" scope types) and excludes with (with has dynamic scope * syntactic blocks: block statements and try/catch/finally statements.
* pending the "reformed with" in ES4/JS2). It includes all try-catch-finally
* types, which are high-numbered maybe-scope types.
* *
* STMT_TYPE_LINKS_SCOPE tells whether a JSStmtInfo of the given type eagerly * 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 * links to other scoping statement info records. It excludes the the "maybe"
* "maybe" types, block and switch, as well as the try and both finally types, * type, block, as well as the try and both finally types, since try and the
* since try and the other trailing maybe-scope types don't need block scope * other trailing maybe-scope types don't need block scope unless they contain
* unless they contain let declarations. * let declarations.
* *
* We treat with as a static scope because it prevents lexical binding from * We treat WITH as a static scope because it prevents lexical binding from
* continuing further up the static scope chain. With the "reformed with" * continuing further up the static scope chain. With the "reformed with"
* proposal for JS2, we'll be able to model it statically, too. * proposal for JS2, we'll be able to model it statically, too.
*/ */
#define STMT_TYPE_MAYBE_SCOPE(type) \ #define STMT_TYPE_MAYBE_SCOPE(type) \
@ -141,8 +139,8 @@ struct JSStmtInfo {
/* /*
* To reuse space in JSStmtInfo, rename breaks and continues for use during * To reuse space in JSStmtInfo, rename breaks and continues for use during
* try/catch/finally code generation and backpatching. To match most common * 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 * 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, * 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 * and only a for loop has an update backpatch chain, so it's safe to overlay
* these for the "trying" JSStmtTypes. * 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 * 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. * "tops-of-stack" space above their codeMark, noteMark, and tempMark points.
* This means you cannot alloc from tempPool and save the pointer beyond the * This means you cannot alloc from tempPool and save the pointer beyond the
* next JS_FinishCodeGenerator. * next JS_FinishCodeGenerator.
@ -445,7 +443,7 @@ js_PushStatement(JSTreeContext *tc, JSStmtInfo *stmt, JSStmtType type,
ptrdiff_t top); 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 * this statement info record, use js_PopStatement as usual, or if appropriate
* (if generating code), js_PopStatementCG. * (if generating code), js_PopStatementCG.
*/ */
@ -454,7 +452,7 @@ js_PushBlockScope(JSTreeContext *tc, JSStmtInfo *stmt, JSObject *blockObj,
ptrdiff_t top); 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. * is up to the caller to free it.
*/ */
extern void 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. * Define and lookup a primitive jsval associated with the const named by atom.
* js_DefineCompileTimeConstant analyzes the constant-folded initializer at pn * 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 * 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 * 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 * 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 * value other than undefined if the constant was found, true with *vp set to
* JSVAL_VOID if not found, and false on error. * 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. * comprehension) named by atom, looking in tc's compile-time scopes.
* *
* If a WITH statement is reached along the scope stack, return its statement * 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. * 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 * 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, * scope chain must have had their depth slots computed by the code generator,
* so the caller must be under js_EmitTree. * so the caller must be under js_EmitTree.
* *
* In any event, directly return the statement info record in which atom was * In any event, directly return the statement info record in which atom was
* found. Otherwise return null. * found. Otherwise return null.
*/ */
extern JSStmtInfo * extern JSStmtInfo *
js_LexicalLookup(JSTreeContext *tc, JSAtom *atom, jsint *slotp, 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. * 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 * 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 * (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. * immediately after them, in note bytes or byte-triples.
* *
* Source Note Extended Delta * 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 * 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 * 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 * 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 * arity, offsetBias, and isSpanDep initializers in js_SrcNoteSpec. This is
* why SRC_IF and SRC_INITPROP have the same value below. For bad historical * 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 * reasons, some bytecodes below that could be overlayed have not been, but
* before using SRC_EXTENDED, consider compressing the existing note types. * before using SRC_EXTENDED, consider compressing the existing note types.
* *
@ -588,7 +586,7 @@ typedef enum JSSrcNoteType {
} 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 * 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 * 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 * 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 * 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 * 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 * within the array pointed at by cg->current->notes. Return -1 if out of
* memory. * memory.
*/ */
extern intN 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 * 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. * on malloc failure, which means this function reported an error.
* *
* To compute the number of jssrcnotes to allocate and pass in via notes, use * 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 * js_FinishTakingSrcNotes, SO DON'T CHANGE jsemit.c's js_FinishTakingSrcNotes
* FUNCTION WITHOUT CHECKING WHETHER THIS MACRO NEEDS CORRESPONDING CHANGES! * FUNCTION WITHOUT CHECKING WHETHER THIS MACRO NEEDS CORRESPONDING CHANGES!
*/ */

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

@ -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 { struct JSPrinter {
Sprinter sprinter; /* base class state */ Sprinter sprinter; /* base class state */
JSArenaPool pool; /* string allocation pool */ JSArenaPool pool; /* string allocation pool */
@ -625,10 +617,6 @@ struct JSPrinter {
jsbytecode *dvgfence; /* js_DecompileValueGenerator fencepost */ jsbytecode *dvgfence; /* js_DecompileValueGenerator fencepost */
JSFunction *fun; /* interpreted function */ JSFunction *fun; /* interpreted function */
JSAtom **localNames; /* argument and variable names */ 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->grouped = (indent & JS_IN_GROUP_CONTEXT) != 0;
jp->script = NULL; jp->script = NULL;
jp->dvgfence = NULL; jp->dvgfence = NULL;
#if JS_HAS_BLOCK_SCOPE
jp->braceState = ALWAYS_BRACE;
jp->spaceOffset = -1;
#endif
jp->fun = fun; jp->fun = fun;
if (!fun || !FUN_INTERPRETED(fun) || fun->nargs + fun->u.i.nvars == 0) { if (!fun || !FUN_INTERPRETED(fun) || fun->nargs + fun->u.i.nvars == 0) {
jp->localNames = NULL; jp->localNames = NULL;
@ -712,55 +696,6 @@ VarPrefix(jssrcnote *sn)
return ""; 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 int
js_printf(JSPrinter *jp, const char *format, ...) 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 pretty-printing, expand magic tab into a run of jp->indent spaces. */
if (*format == '\t') { if (*format == '\t') {
format++; 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) if (jp->pretty && Sprint(&jp->sprinter, "%*s", jp->indent, "") < 0)
return -1; return -1;
} }
@ -1081,7 +976,7 @@ DecompileSwitch(SprintStack *ss, TableEntry *table, uintN tableLength,
off = isCondSwitch ? GetOff(ss, ss->top-1) : PopOff(ss, JSOP_NOP); off = isCondSwitch ? GetOff(ss, ss->top-1) : PopOff(ss, JSOP_NOP);
lval = OFF2STR(&ss->sprinter, off); lval = OFF2STR(&ss->sprinter, off);
js_printf(CLEAR_MAYBE_BRACE(jp), "\tswitch (%s) {\n", lval); js_printf(jp, "\tswitch (%s) {\n", lval);
if (tableLength) { if (tableLength) {
diff = table[0].offset - defaultOffset; diff = table[0].offset - defaultOffset;
@ -1970,7 +1865,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
tail = js_GetSrcNoteOffset(sn, 0) - 1; tail = js_GetSrcNoteOffset(sn, 0) - 1;
LOCAL_ASSERT(pc[tail] == JSOP_IFNE || LOCAL_ASSERT(pc[tail] == JSOP_IFNE ||
pc[tail] == JSOP_IFNEX); pc[tail] == JSOP_IFNEX);
js_printf(SET_MAYBE_BRACE(jp), "\tdo {\n"); js_printf(jp, "\tdo {\n");
jp->indent += 4; jp->indent += 4;
DECOMPILE_CODE(pc, tail); DECOMPILE_CODE(pc, tail);
jp->indent -= 4; jp->indent -= 4;
@ -2012,7 +1907,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
} }
/* Do the loop body. */ /* Do the loop body. */
js_printf(SET_MAYBE_BRACE(jp), ") {\n"); js_printf(jp, ") {\n");
jp->indent += 4; jp->indent += 4;
oplen = (cond) ? js_CodeSpec[pc[cond]].length : 0; oplen = (cond) ? js_CodeSpec[pc[cond]].length : 0;
DECOMPILE_CODE(pc + cond + oplen, next - cond - oplen); DECOMPILE_CODE(pc + cond + oplen, next - cond - oplen);
@ -2030,7 +1925,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
if (!rval) if (!rval)
return NULL; return NULL;
RETRACT(&ss->sprinter, rval); RETRACT(&ss->sprinter, rval);
js_printf(CLEAR_MAYBE_BRACE(jp), "\t%s:\n", rval); js_printf(jp, "\t%s:\n", rval);
jp->indent += 4; jp->indent += 4;
break; break;
@ -2040,7 +1935,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
if (!rval) if (!rval)
return NULL; return NULL;
RETRACT(&ss->sprinter, rval); RETRACT(&ss->sprinter, rval);
js_printf(CLEAR_MAYBE_BRACE(jp), "\t%s: {\n", rval); js_printf(jp, "\t%s: {\n", rval);
jp->indent += 4; jp->indent += 4;
break; break;
@ -2069,7 +1964,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
break; break;
case SRC_BRACE: case SRC_BRACE:
js_printf(CLEAR_MAYBE_BRACE(jp), "\t{\n"); js_printf(jp, "\t{\n");
jp->indent += 4; jp->indent += 4;
len = js_GetSrcNoteOffset(sn, 0); len = js_GetSrcNoteOffset(sn, 0);
DECOMPILE_CODE(pc + oplen, len - oplen); DECOMPILE_CODE(pc + oplen, len - oplen);
@ -2138,14 +2033,14 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
break; break;
case JSOP_TRY: case JSOP_TRY:
js_printf(CLEAR_MAYBE_BRACE(jp), "\ttry {\n"); js_printf(jp, "\ttry {\n");
jp->indent += 4; jp->indent += 4;
todo = -2; todo = -2;
break; break;
case JSOP_FINALLY: case JSOP_FINALLY:
jp->indent -= 4; jp->indent -= 4;
js_printf(CLEAR_MAYBE_BRACE(jp), "\t} finally {\n"); js_printf(jp, "\t} finally {\n");
jp->indent += 4; 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, * If control flow reaches this point with todo still -2,
* just print rval as an expression statement. * just print rval as an expression statement.
*/ */
if (todo == -2) { if (todo == -2)
MAYBE_SET_DONT_BRACE(jp, pc, endpc, rval);
js_printf(jp, "\t%s;\n", rval); js_printf(jp, "\t%s;\n", rval);
}
end_popn: end_popn:
break; break;
} }
@ -2378,8 +2271,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
#endif #endif
len = js_GetSrcNoteOffset(sn, 0); len = js_GetSrcNoteOffset(sn, 0);
if (pc[len] == JSOP_LEAVEBLOCK) { if (pc[len] == JSOP_LEAVEBLOCK) {
js_printf(CLEAR_MAYBE_BRACE(jp), "\tlet (%s) {\n", js_printf(jp, "\tlet (%s) {\n", POP_STR());
POP_STR());
jp->indent += 4; jp->indent += 4;
DECOMPILE_CODE(pc, len); DECOMPILE_CODE(pc, len);
jp->indent -= 4; jp->indent -= 4;
@ -2422,7 +2314,6 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
* not appear in the decompiler's output. * not appear in the decompiler's output.
*/ */
if (*rval != '\0' && (rval[0] != '/' || rval[1] != '*')) { if (*rval != '\0' && (rval[0] != '/' || rval[1] != '*')) {
MAYBE_SET_DONT_BRACE(jp, pc, endpc, rval);
js_printf(jp, js_printf(jp,
(*rval == '{' || (*rval == '{' ||
(strncmp(rval, js_function_str, 8) == 0 && (strncmp(rval, js_function_str, 8) == 0 &&
@ -2451,7 +2342,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
case JSOP_ENTERWITH: case JSOP_ENTERWITH:
LOCAL_ASSERT(!js_GetSrcNote(jp->script, pc)); LOCAL_ASSERT(!js_GetSrcNote(jp->script, pc));
rval = POP_STR(); rval = POP_STR();
js_printf(SET_MAYBE_BRACE(jp), "\twith (%s) {\n", rval); js_printf(jp, "\twith (%s) {\n", rval);
jp->indent += 4; jp->indent += 4;
todo = Sprint(&ss->sprinter, with_cookie); todo = Sprint(&ss->sprinter, with_cookie);
break; break;
@ -2505,7 +2396,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
switch (sn ? SN_TYPE(sn) : SRC_NULL) { switch (sn ? SN_TYPE(sn) : SRC_NULL) {
#if JS_HAS_BLOCK_SCOPE #if JS_HAS_BLOCK_SCOPE
case SRC_BRACE: case SRC_BRACE:
js_printf(CLEAR_MAYBE_BRACE(jp), "\t{\n"); js_printf(jp, "\t{\n");
jp->indent += 4; jp->indent += 4;
len = js_GetSrcNoteOffset(sn, 0); len = js_GetSrcNoteOffset(sn, 0);
ok = Decompile(ss, pc + oplen, len - oplen, JSOP_NOP) 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: case SRC_CATCH:
jp->indent -= 4; jp->indent -= 4;
js_printf(CLEAR_MAYBE_BRACE(jp), "\t} catch ("); js_printf(jp, "\t} catch (");
pc2 = pc; pc2 = pc;
pc += oplen; pc += oplen;
@ -2862,7 +2753,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
tail = js_GetSrcNoteOffset(sn, 0); tail = js_GetSrcNoteOffset(sn, 0);
DECOMPILE_CODE(pc + cond, tail - cond); DECOMPILE_CODE(pc + cond, tail - cond);
rval = POP_STR(); rval = POP_STR();
js_printf(SET_MAYBE_BRACE(jp), "\twhile (%s) {\n", rval); js_printf(jp, "\twhile (%s) {\n", rval);
jp->indent += 4; jp->indent += 4;
DECOMPILE_CODE(pc + oplen, cond - oplen); DECOMPILE_CODE(pc + oplen, cond - oplen);
jp->indent -= 4; jp->indent -= 4;
@ -2926,7 +2817,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
return NULL; return NULL;
AddParenSlop(ss); AddParenSlop(ss);
} else { } else {
js_printf(SET_MAYBE_BRACE(jp), js_printf(jp,
elseif ? " if (%s) {\n" : "\tif (%s) {\n", elseif ? " if (%s) {\n" : "\tif (%s) {\n",
rval); rval);
jp->indent += 4; jp->indent += 4;
@ -2961,7 +2852,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
goto if_again; goto if_again;
} }
js_printf(SET_MAYBE_BRACE(jp), " {\n"); js_printf(jp, " {\n");
jp->indent += 4; jp->indent += 4;
DECOMPILE_CODE(pc + oplen, len - oplen); DECOMPILE_CODE(pc + oplen, len - oplen);
} }
@ -3155,8 +3046,7 @@ Decompile(SprintStack *ss, jsbytecode *pc, intN nb, JSOp nextop)
AddParenSlop(ss); AddParenSlop(ss);
DECOMPILE_CODE(pc + oplen, tail - oplen); DECOMPILE_CODE(pc + oplen, tail - oplen);
} else { } else {
js_printf(SET_MAYBE_BRACE(jp), "\t%s in %s) {\n", js_printf(jp, "\t%s in %s) {\n", lval, rval);
lval, rval);
jp->indent += 4; jp->indent += 4;
DECOMPILE_CODE(pc + oplen, tail - oplen); DECOMPILE_CODE(pc + oplen, tail - oplen);
jp->indent -= 4; jp->indent -= 4;

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

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

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

@ -560,7 +560,8 @@ js_ReportCompileErrorNumber(JSContext *cx, JSTokenStream *ts, JSParseNode *pn,
goto report; goto report;
tp = &pn->pn_pos; tp = &pn->pn_pos;
} else { } 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; report.lineno = ts->lineno;
linelength = PTRDIFF(ts->linebuf.limit, ts->linebuf.base, jschar); linelength = PTRDIFF(ts->linebuf.limit, ts->linebuf.base, jschar);