js_DeflateStringToBuffer(buf, TOKENBUF_BASE(), TOKENBUF_LENGTH());
size_t buflen = sizeof(buf) - 1; if (!js_DeflateStringToBuffer(cx, TOKENBUF_BASE(), TOKENBUF_LENGTH(), buf, &buflen)) goto error; buf [buflen] = 0;
js_GetToken(JSContext *cx, JSTokenStream *ts){    JSTokenType tt;    int32 c, qc;    JSToken *tp;    JSAtom *atom;    JSBool hadUnicodeEscape;#define INIT_TOKENBUF()     (ts->tokenbuf.ptr = ts->tokenbuf.base)#define NUL_TERM_TOKENBUF() (*ts->tokenbuf.ptr = 0)#define TRIM_TOKENBUF(i)    (ts->tokenbuf.ptr = ts->tokenbuf.base + i)#define TOKENBUF_LENGTH()   PTRDIFF(ts->tokenbuf.ptr, ts->tokenbuf.base, jschar)#define TOKENBUF_BASE()     (ts->tokenbuf.base)#define TOKENBUF_CHAR(i)    (ts->tokenbuf.base[i])#define TOKENBUF_TO_ATOM()  js_AtomizeChars(cx,                               \                                            TOKENBUF_BASE(),                  \                                            TOKENBUF_LENGTH(),                \                                            0)#define ADD_TO_TOKENBUF(c)  FastAppendChar(&ts->tokenbuf, (jschar) (c))    /* 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) {        JS_ASSERT(!(ts->flags & TSF_XMLTEXTMODE));        ts->lookahead--;        ts->cursor = (ts->cursor + 1) & NTOKENS_MASK;        tt = CURRENT_TOKEN(ts).type;        if (tt != TOK_EOL || (ts->flags & TSF_NEWLINES))            return tt;    }#if JS_HAS_XML_SUPPORT    if (ts->flags & TSF_XMLTEXTMODE) {        tt = TOK_XMLSPACE;      /* veto if non-space, return TOK_XMLTEXT */        tp = NewToken(ts, 0);        INIT_TOKENBUF();        qc = (ts->flags & TSF_XMLONLYMODE) ? '<' : '{';        while ((c = GetChar(ts)) != qc && c != '<' && c != EOF) {            if (c == '&' && qc == '<') {                if (!GetXMLEntity(cx, ts))                    goto error;                tt = TOK_XMLTEXT;                continue;            }            if (!JS_ISXMLSPACE(c))                tt = TOK_XMLTEXT;            ADD_TO_TOKENBUF(c);        }        UngetChar(ts, c);        if (TOKENBUF_LENGTH() == 0) {            atom = NULL;        } else {            atom = TOKENBUF_TO_ATOM();            if (!atom)                goto error;        }        tp->pos.end.lineno = (uint16)ts->lineno;        tp->t_op = JSOP_STRING;        tp->t_atom = atom;        goto out;    }    if (ts->flags & TSF_XMLTAGMODE) {        tp = NewToken(ts, 0);        c = GetChar(ts);        if (JS_ISXMLSPACE(c)) {            do {                c = GetChar(ts);            } while (JS_ISXMLSPACE(c));            UngetChar(ts, c);            tt = TOK_XMLSPACE;            goto out;        }        if (c == EOF) {            tt = TOK_EOF;            goto out;        }        INIT_TOKENBUF();        if (JS_ISXMLNSSTART(c)) {            JSBool sawColon = JS_FALSE;            ADD_TO_TOKENBUF(c);            while ((c = GetChar(ts)) != EOF && JS_ISXMLNAME(c)) {                if (c == ':') {                    if (sawColon || !JS_ISXMLNAME(PeekChar(ts))) {                        js_ReportCompileErrorNumber(cx, ts,                                                    JSREPORT_TS |                                                    JSREPORT_ERROR,                                                    JSMSG_BAD_XML_QNAME);                        goto error;                    }                    sawColon = JS_TRUE;                }                ADD_TO_TOKENBUF(c);            }            UngetChar(ts, c);            atom = TOKENBUF_TO_ATOM();            if (!atom)                goto error;            tp->t_op = JSOP_STRING;            tp->t_atom = atom;            tt = TOK_XMLNAME;            goto out;        }        switch (c) {          case '{':            if (ts->flags & TSF_XMLONLYMODE)                goto bad_xml_char;            tt = TOK_LC;            goto out;          case '=':            tt = TOK_ASSIGN;            goto out;          case '"':          case '\'':            qc = c;            while ((c = GetChar(ts)) != qc) {                if (c == EOF) {                    js_ReportCompileErrorNumber(cx, ts,                                                JSREPORT_TS | JSREPORT_ERROR,                                                JSMSG_UNTERMINATED_STRING);                    goto error;                }                /*                 * XML attribute values are double-quoted when pretty-printed,                 * so escape " if it is expressed directly in a single-quoted                 * attribute value.                 */                if (c == '"') {                    JS_ASSERT(qc == '\'');                    js_AppendCString(&ts->tokenbuf, js_quot_entity_str);                    continue;                }                if (c == '&' && (ts->flags & TSF_XMLONLYMODE)) {                    if (!GetXMLEntity(cx, ts))                        goto error;                    continue;                }                ADD_TO_TOKENBUF(c);            }            atom = TOKENBUF_TO_ATOM();            if (!atom)                goto error;            tp->pos.end.lineno = (uint16)ts->lineno;            tp->t_op = JSOP_STRING;            tp->t_atom = atom;            tt = TOK_XMLATTR;            goto out;          case '>':            tt = TOK_XMLTAGC;            goto out;          case '/':            if (MatchChar(ts, '>')) {                tt = TOK_XMLPTAGC;                goto out;            }            /* FALL THROUGH */          bad_xml_char:          default:            js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR,                                        JSMSG_BAD_XML_CHARACTER);            goto error;        }        /* NOTREACHED */    }#endif /* JS_HAS_XML_SUPPORT */retry:    do {        c = GetChar(ts);        if (c == '\n') {            ts->flags &= ~TSF_DIRTYLINE;            if (ts->flags & TSF_NEWLINES)                break;        }    } while (JS_ISSPACE(c));    tp = NewToken(ts, -1);    if (c == EOF) {        tt = TOK_EOF;        goto out;    }    hadUnicodeEscape = JS_FALSE;    if (JS_ISIDSTART(c) ||        (c == '\\' &&         (c = GetUnicodeEscape(ts),          hadUnicodeEscape = JS_ISIDSTART(c)))) {        INIT_TOKENBUF();        for (;;) {            ADD_TO_TOKENBUF(c);            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);        atom = TOKENBUF_TO_ATOM();        if (!atom)            goto error;        if (!hadUnicodeEscape && ATOM_KEYWORD(atom)) {            struct keyword *kw;                        JS_ASSERT(!(atom->flags & ATOM_HIDDEN));            kw = ATOM_KEYWORD(atom);            if (kw->tokentype == TOK_RESERVED) {                char buf[MAX_KEYWORD_LENGTH + 1];                js_DeflateStringToBuffer(buf, TOKENBUF_BASE(),                                              TOKENBUF_LENGTH());                if (!js_ReportCompileErrorNumber(cx, ts,                                                 JSREPORT_TS |                                                 JSREPORT_WARNING |                                                 JSREPORT_STRICT,                                                 JSMSG_RESERVED_ID, buf)) {                    goto error;                }            } else if (JS_VERSION_IS_ECMA(cx) ||                       kw->version <= (cx->version & JSVERSION_MASK)) {                tt = kw->tokentype;                tp->t_op = (JSOp) kw->op;                goto out;            }        }        tp->t_op = JSOP_NAME;        tp->t_atom = atom;        tt = TOK_NAME;        goto out;    }    if (JS7_ISDEC(c) || (c == '.' && JS7_ISDEC(PeekChar(ts)))) {        jsint radix;        const jschar *endptr;        jsdouble dval;        radix = 10;        INIT_TOKENBUF();        if (c == '0') {            ADD_TO_TOKENBUF(c);            c = GetChar(ts);            if (JS_TOLOWER(c) == 'x') {                ADD_TO_TOKENBUF(c);                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,                                                     JSREPORT_TS |                                                     JSREPORT_WARNING,                                                     JSMSG_BAD_OCTAL,                                                     c == '8' ? "08" : "09")) {                        goto error;                    }                    radix = 10;                }            }            ADD_TO_TOKENBUF(c);            c = GetChar(ts);        }        if (radix == 10 && (c == '.' || JS_TOLOWER(c) == 'e')) {            if (c == '.') {                do {                    ADD_TO_TOKENBUF(c);                    c = GetChar(ts);                } while (JS7_ISDEC(c));            }            if (JS_TOLOWER(c) == 'e') {                ADD_TO_TOKENBUF(c);                c = GetChar(ts);                if (c == '+' || c == '-') {                    ADD_TO_TOKENBUF(c);                    c = GetChar(ts);                }                if (!JS7_ISDEC(c)) {                    js_ReportCompileErrorNumber(cx, ts,                                                JSREPORT_TS | JSREPORT_ERROR,                                                JSMSG_MISSING_EXPONENT);                    goto error;                }                do {                    ADD_TO_TOKENBUF(c);                    c = GetChar(ts);                } while (JS7_ISDEC(c));            }        }        /* Put back the next char and NUL-terminate tokenbuf for js_strto*. */        UngetChar(ts, c);        ADD_TO_TOKENBUF(0);        if (radix == 10) {            if (!js_strtod(cx, TOKENBUF_BASE(), &endptr, &dval)) {                js_ReportCompileErrorNumber(cx, ts,                                            JSREPORT_TS | JSREPORT_ERROR,                                            JSMSG_OUT_OF_MEMORY);                goto error;            }        } else {            if (!js_strtointeger(cx, TOKENBUF_BASE(), &endptr, radix, &dval)) {                js_ReportCompileErrorNumber(cx, ts,                                            JSREPORT_TS | JSREPORT_ERROR,                                            JSMSG_OUT_OF_MEMORY);                goto error;            }        }        tp->t_dval = dval;        tt = TOK_NUMBER;        goto out;    }    if (c == '"' || c == '\'') {        qc = c;        INIT_TOKENBUF();        while ((c = GetChar(ts)) != qc) {            if (c == '\n' || c == EOF) {                UngetChar(ts, c);                js_ReportCompileErrorNumber(cx, ts,                                            JSREPORT_TS | JSREPORT_ERROR,                                            JSMSG_UNTERMINATED_STRING);                goto 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') {                        int32 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' && JS_VERSION_IS_ECMA(cx)) {                        /* ECMA follows C by removing escaped newlines. */                        continue;                    }                    break;                }            }            ADD_TO_TOKENBUF(c);        }        atom = TOKENBUF_TO_ATOM();        if (!atom)            goto error;        tp->pos.end.lineno = (uint16)ts->lineno;        tp->t_op = JSOP_STRING;        tp->t_atom = atom;        tt = TOK_STRING;        goto out;    }    switch (c) {      case '\n': tt = TOK_EOL; goto eol_out;      case ';':  tt = TOK_SEMI; break;      case '[':  tt = TOK_LB; break;      case ']':  tt = TOK_RB; break;      case '{':  tt = TOK_LC; break;      case '}':  tt = TOK_RC; break;      case '(':  tt = TOK_LP; break;      case ')':  tt = TOK_RP; break;      case ',':  tt = TOK_COMMA; break;      case '?':  tt = TOK_HOOK; break;      case '.':#if JS_HAS_XML_SUPPORT        if (MatchChar(ts, c))            tt = TOK_DBLDOT;        else#endif            tt = TOK_DOT;        break;      case ':':#if JS_HAS_XML_SUPPORT        if (MatchChar(ts, c)) {            tt = TOK_DBLCOLON;            break;        }#endif        /*         * Default so compiler can modify to JSOP_GETTER if 'p getter: v' in an         * object initializer, likewise for setter.         */        tp->t_op = JSOP_NOP;        tt = TOK_COLON;        break;      case '|':        if (MatchChar(ts, c)) {            tt = TOK_OR;        } else if (MatchChar(ts, '=')) {            tp->t_op = JSOP_BITOR;            tt = TOK_ASSIGN;        } else {            tt = TOK_BITOR;        }        break;      case '^':        if (MatchChar(ts, '=')) {            tp->t_op = JSOP_BITXOR;            tt = TOK_ASSIGN;        } else {            tt = TOK_BITXOR;        }        break;      case '&':        if (MatchChar(ts, c)) {            tt = TOK_AND;        } else if (MatchChar(ts, '=')) {            tp->t_op = JSOP_BITAND;            tt = TOK_ASSIGN;        } else {            tt = 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            tt = TOK_EQOP;        } else {            tp->t_op = JSOP_NOP;            tt = 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            tt = TOK_EQOP;        } else {            tp->t_op = JSOP_NOT;            tt = TOK_UNARYOP;        }        break;#if JS_HAS_XML_SUPPORT      case '@':        tt = TOK_AT;        break;#endif      case '<':#if JS_HAS_XML_SUPPORT        /*         * After much testing, it's clear that Postel's advice to protocol         * designers ("be liberal in what you accept, and conservative in what         * you send") invites a natural-law repercussion for JS as "protocol":         *         * "If you are liberal in what you accept, others will utterly fail to         *  be conservative in what they send."         *         * Which means you will get <!-- comments to end of line in the middle         * of .js files, and after if conditions whose then statements are on         * the next line, and other wonders.  See at least the following bugs:         * https://bugzilla.mozilla.org/show_bug.cgi?id=309242         * https://bugzilla.mozilla.org/show_bug.cgi?id=309712         * https://bugzilla.mozilla.org/show_bug.cgi?id=310993         *         * So without JSOPTION_XML, we never scan an XML comment or CDATA         * literal.  We always scan <! as the start of an HTML comment hack         * to end of line, used since Netscape 2 to hide script tag content         * from script-unaware browsers.         */        if ((ts->flags & TSF_OPERAND) &&            (JS_HAS_XML_OPTION(cx) || PeekChar(ts) != '!')) {            /* Check for XML comment or CDATA section. */            if (MatchChar(ts, '!')) {                INIT_TOKENBUF();                /* Scan XML comment. */                if (MatchChar(ts, '-')) {                    if (!MatchChar(ts, '-'))                        goto bad_xml_markup;                    while ((c = GetChar(ts)) != '-' || !MatchChar(ts, '-')) {                        if (c == EOF)                            goto bad_xml_markup;                        ADD_TO_TOKENBUF(c);                    }                    tt = TOK_XMLCOMMENT;                    tp->t_op = JSOP_XMLCOMMENT;                    goto finish_xml_markup;                }                /* Scan CDATA section. */                if (MatchChar(ts, '[')) {                    jschar cp[6];                    if (PeekChars(ts, 6, cp) &&                        cp[0] == 'C' &&                        cp[1] == 'D' &&                        cp[2] == 'A' &&                        cp[3] == 'T' &&                        cp[4] == 'A' &&                        cp[5] == '[') {                        SkipChars(ts, 6);                        while ((c = GetChar(ts)) != ']' ||                               !PeekChars(ts, 2, cp) ||                               cp[0] != ']' ||                               cp[1] != '>') {                            if (c == EOF)                                goto bad_xml_markup;                            ADD_TO_TOKENBUF(c);                        }                        GetChar(ts);            /* discard ] but not > */                        tt = TOK_XMLCDATA;                        tp->t_op = JSOP_XMLCDATA;                        goto finish_xml_markup;                    }                    goto bad_xml_markup;                }            }            /* Check for processing instruction. */            if (MatchChar(ts, '?')) {                JSBool inTarget = JS_TRUE;                size_t targetLength = 0;                ptrdiff_t contentIndex = -1;                INIT_TOKENBUF();                while ((c = GetChar(ts)) != '?' || PeekChar(ts) != '>') {                    if (c == EOF)                        goto bad_xml_markup;                    if (inTarget) {                        if (JS_ISXMLSPACE(c)) {                            if (TOKENBUF_LENGTH() == 0)                                goto bad_xml_markup;                            inTarget = JS_FALSE;                        } else {                            if (!((TOKENBUF_LENGTH() == 0)                                  ? JS_ISXMLNSSTART(c)                                  : JS_ISXMLNS(c))) {                                goto bad_xml_markup;                            }                            ++targetLength;                        }                    } else {                        if (contentIndex < 0 && !JS_ISXMLSPACE(c))                            contentIndex = TOKENBUF_LENGTH();                    }                    ADD_TO_TOKENBUF(c);                }                if (contentIndex < 0) {                    atom = cx->runtime->atomState.emptyAtom;                } else {                    atom = js_AtomizeChars(cx,                                           &TOKENBUF_CHAR(contentIndex),                                           TOKENBUF_LENGTH() - contentIndex,                                           0);                    if (!atom)                        goto error;                    TRIM_TOKENBUF(targetLength);                }                tp->t_atom2 = atom;                tt = TOK_XMLPI;        finish_xml_markup:                if (!MatchChar(ts, '>'))                    goto bad_xml_markup;                atom = TOKENBUF_TO_ATOM();                if (!atom)                    goto error;                tp->t_atom = atom;                tp->pos.end.lineno = (uint16)ts->lineno;                goto out;            }            /* An XML start-of-tag character. */            tt = MatchChar(ts, '/') ? TOK_XMLETAGO : TOK_XMLSTAGO;            goto out;        bad_xml_markup:            js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR,                                        JSMSG_BAD_XML_MARKUP);            goto error;        }#endif /* JS_HAS_XML_SUPPORT */        /* NB: treat HTML begin-comment as comment-till-end-of-line */        if (MatchChar(ts, '!')) {            if (MatchChar(ts, '-')) {                if (MatchChar(ts, '-')) {                    ts->flags |= TSF_IN_HTML_COMMENT;                    goto skipline;                }                UngetChar(ts, '-');            }            UngetChar(ts, '!');        }        if (MatchChar(ts, c)) {            tp->t_op = JSOP_LSH;            tt = MatchChar(ts, '=') ? TOK_ASSIGN : TOK_SHOP;        } else {            tp->t_op = MatchChar(ts, '=') ? JSOP_LE : JSOP_LT;            tt = TOK_RELOP;        }        break;      case '>':        if (MatchChar(ts, c)) {            tp->t_op = MatchChar(ts, c) ? JSOP_URSH : JSOP_RSH;            tt = MatchChar(ts, '=') ? TOK_ASSIGN : TOK_SHOP;        } else {            tp->t_op = MatchChar(ts, '=') ? JSOP_GE : JSOP_GT;            tt = TOK_RELOP;        }        break;      case '*':        tp->t_op = JSOP_MUL;        tt = MatchChar(ts, '=') ? TOK_ASSIGN : TOK_STAR;        break;      case '/':        if (MatchChar(ts, '/')) {            /*             * Hack for source filters such as the Mozilla XUL preprocessor:             * "//@line 123\n" sets the number of the *next* line after the             * comment to 123.             */            if (JS_HAS_ATLINE_OPTION(cx)) {                jschar cp[5];                uintN i, line, temp;                char filename[1024];                if (PeekChars(ts, 5, cp) &&                    cp[0] == '@' &&                    cp[1] == 'l' &&                    cp[2] == 'i' &&                    cp[3] == 'n' &&                    cp[4] == 'e') {                    SkipChars(ts, 5);                    while ((c = GetChar(ts)) != '\n' && JS_ISSPACE(c))                        continue;                    if (JS7_ISDEC(c)) {                        line = JS7_UNDEC(c);                        while ((c = GetChar(ts)) != EOF && JS7_ISDEC(c)) {                            temp = 10 * line + JS7_UNDEC(c);                            if (temp < line) {                                /* Ignore overlarge line numbers. */                                goto skipline;                            }                            line = temp;                        }                        while (c != '\n' && JS_ISSPACE(c))                            c = GetChar(ts);                        i = 0;                        if (c == '"') {                            while ((c = GetChar(ts)) != EOF && c != '"') {                                if (c == '\n') {                                    UngetChar(ts, c);                                    goto skipline;                                }                                if ((c >> 8) != 0 || i >= sizeof filename - 1)                                    goto skipline;                                filename[i++] = (char) c;                            }                            if (c == '"') {                                while ((c = GetChar(ts)) != '\n' &&                                       JS_ISSPACE(c)) {                                    continue;                                }                            }                        }                        filename[i] = '\0';                        if (c == '\n') {                            if (i > 0) {                                if (ts->flags & TSF_OWNFILENAME)                                    JS_free(cx, (void *) ts->filename);                                ts->filename = JS_strdup(cx, filename);                                if (!ts->filename)                                    goto error;                                ts->flags |= TSF_OWNFILENAME;                            }                            ts->lineno = line;                        }                    }                    UngetChar(ts, c);                }            }skipline:            /* Optimize line skipping if we are not in an HTML comment. */            if (ts->flags & TSF_IN_HTML_COMMENT) {                while ((c = GetChar(ts)) != EOF && c != '\n') {                    if (c == '-' && MatchChar(ts, '-') && MatchChar(ts, '>'))                        ts->flags &= ~TSF_IN_HTML_COMMENT;                }            } else {                while ((c = GetChar(ts)) != EOF && c != '\n')                    continue;            }            UngetChar(ts, c);            ts->cursor = (ts->cursor - 1) & NTOKENS_MASK;            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,                                            JSREPORT_TS | JSREPORT_ERROR,                                            JSMSG_UNTERMINATED_COMMENT);                goto error;            }            ts->cursor = (ts->cursor - 1) & NTOKENS_MASK;            goto retry;        }#if JS_HAS_REGEXPS        if (ts->flags & TSF_OPERAND) {            JSObject *obj;            uintN flags;            JSBool inCharClass = JS_FALSE;            INIT_TOKENBUF();            for (;;) {                c = GetChar(ts);                if (c == '\n' || c == EOF) {                    UngetChar(ts, c);                    js_ReportCompileErrorNumber(cx, ts,                                                JSREPORT_TS | JSREPORT_ERROR,                                                JSMSG_UNTERMINATED_REGEXP);                    goto error;                }                if (c == '\\') {                    ADD_TO_TOKENBUF(c);                    c = GetChar(ts);                } else if (c == '[') {                    inCharClass = JS_TRUE;                } else if (c == ']') {                    inCharClass = JS_FALSE;                } else if (c == '/' && !inCharClass) {                    /* For compat with IE, allow unescaped / in char classes. */                    break;                }                ADD_TO_TOKENBUF(c);            }            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,                                            JSREPORT_TS | JSREPORT_ERROR,                                            JSMSG_BAD_REGEXP_FLAG);                (void) GetChar(ts);                goto error;            }            /* XXXbe fix jsregexp.c so it doesn't depend on NUL termination */            NUL_TERM_TOKENBUF();            obj = js_NewRegExpObject(cx, ts,                                     TOKENBUF_BASE(),                                     TOKENBUF_LENGTH(),                                     flags);            if (!obj)                goto error;            atom = js_AtomizeObject(cx, obj, 0);            if (!atom)                goto error;            /*             * If the regexp's script is one-shot, we can avoid the extra             * fork-on-exec costs of JSOP_REGEXP by selecting JSOP_OBJECT.             * Otherwise, to avoid incorrect proto, parent, and lastIndex             * sharing among threads and sequentially across re-execution,             * select JSOP_REGEXP.             */            tp->t_op = (cx->fp->flags & (JSFRAME_EVAL | JSFRAME_COMPILE_N_GO))                       ? JSOP_OBJECT                       : JSOP_REGEXP;            tp->t_atom = atom;            tt = TOK_OBJECT;            break;        }#endif /* JS_HAS_REGEXPS */        tp->t_op = JSOP_DIV;        tt = MatchChar(ts, '=') ? TOK_ASSIGN : TOK_DIVOP;        break;      case '%':        tp->t_op = JSOP_MOD;        tt = MatchChar(ts, '=') ? TOK_ASSIGN : TOK_DIVOP;        break;      case '~':        tp->t_op = JSOP_BITNOT;        tt = TOK_UNARYOP;        break;      case '+':        if (MatchChar(ts, '=')) {            tp->t_op = JSOP_ADD;            tt = TOK_ASSIGN;        } else if (MatchChar(ts, c)) {            tt = TOK_INC;        } else {            tp->t_op = JSOP_POS;            tt = TOK_PLUS;        }        break;      case '-':        if (MatchChar(ts, '=')) {            tp->t_op = JSOP_SUB;            tt = TOK_ASSIGN;        } else if (MatchChar(ts, c)) {            if (PeekChar(ts) == '>' && !(ts->flags & TSF_DIRTYLINE)) {                ts->flags &= ~TSF_IN_HTML_COMMENT;                goto skipline;            }            tt = TOK_DEC;        } else {            tp->t_op = JSOP_NEG;            tt = TOK_MINUS;        }        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,                                            JSREPORT_TS | JSREPORT_ERROR,                                            JSMSG_SHARPVAR_TOO_BIG);                goto 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,                                             JSREPORT_TS |                                             JSREPORT_WARNING |                                             JSREPORT_STRICT,                                             JSMSG_DEPRECATED_USAGE,                                             buf)) {                goto error;            }        }        if (c == '=')            tt = TOK_DEFSHARP;        else if (c == '#')            tt = TOK_USESHARP;        else            goto badchar;        break;      }#endif /* JS_HAS_SHARP_VARS */#if JS_HAS_SHARP_VARS || JS_HAS_XML_SUPPORT      badchar:#endif      default:        js_ReportCompileErrorNumber(cx, ts, JSREPORT_TS | JSREPORT_ERROR,                                    JSMSG_ILLEGAL_CHARACTER);        goto error;    }out:    JS_ASSERT(tt != TOK_EOL);    ts->flags |= TSF_DIRTYLINE;eol_out:    if (!STRING_BUFFER_OK(&ts->tokenbuf))        tt = TOK_ERROR;    JS_ASSERT(tt < TOK_LIMIT);    tp->pos.end.index = ts->linepos +                        PTRDIFF(ts->linebuf.ptr, ts->linebuf.base, jschar) -                        ts->ungetpos;    tp->type = tt;    return tt;error:    tt = TOK_ERROR;    ts->flags |= TSF_ERROR;    goto out;#undef INIT_TOKENBUF#undef TRIM_TOKENBUF#undef TOKENBUF_LENGTH#undef TOKENBUF_BASE#undef TOKENBUF_CHAR#undef TOKENBUF_TO_ATOM#undef ADD_TO_TOKENBUF}