1 //===---------------------StructuredData.cpp ---------------------*- C++-*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "lldb/Utility/StructuredData.h"
10 #include "lldb/Utility/DataBuffer.h"
11 #include "lldb/Utility/FileSpec.h"
12 #include "lldb/Utility/JSON.h"
13 #include "lldb/Utility/Status.h"
14 #include "lldb/Utility/Stream.h"
15 #include "lldb/Utility/StreamString.h"
16 #include "llvm/ADT/STLExtras.h"
17 #include "llvm/Support/MemoryBuffer.h"
23 using namespace lldb_private;
25 // Functions that use a JSONParser to parse JSON into StructuredData
26 static StructuredData::ObjectSP ParseJSONValue(JSONParser &json_parser);
27 static StructuredData::ObjectSP ParseJSONObject(JSONParser &json_parser);
28 static StructuredData::ObjectSP ParseJSONArray(JSONParser &json_parser);
30 StructuredData::ObjectSP
31 StructuredData::ParseJSONFromFile(const FileSpec &input_spec, Status &error) {
32 StructuredData::ObjectSP return_sp;
34 auto buffer_or_error = llvm::MemoryBuffer::getFile(input_spec.GetPath());
35 if (!buffer_or_error) {
36 error.SetErrorStringWithFormatv("could not open input file: {0} - {1}.",
38 buffer_or_error.getError().message());
42 JSONParser json_parser(buffer_or_error.get()->getBuffer());
43 return_sp = ParseJSONValue(json_parser);
47 static StructuredData::ObjectSP ParseJSONObject(JSONParser &json_parser) {
48 // The "JSONParser::Token::ObjectStart" token should have already been
49 // consumed by the time this function is called
50 auto dict_up = llvm::make_unique<StructuredData::Dictionary>();
55 JSONParser::Token token = json_parser.GetToken(value);
57 if (token == JSONParser::Token::String) {
59 token = json_parser.GetToken(value);
60 if (token == JSONParser::Token::Colon) {
61 StructuredData::ObjectSP value_sp = ParseJSONValue(json_parser);
63 dict_up->AddItem(key, value_sp);
67 } else if (token == JSONParser::Token::ObjectEnd) {
68 return StructuredData::ObjectSP(dict_up.release());
69 } else if (token == JSONParser::Token::Comma) {
75 return StructuredData::ObjectSP();
78 static StructuredData::ObjectSP ParseJSONArray(JSONParser &json_parser) {
79 // The "JSONParser::Token::ObjectStart" token should have already been
80 // consumed by the time this function is called
81 auto array_up = llvm::make_unique<StructuredData::Array>();
86 StructuredData::ObjectSP value_sp = ParseJSONValue(json_parser);
88 array_up->AddItem(value_sp);
92 JSONParser::Token token = json_parser.GetToken(value);
93 if (token == JSONParser::Token::Comma) {
95 } else if (token == JSONParser::Token::ArrayEnd) {
96 return StructuredData::ObjectSP(array_up.release());
101 return StructuredData::ObjectSP();
104 static StructuredData::ObjectSP ParseJSONValue(JSONParser &json_parser) {
106 const JSONParser::Token token = json_parser.GetToken(value);
108 case JSONParser::Token::ObjectStart:
109 return ParseJSONObject(json_parser);
111 case JSONParser::Token::ArrayStart:
112 return ParseJSONArray(json_parser);
114 case JSONParser::Token::Integer: {
116 if (llvm::to_integer(value, uval, 0))
117 return std::make_shared<StructuredData::Integer>(uval);
120 case JSONParser::Token::Float: {
122 if (llvm::to_float(value, val))
123 return std::make_shared<StructuredData::Float>(val);
126 case JSONParser::Token::String:
127 return std::make_shared<StructuredData::String>(value);
129 case JSONParser::Token::True:
130 case JSONParser::Token::False:
131 return std::make_shared<StructuredData::Boolean>(token ==
132 JSONParser::Token::True);
134 case JSONParser::Token::Null:
135 return std::make_shared<StructuredData::Null>();
140 return StructuredData::ObjectSP();
143 StructuredData::ObjectSP StructuredData::ParseJSON(std::string json_text) {
144 JSONParser json_parser(json_text);
145 StructuredData::ObjectSP object_sp = ParseJSONValue(json_parser);
149 StructuredData::ObjectSP
150 StructuredData::Object::GetObjectForDotSeparatedPath(llvm::StringRef path) {
151 if (this->GetType() == lldb::eStructuredDataTypeDictionary) {
152 std::pair<llvm::StringRef, llvm::StringRef> match = path.split('.');
153 std::string key = match.first.str();
154 ObjectSP value = this->GetAsDictionary()->GetValueForKey(key);
156 // Do we have additional words to descend? If not, return the value
157 // we're at right now.
158 if (match.second.empty()) {
161 return value->GetObjectForDotSeparatedPath(match.second);
167 if (this->GetType() == lldb::eStructuredDataTypeArray) {
168 std::pair<llvm::StringRef, llvm::StringRef> match = path.split('[');
169 if (match.second.empty()) {
170 return this->shared_from_this();
173 uint64_t val = strtoul(match.second.str().c_str(), nullptr, 10);
175 return this->GetAsArray()->GetItemAtIndex(val);
180 return this->shared_from_this();
183 void StructuredData::Object::DumpToStdout(bool pretty_print) const {
185 Dump(stream, pretty_print);
186 llvm::outs() << stream.GetString();
189 void StructuredData::Array::Dump(Stream &s, bool pretty_print) const {
196 for (const auto &item_sp : m_items) {
207 item_sp->Dump(s, pretty_print);
217 void StructuredData::Integer::Dump(Stream &s, bool pretty_print) const {
218 s.Printf("%" PRIu64, m_value);
221 void StructuredData::Float::Dump(Stream &s, bool pretty_print) const {
222 s.Printf("%lg", m_value);
225 void StructuredData::Boolean::Dump(Stream &s, bool pretty_print) const {
227 s.PutCString("true");
229 s.PutCString("false");
232 void StructuredData::String::Dump(Stream &s, bool pretty_print) const {
234 const size_t strsize = m_value.size();
235 for (size_t i = 0; i < strsize; ++i) {
236 char ch = m_value[i];
237 if (ch == '"' || ch == '\\')
238 quoted.push_back('\\');
239 quoted.push_back(ch);
241 s.Printf("\"%s\"", quoted.c_str());
244 void StructuredData::Dictionary::Dump(Stream &s, bool pretty_print) const {
251 for (const auto &pair : m_dict) {
261 s << "\"" << pair.first.AsCString() << "\" : ";
262 pair.second->Dump(s, pretty_print);
272 void StructuredData::Null::Dump(Stream &s, bool pretty_print) const {
276 void StructuredData::Generic::Dump(Stream &s, bool pretty_print) const {
277 s << "0x" << m_object;