2016-11-17 05:15:24 +08:00
|
|
|
//===---------------------StructuredData.cpp ---------------------*- C++-*-===//
|
2014-06-13 10:37:02 +08:00
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2017-06-27 18:45:31 +08:00
|
|
|
#include "lldb/Utility/StructuredData.h"
|
2017-03-04 09:30:05 +08:00
|
|
|
#include "lldb/Utility/DataBuffer.h"
|
2017-03-23 02:40:07 +08:00
|
|
|
#include "lldb/Utility/FileSpec.h"
|
2015-07-07 07:40:40 +08:00
|
|
|
#include "lldb/Utility/JSON.h"
|
2017-05-12 12:51:55 +08:00
|
|
|
#include "lldb/Utility/Status.h"
|
2017-04-07 05:28:29 +08:00
|
|
|
#include "lldb/Utility/Stream.h" // for Stream
|
2017-02-03 05:39:50 +08:00
|
|
|
#include "lldb/Utility/StreamString.h"
|
2017-04-07 05:28:29 +08:00
|
|
|
#include "llvm/ADT/STLExtras.h" // for make_unique
|
2017-11-17 11:28:58 +08:00
|
|
|
#include "llvm/Support/MemoryBuffer.h"
|
2017-06-27 18:45:31 +08:00
|
|
|
#include <cerrno>
|
|
|
|
#include <cstdlib>
|
2017-04-07 05:28:29 +08:00
|
|
|
#include <inttypes.h>
|
2017-06-27 18:45:31 +08:00
|
|
|
#include <limits> // for numeric_limits
|
2015-03-18 04:04:04 +08:00
|
|
|
|
2014-06-13 10:37:02 +08:00
|
|
|
using namespace lldb_private;
|
|
|
|
|
2015-07-07 07:40:40 +08:00
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// Functions that use a JSONParser to parse JSON into StructuredData
|
|
|
|
//----------------------------------------------------------------------
|
2016-09-07 04:57:50 +08:00
|
|
|
static StructuredData::ObjectSP ParseJSONValue(JSONParser &json_parser);
|
|
|
|
static StructuredData::ObjectSP ParseJSONObject(JSONParser &json_parser);
|
|
|
|
static StructuredData::ObjectSP ParseJSONArray(JSONParser &json_parser);
|
|
|
|
|
2016-09-15 03:07:35 +08:00
|
|
|
StructuredData::ObjectSP
|
2017-05-12 12:51:55 +08:00
|
|
|
StructuredData::ParseJSONFromFile(const FileSpec &input_spec, Status &error) {
|
2016-09-13 07:10:56 +08:00
|
|
|
StructuredData::ObjectSP return_sp;
|
|
|
|
if (!input_spec.Exists()) {
|
2017-06-27 18:45:31 +08:00
|
|
|
error.SetErrorStringWithFormatv("input file {0} does not exist.",
|
|
|
|
input_spec);
|
2016-09-13 07:10:56 +08:00
|
|
|
return return_sp;
|
|
|
|
}
|
|
|
|
|
2017-06-27 18:45:31 +08:00
|
|
|
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());
|
2016-09-13 07:10:56 +08:00
|
|
|
return return_sp;
|
|
|
|
}
|
|
|
|
|
2017-06-27 18:45:31 +08:00
|
|
|
JSONParser json_parser(buffer_or_error.get()->getBuffer());
|
2016-09-13 07:10:56 +08:00
|
|
|
return_sp = ParseJSONValue(json_parser);
|
|
|
|
return return_sp;
|
|
|
|
}
|
|
|
|
|
2016-09-07 04:57:50 +08:00
|
|
|
static StructuredData::ObjectSP ParseJSONObject(JSONParser &json_parser) {
|
|
|
|
// The "JSONParser::Token::ObjectStart" token should have already been
|
2017-04-07 05:28:29 +08:00
|
|
|
// consumed by the time this function is called
|
|
|
|
auto dict_up = llvm::make_unique<StructuredData::Dictionary>();
|
2016-09-07 04:57:50 +08:00
|
|
|
|
|
|
|
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) {
|
2015-07-07 07:40:40 +08:00
|
|
|
StructuredData::ObjectSP value_sp = ParseJSONValue(json_parser);
|
|
|
|
if (value_sp)
|
2016-09-07 04:57:50 +08:00
|
|
|
dict_up->AddItem(key, value_sp);
|
2015-07-07 07:40:40 +08:00
|
|
|
else
|
2016-09-07 04:57:50 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else if (token == JSONParser::Token::ObjectEnd) {
|
|
|
|
return StructuredData::ObjectSP(dict_up.release());
|
|
|
|
} else if (token == JSONParser::Token::Comma) {
|
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
break;
|
2014-06-13 10:37:02 +08:00
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
return StructuredData::ObjectSP();
|
2014-06-13 10:37:02 +08:00
|
|
|
}
|
|
|
|
|
2016-09-07 04:57:50 +08:00
|
|
|
static StructuredData::ObjectSP ParseJSONArray(JSONParser &json_parser) {
|
|
|
|
// The "JSONParser::Token::ObjectStart" token should have already been
|
2018-05-01 00:49:04 +08:00
|
|
|
// consumed by the time this function is called
|
2017-04-07 05:28:29 +08:00
|
|
|
auto array_up = llvm::make_unique<StructuredData::Array>();
|
2016-09-07 04:57:50 +08:00
|
|
|
|
|
|
|
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;
|
2014-06-13 10:37:02 +08:00
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
}
|
|
|
|
return StructuredData::ObjectSP();
|
|
|
|
}
|
2014-06-13 10:37:02 +08:00
|
|
|
|
2016-09-07 04:57:50 +08:00
|
|
|
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: {
|
2017-06-27 18:45:31 +08:00
|
|
|
uint64_t uval;
|
|
|
|
if (llvm::to_integer(value, uval, 0))
|
2017-04-07 05:28:29 +08:00
|
|
|
return std::make_shared<StructuredData::Integer>(uval);
|
2016-09-07 04:57:50 +08:00
|
|
|
} break;
|
|
|
|
|
|
|
|
case JSONParser::Token::Float: {
|
2017-06-27 18:45:31 +08:00
|
|
|
double val;
|
|
|
|
if (llvm::to_float(value, val))
|
2017-04-07 05:28:29 +08:00
|
|
|
return std::make_shared<StructuredData::Float>(val);
|
2016-09-07 04:57:50 +08:00
|
|
|
} break;
|
|
|
|
|
|
|
|
case JSONParser::Token::String:
|
2017-04-07 05:28:29 +08:00
|
|
|
return std::make_shared<StructuredData::String>(value);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
|
|
|
case JSONParser::Token::True:
|
|
|
|
case JSONParser::Token::False:
|
2017-04-07 05:28:29 +08:00
|
|
|
return std::make_shared<StructuredData::Boolean>(token ==
|
|
|
|
JSONParser::Token::True);
|
2016-09-07 04:57:50 +08:00
|
|
|
|
|
|
|
case JSONParser::Token::Null:
|
2017-04-07 05:28:29 +08:00
|
|
|
return std::make_shared<StructuredData::Null>();
|
2016-09-07 04:57:50 +08:00
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return StructuredData::ObjectSP();
|
2015-07-07 07:40:40 +08:00
|
|
|
}
|
2014-06-13 10:37:02 +08:00
|
|
|
|
2016-09-07 04:57:50 +08:00
|
|
|
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;
|
2014-06-13 10:37:02 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
StructuredData::ObjectSP
|
2016-09-07 04:57:50 +08:00
|
|
|
StructuredData::Object::GetObjectForDotSeparatedPath(llvm::StringRef path) {
|
2017-05-29 16:25:46 +08:00
|
|
|
if (this->GetType() == lldb::eStructuredDataTypeDictionary) {
|
2016-09-07 04:57:50 +08:00
|
|
|
std::pair<llvm::StringRef, llvm::StringRef> match = path.split('.');
|
|
|
|
std::string key = match.first.str();
|
2016-11-03 04:34:10 +08:00
|
|
|
ObjectSP value = this->GetAsDictionary()->GetValueForKey(key);
|
2016-09-07 04:57:50 +08:00
|
|
|
if (value.get()) {
|
2018-05-01 00:49:04 +08:00
|
|
|
// Do we have additional words to descend? If not, return the value
|
|
|
|
// we're at right now.
|
2016-09-07 04:57:50 +08:00
|
|
|
if (match.second.empty()) {
|
|
|
|
return value;
|
|
|
|
} else {
|
|
|
|
return value->GetObjectForDotSeparatedPath(match.second);
|
|
|
|
}
|
2014-06-13 10:37:02 +08:00
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
return ObjectSP();
|
|
|
|
}
|
2014-06-13 10:37:02 +08:00
|
|
|
|
2017-05-29 16:25:46 +08:00
|
|
|
if (this->GetType() == lldb::eStructuredDataTypeArray) {
|
2016-09-07 04:57:50 +08:00
|
|
|
std::pair<llvm::StringRef, llvm::StringRef> 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);
|
2014-06-13 10:37:02 +08:00
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
return ObjectSP();
|
|
|
|
}
|
2014-06-13 10:37:02 +08:00
|
|
|
|
2016-09-07 04:57:50 +08:00
|
|
|
return this->shared_from_this();
|
2014-06-13 10:37:02 +08:00
|
|
|
}
|
|
|
|
|
2016-09-07 04:57:50 +08:00
|
|
|
void StructuredData::Object::DumpToStdout(bool pretty_print) const {
|
|
|
|
StreamString stream;
|
|
|
|
Dump(stream, pretty_print);
|
2017-06-27 18:45:31 +08:00
|
|
|
llvm::outs() << stream.GetString();
|
2015-03-18 04:04:04 +08:00
|
|
|
}
|
|
|
|
|
2016-09-07 04:57:50 +08:00
|
|
|
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)
|
2016-07-20 11:49:02 +08:00
|
|
|
s << "\n";
|
|
|
|
}
|
2016-09-07 04:57:50 +08:00
|
|
|
|
2016-07-20 11:49:02 +08:00
|
|
|
if (pretty_print)
|
2016-09-07 04:57:50 +08:00
|
|
|
s.Indent();
|
|
|
|
item_sp->Dump(s, pretty_print);
|
|
|
|
}
|
|
|
|
if (pretty_print) {
|
|
|
|
s.IndentLess();
|
|
|
|
s.EOL();
|
|
|
|
s.Indent();
|
|
|
|
}
|
|
|
|
s << "]";
|
2014-06-13 10:37:02 +08:00
|
|
|
}
|
|
|
|
|
2016-09-07 04:57:50 +08:00
|
|
|
void StructuredData::Integer::Dump(Stream &s, bool pretty_print) const {
|
|
|
|
s.Printf("%" PRIu64, m_value);
|
2014-06-13 10:37:02 +08:00
|
|
|
}
|
|
|
|
|
2016-09-07 04:57:50 +08:00
|
|
|
void StructuredData::Float::Dump(Stream &s, bool pretty_print) const {
|
|
|
|
s.Printf("%lg", m_value);
|
2014-06-13 10:37:02 +08:00
|
|
|
}
|
|
|
|
|
2016-09-07 04:57:50 +08:00
|
|
|
void StructuredData::Boolean::Dump(Stream &s, bool pretty_print) const {
|
|
|
|
if (m_value == true)
|
|
|
|
s.PutCString("true");
|
|
|
|
else
|
|
|
|
s.PutCString("false");
|
2014-06-13 10:37:02 +08:00
|
|
|
}
|
|
|
|
|
2016-09-07 04:57:50 +08:00
|
|
|
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];
|
2016-09-22 23:26:43 +08:00
|
|
|
if (ch == '"' || ch == '\\')
|
2016-09-07 04:57:50 +08:00
|
|
|
quoted.push_back('\\');
|
|
|
|
quoted.push_back(ch);
|
|
|
|
}
|
|
|
|
s.Printf("\"%s\"", quoted.c_str());
|
2014-06-13 10:37:02 +08:00
|
|
|
}
|
|
|
|
|
2016-09-07 04:57:50 +08:00
|
|
|
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)
|
2016-07-22 06:50:01 +08:00
|
|
|
s << "\n";
|
2016-07-20 11:49:02 +08:00
|
|
|
}
|
|
|
|
if (pretty_print)
|
2016-09-07 04:57:50 +08:00
|
|
|
s.Indent();
|
|
|
|
s << "\"" << pair.first.AsCString() << "\" : ";
|
|
|
|
pair.second->Dump(s, pretty_print);
|
|
|
|
}
|
|
|
|
if (pretty_print) {
|
|
|
|
s.IndentLess();
|
|
|
|
s.EOL();
|
|
|
|
s.Indent();
|
|
|
|
}
|
|
|
|
s << "}";
|
2014-06-13 10:37:02 +08:00
|
|
|
}
|
|
|
|
|
2016-09-07 04:57:50 +08:00
|
|
|
void StructuredData::Null::Dump(Stream &s, bool pretty_print) const {
|
|
|
|
s << "null";
|
2014-06-13 10:37:02 +08:00
|
|
|
}
|
2015-03-18 04:04:04 +08:00
|
|
|
|
2016-09-07 04:57:50 +08:00
|
|
|
void StructuredData::Generic::Dump(Stream &s, bool pretty_print) const {
|
|
|
|
s << "0x" << m_object;
|
2015-03-18 04:04:04 +08:00
|
|
|
}
|