1 //===---------------------StructuredData.cpp ---------------------*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "lldb/Core/StructuredData.h"
11
12 #include <errno.h>
13 #include <stdlib.h>
14 #include <inttypes.h>
15
16 #include "lldb/Core/StreamString.h"
17 #include "lldb/Host/StringConvert.h"
18 #include "lldb/Utility/JSON.h"
19
20 using namespace lldb_private;
21
22
23 //----------------------------------------------------------------------
24 // Functions that use a JSONParser to parse JSON into StructuredData
25 //----------------------------------------------------------------------
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 static StructuredData::ObjectSP
ParseJSONObject(JSONParser & json_parser)31 ParseJSONObject (JSONParser &json_parser)
32 {
33 // The "JSONParser::Token::ObjectStart" token should have already been consumed
34 // by the time this function is called
35 std::unique_ptr<StructuredData::Dictionary> dict_up(new StructuredData::Dictionary());
36
37 std::string value;
38 std::string key;
39 while (1)
40 {
41 JSONParser::Token token = json_parser.GetToken(value);
42
43 if (token == JSONParser::Token::String)
44 {
45 key.swap(value);
46 token = json_parser.GetToken(value);
47 if (token == JSONParser::Token::Colon)
48 {
49 StructuredData::ObjectSP value_sp = ParseJSONValue(json_parser);
50 if (value_sp)
51 dict_up->AddItem(key, value_sp);
52 else
53 break;
54 }
55 }
56 else if (token == JSONParser::Token::ObjectEnd)
57 {
58 return StructuredData::ObjectSP(dict_up.release());
59 }
60 else if (token == JSONParser::Token::Comma)
61 {
62 continue;
63 }
64 else
65 {
66 break;
67 }
68 }
69 return StructuredData::ObjectSP();
70 }
71
72 static StructuredData::ObjectSP
ParseJSONArray(JSONParser & json_parser)73 ParseJSONArray (JSONParser &json_parser)
74 {
75 // The "JSONParser::Token::ObjectStart" token should have already been consumed
76 // by the time this function is called
77 std::unique_ptr<StructuredData::Array> array_up(new StructuredData::Array());
78
79 std::string value;
80 std::string key;
81 while (1)
82 {
83 StructuredData::ObjectSP value_sp = ParseJSONValue(json_parser);
84 if (value_sp)
85 array_up->AddItem(value_sp);
86 else
87 break;
88
89 JSONParser::Token token = json_parser.GetToken(value);
90 if (token == JSONParser::Token::Comma)
91 {
92 continue;
93 }
94 else if (token == JSONParser::Token::ArrayEnd)
95 {
96 return StructuredData::ObjectSP(array_up.release());
97 }
98 else
99 {
100 break;
101 }
102 }
103 return StructuredData::ObjectSP();
104 }
105
106 static StructuredData::ObjectSP
ParseJSONValue(JSONParser & json_parser)107 ParseJSONValue (JSONParser &json_parser)
108 {
109 std::string value;
110 const JSONParser::Token token = json_parser.GetToken(value);
111 switch (token)
112 {
113 case JSONParser::Token::ObjectStart:
114 return ParseJSONObject(json_parser);
115
116 case JSONParser::Token::ArrayStart:
117 return ParseJSONArray(json_parser);
118
119 case JSONParser::Token::Integer:
120 {
121 bool success = false;
122 uint64_t uval = StringConvert::ToUInt64(value.c_str(), 0, 0, &success);
123 if (success)
124 return StructuredData::ObjectSP(new StructuredData::Integer(uval));
125 }
126 break;
127
128 case JSONParser::Token::Float:
129 {
130 bool success = false;
131 double val = StringConvert::ToDouble(value.c_str(), 0.0, &success);
132 if (success)
133 return StructuredData::ObjectSP(new StructuredData::Float(val));
134 }
135 break;
136
137 case JSONParser::Token::String:
138 return StructuredData::ObjectSP(new StructuredData::String(value));
139
140 case JSONParser::Token::True:
141 case JSONParser::Token::False:
142 return StructuredData::ObjectSP(new StructuredData::Boolean(token == JSONParser::Token::True));
143
144 case JSONParser::Token::Null:
145 return StructuredData::ObjectSP(new StructuredData::Null());
146
147 default:
148 break;
149 }
150 return StructuredData::ObjectSP();
151
152 }
153
154 StructuredData::ObjectSP
ParseJSON(std::string json_text)155 StructuredData::ParseJSON (std::string json_text)
156 {
157 JSONParser json_parser(json_text.c_str());
158 StructuredData::ObjectSP object_sp = ParseJSONValue(json_parser);
159 return object_sp;
160 }
161
162 StructuredData::ObjectSP
GetObjectForDotSeparatedPath(llvm::StringRef path)163 StructuredData::Object::GetObjectForDotSeparatedPath (llvm::StringRef path)
164 {
165 if (this->GetType() == Type::eTypeDictionary)
166 {
167 std::pair<llvm::StringRef, llvm::StringRef> match = path.split('.');
168 std::string key = match.first.str();
169 ObjectSP value = this->GetAsDictionary()->GetValueForKey (key.c_str());
170 if (value.get())
171 {
172 // Do we have additional words to descend? If not, return the
173 // value we're at right now.
174 if (match.second.empty())
175 {
176 return value;
177 }
178 else
179 {
180 return value->GetObjectForDotSeparatedPath (match.second);
181 }
182 }
183 return ObjectSP();
184 }
185
186 if (this->GetType() == Type::eTypeArray)
187 {
188 std::pair<llvm::StringRef, llvm::StringRef> match = path.split('[');
189 if (match.second.size() == 0)
190 {
191 return this->shared_from_this();
192 }
193 errno = 0;
194 uint64_t val = strtoul (match.second.str().c_str(), NULL, 10);
195 if (errno == 0)
196 {
197 return this->GetAsArray()->GetItemAtIndex(val);
198 }
199 return ObjectSP();
200 }
201
202 return this->shared_from_this();
203 }
204
205 void
DumpToStdout() const206 StructuredData::Object::DumpToStdout() const
207 {
208 StreamString stream;
209 Dump(stream);
210 printf("%s\n", stream.GetString().c_str());
211 }
212
213 void
Dump(Stream & s) const214 StructuredData::Array::Dump(Stream &s) const
215 {
216 bool first = true;
217 s << "[\n";
218 s.IndentMore();
219 for (const auto &item_sp : m_items)
220 {
221 if (first)
222 first = false;
223 else
224 s << ",\n";
225
226 s.Indent();
227 item_sp->Dump(s);
228 }
229 s.IndentLess();
230 s.EOL();
231 s.Indent();
232 s << "]";
233 }
234
235 void
Dump(Stream & s) const236 StructuredData::Integer::Dump (Stream &s) const
237 {
238 s.Printf ("%" PRIu64, m_value);
239 }
240
241
242 void
Dump(Stream & s) const243 StructuredData::Float::Dump (Stream &s) const
244 {
245 s.Printf ("%lg", m_value);
246 }
247
248 void
Dump(Stream & s) const249 StructuredData::Boolean::Dump (Stream &s) const
250 {
251 if (m_value == true)
252 s.PutCString ("true");
253 else
254 s.PutCString ("false");
255 }
256
257
258 void
Dump(Stream & s) const259 StructuredData::String::Dump (Stream &s) const
260 {
261 std::string quoted;
262 const size_t strsize = m_value.size();
263 for (size_t i = 0; i < strsize ; ++i)
264 {
265 char ch = m_value[i];
266 if (ch == '"')
267 quoted.push_back ('\\');
268 quoted.push_back (ch);
269 }
270 s.Printf ("\"%s\"", quoted.c_str());
271 }
272
273 void
Dump(Stream & s) const274 StructuredData::Dictionary::Dump (Stream &s) const
275 {
276 bool first = true;
277 s << "{\n";
278 s.IndentMore();
279 for (const auto &pair : m_dict)
280 {
281 if (first)
282 first = false;
283 else
284 s << ",\n";
285 s.Indent();
286 s << "\"" << pair.first.AsCString() << "\" : ";
287 pair.second->Dump(s);
288 }
289 s.IndentLess();
290 s.EOL();
291 s.Indent();
292 s << "}";
293 }
294
295 void
Dump(Stream & s) const296 StructuredData::Null::Dump (Stream &s) const
297 {
298 s << "null";
299 }
300
301 void
Dump(Stream & s) const302 StructuredData::Generic::Dump(Stream &s) const
303 {
304 s << "0x" << m_object;
305 }
306