blob: c13449bfcc5d0db556a8660cd2a68b628965763f [file] [log] [blame]
// Copyright 2019 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/torque/ls/json-parser.h"
#include <cctype>
#include "src/torque/earley-parser.h"
namespace v8 {
namespace internal {
namespace torque {
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId ParseResultHolder<ls::JsonValue>::id =
ParseResultTypeId::kJsonValue;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
ParseResultHolder<std::pair<std::string, ls::JsonValue>>::id =
ParseResultTypeId::kJsonMember;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
ParseResultHolder<std::vector<ls::JsonValue>>::id =
ParseResultTypeId::kStdVectorOfJsonValue;
template <>
V8_EXPORT_PRIVATE const ParseResultTypeId
ParseResultHolder<std::vector<std::pair<std::string, ls::JsonValue>>>::id =
ParseResultTypeId::kStdVectorOfJsonMember;
namespace ls {
using JsonMember = std::pair<std::string, JsonValue>;
template <bool value>
base::Optional<ParseResult> MakeBoolLiteral(
ParseResultIterator* child_results) {
return ParseResult{JsonValue::From(value)};
}
base::Optional<ParseResult> MakeNullLiteral(
ParseResultIterator* child_results) {
JsonValue result;
result.tag = JsonValue::IS_NULL;
return ParseResult{std::move(result)};
}
base::Optional<ParseResult> MakeNumberLiteral(
ParseResultIterator* child_results) {
auto number = child_results->NextAs<std::string>();
double d = std::stod(number.c_str());
return ParseResult{JsonValue::From(d)};
}
base::Optional<ParseResult> MakeStringLiteral(
ParseResultIterator* child_results) {
std::string literal = child_results->NextAs<std::string>();
return ParseResult{JsonValue::From(StringLiteralUnquote(literal))};
}
base::Optional<ParseResult> MakeArray(ParseResultIterator* child_results) {
JsonArray array = child_results->NextAs<JsonArray>();
return ParseResult{JsonValue::From(std::move(array))};
}
base::Optional<ParseResult> MakeMember(ParseResultIterator* child_results) {
JsonMember result;
std::string key = child_results->NextAs<std::string>();
result.first = StringLiteralUnquote(key);
result.second = child_results->NextAs<JsonValue>();
return ParseResult{std::move(result)};
}
base::Optional<ParseResult> MakeObject(ParseResultIterator* child_results) {
using MemberList = std::vector<JsonMember>;
MemberList members = child_results->NextAs<MemberList>();
JsonObject object;
for (auto& member : members) object.insert(std::move(member));
return ParseResult{JsonValue::From(std::move(object))};
}
class JsonGrammar : public Grammar {
static bool MatchWhitespace(InputPosition* pos) {
while (MatchChar(std::isspace, pos)) {
}
return true;
}
static bool MatchStringLiteral(InputPosition* pos) {
InputPosition current = *pos;
if (MatchString("\"", &current)) {
while (
(MatchString("\\", &current) && MatchAnyChar(&current)) ||
MatchChar([](char c) { return c != '"' && c != '\n'; }, &current)) {
}
if (MatchString("\"", &current)) {
*pos = current;
return true;
}
}
current = *pos;
if (MatchString("'", &current)) {
while (
(MatchString("\\", &current) && MatchAnyChar(&current)) ||
MatchChar([](char c) { return c != '\'' && c != '\n'; }, &current)) {
}
if (MatchString("'", &current)) {
*pos = current;
return true;
}
}
return false;
}
static bool MatchHexLiteral(InputPosition* pos) {
InputPosition current = *pos;
MatchString("-", &current);
if (MatchString("0x", &current) && MatchChar(std::isxdigit, &current)) {
while (MatchChar(std::isxdigit, &current)) {
}
*pos = current;
return true;
}
return false;
}
static bool MatchDecimalLiteral(InputPosition* pos) {
InputPosition current = *pos;
bool found_digit = false;
MatchString("-", &current);
while (MatchChar(std::isdigit, &current)) found_digit = true;
MatchString(".", &current);
while (MatchChar(std::isdigit, &current)) found_digit = true;
if (!found_digit) return false;
*pos = current;
if ((MatchString("e", &current) || MatchString("E", &current)) &&
(MatchString("+", &current) || MatchString("-", &current) || true) &&
MatchChar(std::isdigit, &current)) {
while (MatchChar(std::isdigit, &current)) {
}
*pos = current;
return true;
}
return true;
}
public:
JsonGrammar() : Grammar(&file) { SetWhitespace(MatchWhitespace); }
Symbol trueLiteral = {Rule({Token("true")})};
Symbol falseLiteral = {Rule({Token("false")})};
Symbol nullLiteral = {Rule({Token("null")})};
Symbol decimalLiteral = {
Rule({Pattern(MatchDecimalLiteral)}, YieldMatchedInput),
Rule({Pattern(MatchHexLiteral)}, YieldMatchedInput)};
Symbol stringLiteral = {
Rule({Pattern(MatchStringLiteral)}, YieldMatchedInput)};
Symbol* elementList = List<JsonValue>(&value, Token(","));
Symbol array = {Rule({Token("["), elementList, Token("]")})};
Symbol member = {Rule({&stringLiteral, Token(":"), &value}, MakeMember)};
Symbol* memberList = List<JsonMember>(&member, Token(","));
Symbol object = {Rule({Token("{"), memberList, Token("}")})};
Symbol value = {Rule({&trueLiteral}, MakeBoolLiteral<true>),
Rule({&falseLiteral}, MakeBoolLiteral<false>),
Rule({&nullLiteral}, MakeNullLiteral),
Rule({&decimalLiteral}, MakeNumberLiteral),
Rule({&stringLiteral}, MakeStringLiteral),
Rule({&object}, MakeObject),
Rule({&array}, MakeArray)};
Symbol file = {Rule({&value})};
};
JsonParserResult ParseJson(const std::string& input) {
// Torque needs a CurrentSourceFile scope during parsing.
// As JSON lives in memory only, a unknown file scope is created.
SourceFileMap::Scope source_map_scope("");
TorqueMessages::Scope messages_scope;
CurrentSourceFile::Scope unkown_file(SourceFileMap::AddSource("<json>"));
JsonParserResult result;
try {
result.value = (*JsonGrammar().Parse(input)).Cast<JsonValue>();
} catch (TorqueAbortCompilation&) {
CHECK(!TorqueMessages::Get().empty());
result.error = TorqueMessages::Get().front();
}
return result;
}
} // namespace ls
} // namespace torque
} // namespace internal
} // namespace v8