1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
2 * vim: set sw=4 ts=8 et tw=78:
4 * ***** BEGIN LICENSE BLOCK *****
5 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
17 * The Original Code is Mozilla Communicator client code, released
20 * The Initial Developer of the Original Code is
21 * Netscape Communications Corporation.
22 * Portions created by the Initial Developer are Copyright (C) 1998
23 * the Initial Developer. All Rights Reserved.
27 * Alternatively, the contents of this file may be used under the terms of
28 * either of the GNU General Public License Version 2 or later (the "GPL"),
29 * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
39 * ***** END LICENSE BLOCK ***** */
44 #include <stdio.h> /* first to avoid trouble on some systems */
56 #include "jsarena.h" /* Added by JSIFY */
58 #include "jsutil.h" /* Added by JSIFY */
64 #include "jsversion.h"
73 #include "jsstaticcheck.h"
75 #if JS_HAS_XML_SUPPORT
79 #define JS_KEYWORD(keyword, type, op, version) \
80 const char js_##keyword##_str[] = #keyword;
81 #include "jskeyword.tbl"
85 const char *chars
; /* C string with keyword text */
86 JSTokenType tokentype
; /* JSTokenType */
88 JSVersion version
; /* JSVersion */
91 static const struct keyword keyword_defs
[] = {
92 #define JS_KEYWORD(keyword, type, op, version) \
93 {js_##keyword##_str, type, op, version},
94 #include "jskeyword.tbl"
98 #define KEYWORD_COUNT JS_ARRAY_LENGTH(keyword_defs)
100 static const struct keyword
*
101 FindKeyword(const jschar
*s
, size_t length
)
104 const struct keyword
*kw
;
107 JS_ASSERT(length
!= 0);
109 #define JSKW_LENGTH() length
110 #define JSKW_AT(column) s[column]
111 #define JSKW_GOT_MATCH(index) i = (index); goto got_match;
112 #define JSKW_TEST_GUESS(index) i = (index); goto test_guess;
113 #define JSKW_NO_MATCH() goto no_match;
114 #include "jsautokw.h"
116 #undef JSKW_TEST_GUESS
117 #undef JSKW_GOT_MATCH
122 return &keyword_defs
[i
];
125 kw
= &keyword_defs
[i
];
128 if (*s
++ != (unsigned char)(*chars
++))
130 } while (--length
!= 0);
138 js_CheckKeyword(const jschar
*str
, size_t length
)
140 const struct keyword
*kw
;
142 JS_ASSERT(length
!= 0);
143 kw
= FindKeyword(str
, length
);
144 return kw
? kw
->tokentype
: TOK_EOF
;
148 js_MapKeywords(void (*mapfun
)(const char *))
152 for (i
= 0; i
!= KEYWORD_COUNT
; ++i
)
153 mapfun(keyword_defs
[i
].chars
);
157 js_IsIdentifier(JSString
*str
)
161 const jschar
*chars
, *end
;
163 str
->getCharsAndLength(chars
, length
);
167 if (!JS_ISIDSTART(c
))
169 end
= chars
+ length
;
170 while (++chars
!= end
) {
181 GrowTokenBuf(JSStringBuffer
*sb
, size_t newlength
)
185 ptrdiff_t offset
, length
;
189 cx
= (JSContext
*) sb
->data
;
191 offset
= sb
->ptr
- base
;
192 pool
= &cx
->tempPool
;
194 tbsize
= TBMIN
* sizeof(jschar
);
196 JS_ARENA_ALLOCATE_CAST(base
, jschar
*, pool
, tbsize
);
198 length
= sb
->limit
- base
;
199 if ((size_t)length
>= ~(size_t)0 / sizeof(jschar
)) {
202 tbsize
= (length
+ 1) * sizeof(jschar
);
203 length
+= length
+ 1;
204 JS_ARENA_GROW_CAST(base
, jschar
*, pool
, tbsize
, tbsize
);
208 js_ReportOutOfScriptQuota(cx
);
209 sb
->base
= STRING_BUFFER_ERROR_BASE
;
213 sb
->limit
= base
+ length
;
214 sb
->ptr
= base
+ offset
;
219 js_InitTokenStream(JSContext
*cx
, JSTokenStream
*ts
,
220 const jschar
*base
, size_t length
,
221 FILE *fp
, const char *filename
, uintN lineno
)
226 JS_ASSERT_IF(fp
, !base
);
227 JS_ASSERT_IF(!base
, length
== 0);
229 ? 2 * JS_LINE_LIMIT
* sizeof(jschar
)
230 : JS_LINE_LIMIT
* sizeof(jschar
);
231 JS_ARENA_ALLOCATE_CAST(buf
, jschar
*, &cx
->tempPool
, nb
);
233 js_ReportOutOfScriptQuota(cx
);
237 memset(ts
, 0, sizeof(*ts
));
238 ts
->filename
= filename
;
240 ts
->linebuf
.base
= ts
->linebuf
.limit
= ts
->linebuf
.ptr
= buf
;
243 ts
->userbuf
.base
= buf
+ JS_LINE_LIMIT
;
244 ts
->userbuf
.ptr
= ts
->userbuf
.limit
= ts
->userbuf
.base
+ JS_LINE_LIMIT
;
246 ts
->userbuf
.base
= (jschar
*)base
;
247 ts
->userbuf
.limit
= (jschar
*)base
+ length
;
248 ts
->userbuf
.ptr
= (jschar
*)base
;
250 ts
->tokenbuf
.grow
= GrowTokenBuf
;
251 ts
->tokenbuf
.data
= cx
;
252 ts
->listener
= cx
->debugHooks
->sourceHandler
;
253 ts
->listenerData
= cx
->debugHooks
->sourceHandlerData
;
258 js_CloseTokenStream(JSContext
*cx
, JSTokenStream
*ts
)
260 if (ts
->flags
& TSF_OWNFILENAME
)
261 cx
->free((void *) ts
->filename
);
265 js_fgets(char *buf
, int size
, FILE *file
)
275 for (i
= 0; i
< n
&& (c
= getc(file
)) != EOF
; i
++) {
277 if (c
== '\n') { /* any \n ends a line */
278 i
++; /* keep the \n; we know there is room for \0 */
281 if (crflag
) { /* \r not followed by \n ends line at the \r */
283 break; /* and overwrite c in buf with \0 */
285 crflag
= (c
== '\r');
293 GetChar(JSTokenStream
*ts
)
296 ptrdiff_t i
, j
, len
, olen
;
298 char cbuf
[JS_LINE_LIMIT
];
301 if (ts
->ungetpos
!= 0) {
302 c
= ts
->ungetbuf
[--ts
->ungetpos
];
304 if (ts
->linebuf
.ptr
== ts
->linebuf
.limit
) {
305 len
= ts
->userbuf
.limit
- ts
->userbuf
.ptr
;
308 ts
->flags
|= TSF_EOF
;
312 /* Fill ts->userbuf so that \r and \r\n convert to \n. */
313 crflag
= (ts
->flags
& TSF_CRFLAG
) != 0;
314 len
= js_fgets(cbuf
, JS_LINE_LIMIT
- crflag
, ts
->file
);
316 ts
->flags
|= TSF_EOF
;
320 ubuf
= ts
->userbuf
.base
;
323 ts
->flags
&= ~TSF_CRFLAG
;
324 if (cbuf
[0] != '\n') {
330 for (j
= 0; i
< len
; i
++, j
++)
331 ubuf
[i
] = (jschar
) (unsigned char) cbuf
[j
];
332 ts
->userbuf
.limit
= ubuf
+ len
;
333 ts
->userbuf
.ptr
= ubuf
;
336 ts
->listener(ts
->filename
, ts
->lineno
, ts
->userbuf
.ptr
, len
,
337 &ts
->listenerTSData
, ts
->listenerData
);
343 * Any one of \n, \r, or \r\n ends a line (the longest
344 * match wins). Also allow the Unicode line and paragraph
347 for (nl
= ts
->userbuf
.ptr
; nl
< ts
->userbuf
.limit
; nl
++) {
349 * Try to prevent value-testing on most characters by
350 * filtering out characters that aren't 000x or 202x.
352 if ((*nl
& 0xDFD0) == 0) {
356 if (nl
+ 1 < ts
->userbuf
.limit
&& nl
[1] == '\n')
360 if (*nl
== LINE_SEPARATOR
|| *nl
== PARA_SEPARATOR
)
367 * If there was a line terminator, copy thru it into linebuf.
368 * Else copy JS_LINE_LIMIT-1 bytes into linebuf.
370 if (nl
< ts
->userbuf
.limit
)
371 len
= (nl
- ts
->userbuf
.ptr
) + 1;
372 if (len
>= JS_LINE_LIMIT
) {
373 len
= JS_LINE_LIMIT
- 1;
378 js_strncpy(ts
->linebuf
.base
, ts
->userbuf
.ptr
, len
);
379 ts
->userbuf
.ptr
+= len
;
383 * Make sure linebuf contains \n for EOL (don't do this in
384 * userbuf because the user's string might be readonly).
386 if (nl
< ts
->userbuf
.limit
) {
388 if (ts
->linebuf
.base
[len
-1] == '\r') {
390 * Does the line segment end in \r? We must check
391 * for a \n at the front of the next segment before
392 * storing a \n into linebuf. This case matters
393 * only when we're reading from a file.
395 if (nl
+ 1 == ts
->userbuf
.limit
&& ts
->file
) {
397 ts
->flags
|= TSF_CRFLAG
; /* clear NLFLAG? */
400 * This can happen when a segment ends in
401 * \r\r. Start over. ptr == limit in this
402 * case, so we'll fall into buffer-filling
408 ts
->linebuf
.base
[len
-1] = '\n';
411 } else if (*nl
== '\n') {
412 if (nl
> ts
->userbuf
.base
&&
414 ts
->linebuf
.base
[len
-2] == '\r') {
416 JS_ASSERT(ts
->linebuf
.base
[len
] == '\n');
417 ts
->linebuf
.base
[len
-1] = '\n';
419 } else if (*nl
== LINE_SEPARATOR
|| *nl
== PARA_SEPARATOR
) {
420 ts
->linebuf
.base
[len
-1] = '\n';
424 /* Reset linebuf based on adjusted segment length. */
425 ts
->linebuf
.limit
= ts
->linebuf
.base
+ len
;
426 ts
->linebuf
.ptr
= ts
->linebuf
.base
;
428 /* Update position of linebuf within physical userbuf line. */
429 if (!(ts
->flags
& TSF_NLFLAG
))
430 ts
->linepos
+= ts
->linelen
;
433 if (ts
->linebuf
.limit
[-1] == '\n')
434 ts
->flags
|= TSF_NLFLAG
;
436 ts
->flags
&= ~TSF_NLFLAG
;
438 /* Update linelen from original segment length. */
441 c
= *ts
->linebuf
.ptr
++;
449 UngetChar(JSTokenStream
*ts
, int32 c
)
453 JS_ASSERT(ts
->ungetpos
< JS_ARRAY_LENGTH(ts
->ungetbuf
));
456 ts
->ungetbuf
[ts
->ungetpos
++] = (jschar
)c
;
460 PeekChar(JSTokenStream
*ts
)
470 * Peek n chars ahead into ts. Return true if n chars were read, false if
471 * there weren't enough characters in the input stream. This function cannot
472 * be used to peek into or past a newline.
475 PeekChars(JSTokenStream
*ts
, intN n
, jschar
*cp
)
480 for (i
= 0; i
< n
; i
++) {
490 for (j
= i
- 1; j
>= 0; j
--)
491 UngetChar(ts
, cp
[j
]);
496 SkipChars(JSTokenStream
*ts
, intN n
)
503 MatchChar(JSTokenStream
*ts
, int32 expect
)
515 js_ReportCompileErrorNumber(JSContext
*cx
, JSTokenStream
*ts
, JSParseNode
*pn
,
516 uintN flags
, uintN errorNumber
, ...)
518 JSErrorReport report
;
527 JSErrorReporter onError
;
529 JS_ASSERT(ts
->linebuf
.limit
< ts
->linebuf
.base
+ JS_LINE_LIMIT
);
531 if ((flags
& JSREPORT_STRICT
) && !JS_HAS_STRICT_OPTION(cx
))
534 memset(&report
, 0, sizeof report
);
535 report
.flags
= flags
;
536 report
.errorNumber
= errorNumber
;
541 MUST_FLOW_THROUGH("out");
542 va_start(ap
, errorNumber
);
543 ok
= js_ExpandErrorArguments(cx
, js_GetErrorMessage
, NULL
,
544 errorNumber
, &message
, &report
, &warning
,
545 !(flags
& JSREPORT_UC
), ap
);
552 report
.filename
= ts
->filename
;
555 report
.lineno
= pn
->pn_pos
.begin
.lineno
;
556 if (report
.lineno
!= ts
->lineno
)
560 /* Point to the current token, not the next one to get. */
561 tp
= &ts
->tokens
[ts
->cursor
].pos
;
563 report
.lineno
= ts
->lineno
;
564 linelength
= ts
->linebuf
.limit
- ts
->linebuf
.base
;
565 linechars
= (jschar
*)cx
->malloc((linelength
+ 1) * sizeof(jschar
));
570 memcpy(linechars
, ts
->linebuf
.base
, linelength
* sizeof(jschar
));
571 linechars
[linelength
] = 0;
572 linebytes
= js_DeflateString(cx
, linechars
, linelength
);
577 report
.linebuf
= linebytes
;
580 * FIXME: What should instead happen here is that we should
581 * find error-tokens in userbuf, if !ts->file. That will
582 * allow us to deliver a more helpful error message, which
583 * includes all or part of the bad string or bad token. The
584 * code here yields something that looks truncated.
585 * See https://bugzilla.mozilla.org/show_bug.cgi?id=352970
588 if (tp
->begin
.lineno
== tp
->end
.lineno
) {
589 if (tp
->begin
.index
< ts
->linepos
)
592 index
= tp
->begin
.index
- ts
->linepos
;
595 report
.tokenptr
= report
.linebuf
+ index
;
596 report
.uclinebuf
= linechars
;
597 report
.uctokenptr
= report
.uclinebuf
+ index
;
600 * If there's a runtime exception type associated with this error
601 * number, set that as the pending exception. For errors occuring at
602 * compile time, this is very likely to be a JSEXN_SYNTAXERR.
604 * If an exception is thrown but not caught, the JSREPORT_EXCEPTION
605 * flag will be set in report.flags. Proper behavior for an error
606 * reporter is to ignore a report with this flag for all but top-level
607 * compilation errors. The exception will remain pending, and so long
608 * as the non-top-level "load", "eval", or "compile" native function
609 * returns false, the top-level reporter will eventually receive the
610 * uncaught exception report.
612 * XXX it'd probably be best if there was only one call to this
613 * function, but there seem to be two error reporter call points.
616 onError
= cx
->errorReporter
;
619 * Try to raise an exception only if there isn't one already set --
620 * otherwise the exception will describe the last compile-time error,
621 * which is likely spurious.
623 if (!(ts
->flags
& TSF_ERROR
)) {
624 if (js_ErrorToException(cx
, message
, &report
))
629 * Suppress any compile-time errors that don't occur at the top level.
630 * This may still fail, as interplevel may be zero in contexts where we
631 * don't really want to call the error reporter, as when js is called
632 * by other code which could catch the error.
634 if (cx
->interpLevel
!= 0 && !JSREPORT_IS_WARNING(flags
))
638 JSDebugErrorHook hook
= cx
->debugHooks
->debugErrorHook
;
641 * If debugErrorHook is present then we give it a chance to veto
642 * sending the error on to the regular error reporter.
644 if (hook
&& !hook(cx
, message
, &report
,
645 cx
->debugHooks
->debugErrorHookData
)) {
650 (*onError
)(cx
, message
, &report
);
659 if (report
.ucmessage
)
660 cx
->free((void *)report
.ucmessage
);
662 if (report
.messageArgs
) {
663 if (!(flags
& JSREPORT_UC
)) {
665 while (report
.messageArgs
[i
])
666 cx
->free((void *)report
.messageArgs
[i
++]);
668 cx
->free((void *)report
.messageArgs
);
671 if (!JSREPORT_IS_WARNING(flags
)) {
672 /* Set the error flag to suppress spurious reports. */
673 ts
->flags
|= TSF_ERROR
;
680 GrowStringBuffer(JSStringBuffer
*sb
, size_t amount
)
682 ptrdiff_t offset
= sb
->ptr
- sb
->base
;
683 JS_ASSERT(offset
>= 0);
686 * This addition needs an overflow check, but we can defer bounding against
687 * ~size_t(0) / sizeof(jschar) till later to consolidate that test.
689 size_t newlength
= offset
+ amount
+ 1;
690 if (size_t(offset
) < newlength
) {
691 /* Grow by powers of two until 16MB, then grow by that chunk size. */
692 const size_t CHUNK_SIZE_MASK
= JS_BITMASK(24);
694 if (newlength
<= CHUNK_SIZE_MASK
)
695 newlength
= JS_BIT(JS_CeilingLog2(newlength
));
696 else if (newlength
& CHUNK_SIZE_MASK
)
697 newlength
= (newlength
| CHUNK_SIZE_MASK
) + 1;
699 /* Now do the full overflow check. */
700 if (size_t(offset
) < newlength
&& newlength
< ~size_t(0) / sizeof(jschar
)) {
701 jschar
*bp
= (jschar
*) js_realloc(sb
->base
, newlength
* sizeof(jschar
));
704 sb
->ptr
= bp
+ offset
;
705 sb
->limit
= bp
+ newlength
- 1;
711 /* Either newlength overflow or realloc failure: poison the well. */
713 sb
->base
= STRING_BUFFER_ERROR_BASE
;
718 FreeStringBuffer(JSStringBuffer
*sb
)
720 JS_ASSERT(STRING_BUFFER_OK(sb
));
726 js_InitStringBuffer(JSStringBuffer
*sb
)
728 sb
->base
= sb
->limit
= sb
->ptr
= NULL
;
730 sb
->grow
= GrowStringBuffer
;
731 sb
->free
= FreeStringBuffer
;
735 js_FinishStringBuffer(JSStringBuffer
*sb
)
741 js_AppendChar(JSStringBuffer
*sb
, jschar c
)
745 if (!STRING_BUFFER_OK(sb
))
747 if (!ENSURE_STRING_BUFFER(sb
, 1))
756 js_AppendUCString(JSStringBuffer
*sb
, const jschar
*buf
, uintN len
)
760 if (!STRING_BUFFER_OK(sb
))
762 if (len
== 0 || !ENSURE_STRING_BUFFER(sb
, len
))
765 js_strncpy(bp
, buf
, len
);
771 #if JS_HAS_XML_SUPPORT
774 js_RepeatChar(JSStringBuffer
*sb
, jschar c
, uintN count
)
778 if (!STRING_BUFFER_OK(sb
) || count
== 0)
780 if (!ENSURE_STRING_BUFFER(sb
, count
))
782 for (bp
= sb
->ptr
; count
; --count
)
789 js_AppendCString(JSStringBuffer
*sb
, const char *asciiz
)
794 if (!STRING_BUFFER_OK(sb
) || *asciiz
== '\0')
796 length
= strlen(asciiz
);
797 if (!ENSURE_STRING_BUFFER(sb
, length
))
799 for (bp
= sb
->ptr
; length
; --length
)
800 *bp
++ = (jschar
) *asciiz
++;
806 js_AppendJSString(JSStringBuffer
*sb
, JSString
*str
)
808 js_AppendUCString(sb
, str
->chars(), str
->length());
812 GetXMLEntity(JSContext
*cx
, JSTokenStream
*ts
)
814 ptrdiff_t offset
, length
, i
;
821 /* Put the entity, including the '&' already scanned, in ts->tokenbuf. */
822 offset
= ts
->tokenbuf
.ptr
- ts
->tokenbuf
.base
;
823 js_FastAppendChar(&ts
->tokenbuf
, '&');
824 if (!STRING_BUFFER_OK(&ts
->tokenbuf
))
826 while ((c
= GetChar(ts
)) != ';') {
827 if (c
== EOF
|| c
== '\n') {
828 js_ReportCompileErrorNumber(cx
, ts
, NULL
, JSREPORT_ERROR
,
829 JSMSG_END_OF_XML_ENTITY
);
832 js_FastAppendChar(&ts
->tokenbuf
, (jschar
) c
);
833 if (!STRING_BUFFER_OK(&ts
->tokenbuf
))
837 /* Let length be the number of jschars after the '&', including the ';'. */
838 length
= (ts
->tokenbuf
.ptr
- ts
->tokenbuf
.base
) - offset
;
839 bp
= ts
->tokenbuf
.base
+ offset
;
842 if (length
> 2 && bp
[1] == '#') {
843 /* Match a well-formed XML Character Reference. */
845 if (length
> 3 && JS_TOLOWER(bp
[i
]) == 'x') {
846 if (length
> 9) /* at most 6 hex digits allowed */
848 while (++i
< length
) {
850 if (!JS7_ISHEX(digit
))
852 c
= (c
<< 4) + JS7_UNHEX(digit
);
857 if (!JS7_ISDEC(digit
))
859 c
= (c
* 10) + JS7_UNDEC(digit
);
865 if (0x10000 <= c
&& c
<= 0x10FFFF) {
866 /* Form a surrogate pair (c, d) -- c is the high surrogate. */
867 d
= 0xDC00 + (c
& 0x3FF);
868 c
= 0xD7C0 + (c
>> 10);
871 /* Enforce the http://www.w3.org/TR/REC-xml/#wf-Legalchar WFC. */
872 if (c
!= 0x9 && c
!= 0xA && c
!= 0xD &&
873 !(0x20 <= c
&& c
<= 0xD7FF) &&
874 !(0xE000 <= c
&& c
<= 0xFFFD)) {
879 /* Try to match one of the five XML 1.0 predefined entities. */
885 else if (bp
[1] == 'g')
890 if (bp
[1] == 'a' && bp
[2] == 'm' && bp
[3] == 'p')
895 if (bp
[1] == 'a' && bp
[2] == 'p' && bp
[4] == 's')
897 else if (bp
[1] == 'q' && bp
[2] == 'u' && bp
[4] == 't')
903 msg
= JSMSG_UNKNOWN_XML_ENTITY
;
908 /* If we matched, retract ts->tokenbuf and store the entity's value. */
913 ts
->tokenbuf
.ptr
= bp
;
917 msg
= JSMSG_BAD_XML_NCR
;
919 /* No match: throw a TypeError per ECMA-357 10.3.2.1 step 8(a). */
920 JS_ASSERT(STRING_BUFFER_OK(&ts
->tokenbuf
));
921 JS_ASSERT((ts
->tokenbuf
.ptr
- bp
) >= 1);
922 bytes
= js_DeflateString(cx
, bp
+ 1,
923 (ts
->tokenbuf
.ptr
- bp
) - 1);
925 js_ReportCompileErrorNumber(cx
, ts
, NULL
, JSREPORT_ERROR
,
932 #endif /* JS_HAS_XML_SUPPORT */
935 js_PeekToken(JSContext
*cx
, JSTokenStream
*ts
)
939 if (ts
->lookahead
!= 0) {
940 tt
= ts
->tokens
[(ts
->cursor
+ ts
->lookahead
) & NTOKENS_MASK
].type
;
942 tt
= js_GetToken(cx
, ts
);
949 js_PeekTokenSameLine(JSContext
*cx
, JSTokenStream
*ts
)
953 if (!ON_CURRENT_LINE(ts
, CURRENT_TOKEN(ts
).pos
))
955 ts
->flags
|= TSF_NEWLINES
;
956 tt
= js_PeekToken(cx
, ts
);
957 ts
->flags
&= ~TSF_NEWLINES
;
962 * We have encountered a '\': check for a Unicode escape sequence after it,
963 * returning the character code value if we found a Unicode escape sequence.
964 * Otherwise, non-destructively return the original '\'.
967 GetUnicodeEscape(JSTokenStream
*ts
)
972 if (PeekChars(ts
, 5, cp
) && cp
[0] == 'u' &&
973 JS7_ISHEX(cp
[1]) && JS7_ISHEX(cp
[2]) &&
974 JS7_ISHEX(cp
[3]) && JS7_ISHEX(cp
[4]))
976 c
= (((((JS7_UNHEX(cp
[1]) << 4)
977 + JS7_UNHEX(cp
[2])) << 4)
978 + JS7_UNHEX(cp
[3])) << 4)
987 NewToken(JSTokenStream
*ts
, ptrdiff_t adjust
)
991 ts
->cursor
= (ts
->cursor
+ 1) & NTOKENS_MASK
;
992 tp
= &CURRENT_TOKEN(ts
);
993 tp
->ptr
= ts
->linebuf
.ptr
+ adjust
;
994 tp
->pos
.begin
.index
= ts
->linepos
+
995 (tp
->ptr
- ts
->linebuf
.base
) -
997 tp
->pos
.begin
.lineno
= tp
->pos
.end
.lineno
= (uint16
)ts
->lineno
;
1001 static JS_ALWAYS_INLINE JSBool
1002 ScanAsSpace(jschar c
)
1004 /* Treat little- and big-endian BOMs as whitespace for compatibility. */
1005 if (JS_ISSPACE(c
) || c
== 0xfffe || c
== 0xfeff)
1011 js_GetToken(JSContext
*cx
, JSTokenStream
*ts
)
1017 JSBool hadUnicodeEscape
;
1018 const struct keyword
*kw
;
1019 #if JS_HAS_XML_SUPPORT
1021 size_t targetLength
;
1022 ptrdiff_t contentIndex
;
1025 #define INIT_TOKENBUF() (ts->tokenbuf.ptr = ts->tokenbuf.base)
1026 #define TOKENBUF_LENGTH() (ts->tokenbuf.ptr - ts->tokenbuf.base)
1027 #define TOKENBUF_OK() STRING_BUFFER_OK(&ts->tokenbuf)
1028 #define TOKENBUF_TO_ATOM() (TOKENBUF_OK() \
1029 ? js_AtomizeChars(cx, \
1031 TOKENBUF_LENGTH(), \
1034 #define ADD_TO_TOKENBUF(c) JS_BEGIN_MACRO \
1035 js_FastAppendChar(&ts->tokenbuf, jschar(c)); \
1036 if (!TOKENBUF_OK()) \
1040 /* The following 4 macros should only be used when TOKENBUF_OK() is true. */
1041 #define TOKENBUF_BASE() (ts->tokenbuf.base)
1042 #define TOKENBUF_END() (ts->tokenbuf.ptr)
1043 #define TOKENBUF_CHAR(i) (ts->tokenbuf.base[i])
1044 #define TRIM_TOKENBUF(i) (ts->tokenbuf.ptr = ts->tokenbuf.base + i)
1045 #define NUL_TERM_TOKENBUF() (*ts->tokenbuf.ptr = 0)
1047 /* Check for a pushed-back token resulting from mismatching lookahead. */
1048 while (ts
->lookahead
!= 0) {
1049 JS_ASSERT(!(ts
->flags
& TSF_XMLTEXTMODE
));
1051 ts
->cursor
= (ts
->cursor
+ 1) & NTOKENS_MASK
;
1052 tt
= CURRENT_TOKEN(ts
).type
;
1053 if (tt
!= TOK_EOL
|| (ts
->flags
& TSF_NEWLINES
))
1057 /* If there was a fatal error, keep returning TOK_ERROR. */
1058 if (ts
->flags
& TSF_ERROR
)
1061 #if JS_HAS_XML_SUPPORT
1062 if (ts
->flags
& TSF_XMLTEXTMODE
) {
1063 tt
= TOK_XMLSPACE
; /* veto if non-space, return TOK_XMLTEXT */
1064 tp
= NewToken(ts
, 0);
1066 qc
= (ts
->flags
& TSF_XMLONLYMODE
) ? '<' : '{';
1068 while ((c
= GetChar(ts
)) != qc
&& c
!= '<' && c
!= EOF
) {
1069 if (c
== '&' && qc
== '<') {
1070 if (!GetXMLEntity(cx
, ts
))
1076 if (!JS_ISXMLSPACE(c
))
1082 if (TOKENBUF_LENGTH() == 0) {
1085 atom
= TOKENBUF_TO_ATOM();
1089 tp
->pos
.end
.lineno
= (uint16
)ts
->lineno
;
1090 tp
->t_op
= JSOP_STRING
;
1095 if (ts
->flags
& TSF_XMLTAGMODE
) {
1096 tp
= NewToken(ts
, 0);
1098 if (JS_ISXMLSPACE(c
)) {
1101 } while (JS_ISXMLSPACE(c
));
1113 if (JS_ISXMLNSSTART(c
)) {
1114 JSBool sawColon
= JS_FALSE
;
1117 while ((c
= GetChar(ts
)) != EOF
&& JS_ISXMLNAME(c
)) {
1122 (nextc
= PeekChar(ts
),
1123 ((ts
->flags
& TSF_XMLONLYMODE
) || nextc
!= '{') &&
1124 !JS_ISXMLNAME(nextc
))) {
1125 js_ReportCompileErrorNumber(cx
, ts
, NULL
,
1127 JSMSG_BAD_XML_QNAME
);
1137 atom
= TOKENBUF_TO_ATOM();
1140 tp
->t_op
= JSOP_STRING
;
1148 if (ts
->flags
& TSF_XMLONLYMODE
)
1160 while ((c
= GetChar(ts
)) != qc
) {
1162 js_ReportCompileErrorNumber(cx
, ts
, NULL
, JSREPORT_ERROR
,
1163 JSMSG_UNTERMINATED_STRING
);
1168 * XML attribute values are double-quoted when pretty-printed,
1169 * so escape " if it is expressed directly in a single-quoted
1172 if (c
== '"' && !(ts
->flags
& TSF_XMLONLYMODE
)) {
1173 JS_ASSERT(qc
== '\'');
1174 js_AppendCString(&ts
->tokenbuf
, js_quot_entity_str
);
1178 if (c
== '&' && (ts
->flags
& TSF_XMLONLYMODE
)) {
1179 if (!GetXMLEntity(cx
, ts
))
1186 atom
= TOKENBUF_TO_ATOM();
1189 tp
->pos
.end
.lineno
= (uint16
)ts
->lineno
;
1190 tp
->t_op
= JSOP_STRING
;
1200 if (MatchChar(ts
, '>')) {
1208 js_ReportCompileErrorNumber(cx
, ts
, NULL
, JSREPORT_ERROR
,
1209 JSMSG_BAD_XML_CHARACTER
);
1214 #endif /* JS_HAS_XML_SUPPORT */
1220 ts
->flags
&= ~TSF_DIRTYLINE
;
1221 if (ts
->flags
& TSF_NEWLINES
)
1224 } while (ScanAsSpace((jschar
)c
));
1226 tp
= NewToken(ts
, -1);
1232 hadUnicodeEscape
= JS_FALSE
;
1233 if (JS_ISIDSTART(c
) ||
1235 (qc
= GetUnicodeEscape(ts
),
1236 hadUnicodeEscape
= JS_ISIDSTART(qc
)))) {
1237 if (hadUnicodeEscape
)
1244 qc
= GetUnicodeEscape(ts
);
1245 if (!JS_ISIDENT(qc
))
1248 hadUnicodeEscape
= JS_TRUE
;
1257 * Check for keywords unless we saw Unicode escape or parser asks
1258 * to ignore keywords.
1260 if (!hadUnicodeEscape
&&
1261 !(ts
->flags
& TSF_KEYWORD_IS_NAME
) &&
1263 (kw
= FindKeyword(TOKENBUF_BASE(), TOKENBUF_LENGTH()))) {
1264 if (kw
->tokentype
== TOK_RESERVED
) {
1265 if (!js_ReportCompileErrorNumber(cx
, ts
, NULL
,
1272 } else if (kw
->version
<= JSVERSION_NUMBER(cx
)) {
1274 tp
->t_op
= (JSOp
) kw
->op
;
1279 atom
= TOKENBUF_TO_ATOM();
1282 tp
->t_op
= JSOP_NAME
;
1288 if (JS7_ISDEC(c
) || (c
== '.' && JS7_ISDEC(PeekChar(ts
)))) {
1290 const jschar
*endptr
;
1299 if (JS_TOLOWER(c
) == 'x') {
1303 } else if (JS7_ISDEC(c
)) {
1308 while (JS7_ISHEX(c
)) {
1314 * We permit 08 and 09 as decimal numbers, which makes our
1315 * behaviour a superset of the ECMA numeric grammar. We might
1316 * not always be so permissive, so we warn about it.
1318 if (radix
== 8 && c
>= '8') {
1319 if (!js_ReportCompileErrorNumber(cx
, ts
, NULL
,
1322 c
== '8' ? "08" : "09")) {
1332 if (radix
== 10 && (c
== '.' || JS_TOLOWER(c
) == 'e')) {
1337 } while (JS7_ISDEC(c
));
1339 if (JS_TOLOWER(c
) == 'e') {
1342 if (c
== '+' || c
== '-') {
1346 if (!JS7_ISDEC(c
)) {
1347 js_ReportCompileErrorNumber(cx
, ts
, NULL
, JSREPORT_ERROR
,
1348 JSMSG_MISSING_EXPONENT
);
1354 } while (JS7_ISDEC(c
));
1358 /* Put back the next char and NUL-terminate tokenbuf for js_strto*. */
1365 if (!js_strtod(cx
, TOKENBUF_BASE(), TOKENBUF_END(),
1367 js_ReportCompileErrorNumber(cx
, ts
, NULL
, JSREPORT_ERROR
,
1368 JSMSG_OUT_OF_MEMORY
);
1372 if (!js_strtointeger(cx
, TOKENBUF_BASE(), TOKENBUF_END(),
1373 &endptr
, radix
, &dval
)) {
1374 js_ReportCompileErrorNumber(cx
, ts
, NULL
, JSREPORT_ERROR
,
1375 JSMSG_OUT_OF_MEMORY
);
1384 if (c
== '"' || c
== '\'') {
1387 while ((c
= GetChar(ts
)) != qc
) {
1388 if (c
== '\n' || c
== EOF
) {
1390 js_ReportCompileErrorNumber(cx
, ts
, NULL
, JSREPORT_ERROR
,
1391 JSMSG_UNTERMINATED_STRING
);
1395 switch (c
= GetChar(ts
)) {
1396 case 'b': c
= '\b'; break;
1397 case 'f': c
= '\f'; break;
1398 case 'n': c
= '\n'; break;
1399 case 'r': c
= '\r'; break;
1400 case 't': c
= '\t'; break;
1401 case 'v': c
= '\v'; break;
1404 if ('0' <= c
&& c
< '8') {
1405 int32 val
= JS7_UNDEC(c
);
1408 if ('0' <= c
&& c
< '8') {
1409 val
= 8 * val
+ JS7_UNDEC(c
);
1412 if ('0' <= c
&& c
< '8') {
1414 val
= 8 * val
+ JS7_UNDEC(c
);
1423 } else if (c
== 'u') {
1425 if (PeekChars(ts
, 4, cp
) &&
1426 JS7_ISHEX(cp
[0]) && JS7_ISHEX(cp
[1]) &&
1427 JS7_ISHEX(cp
[2]) && JS7_ISHEX(cp
[3])) {
1428 c
= (((((JS7_UNHEX(cp
[0]) << 4)
1429 + JS7_UNHEX(cp
[1])) << 4)
1430 + JS7_UNHEX(cp
[2])) << 4)
1434 } else if (c
== 'x') {
1436 if (PeekChars(ts
, 2, cp
) &&
1437 JS7_ISHEX(cp
[0]) && JS7_ISHEX(cp
[1])) {
1438 c
= (JS7_UNHEX(cp
[0]) << 4) + JS7_UNHEX(cp
[1]);
1441 } else if (c
== '\n') {
1442 /* ECMA follows C by removing escaped newlines. */
1450 atom
= TOKENBUF_TO_ATOM();
1453 tp
->pos
.end
.lineno
= (uint16
)ts
->lineno
;
1454 tp
->t_op
= JSOP_STRING
;
1461 case '\n': tt
= TOK_EOL
; goto eol_out
;
1462 case ';': tt
= TOK_SEMI
; break;
1463 case '[': tt
= TOK_LB
; break;
1464 case ']': tt
= TOK_RB
; break;
1465 case '{': tt
= TOK_LC
; break;
1466 case '}': tt
= TOK_RC
; break;
1467 case '(': tt
= TOK_LP
; break;
1468 case ')': tt
= TOK_RP
; break;
1469 case ',': tt
= TOK_COMMA
; break;
1470 case '?': tt
= TOK_HOOK
; break;
1473 #if JS_HAS_XML_SUPPORT
1474 if (MatchChar(ts
, c
))
1482 #if JS_HAS_XML_SUPPORT
1483 if (MatchChar(ts
, c
)) {
1489 * Default so compiler can modify to JSOP_GETTER if 'p getter: v' in an
1490 * object initializer, likewise for setter.
1492 tp
->t_op
= JSOP_NOP
;
1497 if (MatchChar(ts
, c
)) {
1499 } else if (MatchChar(ts
, '=')) {
1500 tp
->t_op
= JSOP_BITOR
;
1508 if (MatchChar(ts
, '=')) {
1509 tp
->t_op
= JSOP_BITXOR
;
1517 if (MatchChar(ts
, c
)) {
1519 } else if (MatchChar(ts
, '=')) {
1520 tp
->t_op
= JSOP_BITAND
;
1528 if (MatchChar(ts
, c
)) {
1529 tp
->t_op
= MatchChar(ts
, c
) ? JSOP_STRICTEQ
: JSOP_EQ
;
1532 tp
->t_op
= JSOP_NOP
;
1538 if (MatchChar(ts
, '=')) {
1539 tp
->t_op
= MatchChar(ts
, '=') ? JSOP_STRICTNE
: JSOP_NE
;
1542 tp
->t_op
= JSOP_NOT
;
1547 #if JS_HAS_XML_SUPPORT
1554 #if JS_HAS_XML_SUPPORT
1556 * After much testing, it's clear that Postel's advice to protocol
1557 * designers ("be liberal in what you accept, and conservative in what
1558 * you send") invites a natural-law repercussion for JS as "protocol":
1560 * "If you are liberal in what you accept, others will utterly fail to
1561 * be conservative in what they send."
1563 * Which means you will get <!-- comments to end of line in the middle
1564 * of .js files, and after if conditions whose then statements are on
1565 * the next line, and other wonders. See at least the following bugs:
1566 * https://bugzilla.mozilla.org/show_bug.cgi?id=309242
1567 * https://bugzilla.mozilla.org/show_bug.cgi?id=309712
1568 * https://bugzilla.mozilla.org/show_bug.cgi?id=310993
1570 * So without JSOPTION_XML, we changed around Firefox 1.5 never to scan
1571 * an XML comment or CDATA literal. Instead, we always scan <! as the
1572 * start of an HTML comment hack to end of line, used since Netscape 2
1573 * to hide script tag content from script-unaware browsers.
1575 * But this still leaves XML resources with certain internal structure
1576 * vulnerable to being loaded as script cross-origin, and some internal
1577 * data stolen, so for Firefox 3.5 and beyond, we reject programs whose
1578 * source consists only of XML literals. See:
1580 * https://bugzilla.mozilla.org/show_bug.cgi?id=336551
1582 * The check for this is in jsparse.cpp, JSCompiler::compileScript.
1584 if ((ts
->flags
& TSF_OPERAND
) &&
1585 (JS_HAS_XML_OPTION(cx
) || PeekChar(ts
) != '!')) {
1586 /* Check for XML comment or CDATA section. */
1587 if (MatchChar(ts
, '!')) {
1590 /* Scan XML comment. */
1591 if (MatchChar(ts
, '-')) {
1592 if (!MatchChar(ts
, '-'))
1593 goto bad_xml_markup
;
1594 while ((c
= GetChar(ts
)) != '-' || !MatchChar(ts
, '-')) {
1596 goto bad_xml_markup
;
1599 tt
= TOK_XMLCOMMENT
;
1600 tp
->t_op
= JSOP_XMLCOMMENT
;
1601 goto finish_xml_markup
;
1604 /* Scan CDATA section. */
1605 if (MatchChar(ts
, '[')) {
1607 if (PeekChars(ts
, 6, cp
) &&
1615 while ((c
= GetChar(ts
)) != ']' ||
1616 !PeekChars(ts
, 2, cp
) ||
1620 goto bad_xml_markup
;
1623 GetChar(ts
); /* discard ] but not > */
1625 tp
->t_op
= JSOP_XMLCDATA
;
1626 goto finish_xml_markup
;
1628 goto bad_xml_markup
;
1632 /* Check for processing instruction. */
1633 if (MatchChar(ts
, '?')) {
1639 while ((c
= GetChar(ts
)) != '?' || PeekChar(ts
) != '>') {
1641 goto bad_xml_markup
;
1643 if (JS_ISXMLSPACE(c
)) {
1644 if (TOKENBUF_LENGTH() == 0)
1645 goto bad_xml_markup
;
1646 inTarget
= JS_FALSE
;
1648 if (!((TOKENBUF_LENGTH() == 0)
1649 ? JS_ISXMLNSSTART(c
)
1651 goto bad_xml_markup
;
1656 if (contentIndex
< 0 && !JS_ISXMLSPACE(c
))
1657 contentIndex
= TOKENBUF_LENGTH();
1661 if (targetLength
== 0)
1662 goto bad_xml_markup
;
1665 if (contentIndex
< 0) {
1666 atom
= cx
->runtime
->atomState
.emptyAtom
;
1668 atom
= js_AtomizeChars(cx
,
1669 &TOKENBUF_CHAR(contentIndex
),
1670 TOKENBUF_LENGTH() - contentIndex
,
1675 TRIM_TOKENBUF(targetLength
);
1680 if (!MatchChar(ts
, '>'))
1681 goto bad_xml_markup
;
1682 atom
= TOKENBUF_TO_ATOM();
1686 tp
->pos
.end
.lineno
= (uint16
)ts
->lineno
;
1690 /* An XML start-of-tag character. */
1691 tt
= MatchChar(ts
, '/') ? TOK_XMLETAGO
: TOK_XMLSTAGO
;
1695 js_ReportCompileErrorNumber(cx
, ts
, NULL
, JSREPORT_ERROR
,
1696 JSMSG_BAD_XML_MARKUP
);
1699 #endif /* JS_HAS_XML_SUPPORT */
1701 /* NB: treat HTML begin-comment as comment-till-end-of-line */
1702 if (MatchChar(ts
, '!')) {
1703 if (MatchChar(ts
, '-')) {
1704 if (MatchChar(ts
, '-')) {
1705 ts
->flags
|= TSF_IN_HTML_COMMENT
;
1712 if (MatchChar(ts
, c
)) {
1713 tp
->t_op
= JSOP_LSH
;
1714 tt
= MatchChar(ts
, '=') ? TOK_ASSIGN
: TOK_SHOP
;
1716 tp
->t_op
= MatchChar(ts
, '=') ? JSOP_LE
: JSOP_LT
;
1722 if (MatchChar(ts
, c
)) {
1723 tp
->t_op
= MatchChar(ts
, c
) ? JSOP_URSH
: JSOP_RSH
;
1724 tt
= MatchChar(ts
, '=') ? TOK_ASSIGN
: TOK_SHOP
;
1726 tp
->t_op
= MatchChar(ts
, '=') ? JSOP_GE
: JSOP_GT
;
1732 tp
->t_op
= JSOP_MUL
;
1733 tt
= MatchChar(ts
, '=') ? TOK_ASSIGN
: TOK_STAR
;
1737 if (MatchChar(ts
, '/')) {
1739 * Hack for source filters such as the Mozilla XUL preprocessor:
1740 * "//@line 123\n" sets the number of the *next* line after the
1743 if (JS_HAS_ATLINE_OPTION(cx
)) {
1745 uintN i
, line
, temp
;
1746 char filename
[1024];
1748 if (PeekChars(ts
, 5, cp
) &&
1755 while ((c
= GetChar(ts
)) != '\n' && ScanAsSpace((jschar
)c
))
1758 line
= JS7_UNDEC(c
);
1759 while ((c
= GetChar(ts
)) != EOF
&& JS7_ISDEC(c
)) {
1760 temp
= 10 * line
+ JS7_UNDEC(c
);
1762 /* Ignore overlarge line numbers. */
1767 while (c
!= '\n' && ScanAsSpace((jschar
)c
))
1771 while ((c
= GetChar(ts
)) != EOF
&& c
!= '"') {
1776 if ((c
>> 8) != 0 || i
>= sizeof filename
- 1)
1778 filename
[i
++] = (char) c
;
1781 while ((c
= GetChar(ts
)) != '\n' &&
1782 ScanAsSpace((jschar
)c
)) {
1790 if (ts
->flags
& TSF_OWNFILENAME
)
1791 cx
->free((void *) ts
->filename
);
1792 ts
->filename
= JS_strdup(cx
, filename
);
1795 ts
->flags
|= TSF_OWNFILENAME
;
1805 /* Optimize line skipping if we are not in an HTML comment. */
1806 if (ts
->flags
& TSF_IN_HTML_COMMENT
) {
1807 while ((c
= GetChar(ts
)) != EOF
&& c
!= '\n') {
1808 if (c
== '-' && MatchChar(ts
, '-') && MatchChar(ts
, '>'))
1809 ts
->flags
&= ~TSF_IN_HTML_COMMENT
;
1812 while ((c
= GetChar(ts
)) != EOF
&& c
!= '\n')
1816 ts
->cursor
= (ts
->cursor
- 1) & NTOKENS_MASK
;
1820 if (MatchChar(ts
, '*')) {
1821 uintN lineno
= ts
->lineno
;
1822 while ((c
= GetChar(ts
)) != EOF
&&
1823 !(c
== '*' && MatchChar(ts
, '/'))) {
1824 /* Ignore all characters until comment close. */
1827 js_ReportCompileErrorNumber(cx
, ts
, NULL
, JSREPORT_ERROR
,
1828 JSMSG_UNTERMINATED_COMMENT
);
1831 if ((ts
->flags
& TSF_NEWLINES
) && lineno
!= ts
->lineno
) {
1832 ts
->flags
&= ~TSF_DIRTYLINE
;
1836 ts
->cursor
= (ts
->cursor
- 1) & NTOKENS_MASK
;
1840 if (ts
->flags
& TSF_OPERAND
) {
1841 uintN flags
, length
;
1842 JSBool inCharClass
= JS_FALSE
;
1847 if (c
== '\n' || c
== EOF
) {
1849 js_ReportCompileErrorNumber(cx
, ts
, NULL
, JSREPORT_ERROR
,
1850 JSMSG_UNTERMINATED_REGEXP
);
1856 } else if (c
== '[') {
1857 inCharClass
= JS_TRUE
;
1858 } else if (c
== ']') {
1859 inCharClass
= JS_FALSE
;
1860 } else if (c
== '/' && !inCharClass
) {
1861 /* For compat with IE, allow unescaped / in char classes. */
1866 for (flags
= 0, length
= TOKENBUF_LENGTH() + 1; ; length
++) {
1868 if (c
== 'g' && !(flags
& JSREG_GLOB
))
1869 flags
|= JSREG_GLOB
;
1870 else if (c
== 'i' && !(flags
& JSREG_FOLD
))
1871 flags
|= JSREG_FOLD
;
1872 else if (c
== 'm' && !(flags
& JSREG_MULTILINE
))
1873 flags
|= JSREG_MULTILINE
;
1874 else if (c
== 'y' && !(flags
& JSREG_STICKY
))
1875 flags
|= JSREG_STICKY
;
1882 char buf
[2] = { '\0' };
1883 tp
->pos
.begin
.index
+= length
+ 1;
1885 js_ReportCompileErrorNumber(cx
, ts
, NULL
, JSREPORT_ERROR
,
1886 JSMSG_BAD_REGEXP_FLAG
, buf
);
1890 /* XXXbe fix jsregexp.c so it doesn't depend on NUL termination */
1893 NUL_TERM_TOKENBUF();
1894 tp
->t_reflags
= flags
;
1899 tp
->t_op
= JSOP_DIV
;
1900 tt
= MatchChar(ts
, '=') ? TOK_ASSIGN
: TOK_DIVOP
;
1904 tp
->t_op
= JSOP_MOD
;
1905 tt
= MatchChar(ts
, '=') ? TOK_ASSIGN
: TOK_DIVOP
;
1909 tp
->t_op
= JSOP_BITNOT
;
1914 if (MatchChar(ts
, '=')) {
1915 tp
->t_op
= JSOP_ADD
;
1917 } else if (MatchChar(ts
, c
)) {
1920 tp
->t_op
= JSOP_POS
;
1926 if (MatchChar(ts
, '=')) {
1927 tp
->t_op
= JSOP_SUB
;
1929 } else if (MatchChar(ts
, c
)) {
1930 if (PeekChar(ts
) == '>' && !(ts
->flags
& TSF_DIRTYLINE
)) {
1931 ts
->flags
&= ~TSF_IN_HTML_COMMENT
;
1936 tp
->t_op
= JSOP_NEG
;
1941 #if JS_HAS_SHARP_VARS
1947 if (!JS7_ISDEC(c
)) {
1951 n
= (uint32
)JS7_UNDEC(c
);
1956 n
= 10 * n
+ JS7_UNDEC(c
);
1957 if (n
>= UINT16_LIMIT
) {
1958 js_ReportCompileErrorNumber(cx
, ts
, NULL
, JSREPORT_ERROR
,
1959 JSMSG_SHARPVAR_TOO_BIG
);
1963 tp
->t_dval
= (jsdouble
) n
;
1964 if (JS_HAS_STRICT_OPTION(cx
) &&
1965 (c
== '=' || c
== '#')) {
1967 JS_snprintf(buf
, sizeof buf
, "#%u%c", n
, c
);
1968 if (!js_ReportCompileErrorNumber(cx
, ts
, NULL
,
1971 JSMSG_DEPRECATED_USAGE
,
1984 #endif /* JS_HAS_SHARP_VARS */
1986 #if JS_HAS_SHARP_VARS || JS_HAS_XML_SUPPORT
1991 js_ReportCompileErrorNumber(cx
, ts
, NULL
, JSREPORT_ERROR
,
1992 JSMSG_ILLEGAL_CHARACTER
);
1997 JS_ASSERT(tt
!= TOK_EOL
);
1998 ts
->flags
|= TSF_DIRTYLINE
;
2001 if (!STRING_BUFFER_OK(&ts
->tokenbuf
))
2003 JS_ASSERT(tt
< TOK_LIMIT
);
2004 tp
->pos
.end
.index
= ts
->linepos
+
2005 (ts
->linebuf
.ptr
- ts
->linebuf
.base
) -
2012 ts
->flags
|= TSF_ERROR
;
2015 #undef INIT_TOKENBUF
2016 #undef TOKENBUF_LENGTH
2018 #undef TOKENBUF_TO_ATOM
2019 #undef ADD_TO_TOKENBUF
2020 #undef TOKENBUF_BASE
2021 #undef TOKENBUF_CHAR
2022 #undef TRIM_TOKENBUF
2023 #undef NUL_TERM_TOKENBUF
2027 js_UngetToken(JSTokenStream
*ts
)
2029 JS_ASSERT(ts
->lookahead
< NTOKENS_MASK
);
2031 ts
->cursor
= (ts
->cursor
- 1) & NTOKENS_MASK
;
2035 js_MatchToken(JSContext
*cx
, JSTokenStream
*ts
, JSTokenType tt
)
2037 if (js_GetToken(cx
, ts
) == tt
)