Index: lldb/trunk/include/lldb/Utility/JSON.h =================================================================== --- lldb/trunk/include/lldb/Utility/JSON.h +++ lldb/trunk/include/lldb/Utility/JSON.h @@ -1,283 +0,0 @@ -//===---------------------JSON.h --------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef utility_JSON_h_ -#define utility_JSON_h_ - -#include "lldb/Utility/StringExtractor.h" - -#include -#include -#include -#include -#include - -#include - -namespace lldb_private { -class Stream; - -class JSONValue { -public: - virtual void Write(Stream &s) = 0; - - typedef std::shared_ptr SP; - - enum class Kind { String, Number, True, False, Null, Object, Array }; - - JSONValue(Kind k) : m_kind(k) {} - - Kind GetKind() const { return m_kind; } - - virtual ~JSONValue() = default; - -private: - const Kind m_kind; -}; - -class JSONString : public JSONValue { -public: - JSONString(); - JSONString(const char *s); - JSONString(const std::string &s); - - JSONString(const JSONString &s) = delete; - JSONString &operator=(const JSONString &s) = delete; - - void Write(Stream &s) override; - - typedef std::shared_ptr SP; - - std::string GetData() { return m_data; } - - static bool classof(const JSONValue *V) { - return V->GetKind() == JSONValue::Kind::String; - } - - ~JSONString() override = default; - -private: - static std::string json_string_quote_metachars(const std::string &); - - std::string m_data; -}; - -class JSONNumber : public JSONValue { -public: - typedef std::shared_ptr SP; - - // We cretae a constructor for all integer and floating point type with using - // templates and - // SFINAE to avoid having ambiguous overloads because of the implicit type - // promotion. If we - // would have constructors only with int64_t, uint64_t and double types then - // constructing a JSONNumber from an int32_t (or any other similar type) - // would fail to compile. - - template ::value && - std::is_unsigned::value>::type * = nullptr> - explicit JSONNumber(T u) - : JSONValue(JSONValue::Kind::Number), m_data_type(DataType::Unsigned) { - m_data.m_unsigned = u; - } - - template ::value && - std::is_signed::value>::type * = nullptr> - explicit JSONNumber(T s) - : JSONValue(JSONValue::Kind::Number), m_data_type(DataType::Signed) { - m_data.m_signed = s; - } - - template ::value>::type * = nullptr> - explicit JSONNumber(T d) - : JSONValue(JSONValue::Kind::Number), m_data_type(DataType::Double) { - m_data.m_double = d; - } - - ~JSONNumber() override = default; - - JSONNumber(const JSONNumber &s) = delete; - JSONNumber &operator=(const JSONNumber &s) = delete; - - void Write(Stream &s) override; - - uint64_t GetAsUnsigned() const; - - int64_t GetAsSigned() const; - - double GetAsDouble() const; - - static bool classof(const JSONValue *V) { - return V->GetKind() == JSONValue::Kind::Number; - } - -private: - enum class DataType : uint8_t { Unsigned, Signed, Double } m_data_type; - - union { - uint64_t m_unsigned; - int64_t m_signed; - double m_double; - } m_data; -}; - -class JSONTrue : public JSONValue { -public: - JSONTrue(); - - JSONTrue(const JSONTrue &s) = delete; - JSONTrue &operator=(const JSONTrue &s) = delete; - - void Write(Stream &s) override; - - typedef std::shared_ptr SP; - - static bool classof(const JSONValue *V) { - return V->GetKind() == JSONValue::Kind::True; - } - - ~JSONTrue() override = default; -}; - -class JSONFalse : public JSONValue { -public: - JSONFalse(); - - JSONFalse(const JSONFalse &s) = delete; - JSONFalse &operator=(const JSONFalse &s) = delete; - - void Write(Stream &s) override; - - typedef std::shared_ptr SP; - - static bool classof(const JSONValue *V) { - return V->GetKind() == JSONValue::Kind::False; - } - - ~JSONFalse() override = default; -}; - -class JSONNull : public JSONValue { -public: - JSONNull(); - - JSONNull(const JSONNull &s) = delete; - JSONNull &operator=(const JSONNull &s) = delete; - - void Write(Stream &s) override; - - typedef std::shared_ptr SP; - - static bool classof(const JSONValue *V) { - return V->GetKind() == JSONValue::Kind::Null; - } - - ~JSONNull() override = default; -}; - -class JSONObject : public JSONValue { -public: - JSONObject(); - - JSONObject(const JSONObject &s) = delete; - JSONObject &operator=(const JSONObject &s) = delete; - - void Write(Stream &s) override; - - typedef std::shared_ptr SP; - - static bool classof(const JSONValue *V) { - return V->GetKind() == JSONValue::Kind::Object; - } - - bool SetObject(const std::string &key, JSONValue::SP value); - - JSONValue::SP GetObject(const std::string &key); - - ~JSONObject() override = default; - -private: - typedef std::map Map; - typedef Map::iterator Iterator; - Map m_elements; -}; - -class JSONArray : public JSONValue { -public: - JSONArray(); - - JSONArray(const JSONArray &s) = delete; - JSONArray &operator=(const JSONArray &s) = delete; - - void Write(Stream &s) override; - - typedef std::shared_ptr SP; - - static bool classof(const JSONValue *V) { - return V->GetKind() == JSONValue::Kind::Array; - } - -private: - typedef std::vector Vector; - typedef Vector::iterator Iterator; - typedef Vector::size_type Index; - typedef Vector::size_type Size; - -public: - bool SetObject(Index i, JSONValue::SP value); - - bool AppendObject(JSONValue::SP value); - - JSONValue::SP GetObject(Index i); - - Size GetNumElements(); - - ~JSONArray() override = default; - - Vector m_elements; -}; - -class JSONParser : public StringExtractor { -public: - enum Token { - Invalid, - Status, - ObjectStart, - ObjectEnd, - ArrayStart, - ArrayEnd, - Comma, - Colon, - String, - Integer, - Float, - True, - False, - Null, - EndOfFile - }; - - JSONParser(llvm::StringRef data); - - int GetEscapedChar(bool &was_escaped); - - Token GetToken(std::string &value); - - JSONValue::SP ParseJSONValue(); - -protected: - JSONValue::SP ParseJSONObject(); - - JSONValue::SP ParseJSONArray(); -}; -} // namespace lldb_private - -#endif // utility_JSON_h_ Index: lldb/trunk/source/Utility/CMakeLists.txt =================================================================== --- lldb/trunk/source/Utility/CMakeLists.txt +++ lldb/trunk/source/Utility/CMakeLists.txt @@ -27,7 +27,6 @@ FileSpec.cpp GDBRemote.cpp IOObject.cpp - JSON.cpp LLDBAssert.cpp Listener.cpp Log.cpp Index: lldb/trunk/source/Utility/JSON.cpp =================================================================== --- lldb/trunk/source/Utility/JSON.cpp +++ lldb/trunk/source/Utility/JSON.cpp @@ -1,550 +0,0 @@ -//===--------------------- JSON.cpp -----------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "lldb/Utility/JSON.h" - -#include "lldb/Utility/Stream.h" -#include "lldb/Utility/StreamString.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/ErrorHandling.h" - -#include -#include -#include -#include - -using namespace lldb_private; - -std::string JSONString::json_string_quote_metachars(const std::string &s) { - if (s.find_first_of("\\\n\"") == std::string::npos) - return s; - - std::string output; - const size_t s_size = s.size(); - const char *s_chars = s.c_str(); - for (size_t i = 0; i < s_size; i++) { - unsigned char ch = *(s_chars + i); - if (ch == '"' || ch == '\\' || ch == '\n') { - output.push_back('\\'); - if (ch == '\n') ch = 'n'; - } - output.push_back(ch); - } - return output; -} - -JSONString::JSONString() : JSONValue(JSONValue::Kind::String), m_data() {} - -JSONString::JSONString(const char *s) - : JSONValue(JSONValue::Kind::String), m_data(s ? s : "") {} - -JSONString::JSONString(const std::string &s) - : JSONValue(JSONValue::Kind::String), m_data(s) {} - -void JSONString::Write(Stream &s) { - s.Printf("\"%s\"", json_string_quote_metachars(m_data).c_str()); -} - -uint64_t JSONNumber::GetAsUnsigned() const { - switch (m_data_type) { - case DataType::Unsigned: - return m_data.m_unsigned; - case DataType::Signed: - return static_cast(m_data.m_signed); - case DataType::Double: - return static_cast(m_data.m_double); - } - llvm_unreachable("Unhandled data type"); -} - -int64_t JSONNumber::GetAsSigned() const { - switch (m_data_type) { - case DataType::Unsigned: - return static_cast(m_data.m_unsigned); - case DataType::Signed: - return m_data.m_signed; - case DataType::Double: - return static_cast(m_data.m_double); - } - llvm_unreachable("Unhandled data type"); -} - -double JSONNumber::GetAsDouble() const { - switch (m_data_type) { - case DataType::Unsigned: - return static_cast(m_data.m_unsigned); - case DataType::Signed: - return static_cast(m_data.m_signed); - case DataType::Double: - return m_data.m_double; - } - llvm_unreachable("Unhandled data type"); -} - -void JSONNumber::Write(Stream &s) { - switch (m_data_type) { - case DataType::Unsigned: - s.Printf("%" PRIu64, m_data.m_unsigned); - break; - case DataType::Signed: - s.Printf("%" PRId64, m_data.m_signed); - break; - case DataType::Double: - s.Printf("%g", m_data.m_double); - break; - } -} - -JSONTrue::JSONTrue() : JSONValue(JSONValue::Kind::True) {} - -void JSONTrue::Write(Stream &s) { s.Printf("true"); } - -JSONFalse::JSONFalse() : JSONValue(JSONValue::Kind::False) {} - -void JSONFalse::Write(Stream &s) { s.Printf("false"); } - -JSONNull::JSONNull() : JSONValue(JSONValue::Kind::Null) {} - -void JSONNull::Write(Stream &s) { s.Printf("null"); } - -JSONObject::JSONObject() : JSONValue(JSONValue::Kind::Object) {} - -void JSONObject::Write(Stream &s) { - bool first = true; - s.PutChar('{'); - auto iter = m_elements.begin(), end = m_elements.end(); - for (; iter != end; iter++) { - if (first) - first = false; - else - s.PutChar(','); - JSONString key(iter->first); - JSONValue::SP value(iter->second); - key.Write(s); - s.PutChar(':'); - value->Write(s); - } - s.PutChar('}'); -} - -bool JSONObject::SetObject(const std::string &key, JSONValue::SP value) { - if (key.empty() || nullptr == value.get()) - return false; - m_elements[key] = value; - return true; -} - -JSONValue::SP JSONObject::GetObject(const std::string &key) { - auto iter = m_elements.find(key), end = m_elements.end(); - if (iter == end) - return JSONValue::SP(); - return iter->second; -} - -JSONArray::JSONArray() : JSONValue(JSONValue::Kind::Array) {} - -void JSONArray::Write(Stream &s) { - bool first = true; - s.PutChar('['); - auto iter = m_elements.begin(), end = m_elements.end(); - for (; iter != end; iter++) { - if (first) - first = false; - else - s.PutChar(','); - (*iter)->Write(s); - } - s.PutChar(']'); -} - -bool JSONArray::SetObject(Index i, JSONValue::SP value) { - if (value.get() == nullptr) - return false; - if (i < m_elements.size()) { - m_elements[i] = value; - return true; - } - if (i == m_elements.size()) { - m_elements.push_back(value); - return true; - } - return false; -} - -bool JSONArray::AppendObject(JSONValue::SP value) { - if (value.get() == nullptr) - return false; - m_elements.push_back(value); - return true; -} - -JSONValue::SP JSONArray::GetObject(Index i) { - if (i < m_elements.size()) - return m_elements[i]; - return JSONValue::SP(); -} - -JSONArray::Size JSONArray::GetNumElements() { return m_elements.size(); } - -JSONParser::JSONParser(llvm::StringRef data) : StringExtractor(data) {} - -JSONParser::Token JSONParser::GetToken(std::string &value) { - StreamString error; - - value.clear(); - SkipSpaces(); - const uint64_t start_index = m_index; - const char ch = GetChar(); - switch (ch) { - case '{': - return Token::ObjectStart; - case '}': - return Token::ObjectEnd; - case '[': - return Token::ArrayStart; - case ']': - return Token::ArrayEnd; - case ',': - return Token::Comma; - case ':': - return Token::Colon; - case '\0': - return Token::EndOfFile; - case 't': - if (GetChar() == 'r') - if (GetChar() == 'u') - if (GetChar() == 'e') - return Token::True; - break; - - case 'f': - if (GetChar() == 'a') - if (GetChar() == 'l') - if (GetChar() == 's') - if (GetChar() == 'e') - return Token::False; - break; - - case 'n': - if (GetChar() == 'u') - if (GetChar() == 'l') - if (GetChar() == 'l') - return Token::Null; - break; - - case '"': { - while (true) { - bool was_escaped = false; - int escaped_ch = GetEscapedChar(was_escaped); - if (escaped_ch == -1) { - error.Printf( - "error: an error occurred getting a character from offset %" PRIu64, - start_index); - value = std::move(error.GetString()); - return Token::Status; - - } else { - const bool is_end_quote = escaped_ch == '"'; - const bool is_null = escaped_ch == 0; - if (was_escaped || (!is_end_quote && !is_null)) { - if (CHAR_MIN <= escaped_ch && escaped_ch <= CHAR_MAX) { - value.append(1, static_cast(escaped_ch)); - } else { - error.Printf("error: wide character support is needed for unicode " - "character 0x%4.4x at offset %" PRIu64, - escaped_ch, start_index); - value = std::move(error.GetString()); - return Token::Status; - } - } else if (is_end_quote) { - return Token::String; - } else if (is_null) { - value = "error: missing end quote for string"; - return Token::Status; - } - } - } - } break; - - case '-': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': { - bool done = false; - bool got_decimal_point = false; - uint64_t exp_index = 0; - bool got_int_digits = (ch >= '0') && (ch <= '9'); - bool got_frac_digits = false; - bool got_exp_digits = false; - while (!done) { - const char next_ch = PeekChar(); - switch (next_ch) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - if (exp_index != 0) { - got_exp_digits = true; - } else if (got_decimal_point) { - got_frac_digits = true; - } else { - got_int_digits = true; - } - ++m_index; // Skip this character - break; - - case '.': - if (got_decimal_point) { - error.Printf("error: extra decimal point found at offset %" PRIu64, - start_index); - value = std::move(error.GetString()); - return Token::Status; - } else { - got_decimal_point = true; - ++m_index; // Skip this character - } - break; - - case 'e': - case 'E': - if (exp_index != 0) { - error.Printf( - "error: extra exponent character found at offset %" PRIu64, - start_index); - value = std::move(error.GetString()); - return Token::Status; - } else { - exp_index = m_index; - ++m_index; // Skip this character - } - break; - - case '+': - case '-': - // The '+' and '-' can only come after an exponent character... - if (exp_index == m_index - 1) { - ++m_index; // Skip the exponent sign character - } else { - error.Printf("error: unexpected %c character at offset %" PRIu64, - next_ch, start_index); - value = std::move(error.GetString()); - return Token::Status; - } - break; - - default: - done = true; - break; - } - } - - if (m_index > start_index) { - value = m_packet.substr(start_index, m_index - start_index); - if (got_decimal_point) { - if (exp_index != 0) { - // We have an exponent, make sure we got exponent digits - if (got_exp_digits) { - return Token::Float; - } else { - error.Printf("error: got exponent character but no exponent digits " - "at offset in float value \"%s\"", - value.c_str()); - value = std::move(error.GetString()); - return Token::Status; - } - } else { - // No exponent, but we need at least one decimal after the decimal - // point - if (got_frac_digits) { - return Token::Float; - } else { - error.Printf("error: no digits after decimal point \"%s\"", - value.c_str()); - value = std::move(error.GetString()); - return Token::Status; - } - } - } else { - // No decimal point - if (got_int_digits) { - // We need at least some integer digits to make an integer - return Token::Integer; - } else { - error.Printf("error: no digits negate sign \"%s\"", value.c_str()); - value = std::move(error.GetString()); - return Token::Status; - } - } - } else { - error.Printf("error: invalid number found at offset %" PRIu64, - start_index); - value = std::move(error.GetString()); - return Token::Status; - } - } break; - default: - break; - } - error.Printf("error: failed to parse token at offset %" PRIu64 - " (around character '%c')", - start_index, ch); - value = std::move(error.GetString()); - return Token::Status; -} - -int JSONParser::GetEscapedChar(bool &was_escaped) { - was_escaped = false; - const char ch = GetChar(); - if (ch == '\\') { - was_escaped = true; - const char ch2 = GetChar(); - switch (ch2) { - case '"': - case '\\': - case '/': - default: - break; - - case 'b': - return '\b'; - case 'f': - return '\f'; - case 'n': - return '\n'; - case 'r': - return '\r'; - case 't': - return '\t'; - case 'u': { - const int hi_byte = DecodeHexU8(); - const int lo_byte = DecodeHexU8(); - if (hi_byte >= 0 && lo_byte >= 0) - return hi_byte << 8 | lo_byte; - return -1; - } break; - } - return ch2; - } - return ch; -} - -JSONValue::SP JSONParser::ParseJSONObject() { - // The "JSONParser::Token::ObjectStart" token should have already been - // consumed by the time this function is called - std::unique_ptr dict_up(new JSONObject()); - - std::string value; - std::string key; - while (true) { - JSONParser::Token token = GetToken(value); - - if (token == JSONParser::Token::String) { - key.swap(value); - token = GetToken(value); - if (token == JSONParser::Token::Colon) { - JSONValue::SP value_sp = ParseJSONValue(); - if (value_sp) - dict_up->SetObject(key, value_sp); - else - break; - } - } else if (token == JSONParser::Token::ObjectEnd) { - return JSONValue::SP(dict_up.release()); - } else if (token == JSONParser::Token::Comma) { - continue; - } else { - break; - } - } - return JSONValue::SP(); -} - -JSONValue::SP JSONParser::ParseJSONArray() { - // The "JSONParser::Token::ObjectStart" token should have already been - // consumed by the time this function is called - std::unique_ptr array_up(new JSONArray()); - - std::string value; - std::string key; - while (true) { - JSONValue::SP value_sp = ParseJSONValue(); - if (value_sp) - array_up->AppendObject(value_sp); - else - break; - - JSONParser::Token token = GetToken(value); - if (token == JSONParser::Token::Comma) { - continue; - } else if (token == JSONParser::Token::ArrayEnd) { - return JSONValue::SP(array_up.release()); - } else { - break; - } - } - return JSONValue::SP(); -} - -JSONValue::SP JSONParser::ParseJSONValue() { - std::string value; - const JSONParser::Token token = GetToken(value); - switch (token) { - case JSONParser::Token::ObjectStart: - return ParseJSONObject(); - - case JSONParser::Token::ArrayStart: - return ParseJSONArray(); - - case JSONParser::Token::Integer: { - if (value.front() == '-') { - int64_t sval = 0; - if (!llvm::StringRef(value).getAsInteger(0, sval)) - return JSONValue::SP(new JSONNumber(sval)); - } else { - uint64_t uval = 0; - if (!llvm::StringRef(value).getAsInteger(0, uval)) - return JSONValue::SP(new JSONNumber(uval)); - } - } break; - - case JSONParser::Token::Float: { - double D; - if (!llvm::StringRef(value).getAsDouble(D)) - return JSONValue::SP(new JSONNumber(D)); - } break; - - case JSONParser::Token::String: - return JSONValue::SP(new JSONString(value)); - - case JSONParser::Token::True: - return JSONValue::SP(new JSONTrue()); - - case JSONParser::Token::False: - return JSONValue::SP(new JSONFalse()); - - case JSONParser::Token::Null: - return JSONValue::SP(new JSONNull()); - - default: - break; - } - return JSONValue::SP(); -} Index: lldb/trunk/unittests/Utility/CMakeLists.txt =================================================================== --- lldb/trunk/unittests/Utility/CMakeLists.txt +++ lldb/trunk/unittests/Utility/CMakeLists.txt @@ -11,7 +11,6 @@ EventTest.cpp FileSpecTest.cpp FlagsTest.cpp - JSONTest.cpp ListenerTest.cpp LogTest.cpp NameMatchesTest.cpp Index: lldb/trunk/unittests/Utility/JSONTest.cpp =================================================================== --- lldb/trunk/unittests/Utility/JSONTest.cpp +++ lldb/trunk/unittests/Utility/JSONTest.cpp @@ -1,26 +0,0 @@ -#include "gtest/gtest.h" - -#include "lldb/Utility/JSON.h" -#include "lldb/Utility/StreamString.h" - -using namespace lldb_private; - -TEST(JSONTest, Dictionary) { - JSONObject o; - o.SetObject("key", std::make_shared("value")); - - StreamString stream; - o.Write(stream); - - ASSERT_EQ(stream.GetString(), R"({"key":"value"})"); -} - -TEST(JSONTest, Newlines) { - JSONObject o; - o.SetObject("key", std::make_shared("hello\nworld")); - - StreamString stream; - o.Write(stream); - - ASSERT_EQ(stream.GetString(), R"({"key":"hello\nworld"})"); -}