static JSParser FunctionStmt; #if JS_HAS_LEXICAL_CLOSURE static JSParser FunctionExpr; #endif static 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 JSParser MemberExpr; static JSParser PrimaryExpr;   #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)   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 JSBool WellTerminated(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; }   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; }   static JSBool CheckFinalReturn(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:  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  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; }   JSBool js_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; }   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 JSBool InWithStatement(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;   pn = NewParseNode(cx, &ts->token, PN_FUNC); if (!pn) return NULL;   if (js_MatchToken(cx, ts, TOK_NAME)) funAtom = ts->token.t_atom; else funAtom = NULL;   parent = js_FindVariableScope(cx, &outerFun); if (!parent) return NULL;   topStmt = tc->topStmt; tc->topStmt = NULL;  #if JS_HAS_LEXICAL_CLOSURE if (!funAtom || cx->fp->scopeChain != parent || InWithStatement(tc)) {  fun = js_NewFunction(cx, NULL, NULL, 0, 0, cx->fp->scopeChain, funAtom); named = JS_FALSE; } else #endif {  fun = js_DefineFunction(cx, parent, funAtom, NULL, 0, JSPROP_ENUMERATE); named = (fun != NULL); } if (!fun) { ok = JS_FALSE; goto out; }   MUST_MATCH_TOKEN_THROW(TOK_LP, "missing ( before formal parameters", ok = JS_FALSE; goto out);  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));   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);}