25b5fc365ac453631c4d4473f0741afaab7c2f5c
[org.ibex.core.git] / src / org / mozilla / javascript / TokenStream.java
1 /* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-\r
2  *\r
3  * The contents of this file are subject to the Netscape Public\r
4  * License Version 1.1 (the "License"); you may not use this file\r
5  * except in compliance with the License. You may obtain a copy of\r
6  * the License at http://www.mozilla.org/NPL/\r
7  *\r
8  * Software distributed under the License is distributed on an "AS\r
9  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express oqr\r
10  * implied. See the License for the specific language governing\r
11  * rights and limitations under the License.\r
12  *\r
13  * The Original Code is Rhino code, released\r
14  * May 6, 1999.\r
15  *\r
16  * The Initial Developer of the Original Code is Netscape\r
17  * Communications Corporation.  Portions created by Netscape are\r
18  * Copyright (C) 1997-1999 Netscape Communications Corporation. All\r
19  * Rights Reserved.\r
20  *\r
21  * Contributor(s): \r
22  * Roger Lawrence\r
23  * Mike McCabe\r
24  *\r
25  * Alternatively, the contents of this file may be used under the\r
26  * terms of the GNU Public License (the "GPL"), in which case the\r
27  * provisions of the GPL are applicable instead of those above.\r
28  * If you wish to allow use of your version of this file only\r
29  * under the terms of the GPL and not to allow others to use your\r
30  * version of this file under the NPL, indicate your decision by\r
31  * deleting the provisions above and replace them with the notice\r
32  * and other provisions required by the GPL.  If you do not delete\r
33  * the provisions above, a recipient may use your version of this\r
34  * file under either the NPL or the GPL.\r
35  */\r
36 \r
37 package org.mozilla.javascript;\r
38 \r
39 import java.io.*;\r
40 \r
41 /**\r
42  * This class implements the JavaScript scanner.\r
43  *\r
44  * It is based on the C source files jsscan.c and jsscan.h\r
45  * in the jsref package.\r
46  *\r
47  * @see org.mozilla.javascript.Parser\r
48  *\r
49  * @author Mike McCabe\r
50  * @author Brendan Eich\r
51  */\r
52 \r
53 public class TokenStream {\r
54     /*\r
55      * JSTokenStream flags, mirroring those in jsscan.h.  These are used\r
56      * by the parser to change/check the state of the scanner.\r
57      */\r
58 \r
59     public final static int\r
60         TSF_NEWLINES    = 0x0001,  // tokenize newlines\r
61         TSF_FUNCTION    = 0x0002,  // scanning inside function body\r
62         TSF_RETURN_EXPR = 0x0004,  // function has 'return expr;'\r
63         TSF_RETURN_VOID = 0x0008,  // function has 'return;'\r
64         TSF_REGEXP      = 0x0010;  // looking for a regular expression\r
65 \r
66     /*\r
67      * For chars - because we need something out-of-range\r
68      * to check.  (And checking EOF by exception is annoying.)\r
69      * Note distinction from EOF token type!\r
70      */\r
71     private final static int\r
72         EOF_CHAR = -1;\r
73 \r
74     /**\r
75      * Token types.  These values correspond to JSTokenType values in\r
76      * jsscan.c.\r
77      */\r
78 \r
79     public final static int\r
80     // start enum\r
81         ERROR       = -1, // well-known as the only code < EOF\r
82         EOF         = 0,  // end of file token - (not EOF_CHAR)\r
83         EOL         = 1,  // end of line\r
84         // Beginning here are interpreter bytecodes. Their values\r
85         // must not exceed 127.\r
86         POPV        = 2,\r
87         ENTERWITH   = 3,\r
88         LEAVEWITH   = 4,\r
89         RETURN      = 5,\r
90         GOTO        = 6,\r
91         IFEQ        = 7,\r
92         IFNE        = 8,\r
93         DUP         = 9,\r
94         SETNAME     = 10,\r
95         BITOR       = 11,\r
96         BITXOR      = 12,\r
97         BITAND      = 13,\r
98         EQ          = 14,\r
99         NE          = 15,\r
100         LT          = 16,\r
101         LE          = 17,\r
102         GT          = 18,\r
103         GE          = 19,\r
104         LSH         = 20,\r
105         RSH         = 21,\r
106         URSH        = 22,\r
107         ADD         = 23,\r
108         SUB         = 24,\r
109         MUL         = 25,\r
110         DIV         = 26,\r
111         MOD         = 27,\r
112         BITNOT      = 28,\r
113         NEG         = 29,\r
114         NEW         = 30,\r
115         DELPROP     = 31,\r
116         TYPEOF      = 32,\r
117         NAMEINC     = 33,\r
118         PROPINC     = 34,\r
119         ELEMINC     = 35,\r
120         NAMEDEC     = 36,\r
121         PROPDEC     = 37,\r
122         ELEMDEC     = 38,\r
123         GETPROP     = 39,\r
124         SETPROP     = 40,\r
125         GETELEM     = 41,\r
126         SETELEM     = 42,\r
127         CALL        = 43,\r
128         NAME        = 44,\r
129         NUMBER      = 45,\r
130         STRING      = 46,\r
131         ZERO        = 47,\r
132         ONE         = 48,\r
133         NULL        = 49,\r
134         THIS        = 50,\r
135         FALSE       = 51,\r
136         TRUE        = 52,\r
137         SHEQ        = 53,   // shallow equality (===)\r
138         SHNE        = 54,   // shallow inequality (!==)\r
139         CLOSURE     = 55,\r
140         OBJECT      = 56,\r
141         POP         = 57,\r
142         POS         = 58,\r
143         VARINC      = 59,\r
144         VARDEC      = 60,\r
145         BINDNAME    = 61,\r
146         THROW       = 62,\r
147         IN          = 63,\r
148         INSTANCEOF  = 64,\r
149         GOSUB       = 65,\r
150         RETSUB      = 66,\r
151         CALLSPECIAL = 67,\r
152         GETTHIS     = 68,\r
153         NEWTEMP     = 69,\r
154         USETEMP     = 70,\r
155         GETBASE     = 71,\r
156         GETVAR      = 72,\r
157         SETVAR      = 73,\r
158         UNDEFINED   = 74,\r
159         TRY         = 75,\r
160         ENDTRY      = 76,\r
161         NEWSCOPE    = 77,\r
162         TYPEOFNAME  = 78,\r
163         ENUMINIT    = 79,\r
164         ENUMNEXT    = 80,\r
165         GETPROTO    = 81,\r
166         GETPARENT   = 82,\r
167         SETPROTO    = 83,\r
168         SETPARENT   = 84,\r
169         SCOPE       = 85,\r
170         GETSCOPEPARENT = 86,\r
171         THISFN      = 87,\r
172         JTHROW      = 88,\r
173         // End of interpreter bytecodes\r
174         SEMI        = 89,  // semicolon\r
175         LB          = 90,  // left and right brackets\r
176         RB          = 91,\r
177         LC          = 92,  // left and right curlies (braces)\r
178         RC          = 93,\r
179         LP          = 94,  // left and right parentheses\r
180         RP          = 95,\r
181         COMMA       = 96,  // comma operator\r
182         ASSIGN      = 97, // assignment ops (= += -= etc.)\r
183         HOOK        = 98, // conditional (?:)\r
184         COLON       = 99,\r
185         OR          = 100, // logical or (||)\r
186         AND         = 101, // logical and (&&)\r
187         EQOP        = 102, // equality ops (== !=)\r
188         RELOP       = 103, // relational ops (< <= > >=)\r
189         SHOP        = 104, // shift ops (<< >> >>>)\r
190         UNARYOP     = 105, // unary prefix operator\r
191         INC         = 106, // increment/decrement (++ --)\r
192         DEC         = 107,\r
193         DOT         = 108, // member operator (.)\r
194         PRIMARY     = 109, // true, false, null, this\r
195         FUNCTION    = 110, // function keyword\r
196         EXPORT      = 111, // export keyword\r
197         IMPORT      = 112, // import keyword\r
198         IF          = 113, // if keyword\r
199         ELSE        = 114, // else keyword\r
200         SWITCH      = 115, // switch keyword\r
201         CASE        = 116, // case keyword\r
202         DEFAULT     = 117, // default keyword\r
203         WHILE       = 118, // while keyword\r
204         DO          = 119, // do keyword\r
205         FOR         = 120, // for keyword\r
206         BREAK       = 121, // break keyword\r
207         CONTINUE    = 122, // continue keyword\r
208         VAR         = 123, // var keyword\r
209         WITH        = 124, // with keyword\r
210         CATCH       = 125, // catch keyword\r
211         FINALLY     = 126, // finally keyword\r
212         RESERVED    = 127, // reserved keywords\r
213 \r
214         /** Added by Mike - these are JSOPs in the jsref, but I\r
215          * don't have them yet in the java implementation...\r
216          * so they go here.  Also whatever I needed.\r
217 \r
218          * Most of these go in the 'op' field when returning\r
219          * more general token types, eg. 'DIV' as the op of 'ASSIGN'.\r
220          */\r
221         NOP         = 128, // NOP\r
222         NOT         = 129, // etc.\r
223         PRE         = 130, // for INC, DEC nodes.\r
224         POST        = 131,\r
225 \r
226         /**\r
227          * For JSOPs associated with keywords...\r
228          * eg. op = THIS; token = PRIMARY\r
229          */\r
230 \r
231         VOID        = 132,\r
232 \r
233         /* types used for the parse tree - these never get returned\r
234          * by the scanner.\r
235          */\r
236         BLOCK       = 133, // statement block\r
237         ARRAYLIT    = 134, // array literal\r
238         OBJLIT      = 135, // object literal\r
239         LABEL       = 136, // label\r
240         TARGET      = 137,\r
241         LOOP        = 138,\r
242         ENUMDONE    = 139,\r
243         EXPRSTMT    = 140,\r
244         PARENT      = 141,\r
245         CONVERT     = 142,\r
246         JSR         = 143,\r
247         NEWLOCAL    = 144,\r
248         USELOCAL    = 145,\r
249         SCRIPT      = 146,   // top-level node for entire script\r
250         \r
251         /**\r
252          * For the interpreted mode indicating a line number change in icodes.\r
253          */\r
254         LINE        = 147,\r
255         SOURCEFILE  = 148,\r
256         \r
257         // For debugger\r
258         \r
259         BREAKPOINT  = 149,\r
260         ASSERT      = 150; // XWT assert hack\r
261     // end enum\r
262 \r
263 \r
264     /* for mapping int token types to printable strings.\r
265      * make sure to add 1 to index before using these!\r
266      */\r
267     private static String names[];\r
268     private static void checkNames() {\r
269         if (Context.printTrees && names == null) {\r
270             String[] a = {\r
271                 "error",\r
272                 "eof",\r
273                 "eol",\r
274                 "popv",\r
275                 "enterwith",\r
276                 "leavewith",\r
277                 "return",\r
278                 "goto",\r
279                 "ifeq",\r
280                 "ifne",\r
281                 "dup",\r
282                 "setname",\r
283                 "bitor",\r
284                 "bitxor",\r
285                 "bitand",\r
286                 "eq",\r
287                 "ne",\r
288                 "lt",\r
289                 "le",\r
290                 "gt",\r
291                 "ge",\r
292                 "lsh",\r
293                 "rsh",\r
294                 "ursh",\r
295                 "add",\r
296                 "sub",\r
297                 "mul",\r
298                 "div",\r
299                 "mod",\r
300                 "bitnot",\r
301                 "neg",\r
302                 "new",\r
303                 "delprop",\r
304                 "typeof",\r
305                 "nameinc",\r
306                 "propinc",\r
307                 "eleminc",\r
308                 "namedec",\r
309                 "propdec",\r
310                 "elemdec",\r
311                 "getprop",\r
312                 "setprop",\r
313                 "getelem",\r
314                 "setelem",\r
315                 "call",\r
316                 "name",\r
317                 "number",\r
318                 "string",\r
319                 "zero",\r
320                 "one",\r
321                 "null",\r
322                 "this",\r
323                 "false",\r
324                 "true",\r
325                 "sheq",\r
326                 "shne",\r
327                 "closure",\r
328                 "object",\r
329                 "pop",\r
330                 "pos",\r
331                 "varinc",\r
332                 "vardec",\r
333                 "bindname",\r
334                 "throw",\r
335                 "in",\r
336                 "instanceof",\r
337                 "gosub",\r
338                 "retsub",\r
339                 "callspecial",\r
340                 "getthis",\r
341                 "newtemp",\r
342                 "usetemp",\r
343                 "getbase",\r
344                 "getvar",\r
345                 "setvar",\r
346                 "undefined",\r
347                 "try",\r
348                 "endtry",\r
349                 "newscope",\r
350                 "typeofname",\r
351                 "enuminit",\r
352                 "enumnext",\r
353                 "getproto",\r
354                 "getparent",\r
355                 "setproto",\r
356                 "setparent",\r
357                 "scope",\r
358                 "getscopeparent",\r
359                 "thisfn",\r
360                 "jthrow",\r
361                 "semi",\r
362                 "lb",\r
363                 "rb",\r
364                 "lc",\r
365                 "rc",\r
366                 "lp",\r
367                 "rp",\r
368                 "comma",\r
369                 "assign",\r
370                 "hook",\r
371                 "colon",\r
372                 "or",\r
373                 "and",\r
374                 "eqop",\r
375                 "relop",\r
376                 "shop",\r
377                 "unaryop",\r
378                 "inc",\r
379                 "dec",\r
380                 "dot",\r
381                 "primary",\r
382                 "function",\r
383                 "export",\r
384                 "import",\r
385                 "if",\r
386                 "else",\r
387                 "switch",\r
388                 "case",\r
389                 "default",\r
390                 "while",\r
391                 "do",\r
392                 "for",\r
393                 "break",\r
394                 "continue",\r
395                 "var",\r
396                 "with",\r
397                 "catch",\r
398                 "finally",\r
399                 "reserved",\r
400                 "nop",\r
401                 "not",\r
402                 "pre",\r
403                 "post",\r
404                 "void",\r
405                 "block",\r
406                 "arraylit",\r
407                 "objlit",\r
408                 "label",\r
409                 "target",\r
410                 "loop",\r
411                 "enumdone",\r
412                 "exprstmt",\r
413                 "parent",\r
414                 "convert",\r
415                 "jsr",\r
416                 "newlocal",\r
417                 "uselocal",\r
418                 "script",\r
419                 "line",\r
420                 "sourcefile",\r
421             };\r
422             names = a;\r
423         }\r
424     }\r
425 \r
426     /* This function uses the cached op, string and number fields in\r
427      * TokenStream; if getToken has been called since the passed token\r
428      * was scanned, the op or string printed may be incorrect.\r
429      */\r
430     public String tokenToString(int token) {\r
431         if (Context.printTrees) {\r
432             checkNames();\r
433             if (token + 1 >= names.length)\r
434                 return null;\r
435 \r
436             if (token == UNARYOP ||\r
437                 token == ASSIGN ||\r
438                 token == PRIMARY ||\r
439                 token == EQOP ||\r
440                 token == SHOP ||\r
441                 token == RELOP) {\r
442                 return names[token + 1] + " " + names[this.op + 1];\r
443             }\r
444 \r
445             if (token == STRING || token == OBJECT || token == NAME)\r
446                 return names[token + 1] + " `" + this.string + "'";\r
447 \r
448             if (token == NUMBER)\r
449                 return "NUMBER " + this.number;\r
450 \r
451             return names[token + 1];\r
452         }\r
453         return "";\r
454     }\r
455 \r
456     public static String tokenToName(int type) {\r
457         checkNames();\r
458         return names == null ? "" : names[type + 1];\r
459     }\r
460 \r
461 \r
462     private int stringToKeyword(String name) {\r
463 // #string_id_map#\r
464 // The following assumes that EOF == 0\r
465         final int    \r
466             Id_break         = BREAK,\r
467             Id_case          = CASE,\r
468             Id_continue      = CONTINUE,\r
469             Id_default       = DEFAULT,\r
470             Id_delete        = DELPROP,\r
471             Id_do            = DO,\r
472             Id_else          = ELSE,\r
473             Id_export        = EXPORT,\r
474             Id_false         = PRIMARY | (FALSE << 8),\r
475             Id_for           = FOR,\r
476             Id_function      = FUNCTION,\r
477             Id_if            = IF,\r
478             Id_in            = RELOP | (IN << 8),\r
479             Id_new           = NEW,\r
480             Id_null          = PRIMARY | (NULL << 8),\r
481             Id_return        = RETURN,\r
482             Id_switch        = SWITCH,\r
483             Id_this          = PRIMARY | (THIS << 8),\r
484             Id_true          = PRIMARY | (TRUE << 8),\r
485             Id_typeof        = UNARYOP | (TYPEOF << 8),\r
486             Id_var           = VAR,\r
487             Id_void          = UNARYOP | (VOID << 8),\r
488             Id_while         = WHILE,\r
489             Id_with          = WITH,\r
490 \r
491             // the following are #ifdef RESERVE_JAVA_KEYWORDS in jsscan.c\r
492             Id_abstract      = RESERVED,\r
493             Id_boolean       = RESERVED,\r
494             Id_byte          = RESERVED,\r
495             Id_catch         = CATCH,\r
496             Id_char          = RESERVED,\r
497             Id_class         = RESERVED,\r
498             Id_const         = RESERVED,\r
499             Id_debugger      = RESERVED,\r
500             Id_double        = RESERVED,\r
501             Id_enum          = RESERVED,\r
502             Id_extends       = RESERVED,\r
503             Id_final         = RESERVED,\r
504             Id_finally       = FINALLY,\r
505             Id_float         = RESERVED,\r
506             Id_goto          = RESERVED,\r
507             Id_implements    = RESERVED,\r
508             Id_import        = IMPORT,\r
509             Id_instanceof    = RELOP | (INSTANCEOF << 8),\r
510             Id_int           = RESERVED,\r
511             Id_interface     = RESERVED,\r
512             Id_long          = RESERVED,\r
513             Id_native        = RESERVED,\r
514             Id_package       = RESERVED,\r
515             Id_private       = RESERVED,\r
516             Id_protected     = RESERVED,\r
517             Id_public        = RESERVED,\r
518             Id_assert        = ASSERT,\r
519             Id_short         = RESERVED,\r
520             Id_static        = RESERVED,\r
521             Id_super         = RESERVED,\r
522             Id_synchronized  = RESERVED,\r
523             Id_throw         = THROW,\r
524             Id_throws        = RESERVED,\r
525             Id_transient     = RESERVED,\r
526             Id_try           = TRY,\r
527             Id_volatile      = RESERVED;\r
528         \r
529         int id;\r
530         String s = name;\r
531 // #generated# Last update: 2001-06-01 17:45:01 CEST\r
532         L0: { id = 0; String X = null; int c;\r
533             L: switch (s.length()) {\r
534             case 2: c=s.charAt(1);\r
535                 if (c=='f') { if (s.charAt(0)=='i') {id=Id_if; break L0;} }\r
536                 else if (c=='n') { if (s.charAt(0)=='i') {id=Id_in; break L0;} }\r
537                 else if (c=='o') { if (s.charAt(0)=='d') {id=Id_do; break L0;} }\r
538                 break L;\r
539             case 3: switch (s.charAt(0)) {\r
540                 case 'f': if (s.charAt(2)=='r' && s.charAt(1)=='o') {id=Id_for; break L0;} break L;\r
541                 case 'i': if (s.charAt(2)=='t' && s.charAt(1)=='n') {id=Id_int; break L0;} break L;\r
542                 case 'n': if (s.charAt(2)=='w' && s.charAt(1)=='e') {id=Id_new; break L0;} break L;\r
543                 case 't': if (s.charAt(2)=='y' && s.charAt(1)=='r') {id=Id_try; break L0;} break L;\r
544                 case 'v': if (s.charAt(2)=='r' && s.charAt(1)=='a') {id=Id_var; break L0;} break L;\r
545                 } break L;\r
546             case 4: switch (s.charAt(0)) {\r
547                 case 'b': X="byte";id=Id_byte; break L;\r
548                 case 'c': c=s.charAt(3);\r
549                     if (c=='e') { if (s.charAt(2)=='s' && s.charAt(1)=='a') {id=Id_case; break L0;} }\r
550                     else if (c=='r') { if (s.charAt(2)=='a' && s.charAt(1)=='h') {id=Id_char; break L0;} }\r
551                     break L;\r
552                 case 'e': c=s.charAt(3);\r
553                     if (c=='e') { if (s.charAt(2)=='s' && s.charAt(1)=='l') {id=Id_else; break L0;} }\r
554                     else if (c=='m') { if (s.charAt(2)=='u' && s.charAt(1)=='n') {id=Id_enum; break L0;} }\r
555                     break L;\r
556                 case 'g': X="goto";id=Id_goto; break L;\r
557                 case 'l': X="long";id=Id_long; break L;\r
558                 case 'n': X="null";id=Id_null; break L;\r
559                 case 't': c=s.charAt(3);\r
560                     if (c=='e') { if (s.charAt(2)=='u' && s.charAt(1)=='r') {id=Id_true; break L0;} }\r
561                     else if (c=='s') { if (s.charAt(2)=='i' && s.charAt(1)=='h') {id=Id_this; break L0;} }\r
562                     break L;\r
563                 case 'v': X="void";id=Id_void; break L;\r
564                 case 'w': X="with";id=Id_with; break L;\r
565                 } break L;\r
566             case 5: switch (s.charAt(2)) {\r
567                 case 'a': X="class";id=Id_class; break L;\r
568                 case 'e': X="break";id=Id_break; break L;\r
569                 case 'i': X="while";id=Id_while; break L;\r
570                 case 'l': X="false";id=Id_false; break L;\r
571                 case 'n': c=s.charAt(0);\r
572                     if (c=='c') { X="const";id=Id_const; }\r
573                     else if (c=='f') { X="final";id=Id_final; }\r
574                     break L;\r
575                 case 'o': c=s.charAt(0);\r
576                     if (c=='f') { X="float";id=Id_float; }\r
577                     else if (c=='s') { X="short";id=Id_short; }\r
578                     break L;\r
579                 case 'p': X="super";id=Id_super; break L;\r
580                 case 'r': X="throw";id=Id_throw; break L;\r
581                 case 't': X="catch";id=Id_catch; break L;\r
582                 } break L;\r
583             case 6: switch (s.charAt(1)) {\r
584                 case 'a': X="native";id=Id_native; break L;\r
585                 case 'e': c=s.charAt(0);\r
586                     if (c=='d') { X="delete";id=Id_delete; }\r
587                     else if (c=='r') { X="return";id=Id_return; }\r
588                     break L;\r
589                 case 'h': X="throws";id=Id_throws; break L;\r
590                 case 'm': X="import";id=Id_import; break L;\r
591                 case 'o': X="double";id=Id_double; break L;\r
592 \r
593                     // commented out by Adam Megacz for XWT\r
594                     /*\r
595                 case 't': X="static";id=Id_static; break L;\r
596                     */\r
597 \r
598                 case 's': X="assert";id=Id_assert; break L;\r
599                 case 'u': X="public";id=Id_public; break L;\r
600                 case 'w': X="switch";id=Id_switch; break L;\r
601                 case 'x': X="export";id=Id_export; break L;\r
602                 case 'y': X="typeof";id=Id_typeof; break L;\r
603                 } break L;\r
604             case 7: switch (s.charAt(1)) {\r
605                 case 'a': X="package";id=Id_package; break L;\r
606                 case 'e': X="default";id=Id_default; break L;\r
607                 case 'i': X="finally";id=Id_finally; break L;\r
608                 case 'o': X="boolean";id=Id_boolean; break L;\r
609                 case 'r': X="private";id=Id_private; break L;\r
610                 case 'x': X="extends";id=Id_extends; break L;\r
611                 } break L;\r
612             case 8: switch (s.charAt(0)) {\r
613                 case 'a': X="abstract";id=Id_abstract; break L;\r
614                 case 'c': X="continue";id=Id_continue; break L;\r
615                 case 'd': X="debugger";id=Id_debugger; break L;\r
616                 case 'f': X="function";id=Id_function; break L;\r
617                 case 'v': X="volatile";id=Id_volatile; break L;\r
618                 } break L;\r
619             case 9: c=s.charAt(0);\r
620                 if (c=='i') { X="interface";id=Id_interface; }\r
621                 else if (c=='p') { X="protected";id=Id_protected; }\r
622                 else if (c=='t') { X="transient";id=Id_transient; }\r
623                 break L;\r
624             case 10: c=s.charAt(1);\r
625                 if (c=='m') { X="implements";id=Id_implements; }\r
626                 else if (c=='n') { X="instanceof";id=Id_instanceof; }\r
627                 break L;\r
628             case 12: X="synchronized";id=Id_synchronized; break L;\r
629             }\r
630             if (X!=null && X!=s && !X.equals(s)) id = 0;\r
631             if (id == Id_const) Context.reportError("The 'const' keyword is not allowed in XWT scripts",\r
632                                                     getSourceName(), getLineno(), getLine(), getOffset());\r
633             if (id == Id_instanceof) Context.reportError("The 'instanceof' keyword is not allowed in XWT scripts",\r
634                                                          getSourceName(), getLineno(), getLine(), getOffset());\r
635             if (id == Id_delete) Context.reportError("The 'delete' keyword is not allowed in XWT scripts",\r
636                                                      getSourceName(), getLineno(), getLine(), getOffset());\r
637 \r
638         }\r
639         if (id == Id_new) Context.reportError("The 'new' keyword is not allowed in XWT scripts",\r
640                                                getSourceName(), getLineno(), getLine(), getOffset());\r
641 // #/generated#\r
642 // #/string_id_map#\r
643         if (id == 0) { return EOF; }\r
644         this.op = id >> 8;\r
645         return id & 0xff;\r
646     }\r
647 \r
648     public TokenStream(Reader in, Scriptable scope,\r
649                        String sourceName, int lineno)\r
650     {\r
651         this.in = new LineBuffer(in, lineno);\r
652         this.scope = scope;\r
653         this.pushbackToken = EOF;\r
654         this.sourceName = sourceName;\r
655         flags = 0;\r
656     }\r
657     \r
658     public Scriptable getScope() { \r
659         return scope;\r
660     }\r
661 \r
662     /* return and pop the token from the stream if it matches...\r
663      * otherwise return null\r
664      */\r
665     public boolean matchToken(int toMatch) throws IOException {\r
666         int token = getToken();\r
667         if (token == toMatch)\r
668             return true;\r
669 \r
670         // didn't match, push back token\r
671         tokenno--;\r
672         this.pushbackToken = token;\r
673         return false;\r
674     }\r
675 \r
676     public void clearPushback() {\r
677         this.pushbackToken = EOF;\r
678     }\r
679 \r
680     public void ungetToken(int tt) {\r
681         if (this.pushbackToken != EOF && tt != ERROR) {\r
682             String message = Context.getMessage2("msg.token.replaces.pushback",\r
683                 tokenToString(tt), tokenToString(this.pushbackToken));\r
684             throw new RuntimeException(message);\r
685         }\r
686         this.pushbackToken = tt;\r
687         tokenno--;\r
688     }\r
689 \r
690     public int peekToken() throws IOException {\r
691         int result = getToken();\r
692 \r
693         this.pushbackToken = result;\r
694         tokenno--;\r
695         return result;\r
696     }\r
697 \r
698     public int peekTokenSameLine() throws IOException {\r
699         int result;\r
700 \r
701         flags |= TSF_NEWLINES;          // SCAN_NEWLINES from jsscan.h\r
702         result = peekToken();\r
703         flags &= ~TSF_NEWLINES;         // HIDE_NEWLINES from jsscan.h\r
704         if (this.pushbackToken == EOL)\r
705             this.pushbackToken = EOF;\r
706         return result;\r
707     }\r
708 \r
709     protected static boolean isJSIdentifier(String s) {\r
710 \r
711         int length = s.length();\r
712 \r
713         if (length == 0 || !Character.isJavaIdentifierStart(s.charAt(0)))\r
714             return false;\r
715 \r
716         for (int i=1; i<length; i++) {\r
717             char c = s.charAt(i);\r
718             if (!Character.isJavaIdentifierPart(c))\r
719                 if (c == '\\')\r
720                     if (! ((i + 5) < length)\r
721                             && (s.charAt(i + 1) == 'u')\r
722                             && 0 <= xDigitToInt(s.charAt(i + 2))\r
723                             && 0 <= xDigitToInt(s.charAt(i + 3))\r
724                             && 0 <= xDigitToInt(s.charAt(i + 4))\r
725                             && 0 <= xDigitToInt(s.charAt(i + 5)))\r
726                     \r
727                 return false;\r
728         }\r
729 \r
730         return true;\r
731     }\r
732 \r
733     private static boolean isAlpha(int c) {\r
734         return ((c >= 'a' && c <= 'z')\r
735                 || (c >= 'A' && c <= 'Z'));\r
736     }\r
737 \r
738     static boolean isDigit(int c) {\r
739         return (c >= '0' && c <= '9');\r
740     }\r
741 \r
742     static int xDigitToInt(int c) {\r
743         if ('0' <= c && c <= '9') { return c - '0'; }\r
744         if ('a' <= c && c <= 'f') { return c - ('a' - 10); }\r
745         if ('A' <= c && c <= 'F') { return c - ('A' - 10); }\r
746         return -1;\r
747     }\r
748 \r
749     /* As defined in ECMA.  jsscan.c uses C isspace() (which allows\r
750      * \v, I think.)  note that code in in.read() implicitly accepts\r
751      * '\r' == \u000D as well.\r
752      */\r
753     public static boolean isJSSpace(int c) {\r
754         return (c == '\u0020' || c == '\u0009'\r
755                 || c == '\u000C' || c == '\u000B'\r
756                 || c == '\u00A0' \r
757                 || Character.getType((char)c) == Character.SPACE_SEPARATOR);\r
758     }\r
759 \r
760     public static boolean isJSLineTerminator(int c) {\r
761         return (c == '\n' || c == '\r'\r
762                 || c == 0x2028 || c == 0x2029);\r
763     }\r
764     \r
765     public int getToken() throws IOException {\r
766         int c;\r
767         tokenno++;\r
768 \r
769         // Check for pushed-back token\r
770         if (this.pushbackToken != EOF) {\r
771             int result = this.pushbackToken;\r
772             this.pushbackToken = EOF;\r
773             return result;\r
774         }\r
775 \r
776         // Eat whitespace, possibly sensitive to newlines.\r
777         do {\r
778             c = in.read();\r
779             if (c == '\n')\r
780                 if ((flags & TSF_NEWLINES) != 0)\r
781                     break;\r
782         } while (isJSSpace(c) || c == '\n');\r
783 \r
784         if (c == EOF_CHAR)\r
785             return EOF;\r
786 \r
787         // identifier/keyword/instanceof?\r
788         // watch out for starting with a <backslash>\r
789         boolean isUnicodeEscapeStart = false;\r
790         if (c == '\\') {\r
791             c = in.read();\r
792             if (c == 'u')\r
793                 isUnicodeEscapeStart = true;\r
794             else\r
795                 c = '\\';\r
796             // always unread the 'u' or whatever, we need \r
797             // to start the string below at the <backslash>.\r
798             in.unread();\r
799         }\r
800         if (isUnicodeEscapeStart ||\r
801                     Character.isJavaIdentifierStart((char)c)) {\r
802             in.startString();\r
803 \r
804             boolean containsEscape = isUnicodeEscapeStart;            \r
805             do {\r
806                 c = in.read();\r
807                 if (c == '\\') {\r
808                     c = in.read();\r
809                     containsEscape = (c == 'u');\r
810                 }                    \r
811             } while (Character.isJavaIdentifierPart((char)c));\r
812             in.unread();\r
813 \r
814             int result;\r
815 \r
816             String str = in.getString();\r
817             // OPT we shouldn't have to make a string (object!) to\r
818             // check if it's a keyword.\r
819             \r
820             // strictly speaking we should probably push-back\r
821             // all the bad characters if the <backslash>uXXXX  \r
822             // sequence is malformed. But since there isn't a  \r
823             // correct context(is there?) for a bad Unicode  \r
824             // escape sequence after an identifier, we can report\r
825             // an error here.\r
826             if (containsEscape) {\r
827                 char ca[] = str.toCharArray();\r
828                 int L = str.length();\r
829                 int destination = 0;\r
830                 for (int i = 0; i != L;) {\r
831                     c = ca[i];\r
832                     ++i;\r
833                     if (c == '\\' && i != L && ca[i] == 'u') {\r
834                         boolean goodEscape = false;\r
835                         if (i + 4 < L) {\r
836                             int val = xDigitToInt(ca[i + 1]);\r
837                             if (val >= 0) {\r
838                                 val = (val << 4) | xDigitToInt(ca[i + 2]);\r
839                                 if (val >= 0) {\r
840                                     val = (val << 4) | xDigitToInt(ca[i + 3]);\r
841                                     if (val >= 0) {\r
842                                         val = (val << 4) | xDigitToInt(ca[i + 4]);\r
843                                         if (val >= 0) {\r
844                                             c = (char)val;\r
845                                             i += 5;\r
846                                             goodEscape = true;\r
847                                         }\r
848                                     }\r
849                                 }\r
850                             }\r
851                         }\r
852                         if (!goodEscape) {\r
853                             reportSyntaxError("msg.invalid.escape", null);\r
854                             return ERROR;\r
855                         }\r
856                     }\r
857                     ca[destination] = (char)c;\r
858                     ++destination;\r
859                 }\r
860                 str = new String(ca, 0, destination);\r
861             }\r
862             else\r
863                 // Return the corresponding token if it's a keyword\r
864                 if ((result = stringToKeyword(str)) != EOF) {\r
865                     return result;\r
866                 }\r
867 \r
868             this.string = str;\r
869             return NAME;\r
870         }\r
871 \r
872         // is it a number?\r
873         if (isDigit(c) || (c == '.' && isDigit(in.peek()))) {\r
874             int base = 10;\r
875             in.startString();\r
876 \r
877             double dval = ScriptRuntime.NaN;\r
878             long longval = 0;\r
879             boolean isInteger = true;\r
880 \r
881             if (c == '0') {\r
882                 c = in.read();\r
883                 if (c == 'x' || c == 'X') {\r
884                     c = in.read();\r
885                     base = 16;\r
886                     // restart the string, losing leading 0x\r
887                     in.startString();\r
888                 } else if (isDigit(c)) {\r
889                     base = 8;\r
890                 }\r
891             }\r
892 \r
893             while (0 <= xDigitToInt(c)) {\r
894                 if (base < 16) {\r
895                     if (isAlpha(c))\r
896                         break;\r
897                     /*\r
898                      * We permit 08 and 09 as decimal numbers, which\r
899                      * makes our behavior a superset of the ECMA\r
900                      * numeric grammar.  We might not always be so\r
901                      * permissive, so we warn about it.\r
902                      */\r
903                     if (base == 8 && c >= '8') {\r
904                         Object[] errArgs = { c == '8' ? "8" : "9" };\r
905                         Context.reportWarning(\r
906                             Context.getMessage("msg.bad.octal.literal",\r
907                                                errArgs),\r
908                             getSourceName(),\r
909                             in.getLineno(), getLine(), getOffset());\r
910                         base = 10;\r
911                     }\r
912                 }\r
913                 c = in.read();\r
914             }\r
915 \r
916             if (base == 10 && (c == '.' || c == 'e' || c == 'E')) {\r
917                 isInteger = false;\r
918                 if (c == '.') {\r
919                     do {\r
920                         c = in.read();\r
921                     } while (isDigit(c));\r
922                 }\r
923 \r
924                 if (c == 'e' || c == 'E') {\r
925                     c = in.read();\r
926                     if (c == '+' || c == '-') {\r
927                         c = in.read();\r
928                     }\r
929                     if (!isDigit(c)) {\r
930                         in.getString(); // throw away string in progress\r
931                         reportSyntaxError("msg.missing.exponent", null);\r
932                         return ERROR;\r
933                     }\r
934                     do {\r
935                         c = in.read();\r
936                     } while (isDigit(c));\r
937                 }\r
938             }\r
939             in.unread();\r
940             String numString = in.getString();\r
941 \r
942             if (base == 10 && !isInteger) {\r
943                 try {\r
944                     // Use Java conversion to number from string...\r
945                     dval = (Double.valueOf(numString)).doubleValue();\r
946                 }\r
947                 catch (NumberFormatException ex) {\r
948                     Object[] errArgs = { ex.getMessage() };\r
949                     reportSyntaxError("msg.caught.nfe", errArgs);\r
950                     return ERROR;\r
951                 }\r
952             } else {\r
953                 dval = ScriptRuntime.stringToNumber(numString, 0, base);\r
954                 longval = (long) dval;\r
955 \r
956                 // is it an integral fits-in-a-long value?\r
957                 if (longval != dval)\r
958                     isInteger = false;\r
959             }\r
960 \r
961             if (!isInteger) {\r
962                 /* Can't handle floats right now, because postfix INC/DEC\r
963                    generate Doubles, but I would generate a Float through this\r
964                    path, and it causes a stack mismatch. FIXME (MS)\r
965                    if (Float.MIN_VALUE <= dval && dval <= Float.MAX_VALUE)\r
966                    this.number = new Xloat((float) dval);\r
967                    else\r
968                 */\r
969                 this.number = new Double(dval);\r
970             } else {\r
971                 // We generate the smallest possible type here\r
972                 if (Byte.MIN_VALUE <= longval && longval <= Byte.MAX_VALUE)\r
973                     this.number = new Byte((byte)longval);\r
974                 else if (Short.MIN_VALUE <= longval &&\r
975                          longval <= Short.MAX_VALUE)\r
976                     this.number = new Short((short)longval);\r
977                 else if (Integer.MIN_VALUE <= longval &&\r
978                          longval <= Integer.MAX_VALUE)\r
979                     this.number = new Integer((int)longval);\r
980                 else {\r
981                     // May lose some precision here, but that's the \r
982                     // appropriate semantics.\r
983                     this.number = new Double(longval);\r
984                 }\r
985             }\r
986             return NUMBER;\r
987         }\r
988 \r
989         // is it a string?\r
990         if (c == '"' || c == '\'') {\r
991             // We attempt to accumulate a string the fast way, by\r
992             // building it directly out of the reader.  But if there\r
993             // are any escaped characters in the string, we revert to\r
994             // building it out of a StringBuffer.\r
995 \r
996             StringBuffer stringBuf = null;\r
997 \r
998             int quoteChar = c;\r
999             int val = 0;\r
1000 \r
1001             c = in.read();\r
1002             in.startString(); // start after the first "\r
1003             while(c != quoteChar) {\r
1004                 if (c == '\n' || c == EOF_CHAR) {\r
1005                     in.unread();\r
1006                     in.getString(); // throw away the string in progress\r
1007                     reportSyntaxError("msg.unterminated.string.lit", null);\r
1008                     return ERROR;\r
1009                 }\r
1010 \r
1011                 if (c == '\\') {\r
1012                     // We've hit an escaped character; revert to the\r
1013                     // slow method of building a string.\r
1014                     if (stringBuf == null) {\r
1015                         // Don't include the backslash\r
1016                         in.unread();\r
1017                         stringBuf = new StringBuffer(in.getString());\r
1018                         in.read();\r
1019                     }\r
1020 \r
1021                     switch (c = in.read()) {\r
1022                     case 'b': c = '\b'; break;\r
1023                     case 'f': c = '\f'; break;\r
1024                     case 'n': c = '\n'; break;\r
1025                     case 'r': c = '\r'; break;\r
1026                     case 't': c = '\t'; break;\r
1027                     case 'v': c = '\u000B'; break;\r
1028                         // \v a late addition to the ECMA spec.\r
1029                         // '\v' doesn't seem to be valid Java.\r
1030 \r
1031                     default:\r
1032                         if (isDigit(c) && c < '8') {\r
1033                             val = c - '0';\r
1034                             c = in.read();\r
1035                             if (isDigit(c) && c < '8') {\r
1036                                 val = 8 * val + c - '0';\r
1037                                 c = in.read();\r
1038                                 if (isDigit(c) && c < '8') {\r
1039                                     val = 8 * val + c - '0';\r
1040                                     c = in.read();\r
1041                                 }\r
1042                             }\r
1043                             in.unread();\r
1044                             if (val > 0377) {\r
1045                                 reportSyntaxError("msg.oct.esc.too.large", null);\r
1046                                 return ERROR;\r
1047                             }\r
1048                             c = val;\r
1049                         } else if (c == 'u') {\r
1050                             /*\r
1051                              * Get 4 hex digits; if the u escape is not\r
1052                              * followed by 4 hex digits, use 'u' + the literal\r
1053                              * character sequence that follows.  Do some manual\r
1054                              * match (OK because we're in a string) to avoid\r
1055                              * multi-char match on the underlying stream.\r
1056                              */\r
1057                             int c1 = in.read();\r
1058                             c = xDigitToInt(c1);\r
1059                             if (c < 0) {\r
1060                                 in.unread();\r
1061                                 c = 'u';\r
1062                             } else {\r
1063                                 int c2 = in.read();\r
1064                                 c = (c << 4) | xDigitToInt(c2);\r
1065                                 if (c < 0) {\r
1066                                     in.unread();\r
1067                                     stringBuf.append('u');\r
1068                                     c = c1;\r
1069                                 } else {\r
1070                                     int c3 = in.read();\r
1071                                     c = (c << 4) | xDigitToInt(c3);\r
1072                                     if (c < 0) {\r
1073                                         in.unread();\r
1074                                         stringBuf.append('u');\r
1075                                         stringBuf.append((char)c1);\r
1076                                         c = c2;\r
1077                                     } else {\r
1078                                         int c4 = in.read();\r
1079                                         c = (c << 4) | xDigitToInt(c4);\r
1080                                         if (c < 0) {\r
1081                                             in.unread();\r
1082                                             stringBuf.append('u');\r
1083                                             stringBuf.append((char)c1);\r
1084                                             stringBuf.append((char)c2);\r
1085                                             c = c3;\r
1086                                         } else {\r
1087                                             // got 4 hex digits! Woo Hoo!\r
1088                                         }\r
1089                                     }\r
1090                                 }\r
1091                             }\r
1092                         } else if (c == 'x') {\r
1093                             /* Get 2 hex digits, defaulting to 'x' + literal\r
1094                              * sequence, as above.\r
1095                              */\r
1096                             int c1 = in.read();\r
1097                             c = xDigitToInt(c1);\r
1098                             if (c < 0) {\r
1099                                 in.unread();\r
1100                                 c = 'x';\r
1101                             } else {\r
1102                                 int c2 = in.read();\r
1103                                 c = (c << 4) | xDigitToInt(c2);\r
1104                                 if (c < 0) {\r
1105                                     in.unread();\r
1106                                     stringBuf.append('x');\r
1107                                     c = c1;\r
1108                                 } else {\r
1109                                     // got 2 hex digits\r
1110                                 }\r
1111                             }\r
1112                         }\r
1113                     }\r
1114                 }\r
1115                 \r
1116                 if (stringBuf != null)\r
1117                     stringBuf.append((char) c);\r
1118                 c = in.read();\r
1119             }\r
1120 \r
1121             if (stringBuf != null)\r
1122                 this.string = stringBuf.toString();\r
1123             else {\r
1124                 in.unread(); // miss the trailing "\r
1125                 this.string = in.getString();\r
1126                 in.read();\r
1127             }\r
1128             return STRING;\r
1129         }\r
1130 \r
1131         switch (c)\r
1132         {\r
1133         case '\n': return EOL;\r
1134         case ';': return SEMI;\r
1135         case '[': return LB;\r
1136         case ']': return RB;\r
1137         case '{': return LC;\r
1138         case '}': return RC;\r
1139         case '(': return LP;\r
1140         case ')': return RP;\r
1141         case ',': return COMMA;\r
1142         case '?': return HOOK;\r
1143         case ':': return COLON;\r
1144         case '.': return DOT;\r
1145 \r
1146         case '|':\r
1147             if (in.match('|')) {\r
1148                 return OR;\r
1149             } else if (in.match('=')) {\r
1150                 this.op = BITOR;\r
1151                 return ASSIGN;\r
1152             } else {\r
1153                 return BITOR;\r
1154             }\r
1155 \r
1156         case '^':\r
1157             if (in.match('=')) {\r
1158                 this.op = BITXOR;\r
1159                 return ASSIGN;\r
1160             } else {\r
1161                 return BITXOR;\r
1162             }\r
1163 \r
1164         case '&':\r
1165             if (in.match('&')) {\r
1166                 return AND;\r
1167             } else if (in.match('=')) {\r
1168                 this.op = BITAND;\r
1169                 return ASSIGN;\r
1170             } else {\r
1171                 return BITAND;\r
1172             }\r
1173 \r
1174         case '=':\r
1175             if (in.match('=')) {\r
1176                 if (in.match('='))\r
1177                     this.op = SHEQ;\r
1178                 else\r
1179                     this.op = EQ;\r
1180                 return EQOP;\r
1181             } else {\r
1182                 this.op = NOP;\r
1183                 return ASSIGN;\r
1184             }\r
1185 \r
1186         case '!':\r
1187             if (in.match('=')) {\r
1188                 if (in.match('='))\r
1189                     this.op = SHNE;\r
1190                 else\r
1191                     this.op = NE;\r
1192                 return EQOP;\r
1193             } else {\r
1194                 this.op = NOT;\r
1195                 return UNARYOP;\r
1196             }\r
1197 \r
1198         case '<':\r
1199             /* NB:treat HTML begin-comment as comment-till-eol */\r
1200             if (in.match('!')) {\r
1201                 if (in.match('-')) {\r
1202                     if (in.match('-')) {\r
1203                         while ((c = in.read()) != EOF_CHAR && c != '\n')\r
1204                             /* skip to end of line */;\r
1205                         in.unread();\r
1206                         return getToken();  // in place of 'goto retry'\r
1207                     }\r
1208                     in.unread();\r
1209                 }\r
1210                 in.unread();\r
1211             }\r
1212             if (in.match('<')) {\r
1213                 if (in.match('=')) {\r
1214                     this.op = LSH;\r
1215                     return ASSIGN;\r
1216                 } else {\r
1217                     this.op = LSH;\r
1218                     return SHOP;\r
1219                 }\r
1220             } else {\r
1221                 if (in.match('=')) {\r
1222                     this.op = LE;\r
1223                     return RELOP;\r
1224                 } else {\r
1225                     this.op = LT;\r
1226                     return RELOP;\r
1227                 }\r
1228             }\r
1229 \r
1230         case '>':\r
1231             if (in.match('>')) {\r
1232                 if (in.match('>')) {\r
1233                     if (in.match('=')) {\r
1234                         this.op = URSH;\r
1235                         return ASSIGN;\r
1236                     } else {\r
1237                         this.op = URSH;\r
1238                         return SHOP;\r
1239                     }\r
1240                 } else {\r
1241                     if (in.match('=')) {\r
1242                         this.op = RSH;\r
1243                         return ASSIGN;\r
1244                     } else {\r
1245                         this.op = RSH;\r
1246                         return SHOP;\r
1247                     }\r
1248                 }\r
1249             } else {\r
1250                 if (in.match('=')) {\r
1251                     this.op = GE;\r
1252                     return RELOP;\r
1253                 } else {\r
1254                     this.op = GT;\r
1255                     return RELOP;\r
1256                 }\r
1257             }\r
1258 \r
1259         case '*':\r
1260             if (in.match('=')) {\r
1261                 this.op = MUL;\r
1262                 return ASSIGN;\r
1263             } else {\r
1264                 return MUL;\r
1265             }\r
1266 \r
1267         case '/':\r
1268             // is it a // comment?\r
1269             if (in.match('/')) {\r
1270                 while ((c = in.read()) != EOF_CHAR && c != '\n')\r
1271                     /* skip to end of line */;\r
1272                 in.unread();\r
1273                 return getToken();\r
1274             }\r
1275             if (in.match('*')) {\r
1276                 while ((c = in.read()) != -1\r
1277                        && !(c == '*' && in.match('/'))) {\r
1278                     if (c == '\n') {\r
1279                     } else if (c == '/' && in.match('*')) {\r
1280                         if (in.match('/'))\r
1281                             return getToken();\r
1282                         reportSyntaxError("msg.nested.comment", null);\r
1283                         return ERROR;\r
1284                     }\r
1285                 }\r
1286                 if (c == EOF_CHAR) {\r
1287                     reportSyntaxError("msg.unterminated.comment", null);\r
1288                     return ERROR;\r
1289                 }\r
1290                 return getToken();  // `goto retry'\r
1291             }\r
1292 \r
1293             // is it a regexp?\r
1294             if ((flags & TSF_REGEXP) != 0) {\r
1295                 // We don't try to use the in.startString/in.getString\r
1296                 // approach, because escaped characters (which break it)\r
1297                 // seem likely to be common.\r
1298                 StringBuffer re = new StringBuffer();\r
1299                 while ((c = in.read()) != '/') {\r
1300                     if (c == '\n' || c == EOF_CHAR) {\r
1301                         in.unread();\r
1302                         reportSyntaxError("msg.unterminated.re.lit", null);\r
1303                         return ERROR;\r
1304                     }\r
1305                     if (c == '\\') {\r
1306                         re.append((char) c);\r
1307                         c = in.read();\r
1308                     }\r
1309 \r
1310                     re.append((char) c);\r
1311                 }\r
1312 \r
1313                 StringBuffer flagsBuf = new StringBuffer();\r
1314                 while (true) {\r
1315                     if (in.match('g'))\r
1316                         flagsBuf.append('g');\r
1317                     else if (in.match('i'))\r
1318                         flagsBuf.append('i');\r
1319                     else if (in.match('m'))\r
1320                         flagsBuf.append('m');\r
1321                     else\r
1322                         break;\r
1323                 }\r
1324 \r
1325                 if (isAlpha(in.peek())) {\r
1326                     reportSyntaxError("msg.invalid.re.flag", null);\r
1327                     return ERROR;\r
1328                 }\r
1329 \r
1330                 this.string = re.toString();\r
1331                 this.regExpFlags = flagsBuf.toString();\r
1332                 return OBJECT;\r
1333             }\r
1334 \r
1335 \r
1336             if (in.match('=')) {\r
1337                 this.op = DIV;\r
1338                 return ASSIGN;\r
1339             } else {\r
1340                 return DIV;\r
1341             }\r
1342 \r
1343         case '%':\r
1344             this.op = MOD;\r
1345             if (in.match('=')) {\r
1346                 return ASSIGN;\r
1347             } else {\r
1348                 return MOD;\r
1349             }\r
1350 \r
1351         case '~':\r
1352             this.op = BITNOT;\r
1353             return UNARYOP;\r
1354 \r
1355         case '+':\r
1356         case '-':\r
1357             if (in.match('=')) {\r
1358                 if (c == '+') {\r
1359                     this.op = ADD;\r
1360                     return ASSIGN;\r
1361                 } else {\r
1362                     this.op = SUB;\r
1363                     return ASSIGN;\r
1364                 }\r
1365             } else if (in.match((char) c)) {\r
1366                 if (c == '+') {\r
1367                     return INC;\r
1368                 } else {\r
1369                     return DEC;\r
1370                 }\r
1371             } else if (c == '-') {\r
1372                 return SUB;\r
1373             } else {\r
1374                 return ADD;\r
1375             }\r
1376 \r
1377         default:\r
1378             reportSyntaxError("msg.illegal.character", null);\r
1379             return ERROR;\r
1380         }\r
1381     }\r
1382 \r
1383     public void reportSyntaxError(String messageProperty, Object[] args) {\r
1384         String message = Context.getMessage(messageProperty, args);\r
1385         if (scope != null) {\r
1386             // We're probably in an eval. Need to throw an exception.\r
1387             throw NativeGlobal.constructError(\r
1388                             Context.getContext(), "SyntaxError",\r
1389                             message, scope, getSourceName(),\r
1390                             getLineno(), getOffset(), getLine());\r
1391         } else {\r
1392             Context.reportError(message, getSourceName(),\r
1393                                 getLineno(), getLine(), getOffset());\r
1394         }\r
1395     }\r
1396 \r
1397     public String getSourceName() { return sourceName; }\r
1398     public int getLineno() { return in.getLineno(); }\r
1399     public int getOp() { return op; }\r
1400     public String getString() { return string; }\r
1401     public Number getNumber() { return number; }\r
1402     public String getLine() { return in.getLine(); }\r
1403     public int getOffset() { return in.getOffset(); }\r
1404     public int getTokenno() { return tokenno; }\r
1405     public boolean eof() { return in.eof(); }\r
1406 \r
1407     // instance variables\r
1408     private LineBuffer in;\r
1409 \r
1410 \r
1411     /* for TSF_REGEXP, etc.\r
1412      * should this be manipulated by gettor/settor functions?\r
1413      * should it be passed to getToken();\r
1414      */\r
1415     public int flags;\r
1416     public String regExpFlags;\r
1417 \r
1418     private String sourceName;\r
1419     private String line;\r
1420     private Scriptable scope;\r
1421     private int pushbackToken;\r
1422     private int tokenno;\r
1423 \r
1424     private int op;\r
1425 \r
1426     // Set this to an inital non-null value so that the Parser has\r
1427     // something to retrieve even if an error has occured and no\r
1428     // string is found.  Fosters one class of error, but saves lots of\r
1429     // code.\r
1430     private String string = "";\r
1431     private Number number;\r
1432 }\r