15ffd83dbSDimitry Andric //===-- StructuredData.cpp ------------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "lldb/Utility/StructuredData.h"
100b57cec5SDimitry Andric #include "lldb/Utility/FileSpec.h"
110b57cec5SDimitry Andric #include "lldb/Utility/Status.h"
120b57cec5SDimitry Andric #include "llvm/Support/MemoryBuffer.h"
130b57cec5SDimitry Andric #include <cerrno>
14*5f7ddb14SDimitry Andric #include <cinttypes>
150b57cec5SDimitry Andric #include <cstdlib>
160b57cec5SDimitry Andric 
170b57cec5SDimitry Andric using namespace lldb_private;
189dba64beSDimitry Andric using namespace llvm;
190b57cec5SDimitry Andric 
209dba64beSDimitry Andric static StructuredData::ObjectSP ParseJSONValue(json::Value &value);
219dba64beSDimitry Andric static StructuredData::ObjectSP ParseJSONObject(json::Object *object);
229dba64beSDimitry Andric static StructuredData::ObjectSP ParseJSONArray(json::Array *array);
239dba64beSDimitry Andric 
24af732203SDimitry Andric StructuredData::ObjectSP
ParseJSON(const std::string & json_text)25af732203SDimitry Andric StructuredData::ParseJSON(const std::string &json_text) {
269dba64beSDimitry Andric   llvm::Expected<json::Value> value = json::parse(json_text);
279dba64beSDimitry Andric   if (!value) {
289dba64beSDimitry Andric     llvm::consumeError(value.takeError());
299dba64beSDimitry Andric     return nullptr;
309dba64beSDimitry Andric   }
319dba64beSDimitry Andric   return ParseJSONValue(*value);
329dba64beSDimitry Andric }
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric StructuredData::ObjectSP
ParseJSONFromFile(const FileSpec & input_spec,Status & error)350b57cec5SDimitry Andric StructuredData::ParseJSONFromFile(const FileSpec &input_spec, Status &error) {
360b57cec5SDimitry Andric   StructuredData::ObjectSP return_sp;
370b57cec5SDimitry Andric 
380b57cec5SDimitry Andric   auto buffer_or_error = llvm::MemoryBuffer::getFile(input_spec.GetPath());
390b57cec5SDimitry Andric   if (!buffer_or_error) {
400b57cec5SDimitry Andric     error.SetErrorStringWithFormatv("could not open input file: {0} - {1}.",
410b57cec5SDimitry Andric                                     input_spec.GetPath(),
420b57cec5SDimitry Andric                                     buffer_or_error.getError().message());
430b57cec5SDimitry Andric     return return_sp;
440b57cec5SDimitry Andric   }
45af732203SDimitry Andric   llvm::Expected<json::Value> value =
46af732203SDimitry Andric       json::parse(buffer_or_error.get()->getBuffer().str());
47af732203SDimitry Andric   if (value)
48af732203SDimitry Andric     return ParseJSONValue(*value);
49af732203SDimitry Andric   error.SetErrorString(toString(value.takeError()));
50af732203SDimitry Andric   return StructuredData::ObjectSP();
510b57cec5SDimitry Andric }
520b57cec5SDimitry Andric 
ParseJSONValue(json::Value & value)539dba64beSDimitry Andric static StructuredData::ObjectSP ParseJSONValue(json::Value &value) {
549dba64beSDimitry Andric   if (json::Object *O = value.getAsObject())
559dba64beSDimitry Andric     return ParseJSONObject(O);
560b57cec5SDimitry Andric 
579dba64beSDimitry Andric   if (json::Array *A = value.getAsArray())
589dba64beSDimitry Andric     return ParseJSONArray(A);
590b57cec5SDimitry Andric 
60af732203SDimitry Andric   if (auto s = value.getAsString())
61af732203SDimitry Andric     return std::make_shared<StructuredData::String>(*s);
629dba64beSDimitry Andric 
63af732203SDimitry Andric   if (auto b = value.getAsBoolean())
64af732203SDimitry Andric     return std::make_shared<StructuredData::Boolean>(*b);
659dba64beSDimitry Andric 
66af732203SDimitry Andric   if (auto i = value.getAsInteger())
67af732203SDimitry Andric     return std::make_shared<StructuredData::Integer>(*i);
689dba64beSDimitry Andric 
69af732203SDimitry Andric   if (auto d = value.getAsNumber())
70af732203SDimitry Andric     return std::make_shared<StructuredData::Float>(*d);
719dba64beSDimitry Andric 
729dba64beSDimitry Andric   return StructuredData::ObjectSP();
739dba64beSDimitry Andric }
749dba64beSDimitry Andric 
ParseJSONObject(json::Object * object)759dba64beSDimitry Andric static StructuredData::ObjectSP ParseJSONObject(json::Object *object) {
769dba64beSDimitry Andric   auto dict_up = std::make_unique<StructuredData::Dictionary>();
779dba64beSDimitry Andric   for (auto &KV : *object) {
789dba64beSDimitry Andric     StringRef key = KV.first;
799dba64beSDimitry Andric     json::Value value = KV.second;
809dba64beSDimitry Andric     if (StructuredData::ObjectSP value_sp = ParseJSONValue(value))
810b57cec5SDimitry Andric       dict_up->AddItem(key, value_sp);
820b57cec5SDimitry Andric   }
83480093f4SDimitry Andric   return std::move(dict_up);
840b57cec5SDimitry Andric }
850b57cec5SDimitry Andric 
ParseJSONArray(json::Array * array)869dba64beSDimitry Andric static StructuredData::ObjectSP ParseJSONArray(json::Array *array) {
879dba64beSDimitry Andric   auto array_up = std::make_unique<StructuredData::Array>();
889dba64beSDimitry Andric   for (json::Value &value : *array) {
899dba64beSDimitry Andric     if (StructuredData::ObjectSP value_sp = ParseJSONValue(value))
900b57cec5SDimitry Andric       array_up->AddItem(value_sp);
910b57cec5SDimitry Andric   }
92480093f4SDimitry Andric   return std::move(array_up);
930b57cec5SDimitry Andric }
940b57cec5SDimitry Andric 
950b57cec5SDimitry Andric StructuredData::ObjectSP
GetObjectForDotSeparatedPath(llvm::StringRef path)960b57cec5SDimitry Andric StructuredData::Object::GetObjectForDotSeparatedPath(llvm::StringRef path) {
970b57cec5SDimitry Andric   if (this->GetType() == lldb::eStructuredDataTypeDictionary) {
980b57cec5SDimitry Andric     std::pair<llvm::StringRef, llvm::StringRef> match = path.split('.');
990b57cec5SDimitry Andric     std::string key = match.first.str();
1000b57cec5SDimitry Andric     ObjectSP value = this->GetAsDictionary()->GetValueForKey(key);
1010b57cec5SDimitry Andric     if (value.get()) {
1020b57cec5SDimitry Andric       // Do we have additional words to descend?  If not, return the value
1030b57cec5SDimitry Andric       // we're at right now.
1040b57cec5SDimitry Andric       if (match.second.empty()) {
1050b57cec5SDimitry Andric         return value;
1060b57cec5SDimitry Andric       } else {
1070b57cec5SDimitry Andric         return value->GetObjectForDotSeparatedPath(match.second);
1080b57cec5SDimitry Andric       }
1090b57cec5SDimitry Andric     }
1100b57cec5SDimitry Andric     return ObjectSP();
1110b57cec5SDimitry Andric   }
1120b57cec5SDimitry Andric 
1130b57cec5SDimitry Andric   if (this->GetType() == lldb::eStructuredDataTypeArray) {
1140b57cec5SDimitry Andric     std::pair<llvm::StringRef, llvm::StringRef> match = path.split('[');
1150b57cec5SDimitry Andric     if (match.second.empty()) {
1160b57cec5SDimitry Andric       return this->shared_from_this();
1170b57cec5SDimitry Andric     }
1180b57cec5SDimitry Andric     errno = 0;
1190b57cec5SDimitry Andric     uint64_t val = strtoul(match.second.str().c_str(), nullptr, 10);
1200b57cec5SDimitry Andric     if (errno == 0) {
1210b57cec5SDimitry Andric       return this->GetAsArray()->GetItemAtIndex(val);
1220b57cec5SDimitry Andric     }
1230b57cec5SDimitry Andric     return ObjectSP();
1240b57cec5SDimitry Andric   }
1250b57cec5SDimitry Andric 
1260b57cec5SDimitry Andric   return this->shared_from_this();
1270b57cec5SDimitry Andric }
1280b57cec5SDimitry Andric 
DumpToStdout(bool pretty_print) const1290b57cec5SDimitry Andric void StructuredData::Object::DumpToStdout(bool pretty_print) const {
1309dba64beSDimitry Andric   json::OStream stream(llvm::outs(), pretty_print ? 2 : 0);
1319dba64beSDimitry Andric   Serialize(stream);
1320b57cec5SDimitry Andric }
1330b57cec5SDimitry Andric 
Serialize(json::OStream & s) const1349dba64beSDimitry Andric void StructuredData::Array::Serialize(json::OStream &s) const {
1359dba64beSDimitry Andric   s.arrayBegin();
1360b57cec5SDimitry Andric   for (const auto &item_sp : m_items) {
1379dba64beSDimitry Andric     item_sp->Serialize(s);
1389dba64beSDimitry Andric   }
1399dba64beSDimitry Andric   s.arrayEnd();
1400b57cec5SDimitry Andric }
1410b57cec5SDimitry Andric 
Serialize(json::OStream & s) const1429dba64beSDimitry Andric void StructuredData::Integer::Serialize(json::OStream &s) const {
1439dba64beSDimitry Andric   s.value(static_cast<int64_t>(m_value));
1440b57cec5SDimitry Andric }
1450b57cec5SDimitry Andric 
Serialize(json::OStream & s) const1469dba64beSDimitry Andric void StructuredData::Float::Serialize(json::OStream &s) const {
1479dba64beSDimitry Andric   s.value(m_value);
1480b57cec5SDimitry Andric }
1490b57cec5SDimitry Andric 
Serialize(json::OStream & s) const1509dba64beSDimitry Andric void StructuredData::Boolean::Serialize(json::OStream &s) const {
1519dba64beSDimitry Andric   s.value(m_value);
1520b57cec5SDimitry Andric }
1530b57cec5SDimitry Andric 
Serialize(json::OStream & s) const1549dba64beSDimitry Andric void StructuredData::String::Serialize(json::OStream &s) const {
1559dba64beSDimitry Andric   s.value(m_value);
1560b57cec5SDimitry Andric }
1570b57cec5SDimitry Andric 
Serialize(json::OStream & s) const1589dba64beSDimitry Andric void StructuredData::Dictionary::Serialize(json::OStream &s) const {
1599dba64beSDimitry Andric   s.objectBegin();
1600b57cec5SDimitry Andric   for (const auto &pair : m_dict) {
1615ffd83dbSDimitry Andric     s.attributeBegin(pair.first.GetStringRef());
1629dba64beSDimitry Andric     pair.second->Serialize(s);
1639dba64beSDimitry Andric     s.attributeEnd();
1640b57cec5SDimitry Andric   }
1659dba64beSDimitry Andric   s.objectEnd();
1660b57cec5SDimitry Andric }
1670b57cec5SDimitry Andric 
Serialize(json::OStream & s) const1689dba64beSDimitry Andric void StructuredData::Null::Serialize(json::OStream &s) const {
1699dba64beSDimitry Andric   s.value(nullptr);
1700b57cec5SDimitry Andric }
1710b57cec5SDimitry Andric 
Serialize(json::OStream & s) const1729dba64beSDimitry Andric void StructuredData::Generic::Serialize(json::OStream &s) const {
1739dba64beSDimitry Andric   s.value(llvm::formatv("{0:X}", m_object));
1740b57cec5SDimitry Andric }
175