tp->t_op = JSOP_OBJECT;
tp->t_op = (cx->fp->flags & (JSFRAME_EVAL | JSFRAME_COMPILE_N_GO)) ? JSOP_OBJECT : JSOP_REGEXP;
js_GetToken(JSContext *cx, JSTokenStream *ts){    JSTokenType tt;    JSToken *tp;    int32 c;    JSAtom *atom;    JSBool hadUnicodeEscape;#define INIT_TOKENBUF(tb)   ((tb)->ptr = (tb)->base)#define FINISH_TOKENBUF(tb) if (!AddToTokenBuf(cx, tb, 0)) RETURN(TOK_ERROR)#define TOKEN_LENGTH(tb)    ((tb)->ptr - (tb)->base - 1)#define RETURN(tt)          { if (tt == TOK_ERROR) ts->flags |= TSF_ERROR;    \                              tp->pos.end.index = ts->linepos +               \                                  (ts->linebuf.ptr - ts->linebuf.base) -      \                                  ts->ungetpos;                               \                              return (tp->type = tt); }    /* If there was a fatal error, keep returning TOK_ERROR. */    if (ts->flags & TSF_ERROR)        return TOK_ERROR;    /* Check for a pushed-back token resulting from mismatching lookahead. */    while (ts->lookahead != 0) {        ts->lookahead--;        ts->cursor = (ts->cursor + 1) & NTOKENS_MASK;        tt = CURRENT_TOKEN(ts).type;        if (tt != TOK_EOL || (ts->flags & TSF_NEWLINES))            return tt;    }retry:    do {        c = GetChar(ts);        if (c == '\n') {            ts->flags &= ~TSF_DIRTYLINE;            if (ts->flags & TSF_NEWLINES)                break;        }    } while (JS_ISSPACE(c));    ts->cursor = (ts->cursor + 1) & NTOKENS_MASK;    tp = &CURRENT_TOKEN(ts);    tp->ptr = ts->linebuf.ptr - 1;    tp->pos.begin.index = ts->linepos + (tp->ptr - ts->linebuf.base);    tp->pos.begin.lineno = tp->pos.end.lineno = (uint16)ts->lineno;    if (c == EOF)        RETURN(TOK_EOF);    if (c != '-' && c != '\n')        ts->flags |= TSF_DIRTYLINE;    hadUnicodeEscape = JS_FALSE;    if (JS_ISIDENT_START(c) ||        (c == '\\' &&         (c = GetUnicodeEscape(ts),          hadUnicodeEscape = JS_ISIDENT_START(c)))) {        INIT_TOKENBUF(&ts->tokenbuf);        for (;;) {            if (!AddToTokenBuf(cx, &ts->tokenbuf, (jschar)c))                RETURN(TOK_ERROR);            c = GetChar(ts);            if (c == '\\') {                c = GetUnicodeEscape(ts);                if (!JS_ISIDENT(c))                    break;                hadUnicodeEscape = JS_TRUE;            } else {                if (!JS_ISIDENT(c))                    break;            }        }        UngetChar(ts, c);        FINISH_TOKENBUF(&ts->tokenbuf);        atom = js_AtomizeChars(cx,                               ts->tokenbuf.base,                               TOKEN_LENGTH(&ts->tokenbuf),                               0);        if (!atom)            RETURN(TOK_ERROR);        if (!hadUnicodeEscape && ATOM_KEYWORD(atom)) {            struct keyword *kw = ATOM_KEYWORD(atom);            if (JSVERSION_IS_ECMA(cx->version) || kw->version <= cx->version) {                tp->t_op = (JSOp) kw->op;                RETURN(kw->tokentype);            }        }        tp->t_op = JSOP_NAME;        tp->t_atom = atom;        RETURN(TOK_NAME);    }    if (JS7_ISDEC(c) || (c == '.' && JS7_ISDEC(PeekChar(ts)))) {        jsint radix;        const jschar *endptr;        jsdouble dval;        radix = 10;        INIT_TOKENBUF(&ts->tokenbuf);        if (c == '0') {            if (!AddToTokenBuf(cx, &ts->tokenbuf, (jschar)c))                RETURN(TOK_ERROR);            c = GetChar(ts);            if (JS_TOLOWER(c) == 'x') {                if (!AddToTokenBuf(cx, &ts->tokenbuf, (jschar)c))                    RETURN(TOK_ERROR);                c = GetChar(ts);                radix = 16;            } else if (JS7_ISDEC(c)) {                radix = 8;            }        }        while (JS7_ISHEX(c)) {            if (radix < 16) {                if (JS7_ISLET(c))                    break;                /*                 * We permit 08 and 09 as decimal numbers, which makes our                 * behaviour a superset of the ECMA numeric grammar.  We might                 * not always be so permissive, so we warn about it.                 */                if (radix == 8 && c >= '8') {                    if (!js_ReportCompileErrorNumber(cx, ts, NULL,                                                     JSREPORT_WARNING,                                                     JSMSG_BAD_OCTAL,                                                     c == '8' ? "08" : "09")) {                        RETURN(TOK_ERROR);                    }                    radix = 10;                }            }            if (!AddToTokenBuf(cx, &ts->tokenbuf, (jschar)c))                RETURN(TOK_ERROR);            c = GetChar(ts);        }        if (radix == 10 && (c == '.' || JS_TOLOWER(c) == 'e')) {            if (c == '.') {                do {                    if (!AddToTokenBuf(cx, &ts->tokenbuf, (jschar)c))                        RETURN(TOK_ERROR);                    c = GetChar(ts);                } while (JS7_ISDEC(c));            }            if (JS_TOLOWER(c) == 'e') {                if (!AddToTokenBuf(cx, &ts->tokenbuf, (jschar)c))                    RETURN(TOK_ERROR);                c = GetChar(ts);                if (c == '+' || c == '-') {                    if (!AddToTokenBuf(cx, &ts->tokenbuf, (jschar)c))                        RETURN(TOK_ERROR);                    c = GetChar(ts);                }                if (!JS7_ISDEC(c)) {                    js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,                                                JSMSG_MISSING_EXPONENT);                    RETURN(TOK_ERROR);                }                do {                    if (!AddToTokenBuf(cx, &ts->tokenbuf, (jschar)c))                        RETURN(TOK_ERROR);                    c = GetChar(ts);                } while (JS7_ISDEC(c));            }        }        UngetChar(ts, c);        FINISH_TOKENBUF(&ts->tokenbuf);        if (radix == 10) {            if (!js_strtod(cx, ts->tokenbuf.base, &endptr, &dval)) {                js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,                                            JSMSG_OUT_OF_MEMORY);                RETURN(TOK_ERROR);            }        } else {            if (!js_strtointeger(cx, ts->tokenbuf.base, &endptr, radix, &dval)) {                js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,                                            JSMSG_OUT_OF_MEMORY);                RETURN(TOK_ERROR);            }        }        tp->t_dval = dval;        RETURN(TOK_NUMBER);    }    if (c == '"' || c == '\'') {        int32 val, qc = c;        INIT_TOKENBUF(&ts->tokenbuf);        while ((c = GetChar(ts)) != qc) {            if (c == '\n' || c == EOF) {                UngetChar(ts, c);                js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,                                            JSMSG_UNTERMINATED_STRING);                RETURN(TOK_ERROR);            }            if (c == '\\') {                switch (c = GetChar(ts)) {                  case 'b': c = '\b'; break;                  case 'f': c = '\f'; break;                  case 'n': c = '\n'; break;                  case 'r': c = '\r'; break;                  case 't': c = '\t'; break;                  case 'v': c = '\v'; break;                  default:                    if ('0' <= c && c < '8') {                        val = JS7_UNDEC(c);                        c = PeekChar(ts);                        if ('0' <= c && c < '8') {                            val = 8 * val + JS7_UNDEC(c);                            GetChar(ts);                            c = PeekChar(ts);                            if ('0' <= c && c < '8') {                                int32 save = val;                                val = 8 * val + JS7_UNDEC(c);                                if (val <= 0377)                                    GetChar(ts);                                else                                    val = save;                            }                        }                        c = (jschar)val;                    } else if (c == 'u') {                        jschar cp[4];                        if (PeekChars(ts, 4, cp) &&                            JS7_ISHEX(cp[0]) && JS7_ISHEX(cp[1]) &&                            JS7_ISHEX(cp[2]) && JS7_ISHEX(cp[3])) {                            c = (((((JS7_UNHEX(cp[0]) << 4)                                    + JS7_UNHEX(cp[1])) << 4)                                  + JS7_UNHEX(cp[2])) << 4)                                + JS7_UNHEX(cp[3]);                            SkipChars(ts, 4);                        }                    } else if (c == 'x') {                        jschar cp[2];                        if (PeekChars(ts, 2, cp) &&                            JS7_ISHEX(cp[0]) && JS7_ISHEX(cp[1])) {                            c = (JS7_UNHEX(cp[0]) << 4) + JS7_UNHEX(cp[1]);                            SkipChars(ts, 2);                        }                    } else if (c == '\n' && JSVERSION_IS_ECMA(cx->version)) {                        /* ECMA follows C by removing escaped newlines. */                        continue;                    }                    break;                }            }            if (!AddToTokenBuf(cx, &ts->tokenbuf, (jschar)c))                RETURN(TOK_ERROR);        }        FINISH_TOKENBUF(&ts->tokenbuf);        atom = js_AtomizeChars(cx,                               ts->tokenbuf.base,                               TOKEN_LENGTH(&ts->tokenbuf),                               0);        if (!atom)            RETURN(TOK_ERROR);        tp->pos.end.lineno = (uint16)ts->lineno;        tp->t_op = JSOP_STRING;        tp->t_atom = atom;        RETURN(TOK_STRING);    }    switch (c) {      case '\n':         c = TOK_EOL;         break;      case ';': c = TOK_SEMI; break;      case '.': c = TOK_DOT; break;      case '[': c = TOK_LB; break;      case ']': c = TOK_RB; break;      case '{': c = TOK_LC; break;      case '}': c = TOK_RC; break;      case '(': c = TOK_LP; break;      case ')': c = TOK_RP; break;      case ',': c = TOK_COMMA; break;      case '?': c = TOK_HOOK; break;      case ':':        /*         * Default so compiler can modify to JSOP_GETTER if 'p getter: v' in an         * object initializer, likewise for setter.         */        tp->t_op = JSOP_NOP;        c = TOK_COLON;        break;      case '|':        if (MatchChar(ts, c)) {            c = TOK_OR;        } else if (MatchChar(ts, '=')) {            tp->t_op = JSOP_BITOR;            c = TOK_ASSIGN;        } else {            c = TOK_BITOR;        }        break;      case '^':        if (MatchChar(ts, '=')) {            tp->t_op = JSOP_BITXOR;            c = TOK_ASSIGN;        } else {            c = TOK_BITXOR;        }        break;      case '&':        if (MatchChar(ts, c)) {            c = TOK_AND;        } else if (MatchChar(ts, '=')) {            tp->t_op = JSOP_BITAND;            c = TOK_ASSIGN;        } else {            c = TOK_BITAND;        }        break;      case '=':        if (MatchChar(ts, c)) {#if JS_HAS_TRIPLE_EQOPS            tp->t_op = MatchChar(ts, c) ? JSOP_NEW_EQ : (JSOp)cx->jsop_eq;#else            tp->t_op = cx->jsop_eq;#endif            c = TOK_EQOP;        } else {            tp->t_op = JSOP_NOP;            c = TOK_ASSIGN;        }        break;      case '!':        if (MatchChar(ts, '=')) {#if JS_HAS_TRIPLE_EQOPS            tp->t_op = MatchChar(ts, '=') ? JSOP_NEW_NE : (JSOp)cx->jsop_ne;#else            tp->t_op = cx->jsop_ne;#endif            c = TOK_EQOP;        } else {            tp->t_op = JSOP_NOT;            c = TOK_UNARYOP;        }        break;      case '<':        /* NB: treat HTML begin-comment as comment-till-end-of-line */        if (MatchChar(ts, '!')) {            if (MatchChar(ts, '-')) {                if (MatchChar(ts, '-'))                    goto skipline;                UngetChar(ts, '-');            }            UngetChar(ts, '!');        }        if (MatchChar(ts, c)) {            tp->t_op = JSOP_LSH;            c = MatchChar(ts, '=') ? TOK_ASSIGN : TOK_SHOP;        } else {            tp->t_op = MatchChar(ts, '=') ? JSOP_LE : JSOP_LT;            c = TOK_RELOP;        }        break;      case '>':        if (MatchChar(ts, c)) {            tp->t_op = MatchChar(ts, c) ? JSOP_URSH : JSOP_RSH;            c = MatchChar(ts, '=') ? TOK_ASSIGN : TOK_SHOP;        } else {            tp->t_op = MatchChar(ts, '=') ? JSOP_GE : JSOP_GT;            c = TOK_RELOP;        }        break;      case '*':        tp->t_op = JSOP_MUL;        c = MatchChar(ts, '=') ? TOK_ASSIGN : TOK_STAR;        break;      case '/':        if (MatchChar(ts, '/')) {skipline:            while ((c = GetChar(ts)) != EOF && c != '\n')                /* skip to end of line */;            UngetChar(ts, c);            goto retry;        }        if (MatchChar(ts, '*')) {            while ((c = GetChar(ts)) != EOF &&                   !(c == '*' && MatchChar(ts, '/'))) {                /* Ignore all characters until comment close. */            }            if (c == EOF) {                js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,                                            JSMSG_UNTERMINATED_COMMENT);                RETURN(TOK_ERROR);            }            goto retry;        }#if JS_HAS_REGEXPS        if (ts->flags & TSF_REGEXP) {            JSObject *obj;            uintN flags;            INIT_TOKENBUF(&ts->tokenbuf);            while ((c = GetChar(ts)) != '/') {                if (c == '\n' || c == EOF) {                    UngetChar(ts, c);                    js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,                                                JSMSG_UNTERMINATED_REGEXP);                    RETURN(TOK_ERROR);                }                if (c == '\\') {                    if (!AddToTokenBuf(cx, &ts->tokenbuf, (jschar)c))                        RETURN(TOK_ERROR);                    c = GetChar(ts);                }                if (!AddToTokenBuf(cx, &ts->tokenbuf, (jschar)c))                    RETURN(TOK_ERROR);            }            FINISH_TOKENBUF(&ts->tokenbuf);            for (flags = 0; ; ) {                if (MatchChar(ts, 'g'))                    flags |= JSREG_GLOB;                else if (MatchChar(ts, 'i'))                    flags |= JSREG_FOLD;                else if (MatchChar(ts, 'm'))                    flags |= JSREG_MULTILINE;                else                    break;            }            c = PeekChar(ts);            if (JS7_ISLET(c)) {                tp->ptr = ts->linebuf.ptr - 1;                js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,                                            JSMSG_BAD_REGEXP_FLAG);                (void) GetChar(ts);                RETURN(TOK_ERROR);            }            obj = js_NewRegExpObject(cx, ts,                                     ts->tokenbuf.base,                                     TOKEN_LENGTH(&ts->tokenbuf),                                     flags);            if (!obj)                RETURN(TOK_ERROR);            atom = js_AtomizeObject(cx, obj, 0);            if (!atom)                RETURN(TOK_ERROR);            tp->t_op = JSOP_OBJECT;            tp->t_atom = atom;            RETURN(TOK_OBJECT);        }#endif /* JS_HAS_REGEXPS */        tp->t_op = JSOP_DIV;        c = MatchChar(ts, '=') ? TOK_ASSIGN : TOK_DIVOP;        break;      case '%':        tp->t_op = JSOP_MOD;        c = MatchChar(ts, '=') ? TOK_ASSIGN : TOK_DIVOP;        break;      case '~':        tp->t_op = JSOP_BITNOT;        c = TOK_UNARYOP;        break;      case '+':        if (MatchChar(ts, '=')) {            tp->t_op = JSOP_ADD;            c = TOK_ASSIGN;        } else if (MatchChar(ts, c)) {            c = TOK_INC;        } else {            tp->t_op = JSOP_POS;            c = TOK_PLUS;        }        break;      case '-':        if (MatchChar(ts, '=')) {            tp->t_op = JSOP_SUB;            c = TOK_ASSIGN;        } else if (MatchChar(ts, c)) {            if (PeekChar(ts) == '>' && !(ts->flags & TSF_DIRTYLINE))                goto skipline;            c = TOK_DEC;        } else {            tp->t_op = JSOP_NEG;            c = TOK_MINUS;        }        ts->flags |= TSF_DIRTYLINE;        break;#if JS_HAS_SHARP_VARS      case '#':      {        uint32 n;        c = GetChar(ts);        if (!JS7_ISDEC(c)) {            UngetChar(ts, c);            goto badchar;        }        n = (uint32)JS7_UNDEC(c);        for (;;) {            c = GetChar(ts);            if (!JS7_ISDEC(c))                break;            n = 10 * n + JS7_UNDEC(c);            if (n >= ATOM_INDEX_LIMIT) {                js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,                                            JSMSG_SHARPVAR_TOO_BIG);                RETURN(TOK_ERROR);            }        }        tp->t_dval = (jsdouble) n;        if (JS_HAS_STRICT_OPTION(cx) &&            (c == '=' || c == '#')) {            char buf[20];            JS_snprintf(buf, sizeof buf, "#%u%c", n, c);            if (!js_ReportCompileErrorNumber(cx, ts, NULL,                                             JSREPORT_WARNING |                                             JSREPORT_STRICT,                                             JSMSG_DEPRECATED_USAGE,                                             buf)) {                RETURN(TOK_ERROR);            }        }        if (c == '=')            RETURN(TOK_DEFSHARP);        if (c == '#')            RETURN(TOK_USESHARP);        goto badchar;      }      badchar:#endif /* JS_HAS_SHARP_VARS */      default:        js_ReportCompileErrorNumber(cx, ts, NULL, JSREPORT_ERROR,                                    JSMSG_ILLEGAL_CHARACTER);        RETURN(TOK_ERROR);    }    JS_ASSERT(c < TOK_LIMIT);    RETURN((JSTokenType)c);#undef INIT_TOKENBUF#undef FINISH_TOKENBUF#undef TOKEN_LENGTH#undef RETURN}