Implement code generation
This commit is contained in:
parent
c44e0b512e
commit
d18070a799
29 changed files with 2522 additions and 280 deletions
899
src/code_generator.cpp
Normal file
899
src/code_generator.cpp
Normal file
|
|
@ -0,0 +1,899 @@
|
|||
// Copyright (C) 2017 Jonathan Müller <jonathanmueller.dev@gmail.com>
|
||||
// This file is subject to the license terms in the LICENSE file
|
||||
// found in the top-level directory of this distribution.
|
||||
|
||||
#include <cppast/code_generator.hpp>
|
||||
|
||||
#include <cppast/cpp_alias_template.hpp>
|
||||
#include <cppast/cpp_class.hpp>
|
||||
#include <cppast/cpp_class_template.hpp>
|
||||
#include <cppast/cpp_entity_kind.hpp>
|
||||
#include <cppast/cpp_enum.hpp>
|
||||
#include <cppast/cpp_file.hpp>
|
||||
#include <cppast/cpp_function.hpp>
|
||||
#include <cppast/cpp_function_template.hpp>
|
||||
#include <cppast/cpp_language_linkage.hpp>
|
||||
#include <cppast/cpp_member_function.hpp>
|
||||
#include <cppast/cpp_member_variable.hpp>
|
||||
#include <cppast/cpp_namespace.hpp>
|
||||
#include <cppast/cpp_preprocessor.hpp>
|
||||
#include <cppast/cpp_template_parameter.hpp>
|
||||
#include <cppast/cpp_type_alias.hpp>
|
||||
#include <cppast/cpp_variable.hpp>
|
||||
#include <cppast/cpp_variable_template.hpp>
|
||||
|
||||
using namespace cppast;
|
||||
|
||||
namespace
|
||||
{
|
||||
template <typename Sep>
|
||||
auto write_sep(code_generator::output& output, Sep s) -> decltype(output << s)
|
||||
{
|
||||
return output << s;
|
||||
}
|
||||
|
||||
template <typename Sep>
|
||||
auto write_sep(code_generator::output& output, Sep s) -> decltype(s(output))
|
||||
{
|
||||
return s(output);
|
||||
}
|
||||
|
||||
template <class Container, typename Sep>
|
||||
bool write_container(code_generator::output& output, const Container& cont, Sep s)
|
||||
{
|
||||
auto need_sep = false;
|
||||
for (auto& child : cont)
|
||||
{
|
||||
if (need_sep)
|
||||
write_sep(output, s);
|
||||
else
|
||||
need_sep = true;
|
||||
generate_code(*output.generator(), child);
|
||||
}
|
||||
return need_sep;
|
||||
}
|
||||
|
||||
void generate_file(code_generator& generator, const cpp_file& f)
|
||||
{
|
||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(f), true);
|
||||
if (output)
|
||||
{
|
||||
write_container(output, f, newl);
|
||||
output << newl;
|
||||
}
|
||||
}
|
||||
|
||||
void generate_macro_definition(code_generator& generator, const cpp_macro_definition& def)
|
||||
{
|
||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(def), false);
|
||||
if (output)
|
||||
{
|
||||
output << preprocessor_token("#define") << whitespace << identifier(def.name());
|
||||
if (def.is_function_like())
|
||||
output << preprocessor_token("(") << preprocessor_token(def.parameters().value())
|
||||
<< preprocessor_token(")");
|
||||
if (!def.replacement().empty())
|
||||
output << whitespace << preprocessor_token(def.replacement()) << newl;
|
||||
else
|
||||
output << newl;
|
||||
}
|
||||
}
|
||||
|
||||
void generate_include_directive(code_generator& generator, const cpp_include_directive& include)
|
||||
{
|
||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(include), false);
|
||||
if (output)
|
||||
{
|
||||
output << preprocessor_token("#include") << whitespace;
|
||||
if (include.include_kind() == cpp_include_kind::system)
|
||||
output << preprocessor_token("<");
|
||||
else
|
||||
output << preprocessor_token("\"");
|
||||
output << include.target();
|
||||
if (include.include_kind() == cpp_include_kind::system)
|
||||
output << preprocessor_token(">");
|
||||
else
|
||||
output << preprocessor_token("\"");
|
||||
output << newl;
|
||||
}
|
||||
}
|
||||
|
||||
void generate_language_linkage(code_generator& generator, const cpp_language_linkage& linkage)
|
||||
{
|
||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(linkage), true);
|
||||
if (output)
|
||||
{
|
||||
output << keyword("extern") << whitespace << string_literal(linkage.name());
|
||||
if (linkage.is_block())
|
||||
{
|
||||
output << punctuation("{");
|
||||
output.indent();
|
||||
|
||||
write_container(output, linkage, newl);
|
||||
|
||||
output.unindent();
|
||||
output << punctuation("}") << newl;
|
||||
}
|
||||
else
|
||||
{
|
||||
output << whitespace;
|
||||
generate_code(generator, *linkage.begin());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void generate_namespace(code_generator& generator, const cpp_namespace& ns)
|
||||
{
|
||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(ns), true);
|
||||
if (output)
|
||||
{
|
||||
if (ns.is_inline())
|
||||
output << keyword("inline") << whitespace;
|
||||
output << keyword("namespace") << whitespace << identifier(ns.name());
|
||||
output << punctuation("{");
|
||||
output.indent();
|
||||
|
||||
write_container(output, ns, newl);
|
||||
|
||||
output.unindent();
|
||||
output << punctuation("}") << newl;
|
||||
}
|
||||
}
|
||||
|
||||
void generate_namespace_alias(code_generator& generator, const cpp_namespace_alias& alias)
|
||||
{
|
||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(alias), false);
|
||||
if (output)
|
||||
output << keyword("namespace") << whitespace << identifier(alias.name())
|
||||
<< punctuation("=") << alias.target() << punctuation(";") << newl;
|
||||
}
|
||||
|
||||
void generate_using_directive(code_generator& generator, const cpp_using_directive& directive)
|
||||
{
|
||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(directive), false);
|
||||
if (output)
|
||||
output << keyword("using") << whitespace << keyword("namespace") << whitespace
|
||||
<< directive.target() << punctuation(";") << newl;
|
||||
}
|
||||
|
||||
void generate_using_declaration(code_generator& generator,
|
||||
const cpp_using_declaration& declaration)
|
||||
{
|
||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(declaration),
|
||||
false);
|
||||
if (output)
|
||||
output << keyword("using") << whitespace << declaration.target() << punctuation(";")
|
||||
<< newl;
|
||||
}
|
||||
|
||||
void generate_type_alias(code_generator& generator, const cpp_type_alias& alias)
|
||||
{
|
||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(alias), false);
|
||||
if (output)
|
||||
{
|
||||
output << keyword("using") << whitespace << identifier(alias.name())
|
||||
<< punctuation("=");
|
||||
detail::write_type(output, alias.underlying_type(), "");
|
||||
output << punctuation(";") << newl;
|
||||
}
|
||||
}
|
||||
|
||||
void generate_enum_value(code_generator& generator, const cpp_enum_value& value)
|
||||
{
|
||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(value), false);
|
||||
if (output)
|
||||
{
|
||||
output << identifier(value.name());
|
||||
if (value.value())
|
||||
{
|
||||
output << punctuation("=");
|
||||
detail::
|
||||
write_expression(output,
|
||||
value.value()
|
||||
.value()); // should have named something differently...
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void generate_enum(code_generator& generator, const cpp_enum& e)
|
||||
{
|
||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(e), true);
|
||||
if (output)
|
||||
{
|
||||
output << keyword("enum");
|
||||
if (e.is_scoped())
|
||||
output << whitespace << keyword("class");
|
||||
output << whitespace << identifier(e.name());
|
||||
if (e.underlying_type())
|
||||
{
|
||||
output << newl << punctuation(":");
|
||||
detail::write_type(output, e.underlying_type().value(), "");
|
||||
}
|
||||
|
||||
if (e.is_definition())
|
||||
{
|
||||
output << punctuation("{");
|
||||
output.indent();
|
||||
|
||||
auto need_sep = write_container(output, e, [](code_generator::output& out) {
|
||||
out << punctuation(",") << newl;
|
||||
});
|
||||
if (need_sep)
|
||||
output << newl;
|
||||
|
||||
output.unindent();
|
||||
output << punctuation("};") << newl;
|
||||
}
|
||||
else
|
||||
output << punctuation(";") << newl;
|
||||
}
|
||||
}
|
||||
|
||||
void generate_access_specifier(code_generator& generator, const cpp_access_specifier& access)
|
||||
{
|
||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(access), false);
|
||||
if (output)
|
||||
{
|
||||
output.unindent();
|
||||
output << keyword(to_string(access.access_specifier())) << punctuation(":");
|
||||
output.indent(false);
|
||||
}
|
||||
}
|
||||
|
||||
void generate_base_class(code_generator& generator, const cpp_base_class& base)
|
||||
{
|
||||
DEBUG_ASSERT(base.parent() && base.parent().value().kind() == cpp_entity_kind::class_t,
|
||||
detail::assert_handler{});
|
||||
auto parent_kind = static_cast<const cpp_class&>(base.parent().value()).class_kind();
|
||||
|
||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(base), false);
|
||||
if (output)
|
||||
{
|
||||
if (base.is_virtual())
|
||||
output << keyword("virtual") << whitespace;
|
||||
|
||||
auto access = base.access_specifier();
|
||||
if (access == cpp_protected)
|
||||
output << keyword("protected") << whitespace;
|
||||
else if (access == cpp_private && parent_kind != cpp_class_kind::class_t)
|
||||
output << keyword("private") << whitespace;
|
||||
else if (access == cpp_public && parent_kind == cpp_class_kind::class_t)
|
||||
output << keyword("public") << whitespace;
|
||||
|
||||
output << identifier(base.name());
|
||||
}
|
||||
}
|
||||
|
||||
void write_specialization_arguments(code_generator::output& output,
|
||||
const cpp_template_specialization& spec)
|
||||
{
|
||||
if (spec.arguments_exposed())
|
||||
detail::write_template_arguments(output, spec.arguments());
|
||||
else if (!spec.unexposed_arguments().empty())
|
||||
output << punctuation("<") << token_seq(spec.unexposed_arguments()) << punctuation(">");
|
||||
}
|
||||
|
||||
void generate_class(code_generator& generator, const cpp_class& c,
|
||||
type_safe::optional_ref<const cpp_template_specialization> spec = nullptr)
|
||||
{
|
||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(c), true);
|
||||
if (output)
|
||||
{
|
||||
output << keyword(to_string(c.class_kind())) << whitespace;
|
||||
|
||||
if (spec)
|
||||
{
|
||||
output << spec.value().primary_template();
|
||||
write_specialization_arguments(output, spec.value());
|
||||
}
|
||||
else
|
||||
output << identifier(c.name());
|
||||
|
||||
if (c.is_final())
|
||||
output << whitespace << keyword("final");
|
||||
|
||||
if (c.is_declaration())
|
||||
output << punctuation(";") << newl;
|
||||
else
|
||||
{
|
||||
if (!c.bases().empty())
|
||||
{
|
||||
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.indent();
|
||||
|
||||
auto need_sep = false;
|
||||
auto last_access =
|
||||
c.class_kind() == cpp_class_kind::class_t ? cpp_private : cpp_public;
|
||||
for (auto& member : c)
|
||||
{
|
||||
if (member.kind() == cpp_entity_kind::access_specifier_t)
|
||||
{
|
||||
auto& access = static_cast<const cpp_access_specifier&>(member);
|
||||
if (access.access_specifier() != last_access)
|
||||
{
|
||||
if (need_sep)
|
||||
output << newl;
|
||||
else
|
||||
need_sep = true;
|
||||
generate_access_specifier(generator, access);
|
||||
last_access = access.access_specifier();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (need_sep)
|
||||
output << newl;
|
||||
else
|
||||
need_sep = true;
|
||||
generate_code(generator, member);
|
||||
}
|
||||
}
|
||||
|
||||
output.unindent();
|
||||
output << punctuation("};") << newl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void write_variable_base(code_generator::output& output, const cpp_variable_base& var,
|
||||
const std::string& name)
|
||||
{
|
||||
detail::write_type(output, var.type(), name);
|
||||
|
||||
if (var.default_value())
|
||||
{
|
||||
output << punctuation("=");
|
||||
detail::write_expression(output, var.default_value().value());
|
||||
}
|
||||
}
|
||||
|
||||
void write_storage_class(code_generator::output& output, cpp_storage_class_specifiers storage,
|
||||
bool is_constexpr)
|
||||
{
|
||||
if (is_static(storage))
|
||||
output << keyword("static") << whitespace;
|
||||
if (is_extern(storage))
|
||||
output << keyword("extern") << whitespace;
|
||||
if (is_thread_local(storage))
|
||||
output << keyword("thread_local") << whitespace;
|
||||
if (is_constexpr)
|
||||
output << keyword("constexpr") << whitespace;
|
||||
}
|
||||
|
||||
void generate_variable(code_generator& generator, const cpp_variable& var)
|
||||
{
|
||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(var), false);
|
||||
if (output)
|
||||
{
|
||||
write_storage_class(output, var.storage_class(), var.is_constexpr());
|
||||
|
||||
write_variable_base(output, var, var.name());
|
||||
output << punctuation(";") << newl;
|
||||
}
|
||||
}
|
||||
|
||||
void generate_member_variable(code_generator& generator, const cpp_member_variable& var)
|
||||
{
|
||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(var), false);
|
||||
if (output)
|
||||
{
|
||||
if (var.is_mutable())
|
||||
output << keyword("mutable") << whitespace;
|
||||
write_variable_base(output, var, var.name());
|
||||
output << punctuation(";") << newl;
|
||||
}
|
||||
}
|
||||
|
||||
void generate_bitfield(code_generator& generator, const cpp_bitfield& var)
|
||||
{
|
||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(var), false);
|
||||
if (output)
|
||||
{
|
||||
if (var.is_mutable())
|
||||
output << keyword("mutable") << whitespace;
|
||||
write_variable_base(output, var, var.name());
|
||||
output << punctuation(":") << int_literal(std::to_string(var.no_bits()));
|
||||
output << punctuation(";") << newl;
|
||||
}
|
||||
}
|
||||
|
||||
void generate_function_parameter(code_generator& generator, const cpp_function_parameter& param)
|
||||
{
|
||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(param), false);
|
||||
if (output)
|
||||
write_variable_base(output, param, param.name());
|
||||
}
|
||||
|
||||
void write_function_parameters(code_generator::output& output, const cpp_function_base& base)
|
||||
{
|
||||
output << punctuation("(");
|
||||
auto need_sep = write_container(output, base, punctuation(","));
|
||||
if (base.is_variadic())
|
||||
{
|
||||
if (need_sep)
|
||||
output << punctuation(",");
|
||||
output << punctuation("...");
|
||||
}
|
||||
output << punctuation(")");
|
||||
}
|
||||
|
||||
void write_noexcept(code_generator::output& output, const cpp_function_base& base, bool need_ws)
|
||||
{
|
||||
if (!base.noexcept_condition())
|
||||
return;
|
||||
else if (need_ws)
|
||||
output << whitespace;
|
||||
|
||||
auto& cond = base.noexcept_condition().value();
|
||||
if (cond.kind() == cpp_expression_kind::literal_t
|
||||
&& static_cast<const cpp_literal_expression&>(cond).value() == "true")
|
||||
output << keyword("noexcept");
|
||||
else
|
||||
{
|
||||
output << keyword("noexcept") << punctuation("(");
|
||||
detail::write_expression(output, cond);
|
||||
output << punctuation(")");
|
||||
}
|
||||
}
|
||||
|
||||
void write_function_body(code_generator::output& output, const cpp_function_base& base,
|
||||
bool is_pure_virtual)
|
||||
{
|
||||
switch (base.body_kind())
|
||||
{
|
||||
case cpp_function_declaration:
|
||||
case cpp_function_definition:
|
||||
if (is_pure_virtual)
|
||||
output << punctuation("=") << int_literal("0");
|
||||
output << punctuation(";") << newl;
|
||||
break;
|
||||
|
||||
case cpp_function_defaulted:
|
||||
output << punctuation("=") << keyword("default") << punctuation(";") << newl;
|
||||
break;
|
||||
case cpp_function_deleted:
|
||||
output << punctuation("=") << keyword("delete") << punctuation(";") << newl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void generate_function(
|
||||
code_generator& generator, const cpp_function& func,
|
||||
type_safe::optional_ref<const cpp_template_specialization> spec = nullptr)
|
||||
{
|
||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(func), true);
|
||||
if (output)
|
||||
{
|
||||
if (func.is_friend())
|
||||
output << keyword("friend") << whitespace;
|
||||
write_storage_class(output, func.storage_class(), func.is_constexpr());
|
||||
|
||||
if (detail::is_complex_type(func.return_type()))
|
||||
output << keyword("auto") << whitespace;
|
||||
else
|
||||
{
|
||||
detail::write_type(output, func.return_type(), "");
|
||||
output << whitespace;
|
||||
}
|
||||
|
||||
if (spec)
|
||||
{
|
||||
output << spec.value().primary_template();
|
||||
write_specialization_arguments(output, spec.value());
|
||||
}
|
||||
else
|
||||
output << identifier(func.name());
|
||||
write_function_parameters(output, func);
|
||||
write_noexcept(output, func, false);
|
||||
|
||||
if (detail::is_complex_type(func.return_type()))
|
||||
{
|
||||
output << punctuation("->");
|
||||
detail::write_type(output, func.return_type(), "");
|
||||
}
|
||||
write_function_body(output, func, false);
|
||||
}
|
||||
}
|
||||
|
||||
void write_prefix_virtual(code_generator::output& output, const cpp_virtual& virt)
|
||||
{
|
||||
if (is_virtual(virt))
|
||||
output << keyword("virtual") << whitespace;
|
||||
}
|
||||
|
||||
void write_suffix_virtual(code_generator::output& output, const cpp_virtual& virt)
|
||||
{
|
||||
if (is_overriding(virt))
|
||||
output << whitespace << keyword("override");
|
||||
if (is_final(virt))
|
||||
output << whitespace << keyword("final");
|
||||
}
|
||||
|
||||
bool write_cv_ref(code_generator::output& output, const cpp_member_function_base& base)
|
||||
{
|
||||
auto need_ws = false;
|
||||
switch (base.cv_qualifier())
|
||||
{
|
||||
case cpp_cv_none:
|
||||
break;
|
||||
case cpp_cv_const:
|
||||
output << keyword("const");
|
||||
need_ws = true;
|
||||
break;
|
||||
case cpp_cv_volatile:
|
||||
output << keyword("volatile");
|
||||
need_ws = true;
|
||||
break;
|
||||
case cpp_cv_const_volatile:
|
||||
output << keyword("const") << whitespace << keyword("volatile");
|
||||
need_ws = true;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (base.ref_qualifier())
|
||||
{
|
||||
case cpp_ref_none:
|
||||
break;
|
||||
case cpp_ref_lvalue:
|
||||
output << punctuation("&");
|
||||
need_ws = false;
|
||||
break;
|
||||
case cpp_ref_rvalue:
|
||||
output << punctuation("&&");
|
||||
need_ws = false;
|
||||
break;
|
||||
}
|
||||
|
||||
return need_ws;
|
||||
}
|
||||
|
||||
void generate_member_function(
|
||||
code_generator& generator, const cpp_member_function& func,
|
||||
type_safe::optional_ref<const cpp_template_specialization> spec = nullptr)
|
||||
{
|
||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(func), true);
|
||||
if (output)
|
||||
{
|
||||
if (func.is_constexpr())
|
||||
output << keyword("constexpr") << whitespace;
|
||||
else
|
||||
write_prefix_virtual(output, func.virtual_info());
|
||||
|
||||
if (detail::is_complex_type(func.return_type()))
|
||||
output << keyword("auto") << whitespace;
|
||||
else
|
||||
{
|
||||
detail::write_type(output, func.return_type(), "");
|
||||
output << whitespace;
|
||||
}
|
||||
|
||||
if (spec)
|
||||
{
|
||||
output << spec.value().primary_template();
|
||||
write_specialization_arguments(output, spec.value());
|
||||
}
|
||||
else
|
||||
output << identifier(func.name());
|
||||
write_function_parameters(output, func);
|
||||
auto need_ws = write_cv_ref(output, func);
|
||||
write_noexcept(output, func, need_ws);
|
||||
|
||||
if (detail::is_complex_type(func.return_type()))
|
||||
{
|
||||
output << punctuation("->");
|
||||
detail::write_type(output, func.return_type(), "");
|
||||
}
|
||||
|
||||
write_suffix_virtual(output, func.virtual_info());
|
||||
write_function_body(output, func, is_pure(func.virtual_info()));
|
||||
}
|
||||
}
|
||||
|
||||
void generate_conversion_op(code_generator& generator, const cpp_conversion_op& op)
|
||||
{
|
||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(op), true);
|
||||
if (output)
|
||||
{
|
||||
if (op.is_explicit())
|
||||
output << keyword("explicit") << whitespace;
|
||||
if (op.is_constexpr())
|
||||
output << keyword("constexpr") << whitespace;
|
||||
else
|
||||
write_prefix_virtual(output, op.virtual_info());
|
||||
|
||||
auto pos = op.name().find("operator");
|
||||
output << identifier(op.name().substr(0u, pos)) << keyword("operator") << whitespace;
|
||||
detail::write_type(output, op.return_type(), "");
|
||||
output << punctuation("(") << punctuation(")");
|
||||
auto need_ws = write_cv_ref(output, op);
|
||||
write_noexcept(output, op, need_ws);
|
||||
|
||||
write_suffix_virtual(output, op.virtual_info());
|
||||
write_function_body(output, op, is_pure(op.virtual_info()));
|
||||
}
|
||||
}
|
||||
|
||||
void generate_constructor(code_generator& generator, const cpp_constructor& ctor)
|
||||
{
|
||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(ctor), true);
|
||||
if (output)
|
||||
{
|
||||
if (ctor.is_explicit())
|
||||
output << keyword("explicit") << whitespace;
|
||||
if (ctor.is_constexpr())
|
||||
output << keyword("constexpr") << whitespace;
|
||||
|
||||
output << identifier(ctor.name());
|
||||
write_function_parameters(output, ctor);
|
||||
write_noexcept(output, ctor, false);
|
||||
|
||||
write_function_body(output, ctor, false);
|
||||
}
|
||||
}
|
||||
|
||||
void generate_destructor(code_generator& generator, const cpp_destructor& dtor)
|
||||
{
|
||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(dtor), true);
|
||||
if (output)
|
||||
{
|
||||
write_prefix_virtual(output, dtor.virtual_info());
|
||||
output << identifier(dtor.name()) << punctuation("(") << punctuation(")");
|
||||
write_noexcept(output, dtor, false);
|
||||
|
||||
write_suffix_virtual(output, dtor.virtual_info());
|
||||
write_function_body(output, dtor, is_pure(dtor.virtual_info()));
|
||||
}
|
||||
}
|
||||
|
||||
void generate_function_base(code_generator& generator, const cpp_function_base& base,
|
||||
const cpp_template_specialization& spec)
|
||||
{
|
||||
switch (base.kind())
|
||||
{
|
||||
case cpp_entity_kind::function_t:
|
||||
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));
|
||||
break;
|
||||
case cpp_entity_kind::conversion_op_t:
|
||||
generate_conversion_op(generator, static_cast<const cpp_conversion_op&>(base));
|
||||
break;
|
||||
case cpp_entity_kind::constructor_t:
|
||||
generate_constructor(generator, static_cast<const cpp_constructor&>(base));
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG_UNREACHABLE(detail::assert_handler{});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void generate_template_type_parameter(code_generator& generator,
|
||||
const cpp_template_type_parameter& param)
|
||||
{
|
||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(param), false);
|
||||
if (output)
|
||||
{
|
||||
output << keyword(to_string(param.keyword()));
|
||||
if (param.is_variadic())
|
||||
output << punctuation("...");
|
||||
if (!param.name().empty())
|
||||
output << whitespace << identifier(param.name());
|
||||
if (param.default_type())
|
||||
{
|
||||
output << punctuation("=");
|
||||
detail::write_type(output, param.default_type().value(), "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void generate_non_type_template_parameter(code_generator& generator,
|
||||
const cpp_non_type_template_parameter& param)
|
||||
{
|
||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(param), false);
|
||||
if (output)
|
||||
{
|
||||
detail::write_type(output, param.type(), param.name(), param.is_variadic());
|
||||
if (param.default_value())
|
||||
{
|
||||
output << punctuation("=");
|
||||
detail::write_expression(output, param.default_value().value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void generate_template_template_parameter(code_generator& generator,
|
||||
const cpp_template_template_parameter& param)
|
||||
{
|
||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(param), true);
|
||||
if (output)
|
||||
{
|
||||
output << keyword("template") << punctuation("<");
|
||||
write_container(output, param, punctuation(","));
|
||||
output << punctuation(">") << keyword(to_string(param.keyword())) << whitespace;
|
||||
if (param.is_variadic())
|
||||
output << punctuation("...");
|
||||
output << identifier(param.name());
|
||||
if (param.default_template())
|
||||
output << punctuation("=") << param.default_template().value();
|
||||
}
|
||||
}
|
||||
|
||||
void write_template_parameters(code_generator::output& output, const cpp_template& templ)
|
||||
{
|
||||
output << keyword("template") << punctuation("<");
|
||||
auto need_sep = false;
|
||||
for (auto& param : templ.parameters())
|
||||
{
|
||||
if (need_sep)
|
||||
output << punctuation(",");
|
||||
else
|
||||
need_sep = true;
|
||||
generate_code(*output.generator(), param);
|
||||
}
|
||||
output << punctuation(">") << newl;
|
||||
}
|
||||
|
||||
void generate_alias_template(code_generator& generator, const cpp_alias_template& alias)
|
||||
{
|
||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(alias), true);
|
||||
if (output)
|
||||
{
|
||||
write_template_parameters(output, alias);
|
||||
generate_code(generator, alias.type_alias());
|
||||
}
|
||||
}
|
||||
|
||||
void generate_variable_template(code_generator& generator, const cpp_variable_template& var)
|
||||
{
|
||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(var), true);
|
||||
if (output)
|
||||
{
|
||||
write_template_parameters(output, var);
|
||||
generate_code(generator, var.variable());
|
||||
}
|
||||
}
|
||||
|
||||
void generate_function_template(code_generator& generator, const cpp_function_template& func)
|
||||
{
|
||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(func), true);
|
||||
if (output)
|
||||
{
|
||||
write_template_parameters(output, func);
|
||||
generate_code(generator, func.function());
|
||||
}
|
||||
}
|
||||
|
||||
void generate_function_template_specialization(code_generator& generator,
|
||||
const cpp_function_template_specialization& func)
|
||||
{
|
||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(func), true);
|
||||
if (output)
|
||||
{
|
||||
write_template_parameters(output, func);
|
||||
generate_function_base(generator, func.function(), func);
|
||||
}
|
||||
}
|
||||
|
||||
void generate_class_template(code_generator& generator, const cpp_class_template& templ)
|
||||
{
|
||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(templ), true);
|
||||
if (output)
|
||||
{
|
||||
write_template_parameters(output, templ);
|
||||
generate_class(generator, templ.class_());
|
||||
}
|
||||
}
|
||||
|
||||
void generate_class_template_specialization(code_generator& generator,
|
||||
const cpp_class_template_specialization& templ)
|
||||
{
|
||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(templ), true);
|
||||
if (output)
|
||||
{
|
||||
write_template_parameters(output, templ);
|
||||
generate_class(generator, templ.class_(), type_safe::ref(templ));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cppast::generate_code(code_generator& generator, const cpp_entity& e)
|
||||
{
|
||||
switch (e.kind())
|
||||
{
|
||||
#define CPPAST_DETAIL_HANDLE(Name) \
|
||||
case cpp_entity_kind::Name##_t: \
|
||||
generate_##Name(generator, static_cast<const cpp_##Name&>(e)); \
|
||||
break;
|
||||
|
||||
CPPAST_DETAIL_HANDLE(file)
|
||||
|
||||
CPPAST_DETAIL_HANDLE(macro_definition)
|
||||
CPPAST_DETAIL_HANDLE(include_directive)
|
||||
|
||||
CPPAST_DETAIL_HANDLE(language_linkage)
|
||||
CPPAST_DETAIL_HANDLE(namespace)
|
||||
CPPAST_DETAIL_HANDLE(namespace_alias)
|
||||
CPPAST_DETAIL_HANDLE(using_directive)
|
||||
CPPAST_DETAIL_HANDLE(using_declaration)
|
||||
|
||||
CPPAST_DETAIL_HANDLE(type_alias)
|
||||
|
||||
CPPAST_DETAIL_HANDLE(enum)
|
||||
CPPAST_DETAIL_HANDLE(enum_value)
|
||||
|
||||
CPPAST_DETAIL_HANDLE(class)
|
||||
CPPAST_DETAIL_HANDLE(access_specifier)
|
||||
CPPAST_DETAIL_HANDLE(base_class)
|
||||
|
||||
CPPAST_DETAIL_HANDLE(variable)
|
||||
CPPAST_DETAIL_HANDLE(member_variable)
|
||||
CPPAST_DETAIL_HANDLE(bitfield)
|
||||
|
||||
CPPAST_DETAIL_HANDLE(function_parameter)
|
||||
CPPAST_DETAIL_HANDLE(function)
|
||||
CPPAST_DETAIL_HANDLE(member_function)
|
||||
CPPAST_DETAIL_HANDLE(conversion_op)
|
||||
CPPAST_DETAIL_HANDLE(constructor)
|
||||
CPPAST_DETAIL_HANDLE(destructor)
|
||||
|
||||
CPPAST_DETAIL_HANDLE(template_type_parameter)
|
||||
CPPAST_DETAIL_HANDLE(non_type_template_parameter)
|
||||
CPPAST_DETAIL_HANDLE(template_template_parameter)
|
||||
|
||||
CPPAST_DETAIL_HANDLE(alias_template)
|
||||
CPPAST_DETAIL_HANDLE(variable_template)
|
||||
CPPAST_DETAIL_HANDLE(function_template)
|
||||
CPPAST_DETAIL_HANDLE(function_template_specialization)
|
||||
CPPAST_DETAIL_HANDLE(class_template)
|
||||
CPPAST_DETAIL_HANDLE(class_template_specialization)
|
||||
|
||||
#undef CPPAST_DETAIL_HANDLE
|
||||
|
||||
case cpp_entity_kind::count:
|
||||
DEBUG_UNREACHABLE(detail::assert_handler{});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void detail::write_template_arguments(code_generator::output& output,
|
||||
type_safe::array_ref<const cpp_template_argument> arguments)
|
||||
{
|
||||
if (arguments.size() == 0u)
|
||||
return;
|
||||
|
||||
output << punctuation("<");
|
||||
auto need_sep = false;
|
||||
for (auto& arg : arguments)
|
||||
{
|
||||
if (need_sep)
|
||||
output << punctuation(",");
|
||||
else
|
||||
need_sep = true;
|
||||
|
||||
if (auto type = arg.type())
|
||||
detail::write_type(output, type.value(), "");
|
||||
else if (auto expr = arg.expression())
|
||||
detail::write_expression(output, expr.value());
|
||||
else if (auto templ = arg.template_ref())
|
||||
output << templ.value();
|
||||
else
|
||||
DEBUG_UNREACHABLE(detail::assert_handler{});
|
||||
}
|
||||
output << punctuation(">");
|
||||
}
|
||||
93
src/cpp_expression.cpp
Normal file
93
src/cpp_expression.cpp
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
// Copyright (C) 2017 Jonathan Müller <jonathanmueller.dev@gmail.com>
|
||||
// This file is subject to the license terms in the LICENSE file
|
||||
// found in the top-level directory of this distribution.
|
||||
|
||||
#include <cppast/cpp_expression.hpp>
|
||||
|
||||
using namespace cppast;
|
||||
|
||||
namespace
|
||||
{
|
||||
void write_literal(code_generator::output& output, const cpp_literal_expression& expr)
|
||||
{
|
||||
auto type_kind = cpp_void;
|
||||
if (expr.type().kind() == cpp_type_kind::builtin_t)
|
||||
type_kind = static_cast<const cpp_builtin_type&>(expr.type()).builtin_type_kind();
|
||||
else if (expr.type().kind() == cpp_type_kind::pointer_t)
|
||||
{
|
||||
auto& pointee = static_cast<const cpp_pointer_type&>(expr.type()).pointee();
|
||||
if (pointee.kind() == cpp_type_kind::builtin_t)
|
||||
{
|
||||
auto& builtin_pointee = static_cast<const cpp_builtin_type&>(pointee);
|
||||
if (builtin_pointee.builtin_type_kind() == cpp_char
|
||||
|| builtin_pointee.builtin_type_kind() == cpp_wchar
|
||||
|| builtin_pointee.builtin_type_kind() == cpp_char16
|
||||
|| builtin_pointee.builtin_type_kind() == cpp_char32)
|
||||
// pointer to char aka string
|
||||
type_kind = builtin_pointee.builtin_type_kind();
|
||||
}
|
||||
}
|
||||
|
||||
switch (type_kind)
|
||||
{
|
||||
case cpp_void:
|
||||
output << token_seq(expr.value());
|
||||
break;
|
||||
|
||||
case cpp_bool:
|
||||
output << keyword(expr.value());
|
||||
break;
|
||||
|
||||
case cpp_uchar:
|
||||
case cpp_ushort:
|
||||
case cpp_uint:
|
||||
case cpp_ulong:
|
||||
case cpp_ulonglong:
|
||||
case cpp_uint128:
|
||||
case cpp_schar:
|
||||
case cpp_short:
|
||||
case cpp_int:
|
||||
case cpp_long:
|
||||
case cpp_longlong:
|
||||
case cpp_int128:
|
||||
output << int_literal(expr.value());
|
||||
break;
|
||||
|
||||
case cpp_float:
|
||||
case cpp_double:
|
||||
case cpp_longdouble:
|
||||
case cpp_float128:
|
||||
output << float_literal(expr.value());
|
||||
break;
|
||||
|
||||
case cpp_char:
|
||||
case cpp_wchar:
|
||||
case cpp_char16:
|
||||
case cpp_char32:
|
||||
output << string_literal(expr.value());
|
||||
break;
|
||||
|
||||
case cpp_nullptr:
|
||||
output << keyword(expr.value());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void write_unexposed(code_generator::output& output, const cpp_unexposed_expression& expr)
|
||||
{
|
||||
output << token_seq(expr.expression());
|
||||
}
|
||||
}
|
||||
|
||||
void detail::write_expression(code_generator::output& output, const cpp_expression& expr)
|
||||
{
|
||||
switch (expr.kind())
|
||||
{
|
||||
case cpp_expression_kind::literal_t:
|
||||
write_literal(output, static_cast<const cpp_literal_expression&>(expr));
|
||||
break;
|
||||
case cpp_expression_kind::unexposed_t:
|
||||
write_unexposed(output, static_cast<const cpp_unexposed_expression&>(expr));
|
||||
break;
|
||||
}
|
||||
}
|
||||
380
src/cpp_type.cpp
380
src/cpp_type.cpp
|
|
@ -5,6 +5,7 @@
|
|||
#include <cppast/cpp_type.hpp>
|
||||
|
||||
#include <cppast/cpp_array_type.hpp>
|
||||
#include <cppast/cpp_decltype_type.hpp>
|
||||
#include <cppast/cpp_entity.hpp>
|
||||
#include <cppast/cpp_entity_kind.hpp>
|
||||
#include <cppast/cpp_function_type.hpp>
|
||||
|
|
@ -91,3 +92,382 @@ std::unique_ptr<cpp_dependent_type> cpp_dependent_type::build(
|
|||
return std::unique_ptr<cpp_dependent_type>(
|
||||
new cpp_dependent_type(std::move(name), std::move(dependee)));
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
// is directly a complex type
|
||||
// is_complex_type also checks for children
|
||||
bool is_direct_complex(const cpp_type& type) noexcept
|
||||
{
|
||||
switch (type.kind())
|
||||
{
|
||||
case cpp_type_kind::builtin_t:
|
||||
case cpp_type_kind::user_defined_t:
|
||||
case cpp_type_kind::auto_t:
|
||||
case cpp_type_kind::decltype_t:
|
||||
case cpp_type_kind::decltype_auto_t:
|
||||
case cpp_type_kind::cv_qualified_t:
|
||||
case cpp_type_kind::pointer_t:
|
||||
case cpp_type_kind::reference_t:
|
||||
case cpp_type_kind::template_parameter_t:
|
||||
case cpp_type_kind::template_instantiation_t:
|
||||
case cpp_type_kind::dependent_t:
|
||||
case cpp_type_kind::unexposed_t:
|
||||
return false;
|
||||
|
||||
case cpp_type_kind::array_t:
|
||||
case cpp_type_kind::function_t:
|
||||
case cpp_type_kind::member_function_t:
|
||||
case cpp_type_kind::member_object_t:
|
||||
return true;
|
||||
}
|
||||
|
||||
DEBUG_UNREACHABLE(detail::assert_handler{});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool detail::is_complex_type(const cpp_type& type) noexcept
|
||||
{
|
||||
switch (type.kind())
|
||||
{
|
||||
case cpp_type_kind::cv_qualified_t:
|
||||
return is_complex_type(static_cast<const cpp_cv_qualified_type&>(type).type());
|
||||
case cpp_type_kind::pointer_t:
|
||||
return is_complex_type(static_cast<const cpp_pointer_type&>(type).pointee());
|
||||
case cpp_type_kind::reference_t:
|
||||
return is_complex_type(static_cast<const cpp_reference_type&>(type).referee());
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return is_direct_complex(type);
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
void write_builtin(code_generator::output& output, const cpp_builtin_type& type)
|
||||
{
|
||||
output << keyword(to_string(type.builtin_type_kind()));
|
||||
}
|
||||
|
||||
void write_user_defined(code_generator::output& output, const cpp_user_defined_type& type)
|
||||
{
|
||||
output << type.entity();
|
||||
}
|
||||
|
||||
void write_auto(code_generator::output& output, const cpp_auto_type&)
|
||||
{
|
||||
output << keyword("auto");
|
||||
}
|
||||
|
||||
void write_decltype(code_generator::output& output, const cpp_decltype_type& type)
|
||||
{
|
||||
output << keyword("decltype") << punctuation("(");
|
||||
detail::write_expression(output, type.expression());
|
||||
output << punctuation(")");
|
||||
}
|
||||
|
||||
void write_decltype_auto(code_generator::output& output, const cpp_decltype_auto_type&)
|
||||
{
|
||||
output << keyword("decltype") << punctuation("(") << keyword("auto") << punctuation(")");
|
||||
}
|
||||
|
||||
void write_cv_qualified_prefix(code_generator::output& output,
|
||||
const cpp_cv_qualified_type& type)
|
||||
{
|
||||
detail::write_type_prefix(output, type.type());
|
||||
|
||||
if (is_direct_complex(type.type()))
|
||||
output << punctuation("(");
|
||||
|
||||
if (is_const(type.cv_qualifier()))
|
||||
output << whitespace << keyword("const");
|
||||
if (is_volatile(type.cv_qualifier()))
|
||||
output << whitespace << keyword("volatile");
|
||||
}
|
||||
|
||||
void write_cv_qualified_suffix(code_generator::output& output,
|
||||
const cpp_cv_qualified_type& type)
|
||||
{
|
||||
if (is_direct_complex(type.type()))
|
||||
output << punctuation(")");
|
||||
detail::write_type_suffix(output, type.type());
|
||||
}
|
||||
|
||||
bool pointer_requires_paren(const cpp_pointer_type& type)
|
||||
{
|
||||
auto kind = type.pointee().kind();
|
||||
return kind == cpp_type_kind::function_t || kind == cpp_type_kind::array_t;
|
||||
}
|
||||
|
||||
void write_pointer_prefix(code_generator::output& output, const cpp_pointer_type& type)
|
||||
{
|
||||
detail::write_type_prefix(output, type.pointee());
|
||||
if (pointer_requires_paren(type))
|
||||
output << punctuation("(");
|
||||
|
||||
output << punctuation("*");
|
||||
}
|
||||
|
||||
void write_pointer_suffix(code_generator::output& output, const cpp_pointer_type& type)
|
||||
{
|
||||
if (pointer_requires_paren(type))
|
||||
output << punctuation(")");
|
||||
detail::write_type_suffix(output, type.pointee());
|
||||
}
|
||||
|
||||
void write_reference_prefix(code_generator::output& output, const cpp_reference_type& type)
|
||||
{
|
||||
detail::write_type_prefix(output, type.referee());
|
||||
if (is_direct_complex(type.referee()))
|
||||
output << punctuation("(");
|
||||
|
||||
if (type.reference_kind() == cpp_ref_lvalue)
|
||||
output << punctuation("&");
|
||||
else if (type.reference_kind() == cpp_ref_rvalue)
|
||||
output << punctuation("&&");
|
||||
else
|
||||
DEBUG_UNREACHABLE(detail::assert_handler{});
|
||||
}
|
||||
|
||||
void write_reference_suffix(code_generator::output& output, const cpp_reference_type& type)
|
||||
{
|
||||
if (is_direct_complex(type.referee()))
|
||||
output << punctuation(")");
|
||||
detail::write_type_suffix(output, type.referee());
|
||||
}
|
||||
|
||||
void write_array_prefix(code_generator::output& output, const cpp_array_type& type)
|
||||
{
|
||||
detail::write_type_prefix(output, type.value_type());
|
||||
}
|
||||
|
||||
void write_array_suffix(code_generator::output& output, const cpp_array_type& type)
|
||||
{
|
||||
output << punctuation("[");
|
||||
if (type.size())
|
||||
detail::write_expression(output, type.size().value());
|
||||
output << punctuation("]");
|
||||
detail::write_type_suffix(output, type.value_type());
|
||||
}
|
||||
|
||||
void write_function_prefix(code_generator::output& output, const cpp_function_type& type)
|
||||
{
|
||||
detail::write_type_prefix(output, type.return_type());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void write_parameters(code_generator::output& output, const T& type)
|
||||
{
|
||||
output << punctuation("(");
|
||||
|
||||
auto need_sep = false;
|
||||
for (auto& param : type.parameter_types())
|
||||
{
|
||||
if (need_sep)
|
||||
output << punctuation(",");
|
||||
else
|
||||
need_sep = true;
|
||||
detail::write_type_prefix(output, param);
|
||||
detail::write_type_suffix(output, param);
|
||||
}
|
||||
if (type.is_variadic())
|
||||
{
|
||||
if (need_sep)
|
||||
output << punctuation(",");
|
||||
output << punctuation("...");
|
||||
}
|
||||
|
||||
output << punctuation(")");
|
||||
}
|
||||
|
||||
void write_function_suffix(code_generator::output& output, const cpp_function_type& type)
|
||||
{
|
||||
write_parameters(output, type);
|
||||
|
||||
detail::write_type_suffix(output, type.return_type());
|
||||
}
|
||||
|
||||
const cpp_type& strip_class_type(const cpp_type& type, cpp_cv* cv, cpp_reference* ref)
|
||||
{
|
||||
if (type.kind() == cpp_type_kind::cv_qualified_t)
|
||||
{
|
||||
auto& cv_qual = static_cast<const cpp_cv_qualified_type&>(type);
|
||||
if (cv)
|
||||
*cv = cv_qual.cv_qualifier();
|
||||
return strip_class_type(cv_qual.type(), cv, ref);
|
||||
}
|
||||
else if (type.kind() == cpp_type_kind::reference_t)
|
||||
{
|
||||
auto& ref_type = static_cast<const cpp_reference_type&>(type);
|
||||
if (ref)
|
||||
*ref = ref_type.reference_kind();
|
||||
return strip_class_type(ref_type.referee(), cv, ref);
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_ASSERT(!detail::is_complex_type(type), detail::assert_handler{});
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
void write_member_function_prefix(code_generator::output& output,
|
||||
const cpp_member_function_type& type)
|
||||
{
|
||||
detail::write_type_prefix(output, type.return_type());
|
||||
|
||||
output << punctuation("(");
|
||||
detail::write_type_prefix(output, strip_class_type(type.class_type(), nullptr, nullptr));
|
||||
output << punctuation("::");
|
||||
}
|
||||
|
||||
void write_member_function_suffix(code_generator::output& output,
|
||||
const cpp_member_function_type& type)
|
||||
{
|
||||
output << punctuation(")");
|
||||
write_parameters(output, type);
|
||||
|
||||
auto cv = cpp_cv_none;
|
||||
auto ref = cpp_ref_none;
|
||||
strip_class_type(type.class_type(), &cv, &ref);
|
||||
|
||||
if (cv == cpp_cv_const_volatile)
|
||||
output << keyword("const") << whitespace << keyword("volatile");
|
||||
else if (is_const(cv))
|
||||
output << keyword("const");
|
||||
else if (is_volatile(cv))
|
||||
output << keyword("volatile");
|
||||
|
||||
if (ref == cpp_ref_lvalue)
|
||||
output << punctuation("&");
|
||||
else if (ref == cpp_ref_rvalue)
|
||||
output << punctuation("&&");
|
||||
|
||||
detail::write_type_suffix(output, type.return_type());
|
||||
}
|
||||
|
||||
void write_member_object_prefix(code_generator::output& output,
|
||||
const cpp_member_object_type& type)
|
||||
{
|
||||
detail::write_type_prefix(output, type.object_type());
|
||||
output << punctuation("(");
|
||||
DEBUG_ASSERT(!detail::is_complex_type(type.class_type()), detail::assert_handler{});
|
||||
detail::write_type_prefix(output, type.class_type());
|
||||
output << punctuation("::");
|
||||
}
|
||||
|
||||
void write_member_object_suffix(code_generator::output& output, const cpp_member_object_type&)
|
||||
{
|
||||
output << punctuation(")");
|
||||
}
|
||||
|
||||
void write_template_parameter(code_generator::output& output,
|
||||
const cpp_template_parameter_type& type)
|
||||
{
|
||||
output << type.entity();
|
||||
}
|
||||
|
||||
void write_template_instantiation(code_generator::output& output,
|
||||
const cpp_template_instantiation_type& type)
|
||||
{
|
||||
output << type.primary_template();
|
||||
if (type.arguments_exposed())
|
||||
detail::write_template_arguments(output, type.arguments());
|
||||
else
|
||||
output << punctuation("<") << token_seq(type.unexposed_arguments()) << punctuation(">");
|
||||
}
|
||||
|
||||
void write_dependent(code_generator::output& output, const cpp_dependent_type& type)
|
||||
{
|
||||
output << token_seq(type.name());
|
||||
}
|
||||
|
||||
void write_unexposed(code_generator::output& output, const cpp_unexposed_type& type)
|
||||
{
|
||||
output << token_seq(type.name());
|
||||
}
|
||||
}
|
||||
|
||||
void detail::write_type_prefix(code_generator::output& output, const cpp_type& type)
|
||||
{
|
||||
switch (type.kind())
|
||||
{
|
||||
#define CPPAST_DETAIL_HANDLE(Name) \
|
||||
case cpp_type_kind::Name##_t: \
|
||||
write_##Name(output, static_cast<const cpp_##Name##_type&>(type)); \
|
||||
break;
|
||||
|
||||
#define CPPAST_DETAIL_HANDLE_COMPLEX(Name) \
|
||||
case cpp_type_kind::Name##_t: \
|
||||
write_##Name##_prefix(output, static_cast<const cpp_##Name##_type&>(type)); \
|
||||
break;
|
||||
|
||||
CPPAST_DETAIL_HANDLE(builtin)
|
||||
CPPAST_DETAIL_HANDLE(user_defined)
|
||||
CPPAST_DETAIL_HANDLE(auto)
|
||||
CPPAST_DETAIL_HANDLE(decltype)
|
||||
CPPAST_DETAIL_HANDLE(decltype_auto)
|
||||
CPPAST_DETAIL_HANDLE_COMPLEX(cv_qualified)
|
||||
CPPAST_DETAIL_HANDLE_COMPLEX(pointer)
|
||||
CPPAST_DETAIL_HANDLE_COMPLEX(reference)
|
||||
CPPAST_DETAIL_HANDLE_COMPLEX(array)
|
||||
CPPAST_DETAIL_HANDLE_COMPLEX(function)
|
||||
CPPAST_DETAIL_HANDLE_COMPLEX(member_function)
|
||||
CPPAST_DETAIL_HANDLE_COMPLEX(member_object)
|
||||
CPPAST_DETAIL_HANDLE(template_parameter)
|
||||
CPPAST_DETAIL_HANDLE(template_instantiation)
|
||||
CPPAST_DETAIL_HANDLE(dependent)
|
||||
CPPAST_DETAIL_HANDLE(unexposed)
|
||||
}
|
||||
|
||||
#undef CPPAST_DETAIL_HANDLE
|
||||
#undef CPPAST_DETAIL_HANDLE_COMPLEX
|
||||
}
|
||||
|
||||
void detail::write_type_suffix(code_generator::output& output, const cpp_type& type)
|
||||
{
|
||||
switch (type.kind())
|
||||
{
|
||||
#define CPPAST_DETAIL_HANDLE(Name) \
|
||||
case cpp_type_kind::Name##_t: \
|
||||
break;
|
||||
|
||||
#define CPPAST_DETAIL_HANDLE_COMPLEX(Name) \
|
||||
case cpp_type_kind::Name##_t: \
|
||||
write_##Name##_suffix(output, static_cast<const cpp_##Name##_type&>(type)); \
|
||||
break;
|
||||
|
||||
CPPAST_DETAIL_HANDLE(builtin)
|
||||
CPPAST_DETAIL_HANDLE(user_defined)
|
||||
CPPAST_DETAIL_HANDLE(auto)
|
||||
CPPAST_DETAIL_HANDLE(decltype)
|
||||
CPPAST_DETAIL_HANDLE(decltype_auto)
|
||||
CPPAST_DETAIL_HANDLE_COMPLEX(cv_qualified)
|
||||
CPPAST_DETAIL_HANDLE_COMPLEX(pointer)
|
||||
CPPAST_DETAIL_HANDLE_COMPLEX(reference)
|
||||
CPPAST_DETAIL_HANDLE_COMPLEX(array)
|
||||
CPPAST_DETAIL_HANDLE_COMPLEX(function)
|
||||
CPPAST_DETAIL_HANDLE_COMPLEX(member_function)
|
||||
CPPAST_DETAIL_HANDLE_COMPLEX(member_object)
|
||||
CPPAST_DETAIL_HANDLE(template_parameter)
|
||||
CPPAST_DETAIL_HANDLE(template_instantiation)
|
||||
CPPAST_DETAIL_HANDLE(dependent)
|
||||
CPPAST_DETAIL_HANDLE(unexposed)
|
||||
}
|
||||
|
||||
#undef CPPAST_DETAIL_HANDLE
|
||||
#undef CPPAST_DETAIL_HANDLE_COMPLEX
|
||||
}
|
||||
|
||||
void detail::write_type(code_generator::output& output, const cpp_type& type, std::string name,
|
||||
bool is_variadic)
|
||||
{
|
||||
write_type_prefix(output, type);
|
||||
if (!name.empty())
|
||||
output << whitespace << identifier(name);
|
||||
if (is_variadic)
|
||||
output << punctuation("...");
|
||||
write_type_suffix(output, type);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ namespace
|
|||
{
|
||||
auto name = detail::get_cursor_name(cur);
|
||||
auto type = detail::parse_type(context, cur, clang_getCursorType(cur));
|
||||
auto is_decltype = type->kind() == cpp_type_kind::decltype_;
|
||||
auto is_decltype = type->kind() == cpp_type_kind::decltype_t;
|
||||
|
||||
std::unique_ptr<cpp_expression> default_value;
|
||||
detail::visit_children(cur, [&](const CXCursor& child) {
|
||||
|
|
|
|||
|
|
@ -299,13 +299,13 @@ namespace
|
|||
return result;
|
||||
}
|
||||
|
||||
bool bump_c_comment(position& p, detail::preprocessor_output& output)
|
||||
bool bump_c_comment(position& p, detail::preprocessor_output& output, bool in_main_file)
|
||||
{
|
||||
if (!starts_with(p, "/*"))
|
||||
return false;
|
||||
p.bump(2u);
|
||||
|
||||
if (starts_with(p, "*"))
|
||||
if (in_main_file && starts_with(p, "*"))
|
||||
{
|
||||
// doc comment
|
||||
p.bump();
|
||||
|
|
@ -371,20 +371,20 @@ namespace
|
|||
}
|
||||
}
|
||||
|
||||
bool bump_cpp_comment(position& p, detail::preprocessor_output& output)
|
||||
bool bump_cpp_comment(position& p, detail::preprocessor_output& output, bool in_main_file)
|
||||
{
|
||||
if (!starts_with(p, "//"))
|
||||
return false;
|
||||
p.bump(2u);
|
||||
|
||||
if (starts_with(p, "/") || starts_with(p, "!"))
|
||||
if (in_main_file && (starts_with(p, "/") || starts_with(p, "!")))
|
||||
{
|
||||
// C++ style doc comment
|
||||
p.bump();
|
||||
auto comment = parse_cpp_doc_comment(p, false);
|
||||
merge_or_add(output, std::move(comment));
|
||||
}
|
||||
else if (starts_with(p, "<"))
|
||||
else if (in_main_file && starts_with(p, "<"))
|
||||
{
|
||||
// end of line doc comment
|
||||
p.bump();
|
||||
|
|
@ -408,7 +408,8 @@ namespace
|
|||
}
|
||||
|
||||
std::unique_ptr<cpp_macro_definition> parse_macro(position& p,
|
||||
detail::preprocessor_output& output)
|
||||
detail::preprocessor_output& output,
|
||||
bool in_main_file)
|
||||
{
|
||||
// format (at new line): #define <name> [replacement]
|
||||
// or: #define <name>(<args>) [replacement]
|
||||
|
|
@ -446,6 +447,9 @@ namespace
|
|||
}
|
||||
// don't skip newline
|
||||
|
||||
if (!in_main_file)
|
||||
return nullptr;
|
||||
|
||||
auto result = cpp_macro_definition::build(std::move(name), std::move(args), std::move(rep));
|
||||
// match comment directly
|
||||
if (!output.comments.empty() && output.comments.back().matches(*result, p.cur_line()))
|
||||
|
|
@ -472,7 +476,8 @@ namespace
|
|||
}
|
||||
|
||||
std::unique_ptr<cpp_include_directive> parse_include(position& p,
|
||||
detail::preprocessor_output& output)
|
||||
detail::preprocessor_output& output,
|
||||
bool in_main_file)
|
||||
{
|
||||
// format (at new line, literal <>): #include <filename>
|
||||
// or: #include "filename"
|
||||
|
|
@ -505,6 +510,9 @@ namespace
|
|||
DEBUG_ASSERT(starts_with(p, "\n"), detail::assert_handler{});
|
||||
// don't skip newline
|
||||
|
||||
if (!in_main_file)
|
||||
return nullptr;
|
||||
|
||||
auto result = cpp_include_directive::build(cpp_file_ref(cpp_entity_id(filename), filename),
|
||||
include_kind);
|
||||
if (!output.comments.empty() && output.comments.back().matches(*result, p.cur_line()))
|
||||
|
|
@ -614,10 +622,9 @@ detail::preprocessor_output detail::preprocess(const libclang_compile_config& co
|
|||
std::size_t file_depth = 0u;
|
||||
while (p)
|
||||
{
|
||||
if (auto macro = parse_macro(p, result))
|
||||
if (auto macro = parse_macro(p, result, file_depth == 0u))
|
||||
{
|
||||
if (file_depth == 0u)
|
||||
result.entities.push_back({std::move(macro), p.cur_line()});
|
||||
result.entities.push_back({std::move(macro), p.cur_line()});
|
||||
}
|
||||
else if (auto undef = parse_undef(p))
|
||||
{
|
||||
|
|
@ -631,7 +638,7 @@ detail::preprocessor_output detail::preprocess(const libclang_compile_config& co
|
|||
}),
|
||||
result.entities.end());
|
||||
}
|
||||
else if (auto include = parse_include(p, result))
|
||||
else if (auto include = parse_include(p, result, file_depth == 0u))
|
||||
{
|
||||
if (file_depth == 0u)
|
||||
result.entities.push_back({std::move(include), p.cur_line()});
|
||||
|
|
@ -669,9 +676,9 @@ detail::preprocessor_output detail::preprocess(const libclang_compile_config& co
|
|||
break;
|
||||
}
|
||||
}
|
||||
else if (bump_c_comment(p, result))
|
||||
else if (bump_c_comment(p, result, file_depth == 0u))
|
||||
continue;
|
||||
else if (bump_cpp_comment(p, result))
|
||||
else if (bump_cpp_comment(p, result, file_depth == 0u))
|
||||
continue;
|
||||
else
|
||||
p.bump();
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue