blob: b4bfe03a4140fb7308a31403187283d62334d1ed [file] [log] [blame]
Zachary Turnerc1564272016-11-16 21:15:24 +00001//===---------------------StructuredData.cpp ---------------------*- C++-*-===//
Jason Molenda705b1802014-06-13 02:37:02 +00002//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Jason Molenda705b1802014-06-13 02:37:02 +00006//
7//===----------------------------------------------------------------------===//
8
Pavel Labathf2a8bcc2017-06-27 10:45:31 +00009#include "lldb/Utility/StructuredData.h"
Zachary Turner666cc0b2017-03-04 01:30:05 +000010#include "lldb/Utility/DataBuffer.h"
Zachary Turner5713a052017-03-22 18:40:07 +000011#include "lldb/Utility/FileSpec.h"
Greg Clayton98424c42015-07-06 23:40:40 +000012#include "lldb/Utility/JSON.h"
Zachary Turner97206d52017-05-12 04:51:55 +000013#include "lldb/Utility/Status.h"
Jonas Devlieghere672d2c12018-11-11 23:16:43 +000014#include "lldb/Utility/Stream.h"
Zachary Turnerbf9a7732017-02-02 21:39:50 +000015#include "lldb/Utility/StreamString.h"
Jonas Devlieghere672d2c12018-11-11 23:16:43 +000016#include "llvm/ADT/STLExtras.h"
Eugene Zemtsov11c0aab2017-11-17 03:28:58 +000017#include "llvm/Support/MemoryBuffer.h"
Pavel Labathf2a8bcc2017-06-27 10:45:31 +000018#include <cerrno>
19#include <cstdlib>
Zachary Turner2f3df612017-04-06 21:28:29 +000020#include <inttypes.h>
Jonas Devlieghere672d2c12018-11-11 23:16:43 +000021#include <limits>
Zachary Turner0641ca12015-03-17 20:04:04 +000022
Jason Molenda705b1802014-06-13 02:37:02 +000023using namespace lldb_private;
24
Greg Clayton98424c42015-07-06 23:40:40 +000025//----------------------------------------------------------------------
26// Functions that use a JSONParser to parse JSON into StructuredData
27//----------------------------------------------------------------------
Kate Stoneb9c1b512016-09-06 20:57:50 +000028static StructuredData::ObjectSP ParseJSONValue(JSONParser &json_parser);
29static StructuredData::ObjectSP ParseJSONObject(JSONParser &json_parser);
30static StructuredData::ObjectSP ParseJSONArray(JSONParser &json_parser);
Jason Molenda705b1802014-06-13 02:37:02 +000031
Jim Ingham01f16662016-09-14 19:07:35 +000032StructuredData::ObjectSP
Zachary Turner97206d52017-05-12 04:51:55 +000033StructuredData::ParseJSONFromFile(const FileSpec &input_spec, Status &error) {
Jim Inghame14dc262016-09-12 23:10:56 +000034 StructuredData::ObjectSP return_sp;
Jim Inghame14dc262016-09-12 23:10:56 +000035
Pavel Labathf2a8bcc2017-06-27 10:45:31 +000036 auto buffer_or_error = llvm::MemoryBuffer::getFile(input_spec.GetPath());
37 if (!buffer_or_error) {
38 error.SetErrorStringWithFormatv("could not open input file: {0} - {1}.",
39 input_spec.GetPath(),
40 buffer_or_error.getError().message());
Jim Inghame14dc262016-09-12 23:10:56 +000041 return return_sp;
42 }
43
Pavel Labathf2a8bcc2017-06-27 10:45:31 +000044 JSONParser json_parser(buffer_or_error.get()->getBuffer());
Jim Inghame14dc262016-09-12 23:10:56 +000045 return_sp = ParseJSONValue(json_parser);
46 return return_sp;
47}
48
Kate Stoneb9c1b512016-09-06 20:57:50 +000049static StructuredData::ObjectSP ParseJSONObject(JSONParser &json_parser) {
50 // The "JSONParser::Token::ObjectStart" token should have already been
Zachary Turner2f3df612017-04-06 21:28:29 +000051 // consumed by the time this function is called
52 auto dict_up = llvm::make_unique<StructuredData::Dictionary>();
Jason Molenda705b1802014-06-13 02:37:02 +000053
Kate Stoneb9c1b512016-09-06 20:57:50 +000054 std::string value;
55 std::string key;
56 while (1) {
57 JSONParser::Token token = json_parser.GetToken(value);
Jason Molenda705b1802014-06-13 02:37:02 +000058
Kate Stoneb9c1b512016-09-06 20:57:50 +000059 if (token == JSONParser::Token::String) {
60 key.swap(value);
61 token = json_parser.GetToken(value);
62 if (token == JSONParser::Token::Colon) {
Greg Clayton98424c42015-07-06 23:40:40 +000063 StructuredData::ObjectSP value_sp = ParseJSONValue(json_parser);
64 if (value_sp)
Kate Stoneb9c1b512016-09-06 20:57:50 +000065 dict_up->AddItem(key, value_sp);
Greg Clayton98424c42015-07-06 23:40:40 +000066 else
Kate Stoneb9c1b512016-09-06 20:57:50 +000067 break;
68 }
69 } else if (token == JSONParser::Token::ObjectEnd) {
70 return StructuredData::ObjectSP(dict_up.release());
71 } else if (token == JSONParser::Token::Comma) {
72 continue;
73 } else {
74 break;
Jason Molenda705b1802014-06-13 02:37:02 +000075 }
Kate Stoneb9c1b512016-09-06 20:57:50 +000076 }
77 return StructuredData::ObjectSP();
Jason Molenda705b1802014-06-13 02:37:02 +000078}
79
Kate Stoneb9c1b512016-09-06 20:57:50 +000080static StructuredData::ObjectSP ParseJSONArray(JSONParser &json_parser) {
81 // The "JSONParser::Token::ObjectStart" token should have already been
Adrian Prantl05097242018-04-30 16:49:04 +000082 // consumed by the time this function is called
Zachary Turner2f3df612017-04-06 21:28:29 +000083 auto array_up = llvm::make_unique<StructuredData::Array>();
Jason Molenda705b1802014-06-13 02:37:02 +000084
Kate Stoneb9c1b512016-09-06 20:57:50 +000085 std::string value;
86 std::string key;
87 while (1) {
88 StructuredData::ObjectSP value_sp = ParseJSONValue(json_parser);
89 if (value_sp)
90 array_up->AddItem(value_sp);
Jason Molenda705b1802014-06-13 02:37:02 +000091 else
Kate Stoneb9c1b512016-09-06 20:57:50 +000092 break;
Jason Molenda705b1802014-06-13 02:37:02 +000093
Kate Stoneb9c1b512016-09-06 20:57:50 +000094 JSONParser::Token token = json_parser.GetToken(value);
95 if (token == JSONParser::Token::Comma) {
96 continue;
97 } else if (token == JSONParser::Token::ArrayEnd) {
98 return StructuredData::ObjectSP(array_up.release());
99 } else {
100 break;
Jason Molenda705b1802014-06-13 02:37:02 +0000101 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000102 }
103 return StructuredData::ObjectSP();
Jason Molenda705b1802014-06-13 02:37:02 +0000104}
105
Kate Stoneb9c1b512016-09-06 20:57:50 +0000106static StructuredData::ObjectSP ParseJSONValue(JSONParser &json_parser) {
107 std::string value;
108 const JSONParser::Token token = json_parser.GetToken(value);
109 switch (token) {
110 case JSONParser::Token::ObjectStart:
111 return ParseJSONObject(json_parser);
112
113 case JSONParser::Token::ArrayStart:
114 return ParseJSONArray(json_parser);
115
116 case JSONParser::Token::Integer: {
Pavel Labathf2a8bcc2017-06-27 10:45:31 +0000117 uint64_t uval;
118 if (llvm::to_integer(value, uval, 0))
Zachary Turner2f3df612017-04-06 21:28:29 +0000119 return std::make_shared<StructuredData::Integer>(uval);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000120 } break;
121
122 case JSONParser::Token::Float: {
Pavel Labathf2a8bcc2017-06-27 10:45:31 +0000123 double val;
124 if (llvm::to_float(value, val))
Zachary Turner2f3df612017-04-06 21:28:29 +0000125 return std::make_shared<StructuredData::Float>(val);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000126 } break;
127
128 case JSONParser::Token::String:
Zachary Turner2f3df612017-04-06 21:28:29 +0000129 return std::make_shared<StructuredData::String>(value);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000130
131 case JSONParser::Token::True:
132 case JSONParser::Token::False:
Zachary Turner2f3df612017-04-06 21:28:29 +0000133 return std::make_shared<StructuredData::Boolean>(token ==
134 JSONParser::Token::True);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000135
136 case JSONParser::Token::Null:
Zachary Turner2f3df612017-04-06 21:28:29 +0000137 return std::make_shared<StructuredData::Null>();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000138
139 default:
140 break;
141 }
142 return StructuredData::ObjectSP();
143}
144
145StructuredData::ObjectSP StructuredData::ParseJSON(std::string json_text) {
Jonas Devlieghere65e5e2782018-12-13 00:15:17 +0000146 JSONParser json_parser(json_text);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000147 StructuredData::ObjectSP object_sp = ParseJSONValue(json_parser);
148 return object_sp;
149}
150
151StructuredData::ObjectSP
152StructuredData::Object::GetObjectForDotSeparatedPath(llvm::StringRef path) {
Abhishek Aggarwal5bfee5f2017-05-29 08:25:46 +0000153 if (this->GetType() == lldb::eStructuredDataTypeDictionary) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000154 std::pair<llvm::StringRef, llvm::StringRef> match = path.split('.');
155 std::string key = match.first.str();
Malcolm Parsons771ef6d2016-11-02 20:34:10 +0000156 ObjectSP value = this->GetAsDictionary()->GetValueForKey(key);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000157 if (value.get()) {
Adrian Prantl05097242018-04-30 16:49:04 +0000158 // Do we have additional words to descend? If not, return the value
159 // we're at right now.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000160 if (match.second.empty()) {
161 return value;
162 } else {
163 return value->GetObjectForDotSeparatedPath(match.second);
164 }
165 }
166 return ObjectSP();
167 }
168
Abhishek Aggarwal5bfee5f2017-05-29 08:25:46 +0000169 if (this->GetType() == lldb::eStructuredDataTypeArray) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000170 std::pair<llvm::StringRef, llvm::StringRef> match = path.split('[');
Jonas Devlieghere65e5e2782018-12-13 00:15:17 +0000171 if (match.second.empty()) {
Kate Stoneb9c1b512016-09-06 20:57:50 +0000172 return this->shared_from_this();
173 }
174 errno = 0;
Jonas Devlieghere65e5e2782018-12-13 00:15:17 +0000175 uint64_t val = strtoul(match.second.str().c_str(), nullptr, 10);
Kate Stoneb9c1b512016-09-06 20:57:50 +0000176 if (errno == 0) {
177 return this->GetAsArray()->GetItemAtIndex(val);
178 }
179 return ObjectSP();
180 }
181
182 return this->shared_from_this();
183}
184
185void StructuredData::Object::DumpToStdout(bool pretty_print) const {
186 StreamString stream;
187 Dump(stream, pretty_print);
Pavel Labathf2a8bcc2017-06-27 10:45:31 +0000188 llvm::outs() << stream.GetString();
Kate Stoneb9c1b512016-09-06 20:57:50 +0000189}
190
191void StructuredData::Array::Dump(Stream &s, bool pretty_print) const {
192 bool first = true;
193 s << "[";
194 if (pretty_print) {
195 s << "\n";
196 s.IndentMore();
197 }
198 for (const auto &item_sp : m_items) {
199 if (first) {
200 first = false;
201 } else {
202 s << ",";
203 if (pretty_print)
Jason Molendae62dda22016-07-21 22:50:01 +0000204 s << "\n";
Jason Molendad9c9da52016-07-20 03:49:02 +0000205 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000206
207 if (pretty_print)
208 s.Indent();
209 item_sp->Dump(s, pretty_print);
210 }
211 if (pretty_print) {
212 s.IndentLess();
213 s.EOL();
214 s.Indent();
215 }
216 s << "]";
217}
218
219void StructuredData::Integer::Dump(Stream &s, bool pretty_print) const {
220 s.Printf("%" PRIu64, m_value);
221}
222
223void StructuredData::Float::Dump(Stream &s, bool pretty_print) const {
224 s.Printf("%lg", m_value);
225}
226
227void StructuredData::Boolean::Dump(Stream &s, bool pretty_print) const {
Jonas Devliegherea6682a42018-12-15 00:15:33 +0000228 if (m_value)
Kate Stoneb9c1b512016-09-06 20:57:50 +0000229 s.PutCString("true");
230 else
231 s.PutCString("false");
232}
233
234void StructuredData::String::Dump(Stream &s, bool pretty_print) const {
235 std::string quoted;
236 const size_t strsize = m_value.size();
237 for (size_t i = 0; i < strsize; ++i) {
238 char ch = m_value[i];
Pavel Labath2a668842016-09-22 15:26:43 +0000239 if (ch == '"' || ch == '\\')
Kate Stoneb9c1b512016-09-06 20:57:50 +0000240 quoted.push_back('\\');
241 quoted.push_back(ch);
242 }
243 s.Printf("\"%s\"", quoted.c_str());
244}
245
246void StructuredData::Dictionary::Dump(Stream &s, bool pretty_print) const {
247 bool first = true;
248 s << "{";
249 if (pretty_print) {
250 s << "\n";
251 s.IndentMore();
252 }
253 for (const auto &pair : m_dict) {
254 if (first)
255 first = false;
256 else {
257 s << ",";
258 if (pretty_print)
259 s << "\n";
Jason Molenda705b1802014-06-13 02:37:02 +0000260 }
Jason Molendad9c9da52016-07-20 03:49:02 +0000261 if (pretty_print)
Kate Stoneb9c1b512016-09-06 20:57:50 +0000262 s.Indent();
263 s << "\"" << pair.first.AsCString() << "\" : ";
264 pair.second->Dump(s, pretty_print);
265 }
266 if (pretty_print) {
267 s.IndentLess();
268 s.EOL();
269 s.Indent();
270 }
271 s << "}";
Jason Molenda705b1802014-06-13 02:37:02 +0000272}
273
Kate Stoneb9c1b512016-09-06 20:57:50 +0000274void StructuredData::Null::Dump(Stream &s, bool pretty_print) const {
275 s << "null";
Jason Molenda705b1802014-06-13 02:37:02 +0000276}
Zachary Turner0641ca12015-03-17 20:04:04 +0000277
Kate Stoneb9c1b512016-09-06 20:57:50 +0000278void StructuredData::Generic::Dump(Stream &s, bool pretty_print) const {
279 s << "0x" << m_object;
Zachary Turner0641ca12015-03-17 20:04:04 +0000280}