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(JSGlobalObject* globalObject, const CharType* characters, unsigned length, ParserMode mode, CodeBlock* nullOrCodeBlock = nullptr)
96 : m_globalObject(globalObject)
97 , m_nullOrCodeBlock(nullOrCodeBlock)
98 , m_lexer(characters, length, mode)
99 , m_mode(mode)
100 {
101 }
102
103 String getErrorMessage()
104 {
105 if (!m_lexer.getErrorMessage().isEmpty())
106 return "JSON Parse error: " + m_lexer.getErrorMessage();
107 if (!m_parseErrorMessage.isEmpty())
108 return "JSON Parse error: " + m_parseErrorMessage;
109 return "JSON Parse error: Unable to parse JSON string"_s;
110 }
111
112 JSValue tryLiteralParse()
113 {
114 m_lexer.next();
115 JSValue result = parse(m_mode == StrictJSON ? StartParseExpression : StartParseStatement);
116 if (m_lexer.currentToken()->type == TokSemi)
117 m_lexer.next();
118 if (m_lexer.currentToken()->type != TokEnd)
119 return JSValue();
120 return result;
121 }
122
123 bool tryJSONPParse(Vector<JSONPData>&, bool needsFullSourceInfo);
124
125private:
126 class Lexer {
127 public:
128 Lexer(const CharType* characters, unsigned length, ParserMode mode)
129 : m_mode(mode)
130 , m_ptr(characters)
131 , m_end(characters + length)
132 {
133 }
134
135 TokenType next();
136
137#if ASSERT_DISABLED
138 typedef const LiteralParserToken<CharType>* LiteralParserTokenPtr;
139
140 LiteralParserTokenPtr currentToken()
141 {
142 return &m_currentToken;
143 }
144#else
145 class LiteralParserTokenPtr;
146 friend class LiteralParserTokenPtr;
147 class LiteralParserTokenPtr {
148 public:
149 LiteralParserTokenPtr(Lexer& lexer)
150 : m_lexer(lexer)
151 , m_tokenID(lexer.m_currentTokenID)
152 {
153 }
154
155 ALWAYS_INLINE const LiteralParserToken<CharType>* operator->() const
156 {
157 ASSERT(m_tokenID == m_lexer.m_currentTokenID);
158 return &m_lexer.m_currentToken;
159 }
160
161 private:
162 Lexer& m_lexer;
163 unsigned m_tokenID;
164 };
165
166 LiteralParserTokenPtr currentToken()
167 {
168 return LiteralParserTokenPtr(*this);
169 }
170#endif
171
172 String getErrorMessage() { return m_lexErrorMessage; }
173
174 private:
175 String m_lexErrorMessage;
176 TokenType lex(LiteralParserToken<CharType>&);
177 ALWAYS_INLINE TokenType lexIdentifier(LiteralParserToken<CharType>&);
178 ALWAYS_INLINE TokenType lexString(LiteralParserToken<CharType>&, CharType terminator);
179 TokenType lexStringSlow(LiteralParserToken<CharType>&, const CharType* runStart, CharType terminator);
180 ALWAYS_INLINE TokenType lexNumber(LiteralParserToken<CharType>&);
181 LiteralParserToken<CharType> m_currentToken;
182 ParserMode m_mode;
183 const CharType* m_ptr;
184 const CharType* m_end;
185 StringBuilder m_builder;
186#if !ASSERT_DISABLED
187 unsigned m_currentTokenID { 0 };
188#endif
189 };
190
191 class StackGuard;
192 JSValue parse(ParserState);
193
194 JSGlobalObject* m_globalObject;
195 CodeBlock* m_nullOrCodeBlock;
196 typename LiteralParser<CharType>::Lexer m_lexer;
197 ParserMode m_mode;
198 String m_parseErrorMessage;
199 static unsigned const MaximumCachableCharacter = 128;
200 std::array<Identifier, MaximumCachableCharacter> m_shortIdentifiers;
201 std::array<Identifier, MaximumCachableCharacter> m_recentIdentifiers;
202 ALWAYS_INLINE const Identifier makeIdentifier(const LChar* characters, size_t length);
203 ALWAYS_INLINE const Identifier makeIdentifier(const UChar* characters, size_t length);
204};
205
206} // namespace JSC
207