From 0b71d7d3b4d60f35f5d8db344f51828a21efec7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20M=C3=BCller?= Date: Fri, 10 Nov 2017 11:54:21 +0100 Subject: [PATCH] Add enum category example --- example/CMakeLists.txt | 1 + example/enum_category.cpp | 116 ++++++++++++++++++++++++++++++++++++ include/cppast/cpp_type.hpp | 6 +- src/cpp_function.cpp | 2 +- src/cpp_type.cpp | 2 +- 5 files changed, 122 insertions(+), 5 deletions(-) create mode 100644 example/enum_category.cpp diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index 2f83c21..c13a6c0 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -10,5 +10,6 @@ endfunction() _cppast_example(ast_printer) _cppast_example(comparison) _cppast_example(documentation_generator) +_cppast_example(enum_category) _cppast_example(enum_to_string) _cppast_example(serialization) diff --git a/example/enum_category.cpp b/example/enum_category.cpp new file mode 100644 index 0000000..8911b62 --- /dev/null +++ b/example/enum_category.cpp @@ -0,0 +1,116 @@ +// Copyright (C) 2017 Jonathan Müller +// This file is subject to the license terms in the LICENSE file +// found in the top-level directory of this distribution. + +/// \file +/// Generates enum category functions. + +#include +#include +#include + +#include // cpp_enum +#include // cpp_function +#include // visit() + +#include "example_parser.hpp" + +bool is_category(const cppast::cpp_enum_value& e, const std::string& name) +{ + if (auto attr = cppast::has_attribute(e, "generate::enum_category")) + { + auto iter = + std::find_if(attr.value().arguments().value().begin(), + attr.value().arguments().value().end(), + [&](const cppast::cpp_token& tok) { return tok.spelling == name; }); + return iter != attr.value().arguments().value().end(); + } + else + return false; +} + +const cppast::cpp_enum& get_enum(const cppast::cpp_entity_index& index, + const cppast::cpp_function_parameter& param) +{ + auto& param_type = param.type(); + // is an enum + assert(param_type.kind() == cppast::cpp_type_kind::user_defined_t); + auto& definition = + static_cast(param_type).entity().get(index)[0u].get(); + + assert(definition.kind() == cppast::cpp_entity_kind::enum_t); + return static_cast(definition); +} + +void generate_enum_category(const cppast::cpp_entity_index& index, const cppast::cpp_file& file) +{ + cppast::visit(file, + [](const cppast::cpp_entity& e) { + // only visit function declarations that have the attribute set + return (e.kind() == cppast::cpp_entity_kind::function_t + && !cppast::is_definition(e) + && cppast::has_attribute(e, "generate::enum_category")) + // 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::function_t) + { + // a new function, generate implementation + assert(info.is_new_entity()); + + auto category = cppast::has_attribute(e, "generate::enum_category") + .value() + .arguments() + .value() + .as_string(); + + auto& func = static_cast(e); + // return type must be bool + assert(func.return_type().kind() == cppast::cpp_type_kind::builtin_t + && static_cast(func.return_type()) + .builtin_type_kind() + == cppast::cpp_bool); + + // single parameter... + assert(std::next(func.parameters().begin()) == func.parameters().end()); + auto& param = *func.parameters().begin(); + auto& enum_ = get_enum(index, param); + + // generate function definition + std::cout << "inline bool " << func.name() << "(" + << cppast::to_string(param.type()) << " e) {\n"; + + // generate switch + std::cout << " switch (e) {\n"; + for (const auto& enumerator : enum_) + { + std::cout << " case " << enum_.name() << "::" << enumerator.name() + << ":\n"; + if (is_category(enumerator, category)) + std::cout << " return true;\n"; + else + std::cout << " return false;\n"; + } + std::cout << " }\n"; + + 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[]) +{ + cppast::cpp_entity_index index; + return example_main(argc, argv, index, + [&](const cppast::cpp_file& file) { generate_enum_category(index, file); }); +} diff --git a/include/cppast/cpp_type.hpp b/include/cppast/cpp_type.hpp index 9bf3e02..19c707d 100644 --- a/include/cppast/cpp_type.hpp +++ b/include/cppast/cpp_type.hpp @@ -436,6 +436,9 @@ namespace cppast cpp_reference ref_; }; + /// \returns The type as a string representation. + std::string to_string(const cpp_type& type); + /// \exclude namespace detail { @@ -453,9 +456,6 @@ namespace cppast // write prefix, variadic, name, suffix void write_type(code_generator::output& output, const cpp_type& type, std::string name, bool is_variadic = false); - - // simple to_string() for types - std::string to_string(const cpp_type& type); } // namespace detail } // namespace cppast diff --git a/src/cpp_function.cpp b/src/cpp_function.cpp index f3f492b..a6d24e6 100644 --- a/src/cpp_function.cpp +++ b/src/cpp_function.cpp @@ -39,7 +39,7 @@ std::string cpp_function_base::do_get_signature() const { std::string result = "("; for (auto& param : parameters()) - result += detail::to_string(param.type()) + ','; + result += to_string(param.type()) + ','; if (is_variadic()) result += "..."; diff --git a/src/cpp_type.cpp b/src/cpp_type.cpp index a624898..c2dc88a 100644 --- a/src/cpp_type.cpp +++ b/src/cpp_type.cpp @@ -581,7 +581,7 @@ void detail::write_type(code_generator::output& output, const cpp_type& type, st write_type_suffix(output, type); } -std::string detail::to_string(const cpp_type& type) +std::string cppast::to_string(const cpp_type& type) { class to_string_generator : public code_generator {