Index: llvm/include/llvm/Support/ScopedPrinter.h =================================================================== --- llvm/include/llvm/Support/ScopedPrinter.h +++ llvm/include/llvm/Support/ScopedPrinter.h @@ -16,6 +16,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Support/DataTypes.h" #include "llvm/Support/Endian.h" +#include "llvm/Support/JSON.h" #include "llvm/Support/raw_ostream.h" #include @@ -92,7 +93,19 @@ class ScopedPrinter { public: - ScopedPrinter(raw_ostream &OS) : OS(OS), IndentLevel(0) {} + enum ScopedPrinterKind { + Standard, + JSON, + }; + + ScopedPrinter(raw_ostream &OS, ScopedPrinterKind Kind = Standard) + : OS(OS), IndentLevel(0), Kind(Kind) {} + + ScopedPrinterKind getKind() const { return Kind; } + + static bool classof(const ScopedPrinter *SP) { + return SP->getKind() == Standard; + } virtual ~ScopedPrinter() {} @@ -430,6 +443,7 @@ raw_ostream &OS; int IndentLevel; StringRef Prefix; + ScopedPrinterKind Kind; }; template <> @@ -439,6 +453,231 @@ startLine() << Label << ": " << hex(Value) << "\n"; } +class JSONScopedPrinter : public ScopedPrinter { +private: + enum Scope { + Array, + Object, + }; + + enum ScopeKind { + Standard, + Attribute, + NestedAttribute, + }; + + struct ScopeContext { + Scope Context; + ScopeKind Kind; + ScopeContext(Scope Context, ScopeKind Kind = ScopeKind::Standard) + : Context(Context), Kind(Kind) {} + }; + + SmallVector ScopeHistory; + json::OStream JOS; + +public: + JSONScopedPrinter(raw_ostream &OS) + : ScopedPrinter(OS, ScopedPrinter::ScopedPrinterKind::JSON), JOS(OS, 2) {} + + static bool classof(const ScopedPrinter *SP) { return SP->getKind() == JSON; } + + void printNumber(StringRef Label, uint64_t Value) override { + JOS.attribute(Label, Value); + } + + void printNumber(StringRef Label, uint32_t Value) override { + JOS.attribute(Label, Value); + } + + void printNumber(StringRef Label, uint16_t Value) override { + JOS.attribute(Label, Value); + } + + void printNumber(StringRef Label, uint8_t Value) override { + JOS.attribute(Label, Value); + } + + void printNumber(StringRef Label, int64_t Value) override { + JOS.attribute(Label, Value); + } + + void printNumber(StringRef Label, int32_t Value) override { + JOS.attribute(Label, Value); + } + + void printNumber(StringRef Label, int16_t Value) override { + JOS.attribute(Label, Value); + } + + void printNumber(StringRef Label, int8_t Value) override { + JOS.attribute(Label, Value); + } + + void printNumber(StringRef Label, const APSInt &Value) override { + JOS.attributeBegin(Label); + JOS.rawValueBegin() << Value; + JOS.rawValueEnd(); + JOS.attributeEnd(); + } + + void printBoolean(StringRef Label, bool Value) override { + JOS.attribute(Label, Value); + } + + void printString(StringRef Value) override { JOS.value(Value); } + + void printString(StringRef Label, StringRef Value) override { + JOS.attribute(Label, Value); + } + + void objectBegin() override { + scopedBegin({Scope::Object, ScopeKind::Standard}); + } + + void objectBegin(StringRef Label) override { + scopedBegin(Label, Scope::Object); + } + + void objectEnd() override { scopedEnd(); } + + void arrayBegin() override { + scopedBegin({Scope::Array, ScopeKind::Standard}); + } + + void arrayBegin(StringRef Label) override { + scopedBegin(Label, Scope::Array); + } + + void arrayEnd() override { scopedEnd(); } + + raw_ostream &startLine() override { + raw_ostream &OS = JOS.rawValueBegin(); + JOS.rawValueEnd(); + return OS; + } + + raw_ostream &getOStream() override { + raw_ostream &OS = JOS.rawValueBegin(); + JOS.rawValueEnd(); + return OS; + } + +private: + void printFlagsImpl(StringRef Label, HexNumber Value, + ArrayRef Flags) override { + JOS.attributeArray(Label, [&]() { + for (const auto &Flag : Flags) { + JOS.value(Flag.Name); + } + }); + } + + void printListImpl(StringRef Label, + const ArrayRef List) override { + JOS.attributeArray(Label, [&]() { + for (const auto &Item : List) { + JOS.value(Item); + } + }); + } + + void printHexListImpl(StringRef Label, + const ArrayRef List) override { + JOS.attributeArray(Label, [&]() { + for (const auto &Item : List) { + JOS.value(to_hexString(Item.Value)); + } + }); + } + + void printHexImpl(StringRef Label, HexNumber Value) override { + JOS.attribute(Label, Value.Value); + } + + void printHexImpl(StringRef Label, StringRef Str, HexNumber Value) override { + JOS.attributeObject(Label, [&]() { + JOS.attribute("Value", Str); + JOS.attribute("RawValue", Value.Value); + }); + } + + void printSymbolOffsetImpl(StringRef Label, StringRef Symbol, + HexNumber Value) override { + JOS.attributeObject(Label, [&]() { + JOS.attribute("SymName", Symbol); + JOS.attribute("Offset", Value.Value); + }); + } + + void printNumberImpl(StringRef Label, StringRef Str, + StringRef Value) override { + JOS.attributeObject(Label, [&]() { + JOS.attribute("Value", Str); + JOS.attribute("RawValue", Value); + }); + } + + void printBinaryImpl(StringRef Label, StringRef Str, ArrayRef Value, + bool Block, uint32_t StartOffset = 0) override { + JOS.attributeObject(Label, [&]() { + JOS.attribute("Value", Str); + JOS.attributeObject("Bytes", [&]() { + uint32_t CurrentOffset = StartOffset; + for (auto Val : Value) { + JOS.attribute(to_string(CurrentOffset++), Val); + } + }); + JOS.attributeObject("Characters", [&]() { + uint32_t CurrentOffset = StartOffset; + for (auto Val : Value) { + if (isPrint(Val)) { + JOS.attributeBegin(to_string(CurrentOffset++)); + JOS.rawValueBegin() << '"' << static_cast(Val) << '"'; + JOS.rawValueEnd(); + JOS.attributeEnd(); + } else { + JOS.attribute(to_string(CurrentOffset++), "."); + } + } + }); + }); + } + + void scopedBegin(ScopeContext ScopeCtx) { + if (ScopeCtx.Context == Scope::Object) { + JOS.objectBegin(); + } else if (ScopeCtx.Context == Scope::Array) { + JOS.arrayBegin(); + } + ScopeHistory.push_back(ScopeCtx); + } + + void scopedBegin(StringRef Label, Scope Ctx) { + ScopeKind Kind = ScopeKind::Attribute; + if (ScopeHistory.empty() || ScopeHistory.back().Context != Scope::Object) { + JOS.objectBegin(); + Kind = ScopeKind::NestedAttribute; + } + JOS.attributeBegin(Label); + scopedBegin({Ctx, Kind}); + } + + void scopedEnd() { + ScopeContext ScopeCtx = ScopeHistory.back(); + if (ScopeCtx.Context == Scope::Object) + JOS.objectEnd(); + else if (ScopeCtx.Context == Scope::Array) + JOS.arrayEnd(); + if (ScopeCtx.Kind == ScopeKind::Attribute || + ScopeCtx.Kind == ScopeKind::NestedAttribute) + JOS.attributeEnd(); + if (ScopeCtx.Kind == ScopeKind::NestedAttribute) + JOS.objectEnd(); + ScopeHistory.pop_back(); + } +}; + struct DelimitedScope { DelimitedScope(ScopedPrinter &W) : W(W) {} virtual ~DelimitedScope(){};