Rewrite Function.bind as a builtin
[WebKit.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, 2011, 2012, 2013 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/SegmentedVector.h>
32 #include <wtf/Vector.h>
33
34 namespace JSC {
35
36 class Keywords {
37 public:
38     bool isKeyword(const Identifier& ident) const
39     {
40         return m_keywordTable.entry(m_vm, ident);
41     }
42     
43     const HashTableValue* getKeyword(const Identifier& ident) const
44     {
45         return m_keywordTable.entry(m_vm, ident);
46     }
47     
48     ~Keywords()
49     {
50         m_keywordTable.deleteTable();
51     }
52     
53 private:
54     friend class VM;
55     
56     explicit Keywords(VM&);
57     
58     VM& m_vm;
59     const HashTable m_keywordTable;
60 };
61
62 enum LexerFlags {
63     LexerFlagsIgnoreReservedWords = 1, 
64     LexerFlagsDontBuildStrings = 2,
65     LexexFlagsDontBuildKeywords = 4
66 };
67
68 template <typename T>
69 class Lexer {
70     WTF_MAKE_NONCOPYABLE(Lexer);
71     WTF_MAKE_FAST_ALLOCATED;
72
73 public:
74     Lexer(VM*, JSParserStrictness, JSFunctionKind);
75     ~Lexer();
76
77     // Character manipulation functions.
78     static bool isWhiteSpace(T character);
79     static bool isLineTerminator(T character);
80     static unsigned char convertHex(int c1, int c2);
81     static UChar convertUnicode(int c1, int c2, int c3, int c4);
82
83     // Functions to set up parsing.
84     void setCode(const SourceCode&, ParserArena*);
85     void setIsReparsing() { m_isReparsing = true; }
86     bool isReparsing() const { return m_isReparsing; }
87
88     JSTokenType lex(JSToken*, unsigned, bool strictMode);
89     bool nextTokenIsColon();
90     int lineNumber() const { return m_lineNumber; }
91     ALWAYS_INLINE int currentOffset() const { return offsetFromSourcePtr(m_code); }
92     ALWAYS_INLINE int currentLineStartOffset() const { return offsetFromSourcePtr(m_lineStart); }
93     ALWAYS_INLINE JSTextPosition currentPosition() const
94     {
95         return JSTextPosition(m_lineNumber, currentOffset(), currentLineStartOffset());
96     }
97     JSTextPosition positionBeforeLastNewline() const { return m_positionBeforeLastNewline; }
98     void setLastLineNumber(int lastLineNumber) { m_lastLineNumber = lastLineNumber; }
99     int lastLineNumber() const { return m_lastLineNumber; }
100     bool prevTerminator() const { return m_terminator; }
101     bool scanRegExp(const Identifier*& pattern, const Identifier*& flags, UChar patternPrefix = 0);
102     bool skipRegExp();
103
104     // Functions for use after parsing.
105     bool sawError() const { return m_error; }
106     String getErrorMessage() const { return m_lexErrorMessage; }
107     void clear();
108     void setOffset(int offset, int lineStartOffset)
109     {
110         m_error = 0;
111         m_lexErrorMessage = String();
112
113         m_code = sourcePtrFromOffset(offset);
114         m_lineStart = sourcePtrFromOffset(lineStartOffset);
115         ASSERT(currentOffset() >= currentLineStartOffset());
116
117         m_buffer8.resize(0);
118         m_buffer16.resize(0);
119         if (LIKELY(m_code < m_codeEnd))
120             m_current = *m_code;
121         else
122             m_current = 0;
123     }
124     void setLineNumber(int line)
125     {
126         m_lineNumber = line;
127     }
128
129     SourceProvider* sourceProvider() const { return m_source->provider(); }
130
131     JSTokenType lexExpectIdentifier(JSToken*, unsigned, bool strictMode);
132
133 private:
134     void record8(int);
135     void append8(const T*, size_t);
136     void record16(int);
137     void record16(T);
138     void append16(const LChar*, size_t);
139     void append16(const UChar* characters, size_t length) { m_buffer16.append(characters, length); }
140
141     ALWAYS_INLINE void shift();
142     ALWAYS_INLINE bool atEnd() const;
143     ALWAYS_INLINE T peek(int offset) const;
144     struct UnicodeHexValue {
145         
146         enum ValueType { ValidHex, IncompleteHex, InvalidHex };
147         
148         explicit UnicodeHexValue(int value)
149             : m_value(value)
150         {
151         }
152         explicit UnicodeHexValue(ValueType type)
153             : m_value(type == IncompleteHex ? -2 : -1)
154         {
155         }
156
157         ValueType valueType() const
158         {
159             if (m_value >= 0)
160                 return ValidHex;
161             return m_value == -2 ? IncompleteHex : InvalidHex;
162         }
163         bool isValid() const { return m_value >= 0; }
164         int value() const
165         {
166             ASSERT(m_value >= 0);
167             return m_value;
168         }
169         
170     private:
171         int m_value;
172     };
173     UnicodeHexValue parseFourDigitUnicodeHex();
174     void shiftLineTerminator();
175
176     ALWAYS_INLINE int offsetFromSourcePtr(const T* ptr) const { return ptr - m_codeStart; }
177     ALWAYS_INLINE const T* sourcePtrFromOffset(int offset) const { return m_codeStart + offset; }
178
179     String invalidCharacterMessage() const;
180     ALWAYS_INLINE const T* currentSourcePtr() const;
181     ALWAYS_INLINE void setOffsetFromSourcePtr(const T* sourcePtr, unsigned lineStartOffset) { setOffset(offsetFromSourcePtr(sourcePtr), lineStartOffset); }
182
183     ALWAYS_INLINE void setCodeStart(const StringImpl*);
184
185     ALWAYS_INLINE const Identifier* makeIdentifier(const LChar* characters, size_t length);
186     ALWAYS_INLINE const Identifier* makeIdentifier(const UChar* characters, size_t length);
187     ALWAYS_INLINE const Identifier* makeLCharIdentifier(const LChar* characters, size_t length);
188     ALWAYS_INLINE const Identifier* makeLCharIdentifier(const UChar* characters, size_t length);
189     ALWAYS_INLINE const Identifier* makeRightSizedIdentifier(const UChar* characters, size_t length, UChar orAllChars);
190     ALWAYS_INLINE const Identifier* makeIdentifierLCharFromUChar(const UChar* characters, size_t length);
191
192     ALWAYS_INLINE bool lastTokenWasRestrKeyword() const;
193
194     template <int shiftAmount> void internalShift();
195     template <bool shouldCreateIdentifier> ALWAYS_INLINE JSTokenType parseKeyword(JSTokenData*);
196     template <bool shouldBuildIdentifiers> ALWAYS_INLINE JSTokenType parseIdentifier(JSTokenData*, unsigned lexerFlags, bool strictMode);
197     template <bool shouldBuildIdentifiers> NEVER_INLINE JSTokenType parseIdentifierSlowCase(JSTokenData*, unsigned lexerFlags, bool strictMode);
198     enum StringParseResult {
199         StringParsedSuccessfully,
200         StringUnterminated,
201         StringCannotBeParsed
202     };
203     template <bool shouldBuildStrings> ALWAYS_INLINE StringParseResult parseString(JSTokenData*, bool strictMode);
204     template <bool shouldBuildStrings> NEVER_INLINE StringParseResult parseStringSlowCase(JSTokenData*, bool strictMode);
205     ALWAYS_INLINE void parseHex(double& returnValue);
206     ALWAYS_INLINE bool parseOctal(double& returnValue);
207     ALWAYS_INLINE bool parseDecimal(double& returnValue);
208     ALWAYS_INLINE void parseNumberAfterDecimalPoint();
209     ALWAYS_INLINE bool parseNumberAfterExponentIndicator();
210     ALWAYS_INLINE bool parseMultilineComment();
211
212     static const size_t initialReadBufferCapacity = 32;
213
214     int m_lineNumber;
215     int m_lastLineNumber;
216
217     Vector<LChar> m_buffer8;
218     Vector<UChar> m_buffer16;
219     bool m_terminator;
220     int m_lastToken;
221
222     const SourceCode* m_source;
223     unsigned m_sourceOffset;
224     const T* m_code;
225     const T* m_codeStart;
226     const T* m_codeEnd;
227     const T* m_codeStartPlusOffset;
228     const T* m_lineStart;
229     JSTextPosition m_positionBeforeLastNewline;
230     bool m_isReparsing;
231     bool m_atLineStart;
232     bool m_error;
233     String m_lexErrorMessage;
234
235     T m_current;
236
237     IdentifierArena* m_arena;
238
239     VM* m_vm;
240     bool m_parsingBuiltinFunction;
241     JSFunctionKind m_functionKind;
242 };
243
244 template <>
245 ALWAYS_INLINE bool Lexer<LChar>::isWhiteSpace(LChar ch)
246 {
247     return ch == ' ' || ch == '\t' || ch == 0xB || ch == 0xC || ch == 0xA0;
248 }
249
250 template <>
251 ALWAYS_INLINE bool Lexer<UChar>::isWhiteSpace(UChar ch)
252 {
253     // 0x180E used to be in Zs category before Unicode 6.3, and EcmaScript says that we should keep treating it as such.
254     return (ch < 256) ? Lexer<LChar>::isWhiteSpace(static_cast<LChar>(ch)) : (u_charType(ch) == U_SPACE_SEPARATOR || ch == 0x180E || ch == 0xFEFF);
255 }
256
257 template <>
258 ALWAYS_INLINE bool Lexer<LChar>::isLineTerminator(LChar ch)
259 {
260     return ch == '\r' || ch == '\n';
261 }
262
263 template <>
264 ALWAYS_INLINE bool Lexer<UChar>::isLineTerminator(UChar ch)
265 {
266     return ch == '\r' || ch == '\n' || (ch & ~1) == 0x2028;
267 }
268
269 template <typename T>
270 inline unsigned char Lexer<T>::convertHex(int c1, int c2)
271 {
272     return (toASCIIHexValue(c1) << 4) | toASCIIHexValue(c2);
273 }
274
275 template <typename T>
276 inline UChar Lexer<T>::convertUnicode(int c1, int c2, int c3, int c4)
277 {
278     return (convertHex(c1, c2) << 8) | convertHex(c3, c4);
279 }
280
281 template <typename T>
282 ALWAYS_INLINE const Identifier* Lexer<T>::makeIdentifier(const LChar* characters, size_t length)
283 {
284     return &m_arena->makeIdentifier(m_vm, characters, length);
285 }
286
287 template <typename T>
288 ALWAYS_INLINE const Identifier* Lexer<T>::makeIdentifier(const UChar* characters, size_t length)
289 {
290     return &m_arena->makeIdentifier(m_vm, characters, length);
291 }
292
293 template <>
294 ALWAYS_INLINE const Identifier* Lexer<LChar>::makeRightSizedIdentifier(const UChar* characters, size_t length, UChar)
295 {
296     return &m_arena->makeIdentifierLCharFromUChar(m_vm, characters, length);
297 }
298
299 template <>
300 ALWAYS_INLINE const Identifier* Lexer<UChar>::makeRightSizedIdentifier(const UChar* characters, size_t length, UChar orAllChars)
301 {
302     if (!(orAllChars & ~0xff))
303         return &m_arena->makeIdentifierLCharFromUChar(m_vm, characters, length);
304
305     return &m_arena->makeIdentifier(m_vm, characters, length);
306 }
307
308 template <>
309 ALWAYS_INLINE void Lexer<LChar>::setCodeStart(const StringImpl* sourceString)
310 {
311     ASSERT(sourceString->is8Bit());
312     m_codeStart = sourceString->characters8();
313 }
314
315 template <>
316 ALWAYS_INLINE void Lexer<UChar>::setCodeStart(const StringImpl* sourceString)
317 {
318     ASSERT(!sourceString->is8Bit());
319     m_codeStart = sourceString->characters16();
320 }
321
322 template <typename T>
323 ALWAYS_INLINE const Identifier* Lexer<T>::makeIdentifierLCharFromUChar(const UChar* characters, size_t length)
324 {
325     return &m_arena->makeIdentifierLCharFromUChar(m_vm, characters, length);
326 }
327
328 template <typename T>
329 ALWAYS_INLINE const Identifier* Lexer<T>::makeLCharIdentifier(const LChar* characters, size_t length)
330 {
331     return &m_arena->makeIdentifier(m_vm, characters, length);
332 }
333
334 template <typename T>
335 ALWAYS_INLINE const Identifier* Lexer<T>::makeLCharIdentifier(const UChar* characters, size_t length)
336 {
337     return &m_arena->makeIdentifierLCharFromUChar(m_vm, characters, length);
338 }
339
340 #if ASSERT_DISABLED
341 ALWAYS_INLINE bool isSafeBuiltinIdentifier(VM&, const Identifier*) { return true; }
342 #else
343 bool isSafeBuiltinIdentifier(VM&, const Identifier*);
344 #endif
345
346 template <typename T>
347 ALWAYS_INLINE JSTokenType Lexer<T>::lexExpectIdentifier(JSToken* tokenRecord, unsigned lexerFlags, bool strictMode)
348 {
349     JSTokenData* tokenData = &tokenRecord->m_data;
350     JSTokenLocation* tokenLocation = &tokenRecord->m_location;
351     ASSERT((lexerFlags & LexerFlagsIgnoreReservedWords));
352     const T* start = m_code;
353     const T* ptr = start;
354     const T* end = m_codeEnd;
355     JSTextPosition startPosition = currentPosition();
356     if (ptr >= end) {
357         ASSERT(ptr == end);
358         goto slowCase;
359     }
360     if (!WTF::isASCIIAlpha(*ptr))
361         goto slowCase;
362     ++ptr;
363     while (ptr < end) {
364         if (!WTF::isASCIIAlphanumeric(*ptr))
365             break;
366         ++ptr;
367     }
368
369     // Here's the shift
370     if (ptr < end) {
371         if ((!WTF::isASCII(*ptr)) || (*ptr == '\\') || (*ptr == '_') || (*ptr == '$'))
372             goto slowCase;
373         m_current = *ptr;
374     } else
375         m_current = 0;
376
377     m_code = ptr;
378     ASSERT(currentOffset() >= currentLineStartOffset());
379
380     // Create the identifier if needed
381     if (lexerFlags & LexexFlagsDontBuildKeywords
382 #if !ASSERT_DISABLED
383         && !m_parsingBuiltinFunction
384 #endif
385         )
386         tokenData->ident = 0;
387     else
388         tokenData->ident = makeLCharIdentifier(start, ptr - start);
389
390     tokenLocation->line = m_lineNumber;
391     tokenLocation->lineStartOffset = currentLineStartOffset();
392     tokenLocation->startOffset = offsetFromSourcePtr(start);
393     tokenLocation->endOffset = currentOffset();
394     ASSERT(tokenLocation->startOffset >= tokenLocation->lineStartOffset);
395     tokenRecord->m_startPosition = startPosition;
396     tokenRecord->m_endPosition = currentPosition();
397 #if !ASSERT_DISABLED
398     if (m_parsingBuiltinFunction) {
399         if (!isSafeBuiltinIdentifier(*m_vm, tokenData->ident))
400             return ERRORTOK;
401     }
402 #endif
403
404     m_lastToken = IDENT;
405     return IDENT;
406     
407 slowCase:
408     return lex(tokenRecord, lexerFlags, strictMode);
409 }
410
411 } // namespace JSC
412
413 #endif // Lexer_h