summaryrefslogtreecommitdiffstats
path: root/clang-tools-extra/clangd/JSONExpr.h
diff options
context:
space:
mode:
Diffstat (limited to 'clang-tools-extra/clangd/JSONExpr.h')
-rw-r--r--clang-tools-extra/clangd/JSONExpr.h586
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
OpenPOWER on IntegriCloud