Add ability to exclude parts of generation
Also fix bugs when excluding entities.
This commit is contained in:
commit
074759fafb
5 changed files with 394 additions and 148 deletions
|
|
@ -8,6 +8,7 @@
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
#include <type_safe/index.hpp>
|
#include <type_safe/index.hpp>
|
||||||
|
#include <type_safe/flag_set.hpp>
|
||||||
|
|
||||||
#include <cppast/cpp_entity.hpp>
|
#include <cppast/cpp_entity.hpp>
|
||||||
#include <cppast/cpp_entity_ref.hpp>
|
#include <cppast/cpp_entity_ref.hpp>
|
||||||
|
|
@ -129,14 +130,19 @@ namespace cppast
|
||||||
code_generator& operator=(const code_generator&) = delete;
|
code_generator& operator=(const code_generator&) = delete;
|
||||||
virtual ~code_generator() noexcept = default;
|
virtual ~code_generator() noexcept = default;
|
||||||
|
|
||||||
/// Options that control the synopsis.
|
/// Flags that control the generation.
|
||||||
enum synopsis_options
|
enum generation_flags
|
||||||
{
|
{
|
||||||
exclude, //< Exclude the entire entity.
|
exclude, //< Exclude the entire entity.
|
||||||
declaration, //< Only write declaration.
|
exclude_return, //< Exclude the return type of a function entity.
|
||||||
definition, //< Also write definition.
|
exclude_target, //< Exclude the underlying entity of an alias (e.g. typedef).
|
||||||
|
declaration, //< Only write declaration.
|
||||||
|
_flag_set_size, //< \exclude
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Options that control the generation.
|
||||||
|
using generation_options = type_safe::flag_set<generation_flags>;
|
||||||
|
|
||||||
/// Sentinel type used to output a given entity.
|
/// Sentinel type used to output a given entity.
|
||||||
class output
|
class output
|
||||||
{
|
{
|
||||||
|
|
@ -150,10 +156,15 @@ namespace cppast
|
||||||
/// respectively.
|
/// respectively.
|
||||||
explicit output(type_safe::object_ref<code_generator> gen,
|
explicit output(type_safe::object_ref<code_generator> gen,
|
||||||
type_safe::object_ref<const cpp_entity> e, bool is_container)
|
type_safe::object_ref<const cpp_entity> e, bool is_container)
|
||||||
: gen_(gen), options_(is_container ? gen_->on_container_begin(*e) : gen_->on_leaf(*e))
|
: gen_(gen), options_(gen->do_get_options(*e))
|
||||||
{
|
{
|
||||||
if (is_container)
|
if (is_container)
|
||||||
|
{
|
||||||
|
gen_->on_container_begin(*e);
|
||||||
e_ = e;
|
e_ = e;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
gen_->on_leaf(*e);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \effects If the entity is a container
|
/// \effects If the entity is a container
|
||||||
|
|
@ -177,10 +188,22 @@ namespace cppast
|
||||||
return options_ != exclude;
|
return options_ != exclude;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \returns The generation options.
|
||||||
|
generation_options options() const noexcept
|
||||||
|
{
|
||||||
|
return options_;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \returns The generation options for the given entity.
|
||||||
|
generation_options options(const cpp_entity& e) const noexcept
|
||||||
|
{
|
||||||
|
return gen_->do_get_options(e);
|
||||||
|
}
|
||||||
|
|
||||||
/// \returns Whether or not the definition should be generated as well.
|
/// \returns Whether or not the definition should be generated as well.
|
||||||
bool generate_definition() const noexcept
|
bool generate_definition() const noexcept
|
||||||
{
|
{
|
||||||
return options_ == definition;
|
return !(options_ & declaration);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \returns A reference to the generator.
|
/// \returns A reference to the generator.
|
||||||
|
|
@ -280,6 +303,14 @@ namespace cppast
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \effects Calls `do_write_excluded()`.
|
||||||
|
const output& excluded(const cpp_entity& e) const
|
||||||
|
{
|
||||||
|
if (*this)
|
||||||
|
gen_->do_write_excluded(e);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
/// \effects Calls `do_write_newline()`.
|
/// \effects Calls `do_write_newline()`.
|
||||||
const output& operator<<(newl_t) const
|
const output& operator<<(newl_t) const
|
||||||
{
|
{
|
||||||
|
|
@ -299,21 +330,26 @@ namespace cppast
|
||||||
private:
|
private:
|
||||||
type_safe::object_ref<code_generator> gen_;
|
type_safe::object_ref<code_generator> gen_;
|
||||||
type_safe::optional_ref<const cpp_entity> e_;
|
type_safe::optional_ref<const cpp_entity> e_;
|
||||||
synopsis_options options_;
|
generation_options options_;
|
||||||
};
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
code_generator() noexcept = default;
|
code_generator() noexcept = default;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// \effects Will be invoked before code of a container entity is generated.
|
/// \returns The generation options for that entity.
|
||||||
/// The base class version has no effect.
|
/// The base class version always returns no special options.
|
||||||
/// \returns The synopsis options for that entity,
|
virtual generation_options do_get_options(const cpp_entity& e)
|
||||||
/// the base class version always returns `definition`.
|
{
|
||||||
virtual synopsis_options on_container_begin(const cpp_entity& e)
|
(void)e;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \effects Will be invoked before code of a container entity is generated.
|
||||||
|
/// The base class version has no effect.
|
||||||
|
virtual void on_container_begin(const cpp_entity& e)
|
||||||
{
|
{
|
||||||
(void)e;
|
(void)e;
|
||||||
return definition;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \effects Will be invoked after all code of a container entity has been generated.
|
/// \effects Will be invoked after all code of a container entity has been generated.
|
||||||
|
|
@ -325,12 +361,9 @@ namespace cppast
|
||||||
|
|
||||||
/// \effects Will be invoked before code of a non-container entity is generated.
|
/// \effects Will be invoked before code of a non-container entity is generated.
|
||||||
/// The base class version has no effect.
|
/// The base class version has no effect.
|
||||||
/// \returns The synopsis options for that entity,
|
virtual void on_leaf(const cpp_entity& e)
|
||||||
/// the base class version always returns `definition`.
|
|
||||||
virtual synopsis_options on_leaf(const cpp_entity& e)
|
|
||||||
{
|
{
|
||||||
(void)e;
|
(void)e;
|
||||||
return definition;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \effects Will be invoked when the indentation level should be increased by one.
|
/// \effects Will be invoked when the indentation level should be increased by one.
|
||||||
|
|
@ -390,6 +423,14 @@ namespace cppast
|
||||||
do_write_token_seq(punct);
|
do_write_token_seq(punct);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \effects Writes a string for an excluded target or return type for the given entity.
|
||||||
|
/// The base class version writes the identifier `excluded`.
|
||||||
|
virtual void do_write_excluded(const cpp_entity& e)
|
||||||
|
{
|
||||||
|
(void)e;
|
||||||
|
do_write_identifier("excluded");
|
||||||
|
}
|
||||||
|
|
||||||
/// \effects Writes a newline.
|
/// \effects Writes a newline.
|
||||||
/// It is guaranteed that this is the only way a newline will be printed.
|
/// It is guaranteed that this is the only way a newline will be printed.
|
||||||
/// The base class forwards to `do_write_token_seq()`.
|
/// The base class forwards to `do_write_token_seq()`.
|
||||||
|
|
@ -413,7 +454,9 @@ namespace cppast
|
||||||
/// The implementation will write whitespace only where necessary,
|
/// The implementation will write whitespace only where necessary,
|
||||||
/// but a newline after each entity.
|
/// but a newline after each entity.
|
||||||
/// This allows customization of formatting.
|
/// This allows customization of formatting.
|
||||||
void generate_code(code_generator& generator, const cpp_entity& e);
|
///
|
||||||
|
/// \returns Whether or not any code was actually written.
|
||||||
|
bool generate_code(code_generator& generator, const cpp_entity& e);
|
||||||
|
|
||||||
/// \exclude
|
/// \exclude
|
||||||
class cpp_template_argument;
|
class cpp_template_argument;
|
||||||
|
|
|
||||||
|
|
@ -48,24 +48,25 @@ namespace
|
||||||
{
|
{
|
||||||
if (need_sep)
|
if (need_sep)
|
||||||
write_sep(output, s);
|
write_sep(output, s);
|
||||||
else
|
need_sep = generate_code(*output.generator(), child);
|
||||||
need_sep = true;
|
|
||||||
generate_code(*output.generator(), child);
|
|
||||||
}
|
}
|
||||||
return need_sep;
|
return need_sep;
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_file(code_generator& generator, const cpp_file& f)
|
bool generate_file(code_generator& generator, const cpp_file& f)
|
||||||
{
|
{
|
||||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(f), true);
|
code_generator::output output(type_safe::ref(generator), type_safe::ref(f), true);
|
||||||
if (output)
|
if (output)
|
||||||
{
|
{
|
||||||
write_container(output, f, newl);
|
auto need_sep = write_container(output, f, newl);
|
||||||
output << newl;
|
if (!need_sep)
|
||||||
|
// file empty, write newl
|
||||||
|
output << newl;
|
||||||
}
|
}
|
||||||
|
return static_cast<bool>(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_macro_definition(code_generator& generator, const cpp_macro_definition& def)
|
bool generate_macro_definition(code_generator& generator, const cpp_macro_definition& def)
|
||||||
{
|
{
|
||||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(def), false);
|
code_generator::output output(type_safe::ref(generator), type_safe::ref(def), false);
|
||||||
if (output)
|
if (output)
|
||||||
|
|
@ -79,9 +80,10 @@ namespace
|
||||||
else
|
else
|
||||||
output << newl;
|
output << newl;
|
||||||
}
|
}
|
||||||
|
return static_cast<bool>(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_include_directive(code_generator& generator, const cpp_include_directive& include)
|
bool generate_include_directive(code_generator& generator, const cpp_include_directive& include)
|
||||||
{
|
{
|
||||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(include), false);
|
code_generator::output output(type_safe::ref(generator), type_safe::ref(include), false);
|
||||||
if (output)
|
if (output)
|
||||||
|
|
@ -98,9 +100,10 @@ namespace
|
||||||
output << preprocessor_token("\"");
|
output << preprocessor_token("\"");
|
||||||
output << newl;
|
output << newl;
|
||||||
}
|
}
|
||||||
|
return static_cast<bool>(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_language_linkage(code_generator& generator, const cpp_language_linkage& linkage)
|
bool generate_language_linkage(code_generator& generator, const cpp_language_linkage& linkage)
|
||||||
{
|
{
|
||||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(linkage), true);
|
code_generator::output output(type_safe::ref(generator), type_safe::ref(linkage), true);
|
||||||
if (output)
|
if (output)
|
||||||
|
|
@ -122,9 +125,10 @@ namespace
|
||||||
generate_code(generator, *linkage.begin());
|
generate_code(generator, *linkage.begin());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return static_cast<bool>(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_namespace(code_generator& generator, const cpp_namespace& ns)
|
bool generate_namespace(code_generator& generator, const cpp_namespace& ns)
|
||||||
{
|
{
|
||||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(ns), true);
|
code_generator::output output(type_safe::ref(generator), type_safe::ref(ns), true);
|
||||||
if (output)
|
if (output)
|
||||||
|
|
@ -140,25 +144,35 @@ namespace
|
||||||
output.unindent();
|
output.unindent();
|
||||||
output << punctuation("}") << newl;
|
output << punctuation("}") << newl;
|
||||||
}
|
}
|
||||||
|
return static_cast<bool>(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_namespace_alias(code_generator& generator, const cpp_namespace_alias& alias)
|
bool generate_namespace_alias(code_generator& generator, const cpp_namespace_alias& alias)
|
||||||
{
|
{
|
||||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(alias), false);
|
code_generator::output output(type_safe::ref(generator), type_safe::ref(alias), false);
|
||||||
if (output)
|
if (output)
|
||||||
|
{
|
||||||
output << keyword("namespace") << whitespace << identifier(alias.name())
|
output << keyword("namespace") << whitespace << identifier(alias.name())
|
||||||
<< punctuation("=") << alias.target() << punctuation(";") << newl;
|
<< punctuation("=");
|
||||||
|
if (output.options() & code_generator::exclude_target)
|
||||||
|
output.excluded(alias);
|
||||||
|
else
|
||||||
|
output << alias.target();
|
||||||
|
output << punctuation(";") << newl;
|
||||||
|
}
|
||||||
|
return static_cast<bool>(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_using_directive(code_generator& generator, const cpp_using_directive& directive)
|
bool generate_using_directive(code_generator& generator, const cpp_using_directive& directive)
|
||||||
{
|
{
|
||||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(directive), false);
|
code_generator::output output(type_safe::ref(generator), type_safe::ref(directive), false);
|
||||||
if (output)
|
if (output)
|
||||||
output << keyword("using") << whitespace << keyword("namespace") << whitespace
|
output << keyword("using") << whitespace << keyword("namespace") << whitespace
|
||||||
<< directive.target() << punctuation(";") << newl;
|
<< directive.target() << punctuation(";") << newl;
|
||||||
|
return static_cast<bool>(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_using_declaration(code_generator& generator,
|
bool generate_using_declaration(code_generator& generator,
|
||||||
const cpp_using_declaration& declaration)
|
const cpp_using_declaration& declaration)
|
||||||
{
|
{
|
||||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(declaration),
|
code_generator::output output(type_safe::ref(generator), type_safe::ref(declaration),
|
||||||
|
|
@ -166,21 +180,26 @@ namespace
|
||||||
if (output)
|
if (output)
|
||||||
output << keyword("using") << whitespace << declaration.target() << punctuation(";")
|
output << keyword("using") << whitespace << declaration.target() << punctuation(";")
|
||||||
<< newl;
|
<< newl;
|
||||||
|
return static_cast<bool>(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_type_alias(code_generator& generator, const cpp_type_alias& alias)
|
bool generate_type_alias(code_generator& generator, const cpp_type_alias& alias)
|
||||||
{
|
{
|
||||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(alias), false);
|
code_generator::output output(type_safe::ref(generator), type_safe::ref(alias), false);
|
||||||
if (output)
|
if (output)
|
||||||
{
|
{
|
||||||
output << keyword("using") << whitespace << identifier(alias.name())
|
output << keyword("using") << whitespace << identifier(alias.name())
|
||||||
<< punctuation("=");
|
<< punctuation("=");
|
||||||
detail::write_type(output, alias.underlying_type(), "");
|
if (output.options() & code_generator::exclude_target)
|
||||||
|
output.excluded(alias);
|
||||||
|
else
|
||||||
|
detail::write_type(output, alias.underlying_type(), "");
|
||||||
output << punctuation(";") << newl;
|
output << punctuation(";") << newl;
|
||||||
}
|
}
|
||||||
|
return static_cast<bool>(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_enum_value(code_generator& generator, const cpp_enum_value& value)
|
bool generate_enum_value(code_generator& generator, const cpp_enum_value& value)
|
||||||
{
|
{
|
||||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(value), false);
|
code_generator::output output(type_safe::ref(generator), type_safe::ref(value), false);
|
||||||
if (output)
|
if (output)
|
||||||
|
|
@ -195,9 +214,10 @@ namespace
|
||||||
.value()); // should have named something differently...
|
.value()); // should have named something differently...
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return static_cast<bool>(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_enum(code_generator& generator, const cpp_enum& e)
|
bool generate_enum(code_generator& generator, const cpp_enum& e)
|
||||||
{
|
{
|
||||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(e), true);
|
code_generator::output output(type_safe::ref(generator), type_safe::ref(e), true);
|
||||||
if (output)
|
if (output)
|
||||||
|
|
@ -229,20 +249,25 @@ namespace
|
||||||
else
|
else
|
||||||
output << punctuation(";") << newl;
|
output << punctuation(";") << newl;
|
||||||
}
|
}
|
||||||
|
return static_cast<bool>(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_access_specifier(code_generator& generator, const cpp_access_specifier& access)
|
void write_access_specifier(code_generator::output& output, cpp_access_specifier_kind access)
|
||||||
|
{
|
||||||
|
output.unindent();
|
||||||
|
output << keyword(to_string(access)) << punctuation(":");
|
||||||
|
output.indent();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool generate_access_specifier(code_generator& generator, const cpp_access_specifier& access)
|
||||||
{
|
{
|
||||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(access), false);
|
code_generator::output output(type_safe::ref(generator), type_safe::ref(access), false);
|
||||||
if (output)
|
if (output)
|
||||||
{
|
write_access_specifier(output, access.access_specifier());
|
||||||
output.unindent();
|
return static_cast<bool>(output);
|
||||||
output << keyword(to_string(access.access_specifier())) << punctuation(":");
|
|
||||||
output.indent(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_base_class(code_generator& generator, const cpp_base_class& base)
|
bool generate_base_class(code_generator& generator, const cpp_base_class& base)
|
||||||
{
|
{
|
||||||
DEBUG_ASSERT(base.parent() && base.parent().value().kind() == cpp_entity_kind::class_t,
|
DEBUG_ASSERT(base.parent() && base.parent().value().kind() == cpp_entity_kind::class_t,
|
||||||
detail::assert_handler{});
|
detail::assert_handler{});
|
||||||
|
|
@ -264,6 +289,7 @@ namespace
|
||||||
|
|
||||||
output << identifier(base.name());
|
output << identifier(base.name());
|
||||||
}
|
}
|
||||||
|
return static_cast<bool>(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_specialization_arguments(code_generator::output& output,
|
void write_specialization_arguments(code_generator::output& output,
|
||||||
|
|
@ -275,7 +301,24 @@ namespace
|
||||||
output << punctuation("<") << token_seq(spec.unexposed_arguments()) << punctuation(">");
|
output << punctuation("<") << token_seq(spec.unexposed_arguments()) << punctuation(">");
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_class(code_generator& generator, const cpp_class& c,
|
void write_bases(code_generator& generator, code_generator::output& output, const cpp_class& c)
|
||||||
|
{
|
||||||
|
auto need_sep = false;
|
||||||
|
auto first = true;
|
||||||
|
for (auto& base : c.bases())
|
||||||
|
{
|
||||||
|
if (first && !output.options(base).is_set(code_generator::exclude))
|
||||||
|
{
|
||||||
|
first = false;
|
||||||
|
output << newl << punctuation(":");
|
||||||
|
}
|
||||||
|
else if (need_sep)
|
||||||
|
output << punctuation(",");
|
||||||
|
need_sep = generate_base_class(generator, base);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool generate_class(code_generator& generator, const cpp_class& c,
|
||||||
type_safe::optional_ref<const cpp_template_specialization> spec = nullptr)
|
type_safe::optional_ref<const cpp_template_specialization> spec = nullptr)
|
||||||
{
|
{
|
||||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(c), true);
|
code_generator::output output(type_safe::ref(generator), type_safe::ref(c), true);
|
||||||
|
|
@ -301,48 +344,33 @@ namespace
|
||||||
output << punctuation(";") << newl;
|
output << punctuation(";") << newl;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (!c.bases().empty())
|
write_bases(generator, output, c);
|
||||||
{
|
|
||||||
output << newl << punctuation(":");
|
|
||||||
|
|
||||||
auto need_sep = false;
|
|
||||||
for (auto& base : c.bases())
|
|
||||||
{
|
|
||||||
if (need_sep)
|
|
||||||
output << punctuation(",");
|
|
||||||
else
|
|
||||||
need_sep = true;
|
|
||||||
generate_base_class(generator, base);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
output << punctuation("{");
|
output << punctuation("{");
|
||||||
output.indent();
|
output.indent();
|
||||||
|
|
||||||
auto need_sep = false;
|
auto need_sep = false;
|
||||||
auto last_access =
|
auto last_access =
|
||||||
c.class_kind() == cpp_class_kind::class_t ? cpp_private : cpp_public;
|
c.class_kind() == cpp_class_kind::class_t ? cpp_private : cpp_public;
|
||||||
|
auto last_written_access = last_access;
|
||||||
for (auto& member : c)
|
for (auto& member : c)
|
||||||
{
|
{
|
||||||
if (member.kind() == cpp_entity_kind::access_specifier_t)
|
if (member.kind() == cpp_entity_kind::access_specifier_t)
|
||||||
{
|
{
|
||||||
auto& access = static_cast<const cpp_access_specifier&>(member);
|
auto& access = static_cast<const cpp_access_specifier&>(member);
|
||||||
if (access.access_specifier() != last_access)
|
last_access = access.access_specifier();
|
||||||
{
|
|
||||||
if (need_sep)
|
|
||||||
output << newl;
|
|
||||||
else
|
|
||||||
need_sep = true;
|
|
||||||
generate_access_specifier(generator, access);
|
|
||||||
last_access = access.access_specifier();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
else if (output.options(member).is_set(code_generator::exclude))
|
||||||
|
continue;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (need_sep)
|
if (need_sep)
|
||||||
output << newl;
|
output << newl;
|
||||||
else
|
if (last_access != last_written_access)
|
||||||
need_sep = true;
|
{
|
||||||
generate_code(generator, member);
|
write_access_specifier(output, last_access);
|
||||||
|
last_written_access = last_access;
|
||||||
|
}
|
||||||
|
need_sep = generate_code(generator, member);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -350,9 +378,10 @@ namespace
|
||||||
output << punctuation("};") << newl;
|
output << punctuation("};") << newl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return static_cast<bool>(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_variable_base(code_generator::output& output, const cpp_variable_base& var,
|
bool write_variable_base(code_generator::output& output, const cpp_variable_base& var,
|
||||||
const std::string& name)
|
const std::string& name)
|
||||||
{
|
{
|
||||||
detail::write_type(output, var.type(), name);
|
detail::write_type(output, var.type(), name);
|
||||||
|
|
@ -362,6 +391,7 @@ namespace
|
||||||
output << punctuation("=");
|
output << punctuation("=");
|
||||||
detail::write_expression(output, var.default_value().value());
|
detail::write_expression(output, var.default_value().value());
|
||||||
}
|
}
|
||||||
|
return static_cast<bool>(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_storage_class(code_generator::output& output, cpp_storage_class_specifiers storage,
|
void write_storage_class(code_generator::output& output, cpp_storage_class_specifiers storage,
|
||||||
|
|
@ -377,7 +407,7 @@ namespace
|
||||||
output << keyword("constexpr") << whitespace;
|
output << keyword("constexpr") << whitespace;
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_variable(code_generator& generator, const cpp_variable& var)
|
bool generate_variable(code_generator& generator, const cpp_variable& var)
|
||||||
{
|
{
|
||||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(var), false);
|
code_generator::output output(type_safe::ref(generator), type_safe::ref(var), false);
|
||||||
if (output)
|
if (output)
|
||||||
|
|
@ -387,9 +417,10 @@ namespace
|
||||||
write_variable_base(output, var, var.name());
|
write_variable_base(output, var, var.name());
|
||||||
output << punctuation(";") << newl;
|
output << punctuation(";") << newl;
|
||||||
}
|
}
|
||||||
|
return static_cast<bool>(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_member_variable(code_generator& generator, const cpp_member_variable& var)
|
bool generate_member_variable(code_generator& generator, const cpp_member_variable& var)
|
||||||
{
|
{
|
||||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(var), false);
|
code_generator::output output(type_safe::ref(generator), type_safe::ref(var), false);
|
||||||
if (output)
|
if (output)
|
||||||
|
|
@ -399,9 +430,10 @@ namespace
|
||||||
write_variable_base(output, var, var.name());
|
write_variable_base(output, var, var.name());
|
||||||
output << punctuation(";") << newl;
|
output << punctuation(";") << newl;
|
||||||
}
|
}
|
||||||
|
return static_cast<bool>(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_bitfield(code_generator& generator, const cpp_bitfield& var)
|
bool generate_bitfield(code_generator& generator, const cpp_bitfield& var)
|
||||||
{
|
{
|
||||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(var), false);
|
code_generator::output output(type_safe::ref(generator), type_safe::ref(var), false);
|
||||||
if (output)
|
if (output)
|
||||||
|
|
@ -412,13 +444,15 @@ namespace
|
||||||
output << punctuation(":") << int_literal(std::to_string(var.no_bits()));
|
output << punctuation(":") << int_literal(std::to_string(var.no_bits()));
|
||||||
output << punctuation(";") << newl;
|
output << punctuation(";") << newl;
|
||||||
}
|
}
|
||||||
|
return static_cast<bool>(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_function_parameter(code_generator& generator, const cpp_function_parameter& param)
|
bool generate_function_parameter(code_generator& generator, const cpp_function_parameter& param)
|
||||||
{
|
{
|
||||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(param), false);
|
code_generator::output output(type_safe::ref(generator), type_safe::ref(param), false);
|
||||||
if (output)
|
if (output)
|
||||||
write_variable_base(output, param, param.name());
|
write_variable_base(output, param, param.name());
|
||||||
|
return static_cast<bool>(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_function_parameters(code_generator::output& output, const cpp_function_base& base)
|
void write_function_parameters(code_generator::output& output, const cpp_function_base& base)
|
||||||
|
|
@ -474,7 +508,7 @@ namespace
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_function(
|
bool generate_function(
|
||||||
code_generator& generator, const cpp_function& func,
|
code_generator& generator, const cpp_function& func,
|
||||||
type_safe::optional_ref<const cpp_template_specialization> spec = nullptr)
|
type_safe::optional_ref<const cpp_template_specialization> spec = nullptr)
|
||||||
{
|
{
|
||||||
|
|
@ -485,7 +519,9 @@ namespace
|
||||||
output << keyword("friend") << whitespace;
|
output << keyword("friend") << whitespace;
|
||||||
write_storage_class(output, func.storage_class(), func.is_constexpr());
|
write_storage_class(output, func.storage_class(), func.is_constexpr());
|
||||||
|
|
||||||
if (detail::is_complex_type(func.return_type()))
|
if (output.options() & code_generator::exclude_return)
|
||||||
|
output.excluded(func) << whitespace;
|
||||||
|
else if (detail::is_complex_type(func.return_type()))
|
||||||
output << keyword("auto") << whitespace;
|
output << keyword("auto") << whitespace;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -504,13 +540,15 @@ namespace
|
||||||
write_function_parameters(output, func);
|
write_function_parameters(output, func);
|
||||||
write_noexcept(output, func, false);
|
write_noexcept(output, func, false);
|
||||||
|
|
||||||
if (detail::is_complex_type(func.return_type()))
|
if (!(output.options() & code_generator::exclude_return)
|
||||||
|
&& detail::is_complex_type(func.return_type()))
|
||||||
{
|
{
|
||||||
output << punctuation("->");
|
output << punctuation("->");
|
||||||
detail::write_type(output, func.return_type(), "");
|
detail::write_type(output, func.return_type(), "");
|
||||||
}
|
}
|
||||||
write_function_body(output, func, false);
|
write_function_body(output, func, false);
|
||||||
}
|
}
|
||||||
|
return static_cast<bool>(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_prefix_virtual(code_generator::output& output, const cpp_virtual& virt)
|
void write_prefix_virtual(code_generator::output& output, const cpp_virtual& virt)
|
||||||
|
|
@ -565,7 +603,7 @@ namespace
|
||||||
return need_ws;
|
return need_ws;
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_member_function(
|
bool generate_member_function(
|
||||||
code_generator& generator, const cpp_member_function& func,
|
code_generator& generator, const cpp_member_function& func,
|
||||||
type_safe::optional_ref<const cpp_template_specialization> spec = nullptr)
|
type_safe::optional_ref<const cpp_template_specialization> spec = nullptr)
|
||||||
{
|
{
|
||||||
|
|
@ -579,7 +617,9 @@ namespace
|
||||||
else
|
else
|
||||||
write_prefix_virtual(output, func.virtual_info());
|
write_prefix_virtual(output, func.virtual_info());
|
||||||
|
|
||||||
if (detail::is_complex_type(func.return_type()))
|
if (output.options() & code_generator::exclude_return)
|
||||||
|
output.excluded(func) << whitespace;
|
||||||
|
else if (detail::is_complex_type(func.return_type()))
|
||||||
output << keyword("auto") << whitespace;
|
output << keyword("auto") << whitespace;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -599,7 +639,8 @@ namespace
|
||||||
auto need_ws = write_cv_ref(output, func);
|
auto need_ws = write_cv_ref(output, func);
|
||||||
write_noexcept(output, func, need_ws);
|
write_noexcept(output, func, need_ws);
|
||||||
|
|
||||||
if (detail::is_complex_type(func.return_type()))
|
if (!(output.options() & code_generator::exclude_return)
|
||||||
|
&& detail::is_complex_type(func.return_type()))
|
||||||
{
|
{
|
||||||
output << punctuation("->");
|
output << punctuation("->");
|
||||||
detail::write_type(output, func.return_type(), "");
|
detail::write_type(output, func.return_type(), "");
|
||||||
|
|
@ -608,9 +649,10 @@ namespace
|
||||||
write_suffix_virtual(output, func.virtual_info());
|
write_suffix_virtual(output, func.virtual_info());
|
||||||
write_function_body(output, func, is_pure(func.virtual_info()));
|
write_function_body(output, func, is_pure(func.virtual_info()));
|
||||||
}
|
}
|
||||||
|
return static_cast<bool>(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_conversion_op(code_generator& generator, const cpp_conversion_op& op)
|
bool generate_conversion_op(code_generator& generator, const cpp_conversion_op& op)
|
||||||
{
|
{
|
||||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(op), true);
|
code_generator::output output(type_safe::ref(generator), type_safe::ref(op), true);
|
||||||
if (output)
|
if (output)
|
||||||
|
|
@ -628,7 +670,11 @@ namespace
|
||||||
|
|
||||||
auto pos = op.name().find("operator");
|
auto pos = op.name().find("operator");
|
||||||
output << identifier(op.name().substr(0u, pos)) << keyword("operator") << whitespace;
|
output << identifier(op.name().substr(0u, pos)) << keyword("operator") << whitespace;
|
||||||
detail::write_type(output, op.return_type(), "");
|
if (output.options() & code_generator::exclude_return)
|
||||||
|
output.excluded(op);
|
||||||
|
else
|
||||||
|
detail::write_type(output, op.return_type(), "");
|
||||||
|
|
||||||
output << punctuation("(") << punctuation(")");
|
output << punctuation("(") << punctuation(")");
|
||||||
auto need_ws = write_cv_ref(output, op);
|
auto need_ws = write_cv_ref(output, op);
|
||||||
write_noexcept(output, op, need_ws);
|
write_noexcept(output, op, need_ws);
|
||||||
|
|
@ -636,9 +682,10 @@ namespace
|
||||||
write_suffix_virtual(output, op.virtual_info());
|
write_suffix_virtual(output, op.virtual_info());
|
||||||
write_function_body(output, op, is_pure(op.virtual_info()));
|
write_function_body(output, op, is_pure(op.virtual_info()));
|
||||||
}
|
}
|
||||||
|
return static_cast<bool>(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_constructor(code_generator& generator, const cpp_constructor& ctor)
|
bool generate_constructor(code_generator& generator, const cpp_constructor& ctor)
|
||||||
{
|
{
|
||||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(ctor), true);
|
code_generator::output output(type_safe::ref(generator), type_safe::ref(ctor), true);
|
||||||
if (output)
|
if (output)
|
||||||
|
|
@ -656,9 +703,10 @@ namespace
|
||||||
|
|
||||||
write_function_body(output, ctor, false);
|
write_function_body(output, ctor, false);
|
||||||
}
|
}
|
||||||
|
return static_cast<bool>(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_destructor(code_generator& generator, const cpp_destructor& dtor)
|
bool generate_destructor(code_generator& generator, const cpp_destructor& dtor)
|
||||||
{
|
{
|
||||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(dtor), true);
|
code_generator::output output(type_safe::ref(generator), type_safe::ref(dtor), true);
|
||||||
if (output)
|
if (output)
|
||||||
|
|
@ -673,35 +721,34 @@ namespace
|
||||||
write_suffix_virtual(output, dtor.virtual_info());
|
write_suffix_virtual(output, dtor.virtual_info());
|
||||||
write_function_body(output, dtor, is_pure(dtor.virtual_info()));
|
write_function_body(output, dtor, is_pure(dtor.virtual_info()));
|
||||||
}
|
}
|
||||||
|
return static_cast<bool>(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_function_base(code_generator& generator, const cpp_function_base& base,
|
bool generate_function_base(code_generator& generator, const cpp_function_base& base,
|
||||||
const cpp_template_specialization& spec)
|
const cpp_template_specialization& spec)
|
||||||
{
|
{
|
||||||
switch (base.kind())
|
switch (base.kind())
|
||||||
{
|
{
|
||||||
case cpp_entity_kind::function_t:
|
case cpp_entity_kind::function_t:
|
||||||
generate_function(generator, static_cast<const cpp_function&>(base),
|
return generate_function(generator, static_cast<const cpp_function&>(base),
|
||||||
type_safe::ref(spec));
|
|
||||||
break;
|
|
||||||
case cpp_entity_kind::member_function_t:
|
|
||||||
generate_member_function(generator, static_cast<const cpp_member_function&>(base),
|
|
||||||
type_safe::ref(spec));
|
type_safe::ref(spec));
|
||||||
break;
|
case cpp_entity_kind::member_function_t:
|
||||||
|
return generate_member_function(generator,
|
||||||
|
static_cast<const cpp_member_function&>(base),
|
||||||
|
type_safe::ref(spec));
|
||||||
case cpp_entity_kind::conversion_op_t:
|
case cpp_entity_kind::conversion_op_t:
|
||||||
generate_conversion_op(generator, static_cast<const cpp_conversion_op&>(base));
|
return generate_conversion_op(generator, static_cast<const cpp_conversion_op&>(base));
|
||||||
break;
|
|
||||||
case cpp_entity_kind::constructor_t:
|
case cpp_entity_kind::constructor_t:
|
||||||
generate_constructor(generator, static_cast<const cpp_constructor&>(base));
|
return generate_constructor(generator, static_cast<const cpp_constructor&>(base));
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
DEBUG_UNREACHABLE(detail::assert_handler{});
|
DEBUG_UNREACHABLE(detail::assert_handler{});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_friend(code_generator& generator, const cpp_friend& f)
|
bool generate_friend(code_generator& generator, const cpp_friend& f)
|
||||||
{
|
{
|
||||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(f), true);
|
code_generator::output output(type_safe::ref(generator), type_safe::ref(f), true);
|
||||||
if (output)
|
if (output)
|
||||||
|
|
@ -717,9 +764,10 @@ namespace
|
||||||
else
|
else
|
||||||
DEBUG_UNREACHABLE(detail::assert_handler{});
|
DEBUG_UNREACHABLE(detail::assert_handler{});
|
||||||
}
|
}
|
||||||
|
return static_cast<bool>(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_template_type_parameter(code_generator& generator,
|
bool generate_template_type_parameter(code_generator& generator,
|
||||||
const cpp_template_type_parameter& param)
|
const cpp_template_type_parameter& param)
|
||||||
{
|
{
|
||||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(param), false);
|
code_generator::output output(type_safe::ref(generator), type_safe::ref(param), false);
|
||||||
|
|
@ -736,9 +784,10 @@ namespace
|
||||||
detail::write_type(output, param.default_type().value(), "");
|
detail::write_type(output, param.default_type().value(), "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return static_cast<bool>(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_non_type_template_parameter(code_generator& generator,
|
bool generate_non_type_template_parameter(code_generator& generator,
|
||||||
const cpp_non_type_template_parameter& param)
|
const cpp_non_type_template_parameter& param)
|
||||||
{
|
{
|
||||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(param), false);
|
code_generator::output output(type_safe::ref(generator), type_safe::ref(param), false);
|
||||||
|
|
@ -751,9 +800,10 @@ namespace
|
||||||
detail::write_expression(output, param.default_value().value());
|
detail::write_expression(output, param.default_value().value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return static_cast<bool>(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_template_template_parameter(code_generator& generator,
|
bool generate_template_template_parameter(code_generator& generator,
|
||||||
const cpp_template_template_parameter& param)
|
const cpp_template_template_parameter& param)
|
||||||
{
|
{
|
||||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(param), true);
|
code_generator::output output(type_safe::ref(generator), type_safe::ref(param), true);
|
||||||
|
|
@ -768,54 +818,68 @@ namespace
|
||||||
if (param.default_template())
|
if (param.default_template())
|
||||||
output << punctuation("=") << param.default_template().value();
|
output << punctuation("=") << param.default_template().value();
|
||||||
}
|
}
|
||||||
|
return static_cast<bool>(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_template_parameters(code_generator::output& output, const cpp_template& templ)
|
void write_template_parameters(code_generator::output& output, const cpp_template& templ,
|
||||||
|
bool hide_if_empty)
|
||||||
{
|
{
|
||||||
output << keyword("template") << punctuation("<");
|
if (!hide_if_empty)
|
||||||
|
output << keyword("template") << punctuation("<");
|
||||||
|
|
||||||
auto need_sep = false;
|
auto need_sep = false;
|
||||||
|
auto first = hide_if_empty;
|
||||||
for (auto& param : templ.parameters())
|
for (auto& param : templ.parameters())
|
||||||
{
|
{
|
||||||
if (need_sep)
|
if (first
|
||||||
|
&& !output.options(*templ.parameters().begin()).is_set(code_generator::exclude))
|
||||||
|
{
|
||||||
|
first = false;
|
||||||
|
output << keyword("template") << punctuation("<");
|
||||||
|
}
|
||||||
|
else if (need_sep)
|
||||||
output << punctuation(",");
|
output << punctuation(",");
|
||||||
else
|
need_sep = generate_code(*output.generator(), param);
|
||||||
need_sep = true;
|
|
||||||
generate_code(*output.generator(), param);
|
|
||||||
}
|
}
|
||||||
output << punctuation(">") << newl;
|
|
||||||
|
if (!hide_if_empty || need_sep)
|
||||||
|
output << punctuation(">") << newl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_alias_template(code_generator& generator, const cpp_alias_template& alias)
|
bool generate_alias_template(code_generator& generator, const cpp_alias_template& alias)
|
||||||
{
|
{
|
||||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(alias), true);
|
code_generator::output output(type_safe::ref(generator), type_safe::ref(alias), true);
|
||||||
if (output)
|
if (output)
|
||||||
{
|
{
|
||||||
write_template_parameters(output, alias);
|
write_template_parameters(output, alias, true);
|
||||||
generate_code(generator, alias.type_alias());
|
generate_code(generator, alias.type_alias());
|
||||||
}
|
}
|
||||||
|
return static_cast<bool>(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_variable_template(code_generator& generator, const cpp_variable_template& var)
|
bool generate_variable_template(code_generator& generator, const cpp_variable_template& var)
|
||||||
{
|
{
|
||||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(var), true);
|
code_generator::output output(type_safe::ref(generator), type_safe::ref(var), true);
|
||||||
if (output)
|
if (output)
|
||||||
{
|
{
|
||||||
write_template_parameters(output, var);
|
write_template_parameters(output, var, true);
|
||||||
generate_code(generator, var.variable());
|
generate_code(generator, var.variable());
|
||||||
}
|
}
|
||||||
|
return static_cast<bool>(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_function_template(code_generator& generator, const cpp_function_template& func)
|
bool generate_function_template(code_generator& generator, const cpp_function_template& func)
|
||||||
{
|
{
|
||||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(func), true);
|
code_generator::output output(type_safe::ref(generator), type_safe::ref(func), true);
|
||||||
if (output)
|
if (output)
|
||||||
{
|
{
|
||||||
write_template_parameters(output, func);
|
write_template_parameters(output, func, true);
|
||||||
generate_code(generator, func.function());
|
generate_code(generator, func.function());
|
||||||
}
|
}
|
||||||
|
return static_cast<bool>(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_function_template_specialization(code_generator& generator,
|
bool generate_function_template_specialization(code_generator& generator,
|
||||||
const cpp_function_template_specialization& func)
|
const cpp_function_template_specialization& func)
|
||||||
{
|
{
|
||||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(func), true);
|
code_generator::output output(type_safe::ref(generator), type_safe::ref(func), true);
|
||||||
|
|
@ -824,33 +888,36 @@ namespace
|
||||||
DEBUG_ASSERT(func.is_full_specialization(), detail::assert_handler{});
|
DEBUG_ASSERT(func.is_full_specialization(), detail::assert_handler{});
|
||||||
if (!is_friended(func))
|
if (!is_friended(func))
|
||||||
// don't write template parameters in friend
|
// don't write template parameters in friend
|
||||||
write_template_parameters(output, func);
|
write_template_parameters(output, func, false);
|
||||||
generate_function_base(generator, func.function(), func);
|
generate_function_base(generator, func.function(), func);
|
||||||
}
|
}
|
||||||
|
return static_cast<bool>(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_class_template(code_generator& generator, const cpp_class_template& templ)
|
bool generate_class_template(code_generator& generator, const cpp_class_template& templ)
|
||||||
{
|
{
|
||||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(templ), true);
|
code_generator::output output(type_safe::ref(generator), type_safe::ref(templ), true);
|
||||||
if (output)
|
if (output)
|
||||||
{
|
{
|
||||||
write_template_parameters(output, templ);
|
write_template_parameters(output, templ, true);
|
||||||
generate_class(generator, templ.class_());
|
generate_class(generator, templ.class_());
|
||||||
}
|
}
|
||||||
|
return static_cast<bool>(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_class_template_specialization(code_generator& generator,
|
bool generate_class_template_specialization(code_generator& generator,
|
||||||
const cpp_class_template_specialization& templ)
|
const cpp_class_template_specialization& templ)
|
||||||
{
|
{
|
||||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(templ), true);
|
code_generator::output output(type_safe::ref(generator), type_safe::ref(templ), true);
|
||||||
if (output)
|
if (output)
|
||||||
{
|
{
|
||||||
write_template_parameters(output, templ);
|
write_template_parameters(output, templ, false);
|
||||||
generate_class(generator, templ.class_(), type_safe::ref(templ));
|
generate_class(generator, templ.class_(), type_safe::ref(templ));
|
||||||
}
|
}
|
||||||
|
return static_cast<bool>(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_static_assert(code_generator& generator, const cpp_static_assert& assert)
|
bool generate_static_assert(code_generator& generator, const cpp_static_assert& assert)
|
||||||
{
|
{
|
||||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(assert), false);
|
code_generator::output output(type_safe::ref(generator), type_safe::ref(assert), false);
|
||||||
if (output)
|
if (output)
|
||||||
|
|
@ -860,24 +927,25 @@ namespace
|
||||||
output << punctuation(",") << string_literal('"' + assert.message() + '"');
|
output << punctuation(",") << string_literal('"' + assert.message() + '"');
|
||||||
output << punctuation(");") << newl;
|
output << punctuation(");") << newl;
|
||||||
}
|
}
|
||||||
|
return static_cast<bool>(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
void generate_unexposed(code_generator& generator, const cpp_unexposed_entity& entity)
|
bool generate_unexposed(code_generator& generator, const cpp_unexposed_entity& entity)
|
||||||
{
|
{
|
||||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(entity), false);
|
code_generator::output output(type_safe::ref(generator), type_safe::ref(entity), false);
|
||||||
if (output)
|
if (output)
|
||||||
output << token_seq(entity.spelling());
|
output << token_seq(entity.spelling());
|
||||||
|
return static_cast<bool>(output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void cppast::generate_code(code_generator& generator, const cpp_entity& e)
|
bool cppast::generate_code(code_generator& generator, const cpp_entity& e)
|
||||||
{
|
{
|
||||||
switch (e.kind())
|
switch (e.kind())
|
||||||
{
|
{
|
||||||
#define CPPAST_DETAIL_HANDLE(Name) \
|
#define CPPAST_DETAIL_HANDLE(Name) \
|
||||||
case cpp_entity_kind::Name##_t: \
|
case cpp_entity_kind::Name##_t: \
|
||||||
generate_##Name(generator, static_cast<const cpp_##Name&>(e)); \
|
return generate_##Name(generator, static_cast<const cpp_##Name&>(e));
|
||||||
break;
|
|
||||||
|
|
||||||
CPPAST_DETAIL_HANDLE(file)
|
CPPAST_DETAIL_HANDLE(file)
|
||||||
|
|
||||||
|
|
@ -926,8 +994,7 @@ void cppast::generate_code(code_generator& generator, const cpp_entity& e)
|
||||||
CPPAST_DETAIL_HANDLE(static_assert)
|
CPPAST_DETAIL_HANDLE(static_assert)
|
||||||
|
|
||||||
case cpp_entity_kind::unexposed_t:
|
case cpp_entity_kind::unexposed_t:
|
||||||
generate_unexposed(generator, static_cast<const cpp_unexposed_entity&>(e));
|
return generate_unexposed(generator, static_cast<const cpp_unexposed_entity&>(e));
|
||||||
break;
|
|
||||||
|
|
||||||
#undef CPPAST_DETAIL_HANDLE
|
#undef CPPAST_DETAIL_HANDLE
|
||||||
|
|
||||||
|
|
@ -935,6 +1002,8 @@ void cppast::generate_code(code_generator& generator, const cpp_entity& e)
|
||||||
DEBUG_UNREACHABLE(detail::assert_handler{});
|
DEBUG_UNREACHABLE(detail::assert_handler{});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void detail::write_template_arguments(code_generator::output& output,
|
void detail::write_template_arguments(code_generator::output& output,
|
||||||
|
|
|
||||||
|
|
@ -6,11 +6,15 @@
|
||||||
|
|
||||||
#include "test_parser.hpp"
|
#include "test_parser.hpp"
|
||||||
|
|
||||||
|
using namespace cppast;
|
||||||
|
|
||||||
TEST_CASE("code_generator")
|
TEST_CASE("code_generator")
|
||||||
{
|
{
|
||||||
// no need to check much here, as each entity check separately
|
SECTION("basic")
|
||||||
// only write some file with equivalent code and synopsis
|
{
|
||||||
auto code = R"(using type=int;
|
// no need to check much here, as each entity check separately
|
||||||
|
// only write some file with equivalent code and synopsis
|
||||||
|
auto code = R"(using type=int;
|
||||||
|
|
||||||
struct foo{
|
struct foo{
|
||||||
int a;
|
int a;
|
||||||
|
|
@ -31,9 +35,135 @@ enum class bar
|
||||||
|
|
||||||
void func(int(*)(int));
|
void func(int(*)(int));
|
||||||
|
|
||||||
extern void(* ptr)(int(*)(int))=&func;
|
extern void(* ptr)(int(*)(int))=&func;)";
|
||||||
|
|
||||||
|
auto file = parse({}, "code_generator.cpp", code);
|
||||||
|
REQUIRE(get_code(*file) == code);
|
||||||
|
}
|
||||||
|
SECTION("exclude target")
|
||||||
|
{
|
||||||
|
auto code = R"(
|
||||||
|
namespace a {}
|
||||||
|
|
||||||
|
namespace b = a;
|
||||||
|
|
||||||
|
using c = int*;
|
||||||
|
typedef int d;)";
|
||||||
|
|
||||||
|
auto synopsis = R"(namespace a{
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace b=excluded;
|
||||||
|
|
||||||
|
using c=excluded;
|
||||||
|
|
||||||
|
using d=excluded;)";
|
||||||
|
|
||||||
|
auto file = parse({}, "code_generator_exclude_target.cpp", code);
|
||||||
|
REQUIRE(get_code(*file, code_generator::exclude_target) == synopsis);
|
||||||
|
}
|
||||||
|
SECTION("exclude return")
|
||||||
|
{
|
||||||
|
auto code = R"(
|
||||||
|
void a();
|
||||||
|
template <typename T>
|
||||||
|
auto b() -> int*;
|
||||||
|
|
||||||
|
struct foo
|
||||||
|
{
|
||||||
|
int c() const&;
|
||||||
|
operator const int ();
|
||||||
|
};
|
||||||
)";
|
)";
|
||||||
|
|
||||||
auto file = parse({}, "code_generator.cpp", code);
|
auto synopsis = R"(excluded a();
|
||||||
REQUIRE(get_code(*file) == code);
|
|
||||||
|
template<typename T>
|
||||||
|
excluded b();
|
||||||
|
|
||||||
|
struct foo{
|
||||||
|
excluded c()const&;
|
||||||
|
|
||||||
|
operator excluded();
|
||||||
|
};)";
|
||||||
|
|
||||||
|
auto file = parse({}, "code_generator_exclude_return.cpp", code);
|
||||||
|
REQUIRE(get_code(*file, code_generator::exclude_return) == synopsis);
|
||||||
|
}
|
||||||
|
SECTION("exclude")
|
||||||
|
{
|
||||||
|
// exclude all entities starting with `e`
|
||||||
|
class exclude_generator : public test_generator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using test_generator::test_generator;
|
||||||
|
|
||||||
|
private:
|
||||||
|
generation_options do_get_options(const cpp_entity& e) override
|
||||||
|
{
|
||||||
|
if (e.name().front() == 'e')
|
||||||
|
return code_generator::exclude;
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
auto code = R"(
|
||||||
|
void e();
|
||||||
|
|
||||||
|
void func(int a, int e, int c);
|
||||||
|
|
||||||
|
template <typename e1, typename e2>
|
||||||
|
void tfunc(int a);
|
||||||
|
|
||||||
|
struct base {};
|
||||||
|
struct e_t {};
|
||||||
|
|
||||||
|
struct bar : e_t, base {};
|
||||||
|
|
||||||
|
class foo : e_t
|
||||||
|
{
|
||||||
|
int a;
|
||||||
|
|
||||||
|
public:
|
||||||
|
int e1;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int b;
|
||||||
|
|
||||||
|
public:
|
||||||
|
int c;
|
||||||
|
int e2;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int e3;
|
||||||
|
};
|
||||||
|
)";
|
||||||
|
|
||||||
|
auto synopsis = R"(void func(int a,int c);
|
||||||
|
|
||||||
|
void tfunc(int a);
|
||||||
|
|
||||||
|
struct base{
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bar
|
||||||
|
:base{
|
||||||
|
};
|
||||||
|
|
||||||
|
class foo{
|
||||||
|
int a;
|
||||||
|
|
||||||
|
int b;
|
||||||
|
|
||||||
|
public:
|
||||||
|
int c;
|
||||||
|
};
|
||||||
|
)";
|
||||||
|
|
||||||
|
auto file = parse({}, "code_generator_exclude.cpp", code);
|
||||||
|
|
||||||
|
exclude_generator generator(code_generator::generation_options{});
|
||||||
|
generate_code(generator, *file);
|
||||||
|
REQUIRE(generator.str() == synopsis);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,12 +45,21 @@ inline std::unique_ptr<cppast::cpp_file> parse(const cppast::cpp_entity_index& i
|
||||||
class test_generator : public cppast::code_generator
|
class test_generator : public cppast::code_generator
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
test_generator(generation_options options) : options_(std::move(options))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
const std::string& str() const noexcept
|
const std::string& str() const noexcept
|
||||||
{
|
{
|
||||||
return str_;
|
return str_;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
generation_options do_get_options(const cppast::cpp_entity&) override
|
||||||
|
{
|
||||||
|
return options_;
|
||||||
|
}
|
||||||
|
|
||||||
void do_indent() override
|
void do_indent() override
|
||||||
{
|
{
|
||||||
++indent_;
|
++indent_;
|
||||||
|
|
@ -78,14 +87,16 @@ private:
|
||||||
was_newline_ = true;
|
was_newline_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string str_;
|
std::string str_;
|
||||||
unsigned indent_ = 0;
|
generation_options options_;
|
||||||
bool was_newline_ = false;
|
unsigned indent_ = 0;
|
||||||
|
bool was_newline_ = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline std::string get_code(const cppast::cpp_entity& e)
|
inline std::string get_code(const cppast::cpp_entity& e,
|
||||||
|
cppast::code_generator::generation_options options = {})
|
||||||
{
|
{
|
||||||
test_generator generator;
|
test_generator generator(options);
|
||||||
cppast::generate_code(generator, e);
|
cppast::generate_code(generator, e);
|
||||||
auto str = generator.str();
|
auto str = generator.str();
|
||||||
if (!str.empty() && str.back() == '\n')
|
if (!str.empty() && str.back() == '\n')
|
||||||
|
|
|
||||||
|
|
@ -78,18 +78,11 @@ void print_entity(std::ostream& out, const cppast::cpp_entity& e)
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// called at the beginning of the code generation of a container entity (i.e. one with child)
|
// called to retrieve the generation options of an entity
|
||||||
synopsis_options on_container_begin(const cppast::cpp_entity&) override
|
generation_options do_get_options(const cppast::cpp_entity&) override
|
||||||
{
|
{
|
||||||
// generate declaration only
|
// generate declaration only
|
||||||
return synopsis_options::declaration;
|
return code_generator::declaration;
|
||||||
}
|
|
||||||
|
|
||||||
// called before code generation of a leaf entity
|
|
||||||
synopsis_options on_leaf(const cppast::cpp_entity&) override
|
|
||||||
{
|
|
||||||
// generate declaration only
|
|
||||||
return synopsis_options::declaration;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// no need to handle indentation, as only a single line is used
|
// no need to handle indentation, as only a single line is used
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue