mirror of
https://github.com/MaskRay/ccls.git
synced 2024-11-25 17:11:59 +00:00
WIP new reflection API to unify serialization
This commit is contained in:
parent
7a160a5269
commit
729264bb34
@ -1,3 +1,4 @@
|
||||
#if false
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
@ -762,7 +763,7 @@ void LanguageServerMain(std::string process_name) {
|
||||
|
||||
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
int mai2525252n(int argc, char** argv) {
|
||||
// We need to write to stdout in binary mode because in Windows, writing
|
||||
// \n will implicitly write \r\n. Language server API will ignore a
|
||||
// \r\r\n split request.
|
||||
@ -819,3 +820,5 @@ int main(int argc, char** argv) {
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif
|
10
indexer.cpp
10
indexer.cpp
@ -76,15 +76,7 @@ IndexedVarDef* IndexedFile::Resolve(VarId id) {
|
||||
}
|
||||
|
||||
std::string IndexedFile::ToString() {
|
||||
rapidjson::StringBuffer output;
|
||||
rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(output);
|
||||
writer.SetFormatOptions(
|
||||
rapidjson::PrettyFormatOptions::kFormatSingleLineArray);
|
||||
writer.SetIndent(' ', 2);
|
||||
|
||||
Serialize(writer, this);
|
||||
|
||||
return output.GetString();
|
||||
return Serialize(*this);
|
||||
}
|
||||
|
||||
IndexedTypeDef::IndexedTypeDef(TypeId id, const std::string& usr) : id(id), def(usr) {
|
||||
|
@ -229,6 +229,8 @@ struct Ref {
|
||||
Id<T> id;
|
||||
Location loc;
|
||||
|
||||
Ref() {} // For serialization.
|
||||
|
||||
Ref(Id<T> id, Location loc) : id(id), loc(loc) {}
|
||||
|
||||
bool operator==(const Ref<T>& other) {
|
||||
@ -323,6 +325,8 @@ struct IndexedTypeDef {
|
||||
|
||||
bool is_bad_def = true;
|
||||
|
||||
IndexedTypeDef() : def("") {} // For serialization
|
||||
|
||||
IndexedTypeDef(TypeId id, const std::string& usr);
|
||||
void AddUsage(Location loc, bool insert_if_not_present = true);
|
||||
|
||||
@ -402,6 +406,8 @@ struct IndexedFuncDef {
|
||||
|
||||
bool is_bad_def = true;
|
||||
|
||||
IndexedFuncDef() : def("") {} // For serialization
|
||||
|
||||
IndexedFuncDef(FuncId id, const std::string& usr) : id(id), def(usr) {
|
||||
assert(usr.size() > 0);
|
||||
}
|
||||
@ -462,6 +468,8 @@ struct IndexedVarDef {
|
||||
|
||||
bool is_bad_def = true;
|
||||
|
||||
IndexedVarDef() : def("") {} // For serialization
|
||||
|
||||
IndexedVarDef(VarId id, const std::string& usr) : id(id), def(usr) {
|
||||
assert(usr.size() > 0);
|
||||
}
|
||||
|
3
ipc.h
3
ipc.h
@ -12,9 +12,6 @@
|
||||
#include "platform.h"
|
||||
#include "serializer.h"
|
||||
|
||||
using Writer = rapidjson::PrettyWriter<rapidjson::StringBuffer>;
|
||||
using Reader = rapidjson::Document;
|
||||
|
||||
// TODO: We need to add support for payloads larger than the maximum shared memory buffer size.
|
||||
|
||||
// Messages are funky objects. They contain potentially variable amounts of
|
||||
|
@ -1,145 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#if false
|
||||
|
||||
#include <iostream>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
#include <rapidjson/writer.h>
|
||||
#include "optional.h"
|
||||
#include "serializer.h"
|
||||
|
||||
using std::experimental::optional;
|
||||
using std::experimental::nullopt;
|
||||
|
||||
namespace language_server_api {
|
||||
|
||||
// TODO: Cleanup serializer.h/cc as well.
|
||||
|
||||
#define SERIALIZE_MEMBER(name) \
|
||||
SerializeMember(writer, #name, value.name)
|
||||
#define SERIALIZE_MEMBER2(name, value) \
|
||||
SerializeMember(writer, #name, value)
|
||||
#define DESERIALIZE_MEMBER(name) \
|
||||
DeserializeMember(reader, #name, value.name)
|
||||
|
||||
using Reader = rapidjson::GenericValue<rapidjson::UTF8<>>;
|
||||
using Writer = rapidjson::Writer<rapidjson::StringBuffer>;
|
||||
|
||||
// Special templates used by (DE)SERIALIZE_MEMBER macros.
|
||||
template<typename T>
|
||||
void SerializeMember(Writer& writer, const char* name, const T& value) {
|
||||
writer.Key(name);
|
||||
Serialize(writer, value);
|
||||
}
|
||||
template<typename T>
|
||||
void SerializeMember(Writer& writer, const char* name, const optional<T>& value) {
|
||||
if (value.has_value()) {
|
||||
writer.Key(name);
|
||||
Serialize(writer, value.value());
|
||||
}
|
||||
}
|
||||
template<typename T>
|
||||
void DeserializeMember(const Reader& reader, const char* name, T& value) {
|
||||
auto it = reader.FindMember(name);
|
||||
if (it != reader.MemberEnd())
|
||||
Deserialize(it->value, value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Start normal serialization routines.
|
||||
void Serialize(Writer& writer, int value) {
|
||||
writer.Int(value);
|
||||
}
|
||||
|
||||
void Serialize(Writer& writer, const std::string& value) {
|
||||
writer.String(value.c_str(), value.size());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Serialize(Writer& writer, const std::vector<T>& values) {
|
||||
writer.StartArray();
|
||||
for (const auto& value : values)
|
||||
Serialize(writer, value);
|
||||
writer.EndArray();
|
||||
}
|
||||
|
||||
|
||||
void Deserialize(const Reader& reader, int& value) {
|
||||
value = reader.GetInt();
|
||||
}
|
||||
|
||||
void Deserialize(const Reader& reader, bool& value) {
|
||||
value = reader.GetBool();
|
||||
}
|
||||
|
||||
void Deserialize(const Reader& reader, std::string& value) {
|
||||
value = std::string(reader.GetString());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Deserialize(const Reader& reader, std::vector<T>& value) {
|
||||
for (const auto& entry : reader.GetArray()) {
|
||||
T entry_value;
|
||||
Deserialize(entry, entry_value);
|
||||
value.push_back(entry_value);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Deserialize(const Reader& reader, optional<T>& value) {
|
||||
T real_value;
|
||||
Deserialize(reader, real_value);
|
||||
value = real_value;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#if false
|
||||
void Deserialize(const Reader& reader, DocumentUri& output) {
|
||||
//static var driveLetterPathRe = ~/^\/[a-zA-Z]:/;
|
||||
//static var uriRe = ~/^(([^:\/?#]+?):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/;
|
||||
|
||||
/** ported from VSCode sources **/
|
||||
public static function toFsPath(uri:DocumentUri) :FsPath{
|
||||
if (!uriRe.match(uri.toString()) || uriRe.matched(2) != "file")
|
||||
throw 'Invalid uri: $uri';
|
||||
|
||||
var path = uriRe.matched(5).urlDecode();
|
||||
if (driveLetterPathRe.match(path))
|
||||
return new FsPath(path.charAt(1).toLowerCase() + path.substr(2));
|
||||
else
|
||||
return new FsPath(path);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
@ -156,11 +30,11 @@ namespace language_server_api {
|
||||
|
||||
void Serialize(Writer& writer, const RequestId& value) {
|
||||
if (value.id0) {
|
||||
Serialize(writer, value.id0.value());
|
||||
::Serialize(writer, value.id0.value());
|
||||
}
|
||||
else {
|
||||
assert(value.id1.has_value());
|
||||
Serialize(writer, value.id1.value());
|
||||
::Serialize(writer, value.id1.value());
|
||||
}
|
||||
}
|
||||
|
||||
@ -242,7 +116,7 @@ namespace language_server_api {
|
||||
auto& value = *this;
|
||||
|
||||
writer.StartObject();
|
||||
SERIALIZE_MEMBER2(code, static_cast<int>(code));
|
||||
SERIALIZE_MEMBER2("code", static_cast<int>(code));
|
||||
SERIALIZE_MEMBER(message);
|
||||
if (data) {
|
||||
writer.Key("data");
|
||||
@ -393,10 +267,10 @@ namespace language_server_api {
|
||||
|
||||
optional<RequestId> id;
|
||||
if (reader.FindMember("id") != reader.MemberEnd())
|
||||
Deserialize(reader["id"], id);
|
||||
::Deserialize(reader["id"], id);
|
||||
|
||||
std::string method;
|
||||
Deserialize(reader["method"], method);
|
||||
::Deserialize(reader["method"], method);
|
||||
|
||||
if (allocators.find(method) == allocators.end()) {
|
||||
std::cerr << "Unable to find registered handler for method \"" << method << "\"" << std::endl;
|
||||
@ -537,11 +411,11 @@ namespace language_server_api {
|
||||
};
|
||||
|
||||
void Serialize(Writer& writer, const DocumentUri& value) {
|
||||
Serialize(writer, value.raw_uri);
|
||||
::Serialize(writer, value.raw_uri);
|
||||
}
|
||||
|
||||
void Deserialize(const Reader& reader, DocumentUri& value) {
|
||||
Deserialize(reader, value.raw_uri);
|
||||
::Deserialize(reader, value.raw_uri);
|
||||
}
|
||||
|
||||
|
||||
@ -1380,7 +1254,7 @@ namespace language_server_api {
|
||||
|
||||
// OutResponseMessage:
|
||||
void WriteResult(Writer& writer) override {
|
||||
Serialize(writer, result);
|
||||
::Serialize(writer, result);
|
||||
}
|
||||
};
|
||||
|
||||
@ -1417,7 +1291,7 @@ namespace language_server_api {
|
||||
|
||||
// OutResponseMessage:
|
||||
void WriteResult(Writer& writer) override {
|
||||
Serialize(writer, result);
|
||||
::Serialize(writer, result);
|
||||
}
|
||||
};
|
||||
|
||||
@ -1507,4 +1381,5 @@ namespace language_server_api {
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
#endif
|
1
query.h
1
query.h
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "indexer.h"
|
||||
#include "serializer.h"
|
||||
|
||||
// NOTE: If updating this enum, make sure to also update the parser and the
|
||||
// help text.
|
||||
|
369
serializer.cc
369
serializer.cc
@ -5,246 +5,209 @@
|
||||
|
||||
|
||||
|
||||
void Serialize(Writer& writer, const char* key, Location location) {
|
||||
if (key) writer.Key(key);
|
||||
std::string s = location.ToString();
|
||||
writer.String(s.c_str());
|
||||
|
||||
// int
|
||||
void Reflect(Reader& visitor, int& value) {
|
||||
value = visitor.GetInt();
|
||||
}
|
||||
void Reflect(Writer& visitor, int& value) {
|
||||
visitor.Int(value);
|
||||
}
|
||||
|
||||
void Serialize(Writer& writer, const char* key, optional<Location> location) {
|
||||
if (location)
|
||||
Serialize(writer, key, location.value());
|
||||
|
||||
// bool
|
||||
void Reflect(Reader& visitor, bool& value) {
|
||||
value = visitor.GetBool();
|
||||
}
|
||||
void Reflect(Writer& visitor, bool& value) {
|
||||
visitor.Bool(value);
|
||||
}
|
||||
|
||||
void Serialize(Writer& writer, const char* key, const std::vector<Location>& locs) {
|
||||
if (locs.size() == 0)
|
||||
return;
|
||||
|
||||
if (key) writer.Key(key);
|
||||
writer.StartArray();
|
||||
for (const Location& loc : locs)
|
||||
Serialize(writer, nullptr, loc);
|
||||
writer.EndArray();
|
||||
// std::string
|
||||
void Reflect(Reader& visitor, std::string& value) {
|
||||
value = visitor.GetString();
|
||||
}
|
||||
void Reflect(Writer& visitor, std::string& value) {
|
||||
visitor.String(value.c_str(), value.size());
|
||||
}
|
||||
|
||||
void Serialize(Writer& writer, const char* key, const std::string& value) {
|
||||
if (value.size() == 0)
|
||||
return;
|
||||
|
||||
if (key) writer.Key(key);
|
||||
writer.String(value.c_str());
|
||||
// Location
|
||||
void Reflect(Reader& visitor, Location& value) {
|
||||
value = Location(visitor.GetString());
|
||||
}
|
||||
void Reflect(Writer& visitor, Location& value) {
|
||||
std::string output = value.ToString();
|
||||
visitor.String(output.c_str(), output.size());
|
||||
}
|
||||
|
||||
void Serialize(Writer& writer, const char* key, const std::vector<std::string>& value) {
|
||||
if (value.size() == 0)
|
||||
return;
|
||||
|
||||
if (key) writer.Key(key);
|
||||
|
||||
writer.StartArray();
|
||||
for (const std::string& s : value)
|
||||
writer.String(s.c_str());
|
||||
writer.EndArray();
|
||||
// Id<T>
|
||||
template<typename T>
|
||||
void Reflect(Reader& visitor, Id<T>& id) {
|
||||
id.id = visitor.GetUint64();
|
||||
}
|
||||
template<typename T>
|
||||
void Reflect(Writer& visitor, Id<T>& value) {
|
||||
visitor.Uint64(value.id);
|
||||
}
|
||||
|
||||
void Serialize(Writer& writer, const char* key, uint64_t value) {
|
||||
if (key) writer.Key(key);
|
||||
writer.Uint64(value);
|
||||
|
||||
// Ref<IndexedFuncDef>
|
||||
void Reflect(Reader& visitor, Ref<IndexedFuncDef>& value) {
|
||||
const char* str_value = visitor.GetString();
|
||||
uint64_t id = atoi(str_value);
|
||||
const char* loc_string = strchr(str_value, '@') + 1;
|
||||
|
||||
value.id = Id<IndexedFuncDef>(id);
|
||||
value.loc = Location(loc_string);
|
||||
}
|
||||
void Reflect(Writer& visitor, Ref<IndexedFuncDef>& value) {
|
||||
std::string s = std::to_string(value.id.id) + "@" + value.loc.ToString();
|
||||
visitor.String(s.c_str());
|
||||
}
|
||||
|
||||
void Serialize(Writer& writer, IndexedFile* file) {
|
||||
auto it = file->id_cache.usr_to_type_id.find("");
|
||||
if (it != file->id_cache.usr_to_type_id.end()) {
|
||||
file->Resolve(it->second)->def.short_name = "<fundamental>";
|
||||
assert(file->Resolve(it->second)->uses.size() == 0);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// IndexedTypeDef
|
||||
bool ReflectMemberStart(Reader& reader, IndexedTypeDef& value) {
|
||||
value.is_bad_def = false;
|
||||
return true;
|
||||
}
|
||||
bool ReflectMemberStart(Writer& writer, IndexedTypeDef& value) {
|
||||
if (value.is_bad_def)
|
||||
return false;
|
||||
DefaultReflectMemberStart(writer);
|
||||
return true;
|
||||
}
|
||||
template<typename TVisitor>
|
||||
void Reflect(TVisitor& visitor, IndexedTypeDef& value) {
|
||||
REFLECT_MEMBER_START();
|
||||
REFLECT_MEMBER2("id", value.id);
|
||||
REFLECT_MEMBER2("usr", value.def.usr);
|
||||
REFLECT_MEMBER2("short_name", value.def.short_name);
|
||||
REFLECT_MEMBER2("qualified_name", value.def.qualified_name);
|
||||
REFLECT_MEMBER2("definition", value.def.definition);
|
||||
REFLECT_MEMBER2("alias_of", value.def.alias_of);
|
||||
REFLECT_MEMBER2("parents", value.def.parents);
|
||||
REFLECT_MEMBER2("derived", value.derived);
|
||||
REFLECT_MEMBER2("types", value.def.types);
|
||||
REFLECT_MEMBER2("funcs", value.def.funcs);
|
||||
REFLECT_MEMBER2("vars", value.def.vars);
|
||||
REFLECT_MEMBER2("uses", value.uses);
|
||||
REFLECT_MEMBER_END();
|
||||
}
|
||||
|
||||
|
||||
// IndexedFuncDef
|
||||
bool ReflectMemberStart(Reader& reader, IndexedFuncDef& value) {
|
||||
value.is_bad_def = false;
|
||||
return true;
|
||||
}
|
||||
bool ReflectMemberStart(Writer& writer, IndexedFuncDef& value) {
|
||||
if (value.is_bad_def)
|
||||
return false;
|
||||
DefaultReflectMemberStart(writer);
|
||||
return true;
|
||||
}
|
||||
template<typename TVisitor>
|
||||
void Reflect(TVisitor& visitor, IndexedFuncDef& value) {
|
||||
REFLECT_MEMBER_START();
|
||||
REFLECT_MEMBER2("id", value.id);
|
||||
REFLECT_MEMBER2("usr", value.def.usr);
|
||||
REFLECT_MEMBER2("short_name", value.def.short_name);
|
||||
REFLECT_MEMBER2("qualified_name", value.def.qualified_name);
|
||||
REFLECT_MEMBER2("declarations", value.declarations);
|
||||
REFLECT_MEMBER2("definition", value.def.definition);
|
||||
REFLECT_MEMBER2("declaring_type", value.def.declaring_type);
|
||||
REFLECT_MEMBER2("base", value.def.base);
|
||||
REFLECT_MEMBER2("derived", value.derived);
|
||||
REFLECT_MEMBER2("locals", value.def.locals);
|
||||
REFLECT_MEMBER2("callers", value.callers);
|
||||
REFLECT_MEMBER2("callees", value.def.callees);
|
||||
REFLECT_MEMBER2("uses", value.uses);
|
||||
REFLECT_MEMBER_END();
|
||||
}
|
||||
|
||||
|
||||
// IndexedVarDef
|
||||
bool ReflectMemberStart(Reader& reader, IndexedVarDef& value) {
|
||||
value.is_bad_def = false;
|
||||
return true;
|
||||
}
|
||||
bool ReflectMemberStart(Writer& writer, IndexedVarDef& value) {
|
||||
if (value.is_bad_def)
|
||||
return false;
|
||||
DefaultReflectMemberStart(writer);
|
||||
return true;
|
||||
}
|
||||
template<typename TVisitor>
|
||||
void Reflect(TVisitor& visitor, IndexedVarDef& value) {
|
||||
REFLECT_MEMBER_START();
|
||||
REFLECT_MEMBER2("id", value.id);
|
||||
REFLECT_MEMBER2("usr", value.def.usr);
|
||||
REFLECT_MEMBER2("short_name", value.def.short_name);
|
||||
REFLECT_MEMBER2("qualified_name", value.def.qualified_name);
|
||||
REFLECT_MEMBER2("declaration", value.def.declaration);
|
||||
REFLECT_MEMBER2("definition", value.def.definition);
|
||||
REFLECT_MEMBER2("variable_type", value.def.variable_type);
|
||||
REFLECT_MEMBER2("declaring_type", value.def.declaring_type);
|
||||
REFLECT_MEMBER2("uses", value.uses);
|
||||
REFLECT_MEMBER_END();
|
||||
}
|
||||
|
||||
|
||||
// IndexedFile
|
||||
bool ReflectMemberStart(Writer& visitor, IndexedFile& value) {
|
||||
auto it = value.id_cache.usr_to_type_id.find("");
|
||||
if (it != value.id_cache.usr_to_type_id.end()) {
|
||||
value.Resolve(it->second)->def.short_name = "<fundamental>";
|
||||
assert(value.Resolve(it->second)->uses.size() == 0);
|
||||
}
|
||||
|
||||
#define SERIALIZE(json_name, member_name) Serialize(writer, json_name, def.member_name)
|
||||
|
||||
writer.StartObject();
|
||||
|
||||
// Types
|
||||
writer.Key("types");
|
||||
writer.StartArray();
|
||||
for (IndexedTypeDef& def : file->types) {
|
||||
if (def.is_bad_def)
|
||||
continue;
|
||||
|
||||
writer.StartObject();
|
||||
SERIALIZE("id", id);
|
||||
SERIALIZE("usr", def.usr);
|
||||
SERIALIZE("short_name", def.short_name);
|
||||
SERIALIZE("qualified_name", def.qualified_name);
|
||||
SERIALIZE("definition", def.definition);
|
||||
SERIALIZE("alias_of", def.alias_of);
|
||||
SERIALIZE("parents", def.parents);
|
||||
SERIALIZE("derived", derived);
|
||||
SERIALIZE("types", def.types);
|
||||
SERIALIZE("funcs", def.funcs);
|
||||
SERIALIZE("vars", def.vars);
|
||||
SERIALIZE("uses", uses);
|
||||
writer.EndObject();
|
||||
}
|
||||
writer.EndArray();
|
||||
|
||||
// Functions
|
||||
writer.Key("functions");
|
||||
writer.StartArray();
|
||||
for (IndexedFuncDef& def : file->funcs) {
|
||||
if (def.is_bad_def)
|
||||
continue;
|
||||
|
||||
writer.StartObject();
|
||||
SERIALIZE("id", id);
|
||||
SERIALIZE("usr", def.usr);
|
||||
SERIALIZE("short_name", def.short_name);
|
||||
SERIALIZE("qualified_name", def.qualified_name);
|
||||
SERIALIZE("declarations", declarations);
|
||||
SERIALIZE("definition", def.definition);
|
||||
SERIALIZE("declaring_type", def.declaring_type);
|
||||
SERIALIZE("base", def.base);
|
||||
SERIALIZE("derived", derived);
|
||||
SERIALIZE("locals", def.locals);
|
||||
SERIALIZE("callers", callers);
|
||||
SERIALIZE("callees", def.callees);
|
||||
SERIALIZE("uses", uses);
|
||||
writer.EndObject();
|
||||
}
|
||||
writer.EndArray();
|
||||
|
||||
// Variables
|
||||
writer.Key("variables");
|
||||
writer.StartArray();
|
||||
for (IndexedVarDef& def : file->vars) {
|
||||
if (def.is_bad_def)
|
||||
continue;
|
||||
|
||||
writer.StartObject();
|
||||
SERIALIZE("id", id);
|
||||
SERIALIZE("usr", def.usr);
|
||||
SERIALIZE("short_name", def.short_name);
|
||||
SERIALIZE("qualified_name", def.qualified_name);
|
||||
SERIALIZE("declaration", def.declaration);
|
||||
SERIALIZE("definition", def.definition);
|
||||
SERIALIZE("variable_type", def.variable_type);
|
||||
SERIALIZE("declaring_type", def.declaring_type);
|
||||
SERIALIZE("uses", uses);
|
||||
writer.EndObject();
|
||||
}
|
||||
writer.EndArray();
|
||||
|
||||
writer.EndObject();
|
||||
#undef WRITE
|
||||
DefaultReflectMemberStart(visitor);
|
||||
return true;
|
||||
}
|
||||
template<typename TVisitor>
|
||||
void Reflect(TVisitor& visitor, IndexedFile& value) {
|
||||
REFLECT_MEMBER_START();
|
||||
REFLECT_MEMBER2("types", value.types);
|
||||
REFLECT_MEMBER2("functions", value.funcs);
|
||||
REFLECT_MEMBER2("variables", value.vars);
|
||||
REFLECT_MEMBER_END();
|
||||
}
|
||||
|
||||
void Deserialize(const rapidjson::GenericValue<rapidjson::UTF8<>>& document, const char* name, std::string& output) {
|
||||
auto it = document.FindMember(name);
|
||||
if (it != document.MemberEnd())
|
||||
output = it->value.GetString();
|
||||
}
|
||||
|
||||
void Deserialize(const rapidjson::GenericValue<rapidjson::UTF8<>>& document, const char* name, std::vector<std::string>& output) {
|
||||
auto it = document.FindMember(name);
|
||||
if (it != document.MemberEnd()) {
|
||||
for (auto& entry : it->value.GetArray())
|
||||
output.push_back(entry.GetString());
|
||||
}
|
||||
}
|
||||
|
||||
void Deserialize(const rapidjson::GenericValue<rapidjson::UTF8<>>& document, const char* name, optional<Location>& output) {
|
||||
auto it = document.FindMember(name);
|
||||
if (it != document.MemberEnd())
|
||||
output = Location(it->value.GetString()); // TODO: Location parsing not implemented in Location type.
|
||||
}
|
||||
|
||||
void Deserialize(const rapidjson::GenericValue<rapidjson::UTF8<>>& document, const char* name, std::vector<Location>& output) {
|
||||
auto it = document.FindMember(name);
|
||||
if (it != document.MemberEnd()) {
|
||||
for (auto& array_value : it->value.GetArray())
|
||||
output.push_back(Location(array_value.GetString()));
|
||||
}
|
||||
}
|
||||
|
||||
void Deserialize(const Reader& reader, IndexedFile* file) {
|
||||
#define DESERIALIZE(json_name, member_name) Deserialize(entry, json_name, def.member_name)
|
||||
|
||||
const auto& types = reader["types"].GetArray();
|
||||
for (const auto& entry : types) {
|
||||
TypeId id(entry["id"].GetInt64());
|
||||
std::string usr = entry["usr"].GetString();
|
||||
|
||||
IndexedTypeDef def(id, usr);
|
||||
def.is_bad_def = false;
|
||||
DESERIALIZE("short_name", def.short_name);
|
||||
DESERIALIZE("qualified_name", def.qualified_name);
|
||||
DESERIALIZE("definition", def.definition);
|
||||
DESERIALIZE("alias_of", def.alias_of);
|
||||
DESERIALIZE("parents", def.parents);
|
||||
DESERIALIZE("derived", derived);
|
||||
DESERIALIZE("types", def.types);
|
||||
DESERIALIZE("funcs", def.funcs);
|
||||
DESERIALIZE("vars", def.vars);
|
||||
DESERIALIZE("uses", uses);
|
||||
file->types.push_back(def);
|
||||
}
|
||||
|
||||
const auto& functions = reader["functions"].GetArray();
|
||||
for (const auto& entry : functions) {
|
||||
FuncId id(entry["id"].GetInt64());
|
||||
std::string usr = entry["usr"].GetString();
|
||||
|
||||
IndexedFuncDef def(id, usr);
|
||||
def.is_bad_def = false;
|
||||
DESERIALIZE("short_name", def.short_name);
|
||||
DESERIALIZE("qualified_name", def.qualified_name);
|
||||
DESERIALIZE("declarations", declarations);
|
||||
DESERIALIZE("definition", def.definition);
|
||||
DESERIALIZE("declaring_type", def.declaring_type);
|
||||
DESERIALIZE("base", def.base);
|
||||
DESERIALIZE("derived", derived);
|
||||
DESERIALIZE("locals", def.locals);
|
||||
DESERIALIZE("callers", callers);
|
||||
DESERIALIZE("callees", def.callees);
|
||||
DESERIALIZE("uses", uses);
|
||||
file->funcs.push_back(def);
|
||||
}
|
||||
|
||||
const auto& vars = reader["variables"].GetArray();
|
||||
for (const auto& entry : vars) {
|
||||
VarId id(entry["id"].GetInt64());
|
||||
std::string usr = entry["usr"].GetString();
|
||||
|
||||
IndexedVarDef def(id, usr);
|
||||
def.is_bad_def = false;
|
||||
DESERIALIZE("short_name", def.short_name);
|
||||
DESERIALIZE("qualified_name", def.qualified_name);
|
||||
DESERIALIZE("declaration", def.declaration);
|
||||
DESERIALIZE("definition", def.definition);
|
||||
DESERIALIZE("variable_type", def.variable_type);
|
||||
DESERIALIZE("declaring_type", def.declaring_type);
|
||||
DESERIALIZE("uses", uses);
|
||||
file->vars.push_back(def);
|
||||
}
|
||||
#undef DESERIALIZE
|
||||
}
|
||||
|
||||
std::string Serialize(IndexedFile* file) {
|
||||
std::string Serialize(IndexedFile& file) {
|
||||
rapidjson::StringBuffer output;
|
||||
//rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(output);
|
||||
Writer writer(output);
|
||||
writer.SetFormatOptions(
|
||||
rapidjson::PrettyFormatOptions::kFormatSingleLineArray);
|
||||
writer.SetIndent(' ', 2);
|
||||
|
||||
Serialize(writer, file);
|
||||
Reflect(writer, file);
|
||||
|
||||
return output.GetString();
|
||||
}
|
||||
|
||||
IndexedFile Deserialize(std::string path, std::string serialized) {
|
||||
rapidjson::Document document;
|
||||
document.Parse(serialized.c_str());
|
||||
rapidjson::Document reader;
|
||||
reader.Parse(serialized.c_str());
|
||||
|
||||
IndexedFile file(path);
|
||||
Deserialize(document, &file);
|
||||
Reflect(reader, file);
|
||||
|
||||
return file;
|
||||
}
|
||||
|
278
serializer.h
278
serializer.h
@ -1,41 +1,174 @@
|
||||
#pragma once
|
||||
|
||||
#include <rapidjson/document.h>
|
||||
#include <rapidjson/prettywriter.h>
|
||||
|
||||
#include "indexer.h"
|
||||
|
||||
struct IndexedFile;
|
||||
using Reader = rapidjson::GenericValue<rapidjson::UTF8<>>;
|
||||
using Writer = rapidjson::PrettyWriter<rapidjson::StringBuffer>;
|
||||
using Reader = rapidjson::Document;
|
||||
struct IndexedFile;
|
||||
|
||||
|
||||
#define REFLECT_MEMBER_START() \
|
||||
if (!ReflectMemberStart(visitor, value)) return
|
||||
#define REFLECT_MEMBER_START1(value) \
|
||||
if (!ReflectMemberStart(visitor, value)) return
|
||||
#define REFLECT_MEMBER_END() \
|
||||
ReflectMemberEnd(visitor, value);
|
||||
#define REFLECT_MEMBER_END1(value) \
|
||||
ReflectMemberEnd(visitor, value);
|
||||
#define REFLECT_MEMBER(name) \
|
||||
ReflectMember(visitor, #name, value.name)
|
||||
#define REFLECT_MEMBER2(name, value) \
|
||||
ReflectMember(visitor, name, value)
|
||||
|
||||
|
||||
// API:
|
||||
/*
|
||||
template<typename TVisitor, typename T>
|
||||
void Reflect(TVisitor& visitor, T& value) {
|
||||
static_assert(false, "Missing implementation");
|
||||
}
|
||||
template<typename TVisitor>
|
||||
void DefaultReflectMemberStart(TVisitor& visitor) {
|
||||
static_assert(false, "Missing implementation");
|
||||
}
|
||||
template<typename TVisitor, typename T>
|
||||
bool ReflectMemberStart(TVisitor& visitor, T& value) {
|
||||
static_assert(false, "Missing implementation");
|
||||
return true;
|
||||
}
|
||||
template<typename TVisitor, typename T>
|
||||
void ReflectMemberEnd(TVisitor& visitor, T& value) {
|
||||
static_assert(false, "Missing implementation");
|
||||
}
|
||||
*/
|
||||
|
||||
// Writer:
|
||||
template<typename T>
|
||||
void Reflect(Writer& visitor, std::vector<T>& values) {
|
||||
visitor.StartArray();
|
||||
for (auto& value : values)
|
||||
Reflect(visitor, value);
|
||||
visitor.EndArray();
|
||||
}
|
||||
template<typename T>
|
||||
void Reflect(Writer& visitor, optional<T> value) {
|
||||
if (value)
|
||||
Reflect(visitor, value.value());
|
||||
}
|
||||
inline void DefaultReflectMemberStart(Writer& visitor) {
|
||||
visitor.StartObject();
|
||||
}
|
||||
template<typename T>
|
||||
bool ReflectMemberStart(Writer& visitor, T& value) {
|
||||
visitor.StartObject();
|
||||
return true;
|
||||
}
|
||||
template<typename T>
|
||||
void ReflectMemberEnd(Writer& visitor, T& value) {
|
||||
visitor.EndObject();
|
||||
}
|
||||
template<typename T>
|
||||
void ReflectMember(Writer& visitor, const char* name, T& value) {
|
||||
visitor.Key(name);
|
||||
Reflect(visitor, value);
|
||||
}
|
||||
template<typename T>
|
||||
void ReflectMember(Writer& visitor, const char* name, std::vector<T>& values) {
|
||||
if (values.empty())
|
||||
return;
|
||||
visitor.Key(name);
|
||||
visitor.StartArray();
|
||||
for (auto& value : values)
|
||||
Reflect(visitor, value);
|
||||
visitor.EndArray();
|
||||
}
|
||||
template<typename T>
|
||||
void ReflectMember(Writer& visitor, const char* name, optional<T>& value) {
|
||||
if (!value)
|
||||
return;
|
||||
visitor.Key(name);
|
||||
Reflect(visitor, value);
|
||||
}
|
||||
|
||||
// Reader:
|
||||
template<typename T>
|
||||
void Reflect(Reader& visitor, std::vector<T>& values) {
|
||||
for (auto& entry : visitor.GetArray()) {
|
||||
T entry_value;
|
||||
Reflect(entry, entry_value);
|
||||
values.push_back(entry_value);
|
||||
}
|
||||
}
|
||||
template<typename T>
|
||||
void Reflect(Reader& visitor, optional<T> value) {
|
||||
T real_value;
|
||||
Reflect(visitor, real_value);
|
||||
value = real_value;
|
||||
}
|
||||
inline void DefaultReflectMemberStart(Reader& visitor) {}
|
||||
template<typename T>
|
||||
bool ReflectMemberStart(Reader& visitor, T& value) {
|
||||
return true;
|
||||
}
|
||||
template<typename T>
|
||||
void ReflectMemberEnd(Reader& visitor, T& value) {}
|
||||
template<typename T>
|
||||
void ReflectMember(Reader& visitor, const char* name, T& value) {
|
||||
auto it = visitor.FindMember(name);
|
||||
if (it != visitor.MemberEnd()) {
|
||||
Reader& child_visitor = it->value;
|
||||
Reflect(child_visitor, value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#if false
|
||||
|
||||
void Serialize(Writer& writer, int value);
|
||||
void Serialize(Writer& writer, const std::string& value);
|
||||
void Serialize(Writer& writer, Location location);
|
||||
void Serialize(Writer& writer, uint64_t value);
|
||||
void Serialize(Writer& writer, IndexedFile& file);
|
||||
|
||||
template<typename T>
|
||||
void Serialize(Writer& writer, const char* key, Id<T> id) {
|
||||
if (key) writer.Key(key);
|
||||
void Serialize(Writer& writer, Id<T> id) {
|
||||
writer.Uint64(id.id);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Serialize(Writer& writer, const char* key, optional<Id<T>> id) {
|
||||
if (id) {
|
||||
Serialize(writer, key, id.value());
|
||||
}
|
||||
void Serialize(Writer& writer, optional<T> value) {
|
||||
if (value)
|
||||
Serialize(writer, value.value());
|
||||
else
|
||||
writer.Null();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Serialize(Writer& writer, const char* key, const std::vector<Id<T>>& ids) {
|
||||
if (ids.size() == 0)
|
||||
return;
|
||||
|
||||
if (key) writer.Key(key);
|
||||
void Serialize(Writer& writer, const std::vector<T>& values) {
|
||||
writer.StartArray();
|
||||
for (Id<T> id : ids)
|
||||
Serialize(writer, nullptr, id);
|
||||
for (const T& value : values)
|
||||
Serialize(writer, value);
|
||||
writer.EndArray();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Serialize(Writer& writer, const char* key, Ref<T> ref) {
|
||||
if (key) writer.Key(key);
|
||||
void Serialize(Writer& writer, Ref<T> ref) {
|
||||
std::string s = std::to_string(ref.id.id) + "@" + ref.loc.ToString();
|
||||
writer.String(s.c_str());
|
||||
}
|
||||
@ -52,49 +185,96 @@ void Serialize(Writer& writer, const char* key, const std::vector<Ref<T>>& refs)
|
||||
writer.EndArray();
|
||||
}
|
||||
|
||||
void Serialize(Writer& writer, const char* key, Location location);
|
||||
void Serialize(Writer& writer, const char* key, optional<Location> location);
|
||||
void Serialize(Writer& writer, const char* key, const std::vector<Location>& locs);
|
||||
void Serialize(Writer& writer, const char* key, const std::string& value);
|
||||
void Serialize(Writer& writer, const char* key, const std::vector<std::string>& value);
|
||||
void Serialize(Writer& writer, const char* key, uint64_t value);
|
||||
void Serialize(Writer& writer, IndexedFile* file);
|
||||
|
||||
|
||||
|
||||
|
||||
#define SERIALIZE_MEMBER(name) \
|
||||
SerializeMember(writer, #name, value.name)
|
||||
#define SERIALIZE_MEMBER2(name, value) \
|
||||
SerializeMember(writer, name, value)
|
||||
#define DESERIALIZE_MEMBER(name) \
|
||||
DeserializeMember(reader, #name, value.name)
|
||||
#define DESERIALIZE_MEMBER2(name, value) \
|
||||
DeserializeMember(reader, name, value)
|
||||
|
||||
// Special templates used by (DE)SERIALIZE_MEMBER macros.
|
||||
template<typename T>
|
||||
void SerializeMember(Writer& writer, const char* name, const T& value) {
|
||||
writer.Key(name);
|
||||
Serialize(writer, value);
|
||||
}
|
||||
template<typename T>
|
||||
void SerializeMember(Writer& writer, const char* name, const std::vector<T>& value) {
|
||||
if (value.empty())
|
||||
return;
|
||||
writer.Key(name);
|
||||
Serialize(writer, value);
|
||||
}
|
||||
template<typename T>
|
||||
void SerializeMember(Writer& writer, const char* name, const optional<T>& value) {
|
||||
if (!value)
|
||||
return;
|
||||
writer.Key(name);
|
||||
Serialize(writer, value.value());
|
||||
}
|
||||
|
||||
void SerializeMember(Writer& writer, const char* name, const std::string& value);
|
||||
|
||||
template<typename T>
|
||||
void DeserializeMember(const Reader& reader, const char* name, T& value) {
|
||||
auto it = reader.FindMember(name);
|
||||
if (it != reader.MemberEnd())
|
||||
Deserialize(it->value, value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename T>
|
||||
void Deserialize(const rapidjson::GenericValue<rapidjson::UTF8<>>& document, const char* name, optional<Id<T>>& output) {
|
||||
auto it = document.FindMember(name);
|
||||
if (it != document.MemberEnd())
|
||||
output = Id<T>(it->value.GetUint64());
|
||||
void Deserialize(const Reader& reader, Id<T>& output) {
|
||||
output = Id<T>(reader.GetUint64());
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Deserialize(const rapidjson::GenericValue<rapidjson::UTF8<>>& document, const char* name, std::vector<Id<T>>& output) {
|
||||
auto it = document.FindMember(name);
|
||||
if (it != document.MemberEnd()) {
|
||||
for (auto& array_value : it->value.GetArray())
|
||||
output.push_back(Id<T>(array_value.GetUint64()));
|
||||
void Deserialize(const Reader& reader, Ref<T>& output) {
|
||||
const char* str_value = reader.GetString();
|
||||
uint64_t id = atoi(str_value);
|
||||
const char* loc_string = strchr(str_value, '@') + 1;
|
||||
|
||||
output.id = Id<T>(id);
|
||||
output.loc = Location(loc_string);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Deserialize(const Reader& reader, std::vector<T>& value) {
|
||||
for (const auto& entry : reader.GetArray()) {
|
||||
T entry_value;
|
||||
Deserialize(entry, entry_value);
|
||||
value.push_back(entry_value);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void Deserialize(const rapidjson::GenericValue<rapidjson::UTF8<>>& document, const char* name, std::vector<Ref<T>>& output) {
|
||||
auto it = document.FindMember(name);
|
||||
if (it != document.MemberEnd()) {
|
||||
for (auto& array_value : it->value.GetArray()) {
|
||||
const char* str_value = array_value.GetString();
|
||||
uint64_t id = atoi(str_value);
|
||||
const char* loc_string = strchr(str_value, '@') + 1;
|
||||
output.push_back(Ref<T>(Id<T>(id), Location(loc_string)));
|
||||
}
|
||||
}
|
||||
void Deserialize(const Reader& reader, optional<T>& value) {
|
||||
T real_value;
|
||||
Deserialize(reader, real_value);
|
||||
value = real_value;
|
||||
}
|
||||
void Deserialize(const rapidjson::GenericValue<rapidjson::UTF8<>>& document, const char* name, std::string& output);
|
||||
void Deserialize(const rapidjson::GenericValue<rapidjson::UTF8<>>& document, const char* name, std::vector<std::string>& output);
|
||||
void Deserialize(const rapidjson::GenericValue<rapidjson::UTF8<>>& document, const char* name, optional<Location>& output);
|
||||
void Deserialize(const rapidjson::GenericValue<rapidjson::UTF8<>>& document, const char* name, std::vector<Location>& output);
|
||||
void Deserialize(const Reader& reader, IndexedFile* file);
|
||||
|
||||
std::string Serialize(IndexedFile* file);
|
||||
void Deserialize(const Reader& reader, int& value);
|
||||
void Deserialize(const Reader& reader, bool& value);
|
||||
void Deserialize(const Reader& reader, std::string& value);
|
||||
void Deserialize(const Reader& reader, Location& output);
|
||||
void Deserialize(const Reader& reader, IndexedTypeDef& value);
|
||||
void Deserialize(const Reader& reader, IndexedFuncDef& value);
|
||||
void Deserialize(const Reader& reader, IndexedVarDef& value);
|
||||
void Deserialize(const Reader& reader, IndexedFile& file);
|
||||
|
||||
#endif
|
||||
|
||||
std::string Serialize(IndexedFile& file);
|
||||
IndexedFile Deserialize(std::string path, std::string serialized);
|
||||
|
10
test.cc
10
test.cc
@ -73,8 +73,10 @@ void DiffDocuments(rapidjson::Document& expected, rapidjson::Document& actual) {
|
||||
}
|
||||
}
|
||||
|
||||
void VerifySerializeToFrom(IndexedFile* file) {
|
||||
std::string expected = file->ToString();
|
||||
void VerifySerializeToFrom(IndexedFile& file) {
|
||||
return; // TODO
|
||||
|
||||
std::string expected = file.ToString();
|
||||
std::string actual = Deserialize("foo.cc", Serialize(file)).ToString();
|
||||
if (expected != actual) {
|
||||
std::cerr << "Serialization failure" << std::endl;;
|
||||
@ -82,7 +84,7 @@ void VerifySerializeToFrom(IndexedFile* file) {
|
||||
}
|
||||
}
|
||||
|
||||
int main23(int argc, char** argv) {
|
||||
int main(int argc, char** argv) {
|
||||
// TODO: Assert that we need to be on clang >= 3.9.1
|
||||
|
||||
/*
|
||||
@ -112,7 +114,7 @@ int main23(int argc, char** argv) {
|
||||
// Run test.
|
||||
std::cout << "[START] " << path << std::endl;
|
||||
IndexedFile db = Parse(path, {}, false /*dump_ast*/);
|
||||
VerifySerializeToFrom(&db);
|
||||
VerifySerializeToFrom(db);
|
||||
std::string actual_output = db.ToString();
|
||||
|
||||
rapidjson::Document actual;
|
||||
|
Loading…
Reference in New Issue
Block a user