Remove unused data member from Lexer class
[WebKit-https.git] / Source / JavaScriptCore / parser / Lexer.h
1 /*
2  *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3  *  Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
4  *  Copyright (C) 2010 Zoltan Herczeg (zherczeg@inf.u-szeged.hu)
5  *
6  *  This library is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU Library General Public
8  *  License as published by the Free Software Foundation; either
9  *  version 2 of the License, or (at your option) any later version.
10  *
11  *  This library is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  *  Library General Public License for more details.
15  *
16  *  You should have received a copy of the GNU Library General Public License
17  *  along with this library; see the file COPYING.LIB.  If not, write to
18  *  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  *  Boston, MA 02110-1301, USA.
20  *
21  */
22
23 #ifndef Lexer_h
24 #define Lexer_h
25
26 #include "Lookup.h"
27 #include "ParserArena.h"
28 #include "ParserTokens.h"
29 #include "SourceCode.h"
30 #include <wtf/ASCIICType.h>
31 #include <wtf/AlwaysInline.h>
32 #include <wtf/SegmentedVector.h>
33 #include <wtf/Vector.h>
34 #include <wtf/unicode/Unicode.h>
35
36 namespace JSC {
37
38 class Keywords {
39 public:
40     bool isKeyword(const Identifier& ident) const
41     {
42         return m_keywordTable.entry(m_globalData, ident);
43     }
44     
45     const HashEntry* getKeyword(const Identifier& ident) const
46     {
47         return m_keywordTable.entry(m_globalData, ident);
48     }
49     
50     ~Keywords()
51     {
52         m_keywordTable.deleteTable();
53     }
54     
55 private:
56     friend class JSGlobalData;
57     
58     Keywords(JSGlobalData*);
59     
60     JSGlobalData* m_globalData;
61     const HashTable m_keywordTable;
62 };
63
64 enum LexerFlags {
65     LexerFlagsIgnoreReservedWords = 1, 
66     LexerFlagsDontBuildStrings = 2,
67     LexexFlagsDontBuildKeywords = 4
68 };
69
70 class RegExp;
71
72 template <typename T>
73 class Lexer {
74     WTF_MAKE_NONCOPYABLE(Lexer);
75     WTF_MAKE_FAST_ALLOCATED;
76
77 public:
78     Lexer(JSGlobalData*);
79     ~Lexer();
80
81     // Character manipulation functions.
82     static bool isWhiteSpace(T character);
83     static bool isLineTerminator(T character);
84     static unsigned char convertHex(int c1, int c2);
85     static UChar convertUnicode(int c1, int c2, int c3, int c4);
86
87     // Functions to set up parsing.
88     void setCode(const SourceCode&, ParserArena*);
89     void setIsReparsing() { m_isReparsing = true; }
90     bool isReparsing() const { return m_isReparsing; }
91
92     JSTokenType lex(JSTokenData*, JSTokenInfo*, unsigned, bool strictMode);
93     bool nextTokenIsColon();
94     int lineNumber() const { return m_lineNumber; }
95     void setLastLineNumber(int lastLineNumber) { m_lastLineNumber = lastLineNumber; }
96     int lastLineNumber() const { return m_lastLineNumber; }
97     bool prevTerminator() const { return m_terminator; }
98     SourceCode sourceCode(int openBrace, int closeBrace, int firstLine);
99     bool scanRegExp(const Identifier*& pattern, const Identifier*& flags, UChar patternPrefix = 0);
100     bool skipRegExp();
101
102     // Functions for use after parsing.
103     bool sawError() const { return m_error; }
104     UString getErrorMessage() const { return m_lexErrorMessage; }
105     void clear();
106     void setOffset(int offset)
107     {
108         m_error = 0;
109         m_lexErrorMessage = UString();
110         m_code = m_codeStart + offset;
111         m_buffer8.resize(0);
112         m_buffer16.resize(0);
113         // Faster than an if-else sequence
114         m_current = -1;
115         if (LIKELY(m_code < m_codeEnd))
116             m_current = *m_code;
117     }
118     void setLineNumber(int line)
119     {
120         m_lineNumber = line;
121     }
122
123     SourceProvider* sourceProvider() const { return m_source->provider(); }
124
125     JSTokenType lexExpectIdentifier(JSTokenData*, JSTokenInfo*, unsigned, bool strictMode);
126
127 private:
128     void record8(int);
129     void append8(const T*, size_t);
130     void record16(int);
131     void record16(T);
132     void append16(const LChar*, size_t);
133     void append16(const UChar* characters, size_t length) { m_buffer16.append(characters, length); }
134
135     ALWAYS_INLINE void shift();
136     ALWAYS_INLINE int peek(int offset);
137     int getUnicodeCharacter();
138     void shiftLineTerminator();
139
140     UString getInvalidCharMessage();
141     ALWAYS_INLINE const T* currentCharacter() const;
142     ALWAYS_INLINE int currentOffset() const { return m_code - m_codeStart; }
143     ALWAYS_INLINE void setOffsetFromCharOffset(const T* charOffset) { setOffset(charOffset - m_codeStart); }
144
145     ALWAYS_INLINE void setCodeStart(const StringImpl*);
146
147     ALWAYS_INLINE const Identifier* makeIdentifier(const LChar* characters, size_t length);
148     ALWAYS_INLINE const Identifier* makeIdentifier(const UChar* characters, size_t length);
149     ALWAYS_INLINE const Identifier* makeIdentifierLCharFromUChar(const UChar* characters, size_t length);
150
151     ALWAYS_INLINE bool lastTokenWasRestrKeyword() const;
152
153     template <int shiftAmount> void internalShift();
154     template <bool shouldCreateIdentifier> ALWAYS_INLINE JSTokenType parseKeyword(JSTokenData*);
155     template <bool shouldBuildIdentifiers> ALWAYS_INLINE JSTokenType parseIdentifier(JSTokenData*, unsigned lexerFlags, bool strictMode);
156     template <bool shouldBuildIdentifiers> NEVER_INLINE JSTokenType parseIdentifierSlowCase(JSTokenData*, unsigned lexerFlags, bool strictMode);
157     template <bool shouldBuildStrings> ALWAYS_INLINE bool parseString(JSTokenData*, bool strictMode);
158     template <bool shouldBuildStrings> NEVER_INLINE bool parseStringSlowCase(JSTokenData*, bool strictMode);
159     ALWAYS_INLINE void parseHex(double& returnValue);
160     ALWAYS_INLINE bool parseOctal(double& returnValue);
161     ALWAYS_INLINE bool parseDecimal(double& returnValue);
162     ALWAYS_INLINE void parseNumberAfterDecimalPoint();
163     ALWAYS_INLINE bool parseNumberAfterExponentIndicator();
164     ALWAYS_INLINE bool parseMultilineComment();
165
166     static const size_t initialReadBufferCapacity = 32;
167
168     int m_lineNumber;
169     int m_lastLineNumber;
170
171     Vector<LChar> m_buffer8;
172     Vector<UChar> m_buffer16;
173     bool m_terminator;
174     int m_lastToken;
175
176     const SourceCode* m_source;
177     const T* m_code;
178     const T* m_codeStart;
179     const T* m_codeEnd;
180     bool m_isReparsing;
181     bool m_atLineStart;
182     bool m_error;
183     UString m_lexErrorMessage;
184
185     // current and following unicode characters (int to allow for -1 for end-of-file marker)
186     int m_current;
187
188     IdentifierArena* m_arena;
189
190     JSGlobalData* m_globalData;
191 };
192
193 template <>
194 ALWAYS_INLINE bool Lexer<LChar>::isWhiteSpace(LChar ch)
195 {
196     return ch == ' ' || ch == '\t' || ch == 0xB || ch == 0xC || ch == 0xA0;
197 }
198
199 template <>
200 ALWAYS_INLINE bool Lexer<UChar>::isWhiteSpace(UChar ch)
201 {
202     return (ch < 256) ? Lexer<LChar>::isWhiteSpace(static_cast<LChar>(ch)) : (WTF::Unicode::isSeparatorSpace(ch) || ch == 0xFEFF);
203 }
204
205 template <>
206 ALWAYS_INLINE bool Lexer<LChar>::isLineTerminator(LChar ch)
207 {
208     return ch == '\r' || ch == '\n';
209 }
210
211 template <>
212 ALWAYS_INLINE bool Lexer<UChar>::isLineTerminator(UChar ch)
213 {
214     return ch == '\r' || ch == '\n' || (ch & ~1) == 0x2028;
215 }
216
217 template <typename T>
218 inline unsigned char Lexer<T>::convertHex(int c1, int c2)
219 {
220     return (toASCIIHexValue(c1) << 4) | toASCIIHexValue(c2);
221 }
222
223 template <typename T>
224 inline UChar Lexer<T>::convertUnicode(int c1, int c2, int c3, int c4)
225 {
226     return (convertHex(c1, c2) << 8) | convertHex(c3, c4);
227 }
228
229 template <typename T>
230 ALWAYS_INLINE const Identifier* Lexer<T>::makeIdentifier(const LChar* characters, size_t length)
231 {
232     return &m_arena->makeIdentifier(m_globalData, characters, length);
233 }
234
235 template <typename T>
236 ALWAYS_INLINE const Identifier* Lexer<T>::makeIdentifier(const UChar* characters, size_t length)
237 {
238     return &m_arena->makeIdentifier(m_globalData, characters, length);
239 }
240
241 template <>
242 ALWAYS_INLINE void Lexer<LChar>::setCodeStart(const StringImpl* sourceString)
243 {
244     ASSERT(sourceString->is8Bit());
245     m_codeStart = sourceString->characters8();
246 }
247
248 template <>
249 ALWAYS_INLINE void Lexer<UChar>::setCodeStart(const StringImpl* sourceString)
250 {
251     ASSERT(!sourceString->is8Bit());
252     m_codeStart = sourceString->characters16();
253 }
254
255 template <typename T>
256 ALWAYS_INLINE const Identifier* Lexer<T>::makeIdentifierLCharFromUChar(const UChar* characters, size_t length)
257 {
258     return &m_arena->makeIdentifierLCharFromUChar(m_globalData, characters, length);
259 }
260
261 template <typename T>
262 ALWAYS_INLINE JSTokenType Lexer<T>::lexExpectIdentifier(JSTokenData* tokenData, JSTokenInfo* tokenInfo, unsigned lexerFlags, bool strictMode)
263 {
264     ASSERT((lexerFlags & LexerFlagsIgnoreReservedWords));
265     const T* start = m_code;
266     const T* ptr = start;
267     const T* end = m_codeEnd;
268     if (ptr >= end) {
269         ASSERT(ptr == end);
270         goto slowCase;
271     }
272     if (!WTF::isASCIIAlpha(*ptr))
273         goto slowCase;
274     ++ptr;
275     while (ptr < end) {
276         if (!WTF::isASCIIAlphanumeric(*ptr))
277             break;
278         ++ptr;
279     }
280
281     // Here's the shift
282     if (ptr < end) {
283         if ((!WTF::isASCII(*ptr)) || (*ptr == '\\') || (*ptr == '_') || (*ptr == '$'))
284             goto slowCase;
285         m_current = *ptr;
286     } else
287         m_current = -1;
288
289     m_code = ptr;
290
291     // Create the identifier if needed
292     if (lexerFlags & LexexFlagsDontBuildKeywords)
293         tokenData->ident = 0;
294     else
295         tokenData->ident = makeIdentifier(start, ptr - start);
296     tokenInfo->line = m_lineNumber;
297     tokenInfo->startOffset = start - m_codeStart;
298     tokenInfo->endOffset = currentOffset();
299     m_lastToken = IDENT;
300     return IDENT;
301     
302 slowCase:
303     return lex(tokenData, tokenInfo, lexerFlags, strictMode);
304 }
305
306 } // namespace JSC
307
308 #endif // Lexer_h