//===---------------------StructuredData.cpp ---------------------*- C++-*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "lldb/Utility/StructuredData.h" #include "lldb/Utility/DataBuffer.h" #include "lldb/Utility/FileSpec.h" #include "lldb/Utility/JSON.h" #include "lldb/Utility/Status.h" #include "lldb/Utility/Stream.h" // for Stream #include "lldb/Utility/StreamString.h" #include "llvm/ADT/STLExtras.h" // for make_unique #include #include #include #include // for numeric_limits using namespace lldb_private; //---------------------------------------------------------------------- // Functions that use a JSONParser to parse JSON into StructuredData //---------------------------------------------------------------------- static StructuredData::ObjectSP ParseJSONValue(JSONParser &json_parser); static StructuredData::ObjectSP ParseJSONObject(JSONParser &json_parser); static StructuredData::ObjectSP ParseJSONArray(JSONParser &json_parser); StructuredData::ObjectSP StructuredData::ParseJSONFromFile(const FileSpec &input_spec, Status &error) { StructuredData::ObjectSP return_sp; if (!input_spec.Exists()) { error.SetErrorStringWithFormatv("input file {0} does not exist.", input_spec); return return_sp; } auto buffer_or_error = llvm::MemoryBuffer::getFile(input_spec.GetPath()); if (!buffer_or_error) { error.SetErrorStringWithFormatv("could not open input file: {0} - {1}.", input_spec.GetPath(), buffer_or_error.getError().message()); return return_sp; } JSONParser json_parser(buffer_or_error.get()->getBuffer()); return_sp = ParseJSONValue(json_parser); return return_sp; } static StructuredData::ObjectSP ParseJSONObject(JSONParser &json_parser) { // The "JSONParser::Token::ObjectStart" token should have already been // consumed by the time this function is called auto dict_up = llvm::make_unique(); std::string value; std::string key; while (1) { JSONParser::Token token = json_parser.GetToken(value); if (token == JSONParser::Token::String) { key.swap(value); token = json_parser.GetToken(value); if (token == JSONParser::Token::Colon) { StructuredData::ObjectSP value_sp = ParseJSONValue(json_parser); if (value_sp) dict_up->AddItem(key, value_sp); else break; } } else if (token == JSONParser::Token::ObjectEnd) { return StructuredData::ObjectSP(dict_up.release()); } else if (token == JSONParser::Token::Comma) { continue; } else { break; } } return StructuredData::ObjectSP(); } static StructuredData::ObjectSP ParseJSONArray(JSONParser &json_parser) { // The "JSONParser::Token::ObjectStart" token should have already been // consumed // by the time this function is called auto array_up = llvm::make_unique(); std::string value; std::string key; while (1) { StructuredData::ObjectSP value_sp = ParseJSONValue(json_parser); if (value_sp) array_up->AddItem(value_sp); else break; JSONParser::Token token = json_parser.GetToken(value); if (token == JSONParser::Token::Comma) { continue; } else if (token == JSONParser::Token::ArrayEnd) { return StructuredData::ObjectSP(array_up.release()); } else { break; } } return StructuredData::ObjectSP(); } static StructuredData::ObjectSP ParseJSONValue(JSONParser &json_parser) { std::string value; const JSONParser::Token token = json_parser.GetToken(value); switch (token) { case JSONParser::Token::ObjectStart: return ParseJSONObject(json_parser); case JSONParser::Token::ArrayStart: return ParseJSONArray(json_parser); case JSONParser::Token::Integer: { uint64_t uval; if (llvm::to_integer(value, uval, 0)) return std::make_shared(uval); } break; case JSONParser::Token::Float: { double val; if (llvm::to_float(value, val)) return std::make_shared(val); } break; case JSONParser::Token::String: return std::make_shared(value); case JSONParser::Token::True: case JSONParser::Token::False: return std::make_shared(token == JSONParser::Token::True); case JSONParser::Token::Null: return std::make_shared(); default: break; } return StructuredData::ObjectSP(); } StructuredData::ObjectSP StructuredData::ParseJSON(std::string json_text) { JSONParser json_parser(json_text.c_str()); StructuredData::ObjectSP object_sp = ParseJSONValue(json_parser); return object_sp; } StructuredData::ObjectSP StructuredData::Object::GetObjectForDotSeparatedPath(llvm::StringRef path) { if (this->GetType() == lldb::eStructuredDataTypeDictionary) { std::pair match = path.split('.'); std::string key = match.first.str(); ObjectSP value = this->GetAsDictionary()->GetValueForKey(key); if (value.get()) { // Do we have additional words to descend? If not, return the // value we're at right now. if (match.second.empty()) { return value; } else { return value->GetObjectForDotSeparatedPath(match.second); } } return ObjectSP(); } if (this->GetType() == lldb::eStructuredDataTypeArray) { std::pair match = path.split('['); if (match.second.size() == 0) { return this->shared_from_this(); } errno = 0; uint64_t val = strtoul(match.second.str().c_str(), NULL, 10); if (errno == 0) { return this->GetAsArray()->GetItemAtIndex(val); } return ObjectSP(); } return this->shared_from_this(); } void StructuredData::Object::DumpToStdout(bool pretty_print) const { StreamString stream; Dump(stream, pretty_print); llvm::outs() << stream.GetString(); } void StructuredData::Array::Dump(Stream &s, bool pretty_print) const { bool first = true; s << "["; if (pretty_print) { s << "\n"; s.IndentMore(); } for (const auto &item_sp : m_items) { if (first) { first = false; } else { s << ","; if (pretty_print) s << "\n"; } if (pretty_print) s.Indent(); item_sp->Dump(s, pretty_print); } if (pretty_print) { s.IndentLess(); s.EOL(); s.Indent(); } s << "]"; } void StructuredData::Integer::Dump(Stream &s, bool pretty_print) const { s.Printf("%" PRIu64, m_value); } void StructuredData::Float::Dump(Stream &s, bool pretty_print) const { s.Printf("%lg", m_value); } void StructuredData::Boolean::Dump(Stream &s, bool pretty_print) const { if (m_value == true) s.PutCString("true"); else s.PutCString("false"); } void StructuredData::String::Dump(Stream &s, bool pretty_print) const { std::string quoted; const size_t strsize = m_value.size(); for (size_t i = 0; i < strsize; ++i) { char ch = m_value[i]; if (ch == '"' || ch == '\\') quoted.push_back('\\'); quoted.push_back(ch); } s.Printf("\"%s\"", quoted.c_str()); } void StructuredData::Dictionary::Dump(Stream &s, bool pretty_print) const { bool first = true; s << "{"; if (pretty_print) { s << "\n"; s.IndentMore(); } for (const auto &pair : m_dict) { if (first) first = false; else { s << ","; if (pretty_print) s << "\n"; } if (pretty_print) s.Indent(); s << "\"" << pair.first.AsCString() << "\" : "; pair.second->Dump(s, pretty_print); } if (pretty_print) { s.IndentLess(); s.EOL(); s.Indent(); } s << "}"; } void StructuredData::Null::Dump(Stream &s, bool pretty_print) const { s << "null"; } void StructuredData::Generic::Dump(Stream &s, bool pretty_print) const { s << "0x" << m_object; }