1 // Copyright 2019 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/torque/ls/json-parser.h"
6
7 #include <cctype>
8 #include "src/torque/earley-parser.h"
9
10 namespace v8 {
11 namespace internal {
12 namespace torque {
13
14 template <>
15 V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder<ls::JsonValue>::id =
16 ParseResultTypeId::kJsonValue;
17
18 template <>
19 V8_EXPORT_PRIVATE const ParseResultTypeId
20 ParseResultHolder<std::pair<std::string, ls::JsonValue>>::id =
21 ParseResultTypeId::kJsonMember;
22
23 template <>
24 V8_EXPORT_PRIVATE const ParseResultTypeId
25 ParseResultHolder<std::vector<ls::JsonValue>>::id =
26 ParseResultTypeId::kStdVectorOfJsonValue;
27
28 template <>
29 V8_EXPORT_PRIVATE const ParseResultTypeId
30 ParseResultHolder<std::vector<std::pair<std::string, ls::JsonValue>>>::id =
31 ParseResultTypeId::kStdVectorOfJsonMember;
32
33 namespace ls {
34
35 using JsonMember = std::pair<std::string, JsonValue>;
36
37 template <bool value>
MakeBoolLiteral( ParseResultIterator* child_results)38 base::Optional<ParseResult> MakeBoolLiteral(
39 ParseResultIterator* child_results) {
40 return ParseResult{JsonValue::From(value)};
41 }
42
MakeNullLiteral( ParseResultIterator* child_results)43 base::Optional<ParseResult> MakeNullLiteral(
44 ParseResultIterator* child_results) {
45 JsonValue result;
46 result.tag = JsonValue::IS_NULL;
47 return ParseResult{std::move(result)};
48 }
49
MakeNumberLiteral( ParseResultIterator* child_results)50 base::Optional<ParseResult> MakeNumberLiteral(
51 ParseResultIterator* child_results) {
52 auto number = child_results->NextAs<std::string>();
53 double d = std::stod(number.c_str());
54 return ParseResult{JsonValue::From(d)};
55 }
56
MakeStringLiteral( ParseResultIterator* child_results)57 base::Optional<ParseResult> MakeStringLiteral(
58 ParseResultIterator* child_results) {
59 std::string literal = child_results->NextAs<std::string>();
60 return ParseResult{JsonValue::From(StringLiteralUnquote(literal))};
61 }
62
MakeArray(ParseResultIterator* child_results)63 base::Optional<ParseResult> MakeArray(ParseResultIterator* child_results) {
64 JsonArray array = child_results->NextAs<JsonArray>();
65 return ParseResult{JsonValue::From(std::move(array))};
66 }
67
MakeMember(ParseResultIterator* child_results)68 base::Optional<ParseResult> MakeMember(ParseResultIterator* child_results) {
69 JsonMember result;
70 std::string key = child_results->NextAs<std::string>();
71 result.first = StringLiteralUnquote(key);
72 result.second = child_results->NextAs<JsonValue>();
73 return ParseResult{std::move(result)};
74 }
75
MakeObject(ParseResultIterator* child_results)76 base::Optional<ParseResult> MakeObject(ParseResultIterator* child_results) {
77 using MemberList = std::vector<JsonMember>;
78 MemberList members = child_results->NextAs<MemberList>();
79
80 JsonObject object;
81 for (auto& member : members) object.insert(std::move(member));
82
83 return ParseResult{JsonValue::From(std::move(object))};
84 }
85
86 class JsonGrammar : public Grammar {
MatchWhitespace(InputPosition* pos)87 static bool MatchWhitespace(InputPosition* pos) {
88 while (MatchChar(std::isspace, pos)) {
89 }
90 return true;
91 }
92
MatchStringLiteral(InputPosition* pos)93 static bool MatchStringLiteral(InputPosition* pos) {
94 InputPosition current = *pos;
95 if (MatchString("\"", ¤t)) {
96 while (
97 (MatchString("\\", ¤t) && MatchAnyChar(¤t)) ||
98 MatchChar([](char c) { return c != '"' && c != '\n'; }, ¤t)) {
99 }
100 if (MatchString("\"", ¤t)) {
101 *pos = current;
102 return true;
103 }
104 }
105 current = *pos;
106 if (MatchString("'", ¤t)) {
107 while (
108 (MatchString("\\", ¤t) && MatchAnyChar(¤t)) ||
109 MatchChar([](char c) { return c != '\'' && c != '\n'; }, ¤t)) {
110 }
111 if (MatchString("'", ¤t)) {
112 *pos = current;
113 return true;
114 }
115 }
116 return false;
117 }
118
MatchHexLiteral(InputPosition* pos)119 static bool MatchHexLiteral(InputPosition* pos) {
120 InputPosition current = *pos;
121 MatchString("-", ¤t);
122 if (MatchString("0x", ¤t) && MatchChar(std::isxdigit, ¤t)) {
123 while (MatchChar(std::isxdigit, ¤t)) {
124 }
125 *pos = current;
126 return true;
127 }
128 return false;
129 }
130
MatchDecimalLiteral(InputPosition* pos)131 static bool MatchDecimalLiteral(InputPosition* pos) {
132 InputPosition current = *pos;
133 bool found_digit = false;
134 MatchString("-", ¤t);
135 while (MatchChar(std::isdigit, ¤t)) found_digit = true;
136 MatchString(".", ¤t);
137 while (MatchChar(std::isdigit, ¤t)) found_digit = true;
138 if (!found_digit) return false;
139 *pos = current;
140 if ((MatchString("e", ¤t) || MatchString("E", ¤t)) &&
141 (MatchString("+", ¤t) || MatchString("-", ¤t) || true) &&
142 MatchChar(std::isdigit, ¤t)) {
143 while (MatchChar(std::isdigit, ¤t)) {
144 }
145 *pos = current;
146 return true;
147 }
148 return true;
149 }
150
151 public:
JsonGrammar()152 JsonGrammar() : Grammar(&file) { SetWhitespace(MatchWhitespace); }
153
154 Symbol trueLiteral = {Rule({Token("true")})};
155 Symbol falseLiteral = {Rule({Token("false")})};
156 Symbol nullLiteral = {Rule({Token("null")})};
157
158 Symbol decimalLiteral = {
159 Rule({Pattern(MatchDecimalLiteral)}, YieldMatchedInput),
160 Rule({Pattern(MatchHexLiteral)}, YieldMatchedInput)};
161
162 Symbol stringLiteral = {
163 Rule({Pattern(MatchStringLiteral)}, YieldMatchedInput)};
164
165 Symbol* elementList = List<JsonValue>(&value, Token(","));
166 Symbol array = {Rule({Token("["), elementList, Token("]")})};
167
168 Symbol member = {Rule({&stringLiteral, Token(":"), &value}, MakeMember)};
169 Symbol* memberList = List<JsonMember>(&member, Token(","));
170 Symbol object = {Rule({Token("{"), memberList, Token("}")})};
171
172 Symbol value = {Rule({&trueLiteral}, MakeBoolLiteral<true>),
173 Rule({&falseLiteral}, MakeBoolLiteral<false>),
174 Rule({&nullLiteral}, MakeNullLiteral),
175 Rule({&decimalLiteral}, MakeNumberLiteral),
176 Rule({&stringLiteral}, MakeStringLiteral),
177 Rule({&object}, MakeObject),
178 Rule({&array}, MakeArray)};
179
180 Symbol file = {Rule({&value})};
181 };
182
ParseJson(const std::string& input)183 JsonParserResult ParseJson(const std::string& input) {
184 // Torque needs a CurrentSourceFile scope during parsing.
185 // As JSON lives in memory only, a unknown file scope is created.
186 SourceFileMap::Scope source_map_scope("");
187 TorqueMessages::Scope messages_scope;
188 CurrentSourceFile::Scope unkown_file(SourceFileMap::AddSource("<json>"));
189
190 JsonParserResult result;
191 try {
192 result.value = (*JsonGrammar().Parse(input)).Cast<JsonValue>();
193 } catch (TorqueAbortCompilation&) {
194 CHECK(!TorqueMessages::Get().empty());
195 result.error = TorqueMessages::Get().front();
196 }
197 return result;
198 }
199
200 } // namespace ls
201 } // namespace torque
202 } // namespace internal
203 } // namespace v8
204