//===---------------------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 LLDB_TOOLS_DEBUGSERVER_SOURCE_JSON_H
#define LLDB_TOOLS_DEBUGSERVER_SOURCE_JSON_H
#include "StdStringExtractor.h"
// C includes
#include <cinttypes>
#include <cstdint>
// C++ includes
#include <map>
#include <memory>
#include <ostream>
#include <string>
#include <vector>
class JSONValue {
public:
virtual void Write(std::ostream &s) = 0;
typedef std::shared_ptr<JSONValue> 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(std::ostream &s) override;
typedef std::shared_ptr<JSONString> 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<JSONNumber> SP;
// We create 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 <typename T, typename std::enable_if<
std::is_integral<T>::value &&
std::is_unsigned<T>::value>::type * = nullptr>
explicit JSONNumber(T u)
: JSONValue(JSONValue::Kind::Number), m_data_type(DataType::Unsigned) {
m_data.m_unsigned = u;
}
template <typename T,
typename std::enable_if<std::is_integral<T>::value &&
std::is_signed<T>::value>::type * = nullptr>
explicit JSONNumber(T s)
: JSONValue(JSONValue::Kind::Number), m_data_type(DataType::Signed) {
m_data.m_signed = s;
}
template <typename T, typename std::enable_if<
std::is_floating_point<T>::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(std::ostream &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(std::ostream &s) override;
typedef std::shared_ptr<JSONTrue> 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(std::ostream &s) override;
typedef std::shared_ptr<JSONFalse> 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(std::ostream &s) override;
typedef std::shared_ptr<JSONNull> 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(std::ostream &s) override;
typedef std::shared_ptr<JSONObject> 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) const;
/// Return keyed value as bool
///
/// \param[in] key
/// The value of the key to lookup
///
/// \param[out] value
/// The value of the key as a bool. Undefined if the key doesn't
/// exist or if the key is not either true or false.
///
/// \return
/// true if the key existed as was a bool value; false otherwise.
/// Note the return value is *not* the value of the bool, use
/// \b value for that.
bool GetObjectAsBool(const std::string &key, bool &value) const;
bool GetObjectAsString(const std::string &key, std::string &value) const;
~JSONObject() override = default;
private:
typedef std::map<std::string, JSONValue::SP> 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(std::ostream &s) override;
typedef std::shared_ptr<JSONArray> SP;
static bool classof(const JSONValue *V) {
return V->GetKind() == JSONValue::Kind::Array;
}
private:
typedef std::vector<JSONValue::SP> 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 StdStringExtractor {
public:
enum Token {
Invalid,
Status,
ObjectStart,
ObjectEnd,
ArrayStart,
ArrayEnd,
Comma,
Colon,
String,
Integer,
Float,
True,
False,
Null,
EndOfFile
};
JSONParser(const char *cstr);
int GetEscapedChar(bool &was_escaped);
Token GetToken(std::string &value);
JSONValue::SP ParseJSONValue();
protected:
JSONValue::SP ParseJSONValue(const std::string &value, const Token &token);
JSONValue::SP ParseJSONObject();
JSONValue::SP ParseJSONArray();
};
#endif // LLDB_TOOLS_DEBUGSERVER_SOURCE_JSON_H