blob: b6af3f1fe30a56f0b9d571a94a8db84a96add4f9 [file] [log] [blame]
Sam McCalladbaebc2017-11-21 16:00:53 +00001//===--- JSONExpr.h - JSON expressions, parsing and serialization - C++ -*-===//
Sam McCalldd0566b2017-11-06 15:40:30 +00002//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===---------------------------------------------------------------------===//
9
Sam McCalladbaebc2017-11-21 16:00:53 +000010// FIXME: rename to JSON.h now that the scope is wider?
11
Sam McCalldd0566b2017-11-06 15:40:30 +000012#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_JSON_H
13#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_JSON_H
14
15#include <map>
16
17#include "llvm/ADT/SmallVector.h"
18#include "llvm/ADT/StringRef.h"
Sam McCalladbaebc2017-11-21 16:00:53 +000019#include "llvm/Support/Error.h"
Sam McCalldd0566b2017-11-06 15:40:30 +000020#include "llvm/Support/FormatVariadic.h"
21#include "llvm/Support/raw_ostream.h"
22
23namespace clang {
24namespace clangd {
25namespace json {
26
Sam McCalladbaebc2017-11-21 16:00:53 +000027// An Expr is an JSON value of unknown type.
Sam McCalldd0566b2017-11-06 15:40:30 +000028// They can be copied, but should generally be moved.
29//
Sam McCalladbaebc2017-11-21 16:00:53 +000030// === Composing expressions ===
31//
32// You can implicitly construct Exprs from:
Sam McCalldd0566b2017-11-06 15:40:30 +000033// - strings: std::string, SmallString, formatv, StringRef, char*
34// (char*, and StringRef are references, not copies!)
35// - numbers
36// - booleans
37// - null: nullptr
38// - arrays: {"foo", 42.0, false}
39// - serializable things: any T with a T::unparse(const T&) -> Expr
40//
41// They can also be constructed from object/array helpers:
42// - json::obj is a type like map<StringExpr, Expr>
43// - json::ary is a type like vector<Expr>
44// These can be list-initialized, or used to build up collections in a loop.
45// json::ary(Collection) converts all items in a collection to Exprs.
46//
Sam McCalladbaebc2017-11-21 16:00:53 +000047// === Inspecting expressions ===
48//
49// Each Expr is one of the JSON kinds:
50// null (nullptr_t)
51// boolean (bool)
52// number (double)
53// string (StringRef)
54// array (json::ary)
55// object (json::obj)
56//
57// The kind can be queried directly, or implicitly via the typed accessors:
Sam McCall1bb272b2017-11-28 09:25:09 +000058// if (Optional<StringRef> S = E.asString()
Sam McCalladbaebc2017-11-21 16:00:53 +000059// assert(E.kind() == Expr::String);
60//
61// Array and Object also have typed indexing accessors for easy traversal:
62// Expected<Expr> E = parse(R"( {"options": {"font": "sans-serif"}} )");
Sam McCall1bb272b2017-11-28 09:25:09 +000063// if (json::obj* O = E->asObject())
64// if (json::obj* Opts = O->getObject("options"))
65// if (Optional<StringRef> Font = Opts->getString("font"))
Sam McCalladbaebc2017-11-21 16:00:53 +000066// assert(Opts->at("font").kind() == Expr::String);
67//
68// === Serialization ===
69//
Sam McCalldd0566b2017-11-06 15:40:30 +000070// Exprs can be serialized to JSON:
71// 1) raw_ostream << Expr // Basic formatting.
72// 2) raw_ostream << formatv("{0}", Expr) // Basic formatting.
73// 3) raw_ostream << formatv("{0:2}", Expr) // Pretty-print with indent 2.
Sam McCalladbaebc2017-11-21 16:00:53 +000074//
75// And parsed:
76// Expected<Expr> E = json::parse("[1, 2, null]");
77// assert(E && E->kind() == Expr::Array);
Sam McCalldd0566b2017-11-06 15:40:30 +000078class Expr {
79public:
Sam McCalladbaebc2017-11-21 16:00:53 +000080 enum Kind {
81 Null,
82 Boolean,
83 Number,
84 String,
85 Array,
86 Object,
87 };
88 class ObjectExpr;
Sam McCalldd0566b2017-11-06 15:40:30 +000089 class ObjectKey;
Sam McCalladbaebc2017-11-21 16:00:53 +000090 class ArrayExpr;
Sam McCalldd0566b2017-11-06 15:40:30 +000091
92 // It would be nice to have Expr() be null. But that would make {} null too...
93 Expr(const Expr &M) { copyFrom(M); }
94 Expr(Expr &&M) { moveFrom(std::move(M)); }
95 // "cheating" move-constructor for moving from initializer_list.
96 Expr(const Expr &&M) { moveFrom(std::move(M)); }
Sam McCalladbaebc2017-11-21 16:00:53 +000097 Expr(std::initializer_list<Expr> Elements) : Expr(ArrayExpr(Elements)) {}
98 Expr(ArrayExpr &&Elements) : Type(T_Array) {
99 create<ArrayExpr>(std::move(Elements));
100 }
101 Expr(ObjectExpr &&Properties) : Type(T_Object) {
102 create<ObjectExpr>(std::move(Properties));
Sam McCalldd0566b2017-11-06 15:40:30 +0000103 }
104 // Strings: types with value semantics.
105 Expr(std::string &&V) : Type(T_String) { create<std::string>(std::move(V)); }
106 Expr(const std::string &V) : Type(T_String) { create<std::string>(V); }
107 Expr(const llvm::SmallVectorImpl<char> &V) : Type(T_String) {
108 create<std::string>(V.begin(), V.end());
109 }
110 Expr(const llvm::formatv_object_base &V) : Expr(V.str()){};
111 // Strings: types with reference semantics.
112 Expr(llvm::StringRef V) : Type(T_StringRef) { create<llvm::StringRef>(V); }
113 Expr(const char *V) : Type(T_StringRef) { create<llvm::StringRef>(V); }
114 Expr(std::nullptr_t) : Type(T_Null) {}
115 // Prevent implicit conversions to boolean.
116 template <typename T, typename = typename std::enable_if<
117 std::is_same<T, bool>::value>::type>
118 Expr(T B) : Type(T_Boolean) {
119 create<bool>(B);
120 }
121 // Numbers: arithmetic types that are not boolean.
122 template <
123 typename T,
124 typename = typename std::enable_if<std::is_arithmetic<T>::value>::type,
125 typename = typename std::enable_if<std::integral_constant<
126 bool, !std::is_same<T, bool>::value>::value>::type>
127 Expr(T D) : Type(T_Number) {
128 create<double>(D);
129 }
130 // Types with a static T::unparse function returning an Expr.
131 // FIXME: should this be a free unparse() function found by ADL?
132 template <typename T,
133 typename = typename std::enable_if<std::is_same<
134 Expr, decltype(T::unparse(*(const T *)nullptr))>::value>>
135 Expr(const T &V) : Expr(T::unparse(V)) {}
136
137 Expr &operator=(const Expr &M) {
138 destroy();
139 copyFrom(M);
140 return *this;
141 }
142 Expr &operator=(Expr &&M) {
143 destroy();
144 moveFrom(std::move(M));
145 return *this;
146 }
147 ~Expr() { destroy(); }
148
Sam McCalladbaebc2017-11-21 16:00:53 +0000149 Kind kind() const {
150 switch (Type) {
151 case T_Null:
152 return Null;
153 case T_Boolean:
154 return Boolean;
155 case T_Number:
156 return Number;
157 case T_String:
158 case T_StringRef:
159 return String;
160 case T_Object:
161 return Object;
162 case T_Array:
163 return Array;
164 }
Aaron Ballmanfeeb0b72017-11-21 22:24:13 +0000165 llvm_unreachable("Unknown kind");
Sam McCalladbaebc2017-11-21 16:00:53 +0000166 }
167
168 // Typed accessors return None/nullptr if the Expr is not of this type.
Sam McCall1bb272b2017-11-28 09:25:09 +0000169 llvm::Optional<std::nullptr_t> asNull() const {
Sam McCalladbaebc2017-11-21 16:00:53 +0000170 if (LLVM_LIKELY(Type == T_Null))
171 return nullptr;
172 return llvm::None;
173 }
Sam McCall1bb272b2017-11-28 09:25:09 +0000174 llvm::Optional<bool> asBoolean() const {
175 if (LLVM_LIKELY(Type == T_Boolean))
Sam McCalladbaebc2017-11-21 16:00:53 +0000176 return as<bool>();
177 return llvm::None;
178 }
Sam McCall1bb272b2017-11-28 09:25:09 +0000179 llvm::Optional<double> asNumber() const {
Sam McCalladbaebc2017-11-21 16:00:53 +0000180 if (LLVM_LIKELY(Type == T_Number))
181 return as<double>();
182 return llvm::None;
183 }
Sam McCall1bb272b2017-11-28 09:25:09 +0000184 llvm::Optional<llvm::StringRef> asString() const {
Sam McCalladbaebc2017-11-21 16:00:53 +0000185 if (Type == T_String)
186 return llvm::StringRef(as<std::string>());
187 if (LLVM_LIKELY(Type == T_StringRef))
188 return as<llvm::StringRef>();
189 return llvm::None;
190 }
Sam McCall1bb272b2017-11-28 09:25:09 +0000191 const ObjectExpr *asObject() const {
Sam McCalladbaebc2017-11-21 16:00:53 +0000192 return LLVM_LIKELY(Type == T_Object) ? &as<ObjectExpr>() : nullptr;
193 }
Sam McCall1bb272b2017-11-28 09:25:09 +0000194 ObjectExpr *asObject() {
Sam McCalladbaebc2017-11-21 16:00:53 +0000195 return LLVM_LIKELY(Type == T_Object) ? &as<ObjectExpr>() : nullptr;
196 }
Sam McCall1bb272b2017-11-28 09:25:09 +0000197 const ArrayExpr *asArray() const {
Sam McCalladbaebc2017-11-21 16:00:53 +0000198 return LLVM_LIKELY(Type == T_Array) ? &as<ArrayExpr>() : nullptr;
199 }
Sam McCall1bb272b2017-11-28 09:25:09 +0000200 ArrayExpr *asArray() {
Sam McCalladbaebc2017-11-21 16:00:53 +0000201 return LLVM_LIKELY(Type == T_Array) ? &as<ArrayExpr>() : nullptr;
202 }
203
Sam McCalldd0566b2017-11-06 15:40:30 +0000204 friend llvm::raw_ostream &operator<<(llvm::raw_ostream &, const Expr &);
205
206private:
207 void destroy();
208 void copyFrom(const Expr &M);
209 // We allow moving from *const* Exprs, by marking all members as mutable!
210 // This hack is needed to support initializer-list syntax efficiently.
211 // (std::initializer_list<T> is a container of const T).
212 void moveFrom(const Expr &&M);
213
214 template <typename T, typename... U> void create(U &&... V) {
215 new (&as<T>()) T(std::forward<U>(V)...);
216 }
217 template <typename T> T &as() const {
218 return *reinterpret_cast<T *>(Union.buffer);
219 }
220
221 template <typename Indenter>
222 void print(llvm::raw_ostream &, const Indenter &) const;
223 friend struct llvm::format_provider<clang::clangd::json::Expr>;
224
225 enum ExprType : char {
226 T_Null,
227 T_Boolean,
228 T_Number,
229 T_StringRef,
230 T_String,
231 T_Object,
232 T_Array,
233 };
234 mutable ExprType Type;
235
236public:
Sam McCalladbaebc2017-11-21 16:00:53 +0000237 // ObjectKey is a used to capture keys in Expr::ObjectExpr. Like Expr but:
Sam McCalldd0566b2017-11-06 15:40:30 +0000238 // - only strings are allowed
Sam McCalldd0566b2017-11-06 15:40:30 +0000239 // - it's optimized for the string literal case (Owned == nullptr)
240 class ObjectKey {
241 public:
242 ObjectKey(const char *S) : Data(S) {}
243 ObjectKey(llvm::StringRef S) : Data(S) {}
244 ObjectKey(std::string &&V)
245 : Owned(new std::string(std::move(V))), Data(*Owned) {}
246 ObjectKey(const std::string &V) : Owned(new std::string(V)), Data(*Owned) {}
247 ObjectKey(const llvm::SmallVectorImpl<char> &V)
248 : ObjectKey(std::string(V.begin(), V.end())) {}
249 ObjectKey(const llvm::formatv_object_base &V) : ObjectKey(V.str()) {}
250
251 ObjectKey(const ObjectKey &C) { *this = C; }
Sam McCallc2055482017-11-07 08:57:54 +0000252 ObjectKey(ObjectKey &&C) : ObjectKey(static_cast<const ObjectKey &&>(C)) {}
Sam McCalldd0566b2017-11-06 15:40:30 +0000253 ObjectKey &operator=(const ObjectKey &C) {
254 if (C.Owned) {
255 Owned.reset(new std::string(*C.Owned));
256 Data = *Owned;
257 } else {
258 Data = C.Data;
259 }
260 return *this;
261 }
262 ObjectKey &operator=(ObjectKey &&) = default;
263
264 operator llvm::StringRef() const { return Data; }
265
266 friend bool operator<(const ObjectKey &L, const ObjectKey &R) {
267 return L.Data < R.Data;
268 }
269
270 // "cheating" move-constructor for moving from initializer_list.
271 ObjectKey(const ObjectKey &&V) {
272 Owned = std::move(V.Owned);
273 Data = V.Data;
274 }
275
276 private:
277 mutable std::unique_ptr<std::string> Owned; // mutable for cheating.
278 llvm::StringRef Data;
279 };
280
Sam McCalladbaebc2017-11-21 16:00:53 +0000281 class ObjectExpr : public std::map<ObjectKey, Expr> {
Sam McCalldd0566b2017-11-06 15:40:30 +0000282 public:
Sam McCalladbaebc2017-11-21 16:00:53 +0000283 explicit ObjectExpr() {}
Sam McCalldd0566b2017-11-06 15:40:30 +0000284 // Use a custom struct for list-init, because pair forces extra copies.
285 struct KV;
Sam McCalladbaebc2017-11-21 16:00:53 +0000286 explicit ObjectExpr(std::initializer_list<KV> Properties);
Sam McCalldd0566b2017-11-06 15:40:30 +0000287
288 // Allow [] as if Expr was default-constructible as null.
289 Expr &operator[](const ObjectKey &K) {
290 return emplace(K, Expr(nullptr)).first->second;
291 }
292 Expr &operator[](ObjectKey &&K) {
293 return emplace(std::move(K), Expr(nullptr)).first->second;
294 }
Sam McCall1bb272b2017-11-28 09:25:09 +0000295
296 // Look up a property, returning nullptr if it doesn't exist.
297 json::Expr *get(const ObjectKey &K) {
298 auto I = find(K);
299 if (I == end())
300 return nullptr;
301 return &I->second;
302 }
303 const json::Expr *get(const ObjectKey &K) const {
304 auto I = find(K);
305 if (I == end())
306 return nullptr;
307 return &I->second;
308 }
309 // Typed accessors return None/nullptr if
310 // - the property doesn't exist
311 // - or it has the wrong type
312 llvm::Optional<std::nullptr_t> getNull(const ObjectKey &K) const {
313 if (auto *V = get(K))
314 return V->asNull();
315 return llvm::None;
316 }
317 llvm::Optional<bool> getBoolean(const ObjectKey &K) const {
318 if (auto *V = get(K))
319 return V->asBoolean();
320 return llvm::None;
321 }
322 llvm::Optional<double> getNumber(const ObjectKey &K) const {
323 if (auto *V = get(K))
324 return V->asNumber();
325 return llvm::None;
326 }
327 llvm::Optional<llvm::StringRef> getString(const ObjectKey &K) const {
328 if (auto *V = get(K))
329 return V->asString();
330 return llvm::None;
331 }
332 const ObjectExpr *getObject(const ObjectKey &K) const {
333 if (auto *V = get(K))
334 return V->asObject();
335 return nullptr;
336 }
337 ObjectExpr *getObject(const ObjectKey &K) {
338 if (auto *V = get(K))
339 return V->asObject();
340 return nullptr;
341 }
342 const ArrayExpr *getArray(const ObjectKey &K) const {
343 if (auto *V = get(K))
344 return V->asArray();
345 return nullptr;
346 }
347 ArrayExpr *getArray(const ObjectKey &K) {
348 if (auto *V = get(K))
349 return V->asArray();
350 return nullptr;
351 }
Sam McCalldd0566b2017-11-06 15:40:30 +0000352 };
353
Sam McCalladbaebc2017-11-21 16:00:53 +0000354 class ArrayExpr : public std::vector<Expr> {
Sam McCalldd0566b2017-11-06 15:40:30 +0000355 public:
Sam McCalladbaebc2017-11-21 16:00:53 +0000356 explicit ArrayExpr() {}
357 explicit ArrayExpr(std::initializer_list<Expr> Elements) {
Sam McCalldd0566b2017-11-06 15:40:30 +0000358 reserve(Elements.size());
359 for (const Expr &V : Elements)
360 emplace_back(std::move(V));
361 };
Sam McCalladbaebc2017-11-21 16:00:53 +0000362 template <typename Collection> explicit ArrayExpr(const Collection &C) {
Sam McCalldd0566b2017-11-06 15:40:30 +0000363 for (const auto &V : C)
364 emplace_back(V);
365 }
Sam McCall1bb272b2017-11-28 09:25:09 +0000366
367 // Typed accessors return None/nullptr if the element has the wrong type.
368 llvm::Optional<std::nullptr_t> getNull(size_t I) const {
369 return (*this)[I].asNull();
370 }
371 llvm::Optional<bool> getBoolean(size_t I) const {
372 return (*this)[I].asBoolean();
373 }
374 llvm::Optional<double> getNumber(size_t I) const {
375 return (*this)[I].asNumber();
376 }
377 llvm::Optional<llvm::StringRef> getString(size_t I) const {
378 return (*this)[I].asString();
379 }
380 const ObjectExpr *getObject(size_t I) const {
381 return (*this)[I].asObject();
382 }
383 ObjectExpr *getObject(size_t I) { return (*this)[I].asObject(); }
384 const ArrayExpr *getArray(size_t I) const { return (*this)[I].asArray(); }
385 ArrayExpr *getArray(size_t I) { return (*this)[I].asArray(); }
Sam McCalldd0566b2017-11-06 15:40:30 +0000386 };
387
388private:
389 mutable llvm::AlignedCharArrayUnion<bool, double, llvm::StringRef,
Sam McCalladbaebc2017-11-21 16:00:53 +0000390 std::string, ArrayExpr, ObjectExpr>
Sam McCalldd0566b2017-11-06 15:40:30 +0000391 Union;
392};
393
Sam McCalladbaebc2017-11-21 16:00:53 +0000394bool operator==(const Expr &, const Expr &);
395inline bool operator!=(const Expr &L, const Expr &R) { return !(L == R); }
396inline bool operator==(const Expr::ObjectKey &L, const Expr::ObjectKey &R) {
397 return llvm::StringRef(L) == llvm::StringRef(R);
398}
399inline bool operator!=(const Expr::ObjectKey &L, const Expr::ObjectKey &R) {
400 return !(L == R);
401}
402
403struct Expr::ObjectExpr::KV {
Sam McCalldd0566b2017-11-06 15:40:30 +0000404 ObjectKey K;
405 Expr V;
406};
407
Sam McCalladbaebc2017-11-21 16:00:53 +0000408inline Expr::ObjectExpr::ObjectExpr(std::initializer_list<KV> Properties) {
Sam McCalldd0566b2017-11-06 15:40:30 +0000409 for (const auto &P : Properties)
410 emplace(std::move(P.K), std::move(P.V));
411}
412
413// Give Expr::{Object,Array} more convenient names for literal use.
Sam McCalladbaebc2017-11-21 16:00:53 +0000414using obj = Expr::ObjectExpr;
415using ary = Expr::ArrayExpr;
416
417llvm::Expected<Expr> parse(llvm::StringRef JSON);
418
419class ParseError : public llvm::ErrorInfo<ParseError> {
420 const char *Msg;
421 unsigned Line, Column, Offset;
422
423public:
424 static char ID;
425 ParseError(const char *Msg, unsigned Line, unsigned Column, unsigned Offset)
426 : Msg(Msg), Line(Line), Column(Column), Offset(Offset) {}
427 void log(llvm::raw_ostream &OS) const override {
428 OS << llvm::formatv("[{0}:{1}, byte={2}]: {3}", Line, Column, Offset, Msg);
429 }
430 std::error_code convertToErrorCode() const override {
431 return llvm::inconvertibleErrorCode();
432 }
433};
Sam McCalldd0566b2017-11-06 15:40:30 +0000434
435} // namespace json
436} // namespace clangd
437} // namespace clang
438
439namespace llvm {
440template <> struct format_provider<clang::clangd::json::Expr> {
441 static void format(const clang::clangd::json::Expr &, raw_ostream &,
442 StringRef);
443};
444} // namespace llvm
445
446#endif