!js_ReportCompileErrorNumber(cx, ts, NULL,
!js_ReportCompileErrorNumber(cx, ts,
static JSParser FunctionExpr;#endifstatic JSParser Statements;static JSParser Statement;static JSParser Variables;static JSParser Expr;static JSParser AssignExpr;static JSParser CondExpr;static JSParser OrExpr;static JSParser AndExpr;static JSParser BitOrExpr;static JSParser BitXorExpr;static JSParser BitAndExpr;static JSParser EqExpr;static JSParser RelExpr;static JSParser ShiftExpr;static JSParser AddExpr;static JSParser MulExpr;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, NULL, JSREPORT_ERROR, errno); \            return NULL;                                                      \        }                                                                     \    JS_END_MACRO/* * Allocate a JSParseNode from cx's temporary arena. */static JSParseNode *NewParseNode(JSContext *cx, JSToken *tok, JSParseNodeArity arity){    JSParseNode *pn;    JS_ARENA_ALLOCATE_TYPE(pn, JSParseNode, &cx->tempPool);    if (!pn)        return NULL;    pn->pn_type = tok->type;    pn->pn_pos = tok->pos;    pn->pn_op = JSOP_NOP;    pn->pn_arity = arity;    pn->pn_next = NULL;    return pn;}static JSParseNode *NewBinary(JSContext *cx, JSTokenType tt,          JSOp op, JSParseNode *left, JSParseNode *right){    JSParseNode *pn;    if (!left || !right)        return NULL;    JS_ARENA_ALLOCATE_TYPE(pn, JSParseNode, &cx->tempPool);    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;    return pn;}static JSBoolWellTerminated(JSContext *cx, JSTokenStream *ts, JSTokenType lastExprType){    JSTokenType tt;    tt = js_PeekTokenSameLine(cx, ts);    if (tt == TOK_ERROR)        return JS_FALSE;    if (tt != TOK_EOF && tt != TOK_EOL && tt != TOK_SEMI && tt != TOK_RC) {#if JS_HAS_LEXICAL_CLOSURE        if ((tt == TOK_FUNCTION || lastExprType == TOK_FUNCTION) &&            cx->version < JSVERSION_1_2) {            /*             * Checking against version < 1.2 and version >= 1.0             * in the above line breaks old javascript, so we keep it             * this way for now... XXX warning needed?             */            return JS_TRUE;        }#endif        js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,                                    JSMSG_SEMI_BEFORE_STMNT);        return JS_FALSE;    }    return JS_TRUE;}#if JS_HAS_GETTER_SETTERstatic JSTokenTypeCheckGetterOrSetter(JSContext *cx, JSTokenStream *ts, JSTokenType tt){    JSAtom *atom;    JSRuntime *rt;    JSOp op;    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, NULL, 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;    if (!js_ReportCompileErrorNumber(cx, ts, NULL,                                     JSREPORT_WARNING |                                     JSREPORT_STRICT,                                     JSMSG_DEPRECATED_USAGE,                                     ATOM_BYTES(atom))) {        return TOK_ERROR;    }    return tt;}#endif/* * Parse a top-level JS script. */JS_FRIEND_API(JSBool)js_CompileTokenStream(JSContext *cx, JSObject *chain, JSTokenStream *ts,                      JSCodeGenerator *cg){    JSStackFrame *fp, frame;    JSBool ok;    JSParseNode *pn;    fp = cx->fp;    if (!fp || fp->varobj != chain || fp->scopeChain != chain) {        memset(&frame, 0, sizeof frame);        frame.varobj = frame.scopeChain = chain;        frame.down = fp;        cx->fp = &frame;    }    /*     * Prevent GC activation on this context (possible if out of memory when     * atomizing, or from pre-ECMAv2 switch case expr eval in the unlikely     * case of a branch-callback -- unlikely because it means the switch case     * must have called a function).     */    JS_DISABLE_GC(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, NULL, JSREPORT_ERROR,                                    JSMSG_SYNTAX_ERROR);        ok = JS_FALSE;    } else {        pn->pn_type = TOK_LC;        ok = js_FoldConstants(cx, pn) &&             js_AllocTryNotes(cx, cg) &&             js_EmitTree(cx, cg, pn);    }    JS_ENABLE_GC(cx->runtime);    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). */static JSBoolCheckFinalReturn(JSParseNode *pn){    JSBool ok, hasDefault;    JSParseNode *pn2, *pn3;    switch (pn->pn_type) {      case TOK_LC:        if (!pn->pn_head)            return JS_FALSE;        return CheckFinalReturn(PN_LAST(pn));      case TOK_IF:        ok = CheckFinalReturn(pn->pn_kid2);        ok &= pn->pn_kid3 && CheckFinalReturn(pn->pn_kid3);        return ok;#if JS_HAS_SWITCH_STATEMENT      case TOK_SWITCH:        ok = JS_TRUE;        hasDefault = JS_FALSE;        for (pn2 = pn->pn_kid2->pn_head; ok && pn2; pn2 = pn2->pn_next) {            if (pn2->pn_type == TOK_DEFAULT)                hasDefault = JS_TRUE;            pn3 = pn2->pn_right;            JS_ASSERT(pn3->pn_type == TOK_LC);            if (pn3->pn_head)                ok &= CheckFinalReturn(PN_LAST(pn3));        }        /* If a final switch has no default case, we judge it harshly. */        ok &= hasDefault;        return ok;#endif /* JS_HAS_SWITCH_STATEMENT */      case TOK_WITH:        return CheckFinalReturn(pn->pn_right);      case TOK_RETURN:        return JS_TRUE;#if JS_HAS_EXCEPTIONS      case TOK_THROW:        return JS_TRUE;      case TOK_TRY:        /* If we have a finally block that returns, we are done. */        if (pn->pn_kid3 && CheckFinalReturn(pn->pn_kid3))            return JS_TRUE;        /* Else check the try block and any and all catch statements. */        ok = CheckFinalReturn(pn->pn_kid1);        if (pn->pn_kid2)            ok &= CheckFinalReturn(pn->pn_kid2);        return ok;      case TOK_CATCH:        /* Check this block's code and iterate over further catch blocks. */        ok = CheckFinalReturn(pn->pn_kid3);        for (pn2 = pn->pn_kid2; pn2; pn2 = pn2->pn_kid2)            ok &= CheckFinalReturn(pn2->pn_kid3);        return ok;#endif      default:        return JS_FALSE;    }}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;        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(pn)) {            JSBool ok;            if (fun->atom) {                char *name = js_GetStringBytes(ATOM_TO_STRING(fun->atom));                ok = js_ReportCompileErrorNumber(cx, ts, NULL,                                                 JSREPORT_WARNING |                                                 JSREPORT_STRICT,                                                 JSMSG_NO_RETURN_VALUE, name);            } else {                ok = js_ReportCompileErrorNumber(cx, ts, NULL,                                                 JSREPORT_WARNING |                                                 JSREPORT_STRICT,                                                 JSMSG_ANON_NO_RETURN_VALUE);            }            if (!ok)                pn = NULL;        }    }    cx->fp = fp;    tc->flags = oldflags | (tc->flags & TCF_FUN_FLAGS);    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){    JSCodeGenerator funcg;    JSParseNode *pn;    JSBool ok;    if (!js_InitCodeGenerator(cx, &funcg, ts->filename, ts->lineno,                              ts->principals)) {        return JS_FALSE;    }    /* Prevent GC activation on this context during compilation. */    JS_DISABLE_GC(cx->runtime);    /* Ensure that the body looks like a block statement to js_EmitTree. */    CURRENT_TOKEN(ts).type = TOK_LC;    pn = FunctionBody(cx, ts, fun, &funcg.treeContext);    if (!pn) {        ok = JS_FALSE;    } else {        ok = js_FoldConstants(cx, pn) &&             js_EmitFunctionBody(cx, &funcg, pn, fun);    }    JS_ENABLE_GC(cx->runtime);    js_FinishCodeGenerator(cx, &funcg);    return ok;}static JSParseNode *FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,            JSBool lambda){    JSParseNode *pn, *pn2, *body;    JSOp op;    JSAtom *funAtom, *argAtom;    JSFunction *fun;    JSObject *parent;    JSObject *pobj;    JSScopeProperty *sprop;    JSTreeContext funtc;    jsid oldArgId;    JSAtomListElement *ale;    /* Make a TOK_FUNCTION node. */    pn = NewParseNode(cx, &CURRENT_TOKEN(ts), PN_FUNC);    if (!pn)        return NULL;    op = CURRENT_TOKEN(ts).t_op;    /* Scan the optional function name into funAtom. */    if (js_MatchToken(cx, ts, TOK_NAME))        funAtom = CURRENT_TOKEN(ts).t_atom;    else        funAtom = NULL;    /* Find the nearest variable-declaring scope and use it as our parent. */    parent = cx->fp->varobj;    fun = js_NewFunction(cx, NULL, NULL, 0, 0, parent, funAtom);    if (!fun)        return NULL;#if JS_HAS_GETTER_SETTER    if (op != JSOP_NOP)        fun->flags |= (op == JSOP_GETTER) ? JSPROP_GETTER : JSPROP_SETTER;#endif    /* 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_LookupProperty(cx, fun->object, (jsid)argAtom, &pobj,                                   (JSProperty **)&sprop)) {                return NULL;            }            if (sprop && pobj == fun->object) {                if (SPROP_GETTER(sprop, pobj) == js_GetArgument) {                    if (JS_HAS_STRICT_OPTION(cx)) {                        OBJ_DROP_PROPERTY(cx, pobj, (JSProperty *)sprop);                        if (!js_ReportCompileErrorNumber(cx, ts, NULL,                                                         JSREPORT_WARNING |                                                         JSREPORT_STRICT,                                                         JSMSG_DUPLICATE_FORMAL,                                                         ATOM_BYTES(argAtom))) {                            return NULL;                        }                    }                    /*                     * A duplicate parameter name. We create a dummy symbol                     * entry with property id of the parameter number and set                     * the id to the name of the parameter.                     * The decompiler will know to treat this case specially.                     */                    oldArgId = (jsid) sprop->id;                    OBJ_DROP_PROPERTY(cx, pobj, (JSProperty *)sprop);                    sprop = NULL;                    if (!js_DefineProperty(cx, fun->object,                                           oldArgId, JSVAL_VOID,                                           js_GetArgument, js_SetArgument,                                           JSPROP_ENUMERATE | JSPROP_PERMANENT,                                           (JSProperty **)&sprop)) {                        return NULL;                    }                    sprop->id = (jsid) argAtom;                }            }            if (sprop) {                OBJ_DROP_PROPERTY(cx, pobj, (JSProperty *)sprop);                sprop = NULL;            }            if (!js_DefineProperty(cx, fun->object,                                   (jsid)argAtom, JSVAL_VOID,                                   js_GetArgument, js_SetArgument,                                   JSPROP_ENUMERATE | JSPROP_PERMANENT,                                   (JSProperty **)&sprop)) {                return NULL;            }            JS_ASSERT(sprop);            sprop->id = INT_TO_JSVAL(fun->nargs++);            OBJ_DROP_PROPERTY(cx, fun->object, (JSProperty *)sprop);        } 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 we collected flags that include nested functions or with statements     * while compiling our body, flag the function as heavyweight (requiring     * a call object per invocation).  Therefore, update tc->flags to reflect     * the fact that the outer context contains this function, and may also be     * heavy if it is a function body.     */    if (funtc.flags & TCF_FUN_HEAVYWEIGHT)        fun->flags |= JSFUN_HEAVYWEIGHT;    tc->flags |= TCF_FUN_HEAVYWEIGHT;    /*     * 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) {            pn2 = ALE_NODE(ale);            op = pn2->pn_op;            if ((JS_HAS_STRICT_OPTION(cx) || op == JSOP_DEFCONST) &&                !js_ReportCompileErrorNumber(cx, ts, NULL,                                             (op != JSOP_DEFCONST)                                             ? JSREPORT_WARNING|JSREPORT_STRICT                                             : JSREPORT_ERROR,                                             JSMSG_REDECLARED_VAR,                                             (pn2->pn_type == TOK_FUNCTION)                                             ? js_function_str                                             : (op == JSOP_DEFCONST)                                             ? js_const_str                                             : js_var_str,                                             ATOM_BYTES(funAtom))) {                return NULL;            }            if (op == JSOP_DEFVAR)                tc->flags |= TCF_FUN_VS_VAR;        } else {            ale = js_IndexAtom(cx, funAtom, &tc->decls);            if (!ale)                return NULL;        }        ALE_SET_NODE(ale, pn);    }#if JS_HAS_LEXICAL_CLOSURE    if (lambda || !fun->atom) {        /*         * ECMA ed. 3 standard: function expression, possibly anonymous (even         * if at top-level, an unnamed function is an expression statement, not         * a function declaration).         */        op = fun->atom ? JSOP_NAMEDFUNOBJ : JSOP_ANONFUNOBJ;    } else if (!(tc->flags & TCF_TOP_LEVEL) || cx->fp->scopeChain != parent) {        /*         * 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.         *         * The scopeChain != parent test handles eval called from inside a         * with statement body.         */        op = JSOP_CLOSURE;    } else#endif        op = JSOP_NOP;    pn->pn_op = op;    pn->pn_fun = fun;    pn->pn_body = body;    pn->pn_flags = funtc.flags & TCF_FUN_FLAGS;    pn->pn_tryCount = funtc.tryCount;    TREE_CONTEXT_FREE(&funtc);    return pn;}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);}