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