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