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