180814287SRaphael Isemann //===-- StructuredData.cpp ------------------------------------------------===// 2f2a8bccfSPavel Labath // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6f2a8bccfSPavel Labath // 7f2a8bccfSPavel Labath //===----------------------------------------------------------------------===// 8f2a8bccfSPavel Labath 9f2a8bccfSPavel Labath #include "lldb/Utility/StructuredData.h" 10f2a8bccfSPavel Labath #include "lldb/Utility/FileSpec.h" 11f2a8bccfSPavel Labath #include "lldb/Utility/Status.h" 1211c0aab7SEugene Zemtsov #include "llvm/Support/MemoryBuffer.h" 13f2a8bccfSPavel Labath #include <cerrno> 14f2a8bccfSPavel Labath #include <cstdlib> 15f2a8bccfSPavel Labath #include <inttypes.h> 16f2a8bccfSPavel Labath 17f2a8bccfSPavel Labath using namespace lldb_private; 182783d817SJonas Devlieghere using namespace llvm; 19f2a8bccfSPavel Labath 2057b46882SJonas Devlieghere static StructuredData::ObjectSP ParseJSONValue(json::Value &value); 2157b46882SJonas Devlieghere static StructuredData::ObjectSP ParseJSONObject(json::Object *object); 2257b46882SJonas Devlieghere static StructuredData::ObjectSP ParseJSONArray(json::Array *array); 2357b46882SJonas Devlieghere 240d5fc822SJonas Devlieghere StructuredData::ObjectSP 250d5fc822SJonas Devlieghere StructuredData::ParseJSON(const std::string &json_text) { 2657b46882SJonas Devlieghere llvm::Expected<json::Value> value = json::parse(json_text); 2757b46882SJonas Devlieghere if (!value) { 2857b46882SJonas Devlieghere llvm::consumeError(value.takeError()); 2957b46882SJonas Devlieghere return nullptr; 3057b46882SJonas Devlieghere } 3157b46882SJonas Devlieghere return ParseJSONValue(*value); 3257b46882SJonas Devlieghere } 33f2a8bccfSPavel Labath 34f2a8bccfSPavel Labath StructuredData::ObjectSP 35f2a8bccfSPavel Labath StructuredData::ParseJSONFromFile(const FileSpec &input_spec, Status &error) { 36f2a8bccfSPavel Labath StructuredData::ObjectSP return_sp; 37f2a8bccfSPavel Labath 38f2a8bccfSPavel Labath auto buffer_or_error = llvm::MemoryBuffer::getFile(input_spec.GetPath()); 39f2a8bccfSPavel Labath if (!buffer_or_error) { 40f2a8bccfSPavel Labath error.SetErrorStringWithFormatv("could not open input file: {0} - {1}.", 41f2a8bccfSPavel Labath input_spec.GetPath(), 42f2a8bccfSPavel Labath buffer_or_error.getError().message()); 43f2a8bccfSPavel Labath return return_sp; 44f2a8bccfSPavel Labath } 4574c93956SWalter Erquinigo llvm::Expected<json::Value> value = 4674c93956SWalter Erquinigo json::parse(buffer_or_error.get()->getBuffer().str()); 4774c93956SWalter Erquinigo if (value) 4874c93956SWalter Erquinigo return ParseJSONValue(*value); 4974c93956SWalter Erquinigo error.SetErrorString(toString(value.takeError())); 5074c93956SWalter Erquinigo return StructuredData::ObjectSP(); 51f2a8bccfSPavel Labath } 52f2a8bccfSPavel Labath 5357b46882SJonas Devlieghere static StructuredData::ObjectSP ParseJSONValue(json::Value &value) { 5457b46882SJonas Devlieghere if (json::Object *O = value.getAsObject()) 5557b46882SJonas Devlieghere return ParseJSONObject(O); 5657b46882SJonas Devlieghere 5757b46882SJonas Devlieghere if (json::Array *A = value.getAsArray()) 5857b46882SJonas Devlieghere return ParseJSONArray(A); 5957b46882SJonas Devlieghere 60*fa69b608SSam McCall if (auto s = value.getAsString()) 61*fa69b608SSam McCall return std::make_shared<StructuredData::String>(*s); 6257b46882SJonas Devlieghere 63*fa69b608SSam McCall if (auto b = value.getAsBoolean()) 64*fa69b608SSam McCall return std::make_shared<StructuredData::Boolean>(*b); 6557b46882SJonas Devlieghere 66*fa69b608SSam McCall if (auto i = value.getAsInteger(i)) 67*fa69b608SSam McCall return std::make_shared<StructuredData::Integer>(*i); 6857b46882SJonas Devlieghere 69*fa69b608SSam McCall if (auto d = value.getAsNumber()) 70*fa69b608SSam McCall return std::make_shared<StructuredData::Float>(*d); 7157b46882SJonas Devlieghere 7257b46882SJonas Devlieghere return StructuredData::ObjectSP(); 7357b46882SJonas Devlieghere } 7457b46882SJonas Devlieghere 7557b46882SJonas Devlieghere static StructuredData::ObjectSP ParseJSONObject(json::Object *object) { 76a8f3ae7cSJonas Devlieghere auto dict_up = std::make_unique<StructuredData::Dictionary>(); 7757b46882SJonas Devlieghere for (auto &KV : *object) { 7857b46882SJonas Devlieghere StringRef key = KV.first; 7957b46882SJonas Devlieghere json::Value value = KV.second; 8057b46882SJonas Devlieghere if (StructuredData::ObjectSP value_sp = ParseJSONValue(value)) 81f2a8bccfSPavel Labath dict_up->AddItem(key, value_sp); 82f2a8bccfSPavel Labath } 83d1e3b23bSJonas Devlieghere return std::move(dict_up); 84f2a8bccfSPavel Labath } 85f2a8bccfSPavel Labath 8657b46882SJonas Devlieghere static StructuredData::ObjectSP ParseJSONArray(json::Array *array) { 87a8f3ae7cSJonas Devlieghere auto array_up = std::make_unique<StructuredData::Array>(); 8857b46882SJonas Devlieghere for (json::Value &value : *array) { 8957b46882SJonas Devlieghere if (StructuredData::ObjectSP value_sp = ParseJSONValue(value)) 90f2a8bccfSPavel Labath array_up->AddItem(value_sp); 91f2a8bccfSPavel Labath } 92d1e3b23bSJonas Devlieghere return std::move(array_up); 93f2a8bccfSPavel Labath } 94f2a8bccfSPavel Labath 95f2a8bccfSPavel Labath StructuredData::ObjectSP 96f2a8bccfSPavel Labath StructuredData::Object::GetObjectForDotSeparatedPath(llvm::StringRef path) { 97f2a8bccfSPavel Labath if (this->GetType() == lldb::eStructuredDataTypeDictionary) { 98f2a8bccfSPavel Labath std::pair<llvm::StringRef, llvm::StringRef> match = path.split('.'); 99f2a8bccfSPavel Labath std::string key = match.first.str(); 100f2a8bccfSPavel Labath ObjectSP value = this->GetAsDictionary()->GetValueForKey(key); 101f2a8bccfSPavel Labath if (value.get()) { 10205097246SAdrian Prantl // Do we have additional words to descend? If not, return the value 10305097246SAdrian Prantl // we're at right now. 104f2a8bccfSPavel Labath if (match.second.empty()) { 105f2a8bccfSPavel Labath return value; 106f2a8bccfSPavel Labath } else { 107f2a8bccfSPavel Labath return value->GetObjectForDotSeparatedPath(match.second); 108f2a8bccfSPavel Labath } 109f2a8bccfSPavel Labath } 110f2a8bccfSPavel Labath return ObjectSP(); 111f2a8bccfSPavel Labath } 112f2a8bccfSPavel Labath 113f2a8bccfSPavel Labath if (this->GetType() == lldb::eStructuredDataTypeArray) { 114f2a8bccfSPavel Labath std::pair<llvm::StringRef, llvm::StringRef> match = path.split('['); 11565e5e278SJonas Devlieghere if (match.second.empty()) { 116f2a8bccfSPavel Labath return this->shared_from_this(); 117f2a8bccfSPavel Labath } 118f2a8bccfSPavel Labath errno = 0; 11965e5e278SJonas Devlieghere uint64_t val = strtoul(match.second.str().c_str(), nullptr, 10); 120f2a8bccfSPavel Labath if (errno == 0) { 121f2a8bccfSPavel Labath return this->GetAsArray()->GetItemAtIndex(val); 122f2a8bccfSPavel Labath } 123f2a8bccfSPavel Labath return ObjectSP(); 124f2a8bccfSPavel Labath } 125f2a8bccfSPavel Labath 126f2a8bccfSPavel Labath return this->shared_from_this(); 127f2a8bccfSPavel Labath } 128f2a8bccfSPavel Labath 129f2a8bccfSPavel Labath void StructuredData::Object::DumpToStdout(bool pretty_print) const { 1302783d817SJonas Devlieghere json::OStream stream(llvm::outs(), pretty_print ? 2 : 0); 1312783d817SJonas Devlieghere Serialize(stream); 132f2a8bccfSPavel Labath } 133f2a8bccfSPavel Labath 1342783d817SJonas Devlieghere void StructuredData::Array::Serialize(json::OStream &s) const { 1352783d817SJonas Devlieghere s.arrayBegin(); 136f2a8bccfSPavel Labath for (const auto &item_sp : m_items) { 1372783d817SJonas Devlieghere item_sp->Serialize(s); 1382783d817SJonas Devlieghere } 1392783d817SJonas Devlieghere s.arrayEnd(); 140f2a8bccfSPavel Labath } 141f2a8bccfSPavel Labath 1422783d817SJonas Devlieghere void StructuredData::Integer::Serialize(json::OStream &s) const { 1432783d817SJonas Devlieghere s.value(static_cast<int64_t>(m_value)); 144f2a8bccfSPavel Labath } 145f2a8bccfSPavel Labath 1462783d817SJonas Devlieghere void StructuredData::Float::Serialize(json::OStream &s) const { 1472783d817SJonas Devlieghere s.value(m_value); 148f2a8bccfSPavel Labath } 149f2a8bccfSPavel Labath 1502783d817SJonas Devlieghere void StructuredData::Boolean::Serialize(json::OStream &s) const { 1512783d817SJonas Devlieghere s.value(m_value); 152f2a8bccfSPavel Labath } 153f2a8bccfSPavel Labath 1542783d817SJonas Devlieghere void StructuredData::String::Serialize(json::OStream &s) const { 1552783d817SJonas Devlieghere s.value(m_value); 156f2a8bccfSPavel Labath } 157f2a8bccfSPavel Labath 1582783d817SJonas Devlieghere void StructuredData::Dictionary::Serialize(json::OStream &s) const { 1592783d817SJonas Devlieghere s.objectBegin(); 160f2a8bccfSPavel Labath for (const auto &pair : m_dict) { 161642bc15dSRaphael Isemann s.attributeBegin(pair.first.GetStringRef()); 1622783d817SJonas Devlieghere pair.second->Serialize(s); 1632783d817SJonas Devlieghere s.attributeEnd(); 164f2a8bccfSPavel Labath } 1652783d817SJonas Devlieghere s.objectEnd(); 166f2a8bccfSPavel Labath } 167f2a8bccfSPavel Labath 1682783d817SJonas Devlieghere void StructuredData::Null::Serialize(json::OStream &s) const { 1692783d817SJonas Devlieghere s.value(nullptr); 170f2a8bccfSPavel Labath } 171f2a8bccfSPavel Labath 1722783d817SJonas Devlieghere void StructuredData::Generic::Serialize(json::OStream &s) const { 1732783d817SJonas Devlieghere s.value(llvm::formatv("{0:X}", m_object)); 174f2a8bccfSPavel Labath } 175