Add formatting options to code generation
This commit is contained in:
parent
017dbb3114
commit
bb3253220b
4 changed files with 238 additions and 88 deletions
|
|
@ -119,6 +119,27 @@ namespace cppast
|
||||||
{
|
{
|
||||||
} whitespace{};
|
} whitespace{};
|
||||||
|
|
||||||
|
/// Flags that control the code formatting.
|
||||||
|
///
|
||||||
|
/// If a flag is set, it adds additional whitespace.
|
||||||
|
/// If no flags are set, it will only add the whitespace necessary to separate tokens.
|
||||||
|
enum class formatting_flags
|
||||||
|
{
|
||||||
|
brace_nl, //< Set to put the opening braces on a new line.
|
||||||
|
brace_ws, //< Set to put the opening brace at the end of the line after whitespace.
|
||||||
|
|
||||||
|
ptr_ref_var, //< Set to put pointers and references at the variable name (default is type).
|
||||||
|
|
||||||
|
comma_ws, //< Set to put whitespace after a comma.
|
||||||
|
bracket_ws, //< Set to put whitespace inside brackets.
|
||||||
|
operator_ws, //< Set to put whitespace around operators.
|
||||||
|
|
||||||
|
_flag_set_size, //< \exclude
|
||||||
|
};
|
||||||
|
|
||||||
|
/// A set of formatting flags.
|
||||||
|
using formatting = type_safe::flag_set<formatting_flags>;
|
||||||
|
|
||||||
/// Base class to control the code generation.
|
/// Base class to control the code generation.
|
||||||
///
|
///
|
||||||
/// Inherit from it to customize how a [cppast::cpp_entity]() is printed
|
/// Inherit from it to customize how a [cppast::cpp_entity]() is printed
|
||||||
|
|
@ -127,7 +148,9 @@ namespace cppast
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
code_generator(const code_generator&) = delete;
|
code_generator(const code_generator&) = delete;
|
||||||
|
|
||||||
code_generator& operator=(const code_generator&) = delete;
|
code_generator& operator=(const code_generator&) = delete;
|
||||||
|
|
||||||
virtual ~code_generator() noexcept = default;
|
virtual ~code_generator() noexcept = default;
|
||||||
|
|
||||||
/// Flags that control the generation.
|
/// Flags that control the generation.
|
||||||
|
|
@ -178,6 +201,7 @@ namespace cppast
|
||||||
}
|
}
|
||||||
|
|
||||||
output(const output&) = delete;
|
output(const output&) = delete;
|
||||||
|
|
||||||
output& operator=(const output&) = delete;
|
output& operator=(const output&) = delete;
|
||||||
|
|
||||||
/// \returns Whether or not the `on_XXX` function returned something other than `exclude`.
|
/// \returns Whether or not the `on_XXX` function returned something other than `exclude`.
|
||||||
|
|
@ -189,17 +213,23 @@ namespace cppast
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \returns The generation options.
|
/// \returns The generation options.
|
||||||
generation_options options() const noexcept
|
generation_options options() const
|
||||||
{
|
{
|
||||||
return options_;
|
return options_;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \returns The generation options for the given entity.
|
/// \returns The generation options for the given entity.
|
||||||
generation_options options(const cpp_entity& e) const noexcept
|
generation_options options(const cpp_entity& e) const
|
||||||
{
|
{
|
||||||
return gen_->do_get_options(e);
|
return gen_->do_get_options(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \returns The formatting.
|
||||||
|
cppast::formatting formatting() const
|
||||||
|
{
|
||||||
|
return gen_->do_get_formatting();
|
||||||
|
}
|
||||||
|
|
||||||
/// \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
|
||||||
{
|
{
|
||||||
|
|
@ -230,6 +260,13 @@ namespace cppast
|
||||||
gen_->do_unindent();
|
gen_->do_unindent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \effects Calls `func(*this)`.
|
||||||
|
const output& operator<<(void (*func)(const output&)) const
|
||||||
|
{
|
||||||
|
func(*this);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
/// \effects Calls `do_write_keyword()`.
|
/// \effects Calls `do_write_keyword()`.
|
||||||
const output& operator<<(const keyword& k) const
|
const output& operator<<(const keyword& k) const
|
||||||
{
|
{
|
||||||
|
|
@ -337,6 +374,13 @@ namespace cppast
|
||||||
code_generator() noexcept = default;
|
code_generator() noexcept = default;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/// \returns The formatting options that should be used.
|
||||||
|
/// The base class version has no flags set.
|
||||||
|
virtual formatting do_get_formatting() const
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
/// \returns The generation options for that entity.
|
/// \returns The generation options for that entity.
|
||||||
/// The base class version always returns no special options.
|
/// The base class version always returns no special options.
|
||||||
virtual generation_options do_get_options(const cpp_entity& e)
|
virtual generation_options do_get_options(const cpp_entity& e)
|
||||||
|
|
@ -451,9 +495,6 @@ namespace cppast
|
||||||
/// Generates code for the given entity.
|
/// Generates code for the given entity.
|
||||||
///
|
///
|
||||||
/// How the code is generated is customized by the generator.
|
/// How the code is generated is customized by the generator.
|
||||||
/// The implementation will write whitespace only where necessary,
|
|
||||||
/// but a newline after each entity.
|
|
||||||
/// This allows customization of formatting.
|
|
||||||
///
|
///
|
||||||
/// \returns Whether or not any code was actually written.
|
/// \returns Whether or not any code was actually written.
|
||||||
bool generate_code(code_generator& generator, const cpp_entity& e);
|
bool generate_code(code_generator& generator, const cpp_entity& e);
|
||||||
|
|
|
||||||
|
|
@ -28,16 +28,32 @@ using namespace cppast;
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
template <typename Sep>
|
void opening_brace(const code_generator::output& output)
|
||||||
auto write_sep(code_generator::output& output, Sep s) -> decltype(output << s)
|
|
||||||
{
|
{
|
||||||
return output << s;
|
if (output.formatting().is_set(formatting_flags::brace_nl))
|
||||||
|
output << newl;
|
||||||
|
else if (output.formatting().is_set(formatting_flags::brace_ws))
|
||||||
|
output << whitespace;
|
||||||
|
output << punctuation("{");
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Sep>
|
void comma(const code_generator::output& output)
|
||||||
auto write_sep(code_generator::output& output, Sep s) -> decltype(s(output))
|
|
||||||
{
|
{
|
||||||
return s(output);
|
output << punctuation(",");
|
||||||
|
if (output.formatting().is_set(formatting_flags::comma_ws))
|
||||||
|
output << whitespace;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bracket_ws(const code_generator::output& output)
|
||||||
|
{
|
||||||
|
if (output.formatting().is_set(formatting_flags::bracket_ws))
|
||||||
|
output << whitespace;
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator_ws(const code_generator::output& output)
|
||||||
|
{
|
||||||
|
if (output.formatting().is_set(formatting_flags::operator_ws))
|
||||||
|
output << whitespace;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Container, typename Sep>
|
template <class Container, typename Sep>
|
||||||
|
|
@ -47,7 +63,7 @@ namespace
|
||||||
for (auto& child : cont)
|
for (auto& child : cont)
|
||||||
{
|
{
|
||||||
if (need_sep)
|
if (need_sep)
|
||||||
write_sep(output, s);
|
output << s;
|
||||||
need_sep = generate_code(*output.generator(), child);
|
need_sep = generate_code(*output.generator(), child);
|
||||||
}
|
}
|
||||||
return need_sep;
|
return need_sep;
|
||||||
|
|
@ -73,7 +89,8 @@ namespace
|
||||||
{
|
{
|
||||||
output << preprocessor_token("#define") << whitespace << identifier(def.name());
|
output << preprocessor_token("#define") << whitespace << identifier(def.name());
|
||||||
if (def.is_function_like())
|
if (def.is_function_like())
|
||||||
output << preprocessor_token("(") << preprocessor_token(def.parameters().value())
|
output << preprocessor_token("(") << bracket_ws
|
||||||
|
<< preprocessor_token(def.parameters().value()) << bracket_ws
|
||||||
<< preprocessor_token(")");
|
<< preprocessor_token(")");
|
||||||
if (!def.replacement().empty())
|
if (!def.replacement().empty())
|
||||||
output << whitespace << preprocessor_token(def.replacement()) << newl;
|
output << whitespace << preprocessor_token(def.replacement()) << newl;
|
||||||
|
|
@ -111,7 +128,7 @@ namespace
|
||||||
output << keyword("extern") << whitespace << string_literal(linkage.name());
|
output << keyword("extern") << whitespace << string_literal(linkage.name());
|
||||||
if (linkage.is_block())
|
if (linkage.is_block())
|
||||||
{
|
{
|
||||||
output << punctuation("{");
|
output << opening_brace;
|
||||||
output.indent();
|
output.indent();
|
||||||
|
|
||||||
write_container(output, linkage, newl);
|
write_container(output, linkage, newl);
|
||||||
|
|
@ -136,7 +153,7 @@ namespace
|
||||||
if (ns.is_inline())
|
if (ns.is_inline())
|
||||||
output << keyword("inline") << whitespace;
|
output << keyword("inline") << whitespace;
|
||||||
output << keyword("namespace") << whitespace << identifier(ns.name());
|
output << keyword("namespace") << whitespace << identifier(ns.name());
|
||||||
output << punctuation("{");
|
output << opening_brace;
|
||||||
output.indent();
|
output.indent();
|
||||||
|
|
||||||
write_container(output, ns, newl);
|
write_container(output, ns, newl);
|
||||||
|
|
@ -152,8 +169,8 @@ namespace
|
||||||
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()) << operator_ws
|
||||||
<< punctuation("=");
|
<< punctuation("=") << operator_ws;
|
||||||
if (output.options() & code_generator::exclude_target)
|
if (output.options() & code_generator::exclude_target)
|
||||||
output.excluded(alias);
|
output.excluded(alias);
|
||||||
else
|
else
|
||||||
|
|
@ -188,8 +205,8 @@ namespace
|
||||||
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()) << operator_ws
|
||||||
<< punctuation("=");
|
<< punctuation("=") << operator_ws;
|
||||||
if (output.options() & code_generator::exclude_target)
|
if (output.options() & code_generator::exclude_target)
|
||||||
output.excluded(alias);
|
output.excluded(alias);
|
||||||
else
|
else
|
||||||
|
|
@ -207,7 +224,7 @@ namespace
|
||||||
output << identifier(value.name());
|
output << identifier(value.name());
|
||||||
if (value.value())
|
if (value.value())
|
||||||
{
|
{
|
||||||
output << punctuation("=");
|
output << operator_ws << punctuation("=") << operator_ws;
|
||||||
detail::
|
detail::
|
||||||
write_expression(output,
|
write_expression(output,
|
||||||
value.value()
|
value.value()
|
||||||
|
|
@ -228,16 +245,16 @@ namespace
|
||||||
output << whitespace << identifier(e.semantic_scope()) << identifier(e.name());
|
output << whitespace << identifier(e.semantic_scope()) << identifier(e.name());
|
||||||
if (e.has_explicit_type())
|
if (e.has_explicit_type())
|
||||||
{
|
{
|
||||||
output << newl << punctuation(":");
|
output << newl << punctuation(":") << operator_ws;
|
||||||
detail::write_type(output, e.underlying_type(), "");
|
detail::write_type(output, e.underlying_type(), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (output.generate_definition() && e.is_definition())
|
if (output.generate_definition() && e.is_definition())
|
||||||
{
|
{
|
||||||
output << punctuation("{");
|
output << opening_brace;
|
||||||
output.indent();
|
output.indent();
|
||||||
|
|
||||||
auto need_sep = write_container(output, e, [](code_generator::output& out) {
|
auto need_sep = write_container(output, e, [](const code_generator::output& out) {
|
||||||
out << punctuation(",") << newl;
|
out << punctuation(",") << newl;
|
||||||
});
|
});
|
||||||
if (need_sep)
|
if (need_sep)
|
||||||
|
|
@ -298,7 +315,8 @@ namespace
|
||||||
if (spec.arguments_exposed())
|
if (spec.arguments_exposed())
|
||||||
detail::write_template_arguments(output, spec.arguments());
|
detail::write_template_arguments(output, spec.arguments());
|
||||||
else if (!spec.unexposed_arguments().empty())
|
else if (!spec.unexposed_arguments().empty())
|
||||||
output << punctuation("<") << token_seq(spec.unexposed_arguments()) << punctuation(">");
|
output << punctuation("<") << bracket_ws << token_seq(spec.unexposed_arguments())
|
||||||
|
<< bracket_ws << punctuation(">");
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_bases(code_generator& generator, code_generator::output& output, const cpp_class& c)
|
void write_bases(code_generator& generator, code_generator::output& output, const cpp_class& c)
|
||||||
|
|
@ -310,10 +328,10 @@ namespace
|
||||||
if (first && !output.options(base).is_set(code_generator::exclude))
|
if (first && !output.options(base).is_set(code_generator::exclude))
|
||||||
{
|
{
|
||||||
first = false;
|
first = false;
|
||||||
output << newl << punctuation(":");
|
output << newl << punctuation(":") << operator_ws;
|
||||||
}
|
}
|
||||||
else if (need_sep)
|
else if (need_sep)
|
||||||
output << punctuation(",");
|
output << comma;
|
||||||
need_sep = generate_base_class(generator, base);
|
need_sep = generate_base_class(generator, base);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -345,7 +363,7 @@ namespace
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
write_bases(generator, output, c);
|
write_bases(generator, output, c);
|
||||||
output << punctuation("{");
|
output << opening_brace;
|
||||||
output.indent();
|
output.indent();
|
||||||
|
|
||||||
auto need_sep = false;
|
auto need_sep = false;
|
||||||
|
|
@ -388,7 +406,7 @@ namespace
|
||||||
|
|
||||||
if (var.default_value())
|
if (var.default_value())
|
||||||
{
|
{
|
||||||
output << punctuation("=");
|
output << operator_ws << punctuation("=") << operator_ws;
|
||||||
detail::write_expression(output, var.default_value().value());
|
detail::write_expression(output, var.default_value().value());
|
||||||
}
|
}
|
||||||
return static_cast<bool>(output);
|
return static_cast<bool>(output);
|
||||||
|
|
@ -441,7 +459,8 @@ namespace
|
||||||
if (var.is_mutable())
|
if (var.is_mutable())
|
||||||
output << keyword("mutable") << whitespace;
|
output << keyword("mutable") << whitespace;
|
||||||
write_variable_base(output, var, var.name());
|
write_variable_base(output, var, var.name());
|
||||||
output << punctuation(":") << int_literal(std::to_string(var.no_bits()));
|
output << operator_ws << punctuation(":") << operator_ws
|
||||||
|
<< int_literal(std::to_string(var.no_bits()));
|
||||||
output << punctuation(";") << newl;
|
output << punctuation(";") << newl;
|
||||||
}
|
}
|
||||||
return static_cast<bool>(output);
|
return static_cast<bool>(output);
|
||||||
|
|
@ -457,15 +476,15 @@ namespace
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
output << punctuation("(");
|
output << punctuation("(") << bracket_ws;
|
||||||
auto need_sep = write_container(output, base.parameters(), punctuation(","));
|
auto need_sep = write_container(output, base.parameters(), comma);
|
||||||
if (base.is_variadic())
|
if (base.is_variadic())
|
||||||
{
|
{
|
||||||
if (need_sep)
|
if (need_sep)
|
||||||
output << punctuation(",");
|
output << comma;
|
||||||
output << punctuation("...");
|
output << punctuation("...");
|
||||||
}
|
}
|
||||||
output << punctuation(")");
|
output << bracket_ws << punctuation(")");
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_noexcept(code_generator::output& output, const cpp_function_base& base, bool need_ws)
|
void write_noexcept(code_generator::output& output, const cpp_function_base& base, bool need_ws)
|
||||||
|
|
@ -481,9 +500,9 @@ namespace
|
||||||
output << keyword("noexcept");
|
output << keyword("noexcept");
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
output << keyword("noexcept") << punctuation("(");
|
output << keyword("noexcept") << punctuation("(") << bracket_ws;
|
||||||
detail::write_expression(output, cond);
|
detail::write_expression(output, cond);
|
||||||
output << punctuation(")");
|
output << bracket_ws << punctuation(")");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -495,15 +514,17 @@ namespace
|
||||||
case cpp_function_declaration:
|
case cpp_function_declaration:
|
||||||
case cpp_function_definition:
|
case cpp_function_definition:
|
||||||
if (is_pure_virtual)
|
if (is_pure_virtual)
|
||||||
output << punctuation("=") << int_literal("0");
|
output << operator_ws << punctuation("=") << operator_ws << int_literal("0");
|
||||||
output << punctuation(";") << newl;
|
output << punctuation(";") << newl;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case cpp_function_defaulted:
|
case cpp_function_defaulted:
|
||||||
output << punctuation("=") << keyword("default") << punctuation(";") << newl;
|
output << operator_ws << punctuation("=") << operator_ws << keyword("default")
|
||||||
|
<< punctuation(";") << newl;
|
||||||
break;
|
break;
|
||||||
case cpp_function_deleted:
|
case cpp_function_deleted:
|
||||||
output << punctuation("=") << keyword("delete") << punctuation(";") << newl;
|
output << operator_ws << punctuation("=") << operator_ws << keyword("delete")
|
||||||
|
<< punctuation(";") << newl;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -543,7 +564,7 @@ namespace
|
||||||
if (!(output.options() & code_generator::exclude_return)
|
if (!(output.options() & code_generator::exclude_return)
|
||||||
&& detail::is_complex_type(func.return_type()))
|
&& detail::is_complex_type(func.return_type()))
|
||||||
{
|
{
|
||||||
output << punctuation("->");
|
output << operator_ws << punctuation("->") << operator_ws;
|
||||||
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);
|
||||||
|
|
@ -591,11 +612,11 @@ namespace
|
||||||
case cpp_ref_none:
|
case cpp_ref_none:
|
||||||
break;
|
break;
|
||||||
case cpp_ref_lvalue:
|
case cpp_ref_lvalue:
|
||||||
output << punctuation("&");
|
output << operator_ws << punctuation("&") << operator_ws;
|
||||||
need_ws = false;
|
need_ws = false;
|
||||||
break;
|
break;
|
||||||
case cpp_ref_rvalue:
|
case cpp_ref_rvalue:
|
||||||
output << punctuation("&&");
|
output << operator_ws << punctuation("&&") << operator_ws;
|
||||||
need_ws = false;
|
need_ws = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -642,7 +663,7 @@ namespace
|
||||||
if (!(output.options() & code_generator::exclude_return)
|
if (!(output.options() & code_generator::exclude_return)
|
||||||
&& detail::is_complex_type(func.return_type()))
|
&& detail::is_complex_type(func.return_type()))
|
||||||
{
|
{
|
||||||
output << punctuation("->");
|
output << operator_ws << punctuation("->") << operator_ws;
|
||||||
detail::write_type(output, func.return_type(), "");
|
detail::write_type(output, func.return_type(), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -775,12 +796,12 @@ namespace
|
||||||
{
|
{
|
||||||
output << keyword(to_string(param.keyword()));
|
output << keyword(to_string(param.keyword()));
|
||||||
if (param.is_variadic())
|
if (param.is_variadic())
|
||||||
output << punctuation("...");
|
output << operator_ws << punctuation("...");
|
||||||
if (!param.name().empty())
|
if (!param.name().empty())
|
||||||
output << whitespace << identifier(param.name());
|
output << whitespace << identifier(param.name());
|
||||||
if (param.default_type())
|
if (param.default_type())
|
||||||
{
|
{
|
||||||
output << punctuation("=");
|
output << operator_ws << punctuation("=") << operator_ws;
|
||||||
detail::write_type(output, param.default_type().value(), "");
|
detail::write_type(output, param.default_type().value(), "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -796,7 +817,7 @@ namespace
|
||||||
detail::write_type(output, param.type(), param.name(), param.is_variadic());
|
detail::write_type(output, param.type(), param.name(), param.is_variadic());
|
||||||
if (param.default_value())
|
if (param.default_value())
|
||||||
{
|
{
|
||||||
output << punctuation("=");
|
output << operator_ws << punctuation("=") << operator_ws;
|
||||||
detail::write_expression(output, param.default_value().value());
|
detail::write_expression(output, param.default_value().value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -809,14 +830,16 @@ namespace
|
||||||
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);
|
||||||
if (output)
|
if (output)
|
||||||
{
|
{
|
||||||
output << keyword("template") << punctuation("<");
|
output << keyword("template") << operator_ws << punctuation("<") << bracket_ws;
|
||||||
write_container(output, param.parameters(), punctuation(","));
|
write_container(output, param.parameters(), punctuation(","));
|
||||||
output << punctuation(">") << keyword(to_string(param.keyword())) << whitespace;
|
output << bracket_ws << punctuation(">") << operator_ws
|
||||||
|
<< keyword(to_string(param.keyword()));
|
||||||
if (param.is_variadic())
|
if (param.is_variadic())
|
||||||
output << punctuation("...");
|
output << operator_ws << punctuation("...");
|
||||||
output << identifier(param.name());
|
output << whitespace << identifier(param.name());
|
||||||
if (param.default_template())
|
if (param.default_template())
|
||||||
output << punctuation("=") << param.default_template().value();
|
output << operator_ws << punctuation("=") << operator_ws
|
||||||
|
<< param.default_template().value();
|
||||||
}
|
}
|
||||||
return static_cast<bool>(output);
|
return static_cast<bool>(output);
|
||||||
}
|
}
|
||||||
|
|
@ -825,7 +848,7 @@ namespace
|
||||||
bool hide_if_empty)
|
bool hide_if_empty)
|
||||||
{
|
{
|
||||||
if (!hide_if_empty)
|
if (!hide_if_empty)
|
||||||
output << keyword("template") << punctuation("<");
|
output << keyword("template") << operator_ws << punctuation("<") << bracket_ws;
|
||||||
|
|
||||||
auto need_sep = false;
|
auto need_sep = false;
|
||||||
auto first = hide_if_empty;
|
auto first = hide_if_empty;
|
||||||
|
|
@ -835,15 +858,15 @@ namespace
|
||||||
&& !output.options(*templ.parameters().begin()).is_set(code_generator::exclude))
|
&& !output.options(*templ.parameters().begin()).is_set(code_generator::exclude))
|
||||||
{
|
{
|
||||||
first = false;
|
first = false;
|
||||||
output << keyword("template") << punctuation("<");
|
output << keyword("template") << operator_ws << punctuation("<") << bracket_ws;
|
||||||
}
|
}
|
||||||
else if (need_sep)
|
else if (need_sep)
|
||||||
output << punctuation(",");
|
output << comma;
|
||||||
need_sep = generate_code(*output.generator(), param);
|
need_sep = generate_code(*output.generator(), param);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hide_if_empty || need_sep)
|
if (!hide_if_empty || need_sep)
|
||||||
output << punctuation(">") << newl;
|
output << bracket_ws << punctuation(">") << newl;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool generate_alias_template(code_generator& generator, const cpp_alias_template& alias)
|
bool generate_alias_template(code_generator& generator, const cpp_alias_template& alias)
|
||||||
|
|
@ -922,10 +945,10 @@ namespace
|
||||||
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)
|
||||||
{
|
{
|
||||||
output << keyword("static_assert") << punctuation("(");
|
output << keyword("static_assert") << punctuation("(") << bracket_ws;
|
||||||
detail::write_expression(output, assert.expression());
|
detail::write_expression(output, assert.expression());
|
||||||
output << punctuation(",") << string_literal('"' + assert.message() + '"');
|
output << comma << string_literal('"' + assert.message() + '"');
|
||||||
output << punctuation(");") << newl;
|
output << bracket_ws << punctuation(");") << newl;
|
||||||
}
|
}
|
||||||
return static_cast<bool>(output);
|
return static_cast<bool>(output);
|
||||||
}
|
}
|
||||||
|
|
@ -1012,12 +1035,12 @@ void detail::write_template_arguments(code_generator::output&
|
||||||
if (arguments.size() == 0u)
|
if (arguments.size() == 0u)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
output << punctuation("<");
|
output << punctuation("<") << bracket_ws;
|
||||||
auto need_sep = false;
|
auto need_sep = false;
|
||||||
for (auto& arg : arguments)
|
for (auto& arg : arguments)
|
||||||
{
|
{
|
||||||
if (need_sep)
|
if (need_sep)
|
||||||
output << punctuation(",");
|
output << comma;
|
||||||
else
|
else
|
||||||
need_sep = true;
|
need_sep = true;
|
||||||
|
|
||||||
|
|
@ -1030,5 +1053,5 @@ void detail::write_template_arguments(code_generator::output&
|
||||||
else
|
else
|
||||||
DEBUG_UNREACHABLE(detail::assert_handler{});
|
DEBUG_UNREACHABLE(detail::assert_handler{});
|
||||||
}
|
}
|
||||||
output << punctuation(">");
|
output << bracket_ws << punctuation(">");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -190,6 +190,25 @@ bool detail::is_complex_type(const cpp_type& type) noexcept
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
void comma(const code_generator::output& output)
|
||||||
|
{
|
||||||
|
output << punctuation(",");
|
||||||
|
if (output.formatting().is_set(formatting_flags::comma_ws))
|
||||||
|
output << whitespace;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bracket_ws(const code_generator::output& output)
|
||||||
|
{
|
||||||
|
if (output.formatting().is_set(formatting_flags::bracket_ws))
|
||||||
|
output << whitespace;
|
||||||
|
}
|
||||||
|
|
||||||
|
void operator_ws(const code_generator::output& output)
|
||||||
|
{
|
||||||
|
if (output.formatting().is_set(formatting_flags::operator_ws))
|
||||||
|
output << whitespace;
|
||||||
|
}
|
||||||
|
|
||||||
void write_builtin(code_generator::output& output, const cpp_builtin_type& type)
|
void write_builtin(code_generator::output& output, const cpp_builtin_type& type)
|
||||||
{
|
{
|
||||||
output << keyword(to_string(type.builtin_type_kind()));
|
output << keyword(to_string(type.builtin_type_kind()));
|
||||||
|
|
@ -207,14 +226,15 @@ namespace
|
||||||
|
|
||||||
void write_decltype(code_generator::output& output, const cpp_decltype_type& type)
|
void write_decltype(code_generator::output& output, const cpp_decltype_type& type)
|
||||||
{
|
{
|
||||||
output << keyword("decltype") << punctuation("(");
|
output << keyword("decltype") << punctuation("(") << bracket_ws;
|
||||||
detail::write_expression(output, type.expression());
|
detail::write_expression(output, type.expression());
|
||||||
output << punctuation(")");
|
output << bracket_ws << punctuation(")");
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_decltype_auto(code_generator::output& output, const cpp_decltype_auto_type&)
|
void write_decltype_auto(code_generator::output& output, const cpp_decltype_auto_type&)
|
||||||
{
|
{
|
||||||
output << keyword("decltype") << punctuation("(") << keyword("auto") << punctuation(")");
|
output << keyword("decltype") << punctuation("(") << bracket_ws << keyword("auto")
|
||||||
|
<< bracket_ws << punctuation(")");
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_cv_qualified_prefix(code_generator::output& output,
|
void write_cv_qualified_prefix(code_generator::output& output,
|
||||||
|
|
@ -223,7 +243,7 @@ namespace
|
||||||
detail::write_type_prefix(output, type.type());
|
detail::write_type_prefix(output, type.type());
|
||||||
|
|
||||||
if (is_direct_complex(type.type()))
|
if (is_direct_complex(type.type()))
|
||||||
output << punctuation("(");
|
output << punctuation("(") << bracket_ws;
|
||||||
|
|
||||||
if (is_const(type.cv_qualifier()))
|
if (is_const(type.cv_qualifier()))
|
||||||
output << whitespace << keyword("const");
|
output << whitespace << keyword("const");
|
||||||
|
|
@ -235,7 +255,7 @@ namespace
|
||||||
const cpp_cv_qualified_type& type)
|
const cpp_cv_qualified_type& type)
|
||||||
{
|
{
|
||||||
if (is_direct_complex(type.type()))
|
if (is_direct_complex(type.type()))
|
||||||
output << punctuation(")");
|
output << bracket_ws << punctuation(")");
|
||||||
detail::write_type_suffix(output, type.type());
|
detail::write_type_suffix(output, type.type());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -248,8 +268,11 @@ namespace
|
||||||
void write_pointer_prefix(code_generator::output& output, const cpp_pointer_type& type)
|
void write_pointer_prefix(code_generator::output& output, const cpp_pointer_type& type)
|
||||||
{
|
{
|
||||||
detail::write_type_prefix(output, type.pointee());
|
detail::write_type_prefix(output, type.pointee());
|
||||||
|
|
||||||
if (pointer_requires_paren(type))
|
if (pointer_requires_paren(type))
|
||||||
output << punctuation("(");
|
output << punctuation("(") << bracket_ws;
|
||||||
|
else if (output.formatting().is_set(formatting_flags::ptr_ref_var))
|
||||||
|
output << whitespace;
|
||||||
|
|
||||||
output << punctuation("*");
|
output << punctuation("*");
|
||||||
}
|
}
|
||||||
|
|
@ -257,15 +280,18 @@ namespace
|
||||||
void write_pointer_suffix(code_generator::output& output, const cpp_pointer_type& type)
|
void write_pointer_suffix(code_generator::output& output, const cpp_pointer_type& type)
|
||||||
{
|
{
|
||||||
if (pointer_requires_paren(type))
|
if (pointer_requires_paren(type))
|
||||||
output << punctuation(")");
|
output << bracket_ws << punctuation(")");
|
||||||
detail::write_type_suffix(output, type.pointee());
|
detail::write_type_suffix(output, type.pointee());
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_reference_prefix(code_generator::output& output, const cpp_reference_type& type)
|
void write_reference_prefix(code_generator::output& output, const cpp_reference_type& type)
|
||||||
{
|
{
|
||||||
detail::write_type_prefix(output, type.referee());
|
detail::write_type_prefix(output, type.referee());
|
||||||
|
|
||||||
if (is_direct_complex(type.referee()))
|
if (is_direct_complex(type.referee()))
|
||||||
output << punctuation("(");
|
output << punctuation("(") << bracket_ws;
|
||||||
|
else if (output.formatting().is_set(formatting_flags::ptr_ref_var))
|
||||||
|
output << whitespace;
|
||||||
|
|
||||||
if (type.reference_kind() == cpp_ref_lvalue)
|
if (type.reference_kind() == cpp_ref_lvalue)
|
||||||
output << punctuation("&");
|
output << punctuation("&");
|
||||||
|
|
@ -278,7 +304,7 @@ namespace
|
||||||
void write_reference_suffix(code_generator::output& output, const cpp_reference_type& type)
|
void write_reference_suffix(code_generator::output& output, const cpp_reference_type& type)
|
||||||
{
|
{
|
||||||
if (is_direct_complex(type.referee()))
|
if (is_direct_complex(type.referee()))
|
||||||
output << punctuation(")");
|
output << bracket_ws << punctuation(")");
|
||||||
detail::write_type_suffix(output, type.referee());
|
detail::write_type_suffix(output, type.referee());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -291,7 +317,11 @@ namespace
|
||||||
{
|
{
|
||||||
output << punctuation("[");
|
output << punctuation("[");
|
||||||
if (type.size())
|
if (type.size())
|
||||||
|
{
|
||||||
|
output << bracket_ws;
|
||||||
detail::write_expression(output, type.size().value());
|
detail::write_expression(output, type.size().value());
|
||||||
|
output << bracket_ws;
|
||||||
|
}
|
||||||
output << punctuation("]");
|
output << punctuation("]");
|
||||||
detail::write_type_suffix(output, type.value_type());
|
detail::write_type_suffix(output, type.value_type());
|
||||||
}
|
}
|
||||||
|
|
@ -304,13 +334,13 @@ namespace
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void write_parameters(code_generator::output& output, const T& type)
|
void write_parameters(code_generator::output& output, const T& type)
|
||||||
{
|
{
|
||||||
output << punctuation("(");
|
output << punctuation("(") << bracket_ws;
|
||||||
|
|
||||||
auto need_sep = false;
|
auto need_sep = false;
|
||||||
for (auto& param : type.parameter_types())
|
for (auto& param : type.parameter_types())
|
||||||
{
|
{
|
||||||
if (need_sep)
|
if (need_sep)
|
||||||
output << punctuation(",");
|
output << comma;
|
||||||
else
|
else
|
||||||
need_sep = true;
|
need_sep = true;
|
||||||
detail::write_type_prefix(output, param);
|
detail::write_type_prefix(output, param);
|
||||||
|
|
@ -319,11 +349,11 @@ namespace
|
||||||
if (type.is_variadic())
|
if (type.is_variadic())
|
||||||
{
|
{
|
||||||
if (need_sep)
|
if (need_sep)
|
||||||
output << punctuation(",");
|
output << comma;
|
||||||
output << punctuation("...");
|
output << punctuation("...");
|
||||||
}
|
}
|
||||||
|
|
||||||
output << punctuation(")");
|
output << bracket_ws << punctuation(")");
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_function_suffix(code_generator::output& output, const cpp_function_type& type)
|
void write_function_suffix(code_generator::output& output, const cpp_function_type& type)
|
||||||
|
|
@ -361,7 +391,7 @@ namespace
|
||||||
{
|
{
|
||||||
detail::write_type_prefix(output, type.return_type());
|
detail::write_type_prefix(output, type.return_type());
|
||||||
|
|
||||||
output << punctuation("(");
|
output << punctuation("(") << bracket_ws;
|
||||||
detail::write_type_prefix(output, strip_class_type(type.class_type(), nullptr, nullptr));
|
detail::write_type_prefix(output, strip_class_type(type.class_type(), nullptr, nullptr));
|
||||||
output << punctuation("::");
|
output << punctuation("::");
|
||||||
}
|
}
|
||||||
|
|
@ -369,7 +399,7 @@ namespace
|
||||||
void write_member_function_suffix(code_generator::output& output,
|
void write_member_function_suffix(code_generator::output& output,
|
||||||
const cpp_member_function_type& type)
|
const cpp_member_function_type& type)
|
||||||
{
|
{
|
||||||
output << punctuation(")");
|
output << bracket_ws << punctuation(")");
|
||||||
write_parameters(output, type);
|
write_parameters(output, type);
|
||||||
|
|
||||||
auto cv = cpp_cv_none;
|
auto cv = cpp_cv_none;
|
||||||
|
|
@ -384,9 +414,9 @@ namespace
|
||||||
output << keyword("volatile");
|
output << keyword("volatile");
|
||||||
|
|
||||||
if (ref == cpp_ref_lvalue)
|
if (ref == cpp_ref_lvalue)
|
||||||
output << punctuation("&");
|
output << operator_ws << punctuation("&") << operator_ws;
|
||||||
else if (ref == cpp_ref_rvalue)
|
else if (ref == cpp_ref_rvalue)
|
||||||
output << punctuation("&&");
|
output << operator_ws << punctuation("&&") << operator_ws;
|
||||||
|
|
||||||
detail::write_type_suffix(output, type.return_type());
|
detail::write_type_suffix(output, type.return_type());
|
||||||
}
|
}
|
||||||
|
|
@ -395,7 +425,7 @@ namespace
|
||||||
const cpp_member_object_type& type)
|
const cpp_member_object_type& type)
|
||||||
{
|
{
|
||||||
detail::write_type_prefix(output, type.object_type());
|
detail::write_type_prefix(output, type.object_type());
|
||||||
output << punctuation("(");
|
output << punctuation("(") << bracket_ws;
|
||||||
DEBUG_ASSERT(!detail::is_complex_type(type.class_type()), detail::assert_handler{});
|
DEBUG_ASSERT(!detail::is_complex_type(type.class_type()), detail::assert_handler{});
|
||||||
detail::write_type_prefix(output, type.class_type());
|
detail::write_type_prefix(output, type.class_type());
|
||||||
output << punctuation("::");
|
output << punctuation("::");
|
||||||
|
|
@ -403,7 +433,7 @@ namespace
|
||||||
|
|
||||||
void write_member_object_suffix(code_generator::output& output, const cpp_member_object_type&)
|
void write_member_object_suffix(code_generator::output& output, const cpp_member_object_type&)
|
||||||
{
|
{
|
||||||
output << punctuation(")");
|
output << bracket_ws << punctuation(")");
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_template_parameter(code_generator::output& output,
|
void write_template_parameter(code_generator::output& output,
|
||||||
|
|
@ -419,7 +449,8 @@ namespace
|
||||||
if (type.arguments_exposed())
|
if (type.arguments_exposed())
|
||||||
detail::write_template_arguments(output, type.arguments());
|
detail::write_template_arguments(output, type.arguments());
|
||||||
else
|
else
|
||||||
output << punctuation("<") << token_seq(type.unexposed_arguments()) << punctuation(">");
|
output << punctuation("<") << bracket_ws << token_seq(type.unexposed_arguments())
|
||||||
|
<< bracket_ws << punctuation(">");
|
||||||
}
|
}
|
||||||
|
|
||||||
void write_dependent(code_generator::output& output, const cpp_dependent_type& type)
|
void write_dependent(code_generator::output& output, const cpp_dependent_type& type)
|
||||||
|
|
@ -511,6 +542,6 @@ void detail::write_type(code_generator::output& output, const cpp_type& type, st
|
||||||
if (!name.empty())
|
if (!name.empty())
|
||||||
output << whitespace << identifier(name);
|
output << whitespace << identifier(name);
|
||||||
if (is_variadic)
|
if (is_variadic)
|
||||||
output << punctuation("...");
|
output << operator_ws << punctuation("...") << operator_ws;
|
||||||
write_type_suffix(output, type);
|
write_type_suffix(output, type);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,13 +9,16 @@
|
||||||
using namespace cppast;
|
using namespace cppast;
|
||||||
|
|
||||||
TEST_CASE("code_generator")
|
TEST_CASE("code_generator")
|
||||||
{
|
|
||||||
SECTION("basic")
|
|
||||||
{
|
{
|
||||||
// no need to check much here, as each entity check separately
|
// 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;
|
auto code = R"(using type=int;
|
||||||
|
|
||||||
|
type* var;
|
||||||
|
|
||||||
|
template<template<typename>class... T>
|
||||||
|
struct templated{
|
||||||
|
};
|
||||||
|
|
||||||
struct foo{
|
struct foo{
|
||||||
int a;
|
int a;
|
||||||
|
|
||||||
|
|
@ -36,10 +39,62 @@ 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);
|
auto file = parse({}, "code_generator.cpp", code);
|
||||||
|
|
||||||
|
SECTION("basic")
|
||||||
|
{
|
||||||
REQUIRE(get_code(*file) == code);
|
REQUIRE(get_code(*file) == code);
|
||||||
}
|
}
|
||||||
|
SECTION("formatting")
|
||||||
|
{
|
||||||
|
auto synopsis = R"(using type = int;
|
||||||
|
|
||||||
|
type* var;
|
||||||
|
|
||||||
|
template <template <typename> class ... T>
|
||||||
|
struct templated
|
||||||
|
{
|
||||||
|
};
|
||||||
|
|
||||||
|
struct foo
|
||||||
|
{
|
||||||
|
int a;
|
||||||
|
|
||||||
|
auto func(int) -> int(*(*)(int))[42];
|
||||||
|
|
||||||
|
private:
|
||||||
|
int const b = 42;
|
||||||
|
};
|
||||||
|
|
||||||
|
int(*(*(foo::* mptr)(int))(int))[42];
|
||||||
|
|
||||||
|
enum class bar
|
||||||
|
: int
|
||||||
|
{
|
||||||
|
a,
|
||||||
|
b = 42
|
||||||
|
};
|
||||||
|
|
||||||
|
void func(int(*)(int));
|
||||||
|
|
||||||
|
extern void(* ptr)(int(*)(int)) = &func;
|
||||||
|
)";
|
||||||
|
|
||||||
|
class formatted_generator : public test_generator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using test_generator::test_generator;
|
||||||
|
|
||||||
|
private:
|
||||||
|
formatting do_get_formatting() const override
|
||||||
|
{
|
||||||
|
return formatting_flags::brace_nl | formatting_flags::operator_ws
|
||||||
|
| formatting_flags::comma_ws;
|
||||||
|
}
|
||||||
|
} generator(code_generator::generation_options{});
|
||||||
|
generate_code(generator, *file);
|
||||||
|
REQUIRE(generator.str() == synopsis);
|
||||||
|
}
|
||||||
SECTION("exclude target")
|
SECTION("exclude target")
|
||||||
{
|
{
|
||||||
auto code = R"(
|
auto code = R"(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue