else if (lambda) pn->pn_op = JSOP_OBJECT;
else if (lambda || !fun->atom) pn->pn_op = fun->atom ? JSOP_NAMEDFUNOBJ : JSOP_ANONFUNOBJ;
static JSParser FunctionStmt;#if JS_HAS_LEXICAL_CLOSUREstatic 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, 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(pn, &cx->tempPool, sizeof(JSParseNode));    if (!pn)	return NULL;    pn->pn_type = tok->type;    pn->pn_pos = tok->pos;    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(pn, &cx->tempPool, sizeof(JSParseNode));    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, 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, 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;    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;    JSTokenType tt;    JSBool ok;    JSParseNode *pn;    fp = cx->fp;    if (!fp || fp->scopeChain != chain) {	memset(&frame, 0, sizeof frame);	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);    ok = JS_TRUE;    do {	ts->flags |= TSF_REGEXP;	tt = js_GetToken(cx, ts);	ts->flags &= ~TSF_REGEXP;	if (tt <= TOK_EOF) {	    if (tt == TOK_ERROR)		ok = JS_FALSE;	    break;	}#if JS_HAS_GETTER_SETTER        if (tt == TOK_NAME) {            tt = CheckGetterOrSetter(cx, ts, TOK_FUNCTION);            if (tt == TOK_ERROR) {		ok = JS_FALSE;                break;            }        }#endif	if (tt == TOK_FUNCTION) {	    pn = FunctionStmt(cx, ts, &cg->treeContext);	    if (pn && pn->pn_pos.end.lineno == ts->lineno) {                ok = WellTerminated(cx, ts, TOK_FUNCTION);                if (!ok)                    break;	    }        } else {	    js_UngetToken(ts);	    pn = Statement(cx, ts, &cg->treeContext);	}	if (!pn) {	    ok = JS_FALSE;            break;	}        ok = js_FoldConstants(cx, pn);        if (!ok)            break;        ok = js_AllocTryNotes(cx, cg);        if (!ok)            break;        ok = js_EmitTree(cx, cg, pn);    } while (ok);    JS_ENABLE_GC(cx->runtime);    ts->flags &= ~TSF_ERROR;    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 an error XXX should be warning * option). */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;	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;      default:	return JS_FALSE;    }}static JSParseNode *FunctionBody(JSContext *cx, JSTokenStream *ts, JSFunction *fun,	     JSTreeContext *tc){    JSStackFrame *fp, frame;    uintN oldflags;    JSParseNode *pn;    fp = cx->fp;    if (!fp || fp->scopeChain != fun->object) {	memset(&frame, 0, sizeof frame);	frame.scopeChain = fun->object;	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)) {            if (fun->atom) {                char *name = js_GetStringBytes(ATOM_TO_STRING(fun->atom));                js_ReportCompileErrorNumber(cx, ts, JSREPORT_ERROR,                                            JSMSG_NO_RETURN_VALUE, name);            } else {                js_ReportCompileErrorNumber(cx, ts, JSREPORT_ERROR,                                            JSMSG_ANON_NO_RETURN_VALUE);            }	    pn = NULL;	}    }    cx->fp = fp;    tc->flags = oldflags;    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);    /* Satisfy the assertion at the top of Statements. */    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 JSBoolInWithStatement(JSTreeContext *tc){    JSStmtInfo *stmt;    for (stmt = tc->topStmt; stmt; stmt = stmt->down) {	if (stmt->type == STMT_WITH)	    return JS_TRUE;    }    return JS_FALSE;}static JSParseNode *FunctionDef(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc,            JSBool lambda){    JSParseNode *pn, *pn2;    JSOp op;    JSAtom *funAtom, *argAtom;    JSFunction *fun, *outerFun;    JSObject *parent;    JSObject *pobj;    JSScopeProperty *sprop;    JSTreeContext funtc;    jsid oldArgId;    /* 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 = js_FindVariableScope(cx, &outerFun);    if (!parent)	return NULL;    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);                        js_ReportCompileErrorNumber(cx, ts, JSREPORT_ERROR,                                                    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);    pn2 = FunctionBody(cx, ts, fun, &funtc);    if (!pn2)	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    /*     * Generate a closure if in a nested function, or if in 'with (o) eval(s)'     * where s contains a function definition, or if in a with statement being     * compiled from the same source that contains this function.  Otherwise,     * if in a lambda expression, generate a function object reference.  Else,     * generate an annotated NOP for a top-level function.     */    if (outerFun || cx->fp->scopeChain != parent || InWithStatement(tc))        pn->pn_op = JSOP_CLOSURE;    else if (lambda)        pn->pn_op = JSOP_OBJECT;    else#endif        pn->pn_op = JSOP_NOP;    pn->pn_fun = fun;    pn->pn_body = pn2;    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);}