[CMake] Enable USE_FOLDERS property
[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     bool m_delimited; // encountered delimiter like "'" and "}" on last run
175     int m_lastToken;
176
177     const SourceCode* m_source;
178     const T* m_code;
179     const T* m_codeStart;
180     const T* m_codeEnd;
181     bool m_isReparsing;
182     bool m_atLineStart;
183     bool m_error;
184     UString m_lexErrorMessage;
185
186     // current and following unicode characters (int to allow for -1 for end-of-file marker)
187     int m_current;
188
189     IdentifierArena* m_arena;
190
191     JSGlobalData* m_globalData;
192 };
193
194 template <>
195 ALWAYS_INLINE bool Lexer<LChar>::isWhiteSpace(LChar ch)
196 {
197     return ch == ' ' || ch == '\t' || ch == 0xB || ch == 0xC || ch == 0xA0;
198 }
199
200 template <>
201 ALWAYS_INLINE bool Lexer<UChar>::isWhiteSpace(UChar ch)
202 {
203     return (ch < 256) ? Lexer<LChar>::isWhiteSpace(static_cast<LChar>(ch)) : (WTF::Unicode::isSeparatorSpace(ch) || ch == 0xFEFF);
204 }
205
206 template <>
207 ALWAYS_INLINE bool Lexer<LChar>::isLineTerminator(LChar ch)
208 {
209     return ch == '\r' || ch == '\n';
210 }
211
212 template <>
213 ALWAYS_INLINE bool Lexer<UChar>::isLineTerminator(UChar ch)
214 {
215     return ch == '\r' || ch == '\n' || (ch & ~1) == 0x2028;
216 }
217
218 template <typename T>
219 inline unsigned char Lexer<T>::convertHex(int c1, int c2)
220 {
221     return (toASCIIHexValue(c1) << 4) | toASCIIHexValue(c2);
222 }
223
224 template <typename T>
225 inline UChar Lexer<T>::convertUnicode(int c1, int c2, int c3, int c4)
226 {
227     return (convertHex(c1, c2) << 8) | convertHex(c3, c4);
228 }
229
230 template <typename T>
231 ALWAYS_INLINE const Identifier* Lexer<T>::makeIdentifier(const LChar* characters, size_t length)
232 {
233     return &m_arena->makeIdentifier(m_globalData, characters, length);
234 }
235
236 template <typename T>
237 ALWAYS_INLINE const Identifier* Lexer<T>::makeIdentifier(const UChar* characters, size_t length)
238 {
239     return &m_arena->makeIdentifier(m_globalData, characters, length);
240 }
241
242 template <>
243 ALWAYS_INLINE void Lexer<LChar>::setCodeStart(const StringImpl* sourceString)
244 {
245     ASSERT(sourceString->is8Bit());
246     m_codeStart = sourceString->characters8();
247 }
248
249 template <>
250 ALWAYS_INLINE void Lexer<UChar>::setCodeStart(const StringImpl* sourceString)
251 {
252     ASSERT(!sourceString->is8Bit());
253     m_codeStart = sourceString->characters16();
254 }
255
256 template <typename T>
257 ALWAYS_INLINE const Identifier* Lexer<T>::makeIdentifierLCharFromUChar(const UChar* characters, size_t length)
258 {
259     return &m_arena->makeIdentifierLCharFromUChar(m_globalData, characters, length);
260 }
261
262 template <typename T>
263 ALWAYS_INLINE JSTokenType Lexer<T>::lexExpectIdentifier(JSTokenData* tokenData, JSTokenInfo* tokenInfo, unsigned lexerFlags, bool strictMode)
264 {
265     ASSERT((lexerFlags & LexerFlagsIgnoreReservedWords));
266     const T* start = m_code;
267     const T* ptr = start;
268     const T* end = m_codeEnd;
269     if (ptr >= end) {
270         ASSERT(ptr == end);
271         goto slowCase;
272     }
273     if (!WTF::isASCIIAlpha(*ptr))
274         goto slowCase;
275     ++ptr;
276     while (ptr < end) {
277         if (!WTF::isASCIIAlphanumeric(*ptr))
278             break;
279         ++ptr;
280     }
281
282     // Here's the shift
283     if (ptr < end) {
284         if ((!WTF::isASCII(*ptr)) || (*ptr == '\\') || (*ptr == '_') || (*ptr == '$'))
285             goto slowCase;
286         m_current = *ptr;
287     } else
288         m_current = -1;
289
290     m_code = ptr;
291
292     // Create the identifier if needed
293     if (lexerFlags & LexexFlagsDontBuildKeywords)
294         tokenData->ident = 0;
295     else
296         tokenData->ident = makeIdentifier(start, ptr - start);
297     tokenInfo->line = m_lineNumber;
298     tokenInfo->startOffset = start - m_codeStart;
299     tokenInfo->endOffset = currentOffset();
300     m_lastToken = IDENT;
301     return IDENT;
302     
303 slowCase:
304     return lex(tokenData, tokenInfo, lexerFlags, strictMode);
305 }
306
307 } // namespace JSC
308
309 #endif // Lexer_h