|
32 | 32 | #include "swift/Basic/Defer.h"
|
33 | 33 | #include "swift/Basic/QuotedString.h"
|
34 | 34 | #include "swift/Basic/STLExtras.h"
|
| 35 | +#include "swift/Basic/SourceLoc.h" |
| 36 | +#include "swift/Basic/SourceManager.h" |
35 | 37 | #include "swift/Basic/StringExtras.h"
|
36 | 38 | #include "clang/AST/Type.h"
|
37 | 39 | #include "llvm/ADT/APFloat.h"
|
38 | 40 | #include "llvm/ADT/SmallString.h"
|
39 | 41 | #include "llvm/ADT/StringExtras.h"
|
40 | 42 | #include "llvm/Support/ErrorHandling.h"
|
41 | 43 | #include "llvm/Support/FileSystem.h"
|
| 44 | +#include "llvm/Support/JSON.h" |
42 | 45 | #include "llvm/Support/Process.h"
|
43 | 46 | #include "llvm/Support/SaveAndRestore.h"
|
44 | 47 | #include "llvm/Support/raw_ostream.h"
|
@@ -768,6 +771,111 @@ namespace {
|
768 | 771 | bool isParsable() const override { return false; }
|
769 | 772 | };
|
770 | 773 |
|
| 774 | + /// Implements JSON formatted output for `-ast-dump`. |
| 775 | + class JSONWriter : public PrintWriterBase { |
| 776 | + llvm::json::OStream OS; |
| 777 | + std::vector<bool> InObjectStack; |
| 778 | + |
| 779 | + public: |
| 780 | + JSONWriter(raw_ostream &os, unsigned indent = 0) : OS(os, indent) {} |
| 781 | + |
| 782 | + void printRecArbitrary(std::function<void(Label)> body, |
| 783 | + Label label) override { |
| 784 | + // The label is ignored if we're not printing inside an object (meaning |
| 785 | + // we must be in an array). |
| 786 | + if (InObjectStack.back()) { |
| 787 | + OS.attributeBegin(label.text()); |
| 788 | + body(Label::optional("")); |
| 789 | + OS.attributeEnd(); |
| 790 | + } else { |
| 791 | + body(label); |
| 792 | + } |
| 793 | + } |
| 794 | + |
| 795 | + void printRecRange(std::function<void(Label)> body, Label label) override { |
| 796 | + printListArbitrary([&]{ body(label); }, label); |
| 797 | + } |
| 798 | + |
| 799 | + void printListArbitrary(std::function<void()> body, Label label) override { |
| 800 | + OS.attributeBegin(label.text()); |
| 801 | + OS.arrayBegin(); |
| 802 | + InObjectStack.push_back(false); |
| 803 | + body(); |
| 804 | + InObjectStack.pop_back(); |
| 805 | + OS.arrayEnd(); |
| 806 | + OS.attributeEnd(); |
| 807 | + } |
| 808 | + |
| 809 | + void printHead(StringRef name, TerminalColor color, Label label) override { |
| 810 | + OS.objectBegin(); |
| 811 | + InObjectStack.push_back(true); |
| 812 | + OS.attribute(label.empty() ? "_kind" : label.text(), name); |
| 813 | + } |
| 814 | + |
| 815 | + void printFoot() override { |
| 816 | + InObjectStack.pop_back(); |
| 817 | + OS.objectEnd(); |
| 818 | + } |
| 819 | + |
| 820 | + void printFieldRaw(std::function<void(llvm::raw_ostream &)> body, |
| 821 | + Label label, TerminalColor color) override { |
| 822 | + std::string value; |
| 823 | + llvm::raw_string_ostream SOS(value); |
| 824 | + body(SOS); |
| 825 | + // The label is ignored if we're not printing inside an object (meaning |
| 826 | + // we must be in an array). |
| 827 | + if (InObjectStack.back()) { |
| 828 | + OS.attribute(label.text(), value); |
| 829 | + } else { |
| 830 | + OS.value(value); |
| 831 | + } |
| 832 | + } |
| 833 | + |
| 834 | + void printFieldQuotedRaw(std::function<void(llvm::raw_ostream &)> body, |
| 835 | + Label label, TerminalColor color) override { |
| 836 | + // No need to do special quoting for complex values; the JSON output |
| 837 | + // stream will do this for us. |
| 838 | + printFieldRaw(body, label, color); |
| 839 | + } |
| 840 | + |
| 841 | + void printFlagRaw(std::function<void(llvm::raw_ostream &)> body, |
| 842 | + TerminalColor color) override { |
| 843 | + std::string flag; |
| 844 | + llvm::raw_string_ostream SOS(flag); |
| 845 | + body(SOS); |
| 846 | + OS.attribute(flag, true); |
| 847 | + } |
| 848 | + |
| 849 | + void printSourceLoc(const SourceLoc L, const ASTContext *Ctx, |
| 850 | + Label label) override { |
| 851 | + // For compactness, we only print source ranges in JSON, since they |
| 852 | + // provide a superset of this information. |
| 853 | + } |
| 854 | + |
| 855 | + void printSourceRange(const SourceRange R, |
| 856 | + const ASTContext *Ctx) override { |
| 857 | + OS.attributeBegin("range"); |
| 858 | + OS.objectBegin(); |
| 859 | + |
| 860 | + SourceManager &srcMgr = Ctx->SourceMgr; |
| 861 | + unsigned startBufferID = srcMgr.findBufferContainingLoc(R.Start); |
| 862 | + unsigned startOffset = srcMgr.getLocOffsetInBuffer(R.Start, |
| 863 | + startBufferID); |
| 864 | + OS.attribute("start", startOffset); |
| 865 | + |
| 866 | + unsigned endBufferID = srcMgr.findBufferContainingLoc(R.End); |
| 867 | + unsigned endOffset = srcMgr.getLocOffsetInBuffer(R.End, endBufferID); |
| 868 | + OS.attribute("end", endOffset); |
| 869 | + |
| 870 | + OS.objectEnd(); |
| 871 | + OS.attributeEnd(); |
| 872 | + } |
| 873 | + |
| 874 | + bool hasNonStandardOutput() const override { return true; } |
| 875 | + |
| 876 | + bool isParsable() const override { return true; } |
| 877 | + }; |
| 878 | + |
771 | 879 | /// PrintBase - Base type for recursive structured dumps of AST nodes.
|
772 | 880 | ///
|
773 | 881 | /// Please keep direct I/O, especially of structural elements like
|
@@ -2237,6 +2345,11 @@ void SourceFile::dump(llvm::raw_ostream &OS, bool parseIfNeeded) const {
|
2237 | 2345 | llvm::errs() << '\n';
|
2238 | 2346 | }
|
2239 | 2347 |
|
| 2348 | +void SourceFile::dumpJSON(llvm::raw_ostream &OS) const { |
| 2349 | + JSONWriter writer(OS, /*indent*/ 2); |
| 2350 | + PrintDecl(writer, /*parseIfNeeded*/ true).visitSourceFile(*this); |
| 2351 | +} |
| 2352 | + |
2240 | 2353 | void Pattern::dump() const {
|
2241 | 2354 | dump(llvm::errs());
|
2242 | 2355 | }
|
|
0 commit comments