diff --git a/C++ Types.xmind b/C++ Types.xmind deleted file mode 100644 index e23ab57..0000000 Binary files a/C++ Types.xmind and /dev/null differ diff --git a/CMakeLists.txt b/CMakeLists.txt deleted file mode 100644 index 4db44e4..0000000 --- a/CMakeLists.txt +++ /dev/null @@ -1,11 +0,0 @@ -cmake_minimum_required(VERSION 3.6) -project(cppast) - -set(CMAKE_CXX_STANDARD 11) - -set(SOURCE_FILES include/cppast/cpp_entity.hpp include/cppast/cpp_entity_kind.hpp include/cppast/detail/intrusive_list.hpp include/cppast/detail/assert.hpp include/cppast/cpp_entity_container.hpp src/cpp_entity_kind.cpp include/cppast/cpp_file.hpp src/cpp_file.cpp include/cppast/cpp_namespace.hpp include/cppast/cpp_entity_index.hpp include/cppast/cpp_entity_ref.hpp include/cppast/cpp_type.hpp src/cpp_namespace.cpp src/cpp_type.cpp include/cppast/cpp_expression.hpp include/cppast/cpp_array_type.hpp include/cppast/cpp_function_type.hpp include/cppast/cpp_enum.hpp src/cpp_enum.cpp src/cpp_entity.cpp include/cppast/visitor.hpp src/visitor.cpp src/cpp_type_alias.cpp include/cppast/cpp_type_alias.hpp include/cppast/cpp_variable_base.hpp src/cpp_variable.cpp include/cppast/cpp_variable.hpp src/cpp_language_linkage.cpp include/cppast/cpp_language_linkage.hpp src/cpp_function.cpp include/cppast/cpp_function.hpp include/cppast/cpp_storage_specifiers.hpp src/cpp_class.cpp include/cppast/cpp_class.hpp src/cpp_member_variable.cpp include/cppast/cpp_member_variable.hpp src/cpp_member_function.cpp include/cppast/cpp_member_function.hpp src/cpp_template_parameter.cpp include/cppast/cpp_template_parameter.hpp include/cppast/cpp_alias_template.hpp src/cpp_alias_template.cpp include/cppast/cpp_template.hpp src/cpp_function_template.cpp include/cppast/cpp_function_template.hpp src/cpp_class_template.cpp include/cppast/cpp_class_template.hpp src/cpp_variable_template.cpp include/cppast/cpp_variable_template.hpp) -add_library(cppast ${SOURCE_FILES}) -target_include_directories(cppast PUBLIC ../type_safe/include ../debug_assert include/) - -add_executable(cppast_main main.cpp) -target_link_libraries(cppast_main PUBLIC cppast) \ No newline at end of file diff --git a/TODO.md b/TODO.md deleted file mode 100644 index fadbcc0..0000000 --- a/TODO.md +++ /dev/null @@ -1,6 +0,0 @@ -Milestone 0 - Hierachy - -* overloaded entity ref -* namespace id stuff -* preprocessor -* translation_unit diff --git a/include/cppast/cpp_enum.hpp b/include/cppast/cpp_enum.hpp index d4d2518..25302af 100644 --- a/include/cppast/cpp_enum.hpp +++ b/include/cppast/cpp_enum.hpp @@ -21,6 +21,8 @@ namespace cppast class cpp_enum_value final : public cpp_entity { public: + static cpp_entity_kind kind() noexcept; + /// \returns A newly created and registered enum value. /// \notes `value` may be `nullptr`, in which case the enum has an implicit value. static std::unique_ptr build( @@ -49,6 +51,8 @@ namespace cppast class cpp_enum final : public cpp_entity, public cpp_entity_container { public: + static cpp_entity_kind kind() noexcept; + /// Builds a [cppast::cpp_enum](). class builder { diff --git a/main.cpp b/main.cpp deleted file mode 100644 index 3b4877b..0000000 --- a/main.cpp +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright (C) 2017 Jonathan Müller -// This file is subject to the license terms in the LICENSE file -// found in the top-level directory of this distribution. - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -std::unique_ptr make_file(const cppast::cpp_entity_index& idx) -{ - using namespace cppast; - - cpp_file::builder file_builder("main.cpp"); - file_builder.add_child(cpp_namespace::builder("foo", false).finish(idx, "foo"_id)); - - cpp_namespace::builder ns_builder("bar", false); - ns_builder.add_child(cpp_namespace::builder("foo", false).finish(idx, "bar::foo"_id)); - file_builder.add_child(ns_builder.finish(idx, "bar"_id)); - - cpp_enum::builder e_builder("e", true); - e_builder.add_value(cpp_enum_value::build(idx, "e::a"_id, "a", nullptr)); - file_builder.add_child(e_builder.finish(idx, "e"_id)); - - cpp_function::builder f_builder("func", cpp_builtin_type::build("int")); - f_builder.add_parameter( - cpp_function_parameter::build(idx, "param"_id, "param", cpp_builtin_type::build("int"))); - f_builder.is_variadic(); - file_builder.add_child(f_builder.finish(idx, "func"_id)); - - cpp_class::builder c_builder("type", cpp_class_kind::class_t, false); - c_builder.access_specifier(cpp_public); - c_builder.add_child(cpp_variable::build(idx, "var"_id, "var", cpp_builtin_type::build("int"), - nullptr, cpp_storage_class_none, false)); - file_builder.add_child(c_builder.finish(idx, "type"_id)); - - cpp_alias_template::builder a_builder( - cpp_type_alias::build("alias", cpp_template_parameter_type::build( - cpp_template_type_parameter_ref("T"_id, "T")))); - a_builder.add_parameter( - cpp_template_type_parameter::build(idx, "T"_id, "T", cpp_template_keyword::keyword_typename, - false, nullptr)); - file_builder.add_child(a_builder.finish(idx, "alias"_id)); - - return file_builder.finish(idx); -} - -int main() -{ - cppast::cpp_entity_index idx; - auto file = make_file(idx); - - auto level = 0; - cppast::visit(*file, [&](const cppast::cpp_entity& e, cppast::visitor_info info) { - if (info == cppast::visitor_info::container_entity_exit) - --level; - else - { - std::cout << std::string(level, ' ') << cppast::to_string(e.kind()) << ' ' << e.name() - << ' ' << cppast::full_name(e) << '\n'; - if (info == cppast::visitor_info::container_entity_enter) - ++level; - } - - return true; - }); -} diff --git a/src/cpp_enum.cpp b/src/cpp_enum.cpp index 578a725..11d2f00 100644 --- a/src/cpp_enum.cpp +++ b/src/cpp_enum.cpp @@ -8,6 +8,11 @@ using namespace cppast; +cpp_entity_kind cpp_enum_value::kind() noexcept +{ + return cpp_entity_kind::enum_value_t; +} + std::unique_ptr cpp_enum_value::build(const cpp_entity_index& idx, cpp_entity_id id, std::string name, std::unique_ptr value) @@ -20,12 +25,17 @@ std::unique_ptr cpp_enum_value::build(const cpp_entity_index& id cpp_entity_kind cpp_enum_value::do_get_entity_kind() const noexcept { - return cpp_entity_kind::enum_value_t; + return kind(); +} + +cpp_entity_kind cpp_enum::kind() noexcept +{ + return cpp_entity_kind::enum_t; } cpp_entity_kind cpp_enum::do_get_entity_kind() const noexcept { - return cpp_entity_kind::enum_t; + return kind(); } type_safe::optional cpp_enum::do_get_scope_name() const diff --git a/src/libclang/enum_parser.cpp b/src/libclang/enum_parser.cpp new file mode 100644 index 0000000..19952f6 --- /dev/null +++ b/src/libclang/enum_parser.cpp @@ -0,0 +1,82 @@ +// Copyright (C) 2017 Jonathan Müller +// This file is subject to the license terms in the LICENSE file +// found in the top-level directory of this distribution. + +#include + +#include "parse_functions.hpp" +#include "libclang_visitor.hpp" + +using namespace cppast; + +namespace +{ + std::unique_ptr parse_enum_value(const detail::parse_context& context, + const CXCursor& cur) + { + DEBUG_ASSERT(cur.kind == CXCursor_EnumConstantDecl, detail::parse_error_handler{}, cur, + "unexpected child cursor of enum"); + + detail::tokenizer tokenizer(context.tu, context.file, cur); + detail::token_stream stream(tokenizer, cur); + + // , + // or: = , + auto& name = stream.get().value(); + + std::unique_ptr value; + if (detail::skip_if(stream, "=")) + { + detail::visit_children(cur, [&](const CXCursor& child) { + DEBUG_ASSERT(clang_isExpression(child.kind) && !value, + detail::parse_error_handler{}, cur, + "unexpected child cursor of enum value"); + + value = detail::parse_expression(context, child); + }); + } + + return cpp_enum_value::build(*context.idx, detail::get_entity_id(cur), name.c_str(), + std::move(value)); + } + + cpp_enum::builder make_enum_builder(const detail::parse_context& context, const CXCursor& cur) + { + detail::tokenizer tokenizer(context.tu, context.file, cur); + detail::token_stream stream(tokenizer, cur); + + // enum [class] name [: type] { + detail::skip(stream, "enum"); + auto scoped = detail::skip_if(stream, "class"); + auto& name = stream.get().value(); + + std::unique_ptr type; + if (detail::skip_if(stream, ":")) + // parse type, explictly given one + type = detail::parse_type(context, clang_getEnumDeclIntegerType(cur)); + + return cpp_enum::builder(name.c_str(), scoped, std::move(type)); + } +} + +std::unique_ptr detail::parse_cpp_enum(const detail::parse_context& context, + const CXCursor& cur) +{ + DEBUG_ASSERT(cur.kind == CXCursor_EnumDecl, detail::assert_handler{}); + if (!clang_isCursorDefinition(cur)) + return nullptr; + + auto builder = make_enum_builder(context, cur); + detail::visit_children(cur, [&](const CXCursor& child) { + try + { + auto entity = parse_enum_value(context, child); + builder.add_value(std::move(entity)); + } + catch (parse_error& ex) + { + context.logger->log("libclang parser", ex.get_diagnostic()); + } + }); + return builder.finish(*context.idx, get_entity_id(cur)); +} diff --git a/src/libclang/expression_parser.cpp b/src/libclang/expression_parser.cpp new file mode 100644 index 0000000..17ef82d --- /dev/null +++ b/src/libclang/expression_parser.cpp @@ -0,0 +1,34 @@ +// Copyright (C) 2017 Jonathan Müller +// This file is subject to the license terms in the LICENSE file +// found in the top-level directory of this distribution. + +#include + +#include "parse_functions.hpp" + +using namespace cppast; + +std::unique_ptr detail::parse_expression(const detail::parse_context& context, + const CXCursor& cur) +{ + auto kind = clang_getCursorKind(cur); + DEBUG_ASSERT(clang_isExpression(kind), detail::assert_handler{}); + + detail::tokenizer tokenizer(context.tu, context.file, cur); + detail::token_stream stream(tokenizer, cur); + + // just concat everything + std::string expr; + while (!stream.done()) + expr += stream.get().c_str(); + + auto type = parse_type(context, clang_getCursorType(cur)); + + if (kind == CXCursor_CharacterLiteral || kind == CXCursor_CompoundLiteralExpr + || kind == CXCursor_FloatingLiteral || kind == CXCursor_ImaginaryLiteral + || kind == CXCursor_IntegerLiteral || kind == CXCursor_StringLiteral + || kind == CXCursor_CXXBoolLiteralExpr || kind == CXCursor_CXXNullPtrLiteralExpr) + return cpp_literal_expression::build(std::move(type), std::move(expr)); + else + return cpp_unexposed_expression::build(std::move(type), std::move(expr)); +} diff --git a/src/libclang/parse_functions.cpp b/src/libclang/parse_functions.cpp index 01c14a2..993a0aa 100644 --- a/src/libclang/parse_functions.cpp +++ b/src/libclang/parse_functions.cpp @@ -38,6 +38,9 @@ std::unique_ptr detail::parse_entity(const detail::parse_context& co case CXCursor_TypedefDecl: return parse_cpp_type_alias(context, cur); + case CXCursor_EnumDecl: + return parse_cpp_enum(context, cur); + default: break; } diff --git a/src/libclang/parse_functions.hpp b/src/libclang/parse_functions.hpp index 8a70850..055bd81 100644 --- a/src/libclang/parse_functions.hpp +++ b/src/libclang/parse_functions.hpp @@ -14,6 +14,7 @@ namespace cppast { + class cpp_expression; class cpp_type; namespace detail @@ -30,6 +31,9 @@ namespace cppast std::unique_ptr parse_type(const parse_context& context, const CXType& type); + std::unique_ptr parse_expression(const parse_context& context, + const CXCursor& cur); + // parse_entity() dispatches on the cursor type // it calls one of the other parse functions defined elsewhere // try_parse_XXX are not exposed entities @@ -50,6 +54,9 @@ namespace cppast std::unique_ptr parse_cpp_type_alias(const parse_context& context, const CXCursor& cur); + std::unique_ptr parse_cpp_enum(const parse_context& context, + const CXCursor& cur); + std::unique_ptr parse_entity(const parse_context& context, const CXCursor& cur); } } // namespace cppast::detail diff --git a/src/libclang/tokenizer.cpp b/src/libclang/tokenizer.cpp index e0cbee9..8d51d2c 100644 --- a/src/libclang/tokenizer.cpp +++ b/src/libclang/tokenizer.cpp @@ -152,6 +152,9 @@ namespace } while (!token_after_is(tu, file, cur, end, ";")); end = get_next_location(tu, file, end); } + else if (clang_isExpression(clang_getCursorKind(cur))) + // need to shrink range by one + end = get_next_location(tu, file, end, -1); return clang_getRange(begin, end); } diff --git a/src/libclang/type_parser.cpp b/src/libclang/type_parser.cpp index fa72973..af6558c 100644 --- a/src/libclang/type_parser.cpp +++ b/src/libclang/type_parser.cpp @@ -399,17 +399,12 @@ namespace } std::unique_ptr detail::parse_type(const detail::parse_context& context, - const CXType& type) try + const CXType& type) { auto result = parse_type_impl(context, type); DEBUG_ASSERT(result && is_valid(*result), detail::parse_error_handler{}, type, "invalid type"); return std::move(result); } -catch (parse_error& ex) -{ - context.logger->log("libclang parser", ex.get_diagnostic()); - return nullptr; -} std::unique_ptr detail::parse_cpp_type_alias(const detail::parse_context& context, const CXCursor& cur) @@ -419,7 +414,5 @@ std::unique_ptr detail::parse_cpp_type_alias(const detail::parse_con auto name = cxstring(clang_getCursorSpelling(cur)); auto type = parse_type(context, clang_getTypedefDeclUnderlyingType(cur)); - if (!type) - return nullptr; return cpp_type_alias::build(*context.idx, get_entity_id(cur), name.c_str(), std::move(type)); } diff --git a/test.cpp b/test.cpp deleted file mode 100644 index e69de29..0000000 diff --git a/test/cpp_enum.cpp b/test/cpp_enum.cpp new file mode 100644 index 0000000..b0063c3 --- /dev/null +++ b/test/cpp_enum.cpp @@ -0,0 +1,112 @@ +// Copyright (C) 2017 Jonathan Müller +// This file is subject to the license terms in the LICENSE file +// found in the top-level directory of this distribution. + +#include + +#include "test_parser.hpp" + +using namespace cppast; + +TEST_CASE("cpp_enum") +{ + auto code = R"( +enum ignore_me : int; + +enum a +{ + a_a, + a_b = 42, + a_c, + a_d = a_a + 2, +}; + +enum class ignore_me2; + +enum class b : int +{ + b_a, + b_b = 42, + b_c +}; + +)"; + + cpp_entity_index idx; + auto file = parse(idx, "cpp_enum.cpp", code); + auto count = test_visit(*file, [&](const cpp_enum& e) { + if (e.name() == "a") + { + REQUIRE(!e.is_scoped()); + REQUIRE(!e.underlying_type()); + + auto no_vals = 0u; + for (auto& val : e) + { + if (val.name() == "a_a" || val.name() == "a_c") + { + ++no_vals; + REQUIRE(!val.value()); + } + else if (val.name() == "a_b") + { + ++no_vals; + REQUIRE(val.value()); + auto& expr = val.value().value(); + REQUIRE(expr.kind() == cpp_expression_kind::unexposed); + REQUIRE(static_cast(expr).expression() + == "42"); + REQUIRE( + equal_types(idx, expr.type(), *cpp_builtin_type::build("unsigned int"))); + } + else if (val.name() == "a_d") + { + ++no_vals; + REQUIRE(val.value()); + auto& expr = val.value().value(); + // this is unexposed for some reason + REQUIRE(expr.kind() == cpp_expression_kind::unexposed); + REQUIRE(static_cast(expr).expression() + == "a_a+2"); + REQUIRE( + equal_types(idx, expr.type(), *cpp_builtin_type::build("unsigned int"))); + } + else + REQUIRE(false); + } + REQUIRE(no_vals == 4u); + } + else if (e.name() == "b") + { + REQUIRE(e.is_scoped()); + REQUIRE(e.underlying_type()); + REQUIRE(equal_types(idx, e.underlying_type().value(), *cpp_builtin_type::build("int"))); + + auto no_vals = 0u; + for (auto& val : e) + { + REQUIRE(full_name(val) == "b::" + val.name()); + if (val.name() == "b_a" || val.name() == "b_c") + { + ++no_vals; + REQUIRE(!val.value()); + } + else if (val.name() == "b_b") + { + ++no_vals; + REQUIRE(val.value()); + auto& expr = val.value().value(); + REQUIRE(expr.kind() == cpp_expression_kind::literal); + REQUIRE(static_cast(expr).value() == "42"); + REQUIRE(equal_types(idx, expr.type(), *cpp_builtin_type::build("int"))); + } + else + REQUIRE(false); + } + REQUIRE(no_vals == 3u); + } + else + REQUIRE(false); + }); + REQUIRE(count == 2u); +} diff --git a/test/preprocessor.cpp b/test/preprocessor.cpp deleted file mode 100644 index e860755..0000000 --- a/test/preprocessor.cpp +++ /dev/null @@ -1,5 +0,0 @@ -// Copyright (C) 2017 Jonathan Müller -// This file is subject to the license terms in the LICENSE file -// found in the top-level directory of this distribution. - -#i diff --git a/test/test_parser.hpp b/test/test_parser.hpp index 3b20139..53219cd 100644 --- a/test/test_parser.hpp +++ b/test/test_parser.hpp @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -71,4 +72,7 @@ inline void check_parent(const cppast::cpp_entity& e, const char* parent_name, REQUIRE(cppast::full_name(e) == full_name); } +bool equal_types(const cppast::cpp_entity_index& idx, const cppast::cpp_type& parsed, + const cppast::cpp_type& synthesized); + #endif // CPPAST_TEST_PARSER_HPP_INCLUDED