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