Line data Source code
1 : //===--- JSONExpr.h - JSON expressions, parsing and serialization - C++ -*-===//
2 : //
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 :
10 : // FIXME: rename to JSON.h now that the scope is wider?
11 :
12 : #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_JSON_H
13 : #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_JSON_H
14 :
15 : #include "llvm/ADT/SmallVector.h"
16 : #include "llvm/ADT/StringRef.h"
17 : #include "llvm/Support/Error.h"
18 : #include "llvm/Support/FormatVariadic.h"
19 : #include "llvm/Support/raw_ostream.h"
20 : #include <map>
21 :
22 : namespace clang {
23 : namespace clangd {
24 : namespace json {
25 : class Expr;
26 : template <typename T> Expr toJSON(const llvm::Optional<T> &Opt);
27 :
28 : // An Expr is an JSON value of unknown type.
29 : // They can be copied, but should generally be moved.
30 : //
31 : // === Composing expressions ===
32 : //
33 : // You can implicitly construct Exprs from:
34 : // - strings: std::string, SmallString, formatv, StringRef, char*
35 : // (char*, and StringRef are references, not copies!)
36 : // - numbers
37 : // - booleans
38 : // - null: nullptr
39 : // - arrays: {"foo", 42.0, false}
40 : // - serializable things: types with toJSON(const T&)->Expr, found by ADL
41 : //
42 : // They can also be constructed from object/array helpers:
43 : // - json::obj is a type like map<StringExpr, Expr>
44 : // - json::ary is a type like vector<Expr>
45 : // These can be list-initialized, or used to build up collections in a loop.
46 : // json::ary(Collection) converts all items in a collection to Exprs.
47 : //
48 : // === Inspecting expressions ===
49 : //
50 : // Each Expr is one of the JSON kinds:
51 : // null (nullptr_t)
52 : // boolean (bool)
53 : // number (double)
54 : // string (StringRef)
55 : // array (json::ary)
56 : // object (json::obj)
57 : //
58 : // The kind can be queried directly, or implicitly via the typed accessors:
59 : // if (Optional<StringRef> S = E.asString()
60 : // assert(E.kind() == Expr::String);
61 : //
62 : // Array and Object also have typed indexing accessors for easy traversal:
63 : // Expected<Expr> E = parse(R"( {"options": {"font": "sans-serif"}} )");
64 : // if (json::obj* O = E->asObject())
65 : // if (json::obj* Opts = O->getObject("options"))
66 : // if (Optional<StringRef> Font = Opts->getString("font"))
67 : // assert(Opts->at("font").kind() == Expr::String);
68 : //
69 : // === Converting expressions to objects ===
70 : //
71 : // The convention is to have a deserializer function findable via ADL:
72 : // fromJSON(const json::Expr&, T&)->bool
73 : // Deserializers are provided for:
74 : // - bool
75 : // - int
76 : // - double
77 : // - std::string
78 : // - vector<T>, where T is deserializable
79 : // - map<string, T>, where T is deserializable
80 : // - Optional<T>, where T is deserializable
81 : //
82 : // ObjectMapper can help writing fromJSON() functions for object types:
83 : // bool fromJSON(const Expr &E, MyStruct &R) {
84 : // ObjectMapper O(E);
85 : // if (!O || !O.map("mandatory_field", R.MandatoryField))
86 : // return false;
87 : // O.map("optional_field", R.OptionalField);
88 : // return true;
89 : // }
90 : //
91 : // === Serialization ===
92 : //
93 : // Exprs can be serialized to JSON:
94 : // 1) raw_ostream << Expr // Basic formatting.
95 : // 2) raw_ostream << formatv("{0}", Expr) // Basic formatting.
96 : // 3) raw_ostream << formatv("{0:2}", Expr) // Pretty-print with indent 2.
97 : //
98 : // And parsed:
99 : // Expected<Expr> E = json::parse("[1, 2, null]");
100 : // assert(E && E->kind() == Expr::Array);
101 : class Expr {
102 : public:
103 : enum Kind {
104 : Null,
105 : Boolean,
106 : Number,
107 : String,
108 : Array,
109 : Object,
110 : };
111 : class ObjectExpr;
112 : class ObjectKey;
113 : class ArrayExpr;
114 :
115 : // It would be nice to have Expr() be null. But that would make {} null too...
116 0 : Expr(const Expr &M) { copyFrom(M); }
117 : Expr(Expr &&M) { moveFrom(std::move(M)); }
118 : // "cheating" move-constructor for moving from initializer_list.
119 0 : Expr(const Expr &&M) { moveFrom(std::move(M)); }
120 0 : Expr(std::initializer_list<Expr> Elements) : Expr(ArrayExpr(Elements)) {}
121 0 : Expr(ArrayExpr &&Elements) : Type(T_Array) {
122 : create<ArrayExpr>(std::move(Elements));
123 : }
124 0 : Expr(ObjectExpr &&Properties) : Type(T_Object) {
125 : create<ObjectExpr>(std::move(Properties));
126 : }
127 : // Strings: types with value semantics.
128 : Expr(std::string &&V) : Type(T_String) { create<std::string>(std::move(V)); }
129 0 : Expr(const std::string &V) : Type(T_String) { create<std::string>(V); }
130 : Expr(const llvm::SmallVectorImpl<char> &V) : Type(T_String) {
131 : create<std::string>(V.begin(), V.end());
132 : }
133 : Expr(const llvm::formatv_object_base &V) : Expr(V.str()){};
134 : // Strings: types with reference semantics.
135 0 : Expr(llvm::StringRef V) : Type(T_StringRef) { create<llvm::StringRef>(V); }
136 0 : Expr(const char *V) : Type(T_StringRef) { create<llvm::StringRef>(V); }
137 0 : Expr(std::nullptr_t) : Type(T_Null) {}
138 : // Prevent implicit conversions to boolean.
139 : template <typename T, typename = typename std::enable_if<
140 : std::is_same<T, bool>::value>::type>
141 0 : Expr(T B) : Type(T_Boolean) {
142 : create<bool>(B);
143 : }
144 : // Numbers: arithmetic types that are not boolean.
145 : template <
146 : typename T,
147 : typename = typename std::enable_if<std::is_arithmetic<T>::value>::type,
148 : typename = typename std::enable_if<std::integral_constant<
149 : bool, !std::is_same<T, bool>::value>::value>::type>
150 0 : Expr(T D) : Type(T_Number) {
151 : create<double>(D);
152 : }
153 : // Types with a toJSON(const T&)->Expr function, found by ADL.
154 : template <typename T,
155 : typename = typename std::enable_if<std::is_same<
156 : Expr, decltype(toJSON(*(const T *)nullptr))>::value>>
157 0 : Expr(const T &V) : Expr(toJSON(V)) {}
158 :
159 : Expr &operator=(const Expr &M) {
160 : destroy();
161 : copyFrom(M);
162 : return *this;
163 : }
164 : Expr &operator=(Expr &&M) {
165 : destroy();
166 : moveFrom(std::move(M));
167 : return *this;
168 : }
169 0 : ~Expr() { destroy(); }
170 :
171 : Kind kind() const {
172 : switch (Type) {
173 : case T_Null:
174 : return Null;
175 : case T_Boolean:
176 : return Boolean;
177 : case T_Number:
178 : return Number;
179 : case T_String:
180 : case T_StringRef:
181 : return String;
182 : case T_Object:
183 : return Object;
184 : case T_Array:
185 : return Array;
186 : }
187 : llvm_unreachable("Unknown kind");
188 : }
189 :
190 : // Typed accessors return None/nullptr if the Expr is not of this type.
191 : llvm::Optional<std::nullptr_t> asNull() const {
192 0 : if (LLVM_LIKELY(Type == T_Null))
193 : return nullptr;
194 : return llvm::None;
195 : }
196 : llvm::Optional<bool> asBoolean() const {
197 0 : if (LLVM_LIKELY(Type == T_Boolean))
198 : return as<bool>();
199 : return llvm::None;
200 : }
201 : llvm::Optional<double> asNumber() const {
202 0 : if (LLVM_LIKELY(Type == T_Number))
203 : return as<double>();
204 : return llvm::None;
205 : }
206 0 : llvm::Optional<int64_t> asInteger() const {
207 0 : if (LLVM_LIKELY(Type == T_Number)) {
208 0 : double D = as<double>();
209 0 : if (LLVM_LIKELY(std::modf(D, &D) == 0 &&
210 : D >= std::numeric_limits<int64_t>::min() &&
211 0 : D <= std::numeric_limits<int64_t>::max()))
212 0 : return D;
213 : }
214 : return llvm::None;
215 : }
216 : llvm::Optional<llvm::StringRef> asString() const {
217 0 : if (Type == T_String)
218 : return llvm::StringRef(as<std::string>());
219 0 : if (LLVM_LIKELY(Type == T_StringRef))
220 : return as<llvm::StringRef>();
221 : return llvm::None;
222 : }
223 : const ObjectExpr *asObject() const {
224 0 : return LLVM_LIKELY(Type == T_Object) ? &as<ObjectExpr>() : nullptr;
225 : }
226 : ObjectExpr *asObject() {
227 0 : return LLVM_LIKELY(Type == T_Object) ? &as<ObjectExpr>() : nullptr;
228 : }
229 : const ArrayExpr *asArray() const {
230 0 : return LLVM_LIKELY(Type == T_Array) ? &as<ArrayExpr>() : nullptr;
231 : }
232 : ArrayExpr *asArray() {
233 0 : return LLVM_LIKELY(Type == T_Array) ? &as<ArrayExpr>() : nullptr;
234 : }
235 :
236 : friend llvm::raw_ostream &operator<<(llvm::raw_ostream &, const Expr &);
237 :
238 : private:
239 : void destroy();
240 : void copyFrom(const Expr &M);
241 : // We allow moving from *const* Exprs, by marking all members as mutable!
242 : // This hack is needed to support initializer-list syntax efficiently.
243 : // (std::initializer_list<T> is a container of const T).
244 : void moveFrom(const Expr &&M);
245 :
246 : template <typename T, typename... U> void create(U &&... V) {
247 0 : new (&as<T>()) T(std::forward<U>(V)...);
248 : }
249 : template <typename T> T &as() const {
250 0 : return *reinterpret_cast<T *>(Union.buffer);
251 : }
252 :
253 : template <typename Indenter>
254 : void print(llvm::raw_ostream &, const Indenter &) const;
255 : friend struct llvm::format_provider<clang::clangd::json::Expr>;
256 :
257 : enum ExprType : char {
258 : T_Null,
259 : T_Boolean,
260 : T_Number,
261 : T_StringRef,
262 : T_String,
263 : T_Object,
264 : T_Array,
265 : };
266 : mutable ExprType Type;
267 :
268 : public:
269 : // ObjectKey is a used to capture keys in Expr::ObjectExpr. Like Expr but:
270 : // - only strings are allowed
271 : // - it's optimized for the string literal case (Owned == nullptr)
272 : class ObjectKey {
273 : public:
274 : ObjectKey(const char *S) : Data(S) {}
275 0 : ObjectKey(llvm::StringRef S) : Data(S) {}
276 : ObjectKey(std::string &&V)
277 : : Owned(new std::string(std::move(V))), Data(*Owned) {}
278 : ObjectKey(const std::string &V) : Owned(new std::string(V)), Data(*Owned) {}
279 : ObjectKey(const llvm::SmallVectorImpl<char> &V)
280 : : ObjectKey(std::string(V.begin(), V.end())) {}
281 : ObjectKey(const llvm::formatv_object_base &V) : ObjectKey(V.str()) {}
282 :
283 : ObjectKey(const ObjectKey &C) { *this = C; }
284 : ObjectKey(ObjectKey &&C) : ObjectKey(static_cast<const ObjectKey &&>(C)) {}
285 : ObjectKey &operator=(const ObjectKey &C) {
286 : if (C.Owned) {
287 : Owned.reset(new std::string(*C.Owned));
288 : Data = *Owned;
289 : } else {
290 : Data = C.Data;
291 : }
292 : return *this;
293 : }
294 : ObjectKey &operator=(ObjectKey &&) = default;
295 :
296 : operator llvm::StringRef() const { return Data; }
297 :
298 : friend bool operator<(const ObjectKey &L, const ObjectKey &R) {
299 0 : return L.Data < R.Data;
300 : }
301 :
302 : // "cheating" move-constructor for moving from initializer_list.
303 0 : ObjectKey(const ObjectKey &&V) {
304 : Owned = std::move(V.Owned);
305 0 : Data = V.Data;
306 : }
307 :
308 : private:
309 : mutable std::unique_ptr<std::string> Owned; // mutable for cheating.
310 : llvm::StringRef Data;
311 : };
312 :
313 : class ObjectExpr : public std::map<ObjectKey, Expr> {
314 : public:
315 0 : explicit ObjectExpr() {}
316 : // Use a custom struct for list-init, because pair forces extra copies.
317 : struct KV;
318 : explicit ObjectExpr(std::initializer_list<KV> Properties);
319 :
320 : // Allow [] as if Expr was default-constructible as null.
321 : Expr &operator[](const ObjectKey &K) {
322 : return emplace(K, Expr(nullptr)).first->second;
323 : }
324 : Expr &operator[](ObjectKey &&K) {
325 : return emplace(std::move(K), Expr(nullptr)).first->second;
326 : }
327 :
328 : // Look up a property, returning nullptr if it doesn't exist.
329 : json::Expr *get(const ObjectKey &K) {
330 : auto I = find(K);
331 0 : if (I == end())
332 : return nullptr;
333 0 : return &I->second;
334 : }
335 : const json::Expr *get(const ObjectKey &K) const {
336 : auto I = find(K);
337 0 : if (I == end())
338 : return nullptr;
339 0 : return &I->second;
340 : }
341 : // Typed accessors return None/nullptr if
342 : // - the property doesn't exist
343 : // - or it has the wrong type
344 0 : llvm::Optional<std::nullptr_t> getNull(const ObjectKey &K) const {
345 0 : if (auto *V = get(K))
346 0 : return V->asNull();
347 : return llvm::None;
348 : }
349 : llvm::Optional<bool> getBoolean(const ObjectKey &K) const {
350 : if (auto *V = get(K))
351 : return V->asBoolean();
352 : return llvm::None;
353 : }
354 0 : llvm::Optional<double> getNumber(const ObjectKey &K) const {
355 0 : if (auto *V = get(K))
356 : return V->asNumber();
357 : return llvm::None;
358 : }
359 0 : llvm::Optional<int64_t> getInteger(const ObjectKey &K) const {
360 0 : if (auto *V = get(K))
361 0 : return V->asInteger();
362 : return llvm::None;
363 : }
364 0 : llvm::Optional<llvm::StringRef> getString(const ObjectKey &K) const {
365 0 : if (auto *V = get(K))
366 : return V->asString();
367 : return llvm::None;
368 : }
369 : const ObjectExpr *getObject(const ObjectKey &K) const {
370 : if (auto *V = get(K))
371 : return V->asObject();
372 : return nullptr;
373 : }
374 0 : ObjectExpr *getObject(const ObjectKey &K) {
375 0 : if (auto *V = get(K))
376 : return V->asObject();
377 : return nullptr;
378 : }
379 : const ArrayExpr *getArray(const ObjectKey &K) const {
380 : if (auto *V = get(K))
381 : return V->asArray();
382 : return nullptr;
383 : }
384 0 : ArrayExpr *getArray(const ObjectKey &K) {
385 0 : if (auto *V = get(K))
386 : return V->asArray();
387 : return nullptr;
388 : }
389 : };
390 :
391 0 : class ArrayExpr : public std::vector<Expr> {
392 : public:
393 : explicit ArrayExpr() {}
394 0 : explicit ArrayExpr(std::initializer_list<Expr> Elements) {
395 0 : reserve(Elements.size());
396 0 : for (const Expr &V : Elements)
397 0 : emplace_back(std::move(V));
398 0 : };
399 : template <typename Collection> explicit ArrayExpr(const Collection &C) {
400 : for (const auto &V : C)
401 : emplace_back(V);
402 : }
403 :
404 : // Typed accessors return None/nullptr if the element has the wrong type.
405 : llvm::Optional<std::nullptr_t> getNull(size_t I) const {
406 : return (*this)[I].asNull();
407 : }
408 : llvm::Optional<bool> getBoolean(size_t I) const {
409 0 : return (*this)[I].asBoolean();
410 : }
411 : llvm::Optional<double> getNumber(size_t I) const {
412 : return (*this)[I].asNumber();
413 : }
414 : llvm::Optional<int64_t> getInteger(size_t I) const {
415 0 : return (*this)[I].asInteger();
416 : }
417 : llvm::Optional<llvm::StringRef> getString(size_t I) const {
418 : return (*this)[I].asString();
419 : }
420 : const ObjectExpr *getObject(size_t I) const {
421 : return (*this)[I].asObject();
422 : }
423 : ObjectExpr *getObject(size_t I) { return (*this)[I].asObject(); }
424 : const ArrayExpr *getArray(size_t I) const { return (*this)[I].asArray(); }
425 0 : ArrayExpr *getArray(size_t I) { return (*this)[I].asArray(); }
426 : };
427 :
428 : private:
429 : mutable llvm::AlignedCharArrayUnion<bool, double, llvm::StringRef,
430 : std::string, ArrayExpr, ObjectExpr>
431 : Union;
432 : };
433 :
434 : bool operator==(const Expr &, const Expr &);
435 : inline bool operator!=(const Expr &L, const Expr &R) { return !(L == R); }
436 0 : inline bool operator==(const Expr::ObjectKey &L, const Expr::ObjectKey &R) {
437 0 : return llvm::StringRef(L) == llvm::StringRef(R);
438 : }
439 : inline bool operator!=(const Expr::ObjectKey &L, const Expr::ObjectKey &R) {
440 : return !(L == R);
441 : }
442 :
443 0 : struct Expr::ObjectExpr::KV {
444 : ObjectKey K;
445 : Expr V;
446 : };
447 :
448 0 : inline Expr::ObjectExpr::ObjectExpr(std::initializer_list<KV> Properties) {
449 0 : for (const auto &P : Properties)
450 0 : emplace(std::move(P.K), std::move(P.V));
451 0 : }
452 :
453 : // Give Expr::{Object,Array} more convenient names for literal use.
454 : using obj = Expr::ObjectExpr;
455 : using ary = Expr::ArrayExpr;
456 :
457 : // Standard deserializers.
458 0 : inline bool fromJSON(const json::Expr &E, std::string &Out) {
459 0 : if (auto S = E.asString()) {
460 0 : Out = *S;
461 : return true;
462 : }
463 : return false;
464 : }
465 : inline bool fromJSON(const json::Expr &E, int &Out) {
466 0 : if (auto S = E.asInteger()) {
467 0 : Out = *S;
468 : return true;
469 : }
470 : return false;
471 : }
472 : inline bool fromJSON(const json::Expr &E, double &Out) {
473 : if (auto S = E.asNumber()) {
474 : Out = *S;
475 : return true;
476 : }
477 : return false;
478 : }
479 : inline bool fromJSON(const json::Expr &E, bool &Out) {
480 0 : if (auto S = E.asBoolean()) {
481 0 : Out = *S;
482 : return true;
483 : }
484 : return false;
485 : }
486 : template <typename T>
487 0 : bool fromJSON(const json::Expr &E, llvm::Optional<T> &Out) {
488 0 : if (E.asNull()) {
489 : Out = llvm::None;
490 0 : return true;
491 : }
492 : T Result;
493 0 : if (!fromJSON(E, Result))
494 : return false;
495 : Out = std::move(Result);
496 : return true;
497 : }
498 0 : template <typename T> bool fromJSON(const json::Expr &E, std::vector<T> &Out) {
499 : if (auto *A = E.asArray()) {
500 0 : Out.clear();
501 0 : Out.resize(A->size());
502 0 : for (size_t I = 0; I < A->size(); ++I)
503 0 : if (!fromJSON((*A)[I], Out[I]))
504 : return false;
505 : return true;
506 : }
507 : return false;
508 : }
509 : template <typename T>
510 0 : bool fromJSON(const json::Expr &E, std::map<std::string, T> &Out) {
511 : if (auto *O = E.asObject()) {
512 : Out.clear();
513 0 : for (const auto &KV : *O)
514 0 : if (!fromJSON(KV.second, Out[llvm::StringRef(KV.first)]))
515 : return false;
516 : return true;
517 : }
518 : return false;
519 : }
520 :
521 : template <typename T>
522 : json::Expr toJSON(const llvm::Optional<T>& Opt) {
523 : return Opt ? json::Expr(*Opt) : json::Expr(nullptr);
524 : }
525 :
526 : // Helper for mapping JSON objects onto protocol structs.
527 : // See file header for example.
528 : class ObjectMapper {
529 : public:
530 0 : ObjectMapper(const json::Expr &E) : O(E.asObject()) {}
531 :
532 : // True if the expression is an object.
533 : // Must be checked before calling map().
534 : operator bool() { return O; }
535 :
536 : // Maps a property to a field, if it exists.
537 0 : template <typename T> bool map(const char *Prop, T &Out) {
538 : assert(*this && "Must check this is an object before calling map()");
539 0 : if (const json::Expr *E = O->get(Prop))
540 0 : return fromJSON(*E, Out);
541 : return false;
542 : }
543 :
544 : // Optional requires special handling, because missing keys are OK.
545 0 : template <typename T> bool map(const char *Prop, llvm::Optional<T> &Out) {
546 : assert(*this && "Must check this is an object before calling map()");
547 0 : if (const json::Expr *E = O->get(Prop))
548 0 : return fromJSON(*E, Out);
549 : Out = llvm::None;
550 0 : return true;
551 : }
552 :
553 : private:
554 : const json::obj *O;
555 : };
556 :
557 : llvm::Expected<Expr> parse(llvm::StringRef JSON);
558 :
559 0 : class ParseError : public llvm::ErrorInfo<ParseError> {
560 : const char *Msg;
561 : unsigned Line, Column, Offset;
562 :
563 : public:
564 : static char ID;
565 : ParseError(const char *Msg, unsigned Line, unsigned Column, unsigned Offset)
566 : : Msg(Msg), Line(Line), Column(Column), Offset(Offset) {}
567 0 : void log(llvm::raw_ostream &OS) const override {
568 0 : OS << llvm::formatv("[{0}:{1}, byte={2}]: {3}", Line, Column, Offset, Msg);
569 0 : }
570 : std::error_code convertToErrorCode() const override {
571 : return llvm::inconvertibleErrorCode();
572 : }
573 : };
574 :
575 : } // namespace json
576 : } // namespace clangd
577 : } // namespace clang
578 :
579 : namespace llvm {
580 : template <> struct format_provider<clang::clangd::json::Expr> {
581 : static void format(const clang::clangd::json::Expr &, raw_ostream &,
582 : StringRef);
583 : };
584 : } // namespace llvm
585 :
586 : #endif
|