parent
f73e4b420f
commit
c886ef31e4
7 changed files with 70 additions and 1 deletions
36
example/README.md
Normal file
36
example/README.md
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
# cppast - examples
|
||||
|
||||
This directory contains example tools written using cppast.
|
||||
|
||||
***Note:** These are not meant to be production ready tools, just a proof of concept!*
|
||||
|
||||
All example executables get a single parameter,
|
||||
which is the directory where a `compile_commands.json` file is located.
|
||||
This file is a compilation database, you can read more about it [here](https://clang.llvm.org/docs/JSONCompilationDatabase.html).
|
||||
CMake, for example, can generate on when the option `CMAKE_EXPORT_COMPILE_COMMANDS` is `ON`.
|
||||
|
||||
The tools will parse each file in the database and process it.
|
||||
Output will be written to `stdout`.
|
||||
|
||||
## List of examples:
|
||||
|
||||
### `ast_printer.cpp`
|
||||
|
||||
It is a very simplified implementation of the cppast tool, it will print an AST.
|
||||
This is the starting example, it showcases entity visitation.
|
||||
|
||||
### `documentation_generator.cpp`
|
||||
|
||||
It is a very simplified documentation generator.
|
||||
This showcases usage of the `cppast::code_generator`.
|
||||
|
||||
### Attributes example
|
||||
|
||||
* `comparison.cpp`
|
||||
* `documentation_generator.cpp`
|
||||
* `enum_category.cpp`
|
||||
* `enum_to_string.cpp`
|
||||
* `serialization.cpp`
|
||||
|
||||
Those examples were created as a part of my talk [Fun With (User-Defined) Attributes](http://foonathan.net/meetingcpp2017.html).
|
||||
Check the talk video to learn more about them.
|
||||
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
/// \file
|
||||
/// This is a very primitive version of the cppast tool.
|
||||
///
|
||||
/// Given an input file it will print the AST.
|
||||
|
||||
#include <cppast/visitor.hpp> // visit()
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
/// \file
|
||||
/// Generate equality comparisons.
|
||||
///
|
||||
/// Given an input file, it will generate comparison operators for each class that has the [[generate::comparison]] attribute.
|
||||
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
|
@ -14,6 +16,7 @@
|
|||
|
||||
#include "example_parser.hpp"
|
||||
|
||||
// whether or not the token string contains the given token
|
||||
bool has_token(const cppast::cpp_token_string& str, const char* token)
|
||||
{
|
||||
auto iter = std::find_if(str.begin(), str.end(),
|
||||
|
|
@ -21,6 +24,7 @@ bool has_token(const cppast::cpp_token_string& str, const char* token)
|
|||
return iter != str.end();
|
||||
}
|
||||
|
||||
// generates equality operator for a class
|
||||
void generate_op_equal(std::ostream& out, const cppast::cpp_class& c)
|
||||
{
|
||||
out << "inline bool operator==(const " << c.name() << "& lhs, const " << c.name()
|
||||
|
|
@ -29,9 +33,11 @@ void generate_op_equal(std::ostream& out, const cppast::cpp_class& c)
|
|||
|
||||
auto first = true;
|
||||
|
||||
// compare bases
|
||||
for (auto& base : c.bases())
|
||||
{
|
||||
if (cppast::has_attribute(base, "generate::transient"))
|
||||
// if they are not marked not to be compared
|
||||
continue;
|
||||
|
||||
if (first)
|
||||
|
|
@ -42,6 +48,7 @@ void generate_op_equal(std::ostream& out, const cppast::cpp_class& c)
|
|||
<< "&>(rhs)\n";
|
||||
}
|
||||
|
||||
// compare members
|
||||
for (auto& member : c)
|
||||
if (member.kind() == cppast::cpp_entity_kind::member_variable_t
|
||||
&& !cppast::has_attribute(member, "generate::transient"))
|
||||
|
|
@ -59,14 +66,17 @@ void generate_op_equal(std::ostream& out, const cppast::cpp_class& c)
|
|||
out << "}\n\n";
|
||||
}
|
||||
|
||||
// generate non equality operator for a class
|
||||
void generate_op_non_equal(std::ostream& out, const cppast::cpp_class& c)
|
||||
{
|
||||
// just forwards
|
||||
out << "inline bool operator!=(const " << c.name() << "& lhs, const " << c.name()
|
||||
<< "& rhs) {\n";
|
||||
out << " return !(lhs == rhs);\n";
|
||||
out << "}\n\n";
|
||||
}
|
||||
|
||||
// generate comparison operators for all classes in the file
|
||||
void generate_comparison(const cppast::cpp_file& file)
|
||||
{
|
||||
cppast::visit(file,
|
||||
|
|
@ -82,10 +92,12 @@ void generate_comparison(const cppast::cpp_file& file)
|
|||
[](const cppast::cpp_entity& e, const cppast::visitor_info& info) {
|
||||
if (e.kind() == cppast::cpp_entity_kind::class_t && !info.is_old_entity())
|
||||
{
|
||||
// it is a new class
|
||||
auto& class_ = static_cast<const cppast::cpp_class&>(e);
|
||||
auto& attribute =
|
||||
cppast::has_attribute(e, "generate::comparison").value();
|
||||
|
||||
// generate requested operators
|
||||
if (attribute.arguments())
|
||||
{
|
||||
if (has_token(attribute.arguments().value(), "=="))
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
/// \file
|
||||
/// A primitive documentation generator.
|
||||
///
|
||||
/// Given an input file, it will print its documentation including documentation comments.
|
||||
|
||||
#include <cppast/code_generator.hpp> // code_generator, generate_code()
|
||||
#include <cppast/visitor.hpp> // visit()
|
||||
|
|
|
|||
|
|
@ -4,6 +4,9 @@
|
|||
|
||||
/// \file
|
||||
/// Generates enum category functions.
|
||||
///
|
||||
/// Given an input file, it will generate definitions for functions marked with [[generate::enum_category(name)]].
|
||||
/// The function takes an enumerator and will return true if it is marked with the same category.
|
||||
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
|
|
@ -15,10 +18,12 @@
|
|||
|
||||
#include "example_parser.hpp"
|
||||
|
||||
// returns whether or not the given enumerator has the given category
|
||||
bool is_category(const cppast::cpp_enum_value& e, const std::string& name)
|
||||
{
|
||||
if (auto attr = cppast::has_attribute(e, "generate::enum_category"))
|
||||
{
|
||||
// ... by looking for the token
|
||||
auto iter =
|
||||
std::find_if(attr.value().arguments().value().begin(),
|
||||
attr.value().arguments().value().end(),
|
||||
|
|
@ -29,12 +34,14 @@ bool is_category(const cppast::cpp_enum_value& e, const std::string& name)
|
|||
return false;
|
||||
}
|
||||
|
||||
// returns the enum the parameter type refers to
|
||||
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
|
||||
// it is an enum
|
||||
assert(param_type.kind() == cppast::cpp_type_kind::user_defined_t);
|
||||
// lookup definition
|
||||
auto& definition =
|
||||
static_cast<const cppast::cpp_user_defined_type&>(param_type).entity().get(index)[0u].get();
|
||||
|
||||
|
|
@ -42,6 +49,7 @@ const cppast::cpp_enum& get_enum(const cppast::cpp_entity_index& index,
|
|||
return static_cast<const cppast::cpp_enum&>(definition);
|
||||
}
|
||||
|
||||
// generates the function definitions
|
||||
void generate_enum_category(const cppast::cpp_entity_index& index, const cppast::cpp_file& file)
|
||||
{
|
||||
cppast::visit(file,
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
/// \file
|
||||
/// Generates enum `to_string()` code.
|
||||
///
|
||||
/// Given an input file, it will generate a to_string() function for all enums marked with [[generate::to_string]].
|
||||
|
||||
#include <iostream>
|
||||
|
||||
|
|
@ -40,6 +42,7 @@ void generate_to_string(const cppast::cpp_file& file)
|
|||
std::cout << " case " << enum_.name() << "::" << enumerator.name()
|
||||
<< ":\n";
|
||||
|
||||
// attribute can be used to override the string
|
||||
if (auto attr =
|
||||
cppast::has_attribute(enumerator, "generate::to_string"))
|
||||
std::cout << " return "
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
/// \file
|
||||
/// Serialization code generation.
|
||||
///
|
||||
/// Given an input file, it will generate a serialize() function for each class marked with [[generate::serialize]].
|
||||
|
||||
#include <iostream>
|
||||
|
||||
|
|
@ -20,15 +22,18 @@ bool is_c_string(const cppast::cpp_type& type)
|
|||
if (type.kind() != cppast::cpp_type_kind::pointer_t)
|
||||
return false;
|
||||
|
||||
// get the pointee
|
||||
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;
|
||||
|
||||
// check the builtin type kind
|
||||
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;
|
||||
}
|
||||
|
||||
// generate a serialization call for a member
|
||||
void generate_serialize_member(std::ostream& out, const cppast::cpp_member_variable& member)
|
||||
{
|
||||
auto& type = cppast::remove_cv(member.type());
|
||||
|
|
@ -60,6 +65,7 @@ void generate_serialize_member(std::ostream& out, const cppast::cpp_member_varia
|
|||
throw std::invalid_argument("cannot serialize member " + member.name());
|
||||
}
|
||||
|
||||
// generate serialization function
|
||||
void generate_serialize(const cppast::cpp_file& file)
|
||||
{
|
||||
cppast::visit(file,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue