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("\"", &current)) {
96       while (
97           (MatchString("\\", &current) && MatchAnyChar(&current)) ||
98           MatchChar([](char c) { return c != '"' && c != '\n'; }, &current)) {
99       }
100       if (MatchString("\"", &current)) {
101         *pos = current;
102         return true;
103       }
104     }
105     current = *pos;
106     if (MatchString("'", &current)) {
107       while (
108           (MatchString("\\", &current) && MatchAnyChar(&current)) ||
109           MatchChar([](char c) { return c != '\'' && c != '\n'; }, &current)) {
110       }
111       if (MatchString("'", &current)) {
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("-", &current);
122     if (MatchString("0x", &current) && MatchChar(std::isxdigit, &current)) {
123       while (MatchChar(std::isxdigit, &current)) {
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("-", &current);
135     while (MatchChar(std::isdigit, &current)) found_digit = true;
136     MatchString(".", &current);
137     while (MatchChar(std::isdigit, &current)) found_digit = true;
138     if (!found_digit) return false;
139     *pos = current;
140     if ((MatchString("e", &current) || MatchString("E", &current)) &&
141         (MatchString("+", &current) || MatchString("-", &current) || true) &&
142         MatchChar(std::isdigit, &current)) {
143       while (MatchChar(std::isdigit, &current)) {
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