if (!pn || js_Emit1(cx, &funcg, JSOP_STOP) < 0) {
if (!pn) {
static JSParser UnaryExpr;static JSMemberParser MemberExpr;static JSParser PrimaryExpr;/* * Insist that the next token be of type tt, or report errno and return null. * NB: this macro uses cx and ts from its lexical environment. */#define MUST_MATCH_TOKEN(tt, errno)                                           \    JS_BEGIN_MACRO                                                            \        if (js_GetToken(cx, ts) != tt) {                                      \            js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR, \                            errno);                                           \            return NULL;                                                      \        }                                                                     \    JS_END_MACRO#define CHECK_RECURSION()                                                     \    JS_BEGIN_MACRO                                                            \        int stackDummy;                                                       \        if (!JS_CHECK_STACK_SIZE(cx, stackDummy)) {                           \            js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR, \                                        JSMSG_OVER_RECURSED);                 \            return NULL;                                                      \        }                                                                     \    JS_END_MACRO#ifdef METER_PARSENODESstatic uint32 parsenodes = 0;static uint32 maxparsenodes = 0;static uint32 recyclednodes = 0;#endifstatic JSParseNode *RecycleTree(JSParseNode *pn, JSTreeContext *tc){    JSParseNode *next;    if (!pn)        return NULL;    JS_ASSERT(pn != tc->nodeList);      /* catch back-to-back dup recycles */    next = pn->pn_next;    pn->pn_next = tc->nodeList;    tc->nodeList = pn;#ifdef METER_PARSENODES    recyclednodes++;#endif    return next;}static JSParseNode *NewOrRecycledNode(JSContext *cx, JSTreeContext *tc){    JSParseNode *pn;    pn = tc->nodeList;    if (!pn) {        JS_ARENA_ALLOCATE_TYPE(pn, JSParseNode, &cx->tempPool);        if (!pn)            JS_ReportOutOfMemory(cx);    } else {        tc->nodeList = pn->pn_next;        /* Recycle immediate descendents only, to save work and working set. */        switch (pn->pn_arity) {          case PN_FUNC:            RecycleTree(pn->pn_body, tc);            break;          case PN_LIST:            if (pn->pn_head) {                /* XXX check for dup recycles in the list */                *pn->pn_tail = tc->nodeList;                tc->nodeList = pn->pn_head;#ifdef METER_PARSENODES                recyclednodes += pn->pn_count;#endif            }            break;          case PN_TERNARY:            RecycleTree(pn->pn_kid1, tc);            RecycleTree(pn->pn_kid2, tc);            RecycleTree(pn->pn_kid3, tc);            break;          case PN_BINARY:            RecycleTree(pn->pn_left, tc);            RecycleTree(pn->pn_right, tc);            break;          case PN_UNARY:            RecycleTree(pn->pn_kid, tc);            break;          case PN_NAME:            RecycleTree(pn->pn_expr, tc);            break;          case PN_NULLARY:            break;        }    }#ifdef METER_PARSENODES    if (pn) {        parsenodes++;        if (parsenodes - recyclednodes > maxparsenodes)            maxparsenodes = parsenodes - recyclednodes;    }#endif    return pn;}/* * Allocate a JSParseNode from cx's temporary arena. */static JSParseNode *NewParseNode(JSContext *cx, JSTokenStream *ts, JSParseNodeArity arity,             JSTreeContext *tc){    JSParseNode *pn;    JSToken *tp;    pn = NewOrRecycledNode(cx, tc);    if (!pn)        return NULL;    tp = &CURRENT_TOKEN(ts);    pn->pn_type = tp->type;    pn->pn_pos = tp->pos;    pn->pn_op = JSOP_NOP;    pn->pn_arity = arity;    pn->pn_next = NULL;#if JS_HAS_XML_SUPPORT    pn->pn_ts = ts;#endif    return pn;}static JSParseNode *NewBinary(JSContext *cx, JSTokenType tt,          JSOp op, JSParseNode *left, JSParseNode *right,          JSTreeContext *tc){    JSParseNode *pn, *pn1, *pn2;    if (!left || !right)        return NULL;    /*     * Flatten a left-associative (left-heavy) tree of a given operator into     * a list, to reduce js_FoldConstants and js_EmitTree recursion.     */    if (left->pn_type == tt &&        left->pn_op == op &&        (js_CodeSpec[op].format & JOF_LEFTASSOC)) {        if (left->pn_arity != PN_LIST) {            pn1 = left->pn_left, pn2 = left->pn_right;            left->pn_arity = PN_LIST;            PN_INIT_LIST_1(left, pn1);            PN_APPEND(left, pn2);            if (tt == TOK_PLUS) {                if (pn1->pn_type == TOK_STRING)                    left->pn_extra |= PNX_STRCAT;                else if (pn1->pn_type != TOK_NUMBER)                    left->pn_extra |= PNX_CANTFOLD;                if (pn2->pn_type == TOK_STRING)                    left->pn_extra |= PNX_STRCAT;                else if (pn2->pn_type != TOK_NUMBER)                    left->pn_extra |= PNX_CANTFOLD;            }        }        PN_APPEND(left, right);        left->pn_pos.end = right->pn_pos.end;        if (tt == TOK_PLUS) {            if (right->pn_type == TOK_STRING)                left->pn_extra |= PNX_STRCAT;            else if (right->pn_type != TOK_NUMBER)                left->pn_extra |= PNX_CANTFOLD;        }        return left;    }    /*     * Fold constant addition immediately, to conserve node space and, what's     * more, so js_FoldConstants never sees mixed addition and concatenation     * operations with more than one leading non-string operand in a PN_LIST     * generated for expressions such as 1 + 2 + "pt" (which should evaluate     * to "3pt", not "12pt").     */    if (tt == TOK_PLUS &&        left->pn_type == TOK_NUMBER &&        right->pn_type == TOK_NUMBER) {        left->pn_dval += right->pn_dval;        left->pn_pos.end = right->pn_pos.end;        RecycleTree(right, tc);        return left;    }    pn = NewOrRecycledNode(cx, tc);    if (!pn)        return NULL;    pn->pn_type = tt;    pn->pn_pos.begin = left->pn_pos.begin;    pn->pn_pos.end = right->pn_pos.end;    pn->pn_op = op;    pn->pn_arity = PN_BINARY;    pn->pn_left = left;    pn->pn_right = right;    pn->pn_next = NULL;#if JS_HAS_XML_SUPPORT    pn->pn_ts = NULL;#endif    return pn;}#if JS_HAS_GETTER_SETTERstatic JSTokenTypeCheckGetterOrSetter(JSContext *cx, JSTokenStream *ts, JSTokenType tt){    JSAtom *atom;    JSRuntime *rt;    JSOp op;    const char *name;    JS_ASSERT(CURRENT_TOKEN(ts).type == TOK_NAME);    atom = CURRENT_TOKEN(ts).t_atom;    rt = cx->runtime;    if (atom == rt->atomState.getterAtom)        op = JSOP_GETTER;    else if (atom == rt->atomState.setterAtom)        op = JSOP_SETTER;    else        return TOK_NAME;    if (js_PeekTokenSameLine(cx, ts) != tt)        return TOK_NAME;    (void) js_GetToken(cx, ts);    if (CURRENT_TOKEN(ts).t_op != JSOP_NOP) {        js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR,                                    JSMSG_BAD_GETTER_OR_SETTER,                                    (op == JSOP_GETTER)                                    ? js_getter_str                                    : js_setter_str);        return TOK_ERROR;    }    CURRENT_TOKEN(ts).t_op = op;    name = js_AtomToPrintableString(cx, atom);    if (!name ||        !js_ReportCompileErrorNumber(cx, ts,                                     JSREPORT_TS |                                     JSREPORT_WARNING |                                     JSREPORT_STRICT,                                     JSMSG_DEPRECATED_USAGE,                                     name)) {        return TOK_ERROR;    }    return tt;}#endif/* * Parse a top-level JS script. */JS_FRIEND_API(JSParseNode *)js_ParseTokenStream(JSContext *cx, JSObject *chain, JSTokenStream *ts){    JSStackFrame *fp, frame;    JSTreeContext tc;    JSParseNode *pn;    /*     * Push a compiler frame if we have no frames, or if the top frame is a     * lightweight function activation, or if its scope chain doesn't match     * the one passed to us.     */    fp = cx->fp;    if (!fp || !fp->varobj || fp->scopeChain != chain) {        memset(&frame, 0, sizeof frame);        frame.varobj = frame.scopeChain = chain;        if (cx->options & JSOPTION_VAROBJFIX) {            while ((chain = JS_GetParent(cx, chain)) != NULL)                frame.varobj = chain;        }        frame.down = fp;        if (fp)            frame.flags = fp->flags & (JSFRAME_SPECIAL | JSFRAME_COMPILE_N_GO);        cx->fp = &frame;    }    /*     * Protect atoms from being collected by a GC activation, which might     * - nest on this thread due to out of memory (the so-called "last ditch"     *   GC attempted within js_NewGCThing), or     * - run for any reason on another thread if this thread is suspended on     *   an object lock before it finishes generating bytecode into a script     *   protected from the GC by a root or a stack frame reference.     */    JS_KEEP_ATOMS(cx->runtime);    TREE_CONTEXT_INIT(&tc);    pn = Statements(cx, ts, &tc);    if (pn) {        if (!js_MatchToken(cx, ts, TOK_EOF)) {            js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR,                                        JSMSG_SYNTAX_ERROR);            pn = NULL;        } else {            pn->pn_type = TOK_LC;            if (!js_FoldConstants(cx, pn, &tc))                pn = NULL;        }    }    TREE_CONTEXT_FINISH(&tc);    JS_UNKEEP_ATOMS(cx->runtime);    cx->fp = fp;    return pn;}/* * Compile a top-level script. */JS_FRIEND_API(JSBool)js_CompileTokenStream(JSContext *cx, JSObject *chain, JSTokenStream *ts,                      JSCodeGenerator *cg){    JSStackFrame *fp, frame;    uint32 flags;    JSParseNode *pn;    JSBool ok;#ifdef METER_PARSENODES    void *sbrk(ptrdiff_t), *before = sbrk(0);#endif    /*     * Push a compiler frame if we have no frames, or if the top frame is a     * lightweight function activation, or if its scope chain doesn't match     * the one passed to us.     */    fp = cx->fp;    if (!fp || !fp->varobj || fp->scopeChain != chain) {        memset(&frame, 0, sizeof frame);        frame.varobj = frame.scopeChain = chain;        if (cx->options & JSOPTION_VAROBJFIX) {            while ((chain = JS_GetParent(cx, chain)) != NULL)                frame.varobj = chain;        }        frame.down = fp;        if (fp)            frame.flags = fp->flags & (JSFRAME_SPECIAL | JSFRAME_COMPILE_N_GO);        cx->fp = &frame;    }    flags = cx->fp->flags;    cx->fp->flags = flags |                    (JS_HAS_COMPILE_N_GO_OPTION(cx)                     ? JSFRAME_COMPILING | JSFRAME_COMPILE_N_GO                     : JSFRAME_COMPILING);    /* Prevent GC activation while compiling. */    JS_KEEP_ATOMS(cx->runtime);    pn = Statements(cx, ts, &cg->treeContext);    if (!pn) {        ok = JS_FALSE;    } else if (!js_MatchToken(cx, ts, TOK_EOF)) {        js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR,                                    JSMSG_SYNTAX_ERROR);        ok = JS_FALSE;    } else {#ifdef METER_PARSENODES        printf("Parser growth: %d (%u nodes, %u max, %u unrecycled)\n",               (char *)sbrk(0) - (char *)before,               parsenodes,               maxparsenodes,               parsenodes - recyclednodes);        before = sbrk(0);#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.         *         * Update: the threaded interpreter needs a stop instruction, so we         * do have to emit that here.         */        JS_ASSERT(cg->treeContext.flags & TCF_COMPILING);        ok = js_Emit1(cx, cg, JSOP_STOP) >= 0;    }#ifdef METER_PARSENODES    printf("Code-gen growth: %d (%u bytecodes, %u srcnotes)\n",           (char *)sbrk(0) - (char *)before, CG_OFFSET(cg), cg->noteCount);#endif#ifdef JS_ARENAMETER    JS_DumpArenaStats(stdout);#endif    JS_UNKEEP_ATOMS(cx->runtime);    cx->fp->flags = flags;    cx->fp = fp;    return ok;}/* * Insist on a final return before control flows out of pn, but don't be too * smart about loops (do {...; return e2;} while(0) at the end of a function * that contains an early return e1 will get a strict-option-only warning). */#define ENDS_IN_OTHER   0#define ENDS_IN_RETURN  1#define ENDS_IN_BREAK   2static intHasFinalReturn(JSParseNode *pn){    uintN rv, rv2, hasDefault;    JSParseNode *pn2, *pn3;    switch (pn->pn_type) {      case TOK_LC:        if (!pn->pn_head)            return ENDS_IN_OTHER;        return HasFinalReturn(PN_LAST(pn));      case TOK_IF:        rv = HasFinalReturn(pn->pn_kid2);        if (pn->pn_kid3)            rv &= HasFinalReturn(pn->pn_kid3);        return rv;#if JS_HAS_SWITCH_STATEMENT      case TOK_SWITCH:        rv = ENDS_IN_RETURN;        hasDefault = ENDS_IN_OTHER;        for (pn2 = pn->pn_kid2->pn_head; rv && pn2; pn2 = pn2->pn_next) {            if (pn2->pn_type == TOK_DEFAULT)                hasDefault = ENDS_IN_RETURN;            pn3 = pn2->pn_right;            JS_ASSERT(pn3->pn_type == TOK_LC);            if (pn3->pn_head) {                rv2 = HasFinalReturn(PN_LAST(pn3));                if (rv2 == ENDS_IN_OTHER && pn2->pn_next)                    /* Falling through to next case or default. */;                else                    rv &= rv2;            }        }        /* If a final switch has no default case, we judge it harshly. */        rv &= hasDefault;        return rv;#endif /* JS_HAS_SWITCH_STATEMENT */      case TOK_BREAK:        return ENDS_IN_BREAK;      case TOK_WITH:        return HasFinalReturn(pn->pn_right);      case TOK_RETURN:        return ENDS_IN_RETURN;      case TOK_COLON:        return HasFinalReturn(pn->pn_expr);#if JS_HAS_EXCEPTIONS      case TOK_THROW:        return ENDS_IN_RETURN;      case TOK_TRY:        /* If we have a finally block that returns, we are done. */        if (pn->pn_kid3) {            rv = HasFinalReturn(pn->pn_kid3);            if (rv == ENDS_IN_RETURN)                return rv;        }        /* Else check the try block and any and all catch statements. */        rv = HasFinalReturn(pn->pn_kid1);        if (pn->pn_kid2)            rv &= HasFinalReturn(pn->pn_kid2);        return rv;      case TOK_CATCH:        /* Check this block's code and iterate over further catch blocks. */        rv = HasFinalReturn(pn->pn_kid3);        for (pn2 = pn->pn_kid2; pn2; pn2 = pn2->pn_kid2)            rv &= HasFinalReturn(pn2->pn_kid3);        return rv;#endif      default:        return ENDS_IN_OTHER;    }}static JSBoolReportNoReturnValue(JSContext *cx, JSTokenStream *ts){    JSFunction *fun;    JSBool ok;    fun = cx->fp->fun;    if (fun->atom) {        char *name = js_GetStringBytes(ATOM_TO_STRING(fun->atom));        ok = js_ReportCompileErrorNumber(cx, ts,                                         JSREPORT_TS |                                         JSREPORT_WARNING |                                         JSREPORT_STRICT,                                         JSMSG_NO_RETURN_VALUE, name);    } else {        ok = js_ReportCompileErrorNumber(cx, ts,                                         JSREPORT_TS |                                         JSREPORT_WARNING |                                         JSREPORT_STRICT,                                         JSMSG_ANON_NO_RETURN_VALUE);    }    return ok;}static JSBoolCheckFinalReturn(JSContext *cx, JSTokenStream *ts, JSParseNode *pn){    return HasFinalReturn(pn) == ENDS_IN_RETURN || ReportNoReturnValue(cx, ts);}static JSParseNode *FunctionBody(JSContext *cx, JSTokenStream *ts, JSFunction *fun,             JSTreeContext *tc){    JSStackFrame *fp, frame;    JSObject *funobj;    uintN oldflags;    JSParseNode *pn;    fp = cx->fp;    funobj = fun->object;    if (!fp || fp->fun != fun || fp->varobj != funobj ||        fp->scopeChain != funobj) {        memset(&frame, 0, sizeof frame);        frame.fun = fun;        frame.varobj = frame.scopeChain = funobj;        frame.down = fp;        if (fp)            frame.flags = fp->flags & JSFRAME_COMPILE_N_GO;        cx->fp = &frame;    }    oldflags = tc->flags;    tc->flags &= ~(TCF_RETURN_EXPR | TCF_RETURN_VOID);    tc->flags |= TCF_IN_FUNCTION;    pn = Statements(cx, ts, tc);    /* Check for falling off the end of a function that returns a value. */    if (pn && JS_HAS_STRICT_OPTION(cx) && (tc->flags & TCF_RETURN_EXPR)) {        if (!CheckFinalReturn(cx, ts, pn))            pn = NULL;    }    cx->fp = fp;    tc->flags = oldflags | (tc->flags & (TCF_FUN_FLAGS | TCF_HAS_DEFXMLNS));    return pn;}/* * Compile a JS function body, which might appear as the value of an event * handler attribute in an HTML <INPUT> tag. */JSBooljs_CompileFunctionBody(JSContext *cx, JSTokenStream *ts, JSFunction *fun){    JSArenaPool codePool, notePool;    JSCodeGenerator funcg;    JSStackFrame *fp, frame;    JSObject *funobj;    JSParseNode *pn;    JSBool ok;    JS_InitArenaPool(&codePool, "code", 1024, sizeof(jsbytecode));    JS_InitArenaPool(&notePool, "note", 1024, sizeof(jssrcnote));    if (!js_InitCodeGenerator(cx, &funcg, &codePool, &notePool,                              ts->filename, ts->lineno,                              ts->principals)) {        return JS_FALSE;    }    /* Prevent GC activation while compiling. */    JS_KEEP_ATOMS(cx->runtime);    /* Push a JSStackFrame for use by FunctionBody. */    fp = cx->fp;    funobj = fun->object;    JS_ASSERT(!fp || (fp->fun != fun && fp->varobj != funobj &&                      fp->scopeChain != funobj));    memset(&frame, 0, sizeof frame);    frame.fun = fun;    frame.varobj = frame.scopeChain = funobj;    frame.down = fp;    frame.flags = JS_HAS_COMPILE_N_GO_OPTION(cx)                  ? JSFRAME_COMPILING | JSFRAME_COMPILE_N_GO                  : JSFRAME_COMPILING;    cx->fp = &frame;    /*     * Farble the body so that it looks like a block statement to js_EmitTree,     * which is called beneath FunctionBody (see Statements, further below in     * this file).     *     * NB: with threaded interpretation, we must emit a stop opcode at the end     * of every scripted function and top-level script.     */    CURRENT_TOKEN(ts).type = TOK_LC;    pn = FunctionBody(cx, ts, fun, &funcg.treeContext);    if (!pn || js_Emit1(cx, &funcg, JSOP_STOP) < 0) {        ok = JS_FALSE;    } else {        /*         * No need to emit code here -- Statements (via FunctionBody) already         * has.  See similar comment in js_CompileTokenStream, and bug 108257.         */        fun->u.script = js_NewScriptFromCG(cx, &funcg, fun);        if (!fun->u.script) {            ok = JS_FALSE;        } else {            fun->interpreted = JS_TRUE;            if (funcg.treeContext.flags & TCF_FUN_HEAVYWEIGHT)                fun->flags |= JSFUN_HEAVYWEIGHT;            ok = JS_TRUE;        }    }    /* Restore saved state and release code generation arenas. */    cx->fp = fp;    JS_UNKEEP_ATOMS(cx->runtime);    js_FinishCodeGenerator(cx, &funcg);    JS_FinishArenaPool(&codePool);    JS_FinishArenaPool(&notePool);    return ok;}static JSParseNode *FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,            JSBool lambda){    JSOp op, prevop;    JSParseNode *pn, *body, *result;    JSAtom *funAtom, *argAtom;    JSStackFrame *fp;    JSObject *varobj, *pobj;    JSAtomListElement *ale;    JSProperty *prop;    JSFunction *fun;    uintN dupflag;    JSBool ok;    JSTreeContext funtc;    /* Make a TOK_FUNCTION node. */#if JS_HAS_GETTER_SETTER    op = CURRENT_TOKEN(ts).t_op;#endif    pn = NewParseNode(cx, ts, PN_FUNC, tc);    if (!pn)        return NULL;    /* Scan the optional function name into funAtom. */    funAtom = js_MatchToken(cx, ts, TOK_NAME) ? CURRENT_TOKEN(ts).t_atom : NULL;#if !JS_HAS_LEXICAL_CLOSURE    if (!funAtom && !lambda) {        js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR,                                    JSMSG_SYNTAX_ERROR);        return NULL;    }#endif    /* Find the nearest variable-declaring scope and use it as our parent. */    fp = cx->fp;    varobj = fp->varobj;    /*     * Record names for function statements in tc->decls so we know when to     * avoid optimizing variable references that might name a function.     */    if (!lambda && funAtom) {        ATOM_LIST_SEARCH(ale, &tc->decls, funAtom);        if (ale) {            prevop = ALE_JSOP(ale);            if (JS_HAS_STRICT_OPTION(cx) || prevop == JSOP_DEFCONST) {                const char *name = js_AtomToPrintableString(cx, funAtom);                if (!name ||                    !js_ReportCompileErrorNumber(cx, ts,                                                 (prevop != JSOP_DEFCONST)                                                 ? JSREPORT_TS |                                                   JSREPORT_WARNING |                                                   JSREPORT_STRICT                                                 : JSREPORT_TS | JSREPORT_ERROR,                                                 JSMSG_REDECLARED_VAR,                                                 (prevop == JSOP_DEFFUN ||                                                  prevop == JSOP_CLOSURE)                                                 ? js_function_str                                                 : (prevop == JSOP_DEFCONST)                                                 ? js_const_str                                                 : js_var_str,                                                 name)) {                    return NULL;                }            }            if (tc->topStmt && prevop == JSOP_DEFVAR)                tc->flags |= TCF_FUN_CLOSURE_VS_VAR;        } else {            ale = js_IndexAtom(cx, funAtom, &tc->decls);            if (!ale)                return NULL;        }        ALE_SET_JSOP(ale, tc->topStmt ? JSOP_CLOSURE : JSOP_DEFFUN);#if JS_HAS_LEXICAL_CLOSURE        /*         * A function nested at top level inside another's body needs only a         * local variable to bind its name to its value, and not an activation         * object property (it might also need the activation property, if the         * outer function contains with statements, e.g., but the stack slot         * wins when jsemit.c's LookupArgOrVar can optimize a JSOP_NAME into a         * JSOP_GETVAR bytecode).         */        if (!tc->topStmt && (tc->flags & TCF_IN_FUNCTION)) {            /*             * Define a property on the outer function so that LookupArgOrVar             * can properly optimize accesses.             */            JS_ASSERT(OBJ_GET_CLASS(cx, varobj) == &js_FunctionClass);            JS_ASSERT(fp->fun == (JSFunction *) JS_GetPrivate(cx, varobj));            if (!js_LookupHiddenProperty(cx, varobj, ATOM_TO_JSID(funAtom),                                         &pobj, &prop)) {                return NULL;            }            if (prop)                OBJ_DROP_PROPERTY(cx, pobj, prop);            if (!prop ||                pobj != varobj ||                ((JSScopeProperty *)prop)->getter != js_GetLocalVariable) {                if (!js_AddHiddenProperty(cx, varobj, ATOM_TO_JSID(funAtom),                                          js_GetLocalVariable,                                          js_SetLocalVariable,                                          SPROP_INVALID_SLOT,                                          JSPROP_PERMANENT | JSPROP_SHARED,                                          SPROP_HAS_SHORTID, fp->fun->nvars)) {                    return NULL;                }                if (fp->fun->nvars == JS_BITMASK(16)) {                    JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,                                         JSMSG_TOO_MANY_FUN_VARS);                    return NULL;                }                fp->fun->nvars++;            }        }#endif    }    fun = js_NewFunction(cx, NULL, NULL, 0, lambda ? JSFUN_LAMBDA : 0, varobj,                         funAtom);    if (!fun)        return NULL;#if JS_HAS_GETTER_SETTER    if (op != JSOP_NOP)        fun->flags |= (op == JSOP_GETTER) ? JSPROP_GETTER : JSPROP_SETTER;#endif    /*     * Set interpreted early so js_EmitTree can test it to decide whether to     * eliminate useless expressions.     */    fun->interpreted = JS_TRUE;    /* Now parse formal argument list and compute fun->nargs. */    MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_FORMAL);    if (!js_MatchToken(cx, ts, TOK_RP)) {        do {            MUST_MATCH_TOKEN(TOK_NAME, JSMSG_MISSING_FORMAL);            argAtom = CURRENT_TOKEN(ts).t_atom;            pobj = NULL;            if (!js_LookupHiddenProperty(cx, fun->object, ATOM_TO_JSID(argAtom),                                         &pobj, &prop)) {                return NULL;            }            dupflag = 0;            if (prop) {                ok = JS_TRUE;                if (pobj == fun->object &&                    ((JSScopeProperty *) prop)->getter == js_GetArgument) {                    const char *name = js_AtomToPrintableString(cx, argAtom);                    /*                     * A duplicate parameter name. We force a duplicate node                     * on the SCOPE_LAST_PROP(scope) list with the same id,                     * distinguished by the SPROP_IS_DUPLICATE flag, and not                     * mapped by an entry in scope.                     */                    ok = name &&                         js_ReportCompileErrorNumber(cx, ts,                                                     JSREPORT_TS |                                                     JSREPORT_WARNING |                                                     JSREPORT_STRICT,                                                     JSMSG_DUPLICATE_FORMAL,                                                     name);                    dupflag = SPROP_IS_DUPLICATE;                }                OBJ_DROP_PROPERTY(cx, pobj, prop);                if (!ok)                    return NULL;                prop = NULL;            }            if (!js_AddHiddenProperty(cx, fun->object, ATOM_TO_JSID(argAtom),                                      js_GetArgument, js_SetArgument,                                      SPROP_INVALID_SLOT,                                      JSPROP_PERMANENT | JSPROP_SHARED,                                      dupflag | SPROP_HAS_SHORTID,                                      fun->nargs)) {                return NULL;            }            if (fun->nargs == JS_BITMASK(16)) {                JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,                                     JSMSG_TOO_MANY_FUN_ARGS);                return NULL;            }            fun->nargs++;        } while (js_MatchToken(cx, ts, TOK_COMMA));        MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_FORMAL);    }    MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_BODY);    pn->pn_pos.begin = CURRENT_TOKEN(ts).pos.begin;    TREE_CONTEXT_INIT(&funtc);    body = FunctionBody(cx, ts, fun, &funtc);    if (!body)        return NULL;    MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_BODY);    pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end;#if JS_HAS_LEXICAL_CLOSURE    /*     * If we collected flags that indicate nested heavyweight functions, or     * this function contains heavyweight-making statements (references to     * __parent__ or __proto__; use of with, eval, import, or export; and     * assignment to arguments), flag the function as heavyweight (requiring     * a call object per invocation).     */    if (funtc.flags & TCF_FUN_HEAVYWEIGHT) {        fun->flags |= JSFUN_HEAVYWEIGHT;        tc->flags |= TCF_FUN_HEAVYWEIGHT;    } else {        /*         * If this function is a named statement function not at top-level         * (i.e. a JSOP_CLOSURE), or if it refers to unqualified names that         * are not local args or vars (TCF_FUN_USES_NONLOCALS), then our         * enclosing function, if any, must be heavyweight.         */        if ((!lambda && funAtom && tc->topStmt) ||            (funtc.flags & TCF_FUN_USES_NONLOCALS)) {            tc->flags |= TCF_FUN_HEAVYWEIGHT;        }    }#endif    result = pn;#if JS_HAS_LEXICAL_CLOSURE    if (lambda) {        /*         * ECMA ed. 3 standard: function expression, possibly anonymous.         */        op = funAtom ? JSOP_NAMEDFUNOBJ : JSOP_ANONFUNOBJ;    } else if (!funAtom) {        /*         * If this anonymous function definition is *not* embedded within a         * larger expression, we treat it as an expression statement, not as         * a function declaration -- and not as a syntax error (as ECMA-262         * Edition 3 would have it).  Backward compatibility trumps all.         */        result = NewParseNode(cx, ts, PN_UNARY, tc);        if (!result)            return NULL;        result->pn_type = TOK_SEMI;        result->pn_pos = pn->pn_pos;        result->pn_kid = pn;        op = JSOP_ANONFUNOBJ;    } else if (tc->topStmt) {        /*         * ECMA ed. 3 extension: a function expression statement not at the         * top level, e.g., in a compound statement such as the "then" part         * of an "if" statement, binds a closure only if control reaches that         * sub-statement.         */        op = JSOP_CLOSURE;    } else#endif        op = JSOP_NOP;    /*     * Absent use of the new scoped local GC roots API around compiler calls,     * we need to atomize here to protect against a GC activation.  Atoms are     * protected from GC during compilation by the JS_FRIEND_API entry points     * in this file.  There doesn't seem to be any gain in switching from the     * atom-keeping method to the bulkier, slower scoped local roots method.     */    pn->pn_funAtom = js_AtomizeObject(cx, fun->object, 0);    if (!pn->pn_funAtom)        return NULL;    pn->pn_op = op;    pn->pn_body = body;    pn->pn_flags = funtc.flags & (TCF_FUN_FLAGS | TCF_HAS_DEFXMLNS);    pn->pn_tryCount = funtc.tryCount;    TREE_CONTEXT_FINISH(&funtc);    return result;}static JSParseNode *FunctionStmt(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc){    return FunctionDef(cx, ts, tc, JS_FALSE);}#if JS_HAS_LEXICAL_CLOSUREstatic JSParseNode *FunctionExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc){    return FunctionDef(cx, ts, tc, JS_TRUE);}#endif/* * Parse the statements in a block, creating a TOK_LC node that lists the * statements' trees.  If called from block-parsing code, the caller must * match { before and } after. */static JSParseNode *Statements(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc){    JSParseNode *pn, *pn2;    JSTokenType tt;    CHECK_RECURSION();    pn = NewParseNode(cx, ts, PN_LIST, tc);    if (!pn)        return NULL;    PN_INIT_LIST(pn);    ts->flags |= TSF_OPERAND;    while ((tt = js_PeekToken(cx, ts)) > TOK_EOF && tt != TOK_RC) {        ts->flags &= ~TSF_OPERAND;        pn2 = Statement(cx, ts, tc);        if (!pn2) {            if (ts->flags & TSF_EOF)                ts->flags |= TSF_UNEXPECTED_EOF;            return NULL;        }        ts->flags |= TSF_OPERAND;        /* If compiling top-level statements, emit as we go to save space. */        if (!tc->topStmt && (tc->flags & TCF_COMPILING)) {            if (cx->fp->fun &&                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, ts, 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_AllocTryNotes(cx, (JSCodeGenerator *)tc) ||                !js_EmitTree(cx, (JSCodeGenerator *)tc, pn2)) {                tt = TOK_ERROR;                break;            }            RecycleTree(pn2, tc);        } else {            PN_APPEND(pn, pn2);        }    }    ts->flags &= ~TSF_OPERAND;    if (tt == TOK_ERROR)        return NULL;    pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end;    return pn;}static JSParseNode *Condition(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc){    JSParseNode *pn, *pn2;    MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_COND);    pn = Expr(cx, ts, tc);    if (!pn)        return NULL;    MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_COND);    /*     * Check for (a = b) and "correct" it to (a == b) iff b's operator has     * greater precedence than ==.     * XXX not ECMA, but documented in several books -- now a strict warning.     */    if (pn->pn_type == TOK_ASSIGN &&        pn->pn_op == JSOP_NOP &&        pn->pn_right->pn_type > TOK_EQOP)    {        JSBool rewrite = !JS_VERSION_IS_ECMA(cx);        if (!js_ReportCompileErrorNumber(cx, ts,                                         JSREPORT_TS |                                         JSREPORT_WARNING |                                         JSREPORT_STRICT,                                         JSMSG_EQUAL_AS_ASSIGN,                                         rewrite                                         ? "\nAssuming equality test"                                         : "")) {            return NULL;        }        if (rewrite) {            pn->pn_type = TOK_EQOP;            pn->pn_op = (JSOp)cx->jsop_eq;            pn2 = pn->pn_left;            switch (pn2->pn_op) {              case JSOP_SETNAME:                pn2->pn_op = JSOP_NAME;                break;              case JSOP_SETPROP:                pn2->pn_op = JSOP_GETPROP;                break;              case JSOP_SETELEM:                pn2->pn_op = JSOP_GETELEM;                break;              default:                JS_ASSERT(0);            }        }    }    return pn;}static JSBoolMatchLabel(JSContext *cx, JSTokenStream *ts, JSParseNode *pn){    JSAtom *label;#if JS_HAS_LABEL_STATEMENT    JSTokenType tt;    tt = js_PeekTokenSameLine(cx, ts);    if (tt == TOK_ERROR)        return JS_FALSE;    if (tt == TOK_NAME) {        (void) js_GetToken(cx, ts);        label = CURRENT_TOKEN(ts).t_atom;    } else {        label = NULL;    }#else    label = NULL;#endif    pn->pn_atom = label;    return JS_TRUE;}#if JS_HAS_EXPORT_IMPORTstatic JSParseNode *ImportExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc){    JSParseNode *pn, *pn2;    JSTokenType tt;    MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_IMPORT_NAME);    pn = NewParseNode(cx, ts, PN_NAME, tc);    if (!pn)        return NULL;    pn->pn_op = JSOP_NAME;    pn->pn_atom = CURRENT_TOKEN(ts).t_atom;    pn->pn_expr = NULL;    pn->pn_slot = -1;    pn->pn_attrs = 0;    ts->flags |= TSF_OPERAND;    while ((tt = js_GetToken(cx, ts)) == TOK_DOT || tt == TOK_LB) {        ts->flags &= ~TSF_OPERAND;        if (pn->pn_op == JSOP_IMPORTALL)            goto bad_import;        if (tt == TOK_DOT) {            pn2 = NewParseNode(cx, ts, PN_NAME, tc);            if (!pn2)                return NULL;            if (js_MatchToken(cx, ts, TOK_STAR)) {                pn2->pn_op = JSOP_IMPORTALL;                pn2->pn_atom = NULL;            } else {                MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NAME_AFTER_DOT);                pn2->pn_op = JSOP_GETPROP;                pn2->pn_atom = CURRENT_TOKEN(ts).t_atom;                pn2->pn_slot = -1;                pn2->pn_attrs = 0;            }            pn2->pn_expr = pn;            pn2->pn_pos.begin = pn->pn_pos.begin;            pn2->pn_pos.end = CURRENT_TOKEN(ts).pos.end;        } else {            /* Make a TOK_LB binary node. */            pn2 = NewBinary(cx, tt, JSOP_GETELEM, pn, Expr(cx, ts, tc), tc);            if (!pn2)                return NULL;            MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_IN_INDEX);        }        pn = pn2;        ts->flags |= TSF_OPERAND;    }    ts->flags &= ~TSF_OPERAND;    if (tt == TOK_ERROR)        return NULL;    js_UngetToken(ts);    switch (pn->pn_op) {      case JSOP_GETPROP:        pn->pn_op = JSOP_IMPORTPROP;        break;      case JSOP_GETELEM:        pn->pn_op = JSOP_IMPORTELEM;        break;      case JSOP_IMPORTALL:        break;      default:        goto bad_import;    }    return pn;  bad_import:    js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR,                                JSMSG_BAD_IMPORT);    return NULL;}#endif /* JS_HAS_EXPORT_IMPORT */extern const char js_with_statement_str[];static JSParseNode *Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc){    JSTokenType tt;    JSParseNode *pn, *pn1, *pn2, *pn3, *pn4;    JSStmtInfo stmtInfo, *stmt, *stmt2;    JSAtom *label;    CHECK_RECURSION();    ts->flags |= TSF_OPERAND;    tt = js_GetToken(cx, ts);    ts->flags &= ~TSF_OPERAND;#if JS_HAS_GETTER_SETTER    if (tt == TOK_NAME) {        tt = CheckGetterOrSetter(cx, ts, TOK_FUNCTION);        if (tt == TOK_ERROR)            return NULL;    }#endif    switch (tt) {#if JS_HAS_EXPORT_IMPORT      case TOK_EXPORT:        pn = NewParseNode(cx, ts, PN_LIST, tc);        if (!pn)            return NULL;        PN_INIT_LIST(pn);        if (js_MatchToken(cx, ts, TOK_STAR)) {            pn2 = NewParseNode(cx, ts, PN_NULLARY, tc);            if (!pn2)                return NULL;            PN_APPEND(pn, pn2);        } else {            do {                MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_EXPORT_NAME);                pn2 = NewParseNode(cx, ts, PN_NAME, tc);                if (!pn2)                    return NULL;                pn2->pn_op = JSOP_NAME;                pn2->pn_atom = CURRENT_TOKEN(ts).t_atom;                pn2->pn_expr = NULL;                pn2->pn_slot = -1;                pn2->pn_attrs = 0;                PN_APPEND(pn, pn2);            } while (js_MatchToken(cx, ts, TOK_COMMA));        }        pn->pn_pos.end = PN_LAST(pn)->pn_pos.end;        tc->flags |= TCF_FUN_HEAVYWEIGHT;        break;      case TOK_IMPORT:        pn = NewParseNode(cx, ts, PN_LIST, tc);        if (!pn)            return NULL;        PN_INIT_LIST(pn);        do {            pn2 = ImportExpr(cx, ts, tc);            if (!pn2)                return NULL;            PN_APPEND(pn, pn2);        } while (js_MatchToken(cx, ts, TOK_COMMA));        pn->pn_pos.end = PN_LAST(pn)->pn_pos.end;        tc->flags |= TCF_FUN_HEAVYWEIGHT;        break;#endif /* JS_HAS_EXPORT_IMPORT */      case TOK_FUNCTION:#if JS_HAS_XML_SUPPORT        if (js_PeekToken(cx, ts) == TOK_DBLCOLON)            goto expression;#endif        return FunctionStmt(cx, ts, tc);      case TOK_IF:        /* An IF node has three kids: condition, then, and optional else. */        pn = NewParseNode(cx, ts, PN_TERNARY, tc);        if (!pn)            return NULL;        pn1 = Condition(cx, ts, tc);        if (!pn1)            return NULL;        js_PushStatement(tc, &stmtInfo, STMT_IF, -1);        pn2 = Statement(cx, ts, tc);        if (!pn2)            return NULL;        if (js_MatchToken(cx, ts, TOK_ELSE)) {            stmtInfo.type = STMT_ELSE;            pn3 = Statement(cx, ts, tc);            if (!pn3)                return NULL;            pn->pn_pos.end = pn3->pn_pos.end;        } else {            pn3 = NULL;            pn->pn_pos.end = pn2->pn_pos.end;        }        js_PopStatement(tc);        pn->pn_kid1 = pn1;        pn->pn_kid2 = pn2;        pn->pn_kid3 = pn3;        return pn;#if JS_HAS_SWITCH_STATEMENT      case TOK_SWITCH:      {        JSParseNode *pn5;        JSBool seenDefault = JS_FALSE;        pn = NewParseNode(cx, ts, PN_BINARY, tc);        if (!pn)            return NULL;        MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_SWITCH);        /* pn1 points to the switch's discriminant. */        pn1 = Expr(cx, ts, tc);        if (!pn1)            return NULL;        MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_SWITCH);        MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_SWITCH);        /* pn2 is a list of case nodes. The default case has pn_left == NULL */        pn2 = NewParseNode(cx, ts, PN_LIST, tc);        if (!pn2)            return NULL;        PN_INIT_LIST(pn2);        js_PushStatement(tc, &stmtInfo, STMT_SWITCH, -1);        while ((tt = js_GetToken(cx, ts)) != TOK_RC) {            switch (tt) {              case TOK_DEFAULT:                if (seenDefault) {                    js_ReportCompileErrorNumber(cx, ts,                                                JSREPORT_TS | JSREPORT_ERROR,                                                JSMSG_TOO_MANY_DEFAULTS);                    return NULL;                }                seenDefault = JS_TRUE;                /* fall through */              case TOK_CASE:                pn3 = NewParseNode(cx, ts, PN_BINARY, tc);                if (!pn3)                    return NULL;                if (tt == TOK_DEFAULT) {                    pn3->pn_left = NULL;                } else {                    pn3->pn_left = Expr(cx, ts, tc);                    if (!pn3->pn_left)                        return NULL;                }                PN_APPEND(pn2, pn3);                if (pn2->pn_count == JS_BIT(16)) {                    js_ReportCompileErrorNumber(cx, ts,                                                JSREPORT_TS | JSREPORT_ERROR,                                                JSMSG_TOO_MANY_CASES);                    return NULL;                }                break;              case TOK_ERROR:                return NULL;              default:                js_ReportCompileErrorNumber(cx, ts,                                            JSREPORT_TS | JSREPORT_ERROR,                                            JSMSG_BAD_SWITCH);                return NULL;            }            MUST_MATCH_TOKEN(TOK_COLON, JSMSG_COLON_AFTER_CASE);            pn4 = NewParseNode(cx, ts, PN_LIST, tc);            if (!pn4)                return NULL;            pn4->pn_type = TOK_LC;            PN_INIT_LIST(pn4);            ts->flags |= TSF_OPERAND;            while ((tt = js_PeekToken(cx, ts)) != TOK_RC &&                   tt != TOK_CASE && tt != TOK_DEFAULT) {                ts->flags &= ~TSF_OPERAND;                if (tt == TOK_ERROR)                    return NULL;                pn5 = Statement(cx, ts, tc);                if (!pn5)                    return NULL;                pn4->pn_pos.end = pn5->pn_pos.end;                PN_APPEND(pn4, pn5);                ts->flags |= TSF_OPERAND;            }            ts->flags &= ~TSF_OPERAND;            /* Fix the PN_LIST so it doesn't begin at the TOK_COLON. */            if (pn4->pn_head)                pn4->pn_pos.begin = pn4->pn_head->pn_pos.begin;            pn3->pn_pos.end = pn4->pn_pos.end;            pn3->pn_right = pn4;        }        js_PopStatement(tc);        pn->pn_pos.end = pn2->pn_pos.end = CURRENT_TOKEN(ts).pos.end;        pn->pn_kid1 = pn1;        pn->pn_kid2 = pn2;        return pn;      }#endif /* JS_HAS_SWITCH_STATEMENT */      case TOK_WHILE:        pn = NewParseNode(cx, ts, PN_BINARY, tc);        if (!pn)            return NULL;        js_PushStatement(tc, &stmtInfo, STMT_WHILE_LOOP, -1);        pn2 = Condition(cx, ts, tc);        if (!pn2)            return NULL;        pn->pn_left = pn2;        pn2 = Statement(cx, ts, tc);        if (!pn2)            return NULL;        js_PopStatement(tc);        pn->pn_pos.end = pn2->pn_pos.end;        pn->pn_right = pn2;        return pn;#if JS_HAS_DO_WHILE_LOOP      case TOK_DO:        pn = NewParseNode(cx, ts, PN_BINARY, tc);        if (!pn)            return NULL;        js_PushStatement(tc, &stmtInfo, STMT_DO_LOOP, -1);        pn2 = Statement(cx, ts, tc);        if (!pn2)            return NULL;        pn->pn_left = pn2;        MUST_MATCH_TOKEN(TOK_WHILE, JSMSG_WHILE_AFTER_DO);        pn2 = Condition(cx, ts, tc);        if (!pn2)            return NULL;        js_PopStatement(tc);        pn->pn_pos.end = pn2->pn_pos.end;        pn->pn_right = pn2;        if ((cx->version & JSVERSION_MASK) != JSVERSION_ECMA_3) {            /*             * All legacy and extended versions must do automatic semicolon             * insertion after do-while.  See the testcase and discussion in             * http://bugzilla.mozilla.org/show_bug.cgi?id=238945.             */            (void) js_MatchToken(cx, ts, TOK_SEMI);            return pn;        }        break;#endif /* JS_HAS_DO_WHILE_LOOP */      case TOK_FOR:        /* A FOR node is binary, left is loop control and right is the body. */        pn = NewParseNode(cx, ts, PN_BINARY, tc);        if (!pn)            return NULL;        js_PushStatement(tc, &stmtInfo, STMT_FOR_LOOP, -1);#if JS_HAS_XML_SUPPORT        pn->pn_op = JSOP_NOP;        if (js_MatchToken(cx, ts, TOK_NAME)) {            if (CURRENT_TOKEN(ts).t_atom == cx->runtime->atomState.eachAtom)                pn->pn_op = JSOP_FOREACH;            else                js_UngetToken(ts);        }#endif        MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_AFTER_FOR);        ts->flags |= TSF_OPERAND;        tt = js_PeekToken(cx, ts);        ts->flags &= ~TSF_OPERAND;        if (tt == TOK_SEMI) {#if JS_HAS_XML_SUPPORT            if (pn->pn_op == JSOP_FOREACH)                goto bad_for_each;#endif            /* No initializer -- set first kid of left sub-node to null. */            pn1 = NULL;        } else {            /* Set pn1 to a var list or an initializing expression. */#if JS_HAS_IN_OPERATOR            /*             * Set the TCF_IN_FOR_INIT flag during parsing of the first clause             * of the for statement.  This flag will be used by the RelExpr             * production; if it is set, then the 'in' keyword will not be             * recognized as an operator, leaving it available to be parsed as             * part of a for/in loop.  A side effect of this restriction is             * that (unparenthesized) expressions involving an 'in' operator             * are illegal in the init clause of an ordinary for loop.             */            tc->flags |= TCF_IN_FOR_INIT;#endif /* JS_HAS_IN_OPERATOR */            if (tt == TOK_VAR) {                (void) js_GetToken(cx, ts);                pn1 = Variables(cx, ts, tc);            } else {                pn1 = Expr(cx, ts, tc);            }#if JS_HAS_IN_OPERATOR            tc->flags &= ~TCF_IN_FOR_INIT;#endif /* JS_HAS_IN_OPERATOR */            if (!pn1)                return NULL;        }        /*         * We can be sure that it's a for/in loop if there's still an 'in'         * keyword here, even if JavaScript recognizes 'in' as an operator,         * as we've excluded 'in' from being parsed in RelExpr by setting         * the TCF_IN_FOR_INIT flag in our JSTreeContext.         */        if (pn1 && js_MatchToken(cx, ts, TOK_IN)) {            stmtInfo.type = STMT_FOR_IN_LOOP;            /* Check that the left side of the 'in' is valid. */            if ((pn1->pn_type == TOK_VAR)                ? (pn1->pn_count > 1 || pn1->pn_op == JSOP_DEFCONST)                : (pn1->pn_type != TOK_NAME &&                   pn1->pn_type != TOK_DOT &&                   pn1->pn_type != TOK_LB)) {                js_ReportCompileErrorNumber(cx, ts,                                            JSREPORT_TS | JSREPORT_ERROR,                                            JSMSG_BAD_FOR_LEFTSIDE);                return NULL;            }            if (pn1->pn_type == TOK_VAR) {                /* Tell js_EmitTree(TOK_VAR) that pn1 is part of a for/in. */                pn1->pn_extra |= PNX_FORINVAR;                /* Generate a final POP only if the var has an initializer. */                pn2 = pn1->pn_head;                if (pn2->pn_expr)                    pn1->pn_extra |= PNX_POPVAR;            } else {                pn2 = pn1;            }            /* Beware 'for (arguments in ...)' with or without a 'var'. */            if (pn2->pn_type == TOK_NAME &&                pn2->pn_atom == cx->runtime->atomState.argumentsAtom) {                tc->flags |= TCF_FUN_HEAVYWEIGHT;            }            /* Parse the object expression as the right operand of 'in'. */            pn2 = NewBinary(cx, TOK_IN, JSOP_NOP, pn1, Expr(cx, ts, tc), tc);            if (!pn2)                return NULL;            pn->pn_left = pn2;        } else {#if JS_HAS_XML_SUPPORT            if (pn->pn_op == JSOP_FOREACH)                goto bad_for_each;#endif            /* Parse the loop condition or null into pn2. */            MUST_MATCH_TOKEN(TOK_SEMI, JSMSG_SEMI_AFTER_FOR_INIT);            ts->flags |= TSF_OPERAND;            tt = js_PeekToken(cx, ts);            ts->flags &= ~TSF_OPERAND;            if (tt == TOK_SEMI) {                pn2 = NULL;            } else {                pn2 = Expr(cx, ts, tc);                if (!pn2)                    return NULL;            }            /* Parse the update expression or null into pn3. */            MUST_MATCH_TOKEN(TOK_SEMI, JSMSG_SEMI_AFTER_FOR_COND);            ts->flags |= TSF_OPERAND;            tt = js_PeekToken(cx, ts);            ts->flags &= ~TSF_OPERAND;            if (tt == TOK_RP) {                pn3 = NULL;            } else {                pn3 = Expr(cx, ts, tc);                if (!pn3)                    return NULL;            }            /* Build the RESERVED node to use as the left kid of pn. */            pn4 = NewParseNode(cx, ts, PN_TERNARY, tc);            if (!pn4)                return NULL;            pn4->pn_type = TOK_RESERVED;            pn4->pn_op = JSOP_NOP;            pn4->pn_kid1 = pn1;            pn4->pn_kid2 = pn2;            pn4->pn_kid3 = pn3;            pn->pn_left = pn4;        }        MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_FOR_CTRL);        /* Parse the loop body into pn->pn_right. */        pn2 = Statement(cx, ts, tc);        if (!pn2)            return NULL;        pn->pn_right = pn2;        js_PopStatement(tc);        /* Record the absolute line number for source note emission. */        pn->pn_pos.end = pn2->pn_pos.end;        return pn;#if JS_HAS_XML_SUPPORT      bad_for_each:        js_ReportCompileErrorNumber(cx, pn,                                    JSREPORT_PN | JSREPORT_ERROR,                                    JSMSG_BAD_FOR_EACH_LOOP);        return NULL;#endif#if JS_HAS_EXCEPTIONS      case TOK_TRY: {        JSParseNode *catchtail = NULL;        /*         * try nodes are ternary.         * kid1 is the try Statement         * kid2 is the catch node         * kid3 is the finally Statement         *         * catch nodes are ternary.         * kid1 is the discriminant         * kid2 is the next catch node, or NULL         * kid3 is the catch block (on kid3 so that we can always append a         *                          new catch pn on catchtail->kid2)         *         * catch discriminant nodes are binary         * atom is the receptacle         * expr is the discriminant code         *         * finally nodes are unary (just the finally expression)         */        pn = NewParseNode(cx, ts, PN_TERNARY, tc);        pn->pn_op = JSOP_NOP;        MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_TRY);        js_PushStatement(tc, &stmtInfo, STMT_TRY, -1);        pn->pn_kid1 = Statements(cx, ts, tc);        if (!pn->pn_kid1)            return NULL;        MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_TRY);        js_PopStatement(tc);        catchtail = pn;        while (js_PeekToken(cx, ts) == TOK_CATCH) {            /* check for another catch after unconditional catch */            if (catchtail != pn && !catchtail->pn_kid1->pn_expr) {                js_ReportCompileErrorNumber(cx, ts,                                            JSREPORT_TS | JSREPORT_ERROR,                                            JSMSG_CATCH_AFTER_GENERAL);                return NULL;            }            /*             * legal catch forms are:             * catch (v)             * catch (v if <boolean_expression>)             * (the latter is legal only #ifdef JS_HAS_CATCH_GUARD)             */            (void) js_GetToken(cx, ts); /* eat `catch' */            pn2 = NewParseNode(cx, ts, PN_TERNARY, tc);            if (!pn2)                return NULL;            /*             * We use a PN_NAME for the discriminant (catchguard) node             * with the actual discriminant code in the initializer spot             */            MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_CATCH);            MUST_MATCH_TOKEN(TOK_NAME, JSMSG_CATCH_IDENTIFIER);            pn3 = NewParseNode(cx, ts, PN_NAME, tc);            if (!pn3)                return NULL;            pn3->pn_atom = CURRENT_TOKEN(ts).t_atom;            pn3->pn_expr = NULL;#if JS_HAS_CATCH_GUARD            /*             * We use `catch (x if x === 5)' (not `catch (x : x === 5)') to             * avoid conflicting with the JS2/ECMA2 proposed catchguard syntax.             */            if (js_PeekToken(cx, ts) == TOK_IF) {                (void)js_GetToken(cx, ts); /* eat `if' */                pn3->pn_expr = Expr(cx, ts, tc);                if (!pn3->pn_expr)                    return NULL;            }#endif            pn2->pn_kid1 = pn3;            MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_CATCH);            MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_CATCH);            js_PushStatement(tc, &stmtInfo, STMT_CATCH, -1);            stmtInfo.label = pn3->pn_atom;            pn2->pn_kid3 = Statements(cx, ts, tc);            if (!pn2->pn_kid3)                return NULL;            MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_CATCH);            js_PopStatement(tc);            catchtail = catchtail->pn_kid2 = pn2;        }        catchtail->pn_kid2 = NULL;        if (js_MatchToken(cx, ts, TOK_FINALLY)) {            tc->tryCount++;            MUST_MATCH_TOKEN(TOK_LC, JSMSG_CURLY_BEFORE_FINALLY);            js_PushStatement(tc, &stmtInfo, STMT_FINALLY, -1);            pn->pn_kid3 = Statements(cx, ts, tc);            if (!pn->pn_kid3)                return NULL;            MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_AFTER_FINALLY);            js_PopStatement(tc);        } else {            pn->pn_kid3 = NULL;        }        if (!pn->pn_kid2 && !pn->pn_kid3) {            js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR,                                        JSMSG_CATCH_OR_FINALLY);            return NULL;        }        tc->tryCount++;        return pn;      }      case TOK_THROW:        pn = NewParseNode(cx, ts, PN_UNARY, tc);        if (!pn)            return NULL;        /* ECMA-262 Edition 3 says 'throw [no LineTerminator here] Expr'. */        ts->flags |= TSF_OPERAND;        tt = js_PeekTokenSameLine(cx, ts);        ts->flags &= ~TSF_OPERAND;        if (tt == TOK_ERROR)            return NULL;        if (tt == TOK_EOF || tt == TOK_EOL || tt == TOK_SEMI || tt == TOK_RC) {            js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR,                                        JSMSG_SYNTAX_ERROR);            return NULL;        }        pn2 = Expr(cx, ts, tc);        if (!pn2)            return NULL;        pn->pn_pos.end = pn2->pn_pos.end;        pn->pn_op = JSOP_THROW;        pn->pn_kid = pn2;        break;      /* TOK_CATCH and TOK_FINALLY are both handled in the TOK_TRY case */      case TOK_CATCH:        js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR,                                    JSMSG_CATCH_WITHOUT_TRY);        return NULL;      case TOK_FINALLY:        js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR,                                    JSMSG_FINALLY_WITHOUT_TRY);        return NULL;#endif /* JS_HAS_EXCEPTIONS */      case TOK_BREAK:        pn = NewParseNode(cx, ts, PN_NULLARY, tc);        if (!pn)            return NULL;        if (!MatchLabel(cx, ts, pn))            return NULL;        stmt = tc->topStmt;        label = pn->pn_atom;        if (label) {            for (; ; stmt = stmt->down) {                if (!stmt) {                    js_ReportCompileErrorNumber(cx, ts,                                                JSREPORT_TS | JSREPORT_ERROR,                                                JSMSG_LABEL_NOT_FOUND);                    return NULL;                }                if (stmt->type == STMT_LABEL && stmt->label == label)                    break;            }        } else {            for (; ; stmt = stmt->down) {                if (!stmt) {                    js_ReportCompileErrorNumber(cx, ts,                                                JSREPORT_TS | JSREPORT_ERROR,                                                JSMSG_TOUGH_BREAK);                    return NULL;                }                if (STMT_IS_LOOP(stmt) || stmt->type == STMT_SWITCH)                    break;            }        }        if (label)            pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end;        break;      case TOK_CONTINUE:        pn = NewParseNode(cx, ts, PN_NULLARY, tc);        if (!pn)            return NULL;        if (!MatchLabel(cx, ts, pn))            return NULL;        stmt = tc->topStmt;        label = pn->pn_atom;        if (label) {            for (stmt2 = NULL; ; stmt = stmt->down) {                if (!stmt) {                    js_ReportCompileErrorNumber(cx, ts,                                                JSREPORT_TS | JSREPORT_ERROR,                                                JSMSG_LABEL_NOT_FOUND);                    return NULL;                }                if (stmt->type == STMT_LABEL) {                    if (stmt->label == label) {                        if (!stmt2 || !STMT_IS_LOOP(stmt2)) {                            js_ReportCompileErrorNumber(cx, ts,                                                        JSREPORT_TS |                                                        JSREPORT_ERROR,                                                        JSMSG_BAD_CONTINUE);                            return NULL;                        }                        break;                    }                } else {                    stmt2 = stmt;                }            }        } else {            for (; ; stmt = stmt->down) {                if (!stmt) {                    js_ReportCompileErrorNumber(cx, ts,                                                JSREPORT_TS | JSREPORT_ERROR,                                                JSMSG_BAD_CONTINUE);                    return NULL;                }                if (STMT_IS_LOOP(stmt))                    break;            }        }        if (label)            pn->pn_pos.end = CURRENT_TOKEN(ts).pos.end;        break;      case TOK_WITH:        if (!js_ReportCompileErrorNumber(cx, ts,                                         JSREPORT_TS |                                         JSREPORT_WARNING |                                         JSREPORT_STRICT,                                         JSMSG_DEPRECATED_USAGE,                                         js_with_statement_str)) {            return NULL;        }        pn = NewParseNode(cx, ts, PN_BINARY, tc);        if (!pn)            return NULL;        MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_WITH);        pn2 = Expr(cx, ts, tc);        if (!pn2)            return NULL;        MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_WITH);        pn->pn_left = pn2;        js_PushStatement(tc, &stmtInfo, STMT_WITH, -1);        pn2 = Statement(cx, ts, tc);        if (!pn2)            return NULL;        js_PopStatement(tc);        pn->pn_pos.end = pn2->pn_pos.end;        pn->pn_right = pn2;        tc->flags |= TCF_FUN_HEAVYWEIGHT;        return pn;      case TOK_VAR:        pn = Variables(cx, ts, tc);        if (!pn)            return NULL;        /* Tell js_EmitTree to generate a final POP. */        pn->pn_extra |= PNX_POPVAR;        break;      case TOK_RETURN:        if (!(tc->flags & TCF_IN_FUNCTION)) {            js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR,                                        JSMSG_BAD_RETURN);            return NULL;        }        pn = NewParseNode(cx, ts, PN_UNARY, tc);        if (!pn)            return NULL;        /* This is ugly, but we don't want to require a semicolon. */        ts->flags |= TSF_OPERAND;        tt = js_PeekTokenSameLine(cx, ts);        ts->flags &= ~TSF_OPERAND;        if (tt == TOK_ERROR)            return NULL;        if (tt != TOK_EOF && tt != TOK_EOL && tt != TOK_SEMI && tt != TOK_RC) {            pn2 = Expr(cx, ts, tc);            if (!pn2)                return NULL;            tc->flags |= TCF_RETURN_EXPR;            pn->pn_pos.end = pn2->pn_pos.end;            pn->pn_kid = pn2;        } else {            tc->flags |= TCF_RETURN_VOID;            pn->pn_kid = NULL;        }        if (JS_HAS_STRICT_OPTION(cx) &&            (~tc->flags & (TCF_RETURN_EXPR | TCF_RETURN_VOID)) == 0) {            /*             * We must be in a frame with a non-native function, because             * we're compiling one.             */            if (!ReportNoReturnValue(cx, ts))                return NULL;        }        break;      case TOK_LC:        js_PushStatement(tc, &stmtInfo, STMT_BLOCK, -1);        pn = Statements(cx, ts, tc);        if (!pn)            return NULL;        MUST_MATCH_TOKEN(TOK_RC, JSMSG_CURLY_IN_COMPOUND);        js_PopStatement(tc);        return pn;      case TOK_EOL:      case TOK_SEMI:        pn = NewParseNode(cx, ts, PN_UNARY, tc);        if (!pn)            return NULL;        pn->pn_type = TOK_SEMI;        pn->pn_kid = NULL;        return pn;#if JS_HAS_DEBUGGER_KEYWORD      case TOK_DEBUGGER:        pn = NewParseNode(cx, ts, PN_NULLARY, tc);        if (!pn)            return NULL;        pn->pn_type = TOK_DEBUGGER;        tc->flags |= TCF_FUN_HEAVYWEIGHT;        break;#endif /* JS_HAS_DEBUGGER_KEYWORD */#if JS_HAS_XML_SUPPORT      case TOK_DEFAULT:        pn = NewParseNode(cx, ts, PN_UNARY, tc);        if (!pn)            return NULL;        if (!js_MatchToken(cx, ts, TOK_NAME) ||            CURRENT_TOKEN(ts).t_atom != cx->runtime->atomState.xmlAtom ||            !js_MatchToken(cx, ts, TOK_NAME) ||            CURRENT_TOKEN(ts).t_atom != cx->runtime->atomState.namespaceAtom ||            !js_MatchToken(cx, ts, TOK_ASSIGN) ||            CURRENT_TOKEN(ts).t_op != JSOP_NOP) {            js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR,                                        JSMSG_BAD_DEFAULT_XML_NAMESPACE);            return NULL;        }        pn2 = Expr(cx, ts, tc);        if (!pn2)            return NULL;        pn->pn_op = JSOP_DEFXMLNS;        pn->pn_pos.end = pn2->pn_pos.end;        pn->pn_kid = pn2;        tc->flags |= TCF_HAS_DEFXMLNS;        break;#endif      case TOK_ERROR:        return NULL;      default:#if JS_HAS_XML_SUPPORT      expression:#endif        js_UngetToken(ts);        pn2 = Expr(cx, ts, tc);        if (!pn2)            return NULL;        if (js_PeekToken(cx, ts) == TOK_COLON) {            if (pn2->pn_type != TOK_NAME) {                js_ReportCompileErrorNumber(cx, ts,                                            JSREPORT_TS | JSREPORT_ERROR,                                            JSMSG_BAD_LABEL);                return NULL;            }            label = pn2->pn_atom;            for (stmt = tc->topStmt; stmt; stmt = stmt->down) {                if (stmt->type == STMT_LABEL && stmt->label == label) {                    js_ReportCompileErrorNumber(cx, ts,                                                JSREPORT_TS | JSREPORT_ERROR,                                                JSMSG_DUPLICATE_LABEL);                    return NULL;                }            }            (void) js_GetToken(cx, ts);            /* Push a label struct and parse the statement. */            js_PushStatement(tc, &stmtInfo, STMT_LABEL, -1);            stmtInfo.label = label;            pn = Statement(cx, ts, tc);            if (!pn)                return NULL;            /* Pop the label, set pn_expr, and return early. */            js_PopStatement(tc);            pn2->pn_type = TOK_COLON;            pn2->pn_pos.end = pn->pn_pos.end;            pn2->pn_expr = pn;            return pn2;        }        pn = NewParseNode(cx, ts, PN_UNARY, tc);        if (!pn)            return NULL;        pn->pn_type = TOK_SEMI;        pn->pn_pos = pn2->pn_pos;        pn->pn_kid = pn2;        break;    }    /* Check termination of this primitive statement. */    if (ON_CURRENT_LINE(ts, pn->pn_pos)) {        tt = js_PeekTokenSameLine(cx, ts);        if (tt == TOK_ERROR)            return NULL;        if (tt != TOK_EOF && tt != TOK_EOL && tt != TOK_SEMI && tt != TOK_RC) {            js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR,                                        JSMSG_SEMI_BEFORE_STMNT);            return NULL;        }    }    (void) js_MatchToken(cx, ts, TOK_SEMI);    return pn;}static JSParseNode *Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc){    JSParseNode *pn, *pn2;    JSObject *obj, *pobj;    JSStackFrame *fp;    JSFunction *fun;    JSClass *clasp;    JSPropertyOp getter, setter, currentGetter, currentSetter;    JSAtom *atom;    JSAtomListElement *ale;    JSOp prevop;    JSProperty *prop;    JSScopeProperty *sprop;    JSBool ok;    /*     * The tricky part of this code is to create special parsenode opcodes for     * getting and setting variables (which will be stored as special slots in     * the frame).  The complex special case is an eval() inside a function.     * If the evaluated string references variables in the enclosing function,     * then we need to generate the special variable opcodes.  We determine     * this by looking up the variable id in the current variable scope.     */    JS_ASSERT(CURRENT_TOKEN(ts).type == TOK_VAR);    pn = NewParseNode(cx, ts, PN_LIST, tc);    if (!pn)        return NULL;    pn->pn_op = CURRENT_TOKEN(ts).t_op;    PN_INIT_LIST(pn);    /*     * Skip eval and debugger frames when looking for the function whose code     * is being compiled.  If we are called from FunctionBody, TCF_IN_FUNCTION     * will be set in tc->flags, and we can be sure fp->fun is the function to     * use.  But if a function calls eval, the string argument is treated as a     * Program (per ECMA), so TCF_IN_FUNCTION won't be set.     *     * What's more, when the following code is reached from eval, cx->fp->fun     * is eval's JSFunction (a native function), so we need to skip its frame.     * We should find the scripted caller's function frame just below it, but     * we code a loop out of paranoia.     */    for (fp = cx->fp; (fp->flags & JSFRAME_SPECIAL) && fp->down; fp = fp->down)        continue;    obj = fp->varobj;    fun = fp->fun;    clasp = OBJ_GET_CLASS(cx, obj);    if (fun && clasp == &js_FunctionClass) {        /* We are compiling code inside a function */        getter = js_GetLocalVariable;        setter = js_SetLocalVariable;    } else if (fun && clasp == &js_CallClass) {        /* We are compiling code from an eval inside a function */        getter = js_GetCallVariable;        setter = js_SetCallVariable;    } else {        getter = clasp->getProperty;        setter = clasp->setProperty;    }    ok = JS_TRUE;    do {        currentGetter = getter;        currentSetter = setter;        MUST_MATCH_TOKEN(TOK_NAME, JSMSG_NO_VARIABLE_NAME);        atom = CURRENT_TOKEN(ts).t_atom;        ATOM_LIST_SEARCH(ale, &tc->decls, atom);        if (ale) {            prevop = ALE_JSOP(ale);            if (JS_HAS_STRICT_OPTION(cx)                ? pn->pn_op != JSOP_DEFVAR || prevop != JSOP_DEFVAR                : pn->pn_op == JSOP_DEFCONST || prevop == JSOP_DEFCONST) {                const char *name = js_AtomToPrintableString(cx, atom);                if (!name ||                    !js_ReportCompileErrorNumber(cx, ts,                                                 (pn->pn_op != JSOP_DEFCONST &&                                                  prevop != JSOP_DEFCONST)                                                 ? JSREPORT_TS |                                                   JSREPORT_WARNING |                                                   JSREPORT_STRICT                                                 : JSREPORT_TS | JSREPORT_ERROR,                                                 JSMSG_REDECLARED_VAR,                                                 (prevop == JSOP_DEFFUN ||                                                  prevop == JSOP_CLOSURE)                                                 ? js_function_str                                                 : (prevop == JSOP_DEFCONST)                                                 ? js_const_str                                                 : js_var_str,                                                 name)) {                    return NULL;                }            }            if (pn->pn_op == JSOP_DEFVAR && prevop == JSOP_CLOSURE)                tc->flags |= TCF_FUN_CLOSURE_VS_VAR;        } else {            ale = js_IndexAtom(cx, atom, &tc->decls);            if (!ale)                return NULL;        }        ALE_SET_JSOP(ale, pn->pn_op);        pn2 = NewParseNode(cx, ts, PN_NAME, tc);        if (!pn2)            return NULL;        pn2->pn_op = JSOP_NAME;        pn2->pn_atom = atom;        pn2->pn_expr = NULL;        pn2->pn_slot = -1;        pn2->pn_attrs = (pn->pn_op == JSOP_DEFCONST)                        ? JSPROP_PERMANENT | JSPROP_READONLY                        : JSPROP_PERMANENT;        PN_APPEND(pn, pn2);        if (!fun) {            /* Don't lookup global variables at compile time. */            prop = NULL;        } else if (OBJ_IS_NATIVE(obj)) {            if (!js_LookupHiddenProperty(cx, obj, ATOM_TO_JSID(atom),                                         &pobj, &prop)) {                return NULL;            }        } else {            if (!OBJ_LOOKUP_PROPERTY(cx, obj, ATOM_TO_JSID(atom), &pobj, &prop))                return NULL;        }        if (prop && pobj == obj && OBJ_IS_NATIVE(pobj)) {            sprop = (JSScopeProperty *)prop;            if (sprop->getter == js_GetArgument) {                const char *name = js_AtomToPrintableString(cx, atom);                if (!name) {                    ok = JS_FALSE;                } else if (pn->pn_op == JSOP_DEFCONST) {                    js_ReportCompileErrorNumber(cx, ts,                                                JSREPORT_TS | JSREPORT_ERROR,                                                JSMSG_REDECLARED_PARAM,                                                name);                    ok = JS_FALSE;                } else {                    currentGetter = js_GetArgument;                    currentSetter = js_SetArgument;                    ok = js_ReportCompileErrorNumber(cx, ts,                                                     JSREPORT_TS |                                                     JSREPORT_WARNING |                                                     JSREPORT_STRICT,                                                     JSMSG_VAR_HIDES_ARG,                                                     name);                }            } else {                if (fun) {                    /* Not an argument, must be a redeclared local var. */                    if (clasp == &js_FunctionClass) {                        JS_ASSERT(sprop->getter == js_GetLocalVariable);                        JS_ASSERT((sprop->flags & SPROP_HAS_SHORTID) &&                                  (uint16) sprop->shortid < fun->nvars);                    } else if (clasp == &js_CallClass) {                        if (sprop->getter == js_GetCallVariable) {                            /*                             * Referencing a variable introduced by a var                             * statement in the enclosing function. Check                             * that the slot number we have is in range.                             */                            JS_ASSERT((sprop->flags & SPROP_HAS_SHORTID) &&                                      (uint16) sprop->shortid < fun->nvars);                        } else {                            /*                             * A variable introduced through another eval:                             * don't use the special getters and setters                             * since we can't allocate a slot in the frame.                             */                            currentGetter = sprop->getter;                            currentSetter = sprop->setter;                        }                    }                    /* Override the old getter and setter, to handle eval. */                    sprop = js_ChangeNativePropertyAttrs(cx, obj, sprop,                                                         0, sprop->attrs,                                                         currentGetter,                                                         currentSetter);                    if (!sprop)                        ok = JS_FALSE;                }            }        } else {            /*             * Property not found in current variable scope: we have not seen             * this variable before.  Define a new local variable by adding a             * property to the function's scope, allocating one slot in the             * function's frame.  Global variables and any locals declared in             * with statement bodies are handled at runtime, by script prolog             * JSOP_DEFVAR bytecodes generated for slot-less vars.             */            sprop = NULL;            if (prop) {                OBJ_DROP_PROPERTY(cx, pobj, prop);                prop = NULL;            }            if (currentGetter == js_GetCallVariable) {                /* Can't increase fun->nvars in an active frame! */                currentGetter = clasp->getProperty;                currentSetter = clasp->setProperty;            }            if (currentGetter == js_GetLocalVariable &&                atom != cx->runtime->atomState.argumentsAtom &&                fp->scopeChain == obj &&                !js_InWithStatement(tc)) {                if (!js_AddHiddenProperty(cx, obj, ATOM_TO_JSID(atom),                                          currentGetter, currentSetter,                                          SPROP_INVALID_SLOT,                                          pn2->pn_attrs | JSPROP_SHARED,                                          SPROP_HAS_SHORTID, fun->nvars)) {                    return NULL;                }                if (fun->nvars == JS_BITMASK(16)) {                    JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL,                                         JSMSG_TOO_MANY_FUN_VARS);                    return NULL;                }                fun->nvars++;            }        }        if (js_MatchToken(cx, ts, TOK_ASSIGN)) {            if (CURRENT_TOKEN(ts).t_op != JSOP_NOP) {                js_ReportCompileErrorNumber(cx, ts,                                            JSREPORT_TS | JSREPORT_ERROR,                                            JSMSG_BAD_VAR_INIT);                ok = JS_FALSE;            } else {                pn2->pn_expr = AssignExpr(cx, ts, tc);                if (!pn2->pn_expr) {                    ok = JS_FALSE;                } else {                    pn2->pn_op = (pn->pn_op == JSOP_DEFCONST)                                 ? JSOP_SETCONST                                 : JSOP_SETNAME;                    if (atom == cx->runtime->atomState.argumentsAtom)                        tc->flags |= TCF_FUN_HEAVYWEIGHT;                }            }        }        if (prop)            OBJ_DROP_PROPERTY(cx, pobj, prop);        if (!ok)            return NULL;    } while (js_MatchToken(cx, ts, TOK_COMMA));    pn->pn_pos.end = PN_LAST(pn)->pn_pos.end;    return pn;}static JSParseNode *Expr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc){    JSParseNode *pn, *pn2;    pn = AssignExpr(cx, ts, tc);    if (pn && js_MatchToken(cx, ts, TOK_COMMA)) {        pn2 = NewParseNode(cx, ts, PN_LIST, tc);        if (!pn2)            return NULL;        pn2->pn_pos.begin = pn->pn_pos.begin;        PN_INIT_LIST_1(pn2, pn);        pn = pn2;        do {            pn2 = AssignExpr(cx, ts, tc);            if (!pn2)                return NULL;            PN_APPEND(pn, pn2);        } while (js_MatchToken(cx, ts, TOK_COMMA));        pn->pn_pos.end = PN_LAST(pn)->pn_pos.end;    }    return pn;}static JSParseNode *AssignExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc){    JSParseNode *pn, *pn2;    JSTokenType tt;    JSOp op;    CHECK_RECURSION();    pn = CondExpr(cx, ts, tc);    if (!pn)        return NULL;    tt = js_GetToken(cx, ts);#if JS_HAS_GETTER_SETTER    if (tt == TOK_NAME) {        tt = CheckGetterOrSetter(cx, ts, TOK_ASSIGN);        if (tt == TOK_ERROR)            return NULL;    }#endif    if (tt != TOK_ASSIGN) {        js_UngetToken(ts);        return pn;    }    op = CURRENT_TOKEN(ts).t_op;    for (pn2 = pn; pn2->pn_type == TOK_RP; pn2 = pn2->pn_kid)        continue;    switch (pn2->pn_type) {      case TOK_NAME:        pn2->pn_op = JSOP_SETNAME;        if (pn2->pn_atom == cx->runtime->atomState.argumentsAtom)            tc->flags |= TCF_FUN_HEAVYWEIGHT;        break;      case TOK_DOT:        pn2->pn_op = (pn2->pn_op == JSOP_GETMETHOD)                     ? JSOP_SETMETHOD                     : JSOP_SETPROP;        break;      case TOK_LB:        pn2->pn_op = JSOP_SETELEM;        break;#if JS_HAS_LVALUE_RETURN      case TOK_LP:        if (pn2->pn_op == JSOP_CALL) {            pn2->pn_op = JSOP_SETCALL;            break;        }        /* FALL THROUGH */#endif#if JS_HAS_XML_SUPPORT      case TOK_UNARYOP:        if (pn2->pn_op == JSOP_XMLNAME) {            pn2->pn_op = JSOP_SETXMLNAME;            break;        }        /* FALL THROUGH */#endif      default:        js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR,                                    JSMSG_BAD_LEFTSIDE_OF_ASS);        return NULL;    }    pn = NewBinary(cx, TOK_ASSIGN, op, pn2, AssignExpr(cx, ts, tc), tc);    return pn;}static JSParseNode *CondExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc){    JSParseNode *pn, *pn1, *pn2, *pn3;#if JS_HAS_IN_OPERATOR    uintN oldflags;#endif /* JS_HAS_IN_OPERATOR */    pn = OrExpr(cx, ts, tc);    if (pn && js_MatchToken(cx, ts, TOK_HOOK)) {        pn1 = pn;        pn = NewParseNode(cx, ts, PN_TERNARY, tc);        if (!pn)            return NULL;#if JS_HAS_IN_OPERATOR        /*         * Always accept the 'in' operator in the middle clause of a ternary,         * where it's unambiguous, even if we might be parsing the init of a         * for statement.         */        oldflags = tc->flags;        tc->flags &= ~TCF_IN_FOR_INIT;#endif /* JS_HAS_IN_OPERATOR */        pn2 = AssignExpr(cx, ts, tc);#if JS_HAS_IN_OPERATOR        tc->flags = oldflags | (tc->flags & TCF_FUN_FLAGS);#endif /* JS_HAS_IN_OPERATOR */        if (!pn2)            return NULL;        MUST_MATCH_TOKEN(TOK_COLON, JSMSG_COLON_IN_COND);        pn3 = AssignExpr(cx, ts, tc);        if (!pn3)            return NULL;        pn->pn_pos.begin = pn1->pn_pos.begin;        pn->pn_pos.end = pn3->pn_pos.end;        pn->pn_kid1 = pn1;        pn->pn_kid2 = pn2;        pn->pn_kid3 = pn3;    }    return pn;}static JSParseNode *OrExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc){    JSParseNode *pn;    pn = AndExpr(cx, ts, tc);    if (pn && js_MatchToken(cx, ts, TOK_OR))        pn = NewBinary(cx, TOK_OR, JSOP_OR, pn, OrExpr(cx, ts, tc), tc);    return pn;}static JSParseNode *AndExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc){    JSParseNode *pn;    pn = BitOrExpr(cx, ts, tc);    if (pn && js_MatchToken(cx, ts, TOK_AND))        pn = NewBinary(cx, TOK_AND, JSOP_AND, pn, AndExpr(cx, ts, tc), tc);    return pn;}static JSParseNode *BitOrExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc){    JSParseNode *pn;    pn = BitXorExpr(cx, ts, tc);    while (pn && js_MatchToken(cx, ts, TOK_BITOR)) {        pn = NewBinary(cx, TOK_BITOR, JSOP_BITOR, pn, BitXorExpr(cx, ts, tc),                       tc);    }    return pn;}static JSParseNode *BitXorExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc){    JSParseNode *pn;    pn = BitAndExpr(cx, ts, tc);    while (pn && js_MatchToken(cx, ts, TOK_BITXOR)) {        pn = NewBinary(cx, TOK_BITXOR, JSOP_BITXOR, pn, BitAndExpr(cx, ts, tc),                       tc);    }    return pn;}static JSParseNode *BitAndExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc){    JSParseNode *pn;    pn = EqExpr(cx, ts, tc);    while (pn && js_MatchToken(cx, ts, TOK_BITAND))        pn = NewBinary(cx, TOK_BITAND, JSOP_BITAND, pn, EqExpr(cx, ts, tc), tc);    return pn;}static JSParseNode *EqExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc){    JSParseNode *pn;    JSOp op;    pn = RelExpr(cx, ts, tc);    while (pn && js_MatchToken(cx, ts, TOK_EQOP)) {        op = CURRENT_TOKEN(ts).t_op;        pn = NewBinary(cx, TOK_EQOP, op, pn, RelExpr(cx, ts, tc), tc);    }    return pn;}static JSParseNode *RelExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc){    JSParseNode *pn;    JSTokenType tt;    JSOp op;#if JS_HAS_IN_OPERATOR    uintN inForInitFlag = tc->flags & TCF_IN_FOR_INIT;    /*     * Uses of the in operator in ShiftExprs are always unambiguous,     * so unset the flag that prohibits recognizing it.     */    tc->flags &= ~TCF_IN_FOR_INIT;#endif /* JS_HAS_IN_OPERATOR */    pn = ShiftExpr(cx, ts, tc);    while (pn &&           (js_MatchToken(cx, ts, TOK_RELOP)#if JS_HAS_IN_OPERATOR            /*             * Recognize the 'in' token as an operator only if we're not             * currently in the init expr of a for loop.             */            || (inForInitFlag == 0 && js_MatchToken(cx, ts, TOK_IN))#endif /* JS_HAS_IN_OPERATOR */#if JS_HAS_INSTANCEOF            || js_MatchToken(cx, ts, TOK_INSTANCEOF)#endif /* JS_HAS_INSTANCEOF */            )) {        tt = CURRENT_TOKEN(ts).type;        op = CURRENT_TOKEN(ts).t_op;        pn = NewBinary(cx, tt, op, pn, ShiftExpr(cx, ts, tc), tc);    }#if JS_HAS_IN_OPERATOR    /* Restore previous state of inForInit flag. */    tc->flags |= inForInitFlag;#endif /* JS_HAS_IN_OPERATOR */    return pn;}static JSParseNode *ShiftExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc){    JSParseNode *pn;    JSOp op;    pn = AddExpr(cx, ts, tc);    while (pn && js_MatchToken(cx, ts, TOK_SHOP)) {        op = CURRENT_TOKEN(ts).t_op;        pn = NewBinary(cx, TOK_SHOP, op, pn, AddExpr(cx, ts, tc), tc);    }    return pn;}static JSParseNode *AddExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc){    JSParseNode *pn;    JSTokenType tt;    JSOp op;    pn = MulExpr(cx, ts, tc);    while (pn &&           (js_MatchToken(cx, ts, TOK_PLUS) ||            js_MatchToken(cx, ts, TOK_MINUS))) {        tt = CURRENT_TOKEN(ts).type;        op = (tt == TOK_PLUS) ? JSOP_ADD : JSOP_SUB;        pn = NewBinary(cx, tt, op, pn, MulExpr(cx, ts, tc), tc);    }    return pn;}static JSParseNode *MulExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc){    JSParseNode *pn;    JSTokenType tt;    JSOp op;    pn = UnaryExpr(cx, ts, tc);    while (pn &&           (js_MatchToken(cx, ts, TOK_STAR) ||            js_MatchToken(cx, ts, TOK_DIVOP))) {        tt = CURRENT_TOKEN(ts).type;        op = CURRENT_TOKEN(ts).t_op;        pn = NewBinary(cx, tt, op, pn, UnaryExpr(cx, ts, tc), tc);    }    return pn;}static JSParseNode *SetLvalKid(JSContext *cx, JSTokenStream *ts, JSParseNode *pn, JSParseNode *kid,           const char *name){    while (kid->pn_type == TOK_RP)        kid = kid->pn_kid;    if (kid->pn_type != TOK_NAME &&        kid->pn_type != TOK_DOT &&#if JS_HAS_LVALUE_RETURN        (kid->pn_type != TOK_LP || kid->pn_op != JSOP_CALL) &&#endif#if JS_HAS_XML_SUPPORT        (kid->pn_type != TOK_UNARYOP || kid->pn_op != JSOP_XMLNAME) &&#endif        kid->pn_type != TOK_LB) {        js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR,                                    JSMSG_BAD_OPERAND, name);        return NULL;    }    pn->pn_kid = kid;    return kid;}static const char *incop_name_str[] = {"increment", "decrement"};static JSBoolSetIncOpKid(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,            JSParseNode *pn, JSParseNode *kid,            JSTokenType tt, JSBool preorder){    JSOp op;    kid = SetLvalKid(cx, ts, pn, kid, incop_name_str[tt == TOK_DEC]);    if (!kid)        return JS_FALSE;    switch (kid->pn_type) {      case TOK_NAME:        op = (tt == TOK_INC)             ? (preorder ? JSOP_INCNAME : JSOP_NAMEINC)             : (preorder ? JSOP_DECNAME : JSOP_NAMEDEC);        if (kid->pn_atom == cx->runtime->atomState.argumentsAtom)            tc->flags |= TCF_FUN_HEAVYWEIGHT;        break;      case TOK_DOT:        op = (tt == TOK_INC)             ? (preorder ? JSOP_INCPROP : JSOP_PROPINC)             : (preorder ? JSOP_DECPROP : JSOP_PROPDEC);        break;#if JS_HAS_LVALUE_RETURN      case TOK_LP:        JS_ASSERT(kid->pn_op == JSOP_CALL);        kid->pn_op = JSOP_SETCALL;        /* FALL THROUGH */#endif#if JS_HAS_XML_SUPPORT      case TOK_UNARYOP:        if (kid->pn_op == JSOP_XMLNAME)            kid->pn_op = JSOP_SETXMLNAME;        /* FALL THROUGH */#endif      case TOK_LB:        op = (tt == TOK_INC)             ? (preorder ? JSOP_INCELEM : JSOP_ELEMINC)             : (preorder ? JSOP_DECELEM : JSOP_ELEMDEC);        break;      default:        JS_ASSERT(0);        op = JSOP_NOP;    }    pn->pn_op = op;    return JS_TRUE;}static JSParseNode *UnaryExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc){    JSTokenType tt;    JSParseNode *pn, *pn2;    CHECK_RECURSION();    ts->flags |= TSF_OPERAND;    tt = js_GetToken(cx, ts);    ts->flags &= ~TSF_OPERAND;    switch (tt) {      case TOK_UNARYOP:      case TOK_PLUS:      case TOK_MINUS:        pn = NewParseNode(cx, ts, PN_UNARY, tc);        if (!pn)            return NULL;        pn->pn_type = TOK_UNARYOP;      /* PLUS and MINUS are binary */        pn->pn_op = CURRENT_TOKEN(ts).t_op;        pn2 = UnaryExpr(cx, ts, tc);        if (!pn2)            return NULL;        pn->pn_pos.end = pn2->pn_pos.end;        pn->pn_kid = pn2;        break;      case TOK_INC:      case TOK_DEC:        pn = NewParseNode(cx, ts, PN_UNARY, tc);        if (!pn)            return NULL;        pn2 = MemberExpr(cx, ts, tc, JS_TRUE);        if (!pn2)            return NULL;        if (!SetIncOpKid(cx, ts, tc, pn, pn2, tt, JS_TRUE))            return NULL;        pn->pn_pos.end = pn2->pn_pos.end;        break;      case TOK_DELETE:        pn = NewParseNode(cx, ts, PN_UNARY, tc);        if (!pn)            return NULL;        pn2 = UnaryExpr(cx, ts, tc);        if (!pn2)            return NULL;        pn->pn_pos.end = pn2->pn_pos.end;        /*         * Under ECMA3, deleting any unary expression is valid -- it simply         * returns true. Here we strip off any parentheses.         */        while (pn2->pn_type == TOK_RP)            pn2 = pn2->pn_kid;        pn->pn_kid = pn2;        break;      case TOK_ERROR:        return NULL;      default:        js_UngetToken(ts);        pn = MemberExpr(cx, ts, tc, JS_TRUE);        if (!pn)            return NULL;        /* Don't look across a newline boundary for a postfix incop. */        if (ON_CURRENT_LINE(ts, pn->pn_pos)) {            tt = js_PeekTokenSameLine(cx, ts);            if (tt == TOK_INC || tt == TOK_DEC) {                (void) js_GetToken(cx, ts);                pn2 = NewParseNode(cx, ts, PN_UNARY, tc);                if (!pn2)                    return NULL;                if (!SetIncOpKid(cx, ts, tc, pn2, pn, tt, JS_FALSE))                    return NULL;                pn2->pn_pos.begin = pn->pn_pos.begin;                pn = pn2;            }        }        break;    }    return pn;}