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
10namespace v8 {
11namespace internal {
12namespace torque {
13
14template <>
15V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder<ls::JsonValue>::id =
16    ParseResultTypeId::kJsonValue;
17
18template <>
19V8_EXPORT_PRIVATE const ParseResultTypeId
20    ParseResultHolder<std::pair<std::string, ls::JsonValue>>::id =
21        ParseResultTypeId::kJsonMember;
22
23template <>
24V8_EXPORT_PRIVATE const ParseResultTypeId
25    ParseResultHolder<std::vector<ls::JsonValue>>::id =
26        ParseResultTypeId::kStdVectorOfJsonValue;
27
28template <>
29V8_EXPORT_PRIVATE const ParseResultTypeId
30    ParseResultHolder<std::vector<std::pair<std::string, ls::JsonValue>>>::id =
31        ParseResultTypeId::kStdVectorOfJsonMember;
32
33namespace ls {
34
35using JsonMember = std::pair<std::string, JsonValue>;
36
37template <bool value>
38base::Optional<ParseResult> MakeBoolLiteral(
39    ParseResultIterator* child_results) {
40  return ParseResult{JsonValue::From(value)};
41}
42
43base::Optional<ParseResult> MakeNullLiteral(
44    ParseResultIterator* child_results) {
45  JsonValue result;
46  result.tag = JsonValue::IS_NULL;
47  return ParseResult{std::move(result)};
48}
49
50base::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
57base::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
63base::Optional<ParseResult> MakeArray(ParseResultIterator* child_results) {
64  JsonArray array = child_results->NextAs<JsonArray>();
65  return ParseResult{JsonValue::From(std::move(array))};
66}
67
68base::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
76base::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
86class JsonGrammar : public Grammar {
87  static bool MatchWhitespace(InputPosition* pos) {
88    while (MatchChar(std::isspace, pos)) {
89    }
90    return true;
91  }
92
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
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
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:
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
183JsonParserResult 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