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