287 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			287 lines
		
	
	
		
			8.1 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/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 <cerrno>
 | |
| #include <cstdlib>
 | |
| #include <inttypes.h>
 | |
| #include <limits> // 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<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
 | |
|   auto array_up = llvm::make_unique<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: {
 | |
|     uint64_t uval;
 | |
|     if (llvm::to_integer(value, uval, 0))
 | |
|       return std::make_shared<StructuredData::Integer>(uval);
 | |
|   } break;
 | |
| 
 | |
|   case JSONParser::Token::Float: {
 | |
|     double val;
 | |
|     if (llvm::to_float(value, val))
 | |
|       return std::make_shared<StructuredData::Float>(val);
 | |
|   } break;
 | |
| 
 | |
|   case JSONParser::Token::String:
 | |
|     return std::make_shared<StructuredData::String>(value);
 | |
| 
 | |
|   case JSONParser::Token::True:
 | |
|   case JSONParser::Token::False:
 | |
|     return std::make_shared<StructuredData::Boolean>(token ==
 | |
|                                                      JSONParser::Token::True);
 | |
| 
 | |
|   case JSONParser::Token::Null:
 | |
|     return std::make_shared<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() == lldb::eStructuredDataTypeDictionary) {
 | |
|     std::pair<llvm::StringRef, llvm::StringRef> 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<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(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;
 | |
| }
 |