xref: /src/contrib/llvm-project/lldb/source/Utility/StructuredData.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
1cfca06d7SDimitry Andric //===-- StructuredData.cpp ------------------------------------------------===//
20cac4ca3SEd Maste //
35f29bb8aSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f29bb8aSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f29bb8aSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60cac4ca3SEd Maste //
70cac4ca3SEd Maste //===----------------------------------------------------------------------===//
80cac4ca3SEd Maste 
91b306c26SDimitry Andric #include "lldb/Utility/StructuredData.h"
1074a628f7SDimitry Andric #include "lldb/Utility/FileSpec.h"
11b76161e4SDimitry Andric #include "lldb/Utility/Status.h"
127fa27ce4SDimitry Andric #include "llvm/ADT/StringExtras.h"
13ef5d0b5eSDimitry Andric #include "llvm/Support/MemoryBuffer.h"
141b306c26SDimitry Andric #include <cerrno>
15344a3780SDimitry Andric #include <cinttypes>
161b306c26SDimitry Andric #include <cstdlib>
175e95aa85SEd Maste 
180cac4ca3SEd Maste using namespace lldb_private;
19ead24645SDimitry Andric using namespace llvm;
200cac4ca3SEd Maste 
21ead24645SDimitry Andric static StructuredData::ObjectSP ParseJSONValue(json::Value &value);
22ead24645SDimitry Andric static StructuredData::ObjectSP ParseJSONObject(json::Object *object);
23ead24645SDimitry Andric static StructuredData::ObjectSP ParseJSONArray(json::Array *array);
24ead24645SDimitry Andric 
ParseJSON(llvm::StringRef json_text)257fa27ce4SDimitry Andric StructuredData::ObjectSP StructuredData::ParseJSON(llvm::StringRef json_text) {
26ead24645SDimitry Andric   llvm::Expected<json::Value> value = json::parse(json_text);
27ead24645SDimitry Andric   if (!value) {
28ead24645SDimitry Andric     llvm::consumeError(value.takeError());
29ead24645SDimitry Andric     return nullptr;
30ead24645SDimitry Andric   }
31ead24645SDimitry Andric   return ParseJSONValue(*value);
32ead24645SDimitry Andric }
330cac4ca3SEd Maste 
3414f1b3e8SDimitry Andric StructuredData::ObjectSP
ParseJSONFromFile(const FileSpec & input_spec,Status & error)35b76161e4SDimitry Andric StructuredData::ParseJSONFromFile(const FileSpec &input_spec, Status &error) {
3614f1b3e8SDimitry Andric   StructuredData::ObjectSP return_sp;
3714f1b3e8SDimitry Andric 
381b306c26SDimitry Andric   auto buffer_or_error = llvm::MemoryBuffer::getFile(input_spec.GetPath());
391b306c26SDimitry Andric   if (!buffer_or_error) {
401b306c26SDimitry Andric     error.SetErrorStringWithFormatv("could not open input file: {0} - {1}.",
411b306c26SDimitry Andric                                     input_spec.GetPath(),
421b306c26SDimitry Andric                                     buffer_or_error.getError().message());
4314f1b3e8SDimitry Andric     return return_sp;
4414f1b3e8SDimitry Andric   }
45b60736ecSDimitry Andric   llvm::Expected<json::Value> value =
46b60736ecSDimitry Andric       json::parse(buffer_or_error.get()->getBuffer().str());
47b60736ecSDimitry Andric   if (value)
48b60736ecSDimitry Andric     return ParseJSONValue(*value);
49b60736ecSDimitry Andric   error.SetErrorString(toString(value.takeError()));
50b60736ecSDimitry Andric   return StructuredData::ObjectSP();
5114f1b3e8SDimitry Andric }
5214f1b3e8SDimitry Andric 
IsRecordType(const ObjectSP object_sp)53e3b55780SDimitry Andric bool StructuredData::IsRecordType(const ObjectSP object_sp) {
54e3b55780SDimitry Andric   return object_sp->GetType() == lldb::eStructuredDataTypeArray ||
55e3b55780SDimitry Andric          object_sp->GetType() == lldb::eStructuredDataTypeDictionary;
56e3b55780SDimitry Andric }
57e3b55780SDimitry Andric 
ParseJSONValue(json::Value & value)58ead24645SDimitry Andric static StructuredData::ObjectSP ParseJSONValue(json::Value &value) {
59ead24645SDimitry Andric   if (json::Object *O = value.getAsObject())
60ead24645SDimitry Andric     return ParseJSONObject(O);
610cac4ca3SEd Maste 
62ead24645SDimitry Andric   if (json::Array *A = value.getAsArray())
63ead24645SDimitry Andric     return ParseJSONArray(A);
640cac4ca3SEd Maste 
65b60736ecSDimitry Andric   if (auto s = value.getAsString())
66b60736ecSDimitry Andric     return std::make_shared<StructuredData::String>(*s);
67ead24645SDimitry Andric 
68b60736ecSDimitry Andric   if (auto b = value.getAsBoolean())
69b60736ecSDimitry Andric     return std::make_shared<StructuredData::Boolean>(*b);
70ead24645SDimitry Andric 
717fa27ce4SDimitry Andric   if (auto u = value.getAsUINT64())
727fa27ce4SDimitry Andric     return std::make_shared<StructuredData::UnsignedInteger>(*u);
737fa27ce4SDimitry Andric 
74b60736ecSDimitry Andric   if (auto i = value.getAsInteger())
757fa27ce4SDimitry Andric     return std::make_shared<StructuredData::SignedInteger>(*i);
76ead24645SDimitry Andric 
77b60736ecSDimitry Andric   if (auto d = value.getAsNumber())
78b60736ecSDimitry Andric     return std::make_shared<StructuredData::Float>(*d);
79ead24645SDimitry Andric 
80e3b55780SDimitry Andric   if (auto n = value.getAsNull())
81e3b55780SDimitry Andric     return std::make_shared<StructuredData::Null>();
82e3b55780SDimitry Andric 
83ead24645SDimitry Andric   return StructuredData::ObjectSP();
84ead24645SDimitry Andric }
85ead24645SDimitry Andric 
ParseJSONObject(json::Object * object)86ead24645SDimitry Andric static StructuredData::ObjectSP ParseJSONObject(json::Object *object) {
87ead24645SDimitry Andric   auto dict_up = std::make_unique<StructuredData::Dictionary>();
88ead24645SDimitry Andric   for (auto &KV : *object) {
89ead24645SDimitry Andric     StringRef key = KV.first;
90ead24645SDimitry Andric     json::Value value = KV.second;
91ead24645SDimitry Andric     if (StructuredData::ObjectSP value_sp = ParseJSONValue(value))
92027f1c96SDimitry Andric       dict_up->AddItem(key, value_sp);
93027f1c96SDimitry Andric   }
94706b4fc4SDimitry Andric   return std::move(dict_up);
950cac4ca3SEd Maste }
960cac4ca3SEd Maste 
ParseJSONArray(json::Array * array)97ead24645SDimitry Andric static StructuredData::ObjectSP ParseJSONArray(json::Array *array) {
98ead24645SDimitry Andric   auto array_up = std::make_unique<StructuredData::Array>();
99ead24645SDimitry Andric   for (json::Value &value : *array) {
100ead24645SDimitry Andric     if (StructuredData::ObjectSP value_sp = ParseJSONValue(value))
101027f1c96SDimitry Andric       array_up->AddItem(value_sp);
1020cac4ca3SEd Maste   }
103706b4fc4SDimitry Andric   return std::move(array_up);
1040cac4ca3SEd Maste }
1050cac4ca3SEd Maste 
1060cac4ca3SEd Maste StructuredData::ObjectSP
GetObjectForDotSeparatedPath(llvm::StringRef path)10714f1b3e8SDimitry Andric StructuredData::Object::GetObjectForDotSeparatedPath(llvm::StringRef path) {
1087fa27ce4SDimitry Andric   if (GetType() == lldb::eStructuredDataTypeDictionary) {
1090cac4ca3SEd Maste     std::pair<llvm::StringRef, llvm::StringRef> match = path.split('.');
1107fa27ce4SDimitry Andric     llvm::StringRef key = match.first;
1117fa27ce4SDimitry Andric     ObjectSP value = GetAsDictionary()->GetValueForKey(key);
1127fa27ce4SDimitry Andric     if (!value)
1137fa27ce4SDimitry Andric       return {};
1147fa27ce4SDimitry Andric 
115f73363f1SDimitry Andric     // Do we have additional words to descend?  If not, return the value
116f73363f1SDimitry Andric     // we're at right now.
1177fa27ce4SDimitry Andric     if (match.second.empty())
1180cac4ca3SEd Maste       return value;
1197fa27ce4SDimitry Andric 
1200cac4ca3SEd Maste     return value->GetObjectForDotSeparatedPath(match.second);
1210cac4ca3SEd Maste   }
1220cac4ca3SEd Maste 
1237fa27ce4SDimitry Andric   if (GetType() == lldb::eStructuredDataTypeArray) {
1240cac4ca3SEd Maste     std::pair<llvm::StringRef, llvm::StringRef> match = path.split('[');
1257fa27ce4SDimitry Andric     if (match.second.empty())
1267fa27ce4SDimitry Andric       return shared_from_this();
1277fa27ce4SDimitry Andric 
1287fa27ce4SDimitry Andric     uint64_t val = 0;
1297fa27ce4SDimitry Andric     if (!llvm::to_integer(match.second, val, /* Base = */ 10))
1307fa27ce4SDimitry Andric       return {};
1317fa27ce4SDimitry Andric 
1327fa27ce4SDimitry Andric     return GetAsArray()->GetItemAtIndex(val);
1330cac4ca3SEd Maste   }
1340cac4ca3SEd Maste 
1357fa27ce4SDimitry Andric   return shared_from_this();
1360cac4ca3SEd Maste }
1370cac4ca3SEd Maste 
DumpToStdout(bool pretty_print) const13814f1b3e8SDimitry Andric void StructuredData::Object::DumpToStdout(bool pretty_print) const {
139ead24645SDimitry Andric   json::OStream stream(llvm::outs(), pretty_print ? 2 : 0);
140ead24645SDimitry Andric   Serialize(stream);
1415e95aa85SEd Maste }
1425e95aa85SEd Maste 
Serialize(json::OStream & s) const143ead24645SDimitry Andric void StructuredData::Array::Serialize(json::OStream &s) const {
144ead24645SDimitry Andric   s.arrayBegin();
14514f1b3e8SDimitry Andric   for (const auto &item_sp : m_items) {
146ead24645SDimitry Andric     item_sp->Serialize(s);
147ead24645SDimitry Andric   }
148ead24645SDimitry Andric   s.arrayEnd();
14914f1b3e8SDimitry Andric }
15014f1b3e8SDimitry Andric 
Serialize(json::OStream & s) const151ead24645SDimitry Andric void StructuredData::Float::Serialize(json::OStream &s) const {
152ead24645SDimitry Andric   s.value(m_value);
1530cac4ca3SEd Maste }
1540cac4ca3SEd Maste 
Serialize(json::OStream & s) const155ead24645SDimitry Andric void StructuredData::Boolean::Serialize(json::OStream &s) const {
156ead24645SDimitry Andric   s.value(m_value);
1570cac4ca3SEd Maste }
1580cac4ca3SEd Maste 
Serialize(json::OStream & s) const159ead24645SDimitry Andric void StructuredData::String::Serialize(json::OStream &s) const {
160ead24645SDimitry Andric   s.value(m_value);
1610cac4ca3SEd Maste }
1620cac4ca3SEd Maste 
Serialize(json::OStream & s) const163ead24645SDimitry Andric void StructuredData::Dictionary::Serialize(json::OStream &s) const {
164ead24645SDimitry Andric   s.objectBegin();
165b1c73532SDimitry Andric 
166b1c73532SDimitry Andric   // To ensure the output format is always stable, we sort the dictionary by key
167b1c73532SDimitry Andric   // first.
168b1c73532SDimitry Andric   using Entry = std::pair<llvm::StringRef, ObjectSP>;
169b1c73532SDimitry Andric   std::vector<Entry> sorted_entries;
170b1c73532SDimitry Andric   for (const auto &pair : m_dict)
171b1c73532SDimitry Andric     sorted_entries.push_back({pair.first(), pair.second});
172b1c73532SDimitry Andric 
173b1c73532SDimitry Andric   llvm::sort(sorted_entries);
174b1c73532SDimitry Andric 
175b1c73532SDimitry Andric   for (const auto &pair : sorted_entries) {
176b1c73532SDimitry Andric     s.attributeBegin(pair.first);
177ead24645SDimitry Andric     pair.second->Serialize(s);
178ead24645SDimitry Andric     s.attributeEnd();
17914f1b3e8SDimitry Andric   }
180ead24645SDimitry Andric   s.objectEnd();
1810cac4ca3SEd Maste }
1820cac4ca3SEd Maste 
Serialize(json::OStream & s) const183ead24645SDimitry Andric void StructuredData::Null::Serialize(json::OStream &s) const {
184ead24645SDimitry Andric   s.value(nullptr);
1850cac4ca3SEd Maste }
1865e95aa85SEd Maste 
Serialize(json::OStream & s) const187ead24645SDimitry Andric void StructuredData::Generic::Serialize(json::OStream &s) const {
188ead24645SDimitry Andric   s.value(llvm::formatv("{0:X}", m_object));
1895e95aa85SEd Maste }
190e3b55780SDimitry Andric 
GetDescription(lldb_private::Stream & s) const191e3b55780SDimitry Andric void StructuredData::Float::GetDescription(lldb_private::Stream &s) const {
192e3b55780SDimitry Andric   s.Printf("%f", m_value);
193e3b55780SDimitry Andric }
194e3b55780SDimitry Andric 
GetDescription(lldb_private::Stream & s) const195e3b55780SDimitry Andric void StructuredData::Boolean::GetDescription(lldb_private::Stream &s) const {
196e3b55780SDimitry Andric   s.Printf(m_value ? "True" : "False");
197e3b55780SDimitry Andric }
198e3b55780SDimitry Andric 
GetDescription(lldb_private::Stream & s) const199e3b55780SDimitry Andric void StructuredData::String::GetDescription(lldb_private::Stream &s) const {
200e3b55780SDimitry Andric   s.Printf("%s", m_value.empty() ? "\"\"" : m_value.c_str());
201e3b55780SDimitry Andric }
202e3b55780SDimitry Andric 
GetDescription(lldb_private::Stream & s) const203e3b55780SDimitry Andric void StructuredData::Array::GetDescription(lldb_private::Stream &s) const {
204e3b55780SDimitry Andric   size_t index = 0;
205e3b55780SDimitry Andric   size_t indentation_level = s.GetIndentLevel();
206e3b55780SDimitry Andric   for (const auto &item_sp : m_items) {
207e3b55780SDimitry Andric     // Sanitize.
208e3b55780SDimitry Andric     if (!item_sp)
209e3b55780SDimitry Andric       continue;
210e3b55780SDimitry Andric 
211e3b55780SDimitry Andric     // Reset original indentation level.
212e3b55780SDimitry Andric     s.SetIndentLevel(indentation_level);
213e3b55780SDimitry Andric     s.Indent();
214e3b55780SDimitry Andric 
215e3b55780SDimitry Andric     // Print key
216e3b55780SDimitry Andric     s.Printf("[%zu]:", index++);
217e3b55780SDimitry Andric 
218e3b55780SDimitry Andric     // Return to new line and increase indentation if value is record type.
219e3b55780SDimitry Andric     // Otherwise add spacing.
220e3b55780SDimitry Andric     bool should_indent = IsRecordType(item_sp);
221e3b55780SDimitry Andric     if (should_indent) {
222e3b55780SDimitry Andric       s.EOL();
223e3b55780SDimitry Andric       s.IndentMore();
224e3b55780SDimitry Andric     } else {
225e3b55780SDimitry Andric       s.PutChar(' ');
226e3b55780SDimitry Andric     }
227e3b55780SDimitry Andric 
228e3b55780SDimitry Andric     // Print value and new line if now last pair.
229e3b55780SDimitry Andric     item_sp->GetDescription(s);
230e3b55780SDimitry Andric     if (item_sp != *(--m_items.end()))
231e3b55780SDimitry Andric       s.EOL();
232e3b55780SDimitry Andric 
233e3b55780SDimitry Andric     // Reset indentation level if it was incremented previously.
234e3b55780SDimitry Andric     if (should_indent)
235e3b55780SDimitry Andric       s.IndentLess();
236e3b55780SDimitry Andric   }
237e3b55780SDimitry Andric }
238e3b55780SDimitry Andric 
GetDescription(lldb_private::Stream & s) const239e3b55780SDimitry Andric void StructuredData::Dictionary::GetDescription(lldb_private::Stream &s) const {
240e3b55780SDimitry Andric   size_t indentation_level = s.GetIndentLevel();
241b1c73532SDimitry Andric 
242b1c73532SDimitry Andric   // To ensure the output format is always stable, we sort the dictionary by key
243b1c73532SDimitry Andric   // first.
244b1c73532SDimitry Andric   using Entry = std::pair<llvm::StringRef, ObjectSP>;
245b1c73532SDimitry Andric   std::vector<Entry> sorted_entries;
246b1c73532SDimitry Andric   for (const auto &pair : m_dict)
247b1c73532SDimitry Andric     sorted_entries.push_back({pair.first(), pair.second});
248b1c73532SDimitry Andric 
249b1c73532SDimitry Andric   llvm::sort(sorted_entries);
250b1c73532SDimitry Andric 
251b1c73532SDimitry Andric   for (auto iter = sorted_entries.begin(); iter != sorted_entries.end();
252b1c73532SDimitry Andric        iter++) {
253e3b55780SDimitry Andric     // Sanitize.
254b1c73532SDimitry Andric     if (iter->first.empty() || !iter->second)
255e3b55780SDimitry Andric       continue;
256e3b55780SDimitry Andric 
257e3b55780SDimitry Andric     // Reset original indentation level.
258e3b55780SDimitry Andric     s.SetIndentLevel(indentation_level);
259e3b55780SDimitry Andric     s.Indent();
260e3b55780SDimitry Andric 
261e3b55780SDimitry Andric     // Print key.
262b1c73532SDimitry Andric     s.Format("{0}:", iter->first);
263e3b55780SDimitry Andric 
264e3b55780SDimitry Andric     // Return to new line and increase indentation if value is record type.
265e3b55780SDimitry Andric     // Otherwise add spacing.
266b1c73532SDimitry Andric     bool should_indent = IsRecordType(iter->second);
267e3b55780SDimitry Andric     if (should_indent) {
268e3b55780SDimitry Andric       s.EOL();
269e3b55780SDimitry Andric       s.IndentMore();
270e3b55780SDimitry Andric     } else {
271e3b55780SDimitry Andric       s.PutChar(' ');
272e3b55780SDimitry Andric     }
273e3b55780SDimitry Andric 
274e3b55780SDimitry Andric     // Print value and new line if now last pair.
275b1c73532SDimitry Andric     iter->second->GetDescription(s);
276b1c73532SDimitry Andric     if (std::next(iter) != sorted_entries.end())
277e3b55780SDimitry Andric       s.EOL();
278e3b55780SDimitry Andric 
279e3b55780SDimitry Andric     // Reset indentation level if it was incremented previously.
280e3b55780SDimitry Andric     if (should_indent)
281e3b55780SDimitry Andric       s.IndentLess();
282e3b55780SDimitry Andric   }
283e3b55780SDimitry Andric }
284e3b55780SDimitry Andric 
GetDescription(lldb_private::Stream & s) const285e3b55780SDimitry Andric void StructuredData::Null::GetDescription(lldb_private::Stream &s) const {
286e3b55780SDimitry Andric   s.Printf("NULL");
287e3b55780SDimitry Andric }
288e3b55780SDimitry Andric 
GetDescription(lldb_private::Stream & s) const289e3b55780SDimitry Andric void StructuredData::Generic::GetDescription(lldb_private::Stream &s) const {
290e3b55780SDimitry Andric   s.Printf("%p", m_object);
291e3b55780SDimitry Andric }
292