summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/clangd/JSONExpr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang-tools-extra/clangd/JSONExpr.cpp')
-rw-r--r--clang-tools-extra/clangd/JSONExpr.cpp554
1 files changed, 0 insertions, 554 deletions
diff --git a/clang-tools-extra/clangd/JSONExpr.cpp b/clang-tools-extra/clangd/JSONExpr.cpp
deleted file mode 100644
index 3f87c286f1d..00000000000
--- a/clang-tools-extra/clangd/JSONExpr.cpp
+++ /dev/null
@@ -1,554 +0,0 @@
-//=== JSONExpr.cpp - JSON expressions, parsing and serialization - C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===---------------------------------------------------------------------===//
-
-#include "JSONExpr.h"
-#include "llvm/Support/Format.h"
-#include <cctype>
-
-using namespace llvm;
-namespace clang {
-namespace clangd {
-namespace json {
-
-void Expr::copyFrom(const Expr &M) {
- Type = M.Type;
- switch (Type) {
- case T_Null:
- case T_Boolean:
- case T_Number:
- memcpy(Union.buffer, M.Union.buffer, sizeof(Union.buffer));
- break;
- case T_StringRef:
- create<StringRef>(M.as<StringRef>());
- break;
- case T_String:
- create<std::string>(M.as<std::string>());
- break;
- case T_Object:
- create<ObjectExpr>(M.as<ObjectExpr>());
- break;
- case T_Array:
- create<ArrayExpr>(M.as<ArrayExpr>());
- break;
- }
-}
-
-void Expr::moveFrom(const Expr &&M) {
- Type = M.Type;
- switch (Type) {
- case T_Null:
- case T_Boolean:
- case T_Number:
- memcpy(Union.buffer, M.Union.buffer, sizeof(Union.buffer));
- break;
- case T_StringRef:
- create<StringRef>(M.as<StringRef>());
- break;
- case T_String:
- create<std::string>(std::move(M.as<std::string>()));
- M.Type = T_Null;
- break;
- case T_Object:
- create<ObjectExpr>(std::move(M.as<ObjectExpr>()));
- M.Type = T_Null;
- break;
- case T_Array:
- create<ArrayExpr>(std::move(M.as<ArrayExpr>()));
- M.Type = T_Null;
- break;
- }
-}
-
-void Expr::destroy() {
- switch (Type) {
- case T_Null:
- case T_Boolean:
- case T_Number:
- break;
- case T_StringRef:
- as<StringRef>().~StringRef();
- break;
- case T_String:
- as<std::string>().~basic_string();
- break;
- case T_Object:
- as<ObjectExpr>().~ObjectExpr();
- break;
- case T_Array:
- as<ArrayExpr>().~ArrayExpr();
- break;
- }
-}
-
-namespace {
-// Simple recursive-descent JSON parser.
-class Parser {
-public:
- Parser(StringRef JSON)
- : Start(JSON.begin()), P(JSON.begin()), End(JSON.end()) {}
-
- bool parseExpr(Expr &Out);
-
- bool assertEnd() {
- eatWhitespace();
- if (P == End)
- return true;
- return parseError("Text after end of document");
- }
-
- Error takeError() {
- assert(Err);
- return std::move(*Err);
- }
-
-private:
- void eatWhitespace() {
- while (P != End && (*P == ' ' || *P == '\r' || *P == '\n' || *P == '\t'))
- ++P;
- }
-
- // On invalid syntax, parseX() functions return false and set Err.
- bool parseNumber(char First, double &Out);
- bool parseString(std::string &Out);
- bool parseUnicode(std::string &Out);
- bool parseError(const char *Msg); // always returns false
-
- char next() { return P == End ? 0 : *P++; }
- char peek() { return P == End ? 0 : *P; }
- static bool isNumber(char C) {
- return C == '0' || C == '1' || C == '2' || C == '3' || C == '4' ||
- C == '5' || C == '6' || C == '7' || C == '8' || C == '9' ||
- C == 'e' || C == 'E' || C == '+' || C == '-' || C == '.';
- }
- static void encodeUtf8(uint32_t Rune, std::string &Out);
-
- Optional<Error> Err;
- const char *Start, *P, *End;
-};
-
-bool Parser::parseExpr(Expr &Out) {
- eatWhitespace();
- if (P == End)
- return parseError("Unexpected EOF");
- switch (char C = next()) {
- // Bare null/true/false are easy - first char identifies them.
- case 'n':
- Out = nullptr;
- return (next() == 'u' && next() == 'l' && next() == 'l') ||
- parseError("Invalid bareword");
- case 't':
- Out = true;
- return (next() == 'r' && next() == 'u' && next() == 'e') ||
- parseError("Invalid bareword");
- case 'f':
- Out = false;
- return (next() == 'a' && next() == 'l' && next() == 's' && next() == 'e') ||
- parseError("Invalid bareword");
- case '"': {
- std::string S;
- if (parseString(S)) {
- Out = std::move(S);
- return true;
- }
- return false;
- }
- case '[': {
- Out = json::ary{};
- json::ary &A = *Out.asArray();
- eatWhitespace();
- if (peek() == ']') {
- ++P;
- return true;
- }
- for (;;) {
- A.emplace_back(nullptr);
- if (!parseExpr(A.back()))
- return false;
- eatWhitespace();
- switch (next()) {
- case ',':
- eatWhitespace();
- continue;
- case ']':
- return true;
- default:
- return parseError("Expected , or ] after array element");
- }
- }
- }
- case '{': {
- Out = json::obj{};
- json::obj &O = *Out.asObject();
- eatWhitespace();
- if (peek() == '}') {
- ++P;
- return true;
- }
- for (;;) {
- if (next() != '"')
- return parseError("Expected object key");
- std::string K;
- if (!parseString(K))
- return false;
- eatWhitespace();
- if (next() != ':')
- return parseError("Expected : after object key");
- eatWhitespace();
- if (!parseExpr(O[std::move(K)]))
- return false;
- eatWhitespace();
- switch (next()) {
- case ',':
- eatWhitespace();
- continue;
- case '}':
- return true;
- default:
- return parseError("Expected , or } after object property");
- }
- }
- }
- default:
- if (isNumber(C)) {
- double Num;
- if (parseNumber(C, Num)) {
- Out = Num;
- return true;
- } else {
- return false;
- }
- }
- return parseError("Expected JSON value");
- }
-}
-
-bool Parser::parseNumber(char First, double &Out) {
- SmallString<24> S;
- S.push_back(First);
- while (isNumber(peek()))
- S.push_back(next());
- char *End;
- Out = std::strtod(S.c_str(), &End);
- return End == S.end() || parseError("Invalid number");
-}
-
-bool Parser::parseString(std::string &Out) {
- // leading quote was already consumed.
- for (char C = next(); C != '"'; C = next()) {
- if (LLVM_UNLIKELY(P == End))
- return parseError("Unterminated string");
- if (LLVM_UNLIKELY((C & 0x1f) == C))
- return parseError("Control character in string");
- if (LLVM_LIKELY(C != '\\')) {
- Out.push_back(C);
- continue;
- }
- // Handle escape sequence.
- switch (C = next()) {
- case '"':
- case '\\':
- case '/':
- Out.push_back(C);
- break;
- case 'b':
- Out.push_back('\b');
- break;
- case 'f':
- Out.push_back('\f');
- break;
- case 'n':
- Out.push_back('\n');
- break;
- case 'r':
- Out.push_back('\r');
- break;
- case 't':
- Out.push_back('\t');
- break;
- case 'u':
- if (!parseUnicode(Out))
- return false;
- break;
- default:
- return parseError("Invalid escape sequence");
- }
- }
- return true;
-}
-
-void Parser::encodeUtf8(uint32_t Rune, std::string &Out) {
- if (Rune <= 0x7F) {
- Out.push_back(Rune & 0x7F);
- } else if (Rune <= 0x7FF) {
- uint8_t FirstByte = 0xC0 | ((Rune & 0x7C0) >> 6);
- uint8_t SecondByte = 0x80 | (Rune & 0x3F);
- Out.push_back(FirstByte);
- Out.push_back(SecondByte);
- } else if (Rune <= 0xFFFF) {
- uint8_t FirstByte = 0xE0 | ((Rune & 0xF000) >> 12);
- uint8_t SecondByte = 0x80 | ((Rune & 0xFC0) >> 6);
- uint8_t ThirdByte = 0x80 | (Rune & 0x3F);
- Out.push_back(FirstByte);
- Out.push_back(SecondByte);
- Out.push_back(ThirdByte);
- } else if (Rune <= 0x10FFFF) {
- uint8_t FirstByte = 0xF0 | ((Rune & 0x1F0000) >> 18);
- uint8_t SecondByte = 0x80 | ((Rune & 0x3F000) >> 12);
- uint8_t ThirdByte = 0x80 | ((Rune & 0xFC0) >> 6);
- uint8_t FourthByte = 0x80 | (Rune & 0x3F);
- Out.push_back(FirstByte);
- Out.push_back(SecondByte);
- Out.push_back(ThirdByte);
- Out.push_back(FourthByte);
- } else {
- llvm_unreachable("Invalid codepoint");
- }
-}
-
-// Parse a \uNNNN escape sequence, the \u have already been consumed.
-// May parse multiple escapes in the presence of surrogate pairs.
-bool Parser::parseUnicode(std::string &Out) {
- // Note that invalid unicode is not a JSON error. It gets replaced by U+FFFD.
- auto Invalid = [&] { Out.append(/* UTF-8 */ {'\xef', '\xbf', '\xbd'}); };
- auto Parse4Hex = [this](uint16_t &Out) {
- Out = 0;
- char Bytes[] = {next(), next(), next(), next()};
- for (unsigned char C : Bytes) {
- if (!std::isxdigit(C))
- return parseError("Invalid \\u escape sequence");
- Out <<= 4;
- Out |= (C > '9') ? (C & ~0x20) - 'A' + 10 : (C - '0');
- }
- return true;
- };
- uint16_t First;
- if (!Parse4Hex(First))
- return false;
-
- // We loop to allow proper surrogate-pair error handling.
- while (true) {
- if (LLVM_LIKELY(First < 0xD800 || First >= 0xE000)) { // BMP.
- encodeUtf8(First, Out);
- return true;
- }
-
- if (First >= 0xDC00) {
- Invalid(); // Lone trailing surrogate.
- return true;
- }
-
- // We have a leading surrogate, and need a trailing one.
- // Don't advance P: a lone surrogate is valid JSON (but invalid unicode)
- if (P + 2 > End || *P != '\\' || *(P + 1) != 'u') {
- Invalid(); // Lone leading not followed by \u...
- return true;
- }
- P += 2;
- uint16_t Second;
- if (!Parse4Hex(Second))
- return false;
- if (Second < 0xDC00 || Second >= 0xE000) {
- Invalid(); // Leading surrogate not followed by trailing.
- First = Second; // Second escape still needs to be processed.
- continue;
- }
-
- // Valid surrogate pair.
- encodeUtf8(0x10000 | ((First - 0xD800) << 10) | (Second - 0xDC00), Out);
- return true;
- }
-}
-
-bool Parser::parseError(const char *Msg) {
- int Line = 1;
- const char *StartOfLine = Start;
- for (const char *X = Start; X < P; ++X) {
- if (*X == 0x0A) {
- ++Line;
- StartOfLine = X + 1;
- }
- }
- Err.emplace(
- llvm::make_unique<ParseError>(Msg, Line, P - StartOfLine, P - Start));
- return false;
-}
-} // namespace
-
-Expected<Expr> parse(StringRef JSON) {
- Parser P(JSON);
- json::Expr E = nullptr;
- if (P.parseExpr(E))
- if (P.assertEnd())
- return std::move(E);
- return P.takeError();
-}
-char ParseError::ID = 0;
-
-} // namespace json
-} // namespace clangd
-} // namespace clang
-
-namespace {
-void quote(llvm::raw_ostream &OS, llvm::StringRef S) {
- OS << '\"';
- for (unsigned char C : S) {
- if (C == 0x22 || C == 0x5C)
- OS << '\\';
- if (C >= 0x20) {
- OS << C;
- continue;
- }
- OS << '\\';
- switch (C) {
- // A few characters are common enough to make short escapes worthwhile.
- case '\t':
- OS << 't';
- break;
- case '\n':
- OS << 'n';
- break;
- case '\r':
- OS << 'r';
- break;
- default:
- OS << 'u';
- llvm::write_hex(OS, C, llvm::HexPrintStyle::Lower, 4);
- break;
- }
- }
- OS << '\"';
-}
-
-enum IndenterAction {
- Indent,
- Outdent,
- Newline,
- Space,
-};
-} // namespace
-
-// Prints JSON. The indenter can be used to control formatting.
-template <typename Indenter>
-void clang::clangd::json::Expr::print(raw_ostream &OS,
- const Indenter &I) const {
- switch (Type) {
- case T_Null:
- OS << "null";
- break;
- case T_Boolean:
- OS << (as<bool>() ? "true" : "false");
- break;
- case T_Number:
- OS << format("%g", as<double>());
- break;
- case T_StringRef:
- quote(OS, as<StringRef>());
- break;
- case T_String:
- quote(OS, as<std::string>());
- break;
- case T_Object: {
- bool Comma = false;
- OS << '{';
- I(Indent);
- for (const auto &P : as<Expr::ObjectExpr>()) {
- if (Comma)
- OS << ',';
- Comma = true;
- I(Newline);
- quote(OS, P.first);
- OS << ':';
- I(Space);
- P.second.print(OS, I);
- }
- I(Outdent);
- if (Comma)
- I(Newline);
- OS << '}';
- break;
- }
- case T_Array: {
- bool Comma = false;
- OS << '[';
- I(Indent);
- for (const auto &E : as<Expr::ArrayExpr>()) {
- if (Comma)
- OS << ',';
- Comma = true;
- I(Newline);
- E.print(OS, I);
- }
- I(Outdent);
- if (Comma)
- I(Newline);
- OS << ']';
- break;
- }
- }
-}
-
-namespace clang {
-namespace clangd {
-namespace json {
-llvm::raw_ostream &operator<<(raw_ostream &OS, const Expr &E) {
- E.print(OS, [](IndenterAction A) { /*ignore*/ });
- return OS;
-}
-
-bool operator==(const Expr &L, const Expr &R) {
- if (L.kind() != R.kind())
- return false;
- switch (L.kind()) {
- case Expr::Null:
- return *L.asNull() == *R.asNull();
- case Expr::Boolean:
- return *L.asBoolean() == *R.asBoolean();
- case Expr::Number:
- return *L.asNumber() == *R.asNumber();
- case Expr::String:
- return *L.asString() == *R.asString();
- case Expr::Array:
- return *L.asArray() == *R.asArray();
- case Expr::Object:
- return *L.asObject() == *R.asObject();
- }
- llvm_unreachable("Unknown expression kind");
-}
-} // namespace json
-} // namespace clangd
-} // namespace clang
-
-void llvm::format_provider<clang::clangd::json::Expr>::format(
- const clang::clangd::json::Expr &E, raw_ostream &OS, StringRef Options) {
- if (Options.empty()) {
- OS << E;
- return;
- }
- unsigned IndentAmount = 0;
- if (Options.getAsInteger(/*Radix=*/10, IndentAmount))
- assert(false && "json::Expr format options should be an integer");
- unsigned IndentLevel = 0;
- E.print(OS, [&](IndenterAction A) {
- switch (A) {
- case Newline:
- OS << '\n';
- OS.indent(IndentLevel);
- break;
- case Space:
- OS << ' ';
- break;
- case Indent:
- IndentLevel += IndentAmount;
- break;
- case Outdent:
- IndentLevel -= IndentAmount;
- break;
- };
- });
-}
OpenPOWER on IntegriCloud