PN_APPEND(pn2, pn4); if (pn2->pn_count == PR_BIT(16)) { js_ReportCompileError(cx, ts, "too many switch cases"); goto bad_switch; } break;  case TOK_DEFAULT: if (pn3) { js_ReportCompileError(cx, ts, "more than one switch default"); goto bad_switch; } pn4 = NULL; break;
} break;
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 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;}#ifdef CHECK_RETURN_EXPR/* * 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";#endif /* CHECK_RETURN_EXPR */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;    JSBool ok, named;    JSObject *pobj;    JSScopeProperty *sprop;    JSTreeContext funtc;    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;#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) {                if (sprop->getter == js_GetArgument) {#ifdef CHECK_ARGUMENT_HIDING                    OBJ_DROP_PROPERTY(cx, pobj, (JSProperty *)sprop);                    js_ReportCompileError(cx, ts,                                          "duplicate formal argument %s",                                          ATOM_BYTES(argAtom));                    ok = JS_FALSE;                    goto out;#else                    /* 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.                     */                    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;	    }	    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;    INIT_TREE_CONTEXT(&funtc);    pn2 = FunctionBody(cx, ts, fun, &funtc);    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 = funtc.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:    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);}#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.  Our caller must match { before and } after. */static JSParseNode *Statements(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc){    JSParseNode *pn, *pn2;    uintN newlines;    JSTokenType tt;    PR_ASSERT(ts->token.type == TOK_LC);    pn = NewParseNode(cx, &ts->token, PN_LIST);    if (!pn)    	return NULL;    PN_INIT_LIST(pn);    newlines = ts->flags & TSF_NEWLINES;    if (newlines)	HIDE_NEWLINES(ts);    while ((tt = js_PeekToken(cx, ts)) > TOK_EOF && tt != TOK_RC) {	pn2 = Statement(cx, ts, tc);	if (!pn2) {	    pn = NULL;	    goto out;	}	PN_APPEND(pn, pn2);    }    pn->pn_pos.end = ts->token.pos.end;    if (tt == TOK_ERROR)	pn = NULL;out:    if (newlines)	SCAN_NEWLINES(ts);    return pn;}static JSParseNode *Condition(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc){    JSParseNode *pn, *pn2;    MUST_MATCH_TOKEN(TOK_LP, "missing ( before condition");    pn = Expr(cx, ts, tc);    if (!pn)	return NULL;    MUST_MATCH_TOKEN(TOK_RP, "missing ) after condition");    /*     * Check for (a = b) and "correct" it to (a == b).     * XXX not ECMA, but documented in several books -- need a compile option     */    if (pn->pn_type == TOK_ASSIGN && pn->pn_op == JSOP_NOP) {#ifdef CHECK_EQUALITY_ASSIGNMENT	js_ReportCompileError(cx, ts,	    "test for equality (==) mistyped as assignment (=)?\n"	    "Assuming equality test");#endif    	pn->pn_type = TOK_EQOP;    	pn->pn_op = cx->jsop_eq;	pn2 = pn->pn_left;	switch (pn2->pn_op) {	  case JSOP_SETARG:	    pn2->pn_op = JSOP_GETARG;	    break;	  case JSOP_SETVAR:	    pn2->pn_op = JSOP_GETVAR;	    break;	  case JSOP_SETNAME2:	    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:	    PR_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 = ts->token.t_atom;    } else {	label = NULL;    }#else    label = NULL;#endif    pn->pn_atom = label;    if (pn->pn_pos.end.lineno == ts->lineno)	return WellTerminated(cx, ts, TOK_ERROR);    return JS_TRUE;}#if JS_HAS_EXPORT_IMPORTstatic JSParseNode *ImportExpr(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc){    JSParseNode *pn, *pn2, *pn3;    JSTokenType tt;    MUST_MATCH_TOKEN(TOK_NAME, "missing name in import statement");    pn = NewParseNode(cx, &ts->token, PN_NULLARY);    if (!pn)    	return NULL;    pn->pn_op = JSOP_NAME;    pn->pn_atom = ts->token.t_atom;    pn->pn_slot = -1;    ts->flags |= TSF_REGEXP;    while ((tt = js_GetToken(cx, ts)) == TOK_DOT || tt == TOK_LB) {	ts->flags &= ~TSF_REGEXP;	if (pn->pn_op == JSOP_IMPORTALL)	    goto bad_import;	if (tt == TOK_DOT) {	    pn2 = NewParseNode(cx, &ts->token, PN_NAME);	    if (!pn2)		return NULL;	    pn2->pn_expr = pn;	    if (js_MatchToken(cx, ts, TOK_STAR)) {		pn2->pn_op = JSOP_IMPORTALL;		pn2->pn_atom = NULL;	    } else {		MUST_MATCH_TOKEN(TOK_NAME, "missing name after . operator");		pn2->pn_op = JSOP_GETPROP;		pn2->pn_atom = ts->token.t_atom;		pn2->pn_slot = -1;	    }	    pn2->pn_pos.begin = pn->pn_pos.begin;	    pn2->pn_pos.end = ts->token.pos.end;	} else {	    /* Make a TOK_LB node. */	    pn2 = NewParseNode(cx, &ts->token, PN_BINARY);	    if (!pn2)	    	return NULL;	    pn3 = Expr(cx, ts, tc);	    if (!pn3)		return NULL;	    /* [balance: */	    MUST_MATCH_TOKEN(TOK_RB, "missing ] in index expression");	    pn2->pn_pos.begin = pn->pn_pos.begin;	    pn2->pn_pos.end = ts->token.pos.end;	    /* Optimize o['p'] to o.p by rewriting pn2. */	    if (pn3->pn_type == TOK_STRING) {		pn2->pn_type = TOK_DOT;		pn2->pn_op = JSOP_GETPROP;		pn2->pn_arity = PN_NAME;		pn2->pn_expr = pn;		pn2->pn_atom = pn3->pn_atom;	    } else {		pn2->pn_op = JSOP_GETELEM;		pn2->pn_left = pn;		pn2->pn_right = pn3;	    }	}	pn = pn2;	ts->flags |= TSF_REGEXP;    }    ts->flags &= ~TSF_REGEXP;    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_ReportCompileError(cx, ts, "invalid import expression");    return NULL;}#endif /* JS_HAS_EXPORT_IMPORT */static JSParseNode *Statement(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc){    JSTokenType tt, lastExprType;    JSParseNode *pn, *pn1, *pn2, *pn3, *pn4;    JSStmtInfo stmtInfo, *stmt, *stmt2;    JSAtom *label;    ts->flags |= TSF_REGEXP;    tt = js_GetToken(cx, ts);    ts->flags &= ~TSF_REGEXP;    switch (tt) {#if JS_HAS_EXPORT_IMPORT      case TOK_EXPORT:	pn = NewParseNode(cx, &ts->token, PN_LIST);	if (!pn)	    return NULL;	PN_INIT_LIST(pn);	if (js_MatchToken(cx, ts, TOK_STAR)) {	    pn2 = NewParseNode(cx, &ts->token, PN_NULLARY);	    if (!pn2)	    	return NULL;	    PN_APPEND(pn, pn2);	} else {	    do {		MUST_MATCH_TOKEN(TOK_NAME, "missing name in export statement");		pn2 = NewParseNode(cx, &ts->token, PN_NULLARY);		if (!pn2)		    return NULL;		pn2->pn_op = JSOP_NAME;		pn2->pn_atom = ts->token.t_atom;		pn2->pn_slot = -1;		PN_APPEND(pn, pn2);	    } while (js_MatchToken(cx, ts, TOK_COMMA));	}	pn->pn_pos.end = PN_LAST(pn)->pn_pos.end;	if (pn->pn_pos.end.lineno == ts->lineno &&	    !WellTerminated(cx, ts, TOK_ERROR)) {	    return NULL;	}	break;      case TOK_IMPORT:	pn = NewParseNode(cx, &ts->token, PN_LIST);	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;	if (pn->pn_pos.end.lineno == ts->lineno &&	    !WellTerminated(cx, ts, TOK_ERROR)) {	    return NULL;	}	break;#endif /* JS_HAS_EXPORT_IMPORT */      case TOK_IF:	/* An IF node has three kids: condition, then, and optional else. */	pn = NewParseNode(cx, &ts->token, PN_TERNARY);	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:      {	uintN newlines;	JSParseNode *pn5, *pn6;	pn = NewParseNode(cx, &ts->token, PN_TERNARY);	if (!pn)	    return NULL;	MUST_MATCH_TOKEN(TOK_LP, "missing ( before switch expression");	/* pn1 points to the switch's discriminant. */	pn1 = Expr(cx, ts, tc);	if (!pn1)	    return NULL;	MUST_MATCH_TOKEN(TOK_RP, "missing ) after switch expression");	MUST_MATCH_TOKEN(TOK_LC, "missing { before switch body");	/* balance} */	/* pn2 is a list of case nodes, not including the default case. */	pn2 = NewParseNode(cx, &ts->token, PN_LIST);	if (!pn2)	    return NULL;	PN_INIT_LIST(pn2);	/* If not null, pn3 points to the default case's node. */	pn3 = NULL;	js_PushStatement(tc, &stmtInfo, STMT_SWITCH, -1);	newlines = ts->flags & TSF_NEWLINES;	if (newlines)	    HIDE_NEWLINES(ts);	while ((tt = js_GetToken(cx, ts)) != TOK_RC) {	    switch (tt) {	      case TOK_CASE:		pn4 = NewParseNode(cx, &ts->token, PN_BINARY);		if (!pn4)		    goto bad_switch;		pn4->pn_left = Expr(cx, ts, tc);		if (!pn4->pn_left)		    goto bad_switch;		PN_APPEND(pn2, pn4);		if (pn2->pn_count == PR_BIT(16)) {		    js_ReportCompileError(cx, ts, "too many switch cases");		    goto bad_switch;		}		break;	      case TOK_DEFAULT:		if (pn3) {		    js_ReportCompileError(cx, ts,					  "more than one switch default");		    goto bad_switch;		}		pn4 = NULL;		break;	      case TOK_ERROR:		goto bad_switch;	      default:		js_ReportCompileError(cx, ts, "invalid switch statement");		goto bad_switch;	    }	    MUST_MATCH_TOKEN(TOK_COLON, "missing : after case label");	    pn5 = NewParseNode(cx, &ts->token, PN_LIST);	    if (!pn5)	    	goto bad_switch;	    pn5->pn_type = TOK_LC;	    PN_INIT_LIST(pn5);	    while ((tt = js_PeekToken(cx, ts)) != TOK_RC &&		    tt != TOK_CASE && tt != TOK_DEFAULT) {		if (tt == TOK_ERROR)		    goto bad_switch;		pn6 = Statement(cx, ts, tc);		if (!pn6)		    goto bad_switch;	    	pn5->pn_pos.end = pn6->pn_pos.end;	    	PN_APPEND(pn5, pn6);	    }	    if (pn4) {		pn4->pn_pos.end = pn5->pn_pos.end;		pn4->pn_right = pn5;	    } else {	    	pn3 = pn5;	    }	}	if (newlines)	    SCAN_NEWLINES(ts);	js_PopStatement(tc);	pn->pn_pos.end = pn2->pn_pos.end = ts->token.pos.end;      	pn->pn_kid1 = pn1;      	pn->pn_kid2 = pn2;      	pn->pn_kid3 = pn3;      	return pn;      bad_switch:	if (newlines)	    SCAN_NEWLINES(ts);      	return NULL;      }#endif /* JS_HAS_SWITCH_STATEMENT */      case TOK_WHILE:	pn = NewParseNode(cx, &ts->token, PN_BINARY);	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->token, PN_BINARY);	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, "missing while after do-loop body");	pn2 = Condition(cx, ts, tc);	if (!pn2)	    return NULL;	js_PopStatement(tc);	pn->pn_pos.end = pn2->pn_pos.end;	pn->pn_right = pn2;	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->token, PN_BINARY);	if (!pn)	    return NULL;	js_PushStatement(tc, &stmtInfo, STMT_FOR_LOOP, -1);	MUST_MATCH_TOKEN(TOK_LP, "missing ( after for");	/* balance) */	tt = js_PeekToken(cx, ts);	if (tt == TOK_SEMI) {	    /* 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 if it's a for/in loop, there's still an 'in'         * keyword here, even if Javascript recognizes it as an operator,         * because we've excluded it from parsing by setting the         * TCF_IN_FOR_INIT flag on the JSTreeContext argument.         */	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_type != TOK_NAME &&		pn1->pn_type != TOK_DOT &&		pn1->pn_type != TOK_LB) {		js_ReportCompileError(cx, ts, "invalid for/in left-hand side");		return NULL;	    }	    /* Parse the object expression as the right operand of 'in'. */            pn2 = NewBinary(cx, TOK_IN, JSOP_NOP, pn1, Expr(cx, ts, tc));            if (!pn2)                return NULL;	    pn->pn_left = pn2;	} else {	    /* Parse the loop condition or null into pn2. */	    MUST_MATCH_TOKEN(TOK_SEMI, "missing ; after for-loop initializer");	    if (js_PeekToken(cx, ts) == 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, "missing ; after for-loop condition");	    if (js_PeekToken(cx, ts) == 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->token, PN_TERNARY);	    if (!pn4)		return NULL;	    pn4->pn_type = TOK_RESERVED;	    pn4->pn_kid1 = pn1;	    pn4->pn_kid2 = pn2;	    pn4->pn_kid3 = pn3;	    pn->pn_left = pn4;	}	/* (balance: */	MUST_MATCH_TOKEN(TOK_RP, "missing ) after for-loop control");	/* 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_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->token, PN_TERNARY);	pn->pn_op = JSOP_NOP;	MUST_MATCH_TOKEN(TOK_LC, "missing { after before try block");	/* } balance */	pn->pn_kid1 = Statements(cx, ts, tc);	if (!pn->pn_kid1)	    return NULL;	/* { balance */	MUST_MATCH_TOKEN(TOK_RC, "missing } after try block");	pn->pn_kid2 = NULL;	catchtail = pn;	while(js_PeekToken(cx, ts) == TOK_CATCH) {	    /*	     * legal catch forms are:	     * catch (v)	     * catch (v if <boolean_expression>)	     */	    if (!catchtail->pn_kid1->pn_expr) {		js_ReportCompileError(cx, ts,				      "catch clause after general catch");		return NULL;	    }	    /* catch node */	    pn2 = NewParseNode(cx, &ts->token, PN_TERNARY);	    pn2->pn_op = JSOP_NOP;	    /*	     * We use a PN_NAME for the discriminant (catchguard) node	     * with the actual discriminant code in the initializer spot	     */	    pn3 = NewParseNode(cx, &ts->token, PN_NAME);	    if (!pn2 || !pn3)		return NULL;	    (void)js_GetToken(cx, ts); /* eat `catch' */	    MUST_MATCH_TOKEN(TOK_LP, "missing ( after catch"); /* balance) */	    MUST_MATCH_TOKEN(TOK_NAME, "missing identifier in catch");	    pn3->pn_atom = ts->token.t_atom;	    if (js_PeekToken(cx, ts) == TOK_COLON) {		(void)js_GetToken(cx, ts); /* eat `:' */		pn3->pn_expr = Expr(cx, ts, tc);		if (!pn3->pn_expr)		    return NULL;	    } else {		pn3->pn_expr = NULL;	    }	    pn2->pn_kid1 = pn3;	    /* ( balance: */	    MUST_MATCH_TOKEN(TOK_RP, "missing ) after catch");	    MUST_MATCH_TOKEN(TOK_LC, "missing { before catch block");	    pn2->pn_kid3 = Statements(cx, ts, tc);	    if (!pn2->pn_kid3)		return NULL;	    MUST_MATCH_TOKEN(TOK_RC, "missing } after catch block");	    catchtail = catchtail->pn_kid2 = pn2;	}	catchtail->pn_kid2 = NULL;	if (js_MatchToken(cx, ts, TOK_FINALLY)) {	    MUST_MATCH_TOKEN(TOK_LC, "missing { before finally block");	    pn->pn_kid3 = Statements(cx, ts, tc);	    if (!pn->pn_kid3)		return NULL;	    MUST_MATCH_TOKEN(TOK_RC, "missing } after finally block");	} else {	    pn->pn_kid3 = NULL;	}	if (!pn->pn_kid2 && !pn->pn_kid3) {	    js_ReportCompileError(cx, ts,				  "missing catch or finally after try");	    return NULL;	}	tc->tryCount++;	return pn;      }      case TOK_THROW:	pn = NewParseNode(cx, &ts->token, PN_UNARY);	if (!pn)	    return NULL;	pn2 = Expr(cx, ts, tc);	if (!pn2)	    return NULL;	pn->pn_pos.end = pn2->pn_pos.end;	if (pn->pn_pos.end.lineno == ts->lineno &&	    !WellTerminated(cx, ts, TOK_ERROR)) {            return NULL;	}	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_ReportCompileError(cx, ts, "catch without try");	return NULL;      case TOK_FINALLY:	js_ReportCompileError(cx, ts, "finally without try");	return NULL;#endif /* JS_HAS_EXCEPTIONS */      case TOK_BREAK:	pn = NewParseNode(cx, &ts->token, PN_NULLARY);	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_ReportCompileError(cx, ts, "label not found");		    return NULL;		}		if (stmt->type == STMT_LABEL && stmt->label == label)		    break;	    }	} else {	    for (; ; stmt = stmt->down) {		if (!stmt) {		    js_ReportCompileError(cx, ts, "invalid break");		    return NULL;		}		if (STMT_IS_LOOP(stmt) || stmt->type == STMT_SWITCH)		    break;	    }	}	if (label)	    pn->pn_pos.end = ts->token.pos.end;	break;      case TOK_CONTINUE:	pn = NewParseNode(cx, &ts->token, PN_NULLARY);	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_ReportCompileError(cx, ts, "label not found");		    return NULL;		}		if (stmt->type == STMT_LABEL) {		    if (stmt->label == label) {			if (!stmt2 || !STMT_IS_LOOP(stmt2)) {			    js_ReportCompileError(cx, ts, "invalid continue");			    return NULL;			}			break;		    }		} else {		    stmt2 = stmt;		}	    }	} else {	    for (; ; stmt = stmt->down) {		if (!stmt) {		    js_ReportCompileError(cx, ts, "invalid continue");		    return NULL;		}		if (STMT_IS_LOOP(stmt))		    break;	    }	}	if (label)	    pn->pn_pos.end = ts->token.pos.end;	break;      case TOK_WITH:	pn = NewParseNode(cx, &ts->token, PN_BINARY);	if (!pn)	    return NULL;	MUST_MATCH_TOKEN(TOK_LP, "missing ( before with-statement object");	/* balance) */	pn2 = Expr(cx, ts, tc);	if (!pn2)	    return NULL;	/* (balance: */	MUST_MATCH_TOKEN(TOK_RP, "missing ) after with-statement object");	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;	return pn;      case TOK_VAR:	pn = Variables(cx, ts, tc);	if (!pn)	    return NULL;	if (pn->pn_pos.end.lineno == ts->lineno &&	    !WellTerminated(cx, ts, TOK_ERROR)) {	    return NULL;	}	/* Tell js_EmitTree to generate a final POP. */	pn->pn_op = JSOP_POP;	break;      case TOK_RETURN:	if (!(tc->flags & TCF_IN_FUNCTION)) {	    js_ReportCompileError(cx, ts, "invalid return");	    return NULL;	}	pn = NewParseNode(cx, &ts->token, PN_UNARY);	if (!pn)	    return NULL;	/* This is ugly, but we don't want to require a semicolon. */	ts->flags |= TSF_REGEXP;	tt = js_PeekTokenSameLine(cx, ts);	ts->flags &= ~TSF_REGEXP;	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;	    if (pn2->pn_pos.end.lineno == ts->lineno &&		!WellTerminated(cx, ts, TOK_ERROR)) {		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;	}#ifdef CHECK_RETURN_EXPR	if ((tc->flags & (TCF_RETURN_EXPR | TCF_RETURN_VOID)) ==	    (TCF_RETURN_EXPR | TCF_RETURN_VOID)) {	    js_ReportCompileError(cx, ts, badreturn_str);	    return NULL;	}#endif	break;      case TOK_LC:	js_PushStatement(tc, &stmtInfo, STMT_BLOCK, -1);	pn = Statements(cx, ts, tc);	if (!pn)	    return NULL;	/* {balance: */	MUST_MATCH_TOKEN(TOK_RC, "missing } in compound statement");	js_PopStatement(tc);	return pn;      case TOK_EOL:      case TOK_SEMI:	pn = NewParseNode(cx, &ts->token, PN_UNARY);	if (!pn)	    return NULL;	pn->pn_type = TOK_SEMI;	pn->pn_kid = NULL;	return pn;#if JS_HAS_DEBUGGER_KEYWORD      case TOK_DEBUGGER:        if(!WellTerminated(cx, ts, TOK_ERROR))	    return NULL;	pn = NewParseNode(cx, &ts->token, PN_NULLARY);	if (!pn)	    return NULL;	pn->pn_type = TOK_DEBUGGER;	return pn;#endif /* JS_HAS_DEBUGGER_KEYWORD */      case TOK_ERROR:	return NULL;      default:	lastExprType = ts->token.type;	js_UngetToken(ts);	pn2 = Expr(cx, ts, tc);	if (!pn2)	    return NULL;	tt = ts->pushback.type;	if (tt == TOK_COLON) {	    if (pn2->pn_type != TOK_NAME) {		js_ReportCompileError(cx, ts, "invalid label");		return NULL;	    }	    label = pn2->pn_atom;	    for (stmt = tc->topStmt; stmt; stmt = stmt->down) {		if (stmt->type == STMT_LABEL && stmt->label == label) {		    js_ReportCompileError(cx, ts, "duplicate label");		    return NULL;		}	    }	    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;	}        /* Check explicity against (multi-line) function statement */	if (pn2->pn_pos.end.lineno == ts->lineno &&	    !WellTerminated(cx, ts, lastExprType)) {	    return NULL;	}	pn = NewParseNode(cx, &ts->token, PN_UNARY);	if (!pn)	    return NULL;	pn->pn_type = TOK_SEMI;	pn->pn_pos = pn2->pn_pos;	pn->pn_kid = pn2;	break;    }    (void) js_MatchToken(cx, ts, TOK_SEMI);    return pn;}static JSParseNode *Variables(JSContext *cx, JSTokenStream *ts, JSTreeContext *tc){    JSParseNode *pn, *pn2;    JSObject *obj, *pobj;    JSFunction *fun;    JSClass *clasp;    JSPropertyOp getter, setter;    JSAtom *atom;    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.     */    PR_ASSERT(ts->token.type == TOK_VAR);    pn = NewParseNode(cx, &ts->token, PN_LIST);    if (!pn)	return NULL;    pn->pn_op = JSOP_NOP;    PN_INIT_LIST(pn);    obj = js_FindVariableScope(cx, &fun);    if (!obj)	return NULL;    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;    }    do {	MUST_MATCH_TOKEN(TOK_NAME, "missing variable name");	atom = ts->token.t_atom;	pn2 = NewParseNode(cx, &ts->token, PN_NAME);	if (!pn2)	    return NULL;	pn2->pn_op = JSOP_NAME;	pn2->pn_atom = atom;	pn2->pn_expr = NULL;	pn2->pn_slot = -1;	PN_APPEND(pn, pn2);	if (!OBJ_LOOKUP_PROPERTY(cx, obj, (jsid)atom, &pobj, &prop))	    return NULL;	if (pobj == obj &&	    OBJ_IS_NATIVE(pobj) &&	    (sprop = (JSScopeProperty *)prop) != NULL) {	    if (sprop->getter == js_GetArgument) {		getter = sprop->getter;#ifdef CHECK_ARGUMENT_HIDING		js_ReportCompileError(cx, ts, "variable %s hides argument",				      ATOM_BYTES(atom));		ok = JS_FALSE;#else		ok = JS_TRUE;#endif	    } else {		ok = JS_TRUE;		if (fun) {		    /* Not an argument, must be a redeclared local var. */		    if (clasp == &js_FunctionClass) {			PR_ASSERT(sprop->getter == js_GetLocalVariable);			PR_ASSERT(JSVAL_IS_INT(sprop->id) &&				  JSVAL_TO_INT(sprop->id) < 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.                             */			    PR_ASSERT(JSVAL_IS_INT(sprop->id) &&				      JSVAL_TO_INT(sprop->id) < 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.                             */                            getter = sprop->getter;                            setter = sprop->setter;                        }                    }		} else {		    /* Global var: (re-)set id a la js_DefineProperty. */		    sprop->id = ATOM_KEY(atom);		}		sprop->getter = getter;		sprop->setter = setter;		sprop->attrs |= JSPROP_ENUMERATE | JSPROP_PERMANENT;		sprop->attrs &= ~JSPROP_READONLY;	    }	} else {            /*             * Property not found in current variable scope: we have not             * seen this variable before.             * Define a new variable by adding a property to the current             * scope, or by allocating more slots in the function's frame.             */	    sprop = NULL;	    if (prop) {		OBJ_DROP_PROPERTY(cx, pobj, prop);		prop = NULL;	    }            if (getter == js_GetCallVariable) {                /* Can't increase fun->nvars in an active frame! */	        getter = clasp->getProperty;	        setter = clasp->setProperty;            }	    ok = OBJ_DEFINE_PROPERTY(cx, obj, (jsid)atom, JSVAL_VOID,				     getter, setter,				     JSPROP_ENUMERATE | JSPROP_PERMANENT,				     &prop);	    if (ok && prop) {		pobj = obj;		if (getter == js_GetLocalVariable) {                    /*                     * Allocate more room for variables in the                     * function's frame. We can do this only                     * before the function is called.                     */		    sprop = (JSScopeProperty *)prop;		    sprop->id = INT_TO_JSVAL(fun->nvars++);                }	    }	}	if (js_MatchToken(cx, ts, TOK_ASSIGN)) {	    if (ts->token.t_op != JSOP_NOP) {		js_ReportCompileError(cx, ts,				      "invalid variable initialization");		ok = JS_FALSE;	    } else {		pn2->pn_expr = AssignExpr(cx, ts, tc);		if (pn2->pn_expr)		    pn2->pn_op = JSOP_SETNAME2;		else		    ok = JS_FALSE;	    }	}	if (ok && fun && (clasp == &js_FunctionClass ||                          clasp == &js_CallClass) &&            !InWithStatement(tc))        {            /* Depending on the value of the getter, change the             * opcodes to the forms for arguments and variables.             */	    if (getter == js_GetArgument) {		PR_ASSERT(sprop && JSVAL_IS_INT(sprop->id));		pn2->pn_op = (pn2->pn_op == JSOP_NAME)			     ? JSOP_GETARG			     : JSOP_SETARG;		pn2->pn_slot = JSVAL_TO_INT(sprop->id);	    } else if (getter == js_GetLocalVariable ||                       getter == js_GetCallVariable)            {		PR_ASSERT(sprop && JSVAL_IS_INT(sprop->id));		pn2->pn_op = (pn2->pn_op == JSOP_NAME)			     ? JSOP_GETVAR			     : JSOP_SETVAR;		pn2->pn_slot = JSVAL_TO_INT(sprop->id);            }	}	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->token, PN_LIST);	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;}