Parse free functions
This commit is contained in:
parent
210fcf2c36
commit
9267bbbff2
15 changed files with 442 additions and 58 deletions
|
|
@ -38,11 +38,11 @@ void detail::print_cursor_info(const CXCursor& cur) noexcept
|
|||
cxstring(clang_getCursorKindSpelling(cur.kind)).c_str());
|
||||
}
|
||||
|
||||
void detail::print_tokens(const detail::cxtranslation_unit& tu, const CXFile& file,
|
||||
void detail::print_tokens(const CXTranslationUnit& tu, const CXFile& file,
|
||||
const CXCursor& cur) noexcept
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mtx);
|
||||
detail::tokenizer tokenizer(tu.get(), file, cur);
|
||||
detail::tokenizer tokenizer(tu, file, cur);
|
||||
for (auto& token : tokenizer)
|
||||
std::printf("%s ", token.c_str());
|
||||
std::puts("\n");
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ namespace cppast
|
|||
|
||||
void print_cursor_info(const CXCursor& cur) noexcept;
|
||||
|
||||
void print_tokens(const cxtranslation_unit& tu, const CXFile& file,
|
||||
void print_tokens(const CXTranslationUnit& tu, const CXFile& file,
|
||||
const CXCursor& cur) noexcept;
|
||||
}
|
||||
} // namespace cppast::detail
|
||||
|
|
|
|||
|
|
@ -10,11 +10,11 @@ using namespace cppast;
|
|||
|
||||
namespace
|
||||
{
|
||||
std::string get_expression_str(detail::token_stream& stream)
|
||||
std::string get_expression_str(detail::token_stream& stream, detail::token_iterator end)
|
||||
{
|
||||
// just concat everything
|
||||
std::string expr;
|
||||
while (!stream.done())
|
||||
while (stream.cur() != end)
|
||||
expr += stream.get().c_str();
|
||||
return expr;
|
||||
}
|
||||
|
|
@ -30,7 +30,7 @@ std::unique_ptr<cpp_expression> detail::parse_expression(const detail::parse_con
|
|||
detail::token_stream stream(tokenizer, cur);
|
||||
|
||||
auto type = parse_type(context, clang_getCursorType(cur));
|
||||
auto expr = get_expression_str(stream);
|
||||
auto expr = get_expression_str(stream, stream.end());
|
||||
if (kind == CXCursor_CallExpr && (expr.empty() || expr.back() != ')'))
|
||||
{
|
||||
// we have a call expression that doesn't end in a closing parentheses
|
||||
|
|
@ -47,12 +47,13 @@ std::unique_ptr<cpp_expression> detail::parse_expression(const detail::parse_con
|
|||
return cpp_unexposed_expression::build(std::move(type), std::move(expr));
|
||||
}
|
||||
|
||||
std::unique_ptr<cpp_expression> detail::parse_raw_expression(const parse_context& context,
|
||||
token_stream& stream,
|
||||
const CXType& type)
|
||||
std::unique_ptr<cpp_expression> detail::parse_raw_expression(const parse_context&,
|
||||
token_stream& stream,
|
||||
token_iterator end,
|
||||
std::unique_ptr<cpp_type> type)
|
||||
{
|
||||
if (stream.done())
|
||||
return nullptr;
|
||||
auto expr = get_expression_str(stream);
|
||||
return cpp_unexposed_expression::build(parse_type(context, type), std::move(expr));
|
||||
auto expr = get_expression_str(stream, end);
|
||||
return cpp_unexposed_expression::build(std::move(type), std::move(expr));
|
||||
}
|
||||
|
|
|
|||
128
src/libclang/function_parser.cpp
Normal file
128
src/libclang/function_parser.cpp
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
// 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_function.hpp>
|
||||
|
||||
#include "libclang_visitor.hpp"
|
||||
#include "parse_functions.hpp"
|
||||
|
||||
using namespace cppast;
|
||||
|
||||
namespace
|
||||
{
|
||||
std::unique_ptr<cpp_function_parameter> parse_parameter(const detail::parse_context& context,
|
||||
const CXCursor& cur)
|
||||
{
|
||||
auto name = detail::get_cursor_name(cur);
|
||||
auto type = detail::parse_type(context, clang_getCursorType(cur));
|
||||
|
||||
std::unique_ptr<cpp_expression> default_value;
|
||||
detail::visit_children(cur, [&](const CXCursor& child) {
|
||||
DEBUG_ASSERT(clang_isExpression(child.kind) && !default_value,
|
||||
detail::parse_error_handler{}, child,
|
||||
"unexpected child cursor of function parameter");
|
||||
default_value = detail::parse_expression(context, child);
|
||||
});
|
||||
|
||||
return cpp_function_parameter::build(*context.idx, detail::get_entity_id(cur), name.c_str(),
|
||||
std::move(type), std::move(default_value));
|
||||
}
|
||||
|
||||
template <class Builder>
|
||||
void add_parameters(const detail::parse_context& context, Builder& builder, const CXCursor& cur)
|
||||
{
|
||||
detail::visit_children(cur, [&](const CXCursor& child) {
|
||||
if (clang_getCursorKind(child) != CXCursor_ParmDecl)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
auto parameter = parse_parameter(context, child);
|
||||
builder.add_parameter(std::move(parameter));
|
||||
}
|
||||
catch (detail::parse_error& ex)
|
||||
{
|
||||
context.logger->log("libclang parser", ex.get_diagnostic());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void skip_parameters(detail::token_stream& stream)
|
||||
{
|
||||
detail::skip_brackets(stream);
|
||||
}
|
||||
|
||||
std::unique_ptr<cpp_expression> try_parse_noexcept(detail::token_stream& stream,
|
||||
const detail::parse_context& context)
|
||||
{
|
||||
if (!detail::skip_if(stream, "noexcept"))
|
||||
return nullptr;
|
||||
|
||||
auto type = cpp_builtin_type::build("bool");
|
||||
if (stream.peek().value() != "(")
|
||||
return cpp_literal_expression::build(std::move(type), "true");
|
||||
|
||||
auto closing = detail::find_closing_bracket(stream);
|
||||
|
||||
detail::skip(stream, "(");
|
||||
auto expr = detail::parse_raw_expression(context, stream, closing, std::move(type));
|
||||
detail::skip(stream, ")");
|
||||
|
||||
return expr;
|
||||
}
|
||||
|
||||
cpp_function_body_kind parse_body_kind(detail::token_stream& stream)
|
||||
{
|
||||
if (detail::skip_if(stream, "default"))
|
||||
return cpp_function_defaulted;
|
||||
else if (detail::skip_if(stream, "delete"))
|
||||
return cpp_function_deleted;
|
||||
DEBUG_UNREACHABLE(detail::parse_error_handler{}, stream.cursor(),
|
||||
"unexpected token for function body kind");
|
||||
return cpp_function_declaration;
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<cpp_entity> detail::parse_cpp_function(const detail::parse_context& context,
|
||||
const CXCursor& cur)
|
||||
{
|
||||
DEBUG_ASSERT(clang_getCursorKind(cur) == CXCursor_FunctionDecl, detail::assert_handler{});
|
||||
auto name = detail::get_cursor_name(cur);
|
||||
|
||||
cpp_function::builder builder(name.c_str(),
|
||||
detail::parse_type(context, clang_getCursorResultType(cur)));
|
||||
add_parameters(context, builder, cur);
|
||||
if (clang_Cursor_isVariadic(cur))
|
||||
builder.is_variadic();
|
||||
builder.storage_class(detail::get_storage_class(cur));
|
||||
|
||||
detail::tokenizer tokenizer(context.tu, context.file, cur);
|
||||
detail::token_stream stream(tokenizer, cur);
|
||||
|
||||
// parse prefix
|
||||
while (!detail::skip_if(stream, name.c_str()))
|
||||
{
|
||||
if (detail::skip_if(stream, "constexpr"))
|
||||
builder.is_constexpr();
|
||||
else
|
||||
stream.bump();
|
||||
}
|
||||
// skip parameters
|
||||
skip_parameters(stream);
|
||||
|
||||
auto body = clang_isCursorDefinition(cur) ? cpp_function_definition : cpp_function_declaration;
|
||||
// parse suffix
|
||||
// tokenizer only tokenizes signature, so !stream.done() is sufficient
|
||||
while (!stream.done())
|
||||
{
|
||||
if (auto expr = try_parse_noexcept(stream, context))
|
||||
builder.noexcept_condition(std::move(expr));
|
||||
else if (skip_if(stream, "="))
|
||||
body = parse_body_kind(stream);
|
||||
else
|
||||
stream.bump();
|
||||
}
|
||||
|
||||
return builder.finish(*context.idx, detail::get_entity_id(cur), body);
|
||||
}
|
||||
|
|
@ -156,7 +156,7 @@ namespace
|
|||
}
|
||||
}
|
||||
|
||||
return tu;
|
||||
return detail::cxtranslation_unit(tu);
|
||||
}
|
||||
|
||||
unsigned get_line_no(const CXCursor& cursor)
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
#include "parse_functions.hpp"
|
||||
|
||||
#include <cppast/cpp_storage_class_specifiers.hpp>
|
||||
|
||||
using namespace cppast;
|
||||
|
||||
cpp_entity_id detail::get_entity_id(const CXCursor& cur)
|
||||
|
|
@ -18,6 +20,35 @@ detail::cxstring detail::get_cursor_name(const CXCursor& cur)
|
|||
return cxstring(clang_getCursorSpelling(cur));
|
||||
}
|
||||
|
||||
cpp_storage_class_specifiers detail::get_storage_class(const CXCursor& cur)
|
||||
{
|
||||
switch (clang_Cursor_getStorageClass(cur))
|
||||
{
|
||||
case CX_SC_Invalid:
|
||||
break;
|
||||
|
||||
case CX_SC_None:
|
||||
return cpp_storage_class_none;
|
||||
|
||||
case CX_SC_Auto:
|
||||
case CX_SC_Register:
|
||||
return cpp_storage_class_auto;
|
||||
|
||||
case CX_SC_Extern:
|
||||
return cpp_storage_class_extern;
|
||||
case CX_SC_Static:
|
||||
return cpp_storage_class_static;
|
||||
|
||||
case CX_SC_PrivateExtern:
|
||||
case CX_SC_OpenCLWorkGroupLocal:
|
||||
// non-exposed storage classes
|
||||
return cpp_storage_class_auto;
|
||||
}
|
||||
|
||||
DEBUG_UNREACHABLE(detail::parse_error_handler{}, cur, "unexpected storage class");
|
||||
return cpp_storage_class_auto;
|
||||
}
|
||||
|
||||
std::unique_ptr<cpp_entity> detail::parse_entity(const detail::parse_context& context,
|
||||
const CXCursor& cur) try
|
||||
{
|
||||
|
|
@ -54,6 +85,9 @@ std::unique_ptr<cpp_entity> detail::parse_entity(const detail::parse_context& co
|
|||
case CXCursor_FieldDecl:
|
||||
return parse_cpp_member_variable(context, cur);
|
||||
|
||||
case CXCursor_FunctionDecl:
|
||||
return parse_cpp_function(context, cur);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ namespace cppast
|
|||
{
|
||||
class cpp_expression;
|
||||
class cpp_type;
|
||||
enum cpp_storage_class_specifiers : int;
|
||||
|
||||
namespace detail
|
||||
{
|
||||
|
|
@ -26,6 +27,9 @@ namespace cppast
|
|||
// as then you won't get it "as-is"
|
||||
cxstring get_cursor_name(const CXCursor& cur);
|
||||
|
||||
// note: does not handle thread_local
|
||||
cpp_storage_class_specifiers get_storage_class(const CXCursor& cur);
|
||||
|
||||
struct parse_context
|
||||
{
|
||||
CXTranslationUnit tu;
|
||||
|
|
@ -39,12 +43,13 @@ namespace cppast
|
|||
std::unique_ptr<cpp_expression> parse_expression(const parse_context& context,
|
||||
const CXCursor& cur);
|
||||
// parse the expression starting at the current token in the stream
|
||||
// and ends at the end of the stream
|
||||
// and ends at the given iterator
|
||||
// this is required for situations where there is no expression cursor exposed,
|
||||
// like member initializers
|
||||
std::unique_ptr<cpp_expression> parse_raw_expression(const parse_context& context,
|
||||
token_stream& stream,
|
||||
const CXType& type);
|
||||
std::unique_ptr<cpp_expression> parse_raw_expression(const parse_context& context,
|
||||
token_stream& stream,
|
||||
token_iterator end,
|
||||
std::unique_ptr<cpp_type> type);
|
||||
|
||||
// parse_entity() dispatches on the cursor type
|
||||
// it calls one of the other parse functions defined elsewhere
|
||||
|
|
@ -76,6 +81,9 @@ namespace cppast
|
|||
std::unique_ptr<cpp_entity> parse_cpp_member_variable(const parse_context& context,
|
||||
const CXCursor& cur);
|
||||
|
||||
std::unique_ptr<cpp_entity> parse_cpp_function(const parse_context& context,
|
||||
const CXCursor& cur);
|
||||
|
||||
std::unique_ptr<cpp_entity> parse_entity(const parse_context& context, const CXCursor& cur);
|
||||
}
|
||||
} // namespace cppast::detail
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ namespace cppast
|
|||
{
|
||||
}
|
||||
|
||||
raii_wrapper(T obj) noexcept : obj_(obj)
|
||||
explicit raii_wrapper(T obj) noexcept : obj_(obj)
|
||||
{
|
||||
DEBUG_ASSERT(obj_, detail::assert_handler{});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -124,11 +124,21 @@ namespace cppast
|
|||
return cursor_;
|
||||
}
|
||||
|
||||
token_iterator begin() const noexcept
|
||||
{
|
||||
return begin_;
|
||||
}
|
||||
|
||||
token_iterator cur() const noexcept
|
||||
{
|
||||
return cur_;
|
||||
}
|
||||
|
||||
token_iterator end() const noexcept
|
||||
{
|
||||
return end_;
|
||||
}
|
||||
|
||||
void set_cur(token_iterator iter) noexcept
|
||||
{
|
||||
cur_ = iter;
|
||||
|
|
|
|||
|
|
@ -183,6 +183,9 @@ namespace
|
|||
return cpp_ref_none;
|
||||
}
|
||||
|
||||
std::unique_ptr<cpp_type> parse_type_impl(const detail::parse_context& context,
|
||||
const CXType& type);
|
||||
|
||||
std::unique_ptr<cpp_expression> parse_array_size(const CXType& type)
|
||||
{
|
||||
auto size = clang_getArraySize(type);
|
||||
|
|
@ -214,8 +217,27 @@ namespace
|
|||
size_expr.rend()));
|
||||
}
|
||||
|
||||
std::unique_ptr<cpp_type> parse_type_impl(const detail::parse_context& context,
|
||||
const CXType& type);
|
||||
std::unique_ptr<cpp_type> try_parse_array_type(const detail::parse_context& context,
|
||||
const CXType& type)
|
||||
{
|
||||
auto canonical = clang_getCanonicalType(type);
|
||||
auto value_type = clang_getArrayElementType(type);
|
||||
if (value_type.kind == CXType_Invalid)
|
||||
{
|
||||
// value_type is invalid, however type can still be an array
|
||||
// as there seems to be a libclang bug
|
||||
// only if the canonical type is not an array,
|
||||
// is it truly not an array
|
||||
value_type = clang_getArrayElementType(canonical);
|
||||
if (value_type.kind == CXType_Invalid)
|
||||
return nullptr;
|
||||
// we have an array, even though type isn't one directly
|
||||
// only downside of this workaround: we've stripped away typedefs
|
||||
}
|
||||
|
||||
auto size = parse_array_size(canonical); // type may not work, see above
|
||||
return cpp_array_type::build(parse_type_impl(context, value_type), std::move(size));
|
||||
}
|
||||
|
||||
template <class Builder>
|
||||
std::unique_ptr<cpp_type> add_parameters(Builder& builder, const detail::parse_context& context,
|
||||
|
|
@ -317,6 +339,9 @@ namespace
|
|||
// guess what: after you've called clang_getPointeeType() on a function pointer
|
||||
// you'll get an unexposed type
|
||||
return ftype;
|
||||
else if (auto atype = try_parse_array_type(context, type))
|
||||
// same deal here
|
||||
return atype;
|
||||
return cpp_unexposed_type::build(get_type_spelling(type).c_str());
|
||||
|
||||
case CXType_Void:
|
||||
|
|
@ -379,11 +404,7 @@ namespace
|
|||
case CXType_VariableArray:
|
||||
case CXType_DependentSizedArray:
|
||||
case CXType_ConstantArray:
|
||||
{
|
||||
auto size = parse_array_size(type);
|
||||
auto value_type = parse_type_impl(context, clang_getArrayElementType(type));
|
||||
return cpp_array_type::build(std::move(value_type), std::move(size));
|
||||
}
|
||||
return try_parse_array_type(context, type);
|
||||
|
||||
case CXType_FunctionNoProto:
|
||||
case CXType_FunctionProto:
|
||||
|
|
|
|||
|
|
@ -28,35 +28,6 @@ namespace
|
|||
});
|
||||
return expression;
|
||||
}
|
||||
|
||||
cpp_storage_class_specifiers parse_storage_class(const CXCursor& cur)
|
||||
{
|
||||
switch (clang_Cursor_getStorageClass(cur))
|
||||
{
|
||||
case CX_SC_Invalid:
|
||||
break;
|
||||
|
||||
case CX_SC_None:
|
||||
return cpp_storage_class_none;
|
||||
|
||||
case CX_SC_Auto:
|
||||
case CX_SC_Register:
|
||||
return cpp_storage_class_auto;
|
||||
|
||||
case CX_SC_Extern:
|
||||
return cpp_storage_class_extern;
|
||||
case CX_SC_Static:
|
||||
return cpp_storage_class_static;
|
||||
|
||||
case CX_SC_PrivateExtern:
|
||||
case CX_SC_OpenCLWorkGroupLocal:
|
||||
// non-exposed storage classes
|
||||
return cpp_storage_class_auto;
|
||||
}
|
||||
|
||||
DEBUG_UNREACHABLE(detail::parse_error_handler{}, cur, "unexpected storage class");
|
||||
return cpp_storage_class_auto;
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_ptr<cpp_entity> detail::parse_cpp_variable(const detail::parse_context& context,
|
||||
|
|
@ -66,7 +37,7 @@ std::unique_ptr<cpp_entity> detail::parse_cpp_variable(const detail::parse_conte
|
|||
|
||||
auto name = get_cursor_name(cur);
|
||||
auto type = parse_type(context, clang_getCursorType(cur));
|
||||
auto storage_class = parse_storage_class(cur);
|
||||
auto storage_class = get_storage_class(cur);
|
||||
auto is_constexpr = false;
|
||||
|
||||
// just look for thread local or constexpr
|
||||
|
|
@ -118,7 +89,8 @@ std::unique_ptr<cpp_entity> detail::parse_cpp_member_variable(const detail::pars
|
|||
// look for the equal sign, default value starts there
|
||||
while (!stream.done() && !skip_if(stream, "="))
|
||||
stream.bump();
|
||||
auto default_value = parse_raw_expression(context, stream, clang_getCursorType(cur));
|
||||
auto default_value = parse_raw_expression(context, stream, stream.end(),
|
||||
parse_type(context, clang_getCursorType(cur)));
|
||||
|
||||
return cpp_member_variable::build(*context.idx, get_entity_id(cur), name.c_str(),
|
||||
std::move(type), std::move(default_value), is_mutable);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue