]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm-project/lldb/source/Utility/StructuredData.cpp
MFC r355940:
[FreeBSD/FreeBSD.git] / contrib / llvm-project / lldb / source / Utility / StructuredData.cpp
1 //===---------------------StructuredData.cpp ---------------------*- C++-*-===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8
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"
18 #include <cerrno>
19 #include <cstdlib>
20 #include <inttypes.h>
21 #include <limits>
22
23 using namespace lldb_private;
24
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);
29
30 StructuredData::ObjectSP
31 StructuredData::ParseJSONFromFile(const FileSpec &input_spec, Status &error) {
32   StructuredData::ObjectSP return_sp;
33
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}.",
37                                     input_spec.GetPath(),
38                                     buffer_or_error.getError().message());
39     return return_sp;
40   }
41
42   JSONParser json_parser(buffer_or_error.get()->getBuffer());
43   return_sp = ParseJSONValue(json_parser);
44   return return_sp;
45 }
46
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>();
51
52   std::string value;
53   std::string key;
54   while (true) {
55     JSONParser::Token token = json_parser.GetToken(value);
56
57     if (token == JSONParser::Token::String) {
58       key.swap(value);
59       token = json_parser.GetToken(value);
60       if (token == JSONParser::Token::Colon) {
61         StructuredData::ObjectSP value_sp = ParseJSONValue(json_parser);
62         if (value_sp)
63           dict_up->AddItem(key, value_sp);
64         else
65           break;
66       }
67     } else if (token == JSONParser::Token::ObjectEnd) {
68       return StructuredData::ObjectSP(dict_up.release());
69     } else if (token == JSONParser::Token::Comma) {
70       continue;
71     } else {
72       break;
73     }
74   }
75   return StructuredData::ObjectSP();
76 }
77
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>();
82
83   std::string value;
84   std::string key;
85   while (true) {
86     StructuredData::ObjectSP value_sp = ParseJSONValue(json_parser);
87     if (value_sp)
88       array_up->AddItem(value_sp);
89     else
90       break;
91
92     JSONParser::Token token = json_parser.GetToken(value);
93     if (token == JSONParser::Token::Comma) {
94       continue;
95     } else if (token == JSONParser::Token::ArrayEnd) {
96       return StructuredData::ObjectSP(array_up.release());
97     } else {
98       break;
99     }
100   }
101   return StructuredData::ObjectSP();
102 }
103
104 static StructuredData::ObjectSP ParseJSONValue(JSONParser &json_parser) {
105   std::string value;
106   const JSONParser::Token token = json_parser.GetToken(value);
107   switch (token) {
108   case JSONParser::Token::ObjectStart:
109     return ParseJSONObject(json_parser);
110
111   case JSONParser::Token::ArrayStart:
112     return ParseJSONArray(json_parser);
113
114   case JSONParser::Token::Integer: {
115     uint64_t uval;
116     if (llvm::to_integer(value, uval, 0))
117       return std::make_shared<StructuredData::Integer>(uval);
118   } break;
119
120   case JSONParser::Token::Float: {
121     double val;
122     if (llvm::to_float(value, val))
123       return std::make_shared<StructuredData::Float>(val);
124   } break;
125
126   case JSONParser::Token::String:
127     return std::make_shared<StructuredData::String>(value);
128
129   case JSONParser::Token::True:
130   case JSONParser::Token::False:
131     return std::make_shared<StructuredData::Boolean>(token ==
132                                                      JSONParser::Token::True);
133
134   case JSONParser::Token::Null:
135     return std::make_shared<StructuredData::Null>();
136
137   default:
138     break;
139   }
140   return StructuredData::ObjectSP();
141 }
142
143 StructuredData::ObjectSP StructuredData::ParseJSON(std::string json_text) {
144   JSONParser json_parser(json_text);
145   StructuredData::ObjectSP object_sp = ParseJSONValue(json_parser);
146   return object_sp;
147 }
148
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);
155     if (value.get()) {
156       // Do we have additional words to descend?  If not, return the value
157       // we're at right now.
158       if (match.second.empty()) {
159         return value;
160       } else {
161         return value->GetObjectForDotSeparatedPath(match.second);
162       }
163     }
164     return ObjectSP();
165   }
166
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();
171     }
172     errno = 0;
173     uint64_t val = strtoul(match.second.str().c_str(), nullptr, 10);
174     if (errno == 0) {
175       return this->GetAsArray()->GetItemAtIndex(val);
176     }
177     return ObjectSP();
178   }
179
180   return this->shared_from_this();
181 }
182
183 void StructuredData::Object::DumpToStdout(bool pretty_print) const {
184   StreamString stream;
185   Dump(stream, pretty_print);
186   llvm::outs() << stream.GetString();
187 }
188
189 void StructuredData::Array::Dump(Stream &s, bool pretty_print) const {
190   bool first = true;
191   s << "[";
192   if (pretty_print) {
193     s << "\n";
194     s.IndentMore();
195   }
196   for (const auto &item_sp : m_items) {
197     if (first) {
198       first = false;
199     } else {
200       s << ",";
201       if (pretty_print)
202         s << "\n";
203     }
204
205     if (pretty_print)
206       s.Indent();
207     item_sp->Dump(s, pretty_print);
208   }
209   if (pretty_print) {
210     s.IndentLess();
211     s.EOL();
212     s.Indent();
213   }
214   s << "]";
215 }
216
217 void StructuredData::Integer::Dump(Stream &s, bool pretty_print) const {
218   s.Printf("%" PRIu64, m_value);
219 }
220
221 void StructuredData::Float::Dump(Stream &s, bool pretty_print) const {
222   s.Printf("%lg", m_value);
223 }
224
225 void StructuredData::Boolean::Dump(Stream &s, bool pretty_print) const {
226   if (m_value)
227     s.PutCString("true");
228   else
229     s.PutCString("false");
230 }
231
232 void StructuredData::String::Dump(Stream &s, bool pretty_print) const {
233   std::string quoted;
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);
240   }
241   s.Printf("\"%s\"", quoted.c_str());
242 }
243
244 void StructuredData::Dictionary::Dump(Stream &s, bool pretty_print) const {
245   bool first = true;
246   s << "{";
247   if (pretty_print) {
248     s << "\n";
249     s.IndentMore();
250   }
251   for (const auto &pair : m_dict) {
252     if (first)
253       first = false;
254     else {
255       s << ",";
256       if (pretty_print)
257         s << "\n";
258     }
259     if (pretty_print)
260       s.Indent();
261     s << "\"" << pair.first.AsCString() << "\" : ";
262     pair.second->Dump(s, pretty_print);
263   }
264   if (pretty_print) {
265     s.IndentLess();
266     s.EOL();
267     s.Indent();
268   }
269   s << "}";
270 }
271
272 void StructuredData::Null::Dump(Stream &s, bool pretty_print) const {
273   s << "null";
274 }
275
276 void StructuredData::Generic::Dump(Stream &s, bool pretty_print) const {
277   s << "0x" << m_object;
278 }