if (sprop->getter == js_GetArgument) { OBJ_DROP_PROPERTY(cx, pobj, (JSProperty *)sprop); js_ReportCompileError(cx, ts, "duplicate formal argument %s", ATOM_BYTES(argAtom)); ok = JS_FALSE; goto out; } #endif sprop->getter = js_GetArgument; sprop->setter = js_SetArgument; sprop->attrs |= JSPROP_ENUMERATE | JSPROP_PERMANENT; } else { if (sprop) { OBJ_DROP_PROPERTY(cx, pobj, (JSProperty *)sprop); sprop = NULL; } ok = js_DefineProperty(cx, fun->object, (jsid)argAtom, JSVAL_VOID, js_GetArgument, js_SetArgument, JSPROP_ENUMERATE | JSPROP_PERMANENT, (JSProperty **)&sprop);
OBJ_DROP_PROPERTY(cx, pobj, (JSProperty *)sprop); js_ReportCompileError(cx, ts, "duplicate formal argument %s", ATOM_BYTES(argAtom)); ok = JS_FALSE; goto out; #else  jsid oldArgId = (jsid) sprop->id; OBJ_DROP_PROPERTY(cx, pobj, (JSProperty *)sprop); sprop = NULL; ok = js_DefineProperty(cx, fun->object, oldArgId, JSVAL_VOID, js_GetArgument, js_SetArgument, JSPROP_ENUMERATE | JSPROP_PERMANENT, (JSProperty **)&sprop); if (!ok) goto out; sprop->id = (jsid) argAtom; #endif } } if (sprop) { OBJ_DROP_PROPERTY(cx, pobj, (JSProperty *)sprop); sprop = NULL;
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 JSParseNode *MemberExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc, JSBool allowCallSyntax);static JSParser PrimaryExpr;/* * Insist that the next token be of type tt, or report err and throw or fail. * NB: this macro uses cx and ts from its lexical environment. */#define MUST_MATCH_TOKEN_THROW(tt, err, throw)                                \    PR_BEGIN_MACRO                                                            \	if (js_GetToken(cx, ts) != tt) {                                      \	    js_ReportCompileError(cx, ts, err);                               \	    throw;                                                            \	}                                                                     \    PR_END_MACRO#define MUST_MATCH_TOKEN(tt, err)                                             \    MUST_MATCH_TOKEN_THROW(tt, err, return NULL)/* * Allocate a JSParseNode from cx's temporary arena. */static JSParseNode *NewParseNode(JSContext *cx, JSToken *tok, JSParseNodeArity arity){    JSParseNode *pn;    PR_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;    PR_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) {	    return JS_TRUE;	}#endif	js_ReportCompileError(cx, ts, "missing ; before statement");	return JS_FALSE;    }    return JS_TRUE;}/* * Parse a top-level JS script. */JS_FRIEND_API(JSBool)js_CompileTokenStream(JSContext *cx, JSObject *chain, JSTokenStream *ts,		      JSCodeGenerator *cg){    JSStackFrame *fp, frame;    JSTokenType stop, 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;    }    if (ts->flags & TSF_INTERACTIVE) {	SCAN_NEWLINES(ts);	stop = TOK_EOL;    } else {	stop = TOK_EOF;    }    ok = JS_TRUE;    do {	ts->flags |= TSF_REGEXP;	tt = js_GetToken(cx, ts);	ts->flags &= ~TSF_REGEXP;	if (tt == stop || tt <= TOK_EOF) {	    if (tt == TOK_ERROR)		ok = JS_FALSE;	    break;	}	switch (tt) {	  case 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)		    goto out;            }	    break;	  default:	    js_UngetToken(ts);	    pn = Statement(cx, ts, &cg->treeContext);	    if (pn) {		ok = js_FoldConstants(cx, pn);		if (!ok)		    goto out;	    }	    break;	}	if (pn) {	    ok = js_AllocTryNotes(cx, cg);	    if (ok)		ok = js_EmitTree(cx, cg, pn);	} else {	    ok = JS_FALSE;	}    } while (ok);out:    cx->fp = fp;    if (!ok)	CLEAR_PUSHBACK(ts);    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;    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;      case TOK_SWITCH:	/* If a final switch has no default case, we judge it harshly. */      	ok = pn->pn_kid3 && CheckFinalReturn(pn->pn_kid3);      	for (pn2 = pn->pn_kid2->pn_head; ok && pn2; pn2 = pn2->pn_next) {	    pn3 = pn2->pn_right;	    PR_ASSERT(pn3->pn_type == TOK_LC);	    if (pn3->pn_head)		ok &= CheckFinalReturn(PN_LAST(pn3));	}	return ok;      case TOK_WITH:	return CheckFinalReturn(pn->pn_right);      case TOK_RETURN:      	return JS_TRUE;      default:      	return JS_FALSE;    }}static char badreturn_str[] = "function does not always return a value";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);#ifdef CHECK_RETURN_EXPR    /* Check for falling off the end of a function that returns a value. */    if (pn && (tc->flags & TCF_RETURN_EXPR)) {	if (!CheckFinalReturn(pn)) {	    js_ReportCompileError(cx, ts, badreturn_str);	    pn = NULL;	}    }#endif    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;    }    /* Satisfy the assertion at the top of Statements. */    ts->token.type = TOK_LC;    pn = FunctionBody(cx, ts, fun, &funcg.treeContext);    if (!pn) {	CLEAR_PUSHBACK(ts);	ok = JS_FALSE;    } else {	ok = js_FoldConstants(cx, pn);	if (ok)	    ok = js_EmitFunctionBody(cx, &funcg, pn, fun);    }    js_ResetCodeGenerator(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;    JSAtom *funAtom, *argAtom;    JSObject *parent;    JSFunction *fun, *outerFun;    JSStmtInfo *topStmt;    JSBool ok, named;    JSObject *pobj;    JSScopeProperty *sprop;    jsval junk;    /* Make a TOK_FUNCTION node. */    pn = NewParseNode(cx, &ts->token, PN_FUNC);    if (!pn)    	return NULL;    /* Scan the optional function name into funAtom. */    if (js_MatchToken(cx, ts, TOK_NAME))	funAtom = ts->token.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;    /* Clear tc->topStmt for semantic checking (restore at label out:). */    topStmt = tc->topStmt;    tc->topStmt = NULL;#if JS_HAS_LEXICAL_CLOSURE    if (!funAtom || cx->fp->scopeChain != parent || InWithStatement(tc)) {	/* Don't name the function if enclosed by a with statement or equiv. */	fun = js_NewFunction(cx, NULL, NULL, 0, 0, cx->fp->scopeChain,			     funAtom);	named = JS_FALSE;    } else#endif    {	/* Override any previously defined property using js_DefineFunction. */	fun = js_DefineFunction(cx, parent, funAtom, NULL, 0, JSPROP_ENUMERATE);	named = (fun != NULL);    }    if (!fun) {	ok = JS_FALSE;	goto out;    }    /* Now parse formal argument list and compute fun->nargs. */    MUST_MATCH_TOKEN_THROW(TOK_LP, "missing ( before formal parameters",			   ok = JS_FALSE; goto out);    /* balance) */    if (!js_MatchToken(cx, ts, TOK_RP)) {	do {	    MUST_MATCH_TOKEN_THROW(TOK_NAME, "missing formal parameter",				   ok = JS_FALSE; goto out);	    argAtom = ts->token.t_atom;	    pobj = NULL;	    ok = js_LookupProperty(cx, fun->object, (jsid)argAtom, &pobj,				   (JSProperty **)&sprop);	    if (!ok)		goto out;	    if (sprop && pobj == fun->object) {#ifdef CHECK_ARGUMENT_HIDING		if (sprop->getter == js_GetArgument) {		    OBJ_DROP_PROPERTY(cx, pobj, (JSProperty *)sprop);		    js_ReportCompileError(cx, ts,					  "duplicate formal argument %s",					  ATOM_BYTES(argAtom));		    ok = JS_FALSE;		    goto out;		}#endif		sprop->getter = js_GetArgument;		sprop->setter = js_SetArgument;		sprop->attrs |= JSPROP_ENUMERATE | JSPROP_PERMANENT;	    } else {		if (sprop) {		    OBJ_DROP_PROPERTY(cx, pobj, (JSProperty *)sprop);		    sprop = NULL;		}		ok = js_DefineProperty(cx, fun->object,				       (jsid)argAtom, JSVAL_VOID,				       js_GetArgument, js_SetArgument,				       JSPROP_ENUMERATE | JSPROP_PERMANENT,				       (JSProperty **)&sprop);	    }	    if (!ok)		goto out;	    PR_ASSERT(sprop);	    sprop->id = INT_TO_JSVAL(fun->nargs++);	    OBJ_DROP_PROPERTY(cx, fun->object, (JSProperty *)sprop);	} while (js_MatchToken(cx, ts, TOK_COMMA));	/* (balance: */	MUST_MATCH_TOKEN_THROW(TOK_RP, "missing ) after formal parameters",			       ok = JS_FALSE; goto out);    }    MUST_MATCH_TOKEN_THROW(TOK_LC, "missing { before function body",			   ok = JS_FALSE; goto out);    pn->pn_pos.begin = ts->token.pos.begin;    pn2 = FunctionBody(cx, ts, fun, tc);    if (!pn2) {    	ok = JS_FALSE;    	goto out;    }    MUST_MATCH_TOKEN_THROW(TOK_RC, "missing } after function body",			   ok = JS_FALSE; goto out);    pn->pn_pos.end = ts->token.pos.end;    pn->pn_fun = fun;    pn->pn_body = pn2;    pn->pn_tryCount = tc->tryCount;#if JS_HAS_LEXICAL_CLOSURE    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;    ok = JS_TRUE;out:    tc->topStmt = topStmt;    if (!ok) {	if (named)	    (void) OBJ_DELETE_PROPERTY(cx, parent, (jsid)funAtom, &junk);	return NULL;    }    return pn;}static JSParseNode *FunctionStmt(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc){    return FunctionDef(cx, ts, tc, JS_FALSE);}