WIP new reflection API to unify serialization

This commit is contained in:
Jacob Dufault 2017-03-07 01:32:29 -08:00
parent 7a160a5269
commit 729264bb34
9 changed files with 429 additions and 408 deletions

View File

@ -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

View File

@ -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) {

View File

@ -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
View File

@ -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

View File

@ -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);
}
};
@ -1508,3 +1382,4 @@ namespace language_server_api {
}
#endif

View File

@ -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.

View File

@ -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();
}
#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();
// IndexedFuncDef
bool ReflectMemberStart(Reader& reader, IndexedFuncDef& value) {
value.is_bad_def = false;
return true;
}
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();
bool ReflectMemberStart(Writer& writer, IndexedFuncDef& value) {
if (value.is_bad_def)
return false;
DefaultReflectMemberStart(writer);
return true;
}
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
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();
}
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();
// 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();
}
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());
}
// 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);
}
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.
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::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;
}

View File

@ -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()));
}
}
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();
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.push_back(Ref<T>(Id<T>(id), Location(loc_string)));
}
}
}
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);
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 Reader& reader, optional<T>& value) {
T real_value;
Deserialize(reader, real_value);
value = real_value;
}
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
View File

@ -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;