
Change over existing code to use this new parser so StructuredData can use the tokenizer to parse JSON instead of doing it manually. This allowed us to easily parse JSON into JSON* objects as well as into StructuredData. llvm-svn: 241522
306 lines
7.7 KiB
C++
306 lines
7.7 KiB
C++
//===---------------------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/Core/StructuredData.h"
|
|
|
|
#include <errno.h>
|
|
#include <stdlib.h>
|
|
#include <inttypes.h>
|
|
|
|
#include "lldb/Core/StreamString.h"
|
|
#include "lldb/Host/StringConvert.h"
|
|
#include "lldb/Utility/JSON.h"
|
|
|
|
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);
|
|
|
|
static StructuredData::ObjectSP
|
|
ParseJSONObject (JSONParser &json_parser)
|
|
{
|
|
// The "JSONParser::Token::ObjectStart" token should have already been consumed
|
|
// by the time this function is called
|
|
std::unique_ptr<StructuredData::Dictionary> dict_up(new StructuredData::Dictionary());
|
|
|
|
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
|
|
std::unique_ptr<StructuredData::Array> array_up(new StructuredData::Array());
|
|
|
|
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:
|
|
{
|
|
bool success = false;
|
|
uint64_t uval = StringConvert::ToUInt64(value.c_str(), 0, 0, &success);
|
|
if (success)
|
|
return StructuredData::ObjectSP(new StructuredData::Integer(uval));
|
|
}
|
|
break;
|
|
|
|
case JSONParser::Token::Float:
|
|
{
|
|
bool success = false;
|
|
double val = StringConvert::ToDouble(value.c_str(), 0.0, &success);
|
|
if (success)
|
|
return StructuredData::ObjectSP(new StructuredData::Float(val));
|
|
}
|
|
break;
|
|
|
|
case JSONParser::Token::String:
|
|
return StructuredData::ObjectSP(new StructuredData::String(value));
|
|
|
|
case JSONParser::Token::True:
|
|
case JSONParser::Token::False:
|
|
return StructuredData::ObjectSP(new StructuredData::Boolean(token == JSONParser::Token::True));
|
|
|
|
case JSONParser::Token::Null:
|
|
return StructuredData::ObjectSP(new StructuredData::Null());
|
|
|
|
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() == Type::eTypeDictionary)
|
|
{
|
|
std::pair<llvm::StringRef, llvm::StringRef> match = path.split('.');
|
|
std::string key = match.first.str();
|
|
ObjectSP value = this->GetAsDictionary()->GetValueForKey (key.c_str());
|
|
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() == Type::eTypeArray)
|
|
{
|
|
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);
|
|
}
|
|
return ObjectSP();
|
|
}
|
|
|
|
return this->shared_from_this();
|
|
}
|
|
|
|
void
|
|
StructuredData::Object::DumpToStdout() const
|
|
{
|
|
StreamString stream;
|
|
Dump(stream);
|
|
printf("%s\n", stream.GetString().c_str());
|
|
}
|
|
|
|
void
|
|
StructuredData::Array::Dump(Stream &s) const
|
|
{
|
|
bool first = true;
|
|
s << "[\n";
|
|
s.IndentMore();
|
|
for (const auto &item_sp : m_items)
|
|
{
|
|
if (first)
|
|
first = false;
|
|
else
|
|
s << ",\n";
|
|
|
|
s.Indent();
|
|
item_sp->Dump(s);
|
|
}
|
|
s.IndentLess();
|
|
s.EOL();
|
|
s.Indent();
|
|
s << "]";
|
|
}
|
|
|
|
void
|
|
StructuredData::Integer::Dump (Stream &s) const
|
|
{
|
|
s.Printf ("%" PRIu64, m_value);
|
|
}
|
|
|
|
|
|
void
|
|
StructuredData::Float::Dump (Stream &s) const
|
|
{
|
|
s.Printf ("%lg", m_value);
|
|
}
|
|
|
|
void
|
|
StructuredData::Boolean::Dump (Stream &s) const
|
|
{
|
|
if (m_value == true)
|
|
s.PutCString ("true");
|
|
else
|
|
s.PutCString ("false");
|
|
}
|
|
|
|
|
|
void
|
|
StructuredData::String::Dump (Stream &s) 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 == '"')
|
|
quoted.push_back ('\\');
|
|
quoted.push_back (ch);
|
|
}
|
|
s.Printf ("\"%s\"", quoted.c_str());
|
|
}
|
|
|
|
void
|
|
StructuredData::Dictionary::Dump (Stream &s) const
|
|
{
|
|
bool first = true;
|
|
s << "{\n";
|
|
s.IndentMore();
|
|
for (const auto &pair : m_dict)
|
|
{
|
|
if (first)
|
|
first = false;
|
|
else
|
|
s << ",\n";
|
|
s.Indent();
|
|
s << "\"" << pair.first.AsCString() << "\" : ";
|
|
pair.second->Dump(s);
|
|
}
|
|
s.IndentLess();
|
|
s.EOL();
|
|
s.Indent();
|
|
s << "}";
|
|
}
|
|
|
|
void
|
|
StructuredData::Null::Dump (Stream &s) const
|
|
{
|
|
s << "null";
|
|
}
|
|
|
|
void
|
|
StructuredData::Generic::Dump(Stream &s) const
|
|
{
|
|
s << "0x" << m_object;
|
|
}
|