Author: sammccall Date: Tue Nov 28 01:25:09 2017 New Revision: 319157 URL: http://llvm.org/viewvc/llvm-project?rev=319157&view=rev Log: [clangd] Add missing (but documented!) JSONExpr typed accessors
Summary: Noticed this when I tried to port the Protocol.h parsers. And tests for the inspect API, which caught a small bug. Reviewers: ioeric Subscribers: ilya-biryukov Differential Revision: https://reviews.llvm.org/D40399 Modified: clang-tools-extra/trunk/clangd/JSONExpr.cpp clang-tools-extra/trunk/clangd/JSONExpr.h clang-tools-extra/trunk/unittests/clangd/JSONExprTests.cpp Modified: clang-tools-extra/trunk/clangd/JSONExpr.cpp URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/JSONExpr.cpp?rev=319157&r1=319156&r2=319157&view=diff ============================================================================== --- clang-tools-extra/trunk/clangd/JSONExpr.cpp (original) +++ clang-tools-extra/trunk/clangd/JSONExpr.cpp Tue Nov 28 01:25:09 2017 @@ -161,7 +161,7 @@ bool Parser::parseExpr(Expr &Out) { } case '[': { Out = json::ary{}; - json::ary &A = *Out.array(); + json::ary &A = *Out.asArray(); eatWhitespace(); if (peek() == ']') { ++P; @@ -185,7 +185,7 @@ bool Parser::parseExpr(Expr &Out) { } case '{': { Out = json::obj{}; - json::obj &O = *Out.object(); + json::obj &O = *Out.asObject(); eatWhitespace(); if (peek() == '}') { ++P; @@ -507,17 +507,17 @@ bool operator==(const Expr &L, const Exp return false; switch (L.kind()) { case Expr::Null: - return L.null() == R.null(); + return *L.asNull() == *R.asNull(); case Expr::Boolean: - return L.boolean() == R.boolean(); + return *L.asBoolean() == *R.asBoolean(); case Expr::Number: - return L.boolean() == R.boolean(); + return *L.asNumber() == *R.asNumber(); case Expr::String: - return L.string() == R.string(); + return *L.asString() == *R.asString(); case Expr::Array: - return *L.array() == *R.array(); + return *L.asArray() == *R.asArray(); case Expr::Object: - return *L.object() == *R.object(); + return *L.asObject() == *R.asObject(); } llvm_unreachable("Unknown expression kind"); } Modified: clang-tools-extra/trunk/clangd/JSONExpr.h URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/JSONExpr.h?rev=319157&r1=319156&r2=319157&view=diff ============================================================================== --- clang-tools-extra/trunk/clangd/JSONExpr.h (original) +++ clang-tools-extra/trunk/clangd/JSONExpr.h Tue Nov 28 01:25:09 2017 @@ -55,14 +55,14 @@ namespace json { // object (json::obj) // // The kind can be queried directly, or implicitly via the typed accessors: -// if (Optional<StringRef> S = E.string()) +// if (Optional<StringRef> S = E.asString() // assert(E.kind() == Expr::String); // // Array and Object also have typed indexing accessors for easy traversal: // Expected<Expr> E = parse(R"( {"options": {"font": "sans-serif"}} )"); -// if (json::obj* O = E->object()) -// if (json::obj* Opts = O->object("options")) -// if (Optional<StringRef> Font = Opts->string("font")) +// if (json::obj* O = E->asObject()) +// if (json::obj* Opts = O->getObject("options")) +// if (Optional<StringRef> Font = Opts->getString("font")) // assert(Opts->at("font").kind() == Expr::String); // // === Serialization === @@ -166,38 +166,38 @@ public: } // Typed accessors return None/nullptr if the Expr is not of this type. - llvm::Optional<std::nullptr_t> null() const { + llvm::Optional<std::nullptr_t> asNull() const { if (LLVM_LIKELY(Type == T_Null)) return nullptr; return llvm::None; } - llvm::Optional<bool> boolean() const { - if (LLVM_LIKELY(Type == T_Null)) + llvm::Optional<bool> asBoolean() const { + if (LLVM_LIKELY(Type == T_Boolean)) return as<bool>(); return llvm::None; } - llvm::Optional<double> number() const { + llvm::Optional<double> asNumber() const { if (LLVM_LIKELY(Type == T_Number)) return as<double>(); return llvm::None; } - llvm::Optional<llvm::StringRef> string() const { + llvm::Optional<llvm::StringRef> asString() const { if (Type == T_String) return llvm::StringRef(as<std::string>()); if (LLVM_LIKELY(Type == T_StringRef)) return as<llvm::StringRef>(); return llvm::None; } - const ObjectExpr *object() const { + const ObjectExpr *asObject() const { return LLVM_LIKELY(Type == T_Object) ? &as<ObjectExpr>() : nullptr; } - ObjectExpr *object() { + ObjectExpr *asObject() { return LLVM_LIKELY(Type == T_Object) ? &as<ObjectExpr>() : nullptr; } - const ArrayExpr *array() const { + const ArrayExpr *asArray() const { return LLVM_LIKELY(Type == T_Array) ? &as<ArrayExpr>() : nullptr; } - ArrayExpr *array() { + ArrayExpr *asArray() { return LLVM_LIKELY(Type == T_Array) ? &as<ArrayExpr>() : nullptr; } @@ -292,6 +292,63 @@ public: Expr &operator[](ObjectKey &&K) { return emplace(std::move(K), Expr(nullptr)).first->second; } + + // Look up a property, returning nullptr if it doesn't exist. + json::Expr *get(const ObjectKey &K) { + auto I = find(K); + if (I == end()) + return nullptr; + return &I->second; + } + const json::Expr *get(const ObjectKey &K) const { + auto I = find(K); + if (I == end()) + return nullptr; + return &I->second; + } + // Typed accessors return None/nullptr if + // - the property doesn't exist + // - or it has the wrong type + llvm::Optional<std::nullptr_t> getNull(const ObjectKey &K) const { + if (auto *V = get(K)) + return V->asNull(); + return llvm::None; + } + llvm::Optional<bool> getBoolean(const ObjectKey &K) const { + if (auto *V = get(K)) + return V->asBoolean(); + return llvm::None; + } + llvm::Optional<double> getNumber(const ObjectKey &K) const { + if (auto *V = get(K)) + return V->asNumber(); + return llvm::None; + } + llvm::Optional<llvm::StringRef> getString(const ObjectKey &K) const { + if (auto *V = get(K)) + return V->asString(); + return llvm::None; + } + const ObjectExpr *getObject(const ObjectKey &K) const { + if (auto *V = get(K)) + return V->asObject(); + return nullptr; + } + ObjectExpr *getObject(const ObjectKey &K) { + if (auto *V = get(K)) + return V->asObject(); + return nullptr; + } + const ArrayExpr *getArray(const ObjectKey &K) const { + if (auto *V = get(K)) + return V->asArray(); + return nullptr; + } + ArrayExpr *getArray(const ObjectKey &K) { + if (auto *V = get(K)) + return V->asArray(); + return nullptr; + } }; class ArrayExpr : public std::vector<Expr> { @@ -306,6 +363,26 @@ public: for (const auto &V : C) emplace_back(V); } + + // Typed accessors return None/nullptr if the element has the wrong type. + llvm::Optional<std::nullptr_t> getNull(size_t I) const { + return (*this)[I].asNull(); + } + llvm::Optional<bool> getBoolean(size_t I) const { + return (*this)[I].asBoolean(); + } + llvm::Optional<double> getNumber(size_t I) const { + return (*this)[I].asNumber(); + } + llvm::Optional<llvm::StringRef> getString(size_t I) const { + return (*this)[I].asString(); + } + const ObjectExpr *getObject(size_t I) const { + return (*this)[I].asObject(); + } + ObjectExpr *getObject(size_t I) { return (*this)[I].asObject(); } + const ArrayExpr *getArray(size_t I) const { return (*this)[I].asArray(); } + ArrayExpr *getArray(size_t I) { return (*this)[I].asArray(); } }; private: Modified: clang-tools-extra/trunk/unittests/clangd/JSONExprTests.cpp URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/clangd/JSONExprTests.cpp?rev=319157&r1=319156&r2=319157&view=diff ============================================================================== --- clang-tools-extra/trunk/unittests/clangd/JSONExprTests.cpp (original) +++ clang-tools-extra/trunk/unittests/clangd/JSONExprTests.cpp Tue Nov 28 01:25:09 2017 @@ -167,7 +167,6 @@ TEST(JSONTest, ParseErrors) { ExpectErr("Unexpected EOF", ""); ExpectErr("Unexpected EOF", "["); ExpectErr("Text after end of document", "[][]"); - ExpectErr("Text after end of document", "[][]"); ExpectErr("Invalid bareword", "fuzzy"); ExpectErr("Expected , or ]", "[2?]"); ExpectErr("Expected object key", "{a:2}"); @@ -185,6 +184,49 @@ TEST(JSONTest, ParseErrors) { })"); } +TEST(JSONTest, Inspection) { + llvm::Expected<Expr> Doc = parse(R"( + { + "null": null, + "boolean": false, + "number": 2.78, + "string": "json", + "array": [null, true, 3.14, "hello", [1,2,3], {"time": "arrow"}], + "object": {"fruit": "banana"} + } + )"); + EXPECT_TRUE(!!Doc); + + obj *O = Doc->asObject(); + ASSERT_TRUE(O); + + EXPECT_FALSE(O->getNull("missing")); + EXPECT_FALSE(O->getNull("boolean")); + EXPECT_TRUE(O->getNull("null")); + + EXPECT_EQ(O->getNumber("number"), llvm::Optional<double>(2.78)); + EXPECT_EQ(O->getString("string"), llvm::Optional<llvm::StringRef>("json")); + ASSERT_FALSE(O->getObject("missing")); + ASSERT_FALSE(O->getObject("array")); + ASSERT_TRUE(O->getObject("object")); + EXPECT_EQ(*O->getObject("object"), (obj{{"fruit", "banana"}})); + + ary *A = O->getArray("array"); + ASSERT_TRUE(A); + EXPECT_EQ(A->getBoolean(1), llvm::Optional<bool>(true)); + ASSERT_TRUE(A->getArray(4)); + EXPECT_EQ(*A->getArray(4), (ary{1, 2, 3})); + int I = 0; + for (Expr &E : *A) { + if (I++ == 5) { + ASSERT_TRUE(E.asObject()); + EXPECT_EQ(E.asObject()->getString("time"), + llvm::Optional<llvm::StringRef>("arrow")); + } else + EXPECT_FALSE(E.asObject()); + } +} + } // namespace } // namespace json } // namespace clangd _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits