Add serialization example
This commit is contained in:
parent
b69e7bfacd
commit
9329fc75ec
6 changed files with 174 additions and 26 deletions
|
|
@ -10,3 +10,4 @@ endfunction()
|
|||
_cppast_example(ast_printer)
|
||||
_cppast_example(documentation_generator)
|
||||
_cppast_example(enum_to_string)
|
||||
_cppast_example(serialization)
|
||||
|
|
|
|||
|
|
@ -16,8 +16,9 @@ void generate_to_string(const cppast::cpp_file& file)
|
|||
{
|
||||
cppast::visit(file,
|
||||
[](const cppast::cpp_entity& e) {
|
||||
// only visit enums that have the attribute set
|
||||
// only visit enum definitions that have the attribute set
|
||||
return (e.kind() == cppast::cpp_entity_kind::enum_t
|
||||
&& cppast::is_definition(e)
|
||||
&& cppast::has_attribute(e, "generate::to_string"))
|
||||
// or all namespaces
|
||||
|| e.kind() == cppast::cpp_entity_kind::namespace_t;
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
// parses all files in that directory
|
||||
// and invokes the callback for each of them
|
||||
template <typename Callback>
|
||||
int example_main(int argc, char* argv[], const cppast::cpp_entity_index& index, Callback cb)
|
||||
int example_main(int argc, char* argv[], const cppast::cpp_entity_index& index, Callback cb) try
|
||||
{
|
||||
if (argc != 2)
|
||||
{
|
||||
|
|
@ -47,5 +47,10 @@ int example_main(int argc, char* argv[], const cppast::cpp_entity_index& index,
|
|||
|
||||
return 0;
|
||||
}
|
||||
catch (std::exception& ex)
|
||||
{
|
||||
std::cerr << ex.what() << '\n';
|
||||
return 1;
|
||||
}
|
||||
|
||||
#endif // CPPAST_EXAMPLE_PARSER_HPP_INCLUDED
|
||||
|
|
|
|||
115
example/serialization.cpp
Normal file
115
example/serialization.cpp
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
// Copyright (C) 2017 Jonathan Müller <jonathanmueller.dev@gmail.com>
|
||||
// This file is subject to the license terms in the LICENSE file
|
||||
// found in the top-level directory of this distribution.
|
||||
|
||||
/// \file
|
||||
/// Serialization code generation.
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <cppast/cpp_class.hpp>
|
||||
#include <cppast/cpp_member_variable.hpp>
|
||||
#include <cppast/cpp_type.hpp>
|
||||
#include <cppast/visitor.hpp>
|
||||
|
||||
#include "example_parser.hpp"
|
||||
|
||||
// whether or not a type is a C string, i.e. char pointer
|
||||
bool is_c_string(const cppast::cpp_type& type)
|
||||
{
|
||||
if (type.kind() != cppast::cpp_type_kind::pointer_t)
|
||||
return false;
|
||||
|
||||
auto& pointee = cppast::remove_cv(static_cast<const cppast::cpp_pointer_type&>(type).pointee());
|
||||
if (pointee.kind() != cppast::cpp_type_kind::builtin_t)
|
||||
return false;
|
||||
|
||||
auto builtin = static_cast<const cppast::cpp_builtin_type&>(pointee).builtin_type_kind();
|
||||
return builtin == cppast::cpp_char || builtin == cppast::cpp_char16
|
||||
|| builtin == cppast::cpp_char32 || builtin == cppast::cpp_wchar;
|
||||
}
|
||||
|
||||
void generate_serialize_member(std::ostream& out, const cppast::cpp_member_variable& member)
|
||||
{
|
||||
auto& type = cppast::remove_cv(member.type());
|
||||
|
||||
if (cppast::has_attribute(member, "generate::transient"))
|
||||
// don't serialize transient members
|
||||
return;
|
||||
else if (auto attr = cppast::has_attribute(member, "generate::serialize"))
|
||||
{
|
||||
// generate code as specified by the attributes
|
||||
out << " " << attr.value().arguments().value().as_string() << ";\n";
|
||||
}
|
||||
else if (type.kind() == cppast::cpp_type_kind::builtin_t)
|
||||
{
|
||||
// generate hypothetical member function call for builtin types
|
||||
out << " s.serialize(obj." << member.name() << ");\n";
|
||||
}
|
||||
else if (type.kind() == cppast::cpp_type_kind::user_defined_t)
|
||||
{
|
||||
// generate ADL call
|
||||
out << " serialize(s, obj." << member.name() << ");\n";
|
||||
}
|
||||
else if (is_c_string(type))
|
||||
{
|
||||
// generate another hypothetical member function call
|
||||
out << " s.serialize_string(obj." << member.name() << ");\n";
|
||||
}
|
||||
else
|
||||
throw std::invalid_argument("cannot serialize member " + member.name());
|
||||
}
|
||||
|
||||
void generate_serialize(const cppast::cpp_file& file)
|
||||
{
|
||||
cppast::visit(file,
|
||||
[](const cppast::cpp_entity& e) {
|
||||
// only visit non-templated class definitions that have the attribute set
|
||||
return (!cppast::is_templated(e)
|
||||
&& e.kind() == cppast::cpp_entity_kind::class_t
|
||||
&& cppast::is_definition(e)
|
||||
&& cppast::has_attribute(e, "generate::serialize"))
|
||||
// or all namespaces
|
||||
|| e.kind() == cppast::cpp_entity_kind::namespace_t;
|
||||
},
|
||||
[](const cppast::cpp_entity& e, const cppast::visitor_info& info) {
|
||||
if (e.kind() == cppast::cpp_entity_kind::class_t && !info.is_old_entity())
|
||||
{
|
||||
auto& class_ = static_cast<const cppast::cpp_class&>(e);
|
||||
|
||||
std::cout << "void serialize(const foo::serializer& s, const "
|
||||
<< class_.name() << "& obj) {\n";
|
||||
|
||||
// serialize base classes
|
||||
for (auto& base : class_.bases())
|
||||
std::cout << " serialize(s, static_cast<const " << base.name()
|
||||
<< "&>(obj));\n";
|
||||
|
||||
// serialize member variables
|
||||
for (auto& member : class_)
|
||||
{
|
||||
if (member.kind() == cppast::cpp_entity_kind::member_variable_t)
|
||||
generate_serialize_member(std::cout,
|
||||
static_cast<
|
||||
const cppast::cpp_member_variable&>(
|
||||
member));
|
||||
}
|
||||
|
||||
std::cout << "}\n\n";
|
||||
}
|
||||
else if (e.kind() == cppast::cpp_entity_kind::namespace_t)
|
||||
{
|
||||
if (info.event == cppast::visitor_info::container_entity_enter)
|
||||
// open namespace
|
||||
std::cout << "namespace " << e.name() << " {\n\n";
|
||||
else // if (info.event == cppast::visitor_info::container_entity_exit)
|
||||
// close namespace
|
||||
std::cout << "}\n";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
return example_main(argc, argv, {}, generate_serialize);
|
||||
}
|
||||
|
|
@ -74,17 +74,13 @@ namespace cppast
|
|||
}
|
||||
|
||||
protected:
|
||||
cpp_type() noexcept : user_data_(nullptr)
|
||||
{
|
||||
}
|
||||
cpp_type() noexcept : user_data_(nullptr) {}
|
||||
|
||||
private:
|
||||
/// \returns The [cppast::cpp_type_kind]().
|
||||
virtual cpp_type_kind do_get_kind() const noexcept = 0;
|
||||
|
||||
void on_insert(const cpp_type&)
|
||||
{
|
||||
}
|
||||
void on_insert(const cpp_type&) {}
|
||||
|
||||
mutable std::atomic<void*> user_data_;
|
||||
|
||||
|
|
@ -112,9 +108,7 @@ namespace cppast
|
|||
}
|
||||
|
||||
private:
|
||||
cpp_unexposed_type(std::string name) : name_(std::move(name))
|
||||
{
|
||||
}
|
||||
cpp_unexposed_type(std::string name) : name_(std::move(name)) {}
|
||||
|
||||
cpp_type_kind do_get_kind() const noexcept override
|
||||
{
|
||||
|
|
@ -180,9 +174,7 @@ namespace cppast
|
|||
}
|
||||
|
||||
private:
|
||||
cpp_builtin_type(cpp_builtin_type_kind kind) : kind_(kind)
|
||||
{
|
||||
}
|
||||
cpp_builtin_type(cpp_builtin_type_kind kind) : kind_(kind) {}
|
||||
|
||||
cpp_type_kind do_get_kind() const noexcept override
|
||||
{
|
||||
|
|
@ -224,9 +216,7 @@ namespace cppast
|
|||
}
|
||||
|
||||
private:
|
||||
cpp_user_defined_type(cpp_type_ref entity) : entity_(std::move(entity))
|
||||
{
|
||||
}
|
||||
cpp_user_defined_type(cpp_type_ref entity) : entity_(std::move(entity)) {}
|
||||
|
||||
cpp_type_kind do_get_kind() const noexcept override
|
||||
{
|
||||
|
|
@ -361,6 +351,15 @@ namespace cppast
|
|||
cpp_cv cv_;
|
||||
};
|
||||
|
||||
/// \returns The type without top-level const/volatile qualifiers.
|
||||
const cpp_type& remove_cv(const cpp_type& type) noexcept;
|
||||
|
||||
/// \returns The type without top-level const qualifiers.
|
||||
const cpp_type& remove_const(const cpp_type& type) noexcept;
|
||||
|
||||
/// \returns The type without top-level volatile qualifiers.
|
||||
const cpp_type& remove_volatile(const cpp_type& type) noexcept;
|
||||
|
||||
/// A pointer to a [cppast::cpp_type]().
|
||||
class cpp_pointer_type final : public cpp_type
|
||||
{
|
||||
|
|
@ -378,9 +377,7 @@ namespace cppast
|
|||
}
|
||||
|
||||
private:
|
||||
cpp_pointer_type(std::unique_ptr<cpp_type> pointee) : pointee_(std::move(pointee))
|
||||
{
|
||||
}
|
||||
cpp_pointer_type(std::unique_ptr<cpp_type> pointee) : pointee_(std::move(pointee)) {}
|
||||
|
||||
cpp_type_kind do_get_kind() const noexcept override
|
||||
{
|
||||
|
|
|
|||
|
|
@ -76,6 +76,39 @@ const char* cppast::to_string(cpp_builtin_type_kind kind) noexcept
|
|||
return "__ups";
|
||||
}
|
||||
|
||||
const cpp_type& cppast::remove_cv(const cpp_type& type) noexcept
|
||||
{
|
||||
if (type.kind() == cpp_type_kind::cv_qualified_t)
|
||||
{
|
||||
auto& cv = static_cast<const cpp_cv_qualified_type&>(type);
|
||||
return cv.type();
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
const cpp_type& cppast::remove_const(const cpp_type& type) noexcept
|
||||
{
|
||||
if (type.kind() == cpp_type_kind::cv_qualified_t)
|
||||
{
|
||||
auto& cv = static_cast<const cpp_cv_qualified_type&>(type);
|
||||
if (is_const(cv.cv_qualifier()))
|
||||
return cv.type();
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
const cpp_type& cppast::remove_volatile(const cpp_type& type) noexcept
|
||||
{
|
||||
if (type.kind() == cpp_type_kind::cv_qualified_t)
|
||||
{
|
||||
auto& cv = static_cast<const cpp_cv_qualified_type&>(type);
|
||||
if (is_volatile(cv.cv_qualifier()))
|
||||
return cv.type();
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
bool detail::cpp_type_ref_predicate::operator()(const cpp_entity& e)
|
||||
{
|
||||
switch (e.kind())
|
||||
|
|
@ -559,13 +592,9 @@ std::string detail::to_string(const cpp_type& type)
|
|||
}
|
||||
|
||||
private:
|
||||
void do_indent() override
|
||||
{
|
||||
}
|
||||
void do_indent() override {}
|
||||
|
||||
void do_unindent() override
|
||||
{
|
||||
}
|
||||
void do_unindent() override {}
|
||||
|
||||
void do_write_token_seq(string_view tokens) override
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue