-
Notifications
You must be signed in to change notification settings - Fork 171
/
Copy pathdocumentation_generator.cpp
161 lines (141 loc) · 5.24 KB
/
documentation_generator.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
// Copyright (C) 2017-2023 Jonathan Müller and cppast contributors
// SPDX-License-Identifier: MIT
/// \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()
#include "example_parser.hpp"
// don't show in code generation
bool is_excluded_synopsis(const cppast::cpp_entity& e, cppast::cpp_access_specifier_kind access)
{
// exclude privates and those marked for exclusion
return access == cppast::cpp_private || cppast::has_attribute(e, "documentation::exclude");
}
// don't show in documentation
bool is_excluded_documentation(const cppast::cpp_entity& e,
const cppast::cpp_access_specifier_kind access)
{
// exclude uninteresting entities
return e.kind() == cppast::cpp_entity_kind::access_specifier_t
|| e.kind() == cppast::cpp_entity_kind::using_declaration_t
|| e.kind() == cppast::cpp_entity_kind::using_directive_t
|| e.kind() == cppast::cpp_entity_kind::static_assert_t
|| e.kind() == cppast::cpp_entity_kind::include_directive_t
// and all excluded in synopsis
|| is_excluded_synopsis(e, access);
}
// generates synopsis of an entity
std::string generate_synopsis(const cppast::cpp_entity& e)
{
// the generator for the synopsis
class synopsis_generator final : public cppast::code_generator
{
public:
// get the resulting string
std::string result()
{
return std::move(str_);
}
private:
// whether or not the entity is the main entity that is being documented
bool is_main_entity(const cppast::cpp_entity& e)
{
if (cppast::is_templated(e) || cppast::is_friended(e))
// need to ask the real entity
return is_main_entity(e.parent().value());
else
return &e == &this->main_entity();
}
// get some nicer formatting
cppast::formatting do_get_formatting() const override
{
return cppast::formatting_flags::brace_nl | cppast::formatting_flags::comma_ws
| cppast::formatting_flags::operator_ws;
}
// calculate generation options
generation_options do_get_options(const cppast::cpp_entity& e,
cppast::cpp_access_specifier_kind access) override
{
if (is_excluded_synopsis(e, access))
return cppast::code_generator::exclude;
else if (!is_main_entity(e))
// only generation declaration for the non-documented entity
return cppast::code_generator::declaration;
else
// default options
return {};
}
// update indendation level
void do_indent() override
{
++indent_;
}
void do_unindent() override
{
if (indent_)
--indent_;
}
// write specified tokens
// need to change indentation for each newline
void do_write_token_seq(cppast::string_view tokens) override
{
if (was_newline_)
{
str_ += std::string(indent_ * 2u, ' ');
was_newline_ = false;
}
str_ += tokens.c_str();
}
// write + remember newline
void do_write_newline() override
{
str_ += "\n";
was_newline_ = true;
}
std::string str_;
unsigned indent_ = 0;
bool was_newline_ = false;
} generator;
cppast::generate_code(generator, e);
return generator.result();
}
void generate_documentation(const cppast::cpp_file& file)
{
// visit each entity
cppast::visit(
file,
[](const cppast::cpp_entity& e, cppast::cpp_access_specifier_kind access) {
if (is_excluded_documentation(e, access))
// exclude this and all children
return cppast::visit_filter::exclude_and_children;
else if (cppast::is_templated(e) || cppast::is_friended(e))
// continue on with children for a dummy entity
return cppast::visit_filter::exclude;
else
return cppast::visit_filter::include;
},
[](const cppast::cpp_entity& e, const cppast::visitor_info& info) {
if (info.is_old_entity())
// already done
return;
// print name
std::cout << "## " << cppast::to_string(e.kind()) << " '" << e.name() << "'\n";
std::cout << '\n';
// print synopsis
std::cout << "```\n";
std::cout << generate_synopsis(e);
std::cout << "```\n\n";
// print documentation comment
if (e.comment())
std::cout << e.comment().value() << '\n';
// print separator
std::cout << "\n---\n\n";
});
std::cout << "\n\n";
}
int main(int argc, char* argv[])
{
return example_main(argc, argv, {}, &generate_documentation);
}