aizatsky updated this revision to Diff 70877.
aizatsky added a comment.
- getting rid of StringExtractor
- renaming methods to lowerCase.
https://reviews.llvm.org/D24369
Files:
.clang-tidy
include/llvm/Support/JSON.h
lib/Support/CMakeLists.txt
lib/Support/JSON.cpp
unittests/Support/CMakeLists.txt
unittests/Support/JSONTest.cpp
Index: unittests/Support/JSONTest.cpp
===================================================================
--- /dev/null
+++ unittests/Support/JSONTest.cpp
@@ -0,0 +1,46 @@
+//===- llvm/unittest/Support/JSONTest.cpp - JSON.cpp tests ---===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "gtest/gtest.h"
+
+#include "llvm/Support/JSON.h"
+
+using namespace llvm;
+
+static ::testing::AssertionResult MatchRoundtrip(std::string Text) {
+ JSONParser Parser(Text.c_str());
+ auto Obj = Parser.parseJSONValue();
+
+ if (!Obj) {
+ return Text == "null"
+ ? ::testing::AssertionSuccess()
+ : ::testing::AssertionFailure() << "can't parse input: " << Text;
+ }
+
+ std::string S;
+ raw_string_ostream Out(S);
+ Obj->write(Out);
+
+ std::string Actual = Out.str();
+ if (Actual != Text) {
+ return ::testing::AssertionFailure() << "expected: " << Text
+ << " actual: " << Actual;
+ }
+ return ::testing::AssertionSuccess();
+}
+
+TEST(JSON, Roundtrip) {
+ EXPECT_TRUE(MatchRoundtrip("0"));
+ EXPECT_TRUE(MatchRoundtrip("3.145150e+00"));
+ EXPECT_TRUE(MatchRoundtrip("{}"));
+ EXPECT_TRUE(MatchRoundtrip("{\"a\":1,\"b\":2}"));
+ EXPECT_TRUE(MatchRoundtrip("[]"));
+ EXPECT_TRUE(MatchRoundtrip("[0]"));
+ EXPECT_TRUE(MatchRoundtrip("[1,\"two\",3]"));
+}
Index: unittests/Support/CMakeLists.txt
===================================================================
--- unittests/Support/CMakeLists.txt
+++ unittests/Support/CMakeLists.txt
@@ -19,6 +19,7 @@
ErrorTest.cpp
ErrorOrTest.cpp
FileOutputBufferTest.cpp
+ JSONTest.cpp
LEB128Test.cpp
LineIteratorTest.cpp
LockFileManagerTest.cpp
Index: lib/Support/JSON.cpp
===================================================================
--- /dev/null
+++ lib/Support/JSON.cpp
@@ -0,0 +1,595 @@
+//===--------------------- JSON.cpp -----------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Support/JSON.h"
+
+#include <limits.h>
+#include <sstream>
+
+#include "llvm/Support/ErrorHandling.h"
+
+using namespace llvm;
+
+std::string JSONString::jsonStringQuoteMetachars(const std::string &S) {
+ if (S.find('"') == std::string::npos)
+ return S;
+
+ std::string Output;
+ const size_t Size = S.size();
+ const char *Chars = S.c_str();
+ for (size_t I = 0; I < Size; I++) {
+ unsigned char Ch = *(Chars + I);
+ if (Ch == '"') {
+ Output.push_back('\\');
+ }
+ Output.push_back(Ch);
+ }
+ return Output;
+}
+
+JSONString::JSONString() : JSONValue(JSONValue::Kind::String), Data() {}
+
+JSONString::JSONString(const char *S)
+ : JSONValue(JSONValue::Kind::String), Data(S ? S : "") {}
+
+JSONString::JSONString(const std::string &S)
+ : JSONValue(JSONValue::Kind::String), Data(S) {}
+
+void JSONString::write(raw_ostream &OS) const {
+ OS << "\"" << jsonStringQuoteMetachars(Data) << "\"";
+}
+
+uint64_t JSONNumber::getAsUnsigned() const {
+ switch (TheDataType) {
+ case DataType::Unsigned:
+ return Data.Unsigned;
+ case DataType::Signed:
+ return (uint64_t)Data.Signed;
+ case DataType::Double:
+ return (uint64_t)Data.Double;
+ }
+ llvm_unreachable("Unhandled data type");
+}
+
+int64_t JSONNumber::getAsSigned() const {
+ switch (TheDataType) {
+ case DataType::Unsigned:
+ return (int64_t)Data.Unsigned;
+ case DataType::Signed:
+ return Data.Signed;
+ case DataType::Double:
+ return (int64_t)Data.Double;
+ }
+ llvm_unreachable("Unhandled data type");
+}
+
+double JSONNumber::getAsDouble() const {
+ switch (TheDataType) {
+ case DataType::Unsigned:
+ return (double)Data.Unsigned;
+ case DataType::Signed:
+ return (double)Data.Signed;
+ case DataType::Double:
+ return Data.Double;
+ }
+ llvm_unreachable("Unhandled data type");
+}
+
+void JSONNumber::write(raw_ostream &OS) const {
+ switch (TheDataType) {
+ case DataType::Unsigned:
+ OS << Data.Unsigned;
+ break;
+ case DataType::Signed:
+ OS << Data.Signed;
+ break;
+ case DataType::Double:
+ OS << Data.Double;
+ break;
+ }
+}
+
+JSONTrue::JSONTrue() : JSONValue(JSONValue::Kind::True) {}
+
+void JSONTrue::write(raw_ostream &OS) const { OS << "true"; }
+
+JSONFalse::JSONFalse() : JSONValue(JSONValue::Kind::False) {}
+
+void JSONFalse::write(raw_ostream &OS) const { OS << "false"; }
+
+JSONNull::JSONNull() : JSONValue(JSONValue::Kind::Null) {}
+
+void JSONNull::write(raw_ostream &OS) const { OS << "null"; }
+
+JSONObject::JSONObject() : JSONValue(JSONValue::Kind::Object) {}
+
+void JSONObject::write(raw_ostream &OS) const {
+ bool First = true;
+ OS << '{';
+ auto Iter = Elements.begin(), End = Elements.end();
+ for (; Iter != End; Iter++) {
+ if (First)
+ First = false;
+ else
+ OS << ',';
+ JSONString Key(Iter->first);
+ JSONValue::SP Value(Iter->second);
+ Key.write(OS);
+ OS << ':';
+ Value->write(OS);
+ }
+ OS << '}';
+}
+
+bool JSONObject::setObject(const std::string &Key, JSONValue::SP Value) {
+ if (Key.empty() || nullptr == Value.get())
+ return false;
+ Elements[Key] = Value;
+ return true;
+}
+
+JSONValue::SP JSONObject::getObject(const std::string &Key) {
+ auto Iter = Elements.find(Key), End = Elements.end();
+ if (Iter == End)
+ return JSONValue::SP();
+ return Iter->second;
+}
+
+JSONArray::JSONArray() : JSONValue(JSONValue::Kind::Array) {}
+
+void JSONArray::write(raw_ostream &OS) const {
+ bool First = true;
+ OS << '[';
+ auto Iter = Elements.begin(), End = Elements.end();
+ for (; Iter != End; Iter++) {
+ if (First)
+ First = false;
+ else
+ OS << ',';
+ (*Iter)->write(OS);
+ }
+ OS << ']';
+}
+
+bool JSONArray::setObject(Index I, JSONValue::SP Value) {
+ if (Value.get() == nullptr)
+ return false;
+ if (I < Elements.size()) {
+ Elements[I] = Value;
+ return true;
+ }
+ if (I == Elements.size()) {
+ Elements.push_back(Value);
+ return true;
+ }
+ return false;
+}
+
+bool JSONArray::appendObject(JSONValue::SP Value) {
+ if (Value.get() == nullptr)
+ return false;
+ Elements.push_back(Value);
+ return true;
+}
+
+JSONValue::SP JSONArray::getObject(Index I) {
+ if (I < Elements.size())
+ return Elements[I];
+ return JSONValue::SP();
+}
+
+JSONArray::Size JSONArray::getNumElements() { return Elements.size(); }
+
+JSONParser::JSONParser(const char *CStr) : Index(0) {
+ if (CStr)
+ Buffer.assign(CStr);
+}
+
+JSONParser::Token JSONParser::getToken(std::string &Value) {
+ std::stringstream Error;
+
+ Value.clear();
+ skipSpaces();
+ const uint64_t StartIndex = 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 (1) {
+ bool WasEscaped = false;
+ int EscapedCh = getEscapedChar(WasEscaped);
+ if (EscapedCh == -1) {
+ Error << "error: an error occurred getting a character from offset "
+ << StartIndex;
+ Value = Error.str();
+ return Token::Error;
+
+ } else {
+ const bool IsEndQuote = EscapedCh == '"';
+ const bool IsNull = EscapedCh == 0;
+ if (WasEscaped || (!IsEndQuote && !IsNull)) {
+ if (CHAR_MIN <= EscapedCh && EscapedCh <= CHAR_MAX) {
+ Value.append(1, (char)EscapedCh);
+ } else {
+ Error << "error: wide character support is needed for unicode "
+ "character 0x"
+ << std::hex << EscapedCh << std::dec << " at offset "
+ << StartIndex;
+ Value = Error.str();
+ return Token::Error;
+ }
+ } else if (IsEndQuote) {
+ return Token::String;
+ } else if (IsNull) {
+ Value = "error: missing end quote for string";
+ return Token::Error;
+ }
+ }
+ }
+ } break;
+
+ case '-':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9': {
+ uint64_t ExpIndex = 0;
+ bool Done = false;
+ bool GotDecimalPoint = false;
+ bool GotIntDigits = (Ch >= '0') && (Ch <= '9');
+ bool GotFracDigits = false;
+ bool GotExpDigits = false;
+ while (!Done) {
+ const char NextCh = peekChar();
+ switch (NextCh) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (ExpIndex != 0) {
+ GotExpDigits = true;
+ } else if (GotDecimalPoint) {
+ GotFracDigits = true;
+ } else {
+ GotIntDigits = true;
+ }
+ ++Index; // Skip this character
+ break;
+
+ case '.':
+ if (GotDecimalPoint) {
+ Error << "error: extra decimal point found at offset " << StartIndex;
+ Value = Error.str();
+ return Token::Error;
+ } else {
+ GotDecimalPoint = true;
+ ++Index; // Skip this character
+ }
+ break;
+
+ case 'e':
+ case 'E':
+ if (ExpIndex != 0) {
+ Error << "error: extra exponent character found at offset "
+ << StartIndex;
+ Value = Error.str();
+ return Token::Error;
+ } else {
+ ExpIndex = Index;
+ ++Index; // Skip this character
+ }
+ break;
+
+ case '+':
+ case '-':
+ // The '+' and '-' can only come after an exponent character...
+ if (ExpIndex == Index - 1) {
+ ++Index; // Skip the exponent sign character
+ } else {
+ Error << "error: unexpected " << NextCh << " character at offset "
+ << StartIndex;
+ Value = Error.str();
+ return Token::Error;
+ }
+ break;
+
+ default:
+ Done = true;
+ break;
+ }
+ }
+
+ if (Index > StartIndex) {
+ Value = Buffer.substr(StartIndex, Index - StartIndex);
+ if (GotDecimalPoint) {
+ if (ExpIndex != 0) {
+ // We have an exponent, make sure we got exponent digits
+ if (GotExpDigits) {
+ return Token::Float;
+ } else {
+ Error << "error: got exponent character but no exponent digits at "
+ "offset in float value \""
+ << Value << "\"";
+ Value = Error.str();
+ return Token::Error;
+ }
+ } else {
+ // No exponent, but we need at least one decimal after the decimal
+ // point
+ if (GotFracDigits) {
+ return Token::Float;
+ } else {
+ Error << "error: no digits after decimal point \"" << Value << "\"";
+ Value = Error.str();
+ return Token::Error;
+ }
+ }
+ } else {
+ // No decimal point
+ if (GotIntDigits) {
+ // We need at least some integer digits to make an integer
+ return Token::Integer;
+ } else {
+ Error << "error: no digits negate sign \"" << Value << "%s\"";
+ Value = Error.str();
+ return Token::Error;
+ }
+ }
+ } else {
+ Error << "error: invalid number found at offset " << StartIndex;
+ Value = Error.str();
+ return Token::Error;
+ }
+ } break;
+ default:
+ break;
+ }
+ Error << "error: failed to parse token at offset " << StartIndex
+ << " (around character '" << Ch << "')";
+ Value = Error.str();
+ return Token::Error;
+}
+
+int JSONParser::getEscapedChar(bool &WasEscaped) {
+ WasEscaped = false;
+ const char Ch = getChar();
+ if (Ch == '\\') {
+ WasEscaped = 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 HiByte = decodeHexU8();
+ const int LoByte = decodeHexU8();
+ if (HiByte >= 0 && LoByte >= 0)
+ return HiByte << 8 | LoByte;
+ 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<JSONObject> DictUp(new JSONObject());
+
+ std::string Value;
+ std::string Key;
+ while (1) {
+ JSONParser::Token Token = getToken(Value);
+
+ if (Token == JSONParser::Token::String) {
+ Key.swap(Value);
+ Token = getToken(Value);
+ if (Token == JSONParser::Token::Colon) {
+ JSONValue::SP ValueSP = parseJSONValue();
+ if (ValueSP)
+ DictUp->setObject(Key, ValueSP);
+ else
+ break;
+ }
+ } else if (Token == JSONParser::Token::ObjectEnd) {
+ return JSONValue::SP(DictUp.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<JSONArray> ArrayUp(new JSONArray());
+
+ std::string Value;
+ while (1) {
+ skipSpaces();
+
+ char Peek = peekChar();
+ if (Peek == ']' || Peek == ',') {
+ JSONParser::Token Token = getToken(Value);
+ if (Token == JSONParser::Token::Comma) {
+ continue;
+ } else if (Token == JSONParser::Token::ArrayEnd) {
+ return JSONValue::SP(ArrayUp.release());
+ }
+ }
+
+ JSONValue::SP ValueSP = parseJSONValue();
+ if (ValueSP)
+ ArrayUp->appendObject(ValueSP);
+ 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: {
+ char *End = nullptr;
+ if (Value.front() == '-') {
+ int64_t SVal = ::strtoll(Value.c_str(), &End, 10);
+ bool Success = *End == '\0'; // all characters were used.
+ if (Success)
+ return JSONValue::SP(new JSONNumber(SVal));
+ } else {
+ uint64_t UVal = ::strtoul(Value.c_str(), &End, 10);
+ bool Success = *End == '\0'; // all characters were used.
+ if (Success)
+ return JSONValue::SP(new JSONNumber(UVal));
+ }
+ } break;
+
+ case JSONParser::Token::Float: {
+ char *End = nullptr;
+ double Val = ::strtod(Value.c_str(), &End);
+ bool Success = *End == '\0'; // all characters were used.
+ if (Success)
+ return JSONValue::SP(new JSONNumber(Val));
+ } 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();
+}
+
+void JSONParser::skipSpaces() {
+ const size_t S = Buffer.size();
+ while (Index < S && isspace(Buffer[Index]))
+ ++Index;
+}
+
+char JSONParser::getChar() {
+ if (getBytesLeft() < 1)
+ return 0;
+ return Buffer[Index++];
+}
+
+char JSONParser::peekChar() const {
+ if (getBytesLeft() == 0)
+ return 0;
+
+ return Buffer[Index];
+}
+
+static inline int hexDigitToSInt(char Ch) {
+ if (Ch >= 'a' && Ch <= 'f')
+ return 10 + Ch - 'a';
+ if (Ch >= 'A' && Ch <= 'F')
+ return 10 + Ch - 'A';
+ if (Ch >= '0' && Ch <= '9')
+ return Ch - '0';
+ return -1;
+}
+
+uint8_t JSONParser::decodeHexU8() {
+ skipSpaces();
+ if (getBytesLeft() < 2) {
+ return -1;
+ }
+ const int HiNibble = hexDigitToSInt(Buffer[Index]);
+ const int LoNibble = hexDigitToSInt(Buffer[Index + 1]);
+ if (HiNibble == -1 || LoNibble == -1) {
+ return -1;
+ }
+ Index += 2;
+ return (uint8_t)((HiNibble << 4) + LoNibble);
+}
Index: lib/Support/CMakeLists.txt
===================================================================
--- lib/Support/CMakeLists.txt
+++ lib/Support/CMakeLists.txt
@@ -61,6 +61,7 @@
IntervalMap.cpp
IntrusiveRefCntPtr.cpp
JamCRC.cpp
+ JSON.cpp
LEB128.cpp
LineIterator.cpp
Locale.cpp
Index: include/llvm/Support/JSON.h
===================================================================
--- /dev/null
+++ include/llvm/Support/JSON.h
@@ -0,0 +1,287 @@
+//===---------------------JSON.h --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_SUPPORT_JSON_H
+#define LLVM_SUPPORT_JSON_H
+
+#include <inttypes.h>
+#include <map>
+#include <memory>
+#include <stdint.h>
+#include <string>
+#include <vector>
+
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace llvm {
+
+class JSONValue {
+public:
+ typedef std::shared_ptr<JSONValue> SP;
+ enum class Kind { String, Number, True, False, Null, Object, Array };
+
+ JSONValue(Kind K) : TheKind(K) {}
+ virtual ~JSONValue() = default;
+
+ virtual void write(raw_ostream &S) const = 0;
+
+ Kind getKind() const { return TheKind; }
+
+private:
+ const Kind TheKind;
+};
+
+class JSONString : public JSONValue {
+public:
+ typedef std::shared_ptr<JSONString> SP;
+
+ JSONString();
+ JSONString(const char *S);
+ JSONString(const std::string &S);
+
+ JSONString(const JSONString &S) = delete;
+ JSONString &operator=(const JSONString &S) = delete;
+
+ ~JSONString() override = default;
+
+ void write(raw_ostream &S) const override;
+
+ std::string getData() const { return Data; }
+
+ static bool classof(const JSONValue *V) {
+ return V->getKind() == JSONValue::Kind::String;
+ }
+
+private:
+ static std::string jsonStringQuoteMetachars(const std::string &);
+
+ std::string Data;
+};
+
+class JSONNumber : public JSONValue {
+public:
+ typedef std::shared_ptr<JSONNumber> 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 <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), TheDataType(DataType::Unsigned) {
+ Data.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), TheDataType(DataType::Signed) {
+ Data.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), TheDataType(DataType::Double) {
+ Data.Double = D;
+ }
+
+ ~JSONNumber() override = default;
+
+ JSONNumber(const JSONNumber &S) = delete;
+ JSONNumber &operator=(const JSONNumber &S) = delete;
+
+ void write(raw_ostream &S) const 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 } TheDataType;
+
+ union {
+ uint64_t Unsigned;
+ int64_t Signed;
+ double Double;
+ } Data;
+};
+
+class JSONTrue : public JSONValue {
+public:
+ JSONTrue();
+
+ JSONTrue(const JSONTrue &S) = delete;
+ JSONTrue &operator=(const JSONTrue &S) = delete;
+
+ void write(raw_ostream &S) const 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(raw_ostream &S) const 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(raw_ostream &S) const 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(raw_ostream &S) const 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);
+
+ ~JSONObject() override = default;
+
+private:
+ typedef std::map<std::string, JSONValue::SP> Map;
+ typedef Map::iterator Iterator;
+ Map Elements;
+};
+
+class JSONArray : public JSONValue {
+public:
+ JSONArray();
+
+ JSONArray(const JSONArray &S) = delete;
+ JSONArray &operator=(const JSONArray &S) = delete;
+
+ void write(raw_ostream &S) const 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 Elements;
+};
+
+class JSONParser {
+public:
+ enum Token {
+ Invalid,
+ Error,
+ ObjectStart,
+ ObjectEnd,
+ ArrayStart,
+ ArrayEnd,
+ Comma,
+ Colon,
+ String,
+ Integer,
+ Float,
+ True,
+ False,
+ Null,
+ EndOfFile
+ };
+
+ JSONParser(const char *Cstr);
+ JSONValue::SP parseJSONValue();
+
+protected:
+ int getEscapedChar(bool &WasEscaped);
+ Token getToken(std::string &Value);
+ JSONValue::SP parseJSONObject();
+ JSONValue::SP parseJSONArray();
+
+ void skipSpaces();
+ uint8_t decodeHexU8();
+ char getChar();
+ char peekChar() const;
+ size_t getBytesLeft() const { return Buffer.size() - Index; }
+
+ std::string Buffer;
+ size_t Index;
+};
+} // namespace llvm
+
+#endif // LLVM_SUPPORT_JSON_H
Index: .clang-tidy
===================================================================
--- .clang-tidy
+++ .clang-tidy
@@ -5,7 +5,7 @@
- key: readability-identifier-naming.EnumCase
value: CamelCase
- key: readability-identifier-naming.FunctionCase
- value: lowerCase
+ value: camelBack
- key: readability-identifier-naming.MemberCase
value: CamelCase
- key: readability-identifier-naming.ParameterCase
_______________________________________________
lldb-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits