LLDB  mainline
StructuredData.cpp
Go to the documentation of this file.
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 
11 #include "lldb/Utility/FileSpec.h"
12 #include "lldb/Utility/JSON.h"
13 #include "lldb/Utility/Status.h"
14 #include "lldb/Utility/Stream.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
29 
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 
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 (1) {
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 
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 (1) {
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 
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 
144  JSONParser json_parser(json_text);
145  StructuredData::ObjectSP object_sp = ParseJSONValue(json_parser);
146  return object_sp;
147 }
148 
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 }
size_t PutCString(llvm::StringRef cstr)
Output a C string to the stream.
Definition: Stream.cpp:61
void Dump(Stream &s, bool pretty_print=true) const override
Enumerations for broadcasting.
Definition: SBLaunchInfo.h:14
A stream class that can stream formatted output to a file.
Definition: Stream.h:28
void Dump(Stream &s, bool pretty_print=true) const override
void Dump(Stream &s, bool pretty_print=true) const override
A file utility class.
Definition: FileSpec.h:55
static ObjectSP ParseJSONFromFile(const FileSpec &file, Status &error)
void DumpToStdout(bool pretty_print=true) const
Token GetToken(std::string &value)
Definition: JSON.cpp:196
size_t EOL()
Output and End of Line character to the stream.
Definition: Stream.cpp:127
void Dump(Stream &s, bool pretty_print=true) const override
static ObjectSP ParseJSON(std::string json_text)
llvm::StringRef GetString() const
void IndentLess(int amount=2)
Decrement the current indentation level.
Definition: Stream.cpp:221
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition: Stream.cpp:106
static StructuredData::ObjectSP ParseJSONValue(JSONParser &json_parser)
ObjectSP GetObjectForDotSeparatedPath(llvm::StringRef path)
void Dump(Stream &s, bool pretty_print=true) const override
void Dump(Stream &s, bool pretty_print=true) const override
void Dump(Stream &s, bool pretty_print=true) const override
static StructuredData::ObjectSP ParseJSONObject(JSONParser &json_parser)
size_t Indent(const char *s=nullptr)
Indent the current line in the stream.
Definition: Stream.cpp:131
std::shared_ptr< Object > ObjectSP
void SetErrorStringWithFormatv(const char *format, Args &&... args)
Definition: Status.h:185
void IndentMore(int amount=2)
Increment the current indentation level.
Definition: Stream.cpp:218
static StructuredData::ObjectSP ParseJSONArray(JSONParser &json_parser)
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
Definition: FileSpec.cpp:376
void Dump(Stream &s, bool pretty_print=true) const override
An error handling class.
Definition: Status.h:44