diff options
Diffstat (limited to 'clang-tools-extra/clangd/JSONExpr.h')
| -rw-r--r-- | clang-tools-extra/clangd/JSONExpr.h | 586 |
1 files changed, 0 insertions, 586 deletions
diff --git a/clang-tools-extra/clangd/JSONExpr.h b/clang-tools-extra/clangd/JSONExpr.h deleted file mode 100644 index 419932f09a5..00000000000 --- a/clang-tools-extra/clangd/JSONExpr.h +++ /dev/null @@ -1,586 +0,0 @@ -//===--- JSONExpr.h - 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. -// -//===---------------------------------------------------------------------===// - -// FIXME: rename to JSON.h now that the scope is wider? - -#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_JSON_H -#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_JSON_H - -#include "llvm/ADT/SmallVector.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/FormatVariadic.h" -#include "llvm/Support/raw_ostream.h" -#include <map> - -namespace clang { -namespace clangd { -namespace json { -class Expr; -template <typename T> Expr toJSON(const llvm::Optional<T> &Opt); - -// An Expr is an JSON value of unknown type. -// They can be copied, but should generally be moved. -// -// === Composing expressions === -// -// You can implicitly construct Exprs from: -// - strings: std::string, SmallString, formatv, StringRef, char* -// (char*, and StringRef are references, not copies!) -// - numbers -// - booleans -// - null: nullptr -// - arrays: {"foo", 42.0, false} -// - serializable things: types with toJSON(const T&)->Expr, found by ADL -// -// They can also be constructed from object/array helpers: -// - json::obj is a type like map<StringExpr, Expr> -// - json::ary is a type like vector<Expr> -// These can be list-initialized, or used to build up collections in a loop. -// json::ary(Collection) converts all items in a collection to Exprs. -// -// === Inspecting expressions === -// -// Each Expr is one of the JSON kinds: -// null (nullptr_t) -// boolean (bool) -// number (double) -// string (StringRef) -// array (json::ary) -// object (json::obj) -// -// The kind can be queried directly, or implicitly via the typed accessors: -// if (Optional<StringRef> S = E.asString() -// assert(E.kind() == Expr::String); -// -// Array and Object also have typed indexing accessors for easy traversal: -// Expected<Expr> E = parse(R"( {"options": {"font": "sans-serif"}} )"); -// if (json::obj* O = E->asObject()) -// if (json::obj* Opts = O->getObject("options")) -// if (Optional<StringRef> Font = Opts->getString("font")) -// assert(Opts->at("font").kind() == Expr::String); -// -// === Converting expressions to objects === -// -// The convention is to have a deserializer function findable via ADL: -// fromJSON(const json::Expr&, T&)->bool -// Deserializers are provided for: -// - bool -// - int -// - double -// - std::string -// - vector<T>, where T is deserializable -// - map<string, T>, where T is deserializable -// - Optional<T>, where T is deserializable -// -// ObjectMapper can help writing fromJSON() functions for object types: -// bool fromJSON(const Expr &E, MyStruct &R) { -// ObjectMapper O(E); -// if (!O || !O.map("mandatory_field", R.MandatoryField)) -// return false; -// O.map("optional_field", R.OptionalField); -// return true; -// } -// -// === Serialization === -// -// Exprs can be serialized to JSON: -// 1) raw_ostream << Expr // Basic formatting. -// 2) raw_ostream << formatv("{0}", Expr) // Basic formatting. -// 3) raw_ostream << formatv("{0:2}", Expr) // Pretty-print with indent 2. -// -// And parsed: -// Expected<Expr> E = json::parse("[1, 2, null]"); -// assert(E && E->kind() == Expr::Array); -class Expr { -public: - enum Kind { - Null, - Boolean, - Number, - String, - Array, - Object, - }; - class ObjectExpr; - class ObjectKey; - class ArrayExpr; - - // It would be nice to have Expr() be null. But that would make {} null too... - Expr(const Expr &M) { copyFrom(M); } - Expr(Expr &&M) { moveFrom(std::move(M)); } - // "cheating" move-constructor for moving from initializer_list. - Expr(const Expr &&M) { moveFrom(std::move(M)); } - Expr(std::initializer_list<Expr> Elements) : Expr(ArrayExpr(Elements)) {} - Expr(ArrayExpr &&Elements) : Type(T_Array) { - create<ArrayExpr>(std::move(Elements)); - } - Expr(ObjectExpr &&Properties) : Type(T_Object) { - create<ObjectExpr>(std::move(Properties)); - } - // Strings: types with value semantics. - Expr(std::string &&V) : Type(T_String) { create<std::string>(std::move(V)); } - Expr(const std::string &V) : Type(T_String) { create<std::string>(V); } - Expr(const llvm::SmallVectorImpl<char> &V) : Type(T_String) { - create<std::string>(V.begin(), V.end()); - } - Expr(const llvm::formatv_object_base &V) : Expr(V.str()){}; - // Strings: types with reference semantics. - Expr(llvm::StringRef V) : Type(T_StringRef) { create<llvm::StringRef>(V); } - Expr(const char *V) : Type(T_StringRef) { create<llvm::StringRef>(V); } - Expr(std::nullptr_t) : Type(T_Null) {} - // Prevent implicit conversions to boolean. - template <typename T, typename = typename std::enable_if< - std::is_same<T, bool>::value>::type> - Expr(T B) : Type(T_Boolean) { - create<bool>(B); - } - // Numbers: arithmetic types that are not boolean. - template < - typename T, - typename = typename std::enable_if<std::is_arithmetic<T>::value>::type, - typename = typename std::enable_if<std::integral_constant< - bool, !std::is_same<T, bool>::value>::value>::type> - Expr(T D) : Type(T_Number) { - create<double>(D); - } - // Types with a toJSON(const T&)->Expr function, found by ADL. - template <typename T, - typename = typename std::enable_if<std::is_same< - Expr, decltype(toJSON(*(const T *)nullptr))>::value>> - Expr(const T &V) : Expr(toJSON(V)) {} - - Expr &operator=(const Expr &M) { - destroy(); - copyFrom(M); - return *this; - } - Expr &operator=(Expr &&M) { - destroy(); - moveFrom(std::move(M)); - return *this; - } - ~Expr() { destroy(); } - - Kind kind() const { - switch (Type) { - case T_Null: - return Null; - case T_Boolean: - return Boolean; - case T_Number: - return Number; - case T_String: - case T_StringRef: - return String; - case T_Object: - return Object; - case T_Array: - return Array; - } - llvm_unreachable("Unknown kind"); - } - - // Typed accessors return None/nullptr if the Expr is not of this type. - llvm::Optional<std::nullptr_t> asNull() const { - if (LLVM_LIKELY(Type == T_Null)) - return nullptr; - return llvm::None; - } - llvm::Optional<bool> asBoolean() const { - if (LLVM_LIKELY(Type == T_Boolean)) - return as<bool>(); - return llvm::None; - } - llvm::Optional<double> asNumber() const { - if (LLVM_LIKELY(Type == T_Number)) - return as<double>(); - return llvm::None; - } - llvm::Optional<int64_t> asInteger() const { - if (LLVM_LIKELY(Type == T_Number)) { - double D = as<double>(); - if (LLVM_LIKELY(std::modf(D, &D) == 0 && - D >= std::numeric_limits<int64_t>::min() && - D <= std::numeric_limits<int64_t>::max())) - return D; - } - return llvm::None; - } - llvm::Optional<llvm::StringRef> asString() const { - if (Type == T_String) - return llvm::StringRef(as<std::string>()); - if (LLVM_LIKELY(Type == T_StringRef)) - return as<llvm::StringRef>(); - return llvm::None; - } - const ObjectExpr *asObject() const { - return LLVM_LIKELY(Type == T_Object) ? &as<ObjectExpr>() : nullptr; - } - ObjectExpr *asObject() { - return LLVM_LIKELY(Type == T_Object) ? &as<ObjectExpr>() : nullptr; - } - const ArrayExpr *asArray() const { - return LLVM_LIKELY(Type == T_Array) ? &as<ArrayExpr>() : nullptr; - } - ArrayExpr *asArray() { - return LLVM_LIKELY(Type == T_Array) ? &as<ArrayExpr>() : nullptr; - } - - friend llvm::raw_ostream &operator<<(llvm::raw_ostream &, const Expr &); - -private: - void destroy(); - void copyFrom(const Expr &M); - // We allow moving from *const* Exprs, by marking all members as mutable! - // This hack is needed to support initializer-list syntax efficiently. - // (std::initializer_list<T> is a container of const T). - void moveFrom(const Expr &&M); - - template <typename T, typename... U> void create(U &&... V) { - new (&as<T>()) T(std::forward<U>(V)...); - } - template <typename T> T &as() const { - return *reinterpret_cast<T *>(Union.buffer); - } - - template <typename Indenter> - void print(llvm::raw_ostream &, const Indenter &) const; - friend struct llvm::format_provider<clang::clangd::json::Expr>; - - enum ExprType : char { - T_Null, - T_Boolean, - T_Number, - T_StringRef, - T_String, - T_Object, - T_Array, - }; - mutable ExprType Type; - -public: - // ObjectKey is a used to capture keys in Expr::ObjectExpr. Like Expr but: - // - only strings are allowed - // - it's optimized for the string literal case (Owned == nullptr) - class ObjectKey { - public: - ObjectKey(const char *S) : Data(S) {} - ObjectKey(llvm::StringRef S) : Data(S) {} - ObjectKey(std::string &&V) - : Owned(new std::string(std::move(V))), Data(*Owned) {} - ObjectKey(const std::string &V) : Owned(new std::string(V)), Data(*Owned) {} - ObjectKey(const llvm::SmallVectorImpl<char> &V) - : ObjectKey(std::string(V.begin(), V.end())) {} - ObjectKey(const llvm::formatv_object_base &V) : ObjectKey(V.str()) {} - - ObjectKey(const ObjectKey &C) { *this = C; } - ObjectKey(ObjectKey &&C) : ObjectKey(static_cast<const ObjectKey &&>(C)) {} - ObjectKey &operator=(const ObjectKey &C) { - if (C.Owned) { - Owned.reset(new std::string(*C.Owned)); - Data = *Owned; - } else { - Data = C.Data; - } - return *this; - } - ObjectKey &operator=(ObjectKey &&) = default; - - operator llvm::StringRef() const { return Data; } - - friend bool operator<(const ObjectKey &L, const ObjectKey &R) { - return L.Data < R.Data; - } - - // "cheating" move-constructor for moving from initializer_list. - ObjectKey(const ObjectKey &&V) { - Owned = std::move(V.Owned); - Data = V.Data; - } - - private: - mutable std::unique_ptr<std::string> Owned; // mutable for cheating. - llvm::StringRef Data; - }; - - class ObjectExpr : public std::map<ObjectKey, Expr> { - public: - explicit ObjectExpr() {} - // Use a custom struct for list-init, because pair forces extra copies. - struct KV; - explicit ObjectExpr(std::initializer_list<KV> Properties); - - // Allow [] as if Expr was default-constructible as null. - Expr &operator[](const ObjectKey &K) { - return emplace(K, Expr(nullptr)).first->second; - } - Expr &operator[](ObjectKey &&K) { - return emplace(std::move(K), Expr(nullptr)).first->second; - } - - // Look up a property, returning nullptr if it doesn't exist. - json::Expr *get(const ObjectKey &K) { - auto I = find(K); - if (I == end()) - return nullptr; - return &I->second; - } - const json::Expr *get(const ObjectKey &K) const { - auto I = find(K); - if (I == end()) - return nullptr; - return &I->second; - } - // Typed accessors return None/nullptr if - // - the property doesn't exist - // - or it has the wrong type - llvm::Optional<std::nullptr_t> getNull(const ObjectKey &K) const { - if (auto *V = get(K)) - return V->asNull(); - return llvm::None; - } - llvm::Optional<bool> getBoolean(const ObjectKey &K) const { - if (auto *V = get(K)) - return V->asBoolean(); - return llvm::None; - } - llvm::Optional<double> getNumber(const ObjectKey &K) const { - if (auto *V = get(K)) - return V->asNumber(); - return llvm::None; - } - llvm::Optional<int64_t> getInteger(const ObjectKey &K) const { - if (auto *V = get(K)) - return V->asInteger(); - return llvm::None; - } - llvm::Optional<llvm::StringRef> getString(const ObjectKey &K) const { - if (auto *V = get(K)) - return V->asString(); - return llvm::None; - } - const ObjectExpr *getObject(const ObjectKey &K) const { - if (auto *V = get(K)) - return V->asObject(); - return nullptr; - } - ObjectExpr *getObject(const ObjectKey &K) { - if (auto *V = get(K)) - return V->asObject(); - return nullptr; - } - const ArrayExpr *getArray(const ObjectKey &K) const { - if (auto *V = get(K)) - return V->asArray(); - return nullptr; - } - ArrayExpr *getArray(const ObjectKey &K) { - if (auto *V = get(K)) - return V->asArray(); - return nullptr; - } - }; - - class ArrayExpr : public std::vector<Expr> { - public: - explicit ArrayExpr() {} - explicit ArrayExpr(std::initializer_list<Expr> Elements) { - reserve(Elements.size()); - for (const Expr &V : Elements) - emplace_back(std::move(V)); - }; - template <typename Collection> explicit ArrayExpr(const Collection &C) { - for (const auto &V : C) - emplace_back(V); - } - - // Typed accessors return None/nullptr if the element has the wrong type. - llvm::Optional<std::nullptr_t> getNull(size_t I) const { - return (*this)[I].asNull(); - } - llvm::Optional<bool> getBoolean(size_t I) const { - return (*this)[I].asBoolean(); - } - llvm::Optional<double> getNumber(size_t I) const { - return (*this)[I].asNumber(); - } - llvm::Optional<int64_t> getInteger(size_t I) const { - return (*this)[I].asInteger(); - } - llvm::Optional<llvm::StringRef> getString(size_t I) const { - return (*this)[I].asString(); - } - const ObjectExpr *getObject(size_t I) const { - return (*this)[I].asObject(); - } - ObjectExpr *getObject(size_t I) { return (*this)[I].asObject(); } - const ArrayExpr *getArray(size_t I) const { return (*this)[I].asArray(); } - ArrayExpr *getArray(size_t I) { return (*this)[I].asArray(); } - }; - -private: - mutable llvm::AlignedCharArrayUnion<bool, double, llvm::StringRef, - std::string, ArrayExpr, ObjectExpr> - Union; -}; - -bool operator==(const Expr &, const Expr &); -inline bool operator!=(const Expr &L, const Expr &R) { return !(L == R); } -inline bool operator==(const Expr::ObjectKey &L, const Expr::ObjectKey &R) { - return llvm::StringRef(L) == llvm::StringRef(R); -} -inline bool operator!=(const Expr::ObjectKey &L, const Expr::ObjectKey &R) { - return !(L == R); -} - -struct Expr::ObjectExpr::KV { - ObjectKey K; - Expr V; -}; - -inline Expr::ObjectExpr::ObjectExpr(std::initializer_list<KV> Properties) { - for (const auto &P : Properties) - emplace(std::move(P.K), std::move(P.V)); -} - -// Give Expr::{Object,Array} more convenient names for literal use. -using obj = Expr::ObjectExpr; -using ary = Expr::ArrayExpr; - -// Standard deserializers. -inline bool fromJSON(const json::Expr &E, std::string &Out) { - if (auto S = E.asString()) { - Out = *S; - return true; - } - return false; -} -inline bool fromJSON(const json::Expr &E, int &Out) { - if (auto S = E.asInteger()) { - Out = *S; - return true; - } - return false; -} -inline bool fromJSON(const json::Expr &E, double &Out) { - if (auto S = E.asNumber()) { - Out = *S; - return true; - } - return false; -} -inline bool fromJSON(const json::Expr &E, bool &Out) { - if (auto S = E.asBoolean()) { - Out = *S; - return true; - } - return false; -} -template <typename T> -bool fromJSON(const json::Expr &E, llvm::Optional<T> &Out) { - if (E.asNull()) { - Out = llvm::None; - return true; - } - T Result; - if (!fromJSON(E, Result)) - return false; - Out = std::move(Result); - return true; -} -template <typename T> bool fromJSON(const json::Expr &E, std::vector<T> &Out) { - if (auto *A = E.asArray()) { - Out.clear(); - Out.resize(A->size()); - for (size_t I = 0; I < A->size(); ++I) - if (!fromJSON((*A)[I], Out[I])) - return false; - return true; - } - return false; -} -template <typename T> -bool fromJSON(const json::Expr &E, std::map<std::string, T> &Out) { - if (auto *O = E.asObject()) { - Out.clear(); - for (const auto &KV : *O) - if (!fromJSON(KV.second, Out[llvm::StringRef(KV.first)])) - return false; - return true; - } - return false; -} - -template <typename T> -json::Expr toJSON(const llvm::Optional<T>& Opt) { - return Opt ? json::Expr(*Opt) : json::Expr(nullptr); -} - -// Helper for mapping JSON objects onto protocol structs. -// See file header for example. -class ObjectMapper { -public: - ObjectMapper(const json::Expr &E) : O(E.asObject()) {} - - // True if the expression is an object. - // Must be checked before calling map(). - operator bool() { return O; } - - // Maps a property to a field, if it exists. - template <typename T> bool map(const char *Prop, T &Out) { - assert(*this && "Must check this is an object before calling map()"); - if (const json::Expr *E = O->get(Prop)) - return fromJSON(*E, Out); - return false; - } - - // Optional requires special handling, because missing keys are OK. - template <typename T> bool map(const char *Prop, llvm::Optional<T> &Out) { - assert(*this && "Must check this is an object before calling map()"); - if (const json::Expr *E = O->get(Prop)) - return fromJSON(*E, Out); - Out = llvm::None; - return true; - } - -private: - const json::obj *O; -}; - -llvm::Expected<Expr> parse(llvm::StringRef JSON); - -class ParseError : public llvm::ErrorInfo<ParseError> { - const char *Msg; - unsigned Line, Column, Offset; - -public: - static char ID; - ParseError(const char *Msg, unsigned Line, unsigned Column, unsigned Offset) - : Msg(Msg), Line(Line), Column(Column), Offset(Offset) {} - void log(llvm::raw_ostream &OS) const override { - OS << llvm::formatv("[{0}:{1}, byte={2}]: {3}", Line, Column, Offset, Msg); - } - std::error_code convertToErrorCode() const override { - return llvm::inconvertibleErrorCode(); - } -}; - -} // namespace json -} // namespace clangd -} // namespace clang - -namespace llvm { -template <> struct format_provider<clang::clangd::json::Expr> { - static void format(const clang::clangd::json::Expr &, raw_ostream &, - StringRef); -}; -} // namespace llvm - -#endif |

