Parse cpp_converison_op

This commit is contained in:
Jonathan Müller 2017-03-12 17:43:57 +01:00
commit 8691628ec5
9 changed files with 184 additions and 25 deletions

View file

@ -18,11 +18,16 @@ cpp_entity_kind cpp_member_function::do_get_entity_kind() const noexcept
return kind();
}
cpp_entity_kind cpp_conversion_op::do_get_entity_kind() const noexcept
cpp_entity_kind cpp_conversion_op::kind() noexcept
{
return cpp_entity_kind::conversion_op_t;
}
cpp_entity_kind cpp_conversion_op::do_get_entity_kind() const noexcept
{
return kind();
}
cpp_entity_kind cpp_constructor::do_get_entity_kind() const noexcept
{
return cpp_entity_kind::constructor_t;

View file

@ -66,7 +66,8 @@ namespace
prefix_info result;
// just check for keywords until we've reached the function name
while (!detail::skip_if(stream, name.c_str()))
// notes: name can have multiple tokens if it is an operator
while (!detail::skip_if(stream, name.c_str(), true))
{
if (detail::skip_if(stream, "constexpr"))
result.is_constexpr = true;
@ -270,7 +271,7 @@ namespace
auto prefix = parse_prefix_info(stream, name);
DEBUG_ASSERT(!prefix.is_virtual, detail::parse_error_handler{}, cur,
"unexpected tokens in function prefix");
"free function cannot be virtual");
if (prefix.is_constexpr)
builder.is_constexpr();
@ -356,6 +357,21 @@ namespace
return result;
}
}
template <class Builder>
std::unique_ptr<cpp_entity> handle_suffix(const detail::parse_context& context,
const CXCursor& cur, Builder& builder,
detail::token_stream& stream, bool is_virtual)
{
auto suffix = parse_suffix_info(stream, context);
builder.cv_ref_qualifier(suffix.cv_qualifier, suffix.ref_qualifier);
if (suffix.noexcept_condition)
builder.noexcept_condition(move(suffix.noexcept_condition));
if (auto virt = calculate_virtual(cur, is_virtual, suffix.virtual_keywords))
builder.virtual_info(virt.value());
return builder.finish(*context.idx, detail::get_entity_id(cur), suffix.body_kind);
}
}
std::unique_ptr<cpp_entity> detail::parse_cpp_member_function(const detail::parse_context& context,
@ -379,13 +395,53 @@ std::unique_ptr<cpp_entity> detail::parse_cpp_member_function(const detail::pars
builder.is_constexpr();
skip_parameters(stream);
auto suffix = parse_suffix_info(stream, context);
builder.cv_ref_qualifier(suffix.cv_qualifier, suffix.ref_qualifier);
if (suffix.noexcept_condition)
builder.noexcept_condition(std::move(suffix.noexcept_condition));
if (auto virt = calculate_virtual(cur, prefix.is_virtual, suffix.virtual_keywords))
builder.virtual_info(virt.value());
return builder.finish(*context.idx, detail::get_entity_id(cur), suffix.body_kind);
return handle_suffix(context, cur, builder, stream, prefix.is_virtual);
}
std::unique_ptr<cpp_entity> detail::parse_cpp_conversion_op(const detail::parse_context& context,
const CXCursor& cur)
{
DEBUG_ASSERT(clang_getCursorKind(cur) == CXCursor_ConversionFunction, detail::assert_handler{});
cpp_conversion_op::builder builder(detail::parse_type(context, clang_getCursorResultType(cur)));
detail::tokenizer tokenizer(context.tu, context.file, cur);
detail::token_stream stream(tokenizer, cur);
// look for constexpr, explicit, virtual
// must come before the operator token
auto is_virtual = false;
while (!detail::skip_if(stream, "operator"))
{
if (detail::skip_if(stream, "virtual"))
is_virtual = true;
else if (detail::skip_if(stream, "constexpr"))
builder.is_constexpr();
else if (detail::skip_if(stream, "explicit"))
builder.is_explicit();
else
stream.bump();
}
// heuristic to find arguments tokens
// skip forward, skipping inside brackets
while (true)
{
if (detail::skip_if(stream, "("))
{
if (detail::skip_if(stream, ")"))
break;
else
detail::skip_brackets(stream);
}
else if (detail::skip_if(stream, "["))
detail::skip_brackets(stream);
else if (detail::skip_if(stream, "{"))
detail::skip_brackets(stream);
else if (detail::skip_if(stream, "<"))
detail::skip_brackets(stream);
else
stream.bump();
}
return handle_suffix(context, cur, builder, stream, is_virtual);
}

View file

@ -92,6 +92,8 @@ std::unique_ptr<cpp_entity> detail::parse_entity(const detail::parse_context& co
if (auto func = try_parse_static_cpp_function(context, cur))
return func;
return parse_cpp_member_function(context, cur);
case CXCursor_ConversionFunction:
return parse_cpp_conversion_op(context, cur);
default:
break;

View file

@ -89,6 +89,8 @@ namespace cppast
const CXCursor& cur);
std::unique_ptr<cpp_entity> parse_cpp_member_function(const parse_context& context,
const CXCursor& cur);
std::unique_ptr<cpp_entity> parse_cpp_conversion_op(const parse_context& context,
const CXCursor& cur);
std::unique_ptr<cpp_entity> parse_entity(const parse_context& context, const CXCursor& cur);
}

View file

@ -170,12 +170,32 @@ void detail::skip(detail::token_stream& stream, const char* str)
stream.bump();
}
bool detail::skip_if(detail::token_stream& stream, const char* str)
namespace
{
auto& token = stream.peek();
if (token != str)
return false;
stream.bump();
bool starts_with(const char*& str, const detail::token& t)
{
if (std::strncmp(str, t.c_str(), t.value().length()) != 0)
return false;
str += t.value().length();
while (*str == ' ' || *str == '\t')
++str;
return true;
}
}
bool detail::skip_if(detail::token_stream& stream, const char* str, bool multi_token)
{
auto save = stream.cur();
do
{
auto& token = stream.peek();
if (!starts_with(str, token) || (!multi_token && *str != '\0'))
{
stream.set_cur(save);
return false;
}
stream.bump();
} while (multi_token && *str);
return true;
}

View file

@ -154,7 +154,8 @@ namespace cppast
void skip(token_stream& stream, const char* str);
// skips the next token if it has the given string
bool skip_if(token_stream& stream, const char* str);
// if multi_token == true, str can consist of multiple tokens optionally separated by whitespace
bool skip_if(token_stream& stream, const char* str, bool multi_token = false);
// returns the location of the closing bracket
// the current token must be (,[,{ or <