1/*
2 * Copyright (C) 2009 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28#include "Identifier.h"
29#include "JSCJSValue.h"
30#include <array>
31#include <wtf/text/StringBuilder.h>
32#include <wtf/text/WTFString.h>
33
34namespace JSC {
35
36typedef enum { StrictJSON, NonStrictJSON, JSONP } ParserMode;
37
38enum JSONPPathEntryType {
39 JSONPPathEntryTypeDeclareVar, // var pathEntryName = JSON
40 JSONPPathEntryTypeDot, // <prior entries>.pathEntryName = JSON
41 JSONPPathEntryTypeLookup, // <prior entries>[pathIndex] = JSON
42 JSONPPathEntryTypeCall // <prior entries>(JSON)
43};
44
45enum ParserState { StartParseObject, StartParseArray, StartParseExpression,
46 StartParseStatement, StartParseStatementEndStatement,
47 DoParseObjectStartExpression, DoParseObjectEndExpression,
48 DoParseArrayStartExpression, DoParseArrayEndExpression };
49enum TokenType { TokLBracket, TokRBracket, TokLBrace, TokRBrace,
50 TokString, TokIdentifier, TokNumber, TokColon,
51 TokLParen, TokRParen, TokComma, TokTrue, TokFalse,
52 TokNull, TokEnd, TokDot, TokAssign, TokSemi, TokError };
53
54struct JSONPPathEntry {
55 JSONPPathEntryType m_type;
56 Identifier m_pathEntryName;
57 int m_pathIndex;
58};
59
60struct JSONPData {
61 Vector<JSONPPathEntry> m_path;
62 Strong<Unknown> m_value;
63};
64
65template <typename CharType>
66struct LiteralParserToken {
67private:
68WTF_MAKE_NONCOPYABLE(LiteralParserToken<CharType>);
69
70public:
71 LiteralParserToken() = default;
72
73 TokenType type;
74 const CharType* start;
75 const CharType* end;
76 union {
77 double numberToken;
78 struct {
79 union {
80 const LChar* stringToken8;
81 const UChar* stringToken16;
82 };
83 unsigned stringIs8Bit : 1;
84 unsigned stringLength : 31;
85 };
86 };
87};
88
89template <typename CharType>
90ALWAYS_INLINE void setParserTokenString(LiteralParserToken<CharType>&, const CharType* string);
91
92template <typename CharType>
93class LiteralParser {
94public:
95 LiteralParser(ExecState* exec, const CharType* characters, unsigned length, ParserMode mode)
96 : m_exec(exec)
97 , m_lexer(characters, length, mode)
98 , m_mode(mode)
99 {
100 }
101
102 String getErrorMessage()
103 {
104 if (!m_lexer.getErrorMessage().isEmpty())
105 return "JSON Parse error: " + m_lexer.getErrorMessage();
106 if (!m_parseErrorMessage.isEmpty())
107 return "JSON Parse error: " + m_parseErrorMessage;
108 return "JSON Parse error: Unable to parse JSON string"_s;
109 }
110
111 JSValue tryLiteralParse()
112 {
113 m_lexer.next();
114 JSValue result = parse(m_mode == StrictJSON ? StartParseExpression : StartParseStatement);
115 if (m_lexer.currentToken()->type == TokSemi)
116 m_lexer.next();
117 if (m_lexer.currentToken()->type != TokEnd)
118 return JSValue();
119 return result;
120 }
121
122 bool tryJSONPParse(Vector<JSONPData>&, bool needsFullSourceInfo);
123
124private:
125 class Lexer {
126 public:
127 Lexer(const CharType* characters, unsigned length, ParserMode mode)
128 : m_mode(mode)
129 , m_ptr(characters)
130 , m_end(characters + length)
131 {
132 }
133
134 TokenType next();
135
136#if ASSERT_DISABLED
137 typedef const LiteralParserToken<CharType>* LiteralParserTokenPtr;
138
139 LiteralParserTokenPtr currentToken()
140 {
141 return &m_currentToken;
142 }
143#else
144 class LiteralParserTokenPtr;
145 friend class LiteralParserTokenPtr;
146 class LiteralParserTokenPtr {
147 public:
148 LiteralParserTokenPtr(Lexer& lexer)
149 : m_lexer(lexer)
150 , m_tokenID(lexer.m_currentTokenID)
151 {
152 }
153
154 ALWAYS_INLINE const LiteralParserToken<CharType>* operator->() const
155 {
156 ASSERT(m_tokenID == m_lexer.m_currentTokenID);
157 return &m_lexer.m_currentToken;
158 }
159
160 private:
161 Lexer& m_lexer;
162 unsigned m_tokenID;
163 };
164
165 LiteralParserTokenPtr currentToken()
166 {
167 return LiteralParserTokenPtr(*this);
168 }
169#endif
170
171 String getErrorMessage() { return m_lexErrorMessage; }
172
173 private:
174 String m_lexErrorMessage;
175 TokenType lex(LiteralParserToken<CharType>&);
176 ALWAYS_INLINE TokenType lexIdentifier(LiteralParserToken<CharType>&);
177 ALWAYS_INLINE TokenType lexString(LiteralParserToken<CharType>&, CharType terminator);
178 TokenType lexStringSlow(LiteralParserToken<CharType>&, const CharType* runStart, CharType terminator);
179 ALWAYS_INLINE TokenType lexNumber(LiteralParserToken<CharType>&);
180 LiteralParserToken<CharType> m_currentToken;
181 ParserMode m_mode;
182 const CharType* m_ptr;
183 const CharType* m_end;
184 StringBuilder m_builder;
185#if !ASSERT_DISABLED
186 unsigned m_currentTokenID { 0 };
187#endif
188 };
189
190 class StackGuard;
191 JSValue parse(ParserState);
192
193 ExecState* m_exec;
194 typename LiteralParser<CharType>::Lexer m_lexer;
195 ParserMode m_mode;
196 String m_parseErrorMessage;
197 static unsigned const MaximumCachableCharacter = 128;
198 std::array<Identifier, MaximumCachableCharacter> m_shortIdentifiers;
199 std::array<Identifier, MaximumCachableCharacter> m_recentIdentifiers;
200 ALWAYS_INLINE const Identifier makeIdentifier(const LChar* characters, size_t length);
201 ALWAYS_INLINE const Identifier makeIdentifier(const UChar* characters, size_t length);
202};
203
204} // namespace JSC
205