[breaking] Turn macro parameters into propert entities
This commit is contained in:
parent
c341ae01f1
commit
56d4964b61
10 changed files with 194 additions and 31 deletions
|
|
@ -14,6 +14,7 @@ namespace cppast
|
|||
{
|
||||
file_t,
|
||||
|
||||
macro_parameter_t,
|
||||
macro_definition_t,
|
||||
include_directive_t,
|
||||
|
||||
|
|
|
|||
|
|
@ -12,55 +12,136 @@
|
|||
|
||||
namespace cppast
|
||||
{
|
||||
/// A [cppast::cpp_entity]() modelling a macro parameter.
|
||||
class cpp_macro_parameter final : public cpp_entity
|
||||
{
|
||||
public:
|
||||
static cpp_entity_kind kind() noexcept;
|
||||
|
||||
/// \returns A newly built macro parameter.
|
||||
/// \notes It is not meant to be registered in the [cppast::cpp_entity_index]() as no other [cppast::cpp_entity]() can refer to it.
|
||||
static std::unique_ptr<cpp_macro_parameter> build(std::string name)
|
||||
{
|
||||
return std::unique_ptr<cpp_macro_parameter>(new cpp_macro_parameter(std::move(name)));
|
||||
}
|
||||
|
||||
private:
|
||||
cpp_macro_parameter(std::string name) : cpp_entity(std::move(name)) {}
|
||||
|
||||
cpp_entity_kind do_get_entity_kind() const noexcept override;
|
||||
};
|
||||
|
||||
/// A [cppast::cpp_entity]() modelling a macro definition.
|
||||
class cpp_macro_definition final : public cpp_entity
|
||||
{
|
||||
public:
|
||||
static cpp_entity_kind kind() noexcept;
|
||||
|
||||
/// \returns A newly built macro definition.
|
||||
/// \returns A newly built object like macro.
|
||||
/// \notes It is not meant to be registered in the [cppast::cpp_entity_index](),
|
||||
/// as no other [cppast::cpp_entity]() can refer to it.
|
||||
static std::unique_ptr<cpp_macro_definition> build(
|
||||
std::string name, type_safe::optional<std::string> parameters, std::string replacement)
|
||||
static std::unique_ptr<cpp_macro_definition> build_object_like(std::string name,
|
||||
std::string replacement)
|
||||
{
|
||||
return std::unique_ptr<cpp_macro_definition>(
|
||||
new cpp_macro_definition(std::move(name), std::move(parameters),
|
||||
std::move(replacement)));
|
||||
std::unique_ptr<cpp_macro_definition> result{new cpp_macro_definition(std::move(name))};
|
||||
result->replacement_ = std::move(replacement);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Builds a function like macro.
|
||||
class function_like_builder
|
||||
{
|
||||
public:
|
||||
/// \effects Sets the name of the function like macro.
|
||||
function_like_builder(std::string name)
|
||||
: result_(new cpp_macro_definition(std::move(name)))
|
||||
{
|
||||
result_->kind_ = function_like;
|
||||
}
|
||||
|
||||
/// \effects Sets the replacement text.
|
||||
void replacement(std::string replacement)
|
||||
{
|
||||
result_->replacement_ = std::move(replacement);
|
||||
}
|
||||
|
||||
/// \effects Marks the macro as variadic.
|
||||
void is_variadic()
|
||||
{
|
||||
result_->kind_ = variadic_function;
|
||||
}
|
||||
|
||||
/// \effects Adds a parameter.
|
||||
/// \group param
|
||||
void parameter(std::unique_ptr<cpp_macro_parameter> param)
|
||||
{
|
||||
result_->parameters_.push_back(*result_, std::move(param));
|
||||
}
|
||||
/// \group param
|
||||
void parameter(std::string name)
|
||||
{
|
||||
parameter(cpp_macro_parameter::build(std::move(name)));
|
||||
}
|
||||
|
||||
/// \returns The finished macro.
|
||||
/// \notes It is not meant to be registered in the [cppast::cpp_entity_index](),
|
||||
/// as no other [cppast::cpp_entity]() can refer to it.
|
||||
std::unique_ptr<cpp_macro_definition> finish()
|
||||
{
|
||||
return std::move(result_);
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<cpp_macro_definition> result_;
|
||||
};
|
||||
|
||||
/// \returns The replacement text of the macro.
|
||||
const std::string& replacement() const noexcept
|
||||
{
|
||||
return replacement_;
|
||||
}
|
||||
|
||||
/// \returns Whether or not it is an object like macro.
|
||||
bool is_object_like() const noexcept
|
||||
{
|
||||
return kind_ == object_like;
|
||||
}
|
||||
|
||||
/// \returns Whether or not it is a function like macro.
|
||||
bool is_function_like() const noexcept
|
||||
{
|
||||
return parameters_.has_value();
|
||||
return kind_ != object_like;
|
||||
}
|
||||
|
||||
/// \returns The parameters of the macro, as the string spelled out in the source code.
|
||||
/// \notes It has none if it is not a function like macro.
|
||||
const type_safe::optional<std::string>& parameters() const noexcept
|
||||
/// \returns Whether or not it is a variadic macro.
|
||||
bool is_variadic() const noexcept
|
||||
{
|
||||
return parameters_;
|
||||
return kind_ == variadic_function;
|
||||
}
|
||||
|
||||
/// \returns The parameters of the macro.
|
||||
/// \notes It has none if it is not a function like macro.
|
||||
detail::iteratable_intrusive_list<cpp_macro_parameter> parameters() const noexcept
|
||||
{
|
||||
return type_safe::ref(parameters_);
|
||||
}
|
||||
|
||||
private:
|
||||
cpp_entity_kind do_get_entity_kind() const noexcept override;
|
||||
|
||||
cpp_macro_definition(std::string name, type_safe::optional<std::string> parameters,
|
||||
std::string replacement)
|
||||
: cpp_entity(std::move(name)),
|
||||
parameters_(std::move(parameters)),
|
||||
replacement_(std::move(replacement))
|
||||
{
|
||||
}
|
||||
cpp_macro_definition(std::string name) : cpp_entity(std::move(name)), kind_(object_like) {}
|
||||
|
||||
type_safe::optional<std::string> parameters_;
|
||||
std::string replacement_;
|
||||
detail::intrusive_list<cpp_macro_parameter> parameters_;
|
||||
std::string replacement_;
|
||||
|
||||
enum : char
|
||||
{
|
||||
object_like,
|
||||
function_like,
|
||||
variadic_function,
|
||||
} kind_;
|
||||
|
||||
friend function_like_builder;
|
||||
};
|
||||
|
||||
/// The kind of [cppast::cpp_include_directive]().
|
||||
|
|
|
|||
|
|
@ -94,6 +94,15 @@ namespace
|
|||
return static_cast<bool>(output);
|
||||
}
|
||||
|
||||
bool generate_macro_parameter(code_generator& generator, const cpp_macro_parameter& param,
|
||||
cpp_access_specifier_kind cur_access)
|
||||
{
|
||||
code_generator::output output(type_safe::ref(generator), type_safe::ref(param), cur_access);
|
||||
if (output)
|
||||
output << preprocessor_token(param.name());
|
||||
return static_cast<bool>(output);
|
||||
}
|
||||
|
||||
bool generate_macro_definition(code_generator& generator, const cpp_macro_definition& def,
|
||||
cpp_access_specifier_kind cur_access)
|
||||
{
|
||||
|
|
@ -102,9 +111,17 @@ namespace
|
|||
{
|
||||
output << preprocessor_token("#define") << whitespace << identifier(def.name());
|
||||
if (def.is_function_like())
|
||||
output << preprocessor_token("(") << bracket_ws
|
||||
<< preprocessor_token(def.parameters().value()) << bracket_ws
|
||||
<< preprocessor_token(")");
|
||||
{
|
||||
output << preprocessor_token("(") << bracket_ws;
|
||||
auto need_sep = write_container(output, def.parameters(), comma, cpp_public);
|
||||
if (def.is_variadic())
|
||||
{
|
||||
if (need_sep)
|
||||
output << comma;
|
||||
output << preprocessor_token("...");
|
||||
}
|
||||
output << bracket_ws << preprocessor_token(")");
|
||||
}
|
||||
if (!def.replacement().empty() && !output.options().is_set(code_generator::declaration))
|
||||
output << whitespace << preprocessor_token(def.replacement()) << newl;
|
||||
else
|
||||
|
|
@ -1059,6 +1076,7 @@ namespace
|
|||
|
||||
CPPAST_DETAIL_HANDLE(file)
|
||||
|
||||
CPPAST_DETAIL_HANDLE(macro_parameter)
|
||||
CPPAST_DETAIL_HANDLE(macro_definition)
|
||||
CPPAST_DETAIL_HANDLE(include_directive)
|
||||
|
||||
|
|
@ -1116,7 +1134,7 @@ namespace
|
|||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool code_generator::generate_code(const cpp_entity& entity)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -13,6 +13,8 @@ const char* cppast::to_string(cpp_entity_kind kind) noexcept
|
|||
case cpp_entity_kind::file_t:
|
||||
return "file";
|
||||
|
||||
case cpp_entity_kind::macro_parameter_t:
|
||||
return "macro parameter";
|
||||
case cpp_entity_kind::macro_definition_t:
|
||||
return "macro definition";
|
||||
case cpp_entity_kind::include_directive_t:
|
||||
|
|
@ -113,6 +115,7 @@ bool cppast::is_function(cpp_entity_kind kind) noexcept
|
|||
return true;
|
||||
|
||||
case cpp_entity_kind::file_t:
|
||||
case cpp_entity_kind::macro_parameter_t:
|
||||
case cpp_entity_kind::macro_definition_t:
|
||||
case cpp_entity_kind::include_directive_t:
|
||||
case cpp_entity_kind::language_linkage_t:
|
||||
|
|
@ -160,6 +163,7 @@ bool cppast::is_parameter(cpp_entity_kind kind) noexcept
|
|||
return true;
|
||||
|
||||
case cpp_entity_kind::file_t:
|
||||
case cpp_entity_kind::macro_parameter_t:
|
||||
case cpp_entity_kind::macro_definition_t:
|
||||
case cpp_entity_kind::include_directive_t:
|
||||
case cpp_entity_kind::language_linkage_t:
|
||||
|
|
@ -209,6 +213,7 @@ bool cppast::is_template(cpp_entity_kind kind) noexcept
|
|||
return true;
|
||||
|
||||
case cpp_entity_kind::file_t:
|
||||
case cpp_entity_kind::macro_parameter_t:
|
||||
case cpp_entity_kind::macro_definition_t:
|
||||
case cpp_entity_kind::include_directive_t:
|
||||
case cpp_entity_kind::language_linkage_t:
|
||||
|
|
@ -253,6 +258,7 @@ bool cppast::is_template_specialization(cpp_entity_kind kind) noexcept
|
|||
return true;
|
||||
|
||||
case cpp_entity_kind::file_t:
|
||||
case cpp_entity_kind::macro_parameter_t:
|
||||
case cpp_entity_kind::macro_definition_t:
|
||||
case cpp_entity_kind::include_directive_t:
|
||||
case cpp_entity_kind::language_linkage_t:
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ namespace
|
|||
return get_declarable(*static_cast<const cpp_template&>(e).begin());
|
||||
|
||||
case cpp_entity_kind::file_t:
|
||||
case cpp_entity_kind::macro_parameter_t:
|
||||
case cpp_entity_kind::macro_definition_t:
|
||||
case cpp_entity_kind::include_directive_t:
|
||||
case cpp_entity_kind::language_linkage_t:
|
||||
|
|
@ -81,7 +82,7 @@ namespace
|
|||
// else lookup definition
|
||||
return idx.lookup_definition(declarable.value().definition().value());
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool cppast::is_definition(const cpp_entity& e) noexcept
|
||||
{
|
||||
|
|
|
|||
|
|
@ -8,6 +8,16 @@
|
|||
|
||||
using namespace cppast;
|
||||
|
||||
cpp_entity_kind cpp_macro_parameter::kind() noexcept
|
||||
{
|
||||
return cpp_entity_kind::macro_parameter_t;
|
||||
}
|
||||
|
||||
cpp_entity_kind cpp_macro_parameter::do_get_entity_kind() const noexcept
|
||||
{
|
||||
return kind();
|
||||
}
|
||||
|
||||
cpp_entity_kind cpp_macro_definition::kind() noexcept
|
||||
{
|
||||
return cpp_entity_kind::macro_definition_t;
|
||||
|
|
|
|||
|
|
@ -119,6 +119,7 @@ bool detail::cpp_type_ref_predicate::operator()(const cpp_entity& e)
|
|||
return true;
|
||||
|
||||
case cpp_entity_kind::file_t:
|
||||
case cpp_entity_kind::macro_parameter_t:
|
||||
case cpp_entity_kind::macro_definition_t:
|
||||
case cpp_entity_kind::include_directive_t:
|
||||
case cpp_entity_kind::language_linkage_t:
|
||||
|
|
@ -203,7 +204,7 @@ namespace
|
|||
DEBUG_UNREACHABLE(detail::assert_handler{});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool detail::is_complex_type(const cpp_type& type) noexcept
|
||||
{
|
||||
|
|
@ -500,7 +501,7 @@ namespace
|
|||
{
|
||||
output << token_seq(type.name());
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void detail::write_type_prefix(code_generator::output& output, const cpp_type& type)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -833,6 +833,34 @@ namespace
|
|||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<cpp_macro_definition> build(std::string name, ts::optional<std::string> args,
|
||||
std::string rep)
|
||||
{
|
||||
if (!args)
|
||||
return cpp_macro_definition::build_object_like(std::move(name), std::move(rep));
|
||||
|
||||
cpp_macro_definition::function_like_builder builder{std::move(name)};
|
||||
builder.replacement(std::move(rep));
|
||||
|
||||
auto cur_ptr = args.value().c_str();
|
||||
auto cur_param = cur_ptr;
|
||||
while (*cur_ptr)
|
||||
{
|
||||
while (*cur_ptr && *cur_ptr != ',')
|
||||
++cur_ptr;
|
||||
|
||||
if (*cur_param == '.')
|
||||
builder.is_variadic();
|
||||
else
|
||||
builder.parameter(std::string(cur_param, cur_ptr));
|
||||
|
||||
if (*cur_ptr)
|
||||
cur_param = ++cur_ptr;
|
||||
}
|
||||
|
||||
return builder.finish();
|
||||
}
|
||||
|
||||
std::unique_ptr<cpp_macro_definition> parse_macro(position& p,
|
||||
detail::preprocessor_output& output)
|
||||
{
|
||||
|
|
@ -878,7 +906,7 @@ namespace
|
|||
if (!p.write_enabled())
|
||||
return nullptr;
|
||||
|
||||
auto result = cpp_macro_definition::build(std::move(name), std::move(args), std::move(rep));
|
||||
auto result = build(std::move(name), std::move(args), std::move(rep));
|
||||
// match comment directly
|
||||
if (!output.comments.empty() && output.comments.back().matches(*result, cur_line))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ namespace
|
|||
return cb(functor, container,
|
||||
{visitor_info::container_entity_exit, cur_access, last_child});
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool detail::visit(const cpp_entity& e, detail::visitor_callback_t cb, void* functor,
|
||||
cpp_access_specifier_kind cur_access, bool last_child)
|
||||
|
|
@ -91,6 +91,7 @@ bool detail::visit(const cpp_entity& e, detail::visitor_callback_t cb, void* fun
|
|||
return handle_container<cpp_class_template_specialization>(e, cb, functor, cur_access,
|
||||
last_child);
|
||||
|
||||
case cpp_entity_kind::macro_parameter_t:
|
||||
case cpp_entity_kind::macro_definition_t:
|
||||
case cpp_entity_kind::include_directive_t:
|
||||
case cpp_entity_kind::namespace_alias_t:
|
||||
|
|
|
|||
|
|
@ -40,12 +40,28 @@ namespace ns2
|
|||
if (args)
|
||||
{
|
||||
REQUIRE(macro.is_function_like());
|
||||
REQUIRE(macro.parameters().value() == args);
|
||||
|
||||
std::string params;
|
||||
for (auto& param : macro.parameters())
|
||||
{
|
||||
if (!params.empty())
|
||||
params += ",";
|
||||
params += param.name();
|
||||
}
|
||||
if (macro.is_variadic())
|
||||
{
|
||||
if (!params.empty())
|
||||
params += ",";
|
||||
params += "...";
|
||||
}
|
||||
|
||||
REQUIRE(params == args);
|
||||
}
|
||||
else
|
||||
{
|
||||
REQUIRE(!macro.is_function_like());
|
||||
REQUIRE(!macro.parameters().has_value());
|
||||
REQUIRE(!macro.is_variadic());
|
||||
REQUIRE(macro.parameters().empty());
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue