Add comparison
This commit is contained in:
parent
9329fc75ec
commit
0531a19d90
5 changed files with 125 additions and 4 deletions
|
|
@ -8,6 +8,7 @@ function(_cppast_example name)
|
|||
endfunction()
|
||||
|
||||
_cppast_example(ast_printer)
|
||||
_cppast_example(comparison)
|
||||
_cppast_example(documentation_generator)
|
||||
_cppast_example(enum_to_string)
|
||||
_cppast_example(serialization)
|
||||
|
|
|
|||
117
example/comparison.cpp
Normal file
117
example/comparison.cpp
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
// 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
|
||||
/// Generate equality comparisons.
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
#include <cppast/cpp_class.hpp>
|
||||
#include <cppast/cpp_member_variable.hpp>
|
||||
#include <cppast/visitor.hpp>
|
||||
|
||||
#include "example_parser.hpp"
|
||||
|
||||
bool has_token(const cppast::cpp_token_string& str, const char* token)
|
||||
{
|
||||
auto iter = std::find_if(str.begin(), str.end(),
|
||||
[&](const cppast::cpp_token& tok) { return tok.spelling == token; });
|
||||
return iter != str.end();
|
||||
}
|
||||
|
||||
void generate_op_equal(std::ostream& out, const cppast::cpp_class& c)
|
||||
{
|
||||
out << "inline bool operator==(const " << c.name() << "& lhs, const " << c.name()
|
||||
<< "& rhs) {\n";
|
||||
out << " return ";
|
||||
|
||||
auto first = true;
|
||||
|
||||
for (auto& base : c.bases())
|
||||
{
|
||||
if (cppast::has_attribute(base, "generate::transient"))
|
||||
continue;
|
||||
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
out << " && ";
|
||||
out << "static_cast<const " << base.name() << "&>(lhs) == static_cast<const " << base.name()
|
||||
<< "&>(rhs)\n";
|
||||
}
|
||||
|
||||
for (auto& member : c)
|
||||
if (member.kind() == cppast::cpp_entity_kind::member_variable_t
|
||||
&& !cppast::has_attribute(member, "generate::transient"))
|
||||
{
|
||||
// generate comparison code for non-transient member variables
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
out << " && ";
|
||||
out << "lhs." << member.name() << " == "
|
||||
<< "rhs." << member.name() << "\n";
|
||||
}
|
||||
|
||||
out << " ;\n";
|
||||
out << "}\n\n";
|
||||
}
|
||||
|
||||
void generate_op_non_equal(std::ostream& out, const cppast::cpp_class& c)
|
||||
{
|
||||
out << "inline bool operator!=(const " << c.name() << "& lhs, const " << c.name()
|
||||
<< "& rhs) {\n";
|
||||
out << " return !(lhs == rhs);\n";
|
||||
out << "}\n\n";
|
||||
}
|
||||
|
||||
void generate_comparison(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::comparison"))
|
||||
// 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);
|
||||
auto& attribute =
|
||||
cppast::has_attribute(e, "generate::comparison").value();
|
||||
|
||||
if (attribute.arguments())
|
||||
{
|
||||
if (has_token(attribute.arguments().value(), "=="))
|
||||
generate_op_equal(std::cout, class_);
|
||||
else if (has_token(attribute.arguments().value(), "!="))
|
||||
generate_op_non_equal(std::cout, class_);
|
||||
}
|
||||
else
|
||||
{
|
||||
generate_op_equal(std::cout, class_);
|
||||
generate_op_non_equal(std::cout, class_);
|
||||
}
|
||||
}
|
||||
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_comparison);
|
||||
}
|
||||
|
|
@ -30,7 +30,8 @@ void generate_to_string(const cppast::cpp_file& file)
|
|||
auto& enum_ = static_cast<const cppast::cpp_enum&>(e);
|
||||
|
||||
// write function header
|
||||
std::cout << "const char* to_string(const " << enum_.name() << "& e) {\n";
|
||||
std::cout << "inline const char* to_string(const " << enum_.name()
|
||||
<< "& e) {\n";
|
||||
|
||||
// generate switch
|
||||
std::cout << " switch (e) {\n";
|
||||
|
|
|
|||
|
|
@ -77,13 +77,14 @@ void generate_serialize(const cppast::cpp_file& file)
|
|||
{
|
||||
auto& class_ = static_cast<const cppast::cpp_class&>(e);
|
||||
|
||||
std::cout << "void serialize(const foo::serializer& s, const "
|
||||
std::cout << "inline 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";
|
||||
if (!cppast::has_attribute(base, "generate::transient"))
|
||||
std::cout << " serialize(s, static_cast<const " << base.name()
|
||||
<< "&>(obj));\n";
|
||||
|
||||
// serialize member variables
|
||||
for (auto& member : class_)
|
||||
|
|
|
|||
|
|
@ -182,6 +182,7 @@ namespace cppast
|
|||
else
|
||||
return continue_visit;
|
||||
}
|
||||
return continue_visit;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue