1a580b014SDimitry Andric //===---------------------StructuredData.cpp ---------------------*- C++-*-===//
2a580b014SDimitry Andric //
3a580b014SDimitry Andric // The LLVM Compiler Infrastructure
4a580b014SDimitry Andric //
5a580b014SDimitry Andric // This file is distributed under the University of Illinois Open Source
6a580b014SDimitry Andric // License. See LICENSE.TXT for details.
7a580b014SDimitry Andric //
8a580b014SDimitry Andric //===----------------------------------------------------------------------===//
9a580b014SDimitry Andric
10a580b014SDimitry Andric #include "lldb/Utility/StructuredData.h"
11a580b014SDimitry Andric #include "lldb/Utility/DataBuffer.h"
12a580b014SDimitry Andric #include "lldb/Utility/FileSpec.h"
13a580b014SDimitry Andric #include "lldb/Utility/JSON.h"
14a580b014SDimitry Andric #include "lldb/Utility/Status.h"
15*b5893f02SDimitry Andric #include "lldb/Utility/Stream.h"
16a580b014SDimitry Andric #include "lldb/Utility/StreamString.h"
17*b5893f02SDimitry Andric #include "llvm/ADT/STLExtras.h"
18acac075bSDimitry Andric #include "llvm/Support/MemoryBuffer.h"
19a580b014SDimitry Andric #include <cerrno>
20a580b014SDimitry Andric #include <cstdlib>
21a580b014SDimitry Andric #include <inttypes.h>
22*b5893f02SDimitry Andric #include <limits>
23a580b014SDimitry Andric
24a580b014SDimitry Andric using namespace lldb_private;
25a580b014SDimitry Andric
26a580b014SDimitry Andric //----------------------------------------------------------------------
27a580b014SDimitry Andric // Functions that use a JSONParser to parse JSON into StructuredData
28a580b014SDimitry Andric //----------------------------------------------------------------------
29a580b014SDimitry Andric static StructuredData::ObjectSP ParseJSONValue(JSONParser &json_parser);
30a580b014SDimitry Andric static StructuredData::ObjectSP ParseJSONObject(JSONParser &json_parser);
31a580b014SDimitry Andric static StructuredData::ObjectSP ParseJSONArray(JSONParser &json_parser);
32a580b014SDimitry Andric
33a580b014SDimitry Andric StructuredData::ObjectSP
ParseJSONFromFile(const FileSpec & input_spec,Status & error)34a580b014SDimitry Andric StructuredData::ParseJSONFromFile(const FileSpec &input_spec, Status &error) {
35a580b014SDimitry Andric StructuredData::ObjectSP return_sp;
36a580b014SDimitry Andric
37a580b014SDimitry Andric auto buffer_or_error = llvm::MemoryBuffer::getFile(input_spec.GetPath());
38a580b014SDimitry Andric if (!buffer_or_error) {
39a580b014SDimitry Andric error.SetErrorStringWithFormatv("could not open input file: {0} - {1}.",
40a580b014SDimitry Andric input_spec.GetPath(),
41a580b014SDimitry Andric buffer_or_error.getError().message());
42a580b014SDimitry Andric return return_sp;
43a580b014SDimitry Andric }
44a580b014SDimitry Andric
45a580b014SDimitry Andric JSONParser json_parser(buffer_or_error.get()->getBuffer());
46a580b014SDimitry Andric return_sp = ParseJSONValue(json_parser);
47a580b014SDimitry Andric return return_sp;
48a580b014SDimitry Andric }
49a580b014SDimitry Andric
ParseJSONObject(JSONParser & json_parser)50a580b014SDimitry Andric static StructuredData::ObjectSP ParseJSONObject(JSONParser &json_parser) {
51a580b014SDimitry Andric // The "JSONParser::Token::ObjectStart" token should have already been
52a580b014SDimitry Andric // consumed by the time this function is called
53a580b014SDimitry Andric auto dict_up = llvm::make_unique<StructuredData::Dictionary>();
54a580b014SDimitry Andric
55a580b014SDimitry Andric std::string value;
56a580b014SDimitry Andric std::string key;
57a580b014SDimitry Andric while (1) {
58a580b014SDimitry Andric JSONParser::Token token = json_parser.GetToken(value);
59a580b014SDimitry Andric
60a580b014SDimitry Andric if (token == JSONParser::Token::String) {
61a580b014SDimitry Andric key.swap(value);
62a580b014SDimitry Andric token = json_parser.GetToken(value);
63a580b014SDimitry Andric if (token == JSONParser::Token::Colon) {
64a580b014SDimitry Andric StructuredData::ObjectSP value_sp = ParseJSONValue(json_parser);
65a580b014SDimitry Andric if (value_sp)
66a580b014SDimitry Andric dict_up->AddItem(key, value_sp);
67a580b014SDimitry Andric else
68a580b014SDimitry Andric break;
69a580b014SDimitry Andric }
70a580b014SDimitry Andric } else if (token == JSONParser::Token::ObjectEnd) {
71a580b014SDimitry Andric return StructuredData::ObjectSP(dict_up.release());
72a580b014SDimitry Andric } else if (token == JSONParser::Token::Comma) {
73a580b014SDimitry Andric continue;
74a580b014SDimitry Andric } else {
75a580b014SDimitry Andric break;
76a580b014SDimitry Andric }
77a580b014SDimitry Andric }
78a580b014SDimitry Andric return StructuredData::ObjectSP();
79a580b014SDimitry Andric }
80a580b014SDimitry Andric
ParseJSONArray(JSONParser & json_parser)81a580b014SDimitry Andric static StructuredData::ObjectSP ParseJSONArray(JSONParser &json_parser) {
82a580b014SDimitry Andric // The "JSONParser::Token::ObjectStart" token should have already been
834ba319b5SDimitry Andric // consumed by the time this function is called
84a580b014SDimitry Andric auto array_up = llvm::make_unique<StructuredData::Array>();
85a580b014SDimitry Andric
86a580b014SDimitry Andric std::string value;
87a580b014SDimitry Andric std::string key;
88a580b014SDimitry Andric while (1) {
89a580b014SDimitry Andric StructuredData::ObjectSP value_sp = ParseJSONValue(json_parser);
90a580b014SDimitry Andric if (value_sp)
91a580b014SDimitry Andric array_up->AddItem(value_sp);
92a580b014SDimitry Andric else
93a580b014SDimitry Andric break;
94a580b014SDimitry Andric
95a580b014SDimitry Andric JSONParser::Token token = json_parser.GetToken(value);
96a580b014SDimitry Andric if (token == JSONParser::Token::Comma) {
97a580b014SDimitry Andric continue;
98a580b014SDimitry Andric } else if (token == JSONParser::Token::ArrayEnd) {
99a580b014SDimitry Andric return StructuredData::ObjectSP(array_up.release());
100a580b014SDimitry Andric } else {
101a580b014SDimitry Andric break;
102a580b014SDimitry Andric }
103a580b014SDimitry Andric }
104a580b014SDimitry Andric return StructuredData::ObjectSP();
105a580b014SDimitry Andric }
106a580b014SDimitry Andric
ParseJSONValue(JSONParser & json_parser)107a580b014SDimitry Andric static StructuredData::ObjectSP ParseJSONValue(JSONParser &json_parser) {
108a580b014SDimitry Andric std::string value;
109a580b014SDimitry Andric const JSONParser::Token token = json_parser.GetToken(value);
110a580b014SDimitry Andric switch (token) {
111a580b014SDimitry Andric case JSONParser::Token::ObjectStart:
112a580b014SDimitry Andric return ParseJSONObject(json_parser);
113a580b014SDimitry Andric
114a580b014SDimitry Andric case JSONParser::Token::ArrayStart:
115a580b014SDimitry Andric return ParseJSONArray(json_parser);
116a580b014SDimitry Andric
117a580b014SDimitry Andric case JSONParser::Token::Integer: {
118a580b014SDimitry Andric uint64_t uval;
119a580b014SDimitry Andric if (llvm::to_integer(value, uval, 0))
120a580b014SDimitry Andric return std::make_shared<StructuredData::Integer>(uval);
121a580b014SDimitry Andric } break;
122a580b014SDimitry Andric
123a580b014SDimitry Andric case JSONParser::Token::Float: {
124a580b014SDimitry Andric double val;
125a580b014SDimitry Andric if (llvm::to_float(value, val))
126a580b014SDimitry Andric return std::make_shared<StructuredData::Float>(val);
127a580b014SDimitry Andric } break;
128a580b014SDimitry Andric
129a580b014SDimitry Andric case JSONParser::Token::String:
130a580b014SDimitry Andric return std::make_shared<StructuredData::String>(value);
131a580b014SDimitry Andric
132a580b014SDimitry Andric case JSONParser::Token::True:
133a580b014SDimitry Andric case JSONParser::Token::False:
134a580b014SDimitry Andric return std::make_shared<StructuredData::Boolean>(token ==
135a580b014SDimitry Andric JSONParser::Token::True);
136a580b014SDimitry Andric
137a580b014SDimitry Andric case JSONParser::Token::Null:
138a580b014SDimitry Andric return std::make_shared<StructuredData::Null>();
139a580b014SDimitry Andric
140a580b014SDimitry Andric default:
141a580b014SDimitry Andric break;
142a580b014SDimitry Andric }
143a580b014SDimitry Andric return StructuredData::ObjectSP();
144a580b014SDimitry Andric }
145a580b014SDimitry Andric
ParseJSON(std::string json_text)146a580b014SDimitry Andric StructuredData::ObjectSP StructuredData::ParseJSON(std::string json_text) {
147*b5893f02SDimitry Andric JSONParser json_parser(json_text);
148a580b014SDimitry Andric StructuredData::ObjectSP object_sp = ParseJSONValue(json_parser);
149a580b014SDimitry Andric return object_sp;
150a580b014SDimitry Andric }
151a580b014SDimitry Andric
152a580b014SDimitry Andric StructuredData::ObjectSP
GetObjectForDotSeparatedPath(llvm::StringRef path)153a580b014SDimitry Andric StructuredData::Object::GetObjectForDotSeparatedPath(llvm::StringRef path) {
154a580b014SDimitry Andric if (this->GetType() == lldb::eStructuredDataTypeDictionary) {
155a580b014SDimitry Andric std::pair<llvm::StringRef, llvm::StringRef> match = path.split('.');
156a580b014SDimitry Andric std::string key = match.first.str();
157a580b014SDimitry Andric ObjectSP value = this->GetAsDictionary()->GetValueForKey(key);
158a580b014SDimitry Andric if (value.get()) {
1594ba319b5SDimitry Andric // Do we have additional words to descend? If not, return the value
1604ba319b5SDimitry Andric // we're at right now.
161a580b014SDimitry Andric if (match.second.empty()) {
162a580b014SDimitry Andric return value;
163a580b014SDimitry Andric } else {
164a580b014SDimitry Andric return value->GetObjectForDotSeparatedPath(match.second);
165a580b014SDimitry Andric }
166a580b014SDimitry Andric }
167a580b014SDimitry Andric return ObjectSP();
168a580b014SDimitry Andric }
169a580b014SDimitry Andric
170a580b014SDimitry Andric if (this->GetType() == lldb::eStructuredDataTypeArray) {
171a580b014SDimitry Andric std::pair<llvm::StringRef, llvm::StringRef> match = path.split('[');
172*b5893f02SDimitry Andric if (match.second.empty()) {
173a580b014SDimitry Andric return this->shared_from_this();
174a580b014SDimitry Andric }
175a580b014SDimitry Andric errno = 0;
176*b5893f02SDimitry Andric uint64_t val = strtoul(match.second.str().c_str(), nullptr, 10);
177a580b014SDimitry Andric if (errno == 0) {
178a580b014SDimitry Andric return this->GetAsArray()->GetItemAtIndex(val);
179a580b014SDimitry Andric }
180a580b014SDimitry Andric return ObjectSP();
181a580b014SDimitry Andric }
182a580b014SDimitry Andric
183a580b014SDimitry Andric return this->shared_from_this();
184a580b014SDimitry Andric }
185a580b014SDimitry Andric
DumpToStdout(bool pretty_print) const186a580b014SDimitry Andric void StructuredData::Object::DumpToStdout(bool pretty_print) const {
187a580b014SDimitry Andric StreamString stream;
188a580b014SDimitry Andric Dump(stream, pretty_print);
189a580b014SDimitry Andric llvm::outs() << stream.GetString();
190a580b014SDimitry Andric }
191a580b014SDimitry Andric
Dump(Stream & s,bool pretty_print) const192a580b014SDimitry Andric void StructuredData::Array::Dump(Stream &s, bool pretty_print) const {
193a580b014SDimitry Andric bool first = true;
194a580b014SDimitry Andric s << "[";
195a580b014SDimitry Andric if (pretty_print) {
196a580b014SDimitry Andric s << "\n";
197a580b014SDimitry Andric s.IndentMore();
198a580b014SDimitry Andric }
199a580b014SDimitry Andric for (const auto &item_sp : m_items) {
200a580b014SDimitry Andric if (first) {
201a580b014SDimitry Andric first = false;
202a580b014SDimitry Andric } else {
203a580b014SDimitry Andric s << ",";
204a580b014SDimitry Andric if (pretty_print)
205a580b014SDimitry Andric s << "\n";
206a580b014SDimitry Andric }
207a580b014SDimitry Andric
208a580b014SDimitry Andric if (pretty_print)
209a580b014SDimitry Andric s.Indent();
210a580b014SDimitry Andric item_sp->Dump(s, pretty_print);
211a580b014SDimitry Andric }
212a580b014SDimitry Andric if (pretty_print) {
213a580b014SDimitry Andric s.IndentLess();
214a580b014SDimitry Andric s.EOL();
215a580b014SDimitry Andric s.Indent();
216a580b014SDimitry Andric }
217a580b014SDimitry Andric s << "]";
218a580b014SDimitry Andric }
219a580b014SDimitry Andric
Dump(Stream & s,bool pretty_print) const220a580b014SDimitry Andric void StructuredData::Integer::Dump(Stream &s, bool pretty_print) const {
221a580b014SDimitry Andric s.Printf("%" PRIu64, m_value);
222a580b014SDimitry Andric }
223a580b014SDimitry Andric
Dump(Stream & s,bool pretty_print) const224a580b014SDimitry Andric void StructuredData::Float::Dump(Stream &s, bool pretty_print) const {
225a580b014SDimitry Andric s.Printf("%lg", m_value);
226a580b014SDimitry Andric }
227a580b014SDimitry Andric
Dump(Stream & s,bool pretty_print) const228a580b014SDimitry Andric void StructuredData::Boolean::Dump(Stream &s, bool pretty_print) const {
229*b5893f02SDimitry Andric if (m_value)
230a580b014SDimitry Andric s.PutCString("true");
231a580b014SDimitry Andric else
232a580b014SDimitry Andric s.PutCString("false");
233a580b014SDimitry Andric }
234a580b014SDimitry Andric
Dump(Stream & s,bool pretty_print) const235a580b014SDimitry Andric void StructuredData::String::Dump(Stream &s, bool pretty_print) const {
236a580b014SDimitry Andric std::string quoted;
237a580b014SDimitry Andric const size_t strsize = m_value.size();
238a580b014SDimitry Andric for (size_t i = 0; i < strsize; ++i) {
239a580b014SDimitry Andric char ch = m_value[i];
240a580b014SDimitry Andric if (ch == '"' || ch == '\\')
241a580b014SDimitry Andric quoted.push_back('\\');
242a580b014SDimitry Andric quoted.push_back(ch);
243a580b014SDimitry Andric }
244a580b014SDimitry Andric s.Printf("\"%s\"", quoted.c_str());
245a580b014SDimitry Andric }
246a580b014SDimitry Andric
Dump(Stream & s,bool pretty_print) const247a580b014SDimitry Andric void StructuredData::Dictionary::Dump(Stream &s, bool pretty_print) const {
248a580b014SDimitry Andric bool first = true;
249a580b014SDimitry Andric s << "{";
250a580b014SDimitry Andric if (pretty_print) {
251a580b014SDimitry Andric s << "\n";
252a580b014SDimitry Andric s.IndentMore();
253a580b014SDimitry Andric }
254a580b014SDimitry Andric for (const auto &pair : m_dict) {
255a580b014SDimitry Andric if (first)
256a580b014SDimitry Andric first = false;
257a580b014SDimitry Andric else {
258a580b014SDimitry Andric s << ",";
259a580b014SDimitry Andric if (pretty_print)
260a580b014SDimitry Andric s << "\n";
261a580b014SDimitry Andric }
262a580b014SDimitry Andric if (pretty_print)
263a580b014SDimitry Andric s.Indent();
264a580b014SDimitry Andric s << "\"" << pair.first.AsCString() << "\" : ";
265a580b014SDimitry Andric pair.second->Dump(s, pretty_print);
266a580b014SDimitry Andric }
267a580b014SDimitry Andric if (pretty_print) {
268a580b014SDimitry Andric s.IndentLess();
269a580b014SDimitry Andric s.EOL();
270a580b014SDimitry Andric s.Indent();
271a580b014SDimitry Andric }
272a580b014SDimitry Andric s << "}";
273a580b014SDimitry Andric }
274a580b014SDimitry Andric
Dump(Stream & s,bool pretty_print) const275a580b014SDimitry Andric void StructuredData::Null::Dump(Stream &s, bool pretty_print) const {
276a580b014SDimitry Andric s << "null";
277a580b014SDimitry Andric }
278a580b014SDimitry Andric
Dump(Stream & s,bool pretty_print) const279a580b014SDimitry Andric void StructuredData::Generic::Dump(Stream &s, bool pretty_print) const {
280a580b014SDimitry Andric s << "0x" << m_object;
281a580b014SDimitry Andric }
282