StructuredData.cpp revision 344779
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/Utility/StructuredData.h" 11#include "lldb/Utility/DataBuffer.h" 12#include "lldb/Utility/FileSpec.h" 13#include "lldb/Utility/JSON.h" 14#include "lldb/Utility/Status.h" 15#include "lldb/Utility/Stream.h" 16#include "lldb/Utility/StreamString.h" 17#include "llvm/ADT/STLExtras.h" 18#include "llvm/Support/MemoryBuffer.h" 19#include <cerrno> 20#include <cstdlib> 21#include <inttypes.h> 22#include <limits> 23 24using namespace lldb_private; 25 26//---------------------------------------------------------------------- 27// Functions that use a JSONParser to parse JSON into StructuredData 28//---------------------------------------------------------------------- 29static StructuredData::ObjectSP ParseJSONValue(JSONParser &json_parser); 30static StructuredData::ObjectSP ParseJSONObject(JSONParser &json_parser); 31static StructuredData::ObjectSP ParseJSONArray(JSONParser &json_parser); 32 33StructuredData::ObjectSP 34StructuredData::ParseJSONFromFile(const FileSpec &input_spec, Status &error) { 35 StructuredData::ObjectSP return_sp; 36 37 auto buffer_or_error = llvm::MemoryBuffer::getFile(input_spec.GetPath()); 38 if (!buffer_or_error) { 39 error.SetErrorStringWithFormatv("could not open input file: {0} - {1}.", 40 input_spec.GetPath(), 41 buffer_or_error.getError().message()); 42 return return_sp; 43 } 44 45 JSONParser json_parser(buffer_or_error.get()->getBuffer()); 46 return_sp = ParseJSONValue(json_parser); 47 return return_sp; 48} 49 50static StructuredData::ObjectSP ParseJSONObject(JSONParser &json_parser) { 51 // The "JSONParser::Token::ObjectStart" token should have already been 52 // consumed by the time this function is called 53 auto dict_up = llvm::make_unique<StructuredData::Dictionary>(); 54 55 std::string value; 56 std::string key; 57 while (1) { 58 JSONParser::Token token = json_parser.GetToken(value); 59 60 if (token == JSONParser::Token::String) { 61 key.swap(value); 62 token = json_parser.GetToken(value); 63 if (token == JSONParser::Token::Colon) { 64 StructuredData::ObjectSP value_sp = ParseJSONValue(json_parser); 65 if (value_sp) 66 dict_up->AddItem(key, value_sp); 67 else 68 break; 69 } 70 } else if (token == JSONParser::Token::ObjectEnd) { 71 return StructuredData::ObjectSP(dict_up.release()); 72 } else if (token == JSONParser::Token::Comma) { 73 continue; 74 } else { 75 break; 76 } 77 } 78 return StructuredData::ObjectSP(); 79} 80 81static StructuredData::ObjectSP ParseJSONArray(JSONParser &json_parser) { 82 // The "JSONParser::Token::ObjectStart" token should have already been 83 // consumed by the time this function is called 84 auto array_up = llvm::make_unique<StructuredData::Array>(); 85 86 std::string value; 87 std::string key; 88 while (1) { 89 StructuredData::ObjectSP value_sp = ParseJSONValue(json_parser); 90 if (value_sp) 91 array_up->AddItem(value_sp); 92 else 93 break; 94 95 JSONParser::Token token = json_parser.GetToken(value); 96 if (token == JSONParser::Token::Comma) { 97 continue; 98 } else if (token == JSONParser::Token::ArrayEnd) { 99 return StructuredData::ObjectSP(array_up.release()); 100 } else { 101 break; 102 } 103 } 104 return StructuredData::ObjectSP(); 105} 106 107static StructuredData::ObjectSP ParseJSONValue(JSONParser &json_parser) { 108 std::string value; 109 const JSONParser::Token token = json_parser.GetToken(value); 110 switch (token) { 111 case JSONParser::Token::ObjectStart: 112 return ParseJSONObject(json_parser); 113 114 case JSONParser::Token::ArrayStart: 115 return ParseJSONArray(json_parser); 116 117 case JSONParser::Token::Integer: { 118 uint64_t uval; 119 if (llvm::to_integer(value, uval, 0)) 120 return std::make_shared<StructuredData::Integer>(uval); 121 } break; 122 123 case JSONParser::Token::Float: { 124 double val; 125 if (llvm::to_float(value, val)) 126 return std::make_shared<StructuredData::Float>(val); 127 } break; 128 129 case JSONParser::Token::String: 130 return std::make_shared<StructuredData::String>(value); 131 132 case JSONParser::Token::True: 133 case JSONParser::Token::False: 134 return std::make_shared<StructuredData::Boolean>(token == 135 JSONParser::Token::True); 136 137 case JSONParser::Token::Null: 138 return std::make_shared<StructuredData::Null>(); 139 140 default: 141 break; 142 } 143 return StructuredData::ObjectSP(); 144} 145 146StructuredData::ObjectSP StructuredData::ParseJSON(std::string json_text) { 147 JSONParser json_parser(json_text); 148 StructuredData::ObjectSP object_sp = ParseJSONValue(json_parser); 149 return object_sp; 150} 151 152StructuredData::ObjectSP 153StructuredData::Object::GetObjectForDotSeparatedPath(llvm::StringRef path) { 154 if (this->GetType() == lldb::eStructuredDataTypeDictionary) { 155 std::pair<llvm::StringRef, llvm::StringRef> match = path.split('.'); 156 std::string key = match.first.str(); 157 ObjectSP value = this->GetAsDictionary()->GetValueForKey(key); 158 if (value.get()) { 159 // Do we have additional words to descend? If not, return the value 160 // we're at right now. 161 if (match.second.empty()) { 162 return value; 163 } else { 164 return value->GetObjectForDotSeparatedPath(match.second); 165 } 166 } 167 return ObjectSP(); 168 } 169 170 if (this->GetType() == lldb::eStructuredDataTypeArray) { 171 std::pair<llvm::StringRef, llvm::StringRef> match = path.split('['); 172 if (match.second.empty()) { 173 return this->shared_from_this(); 174 } 175 errno = 0; 176 uint64_t val = strtoul(match.second.str().c_str(), nullptr, 10); 177 if (errno == 0) { 178 return this->GetAsArray()->GetItemAtIndex(val); 179 } 180 return ObjectSP(); 181 } 182 183 return this->shared_from_this(); 184} 185 186void StructuredData::Object::DumpToStdout(bool pretty_print) const { 187 StreamString stream; 188 Dump(stream, pretty_print); 189 llvm::outs() << stream.GetString(); 190} 191 192void StructuredData::Array::Dump(Stream &s, bool pretty_print) const { 193 bool first = true; 194 s << "["; 195 if (pretty_print) { 196 s << "\n"; 197 s.IndentMore(); 198 } 199 for (const auto &item_sp : m_items) { 200 if (first) { 201 first = false; 202 } else { 203 s << ","; 204 if (pretty_print) 205 s << "\n"; 206 } 207 208 if (pretty_print) 209 s.Indent(); 210 item_sp->Dump(s, pretty_print); 211 } 212 if (pretty_print) { 213 s.IndentLess(); 214 s.EOL(); 215 s.Indent(); 216 } 217 s << "]"; 218} 219 220void StructuredData::Integer::Dump(Stream &s, bool pretty_print) const { 221 s.Printf("%" PRIu64, m_value); 222} 223 224void StructuredData::Float::Dump(Stream &s, bool pretty_print) const { 225 s.Printf("%lg", m_value); 226} 227 228void StructuredData::Boolean::Dump(Stream &s, bool pretty_print) const { 229 if (m_value) 230 s.PutCString("true"); 231 else 232 s.PutCString("false"); 233} 234 235void StructuredData::String::Dump(Stream &s, bool pretty_print) const { 236 std::string quoted; 237 const size_t strsize = m_value.size(); 238 for (size_t i = 0; i < strsize; ++i) { 239 char ch = m_value[i]; 240 if (ch == '"' || ch == '\\') 241 quoted.push_back('\\'); 242 quoted.push_back(ch); 243 } 244 s.Printf("\"%s\"", quoted.c_str()); 245} 246 247void StructuredData::Dictionary::Dump(Stream &s, bool pretty_print) const { 248 bool first = true; 249 s << "{"; 250 if (pretty_print) { 251 s << "\n"; 252 s.IndentMore(); 253 } 254 for (const auto &pair : m_dict) { 255 if (first) 256 first = false; 257 else { 258 s << ","; 259 if (pretty_print) 260 s << "\n"; 261 } 262 if (pretty_print) 263 s.Indent(); 264 s << "\"" << pair.first.AsCString() << "\" : "; 265 pair.second->Dump(s, pretty_print); 266 } 267 if (pretty_print) { 268 s.IndentLess(); 269 s.EOL(); 270 s.Indent(); 271 } 272 s << "}"; 273} 274 275void StructuredData::Null::Dump(Stream &s, bool pretty_print) const { 276 s << "null"; 277} 278 279void StructuredData::Generic::Dump(Stream &s, bool pretty_print) const { 280 s << "0x" << m_object; 281} 282