2017-11-22 00:00:53 +08:00
|
|
|
//===--- JSONExpr.h - JSON expressions, parsing and serialization - C++ -*-===//
|
Adds a json::Expr type to represent intermediate JSON expressions.
Summary:
This form can be created with a nice clang-format-friendly literal syntax,
and gets escaping right. It knows how to call unparse() on our Protocol types.
All the places where we pass around JSON internally now use this type.
Object properties are sorted (stored as std::map) and so serialization is
canonicalized, with optional prettyprinting (triggered by a -pretty flag).
This makes the lit tests much nicer to read and somewhat nicer to debug.
(Unfortunately the completion tests use CHECK-DAG, which only has
line-granularity, so pretty-printing is disabled there. In future we
could make completion ordering deterministic, or switch to unittests).
Compared to the current approach, it has some efficiencies like avoiding copies
of string literals used as object keys, but is probably slower overall.
I think the code/test quality benefits are worth it.
This patch doesn't attempt to do anything about JSON *parsing*.
It takes direction from the proposal in this doc[1], but is limited in scope
and visibility, for now.
I am of half a mind just to use Expr as the target of a parser, and maybe do a
little string deduplication, but not bother with clever memory allocation.
That would be simple, and fast enough for clangd...
[1] https://docs.google.com/document/d/1OEF9IauWwNuSigZzvvbjc1cVS1uGHRyGTXaoy3DjqM4/edit
+cc d0k so he can tell me not to use std::map.
Reviewers: ioeric, malaperle
Subscribers: bkramer, ilya-biryukov, mgorny, klimek
Differential Revision: https://reviews.llvm.org/D39435
llvm-svn: 317486
2017-11-06 23:40:30 +08:00
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===---------------------------------------------------------------------===//
|
|
|
|
|
2017-11-22 00:00:53 +08:00
|
|
|
// FIXME: rename to JSON.h now that the scope is wider?
|
|
|
|
|
Adds a json::Expr type to represent intermediate JSON expressions.
Summary:
This form can be created with a nice clang-format-friendly literal syntax,
and gets escaping right. It knows how to call unparse() on our Protocol types.
All the places where we pass around JSON internally now use this type.
Object properties are sorted (stored as std::map) and so serialization is
canonicalized, with optional prettyprinting (triggered by a -pretty flag).
This makes the lit tests much nicer to read and somewhat nicer to debug.
(Unfortunately the completion tests use CHECK-DAG, which only has
line-granularity, so pretty-printing is disabled there. In future we
could make completion ordering deterministic, or switch to unittests).
Compared to the current approach, it has some efficiencies like avoiding copies
of string literals used as object keys, but is probably slower overall.
I think the code/test quality benefits are worth it.
This patch doesn't attempt to do anything about JSON *parsing*.
It takes direction from the proposal in this doc[1], but is limited in scope
and visibility, for now.
I am of half a mind just to use Expr as the target of a parser, and maybe do a
little string deduplication, but not bother with clever memory allocation.
That would be simple, and fast enough for clangd...
[1] https://docs.google.com/document/d/1OEF9IauWwNuSigZzvvbjc1cVS1uGHRyGTXaoy3DjqM4/edit
+cc d0k so he can tell me not to use std::map.
Reviewers: ioeric, malaperle
Subscribers: bkramer, ilya-biryukov, mgorny, klimek
Differential Revision: https://reviews.llvm.org/D39435
llvm-svn: 317486
2017-11-06 23:40:30 +08:00
|
|
|
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_JSON_H
|
|
|
|
#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_JSON_H
|
|
|
|
|
|
|
|
#include <map>
|
|
|
|
|
|
|
|
#include "llvm/ADT/SmallVector.h"
|
|
|
|
#include "llvm/ADT/StringRef.h"
|
2017-11-22 00:00:53 +08:00
|
|
|
#include "llvm/Support/Error.h"
|
Adds a json::Expr type to represent intermediate JSON expressions.
Summary:
This form can be created with a nice clang-format-friendly literal syntax,
and gets escaping right. It knows how to call unparse() on our Protocol types.
All the places where we pass around JSON internally now use this type.
Object properties are sorted (stored as std::map) and so serialization is
canonicalized, with optional prettyprinting (triggered by a -pretty flag).
This makes the lit tests much nicer to read and somewhat nicer to debug.
(Unfortunately the completion tests use CHECK-DAG, which only has
line-granularity, so pretty-printing is disabled there. In future we
could make completion ordering deterministic, or switch to unittests).
Compared to the current approach, it has some efficiencies like avoiding copies
of string literals used as object keys, but is probably slower overall.
I think the code/test quality benefits are worth it.
This patch doesn't attempt to do anything about JSON *parsing*.
It takes direction from the proposal in this doc[1], but is limited in scope
and visibility, for now.
I am of half a mind just to use Expr as the target of a parser, and maybe do a
little string deduplication, but not bother with clever memory allocation.
That would be simple, and fast enough for clangd...
[1] https://docs.google.com/document/d/1OEF9IauWwNuSigZzvvbjc1cVS1uGHRyGTXaoy3DjqM4/edit
+cc d0k so he can tell me not to use std::map.
Reviewers: ioeric, malaperle
Subscribers: bkramer, ilya-biryukov, mgorny, klimek
Differential Revision: https://reviews.llvm.org/D39435
llvm-svn: 317486
2017-11-06 23:40:30 +08:00
|
|
|
#include "llvm/Support/FormatVariadic.h"
|
|
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
|
|
|
|
namespace clang {
|
|
|
|
namespace clangd {
|
|
|
|
namespace json {
|
|
|
|
|
2017-11-22 00:00:53 +08:00
|
|
|
// An Expr is an JSON value of unknown type.
|
Adds a json::Expr type to represent intermediate JSON expressions.
Summary:
This form can be created with a nice clang-format-friendly literal syntax,
and gets escaping right. It knows how to call unparse() on our Protocol types.
All the places where we pass around JSON internally now use this type.
Object properties are sorted (stored as std::map) and so serialization is
canonicalized, with optional prettyprinting (triggered by a -pretty flag).
This makes the lit tests much nicer to read and somewhat nicer to debug.
(Unfortunately the completion tests use CHECK-DAG, which only has
line-granularity, so pretty-printing is disabled there. In future we
could make completion ordering deterministic, or switch to unittests).
Compared to the current approach, it has some efficiencies like avoiding copies
of string literals used as object keys, but is probably slower overall.
I think the code/test quality benefits are worth it.
This patch doesn't attempt to do anything about JSON *parsing*.
It takes direction from the proposal in this doc[1], but is limited in scope
and visibility, for now.
I am of half a mind just to use Expr as the target of a parser, and maybe do a
little string deduplication, but not bother with clever memory allocation.
That would be simple, and fast enough for clangd...
[1] https://docs.google.com/document/d/1OEF9IauWwNuSigZzvvbjc1cVS1uGHRyGTXaoy3DjqM4/edit
+cc d0k so he can tell me not to use std::map.
Reviewers: ioeric, malaperle
Subscribers: bkramer, ilya-biryukov, mgorny, klimek
Differential Revision: https://reviews.llvm.org/D39435
llvm-svn: 317486
2017-11-06 23:40:30 +08:00
|
|
|
// They can be copied, but should generally be moved.
|
|
|
|
//
|
2017-11-22 00:00:53 +08:00
|
|
|
// === Composing expressions ===
|
|
|
|
//
|
|
|
|
// You can implicitly construct Exprs from:
|
Adds a json::Expr type to represent intermediate JSON expressions.
Summary:
This form can be created with a nice clang-format-friendly literal syntax,
and gets escaping right. It knows how to call unparse() on our Protocol types.
All the places where we pass around JSON internally now use this type.
Object properties are sorted (stored as std::map) and so serialization is
canonicalized, with optional prettyprinting (triggered by a -pretty flag).
This makes the lit tests much nicer to read and somewhat nicer to debug.
(Unfortunately the completion tests use CHECK-DAG, which only has
line-granularity, so pretty-printing is disabled there. In future we
could make completion ordering deterministic, or switch to unittests).
Compared to the current approach, it has some efficiencies like avoiding copies
of string literals used as object keys, but is probably slower overall.
I think the code/test quality benefits are worth it.
This patch doesn't attempt to do anything about JSON *parsing*.
It takes direction from the proposal in this doc[1], but is limited in scope
and visibility, for now.
I am of half a mind just to use Expr as the target of a parser, and maybe do a
little string deduplication, but not bother with clever memory allocation.
That would be simple, and fast enough for clangd...
[1] https://docs.google.com/document/d/1OEF9IauWwNuSigZzvvbjc1cVS1uGHRyGTXaoy3DjqM4/edit
+cc d0k so he can tell me not to use std::map.
Reviewers: ioeric, malaperle
Subscribers: bkramer, ilya-biryukov, mgorny, klimek
Differential Revision: https://reviews.llvm.org/D39435
llvm-svn: 317486
2017-11-06 23:40:30 +08:00
|
|
|
// - 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: any T with a T::unparse(const T&) -> Expr
|
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
//
|
2017-11-22 00:00:53 +08:00
|
|
|
// === 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:
|
2017-11-28 17:25:09 +08:00
|
|
|
// if (Optional<StringRef> S = E.asString()
|
2017-11-22 00:00:53 +08:00
|
|
|
// 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"}} )");
|
2017-11-28 17:25:09 +08:00
|
|
|
// if (json::obj* O = E->asObject())
|
|
|
|
// if (json::obj* Opts = O->getObject("options"))
|
|
|
|
// if (Optional<StringRef> Font = Opts->getString("font"))
|
2017-11-22 00:00:53 +08:00
|
|
|
// assert(Opts->at("font").kind() == Expr::String);
|
|
|
|
//
|
|
|
|
// === Serialization ===
|
|
|
|
//
|
Adds a json::Expr type to represent intermediate JSON expressions.
Summary:
This form can be created with a nice clang-format-friendly literal syntax,
and gets escaping right. It knows how to call unparse() on our Protocol types.
All the places where we pass around JSON internally now use this type.
Object properties are sorted (stored as std::map) and so serialization is
canonicalized, with optional prettyprinting (triggered by a -pretty flag).
This makes the lit tests much nicer to read and somewhat nicer to debug.
(Unfortunately the completion tests use CHECK-DAG, which only has
line-granularity, so pretty-printing is disabled there. In future we
could make completion ordering deterministic, or switch to unittests).
Compared to the current approach, it has some efficiencies like avoiding copies
of string literals used as object keys, but is probably slower overall.
I think the code/test quality benefits are worth it.
This patch doesn't attempt to do anything about JSON *parsing*.
It takes direction from the proposal in this doc[1], but is limited in scope
and visibility, for now.
I am of half a mind just to use Expr as the target of a parser, and maybe do a
little string deduplication, but not bother with clever memory allocation.
That would be simple, and fast enough for clangd...
[1] https://docs.google.com/document/d/1OEF9IauWwNuSigZzvvbjc1cVS1uGHRyGTXaoy3DjqM4/edit
+cc d0k so he can tell me not to use std::map.
Reviewers: ioeric, malaperle
Subscribers: bkramer, ilya-biryukov, mgorny, klimek
Differential Revision: https://reviews.llvm.org/D39435
llvm-svn: 317486
2017-11-06 23:40:30 +08:00
|
|
|
// 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.
|
2017-11-22 00:00:53 +08:00
|
|
|
//
|
|
|
|
// And parsed:
|
|
|
|
// Expected<Expr> E = json::parse("[1, 2, null]");
|
|
|
|
// assert(E && E->kind() == Expr::Array);
|
Adds a json::Expr type to represent intermediate JSON expressions.
Summary:
This form can be created with a nice clang-format-friendly literal syntax,
and gets escaping right. It knows how to call unparse() on our Protocol types.
All the places where we pass around JSON internally now use this type.
Object properties are sorted (stored as std::map) and so serialization is
canonicalized, with optional prettyprinting (triggered by a -pretty flag).
This makes the lit tests much nicer to read and somewhat nicer to debug.
(Unfortunately the completion tests use CHECK-DAG, which only has
line-granularity, so pretty-printing is disabled there. In future we
could make completion ordering deterministic, or switch to unittests).
Compared to the current approach, it has some efficiencies like avoiding copies
of string literals used as object keys, but is probably slower overall.
I think the code/test quality benefits are worth it.
This patch doesn't attempt to do anything about JSON *parsing*.
It takes direction from the proposal in this doc[1], but is limited in scope
and visibility, for now.
I am of half a mind just to use Expr as the target of a parser, and maybe do a
little string deduplication, but not bother with clever memory allocation.
That would be simple, and fast enough for clangd...
[1] https://docs.google.com/document/d/1OEF9IauWwNuSigZzvvbjc1cVS1uGHRyGTXaoy3DjqM4/edit
+cc d0k so he can tell me not to use std::map.
Reviewers: ioeric, malaperle
Subscribers: bkramer, ilya-biryukov, mgorny, klimek
Differential Revision: https://reviews.llvm.org/D39435
llvm-svn: 317486
2017-11-06 23:40:30 +08:00
|
|
|
class Expr {
|
|
|
|
public:
|
2017-11-22 00:00:53 +08:00
|
|
|
enum Kind {
|
|
|
|
Null,
|
|
|
|
Boolean,
|
|
|
|
Number,
|
|
|
|
String,
|
|
|
|
Array,
|
|
|
|
Object,
|
|
|
|
};
|
|
|
|
class ObjectExpr;
|
Adds a json::Expr type to represent intermediate JSON expressions.
Summary:
This form can be created with a nice clang-format-friendly literal syntax,
and gets escaping right. It knows how to call unparse() on our Protocol types.
All the places where we pass around JSON internally now use this type.
Object properties are sorted (stored as std::map) and so serialization is
canonicalized, with optional prettyprinting (triggered by a -pretty flag).
This makes the lit tests much nicer to read and somewhat nicer to debug.
(Unfortunately the completion tests use CHECK-DAG, which only has
line-granularity, so pretty-printing is disabled there. In future we
could make completion ordering deterministic, or switch to unittests).
Compared to the current approach, it has some efficiencies like avoiding copies
of string literals used as object keys, but is probably slower overall.
I think the code/test quality benefits are worth it.
This patch doesn't attempt to do anything about JSON *parsing*.
It takes direction from the proposal in this doc[1], but is limited in scope
and visibility, for now.
I am of half a mind just to use Expr as the target of a parser, and maybe do a
little string deduplication, but not bother with clever memory allocation.
That would be simple, and fast enough for clangd...
[1] https://docs.google.com/document/d/1OEF9IauWwNuSigZzvvbjc1cVS1uGHRyGTXaoy3DjqM4/edit
+cc d0k so he can tell me not to use std::map.
Reviewers: ioeric, malaperle
Subscribers: bkramer, ilya-biryukov, mgorny, klimek
Differential Revision: https://reviews.llvm.org/D39435
llvm-svn: 317486
2017-11-06 23:40:30 +08:00
|
|
|
class ObjectKey;
|
2017-11-22 00:00:53 +08:00
|
|
|
class ArrayExpr;
|
Adds a json::Expr type to represent intermediate JSON expressions.
Summary:
This form can be created with a nice clang-format-friendly literal syntax,
and gets escaping right. It knows how to call unparse() on our Protocol types.
All the places where we pass around JSON internally now use this type.
Object properties are sorted (stored as std::map) and so serialization is
canonicalized, with optional prettyprinting (triggered by a -pretty flag).
This makes the lit tests much nicer to read and somewhat nicer to debug.
(Unfortunately the completion tests use CHECK-DAG, which only has
line-granularity, so pretty-printing is disabled there. In future we
could make completion ordering deterministic, or switch to unittests).
Compared to the current approach, it has some efficiencies like avoiding copies
of string literals used as object keys, but is probably slower overall.
I think the code/test quality benefits are worth it.
This patch doesn't attempt to do anything about JSON *parsing*.
It takes direction from the proposal in this doc[1], but is limited in scope
and visibility, for now.
I am of half a mind just to use Expr as the target of a parser, and maybe do a
little string deduplication, but not bother with clever memory allocation.
That would be simple, and fast enough for clangd...
[1] https://docs.google.com/document/d/1OEF9IauWwNuSigZzvvbjc1cVS1uGHRyGTXaoy3DjqM4/edit
+cc d0k so he can tell me not to use std::map.
Reviewers: ioeric, malaperle
Subscribers: bkramer, ilya-biryukov, mgorny, klimek
Differential Revision: https://reviews.llvm.org/D39435
llvm-svn: 317486
2017-11-06 23:40:30 +08:00
|
|
|
|
|
|
|
// 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)); }
|
2017-11-22 00:00:53 +08:00
|
|
|
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));
|
Adds a json::Expr type to represent intermediate JSON expressions.
Summary:
This form can be created with a nice clang-format-friendly literal syntax,
and gets escaping right. It knows how to call unparse() on our Protocol types.
All the places where we pass around JSON internally now use this type.
Object properties are sorted (stored as std::map) and so serialization is
canonicalized, with optional prettyprinting (triggered by a -pretty flag).
This makes the lit tests much nicer to read and somewhat nicer to debug.
(Unfortunately the completion tests use CHECK-DAG, which only has
line-granularity, so pretty-printing is disabled there. In future we
could make completion ordering deterministic, or switch to unittests).
Compared to the current approach, it has some efficiencies like avoiding copies
of string literals used as object keys, but is probably slower overall.
I think the code/test quality benefits are worth it.
This patch doesn't attempt to do anything about JSON *parsing*.
It takes direction from the proposal in this doc[1], but is limited in scope
and visibility, for now.
I am of half a mind just to use Expr as the target of a parser, and maybe do a
little string deduplication, but not bother with clever memory allocation.
That would be simple, and fast enough for clangd...
[1] https://docs.google.com/document/d/1OEF9IauWwNuSigZzvvbjc1cVS1uGHRyGTXaoy3DjqM4/edit
+cc d0k so he can tell me not to use std::map.
Reviewers: ioeric, malaperle
Subscribers: bkramer, ilya-biryukov, mgorny, klimek
Differential Revision: https://reviews.llvm.org/D39435
llvm-svn: 317486
2017-11-06 23:40:30 +08:00
|
|
|
}
|
|
|
|
// 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 static T::unparse function returning an Expr.
|
|
|
|
// FIXME: should this be a free unparse() function found by ADL?
|
|
|
|
template <typename T,
|
|
|
|
typename = typename std::enable_if<std::is_same<
|
|
|
|
Expr, decltype(T::unparse(*(const T *)nullptr))>::value>>
|
|
|
|
Expr(const T &V) : Expr(T::unparse(V)) {}
|
|
|
|
|
|
|
|
Expr &operator=(const Expr &M) {
|
|
|
|
destroy();
|
|
|
|
copyFrom(M);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
Expr &operator=(Expr &&M) {
|
|
|
|
destroy();
|
|
|
|
moveFrom(std::move(M));
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
~Expr() { destroy(); }
|
|
|
|
|
2017-11-22 00:00:53 +08:00
|
|
|
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;
|
|
|
|
}
|
2017-11-22 06:24:13 +08:00
|
|
|
llvm_unreachable("Unknown kind");
|
2017-11-22 00:00:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Typed accessors return None/nullptr if the Expr is not of this type.
|
2017-11-28 17:25:09 +08:00
|
|
|
llvm::Optional<std::nullptr_t> asNull() const {
|
2017-11-22 00:00:53 +08:00
|
|
|
if (LLVM_LIKELY(Type == T_Null))
|
|
|
|
return nullptr;
|
|
|
|
return llvm::None;
|
|
|
|
}
|
2017-11-28 17:25:09 +08:00
|
|
|
llvm::Optional<bool> asBoolean() const {
|
|
|
|
if (LLVM_LIKELY(Type == T_Boolean))
|
2017-11-22 00:00:53 +08:00
|
|
|
return as<bool>();
|
|
|
|
return llvm::None;
|
|
|
|
}
|
2017-11-28 17:25:09 +08:00
|
|
|
llvm::Optional<double> asNumber() const {
|
2017-11-22 00:00:53 +08:00
|
|
|
if (LLVM_LIKELY(Type == T_Number))
|
|
|
|
return as<double>();
|
|
|
|
return llvm::None;
|
|
|
|
}
|
2017-11-28 17:37:43 +08:00
|
|
|
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;
|
|
|
|
}
|
2017-11-28 17:25:09 +08:00
|
|
|
llvm::Optional<llvm::StringRef> asString() const {
|
2017-11-22 00:00:53 +08:00
|
|
|
if (Type == T_String)
|
|
|
|
return llvm::StringRef(as<std::string>());
|
|
|
|
if (LLVM_LIKELY(Type == T_StringRef))
|
|
|
|
return as<llvm::StringRef>();
|
|
|
|
return llvm::None;
|
|
|
|
}
|
2017-11-28 17:25:09 +08:00
|
|
|
const ObjectExpr *asObject() const {
|
2017-11-22 00:00:53 +08:00
|
|
|
return LLVM_LIKELY(Type == T_Object) ? &as<ObjectExpr>() : nullptr;
|
|
|
|
}
|
2017-11-28 17:25:09 +08:00
|
|
|
ObjectExpr *asObject() {
|
2017-11-22 00:00:53 +08:00
|
|
|
return LLVM_LIKELY(Type == T_Object) ? &as<ObjectExpr>() : nullptr;
|
|
|
|
}
|
2017-11-28 17:25:09 +08:00
|
|
|
const ArrayExpr *asArray() const {
|
2017-11-22 00:00:53 +08:00
|
|
|
return LLVM_LIKELY(Type == T_Array) ? &as<ArrayExpr>() : nullptr;
|
|
|
|
}
|
2017-11-28 17:25:09 +08:00
|
|
|
ArrayExpr *asArray() {
|
2017-11-22 00:00:53 +08:00
|
|
|
return LLVM_LIKELY(Type == T_Array) ? &as<ArrayExpr>() : nullptr;
|
|
|
|
}
|
|
|
|
|
Adds a json::Expr type to represent intermediate JSON expressions.
Summary:
This form can be created with a nice clang-format-friendly literal syntax,
and gets escaping right. It knows how to call unparse() on our Protocol types.
All the places where we pass around JSON internally now use this type.
Object properties are sorted (stored as std::map) and so serialization is
canonicalized, with optional prettyprinting (triggered by a -pretty flag).
This makes the lit tests much nicer to read and somewhat nicer to debug.
(Unfortunately the completion tests use CHECK-DAG, which only has
line-granularity, so pretty-printing is disabled there. In future we
could make completion ordering deterministic, or switch to unittests).
Compared to the current approach, it has some efficiencies like avoiding copies
of string literals used as object keys, but is probably slower overall.
I think the code/test quality benefits are worth it.
This patch doesn't attempt to do anything about JSON *parsing*.
It takes direction from the proposal in this doc[1], but is limited in scope
and visibility, for now.
I am of half a mind just to use Expr as the target of a parser, and maybe do a
little string deduplication, but not bother with clever memory allocation.
That would be simple, and fast enough for clangd...
[1] https://docs.google.com/document/d/1OEF9IauWwNuSigZzvvbjc1cVS1uGHRyGTXaoy3DjqM4/edit
+cc d0k so he can tell me not to use std::map.
Reviewers: ioeric, malaperle
Subscribers: bkramer, ilya-biryukov, mgorny, klimek
Differential Revision: https://reviews.llvm.org/D39435
llvm-svn: 317486
2017-11-06 23:40:30 +08:00
|
|
|
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:
|
2017-11-22 00:00:53 +08:00
|
|
|
// ObjectKey is a used to capture keys in Expr::ObjectExpr. Like Expr but:
|
Adds a json::Expr type to represent intermediate JSON expressions.
Summary:
This form can be created with a nice clang-format-friendly literal syntax,
and gets escaping right. It knows how to call unparse() on our Protocol types.
All the places where we pass around JSON internally now use this type.
Object properties are sorted (stored as std::map) and so serialization is
canonicalized, with optional prettyprinting (triggered by a -pretty flag).
This makes the lit tests much nicer to read and somewhat nicer to debug.
(Unfortunately the completion tests use CHECK-DAG, which only has
line-granularity, so pretty-printing is disabled there. In future we
could make completion ordering deterministic, or switch to unittests).
Compared to the current approach, it has some efficiencies like avoiding copies
of string literals used as object keys, but is probably slower overall.
I think the code/test quality benefits are worth it.
This patch doesn't attempt to do anything about JSON *parsing*.
It takes direction from the proposal in this doc[1], but is limited in scope
and visibility, for now.
I am of half a mind just to use Expr as the target of a parser, and maybe do a
little string deduplication, but not bother with clever memory allocation.
That would be simple, and fast enough for clangd...
[1] https://docs.google.com/document/d/1OEF9IauWwNuSigZzvvbjc1cVS1uGHRyGTXaoy3DjqM4/edit
+cc d0k so he can tell me not to use std::map.
Reviewers: ioeric, malaperle
Subscribers: bkramer, ilya-biryukov, mgorny, klimek
Differential Revision: https://reviews.llvm.org/D39435
llvm-svn: 317486
2017-11-06 23:40:30 +08:00
|
|
|
// - 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; }
|
2017-11-07 16:57:54 +08:00
|
|
|
ObjectKey(ObjectKey &&C) : ObjectKey(static_cast<const ObjectKey &&>(C)) {}
|
Adds a json::Expr type to represent intermediate JSON expressions.
Summary:
This form can be created with a nice clang-format-friendly literal syntax,
and gets escaping right. It knows how to call unparse() on our Protocol types.
All the places where we pass around JSON internally now use this type.
Object properties are sorted (stored as std::map) and so serialization is
canonicalized, with optional prettyprinting (triggered by a -pretty flag).
This makes the lit tests much nicer to read and somewhat nicer to debug.
(Unfortunately the completion tests use CHECK-DAG, which only has
line-granularity, so pretty-printing is disabled there. In future we
could make completion ordering deterministic, or switch to unittests).
Compared to the current approach, it has some efficiencies like avoiding copies
of string literals used as object keys, but is probably slower overall.
I think the code/test quality benefits are worth it.
This patch doesn't attempt to do anything about JSON *parsing*.
It takes direction from the proposal in this doc[1], but is limited in scope
and visibility, for now.
I am of half a mind just to use Expr as the target of a parser, and maybe do a
little string deduplication, but not bother with clever memory allocation.
That would be simple, and fast enough for clangd...
[1] https://docs.google.com/document/d/1OEF9IauWwNuSigZzvvbjc1cVS1uGHRyGTXaoy3DjqM4/edit
+cc d0k so he can tell me not to use std::map.
Reviewers: ioeric, malaperle
Subscribers: bkramer, ilya-biryukov, mgorny, klimek
Differential Revision: https://reviews.llvm.org/D39435
llvm-svn: 317486
2017-11-06 23:40:30 +08:00
|
|
|
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;
|
|
|
|
};
|
|
|
|
|
2017-11-22 00:00:53 +08:00
|
|
|
class ObjectExpr : public std::map<ObjectKey, Expr> {
|
Adds a json::Expr type to represent intermediate JSON expressions.
Summary:
This form can be created with a nice clang-format-friendly literal syntax,
and gets escaping right. It knows how to call unparse() on our Protocol types.
All the places where we pass around JSON internally now use this type.
Object properties are sorted (stored as std::map) and so serialization is
canonicalized, with optional prettyprinting (triggered by a -pretty flag).
This makes the lit tests much nicer to read and somewhat nicer to debug.
(Unfortunately the completion tests use CHECK-DAG, which only has
line-granularity, so pretty-printing is disabled there. In future we
could make completion ordering deterministic, or switch to unittests).
Compared to the current approach, it has some efficiencies like avoiding copies
of string literals used as object keys, but is probably slower overall.
I think the code/test quality benefits are worth it.
This patch doesn't attempt to do anything about JSON *parsing*.
It takes direction from the proposal in this doc[1], but is limited in scope
and visibility, for now.
I am of half a mind just to use Expr as the target of a parser, and maybe do a
little string deduplication, but not bother with clever memory allocation.
That would be simple, and fast enough for clangd...
[1] https://docs.google.com/document/d/1OEF9IauWwNuSigZzvvbjc1cVS1uGHRyGTXaoy3DjqM4/edit
+cc d0k so he can tell me not to use std::map.
Reviewers: ioeric, malaperle
Subscribers: bkramer, ilya-biryukov, mgorny, klimek
Differential Revision: https://reviews.llvm.org/D39435
llvm-svn: 317486
2017-11-06 23:40:30 +08:00
|
|
|
public:
|
2017-11-22 00:00:53 +08:00
|
|
|
explicit ObjectExpr() {}
|
Adds a json::Expr type to represent intermediate JSON expressions.
Summary:
This form can be created with a nice clang-format-friendly literal syntax,
and gets escaping right. It knows how to call unparse() on our Protocol types.
All the places where we pass around JSON internally now use this type.
Object properties are sorted (stored as std::map) and so serialization is
canonicalized, with optional prettyprinting (triggered by a -pretty flag).
This makes the lit tests much nicer to read and somewhat nicer to debug.
(Unfortunately the completion tests use CHECK-DAG, which only has
line-granularity, so pretty-printing is disabled there. In future we
could make completion ordering deterministic, or switch to unittests).
Compared to the current approach, it has some efficiencies like avoiding copies
of string literals used as object keys, but is probably slower overall.
I think the code/test quality benefits are worth it.
This patch doesn't attempt to do anything about JSON *parsing*.
It takes direction from the proposal in this doc[1], but is limited in scope
and visibility, for now.
I am of half a mind just to use Expr as the target of a parser, and maybe do a
little string deduplication, but not bother with clever memory allocation.
That would be simple, and fast enough for clangd...
[1] https://docs.google.com/document/d/1OEF9IauWwNuSigZzvvbjc1cVS1uGHRyGTXaoy3DjqM4/edit
+cc d0k so he can tell me not to use std::map.
Reviewers: ioeric, malaperle
Subscribers: bkramer, ilya-biryukov, mgorny, klimek
Differential Revision: https://reviews.llvm.org/D39435
llvm-svn: 317486
2017-11-06 23:40:30 +08:00
|
|
|
// Use a custom struct for list-init, because pair forces extra copies.
|
|
|
|
struct KV;
|
2017-11-22 00:00:53 +08:00
|
|
|
explicit ObjectExpr(std::initializer_list<KV> Properties);
|
Adds a json::Expr type to represent intermediate JSON expressions.
Summary:
This form can be created with a nice clang-format-friendly literal syntax,
and gets escaping right. It knows how to call unparse() on our Protocol types.
All the places where we pass around JSON internally now use this type.
Object properties are sorted (stored as std::map) and so serialization is
canonicalized, with optional prettyprinting (triggered by a -pretty flag).
This makes the lit tests much nicer to read and somewhat nicer to debug.
(Unfortunately the completion tests use CHECK-DAG, which only has
line-granularity, so pretty-printing is disabled there. In future we
could make completion ordering deterministic, or switch to unittests).
Compared to the current approach, it has some efficiencies like avoiding copies
of string literals used as object keys, but is probably slower overall.
I think the code/test quality benefits are worth it.
This patch doesn't attempt to do anything about JSON *parsing*.
It takes direction from the proposal in this doc[1], but is limited in scope
and visibility, for now.
I am of half a mind just to use Expr as the target of a parser, and maybe do a
little string deduplication, but not bother with clever memory allocation.
That would be simple, and fast enough for clangd...
[1] https://docs.google.com/document/d/1OEF9IauWwNuSigZzvvbjc1cVS1uGHRyGTXaoy3DjqM4/edit
+cc d0k so he can tell me not to use std::map.
Reviewers: ioeric, malaperle
Subscribers: bkramer, ilya-biryukov, mgorny, klimek
Differential Revision: https://reviews.llvm.org/D39435
llvm-svn: 317486
2017-11-06 23:40:30 +08:00
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
2017-11-28 17:25:09 +08:00
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
2017-11-28 17:37:43 +08:00
|
|
|
llvm::Optional<int64_t> getInteger(const ObjectKey &K) const {
|
|
|
|
if (auto *V = get(K))
|
|
|
|
return V->asInteger();
|
|
|
|
return llvm::None;
|
|
|
|
}
|
2017-11-28 17:25:09 +08:00
|
|
|
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;
|
|
|
|
}
|
Adds a json::Expr type to represent intermediate JSON expressions.
Summary:
This form can be created with a nice clang-format-friendly literal syntax,
and gets escaping right. It knows how to call unparse() on our Protocol types.
All the places where we pass around JSON internally now use this type.
Object properties are sorted (stored as std::map) and so serialization is
canonicalized, with optional prettyprinting (triggered by a -pretty flag).
This makes the lit tests much nicer to read and somewhat nicer to debug.
(Unfortunately the completion tests use CHECK-DAG, which only has
line-granularity, so pretty-printing is disabled there. In future we
could make completion ordering deterministic, or switch to unittests).
Compared to the current approach, it has some efficiencies like avoiding copies
of string literals used as object keys, but is probably slower overall.
I think the code/test quality benefits are worth it.
This patch doesn't attempt to do anything about JSON *parsing*.
It takes direction from the proposal in this doc[1], but is limited in scope
and visibility, for now.
I am of half a mind just to use Expr as the target of a parser, and maybe do a
little string deduplication, but not bother with clever memory allocation.
That would be simple, and fast enough for clangd...
[1] https://docs.google.com/document/d/1OEF9IauWwNuSigZzvvbjc1cVS1uGHRyGTXaoy3DjqM4/edit
+cc d0k so he can tell me not to use std::map.
Reviewers: ioeric, malaperle
Subscribers: bkramer, ilya-biryukov, mgorny, klimek
Differential Revision: https://reviews.llvm.org/D39435
llvm-svn: 317486
2017-11-06 23:40:30 +08:00
|
|
|
};
|
|
|
|
|
2017-11-22 00:00:53 +08:00
|
|
|
class ArrayExpr : public std::vector<Expr> {
|
Adds a json::Expr type to represent intermediate JSON expressions.
Summary:
This form can be created with a nice clang-format-friendly literal syntax,
and gets escaping right. It knows how to call unparse() on our Protocol types.
All the places where we pass around JSON internally now use this type.
Object properties are sorted (stored as std::map) and so serialization is
canonicalized, with optional prettyprinting (triggered by a -pretty flag).
This makes the lit tests much nicer to read and somewhat nicer to debug.
(Unfortunately the completion tests use CHECK-DAG, which only has
line-granularity, so pretty-printing is disabled there. In future we
could make completion ordering deterministic, or switch to unittests).
Compared to the current approach, it has some efficiencies like avoiding copies
of string literals used as object keys, but is probably slower overall.
I think the code/test quality benefits are worth it.
This patch doesn't attempt to do anything about JSON *parsing*.
It takes direction from the proposal in this doc[1], but is limited in scope
and visibility, for now.
I am of half a mind just to use Expr as the target of a parser, and maybe do a
little string deduplication, but not bother with clever memory allocation.
That would be simple, and fast enough for clangd...
[1] https://docs.google.com/document/d/1OEF9IauWwNuSigZzvvbjc1cVS1uGHRyGTXaoy3DjqM4/edit
+cc d0k so he can tell me not to use std::map.
Reviewers: ioeric, malaperle
Subscribers: bkramer, ilya-biryukov, mgorny, klimek
Differential Revision: https://reviews.llvm.org/D39435
llvm-svn: 317486
2017-11-06 23:40:30 +08:00
|
|
|
public:
|
2017-11-22 00:00:53 +08:00
|
|
|
explicit ArrayExpr() {}
|
|
|
|
explicit ArrayExpr(std::initializer_list<Expr> Elements) {
|
Adds a json::Expr type to represent intermediate JSON expressions.
Summary:
This form can be created with a nice clang-format-friendly literal syntax,
and gets escaping right. It knows how to call unparse() on our Protocol types.
All the places where we pass around JSON internally now use this type.
Object properties are sorted (stored as std::map) and so serialization is
canonicalized, with optional prettyprinting (triggered by a -pretty flag).
This makes the lit tests much nicer to read and somewhat nicer to debug.
(Unfortunately the completion tests use CHECK-DAG, which only has
line-granularity, so pretty-printing is disabled there. In future we
could make completion ordering deterministic, or switch to unittests).
Compared to the current approach, it has some efficiencies like avoiding copies
of string literals used as object keys, but is probably slower overall.
I think the code/test quality benefits are worth it.
This patch doesn't attempt to do anything about JSON *parsing*.
It takes direction from the proposal in this doc[1], but is limited in scope
and visibility, for now.
I am of half a mind just to use Expr as the target of a parser, and maybe do a
little string deduplication, but not bother with clever memory allocation.
That would be simple, and fast enough for clangd...
[1] https://docs.google.com/document/d/1OEF9IauWwNuSigZzvvbjc1cVS1uGHRyGTXaoy3DjqM4/edit
+cc d0k so he can tell me not to use std::map.
Reviewers: ioeric, malaperle
Subscribers: bkramer, ilya-biryukov, mgorny, klimek
Differential Revision: https://reviews.llvm.org/D39435
llvm-svn: 317486
2017-11-06 23:40:30 +08:00
|
|
|
reserve(Elements.size());
|
|
|
|
for (const Expr &V : Elements)
|
|
|
|
emplace_back(std::move(V));
|
|
|
|
};
|
2017-11-22 00:00:53 +08:00
|
|
|
template <typename Collection> explicit ArrayExpr(const Collection &C) {
|
Adds a json::Expr type to represent intermediate JSON expressions.
Summary:
This form can be created with a nice clang-format-friendly literal syntax,
and gets escaping right. It knows how to call unparse() on our Protocol types.
All the places where we pass around JSON internally now use this type.
Object properties are sorted (stored as std::map) and so serialization is
canonicalized, with optional prettyprinting (triggered by a -pretty flag).
This makes the lit tests much nicer to read and somewhat nicer to debug.
(Unfortunately the completion tests use CHECK-DAG, which only has
line-granularity, so pretty-printing is disabled there. In future we
could make completion ordering deterministic, or switch to unittests).
Compared to the current approach, it has some efficiencies like avoiding copies
of string literals used as object keys, but is probably slower overall.
I think the code/test quality benefits are worth it.
This patch doesn't attempt to do anything about JSON *parsing*.
It takes direction from the proposal in this doc[1], but is limited in scope
and visibility, for now.
I am of half a mind just to use Expr as the target of a parser, and maybe do a
little string deduplication, but not bother with clever memory allocation.
That would be simple, and fast enough for clangd...
[1] https://docs.google.com/document/d/1OEF9IauWwNuSigZzvvbjc1cVS1uGHRyGTXaoy3DjqM4/edit
+cc d0k so he can tell me not to use std::map.
Reviewers: ioeric, malaperle
Subscribers: bkramer, ilya-biryukov, mgorny, klimek
Differential Revision: https://reviews.llvm.org/D39435
llvm-svn: 317486
2017-11-06 23:40:30 +08:00
|
|
|
for (const auto &V : C)
|
|
|
|
emplace_back(V);
|
|
|
|
}
|
2017-11-28 17:25:09 +08:00
|
|
|
|
|
|
|
// 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();
|
|
|
|
}
|
2017-11-28 17:37:43 +08:00
|
|
|
llvm::Optional<int64_t> getInteger(size_t I) const {
|
|
|
|
return (*this)[I].asInteger();
|
|
|
|
}
|
2017-11-28 17:25:09 +08:00
|
|
|
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(); }
|
Adds a json::Expr type to represent intermediate JSON expressions.
Summary:
This form can be created with a nice clang-format-friendly literal syntax,
and gets escaping right. It knows how to call unparse() on our Protocol types.
All the places where we pass around JSON internally now use this type.
Object properties are sorted (stored as std::map) and so serialization is
canonicalized, with optional prettyprinting (triggered by a -pretty flag).
This makes the lit tests much nicer to read and somewhat nicer to debug.
(Unfortunately the completion tests use CHECK-DAG, which only has
line-granularity, so pretty-printing is disabled there. In future we
could make completion ordering deterministic, or switch to unittests).
Compared to the current approach, it has some efficiencies like avoiding copies
of string literals used as object keys, but is probably slower overall.
I think the code/test quality benefits are worth it.
This patch doesn't attempt to do anything about JSON *parsing*.
It takes direction from the proposal in this doc[1], but is limited in scope
and visibility, for now.
I am of half a mind just to use Expr as the target of a parser, and maybe do a
little string deduplication, but not bother with clever memory allocation.
That would be simple, and fast enough for clangd...
[1] https://docs.google.com/document/d/1OEF9IauWwNuSigZzvvbjc1cVS1uGHRyGTXaoy3DjqM4/edit
+cc d0k so he can tell me not to use std::map.
Reviewers: ioeric, malaperle
Subscribers: bkramer, ilya-biryukov, mgorny, klimek
Differential Revision: https://reviews.llvm.org/D39435
llvm-svn: 317486
2017-11-06 23:40:30 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
private:
|
|
|
|
mutable llvm::AlignedCharArrayUnion<bool, double, llvm::StringRef,
|
2017-11-22 00:00:53 +08:00
|
|
|
std::string, ArrayExpr, ObjectExpr>
|
Adds a json::Expr type to represent intermediate JSON expressions.
Summary:
This form can be created with a nice clang-format-friendly literal syntax,
and gets escaping right. It knows how to call unparse() on our Protocol types.
All the places where we pass around JSON internally now use this type.
Object properties are sorted (stored as std::map) and so serialization is
canonicalized, with optional prettyprinting (triggered by a -pretty flag).
This makes the lit tests much nicer to read and somewhat nicer to debug.
(Unfortunately the completion tests use CHECK-DAG, which only has
line-granularity, so pretty-printing is disabled there. In future we
could make completion ordering deterministic, or switch to unittests).
Compared to the current approach, it has some efficiencies like avoiding copies
of string literals used as object keys, but is probably slower overall.
I think the code/test quality benefits are worth it.
This patch doesn't attempt to do anything about JSON *parsing*.
It takes direction from the proposal in this doc[1], but is limited in scope
and visibility, for now.
I am of half a mind just to use Expr as the target of a parser, and maybe do a
little string deduplication, but not bother with clever memory allocation.
That would be simple, and fast enough for clangd...
[1] https://docs.google.com/document/d/1OEF9IauWwNuSigZzvvbjc1cVS1uGHRyGTXaoy3DjqM4/edit
+cc d0k so he can tell me not to use std::map.
Reviewers: ioeric, malaperle
Subscribers: bkramer, ilya-biryukov, mgorny, klimek
Differential Revision: https://reviews.llvm.org/D39435
llvm-svn: 317486
2017-11-06 23:40:30 +08:00
|
|
|
Union;
|
|
|
|
};
|
|
|
|
|
2017-11-22 00:00:53 +08:00
|
|
|
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 {
|
Adds a json::Expr type to represent intermediate JSON expressions.
Summary:
This form can be created with a nice clang-format-friendly literal syntax,
and gets escaping right. It knows how to call unparse() on our Protocol types.
All the places where we pass around JSON internally now use this type.
Object properties are sorted (stored as std::map) and so serialization is
canonicalized, with optional prettyprinting (triggered by a -pretty flag).
This makes the lit tests much nicer to read and somewhat nicer to debug.
(Unfortunately the completion tests use CHECK-DAG, which only has
line-granularity, so pretty-printing is disabled there. In future we
could make completion ordering deterministic, or switch to unittests).
Compared to the current approach, it has some efficiencies like avoiding copies
of string literals used as object keys, but is probably slower overall.
I think the code/test quality benefits are worth it.
This patch doesn't attempt to do anything about JSON *parsing*.
It takes direction from the proposal in this doc[1], but is limited in scope
and visibility, for now.
I am of half a mind just to use Expr as the target of a parser, and maybe do a
little string deduplication, but not bother with clever memory allocation.
That would be simple, and fast enough for clangd...
[1] https://docs.google.com/document/d/1OEF9IauWwNuSigZzvvbjc1cVS1uGHRyGTXaoy3DjqM4/edit
+cc d0k so he can tell me not to use std::map.
Reviewers: ioeric, malaperle
Subscribers: bkramer, ilya-biryukov, mgorny, klimek
Differential Revision: https://reviews.llvm.org/D39435
llvm-svn: 317486
2017-11-06 23:40:30 +08:00
|
|
|
ObjectKey K;
|
|
|
|
Expr V;
|
|
|
|
};
|
|
|
|
|
2017-11-22 00:00:53 +08:00
|
|
|
inline Expr::ObjectExpr::ObjectExpr(std::initializer_list<KV> Properties) {
|
Adds a json::Expr type to represent intermediate JSON expressions.
Summary:
This form can be created with a nice clang-format-friendly literal syntax,
and gets escaping right. It knows how to call unparse() on our Protocol types.
All the places where we pass around JSON internally now use this type.
Object properties are sorted (stored as std::map) and so serialization is
canonicalized, with optional prettyprinting (triggered by a -pretty flag).
This makes the lit tests much nicer to read and somewhat nicer to debug.
(Unfortunately the completion tests use CHECK-DAG, which only has
line-granularity, so pretty-printing is disabled there. In future we
could make completion ordering deterministic, or switch to unittests).
Compared to the current approach, it has some efficiencies like avoiding copies
of string literals used as object keys, but is probably slower overall.
I think the code/test quality benefits are worth it.
This patch doesn't attempt to do anything about JSON *parsing*.
It takes direction from the proposal in this doc[1], but is limited in scope
and visibility, for now.
I am of half a mind just to use Expr as the target of a parser, and maybe do a
little string deduplication, but not bother with clever memory allocation.
That would be simple, and fast enough for clangd...
[1] https://docs.google.com/document/d/1OEF9IauWwNuSigZzvvbjc1cVS1uGHRyGTXaoy3DjqM4/edit
+cc d0k so he can tell me not to use std::map.
Reviewers: ioeric, malaperle
Subscribers: bkramer, ilya-biryukov, mgorny, klimek
Differential Revision: https://reviews.llvm.org/D39435
llvm-svn: 317486
2017-11-06 23:40:30 +08:00
|
|
|
for (const auto &P : Properties)
|
|
|
|
emplace(std::move(P.K), std::move(P.V));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Give Expr::{Object,Array} more convenient names for literal use.
|
2017-11-22 00:00:53 +08:00
|
|
|
using obj = Expr::ObjectExpr;
|
|
|
|
using ary = Expr::ArrayExpr;
|
|
|
|
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
};
|
Adds a json::Expr type to represent intermediate JSON expressions.
Summary:
This form can be created with a nice clang-format-friendly literal syntax,
and gets escaping right. It knows how to call unparse() on our Protocol types.
All the places where we pass around JSON internally now use this type.
Object properties are sorted (stored as std::map) and so serialization is
canonicalized, with optional prettyprinting (triggered by a -pretty flag).
This makes the lit tests much nicer to read and somewhat nicer to debug.
(Unfortunately the completion tests use CHECK-DAG, which only has
line-granularity, so pretty-printing is disabled there. In future we
could make completion ordering deterministic, or switch to unittests).
Compared to the current approach, it has some efficiencies like avoiding copies
of string literals used as object keys, but is probably slower overall.
I think the code/test quality benefits are worth it.
This patch doesn't attempt to do anything about JSON *parsing*.
It takes direction from the proposal in this doc[1], but is limited in scope
and visibility, for now.
I am of half a mind just to use Expr as the target of a parser, and maybe do a
little string deduplication, but not bother with clever memory allocation.
That would be simple, and fast enough for clangd...
[1] https://docs.google.com/document/d/1OEF9IauWwNuSigZzvvbjc1cVS1uGHRyGTXaoy3DjqM4/edit
+cc d0k so he can tell me not to use std::map.
Reviewers: ioeric, malaperle
Subscribers: bkramer, ilya-biryukov, mgorny, klimek
Differential Revision: https://reviews.llvm.org/D39435
llvm-svn: 317486
2017-11-06 23:40:30 +08:00
|
|
|
|
|
|
|
} // 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
|