Reviewed by Eric Seidel.
[WebKit-https.git] / JavaScriptCore / kjs / lexer.cpp
1 // -*- c-basic-offset: 2 -*-
2 /*
3  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
4  *  Copyright (C) 2006, 2007 Apple Inc. All Rights Reserved.
5  *  Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
6  *
7  *  This library is free software; you can redistribute it and/or
8  *  modify it under the terms of the GNU Library General Public
9  *  License as published by the Free Software Foundation; either
10  *  version 2 of the License, or (at your option) any later version.
11  *
12  *  This library is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  *  Library General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Library General Public License
18  *  along with this library; see the file COPYING.LIB.  If not, write to
19  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  *  Boston, MA 02110-1301, USA.
21  *
22  */
23
24 #include "config.h"
25 #include "lexer.h"
26
27 #include "function.h"
28 #include "interpreter.h"
29 #include "nodes.h"
30 #include <ctype.h>
31 #include <limits.h>
32 #include <string.h>
33 #include <wtf/Assertions.h>
34 #include <wtf/unicode/Unicode.h>
35
36 using namespace WTF;
37 using namespace Unicode;
38
39 // we can't specify the namespace in yacc's C output, so do it here
40 using namespace KJS;
41
42 #ifndef KDE_USE_FINAL
43 #include "grammar.h"
44 #endif
45
46 #include "lookup.h"
47 #include "lexer.lut.h"
48
49 extern YYLTYPE kjsyylloc; // global bison variable holding token info
50
51 // a bridge for yacc from the C world to C++
52 int kjsyylex()
53 {
54   return lexer().lex();
55 }
56
57 namespace KJS {
58
59 static bool isDecimalDigit(int);
60
61 Lexer& lexer()
62 {
63     ASSERT(JSLock::currentThreadIsHoldingLock());
64
65     // FIXME: We'd like to avoid calling new here, but we don't currently 
66     // support tearing down the Lexer at app quit time, since that would involve
67     // tearing down its UString data members without holding the JSLock.
68     static Lexer* staticLexer = new Lexer;
69     return *staticLexer;
70 }
71
72 Lexer::Lexer()
73   : yylineno(1),
74     size8(128), size16(128), restrKeyword(false),
75     eatNextIdentifier(false), stackToken(-1), lastToken(-1), pos(0),
76     code(0), length(0),
77 #ifndef KJS_PURE_ECMA
78     bol(true),
79 #endif
80     current(0), next1(0), next2(0), next3(0),
81     strings(0), numStrings(0), stringsCapacity(0),
82     identifiers(0), numIdentifiers(0), identifiersCapacity(0)
83 {
84   // allocate space for read buffers
85   buffer8 = new char[size8];
86   buffer16 = new KJS::UChar[size16];
87 }
88
89 Lexer::~Lexer()
90 {
91   delete [] buffer8;
92   delete [] buffer16;
93 }
94
95 void Lexer::setCode(const UString &sourceURL, int startingLineNumber, const KJS::UChar *c, unsigned int len)
96 {
97   yylineno = 1 + startingLineNumber;
98   m_sourceURL = sourceURL;
99   restrKeyword = false;
100   delimited = false;
101   eatNextIdentifier = false;
102   stackToken = -1;
103   lastToken = -1;
104   pos = 0;
105   code = c;
106   length = len;
107   skipLF = false;
108   skipCR = false;
109   error = false;
110 #ifndef KJS_PURE_ECMA
111   bol = true;
112 #endif
113
114   // read first characters
115   current = (length > 0) ? code[0].uc : -1;
116   next1 = (length > 1) ? code[1].uc : -1;
117   next2 = (length > 2) ? code[2].uc : -1;
118   next3 = (length > 3) ? code[3].uc : -1;
119 }
120
121 void Lexer::shift(unsigned int p)
122 {
123   // Here would be a good place to strip Cf characters, but that has caused compatibility problems:
124   // <http://bugs.webkit.org/show_bug.cgi?id=10183>.
125   while (p--) {
126     pos++;
127     current = next1;
128     next1 = next2;
129     next2 = next3;
130     next3 = (pos + 3 < length) ? code[pos + 3].uc : -1;
131   }
132 }
133
134 // called on each new line
135 void Lexer::nextLine()
136 {
137   yylineno++;
138 #ifndef KJS_PURE_ECMA
139   bol = true;
140 #endif
141 }
142
143 void Lexer::setDone(State s)
144 {
145   state = s;
146   done = true;
147 }
148
149 int Lexer::lex()
150 {
151   int token = 0;
152   state = Start;
153   unsigned short stringType = 0; // either single or double quotes
154   pos8 = pos16 = 0;
155   done = false;
156   terminator = false;
157   skipLF = false;
158   skipCR = false;
159
160   // did we push a token on the stack previously ?
161   // (after an automatic semicolon insertion)
162   if (stackToken >= 0) {
163     setDone(Other);
164     token = stackToken;
165     stackToken = 0;
166   }
167
168   while (!done) {
169     if (skipLF && current != '\n') // found \r but not \n afterwards
170         skipLF = false;
171     if (skipCR && current != '\r') // found \n but not \r afterwards
172         skipCR = false;
173     if (skipLF || skipCR) // found \r\n or \n\r -> eat the second one
174     {
175         skipLF = false;
176         skipCR = false;
177         shift(1);
178     }
179     switch (state) {
180     case Start:
181       if (isWhiteSpace()) {
182         // do nothing
183       } else if (current == '/' && next1 == '/') {
184         shift(1);
185         state = InSingleLineComment;
186       } else if (current == '/' && next1 == '*') {
187         shift(1);
188         state = InMultiLineComment;
189       } else if (current == -1) {
190         if (!terminator && !delimited) {
191           // automatic semicolon insertion if program incomplete
192           token = ';';
193           stackToken = 0;
194           setDone(Other);
195         } else
196           setDone(Eof);
197       } else if (isLineTerminator()) {
198         nextLine();
199         terminator = true;
200         if (restrKeyword) {
201           token = ';';
202           setDone(Other);
203         }
204       } else if (current == '"' || current == '\'') {
205         state = InString;
206         stringType = static_cast<unsigned short>(current);
207       } else if (isIdentStart(current)) {
208         record16(current);
209         state = InIdentifierOrKeyword;
210       } else if (current == '\\') {
211         state = InIdentifierUnicodeEscapeStart;
212       } else if (current == '0') {
213         record8(current);
214         state = InNum0;
215       } else if (isDecimalDigit(current)) {
216         record8(current);
217         state = InNum;
218       } else if (current == '.' && isDecimalDigit(next1)) {
219         record8(current);
220         state = InDecimal;
221 #ifndef KJS_PURE_ECMA
222         // <!-- marks the beginning of a line comment (for www usage)
223       } else if (current == '<' && next1 == '!' &&
224                  next2 == '-' && next3 == '-') {
225         shift(3);
226         state = InSingleLineComment;
227         // same for -->
228       } else if (bol && current == '-' && next1 == '-' &&  next2 == '>') {
229         shift(2);
230         state = InSingleLineComment;
231 #endif
232       } else {
233         token = matchPunctuator(current, next1, next2, next3);
234         if (token != -1) {
235           setDone(Other);
236         } else {
237           //      cerr << "encountered unknown character" << endl;
238           setDone(Bad);
239         }
240       }
241       break;
242     case InString:
243       if (current == stringType) {
244         shift(1);
245         setDone(String);
246       } else if (isLineTerminator() || current == -1) {
247         setDone(Bad);
248       } else if (current == '\\') {
249         state = InEscapeSequence;
250       } else {
251         record16(current);
252       }
253       break;
254     // Escape Sequences inside of strings
255     case InEscapeSequence:
256       if (isOctalDigit(current)) {
257         if (current >= '0' && current <= '3' &&
258             isOctalDigit(next1) && isOctalDigit(next2)) {
259           record16(convertOctal(current, next1, next2));
260           shift(2);
261           state = InString;
262         } else if (isOctalDigit(current) && isOctalDigit(next1)) {
263           record16(convertOctal('0', current, next1));
264           shift(1);
265           state = InString;
266         } else if (isOctalDigit(current)) {
267           record16(convertOctal('0', '0', current));
268           state = InString;
269         } else {
270           setDone(Bad);
271         }
272       } else if (current == 'x')
273         state = InHexEscape;
274       else if (current == 'u')
275         state = InUnicodeEscape;
276       else if (isLineTerminator()) {
277         nextLine();
278         state = InString;
279       } else {
280         record16(singleEscape(static_cast<unsigned short>(current)));
281         state = InString;
282       }
283       break;
284     case InHexEscape:
285       if (isHexDigit(current) && isHexDigit(next1)) {
286         state = InString;
287         record16(convertHex(current, next1));
288         shift(1);
289       } else if (current == stringType) {
290         record16('x');
291         shift(1);
292         setDone(String);
293       } else {
294         record16('x');
295         record16(current);
296         state = InString;
297       }
298       break;
299     case InUnicodeEscape:
300       if (isHexDigit(current) && isHexDigit(next1) && isHexDigit(next2) && isHexDigit(next3)) {
301         record16(convertUnicode(current, next1, next2, next3));
302         shift(3);
303         state = InString;
304       } else if (current == stringType) {
305         record16('u');
306         shift(1);
307         setDone(String);
308       } else {
309         setDone(Bad);
310       }
311       break;
312     case InSingleLineComment:
313       if (isLineTerminator()) {
314         nextLine();
315         terminator = true;
316         if (restrKeyword) {
317           token = ';';
318           setDone(Other);
319         } else
320           state = Start;
321       } else if (current == -1) {
322         setDone(Eof);
323       }
324       break;
325     case InMultiLineComment:
326       if (current == -1) {
327         setDone(Bad);
328       } else if (isLineTerminator()) {
329         nextLine();
330       } else if (current == '*' && next1 == '/') {
331         state = Start;
332         shift(1);
333       }
334       break;
335     case InIdentifierOrKeyword:
336     case InIdentifier:
337       if (isIdentPart(current))
338         record16(current);
339       else if (current == '\\')
340         state = InIdentifierUnicodeEscapeStart;
341       else
342         setDone(state == InIdentifierOrKeyword ? IdentifierOrKeyword : Identifier);
343       break;
344     case InNum0:
345       if (current == 'x' || current == 'X') {
346         record8(current);
347         state = InHex;
348       } else if (current == '.') {
349         record8(current);
350         state = InDecimal;
351       } else if (current == 'e' || current == 'E') {
352         record8(current);
353         state = InExponentIndicator;
354       } else if (isOctalDigit(current)) {
355         record8(current);
356         state = InOctal;
357       } else if (isDecimalDigit(current)) {
358         record8(current);
359         state = InDecimal;
360       } else {
361         setDone(Number);
362       }
363       break;
364     case InHex:
365       if (isHexDigit(current)) {
366         record8(current);
367       } else {
368         setDone(Hex);
369       }
370       break;
371     case InOctal:
372       if (isOctalDigit(current)) {
373         record8(current);
374       }
375       else if (isDecimalDigit(current)) {
376         record8(current);
377         state = InDecimal;
378       } else
379         setDone(Octal);
380       break;
381     case InNum:
382       if (isDecimalDigit(current)) {
383         record8(current);
384       } else if (current == '.') {
385         record8(current);
386         state = InDecimal;
387       } else if (current == 'e' || current == 'E') {
388         record8(current);
389         state = InExponentIndicator;
390       } else
391         setDone(Number);
392       break;
393     case InDecimal:
394       if (isDecimalDigit(current)) {
395         record8(current);
396       } else if (current == 'e' || current == 'E') {
397         record8(current);
398         state = InExponentIndicator;
399       } else
400         setDone(Number);
401       break;
402     case InExponentIndicator:
403       if (current == '+' || current == '-') {
404         record8(current);
405       } else if (isDecimalDigit(current)) {
406         record8(current);
407         state = InExponent;
408       } else
409         setDone(Bad);
410       break;
411     case InExponent:
412       if (isDecimalDigit(current)) {
413         record8(current);
414       } else
415         setDone(Number);
416       break;
417     case InIdentifierUnicodeEscapeStart:
418       if (current == 'u')
419         state = InIdentifierUnicodeEscape;
420       else
421         setDone(Bad);
422       break;
423     case InIdentifierUnicodeEscape:
424       if (isHexDigit(current) && isHexDigit(next1) && isHexDigit(next2) && isHexDigit(next3)) {
425         record16(convertUnicode(current, next1, next2, next3));
426         shift(3);
427         state = InIdentifier;
428       } else {
429         setDone(Bad);
430       }
431       break;
432     default:
433       ASSERT(!"Unhandled state in switch statement");
434     }
435
436     // move on to the next character
437     if (!done)
438       shift(1);
439 #ifndef KJS_PURE_ECMA
440     if (state != Start && state != InSingleLineComment)
441       bol = false;
442 #endif
443   }
444
445   // no identifiers allowed directly after numeric literal, e.g. "3in" is bad
446   if ((state == Number || state == Octal || state == Hex) && isIdentStart(current))
447     state = Bad;
448
449   // terminate string
450   buffer8[pos8] = '\0';
451
452 #ifdef KJS_DEBUG_LEX
453   fprintf(stderr, "line: %d ", lineNo());
454   fprintf(stderr, "yytext (%x): ", buffer8[0]);
455   fprintf(stderr, "%s ", buffer8);
456 #endif
457
458   double dval = 0;
459   if (state == Number) {
460     dval = strtod(buffer8, 0L);
461   } else if (state == Hex) { // scan hex numbers
462     const char *p = buffer8 + 2;
463     while (char c = *p++) {
464       dval *= 16;
465       dval += convertHex(c);
466     }
467
468     if (dval >= mantissaOverflowLowerBound)
469       dval = parseIntOverflow(buffer8 + 2, p - (buffer8 + 3), 16);
470
471     state = Number;
472   } else if (state == Octal) {   // scan octal number
473     const char *p = buffer8 + 1;
474     while (char c = *p++) {
475       dval *= 8;
476       dval += c - '0';
477     }
478
479     if (dval >= mantissaOverflowLowerBound)
480       dval = parseIntOverflow(buffer8 + 1, p - (buffer8 + 2), 8);
481
482     state = Number;
483   }
484
485 #ifdef KJS_DEBUG_LEX
486   switch (state) {
487   case Eof:
488     printf("(EOF)\n");
489     break;
490   case Other:
491     printf("(Other)\n");
492     break;
493   case Identifier:
494     printf("(Identifier)/(Keyword)\n");
495     break;
496   case String:
497     printf("(String)\n");
498     break;
499   case Number:
500     printf("(Number)\n");
501     break;
502   default:
503     printf("(unknown)");
504   }
505 #endif
506
507   if (state != Identifier && eatNextIdentifier)
508     eatNextIdentifier = false;
509
510   restrKeyword = false;
511   delimited = false;
512   kjsyylloc.first_line = yylineno; // ???
513   kjsyylloc.last_line = yylineno;
514
515   switch (state) {
516   case Eof:
517     token = 0;
518     break;
519   case Other:
520     if(token == '}' || token == ';') {
521       delimited = true;
522     }
523     break;
524   case IdentifierOrKeyword:
525     if ((token = Lookup::find(&mainTable, buffer16, pos16)) < 0) {
526   case Identifier:
527       // Lookup for keyword failed, means this is an identifier
528       // Apply anonymous-function hack below (eat the identifier)
529       if (eatNextIdentifier) {
530         eatNextIdentifier = false;
531         token = lex();
532         break;
533       }
534       kjsyylval.ident = makeIdentifier(buffer16, pos16);
535       token = IDENT;
536       break;
537     }
538
539     eatNextIdentifier = false;
540     // Hack for "f = function somename() { ... }", too hard to get into the grammar
541     if (token == FUNCTION && lastToken == '=' )
542       eatNextIdentifier = true;
543
544     if (token == CONTINUE || token == BREAK ||
545         token == RETURN || token == THROW)
546       restrKeyword = true;
547     break;
548   case String:
549     kjsyylval.string = makeUString(buffer16, pos16);
550     token = STRING;
551     break;
552   case Number:
553     kjsyylval.doubleValue = dval;
554     token = NUMBER;
555     break;
556   case Bad:
557 #ifdef KJS_DEBUG_LEX
558     fprintf(stderr, "yylex: ERROR.\n");
559 #endif
560     error = true;
561     return -1;
562   default:
563     ASSERT(!"unhandled numeration value in switch");
564     error = true;
565     return -1;
566   }
567   lastToken = token;
568   return token;
569 }
570
571 bool Lexer::isWhiteSpace() const
572 {
573   return current == '\t' || current == 0x0b || current == 0x0c || isSeparatorSpace(current);
574 }
575
576 bool Lexer::isLineTerminator()
577 {
578   bool cr = (current == '\r');
579   bool lf = (current == '\n');
580   if (cr)
581       skipLF = true;
582   else if (lf)
583       skipCR = true;
584   return cr || lf || current == 0x2028 || current == 0x2029;
585 }
586
587 bool Lexer::isIdentStart(int c)
588 {
589   return (category(c) & (Letter_Uppercase | Letter_Lowercase | Letter_Titlecase | Letter_Modifier | Letter_Other))
590     || c == '$' || c == '_';
591 }
592
593 bool Lexer::isIdentPart(int c)
594 {
595   return (category(c) & (Letter_Uppercase | Letter_Lowercase | Letter_Titlecase | Letter_Modifier | Letter_Other
596         | Mark_NonSpacing | Mark_SpacingCombining | Number_DecimalDigit | Punctuation_Connector))
597     || c == '$' || c == '_';
598 }
599
600 static bool isDecimalDigit(int c)
601 {
602   return (c >= '0' && c <= '9');
603 }
604
605 bool Lexer::isHexDigit(int c)
606 {
607   return (c >= '0' && c <= '9' ||
608           c >= 'a' && c <= 'f' ||
609           c >= 'A' && c <= 'F');
610 }
611
612 bool Lexer::isOctalDigit(int c)
613 {
614   return (c >= '0' && c <= '7');
615 }
616
617 int Lexer::matchPunctuator(int c1, int c2, int c3, int c4)
618 {
619   if (c1 == '>' && c2 == '>' && c3 == '>' && c4 == '=') {
620     shift(4);
621     return URSHIFTEQUAL;
622   } else if (c1 == '=' && c2 == '=' && c3 == '=') {
623     shift(3);
624     return STREQ;
625   } else if (c1 == '!' && c2 == '=' && c3 == '=') {
626     shift(3);
627     return STRNEQ;
628    } else if (c1 == '>' && c2 == '>' && c3 == '>') {
629     shift(3);
630     return URSHIFT;
631   } else if (c1 == '<' && c2 == '<' && c3 == '=') {
632     shift(3);
633     return LSHIFTEQUAL;
634   } else if (c1 == '>' && c2 == '>' && c3 == '=') {
635     shift(3);
636     return RSHIFTEQUAL;
637   } else if (c1 == '<' && c2 == '=') {
638     shift(2);
639     return LE;
640   } else if (c1 == '>' && c2 == '=') {
641     shift(2);
642     return GE;
643   } else if (c1 == '!' && c2 == '=') {
644     shift(2);
645     return NE;
646   } else if (c1 == '+' && c2 == '+') {
647     shift(2);
648     if (terminator)
649       return AUTOPLUSPLUS;
650     else
651       return PLUSPLUS;
652   } else if (c1 == '-' && c2 == '-') {
653     shift(2);
654     if (terminator)
655       return AUTOMINUSMINUS;
656     else
657       return MINUSMINUS;
658   } else if (c1 == '=' && c2 == '=') {
659     shift(2);
660     return EQEQ;
661   } else if (c1 == '+' && c2 == '=') {
662     shift(2);
663     return PLUSEQUAL;
664   } else if (c1 == '-' && c2 == '=') {
665     shift(2);
666     return MINUSEQUAL;
667   } else if (c1 == '*' && c2 == '=') {
668     shift(2);
669     return MULTEQUAL;
670   } else if (c1 == '/' && c2 == '=') {
671     shift(2);
672     return DIVEQUAL;
673   } else if (c1 == '&' && c2 == '=') {
674     shift(2);
675     return ANDEQUAL;
676   } else if (c1 == '^' && c2 == '=') {
677     shift(2);
678     return XOREQUAL;
679   } else if (c1 == '%' && c2 == '=') {
680     shift(2);
681     return MODEQUAL;
682   } else if (c1 == '|' && c2 == '=') {
683     shift(2);
684     return OREQUAL;
685   } else if (c1 == '<' && c2 == '<') {
686     shift(2);
687     return LSHIFT;
688   } else if (c1 == '>' && c2 == '>') {
689     shift(2);
690     return RSHIFT;
691   } else if (c1 == '&' && c2 == '&') {
692     shift(2);
693     return AND;
694   } else if (c1 == '|' && c2 == '|') {
695     shift(2);
696     return OR;
697   }
698
699   switch(c1) {
700     case '=':
701     case '>':
702     case '<':
703     case ',':
704     case '!':
705     case '~':
706     case '?':
707     case ':':
708     case '.':
709     case '+':
710     case '-':
711     case '*':
712     case '/':
713     case '&':
714     case '|':
715     case '^':
716     case '%':
717     case '(':
718     case ')':
719     case '{':
720     case '}':
721     case '[':
722     case ']':
723     case ';':
724       shift(1);
725       return static_cast<int>(c1);
726     default:
727       return -1;
728   }
729 }
730
731 unsigned short Lexer::singleEscape(unsigned short c)
732 {
733   switch(c) {
734   case 'b':
735     return 0x08;
736   case 't':
737     return 0x09;
738   case 'n':
739     return 0x0A;
740   case 'v':
741     return 0x0B;
742   case 'f':
743     return 0x0C;
744   case 'r':
745     return 0x0D;
746   case '"':
747     return 0x22;
748   case '\'':
749     return 0x27;
750   case '\\':
751     return 0x5C;
752   default:
753     return c;
754   }
755 }
756
757 unsigned short Lexer::convertOctal(int c1, int c2, int c3)
758 {
759   return static_cast<unsigned short>((c1 - '0') * 64 + (c2 - '0') * 8 + c3 - '0');
760 }
761
762 unsigned char Lexer::convertHex(int c)
763 {
764   if (c >= '0' && c <= '9')
765     return static_cast<unsigned char>(c - '0');
766   if (c >= 'a' && c <= 'f')
767     return static_cast<unsigned char>(c - 'a' + 10);
768   return static_cast<unsigned char>(c - 'A' + 10);
769 }
770
771 unsigned char Lexer::convertHex(int c1, int c2)
772 {
773   return ((convertHex(c1) << 4) + convertHex(c2));
774 }
775
776 KJS::UChar Lexer::convertUnicode(int c1, int c2, int c3, int c4)
777 {
778   // FIXME: This conversion is lossy. See http://bugs.webkit.org/show_bug.cgi?id=4920.
779   return KJS::UChar((convertHex(c1) << 4) + convertHex(c2),
780                (convertHex(c3) << 4) + convertHex(c4));
781 }
782
783 void Lexer::record8(int c)
784 {
785   ASSERT(c >= 0);
786   ASSERT(c <= 0xff);
787
788   // enlarge buffer if full
789   if (pos8 >= size8 - 1) {
790     char *tmp = new char[2 * size8];
791     memcpy(tmp, buffer8, size8 * sizeof(char));
792     delete [] buffer8;
793     buffer8 = tmp;
794     size8 *= 2;
795   }
796
797   buffer8[pos8++] = (char) c;
798 }
799
800 void Lexer::record16(int c)
801 {
802   ASSERT(c >= 0);
803   ASSERT(c <= USHRT_MAX);
804   record16(UChar(static_cast<unsigned short>(c)));
805 }
806
807 void Lexer::record16(KJS::UChar c)
808 {
809   // enlarge buffer if full
810   if (pos16 >= size16 - 1) {
811     KJS::UChar *tmp = new KJS::UChar[2 * size16];
812     memcpy(tmp, buffer16, size16 * sizeof(KJS::UChar));
813     delete [] buffer16;
814     buffer16 = tmp;
815     size16 *= 2;
816   }
817
818   buffer16[pos16++] = c;
819 }
820
821 bool Lexer::scanRegExp()
822 {
823   pos16 = 0;
824   bool lastWasEscape = false;
825   bool inBrackets = false;
826
827   while (1) {
828     if (isLineTerminator() || current == -1)
829       return false;
830     else if (current != '/' || lastWasEscape == true || inBrackets == true)
831     {
832         // keep track of '[' and ']'
833         if (!lastWasEscape) {
834           if ( current == '[' && !inBrackets )
835             inBrackets = true;
836           if ( current == ']' && inBrackets )
837             inBrackets = false;
838         }
839         record16(current);
840         lastWasEscape =
841             !lastWasEscape && (current == '\\');
842     }
843     else { // end of regexp
844       m_pattern = UString(buffer16, pos16);
845       pos16 = 0;
846       shift(1);
847       break;
848     }
849     shift(1);
850   }
851
852   while (isIdentPart(current)) {
853     record16(current);
854     shift(1);
855   }
856   m_flags = UString(buffer16, pos16);
857
858   return true;
859 }
860
861 void Lexer::clear()
862 {
863   for (unsigned i = 0; i < numIdentifiers; i++)
864     delete identifiers[i];
865   fastFree(identifiers);
866   identifiers = 0;
867   numIdentifiers = 0;
868   identifiersCapacity = 0;
869
870   for (unsigned i = 0; i < numStrings; i++)
871     delete strings[i];
872   fastFree(strings);
873   strings = 0;
874   numStrings = 0;
875   stringsCapacity = 0;
876   
877   m_pattern = 0;
878   m_flags = 0;
879   m_sourceURL = 0;
880 }
881
882 const int initialCapacity = 64;
883 const int growthFactor = 2;
884
885 Identifier* Lexer::makeIdentifier(KJS::UChar* buffer, unsigned int pos)
886 {
887   if (numIdentifiers == identifiersCapacity) {
888     identifiersCapacity = (identifiersCapacity == 0) ? initialCapacity : identifiersCapacity *growthFactor;
889     identifiers = (KJS::Identifier **)fastRealloc(identifiers, sizeof(KJS::Identifier *) * identifiersCapacity);
890   }
891
892   KJS::Identifier *identifier = new KJS::Identifier(buffer, pos);
893   identifiers[numIdentifiers++] = identifier;
894   return identifier;
895 }
896  
897 UString* Lexer::makeUString(KJS::UChar* buffer, unsigned int pos)
898 {
899   if (numStrings == stringsCapacity) {
900     stringsCapacity = (stringsCapacity == 0) ? initialCapacity : stringsCapacity *growthFactor;
901     strings = (UString **)fastRealloc(strings, sizeof(UString *) * stringsCapacity);
902   }
903
904   UString *string = new UString(buffer, pos);
905   strings[numStrings++] = string;
906   return string;
907 }
908
909 } // namespace KJS