Add ability to parse multiple files
This commit is contained in:
parent
4ebf134cf2
commit
738b0198c2
4 changed files with 284 additions and 113 deletions
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.11)
|
cmake_minimum_required(VERSION 3.11)
|
||||||
project(cppast VERSION 0.1.0)
|
project(cppast VERSION 0.1.0)
|
||||||
|
set (CMAKE_CXX_STANDARD 20)
|
||||||
|
|
||||||
# options
|
# options
|
||||||
option(CPPAST_BUILD_TEST "whether or not to build the tests" OFF)
|
option(CPPAST_BUILD_TEST "whether or not to build the tests" OFF)
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
# Copyright (C) 2017-2022 Jonathan Müller and cppast contributors
|
# Copyright (C) 2017-2022 Jonathan Müller and cppast contributors
|
||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
# found in the top-level directory of this distribution.
|
# found in the top-level directory of this distribution.
|
||||||
|
set (CMAKE_CXX_STANDARD 20)
|
||||||
|
|
||||||
|
|
||||||
set(detail_header
|
set(detail_header
|
||||||
../include/cppast/detail/assert.hpp
|
../include/cppast/detail/assert.hpp
|
||||||
|
|
@ -106,7 +108,7 @@ set(libclang_source
|
||||||
libclang/variable_parser.cpp)
|
libclang/variable_parser.cpp)
|
||||||
|
|
||||||
add_library(cppast ${detail_header} ${header} ${source} ${libclang_source})
|
add_library(cppast ${detail_header} ${header} ${source} ${libclang_source})
|
||||||
target_compile_features(cppast PUBLIC cxx_std_11)
|
target_compile_features(cppast PUBLIC cxx_std_20)
|
||||||
target_include_directories(cppast PRIVATE ../include SYSTEM INTERFACE ../include)
|
target_include_directories(cppast PRIVATE ../include SYSTEM INTERFACE ../include)
|
||||||
target_link_libraries(cppast PUBLIC type_safe _cppast_tiny_process _cppast_libclang)
|
target_link_libraries(cppast PUBLIC type_safe _cppast_tiny_process _cppast_libclang)
|
||||||
target_compile_definitions(cppast PUBLIC
|
target_compile_definitions(cppast PUBLIC
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,15 @@
|
||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
# found in the top-level directory of this distribution.
|
# found in the top-level directory of this distribution.
|
||||||
|
|
||||||
|
set (CMAKE_CXX_STANDARD 20)
|
||||||
add_executable(cppast_tool main.cpp)
|
add_executable(cppast_tool main.cpp)
|
||||||
target_link_libraries(cppast_tool PUBLIC cppast cxxopts)
|
target_link_libraries(cppast_tool PUBLIC cppast cxxopts)
|
||||||
set_target_properties(cppast_tool PROPERTIES CXX_STANDARD 11 OUTPUT_NAME cppast)
|
set_target_properties(cppast_tool PROPERTIES CXX_STANDARD 20 OUTPUT_NAME cppast)
|
||||||
|
|
||||||
install(TARGETS cppast_tool)
|
install(TARGETS cppast_tool)
|
||||||
|
|
||||||
add_executable(cppcgen cppcgen.cpp)
|
add_executable(cppcgen cppcgen.cpp)
|
||||||
target_link_libraries(cppcgen PUBLIC cppast cxxopts)
|
target_link_libraries(cppcgen PUBLIC cppast cxxopts)
|
||||||
set_target_properties(cppcgen PROPERTIES CXX_STANDARD 11 OUTPUT_NAME cppcgen)
|
set_target_properties(cppcgen PROPERTIES CXX_STANDARD 20 OUTPUT_NAME cppcgen)
|
||||||
|
|
||||||
install(TARGETS cppcgen)
|
install(TARGETS cppcgen)
|
||||||
|
|
|
||||||
387
tool/cppcgen.cpp
387
tool/cppcgen.cpp
|
|
@ -1,9 +1,13 @@
|
||||||
// Copyright (C) 2017-2022 Jonathan Müller and cppast contributors
|
// Copyright (C) 2017-2022 Jonathan Müller and cppast contributors
|
||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
|
#include <fstream>
|
||||||
|
#include <string>
|
||||||
|
#include <list>
|
||||||
#include <regex>
|
#include <regex>
|
||||||
#include "cppast/cpp_member_function.hpp"
|
#include <cppast/cpp_member_function.hpp>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
#include <cxxopts.hpp>
|
#include <cxxopts.hpp>
|
||||||
|
|
||||||
|
|
@ -256,22 +260,55 @@ static inline void rtrim(std::string &s) {
|
||||||
}).base(), s.end());
|
}).base(), s.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string serialize_method_params(const cppast::cpp_member_function& mf) {
|
||||||
|
std::stringstream stream;
|
||||||
|
for (auto& param : mf.parameters()) {
|
||||||
|
stream << cppast::to_string(param.type());
|
||||||
|
}
|
||||||
|
auto result = stream.str();
|
||||||
|
auto reg = R"((const\s*|&|\*|::|\[\]|\s*|\w+))";
|
||||||
|
result = std::regex_replace_lambda(
|
||||||
|
result,
|
||||||
|
std::regex(reg),
|
||||||
|
[](const std::smatch& m){
|
||||||
|
std::string match = m.str(1);
|
||||||
|
if (match == "&") {
|
||||||
|
return std::string("R");
|
||||||
|
}
|
||||||
|
else if (match == "*") {
|
||||||
|
return std::string("P");
|
||||||
|
}
|
||||||
|
else if (match == "[]") {
|
||||||
|
return std::string("B");
|
||||||
|
}
|
||||||
|
else if (match == "::") {
|
||||||
|
return std::string("N");
|
||||||
|
}
|
||||||
|
else if (match.starts_with("const")) {
|
||||||
|
return std::string("C");
|
||||||
|
}
|
||||||
|
else if (match.find_first_not_of(' ') == match.npos) {
|
||||||
|
return std::string("");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void output_member_function_typedef(std::stringstream& out, const cppast::cpp_entity& e, std::string& current_class) {
|
void output_member_function_typedef(std::stringstream& out, const cppast::cpp_entity& e, std::string& current_class) {
|
||||||
if (e.kind() != cppast::cpp_entity_kind::member_function_t) return;
|
if (e.kind() != cppast::cpp_entity_kind::member_function_t) return;
|
||||||
|
|
||||||
auto& mf = static_cast<const cppast::cpp_member_function&>(e);
|
auto& mf = static_cast<const cppast::cpp_member_function&>(e);
|
||||||
out << "typedef ";
|
out << "typedef ";
|
||||||
out << cppast::to_string(mf.return_type()) << " ";
|
out << cppast::to_string(mf.return_type()) << " ";
|
||||||
out << "(*"<< current_class << sanitize_method_name(mf.name()) << FUNC_SUFFIX << ")(const " << current_class << "*" << " self";
|
out << "(*"<< current_class << sanitize_method_name(mf.name()) << serialize_method_params(mf) << FUNC_SUFFIX << ")(const " << current_class << "*" << " self";
|
||||||
int i = 0;
|
|
||||||
for (auto& param : mf.parameters()) {
|
for (auto& param : mf.parameters()) {
|
||||||
if (i == 0) {
|
out << ", " << cppast::to_string(param.type()) << " " << param.name();
|
||||||
// add comma if there are parameters
|
|
||||||
out << ", ";
|
|
||||||
}
|
|
||||||
out << ( i ? ", " : "" );
|
|
||||||
out << cppast::to_string(param.type()) << " " << param.name();
|
|
||||||
i++;
|
|
||||||
}
|
}
|
||||||
out << ");\n";
|
out << ");\n";
|
||||||
}
|
}
|
||||||
|
|
@ -279,23 +316,25 @@ void output_member_function_typedef(std::stringstream& out, const cppast::cpp_en
|
||||||
void output_member_function_param(std::stringstream& out, const cppast::cpp_entity& e, std::string& current_class) {
|
void output_member_function_param(std::stringstream& out, const cppast::cpp_entity& e, std::string& current_class) {
|
||||||
if (e.kind() != cppast::cpp_entity_kind::member_function_t) return;
|
if (e.kind() != cppast::cpp_entity_kind::member_function_t) return;
|
||||||
|
|
||||||
std::string mpar_name = FUNC_PARAM_PREFIX + sanitize_method_name(e.name());
|
auto& mf = static_cast<const cppast::cpp_member_function&>(e);
|
||||||
out << current_class << sanitize_method_name(e.name()) << FUNC_SUFFIX << " " << mpar_name;
|
std::string mpar_name = FUNC_PARAM_PREFIX + sanitize_method_name(e.name()) + serialize_method_params(mf);
|
||||||
|
out << current_class << sanitize_method_name(e.name()) << serialize_method_params(mf) << FUNC_SUFFIX << " " << mpar_name;
|
||||||
out << ", ";
|
out << ", ";
|
||||||
}
|
}
|
||||||
|
|
||||||
void output_member_function_var_init(std::stringstream& out, std::string& prefix, const cppast::cpp_entity& e, std::string& current_class) {
|
void output_member_function_var_init(std::stringstream& out, std::string& prefix, const cppast::cpp_entity& e, std::string& current_class) {
|
||||||
if (e.kind() != cppast::cpp_entity_kind::member_function_t) return;
|
if (e.kind() != cppast::cpp_entity_kind::member_function_t) return;
|
||||||
|
auto& mf = static_cast<const cppast::cpp_member_function&>(e);
|
||||||
|
|
||||||
std::string mpar_name = FUNC_PARAM_PREFIX + sanitize_method_name(e.name());
|
std::string mpar_name = FUNC_PARAM_PREFIX + sanitize_method_name(e.name()) + serialize_method_params(mf);
|
||||||
std::string mvar_name = FUNC_VAR_PREFIX + current_class + sanitize_method_name(e.name());
|
std::string mvar_name = FUNC_VAR_PREFIX + current_class + sanitize_method_name(e.name()) + serialize_method_params(mf);
|
||||||
out << prefix << prefix << mvar_name << " = " << mpar_name << ";\n";
|
out << prefix << prefix << mvar_name << " = " << mpar_name << ";\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void output_member_function(std::stringstream& out, const cppast::cpp_entity& e, std::string& prefix, std::string& base_class, std::string& current_class) {
|
void output_member_function(std::stringstream& out, const cppast::cpp_entity& e, std::string& prefix, std::string& base_class, std::string& current_class) {
|
||||||
if (e.kind() != cppast::cpp_entity_kind::member_function_t) return;
|
if (e.kind() != cppast::cpp_entity_kind::member_function_t) return;
|
||||||
|
|
||||||
auto& mf = static_cast<const cppast::cpp_member_function_base&>(e);
|
auto& mf = static_cast<const cppast::cpp_member_function&>(e);
|
||||||
int j = 0;
|
int j = 0;
|
||||||
for (auto& param : mf.parameters()) {
|
for (auto& param : mf.parameters()) {
|
||||||
if (param.name().empty()) {
|
if (param.name().empty()) {
|
||||||
|
|
@ -305,16 +344,17 @@ void output_member_function(std::stringstream& out, const cppast::cpp_entity& e,
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string method_stub = generate_synopsis(e);
|
std::string method_stub = generate_synopsis(e);
|
||||||
|
bool method_is_zero = false;
|
||||||
|
if (method_stub.find("= 0;") != std::string::npos) {
|
||||||
|
method_is_zero = true;
|
||||||
|
}
|
||||||
|
/* method_is_zero = false; */
|
||||||
method_stub = std::regex_replace(method_stub, std::regex(R"((\s*=\s*[a-zA-Z0-9_]+)?;)"), "", std::regex_constants::format_first_only);
|
method_stub = std::regex_replace(method_stub, std::regex(R"((\s*=\s*[a-zA-Z0-9_]+)?;)"), "", std::regex_constants::format_first_only);
|
||||||
rtrim(method_stub);
|
rtrim(method_stub);
|
||||||
//method_stub.pop_back(); // get rid of semicolon
|
|
||||||
|
|
||||||
std::string mvar_name = FUNC_VAR_PREFIX + current_class + sanitize_method_name(mf.name());
|
std::string mvar_name = FUNC_VAR_PREFIX + current_class + sanitize_method_name(mf.name()) + serialize_method_params(mf);
|
||||||
std::string func_type = current_class + sanitize_method_name(mf.name()) + FUNC_SUFFIX;
|
std::string func_type = current_class + sanitize_method_name(mf.name()) + serialize_method_params(mf) + FUNC_SUFFIX;
|
||||||
std::stringstream all_params_stream;
|
std::stringstream all_params_stream;
|
||||||
/* std::unique_ptr<cppast::cpp_type> ty = cppast::cpp_user_defined_type::build(cppast::cpp_type_ref(cppast::cpp_entity_id(func_type), func_type)); */
|
|
||||||
/* auto fp = cppast::cpp_function_parameter::build(std::string("callback"), std::move(ty), nullptr); */
|
|
||||||
/* mf.add_parameter(); */
|
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (auto& param : mf.parameters()) {
|
for (auto& param : mf.parameters()) {
|
||||||
|
|
@ -325,17 +365,8 @@ void output_member_function(std::stringstream& out, const cppast::cpp_entity& e,
|
||||||
std::string all_params = all_params_stream.str();
|
std::string all_params = all_params_stream.str();
|
||||||
|
|
||||||
// generate class var
|
// generate class var
|
||||||
out << prefix << func_type << " " << mvar_name << ";\n";
|
out << prefix << func_type << " " << mvar_name << " = NULL;\n";
|
||||||
// TODO: Generate class var accessors (Get and Set)
|
|
||||||
// Maybe don't need to?
|
|
||||||
|
|
||||||
/* if (i > 0) { */
|
|
||||||
/* method_stub.replace(method_stub.find(")"), 1, ", " + func_type + " callback)"); */
|
|
||||||
/* } */
|
|
||||||
/* else { */
|
|
||||||
/* method_stub.replace(method_stub.find(")"), 1, func_type + " callback)"); */
|
|
||||||
/* } */
|
|
||||||
// bool is_override = cppast::is_overriding(mf.virtual_info());
|
|
||||||
// generate method
|
// generate method
|
||||||
out << prefix << method_stub;
|
out << prefix << method_stub;
|
||||||
if (method_stub.find("override") == std::string::npos) {
|
if (method_stub.find("override") == std::string::npos) {
|
||||||
|
|
@ -348,15 +379,15 @@ void output_member_function(std::stringstream& out, const cppast::cpp_entity& e,
|
||||||
std::string ret_type = cppast::to_string(mf.return_type());
|
std::string ret_type = cppast::to_string(mf.return_type());
|
||||||
bool is_void = ret_type == "void";
|
bool is_void = ret_type == "void";
|
||||||
|
|
||||||
// call super
|
if (!method_is_zero) {
|
||||||
if (!is_void) {
|
// call super
|
||||||
out << ret_type << " res = ";
|
if (!is_void) {
|
||||||
|
out << ret_type << " res = ";
|
||||||
|
}
|
||||||
|
out << base_class << "::" << mf.name() << "(" << all_params << ");\n";
|
||||||
|
out << prefix << PREFIX_SPACING;
|
||||||
}
|
}
|
||||||
out << base_class << "::" << mf.name() << "(" << all_params << ");\n";
|
|
||||||
/* out << prefix << prefix; */
|
|
||||||
/* out << "std::cout << \"" << mvar_name << " is NULL? \" << " << "(*" << mvar_name << " == NULL)" << " << \"" << R"(\n)" << "\";\n"; */
|
|
||||||
|
|
||||||
out << prefix << PREFIX_SPACING;
|
|
||||||
out << "if (*" << mvar_name << " != NULL){\n";
|
out << "if (*" << mvar_name << " != NULL){\n";
|
||||||
out << prefix << PREFIX_SPACING << PREFIX_SPACING;
|
out << prefix << PREFIX_SPACING << PREFIX_SPACING;
|
||||||
out << "return ";
|
out << "return ";
|
||||||
|
|
@ -368,7 +399,7 @@ void output_member_function(std::stringstream& out, const cppast::cpp_entity& e,
|
||||||
}
|
}
|
||||||
out << prefix << PREFIX_SPACING;
|
out << prefix << PREFIX_SPACING;
|
||||||
out << "}\n"; // endif
|
out << "}\n"; // endif
|
||||||
if (!is_void) {
|
if (!is_void && !method_is_zero) {
|
||||||
out << prefix << PREFIX_SPACING;
|
out << prefix << PREFIX_SPACING;
|
||||||
out << "else {\n";
|
out << "else {\n";
|
||||||
out << prefix << PREFIX_SPACING << PREFIX_SPACING;
|
out << prefix << PREFIX_SPACING << PREFIX_SPACING;
|
||||||
|
|
@ -377,6 +408,14 @@ void output_member_function(std::stringstream& out, const cppast::cpp_entity& e,
|
||||||
out << "}\n";
|
out << "}\n";
|
||||||
|
|
||||||
}
|
}
|
||||||
|
else if (!is_void && method_is_zero) {
|
||||||
|
out << prefix << PREFIX_SPACING;
|
||||||
|
out << "else {\n";
|
||||||
|
out << prefix << PREFIX_SPACING << PREFIX_SPACING;
|
||||||
|
out << "return NULL;\n";
|
||||||
|
out << prefix << PREFIX_SPACING;
|
||||||
|
out << "}\n";
|
||||||
|
}
|
||||||
|
|
||||||
out << prefix << "}\n";
|
out << prefix << "}\n";
|
||||||
}
|
}
|
||||||
|
|
@ -431,7 +470,6 @@ void output_consdes(std::stringstream& out, const cppast::cpp_entity& e, std::st
|
||||||
// get rid of the ' = 0;' or ' = default;' in the constructor
|
// get rid of the ' = 0;' or ' = default;' in the constructor
|
||||||
method_stub = std::regex_replace(method_stub, std::regex(R"((\s*=\s*[a-zA-Z0-9_]+)?;)"), "", std::regex_constants::format_first_only);
|
method_stub = std::regex_replace(method_stub, std::regex(R"((\s*=\s*[a-zA-Z0-9_]+)?;)"), "", std::regex_constants::format_first_only);
|
||||||
rtrim(method_stub);
|
rtrim(method_stub);
|
||||||
//method_stub.pop_back(); // get rid of semicolon
|
|
||||||
|
|
||||||
/* std::string mvar_name = FUNC_VAR_PREFIX + (is_constructor ? "new" : "destroy") + current_class; */
|
/* std::string mvar_name = FUNC_VAR_PREFIX + (is_constructor ? "new" : "destroy") + current_class; */
|
||||||
std::string func_type = current_class + FUNC_SUFFIX;
|
std::string func_type = current_class + FUNC_SUFFIX;
|
||||||
|
|
@ -439,24 +477,11 @@ void output_consdes(std::stringstream& out, const cppast::cpp_entity& e, std::st
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
for (auto& param : mf.parameters()) {
|
for (auto& param : mf.parameters()) {
|
||||||
all_params_stream << ( i ? ", " : "" );
|
all_params_stream << ( i ? ", " : "" ) << param.name();
|
||||||
all_params_stream << param.name();
|
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
std::string all_params = all_params_stream.str();
|
std::string all_params = all_params_stream.str();
|
||||||
|
|
||||||
// generate class var
|
|
||||||
/* out << prefix; */
|
|
||||||
/* if (is_constructor) { */
|
|
||||||
/* out << "new"; */
|
|
||||||
/* } */
|
|
||||||
/* else { */
|
|
||||||
/* out << "destroy"; */
|
|
||||||
/* } */
|
|
||||||
/* out << func_type << " " << mvar_name << ";\n"; */
|
|
||||||
// TODO: Generate class var accessors (Get and Set)
|
|
||||||
// Maybe don't need to?
|
|
||||||
|
|
||||||
// generate method
|
// generate method
|
||||||
auto new_stub = std::regex_replace(method_stub, std::regex(base_class), current_class, std::regex_constants::format_first_only);
|
auto new_stub = std::regex_replace(method_stub, std::regex(base_class), current_class, std::regex_constants::format_first_only);
|
||||||
out << prefix << new_stub;
|
out << prefix << new_stub;
|
||||||
|
|
@ -465,24 +490,49 @@ void output_consdes(std::stringstream& out, const cppast::cpp_entity& e, std::st
|
||||||
out << ": " << base_class << "(" << all_params << ")";
|
out << ": " << base_class << "(" << all_params << ")";
|
||||||
}
|
}
|
||||||
out << prefix << "{";
|
out << prefix << "{";
|
||||||
//out << prefix << prefix;
|
|
||||||
|
|
||||||
/* out << "if (" << mvar_name << "){\n"; */
|
|
||||||
/* out << prefix << prefix << prefix; */
|
|
||||||
/* if (i > 0) { */
|
|
||||||
/* out << mvar_name << "(" << all_params << ");\n"; */
|
|
||||||
/* } */
|
|
||||||
/* else { */
|
|
||||||
/* out << mvar_name << "();\n"; */
|
|
||||||
/* } */
|
|
||||||
/* out << prefix << prefix; */
|
|
||||||
/* out << "}\n"; // endif */
|
|
||||||
/* // */
|
|
||||||
out << prefix << "}\n";
|
out << prefix << "}\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool efilter(const cppast::cpp_entity& e, cppast::cpp_access_specifier_kind access) {
|
||||||
|
// only visit non-templated class definitions
|
||||||
|
return (!cppast::is_templated(e) && !cppast::is_template(e.kind()) && e.kind() != cppast::cpp_entity_kind::class_template_t &&
|
||||||
|
access != cppast::cpp_private &&
|
||||||
|
(
|
||||||
|
(e.kind() == cppast::cpp_entity_kind::class_t && cppast::is_definition(e)) ||
|
||||||
|
(e.kind() == cppast::cpp_entity_kind::member_function_t && static_cast<const cppast::cpp_member_function_base&>(e).is_virtual()) ||
|
||||||
|
(e.kind() == cppast::cpp_entity_kind::constructor_t) ||
|
||||||
|
(e.kind() == cppast::cpp_entity_kind::destructor_t && static_cast<const cppast::cpp_destructor&>(e).is_virtual()) ||
|
||||||
|
e.kind() == cppast::cpp_entity_kind::base_class_t ||
|
||||||
|
e.kind() == cppast::cpp_entity_kind::macro_definition_t ||
|
||||||
|
e.kind() == cppast::cpp_entity_kind::type_alias_t
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool method_filter(const cppast::cpp_entity& e, cppast::cpp_access_specifier_kind access) {
|
||||||
|
// only visit non-templated class definitions
|
||||||
|
return (!cppast::is_templated(e) && !cppast::is_template(e.kind()) && e.kind() != cppast::cpp_entity_kind::class_template_t &&
|
||||||
|
access != cppast::cpp_private &&
|
||||||
|
(
|
||||||
|
(e.kind() == cppast::cpp_entity_kind::member_function_t && static_cast<const cppast::cpp_member_function_base&>(e).is_virtual())
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string hash_member_function(const cppast::cpp_member_function& mf) {
|
||||||
|
std::stringstream stream;
|
||||||
|
stream << sanitize_method_name(mf.name()) << "<";
|
||||||
|
int i = 0;
|
||||||
|
for (auto& param : mf.parameters()) {
|
||||||
|
stream << (i != 0 ? ", " : "") << cppast::to_string(param.type());
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
stream << ">";
|
||||||
|
return stream.str();
|
||||||
|
}
|
||||||
|
|
||||||
// prints the AST of a file
|
// prints the AST of a file
|
||||||
void print_ast(std::ostream& out, const cppast::cpp_file& file)
|
void print_ast(std::ostream& out, const cppast::cpp_file& file, const cppast::cpp_entity_index& idx)
|
||||||
{
|
{
|
||||||
// print file name
|
// print file name
|
||||||
std::cerr << "AST for '" << file.name() << "':\n";
|
std::cerr << "AST for '" << file.name() << "':\n";
|
||||||
|
|
@ -513,32 +563,19 @@ void print_ast(std::ostream& out, const cppast::cpp_file& file)
|
||||||
bool in_class = false;
|
bool in_class = false;
|
||||||
bool has_class_ending = false;
|
bool has_class_ending = false;
|
||||||
|
|
||||||
|
std::map<std::string, const cppast::cpp_member_function*> members;
|
||||||
|
|
||||||
// - Forward declare the class
|
// - Forward declare the class
|
||||||
// - typedef all of the virtual methods with class as first arg
|
// - typedef all of the virtual methods with class as first arg
|
||||||
// - declare the class with a postfix (class wxAppC: public wxApp)
|
// - declare the class with a postfix (class wxAppC: public wxApp)
|
||||||
// - output variable and virtual method override
|
// - output variable and virtual method override
|
||||||
// check function pointer for null, then call it
|
// check function pointer for null, then call it
|
||||||
//
|
//
|
||||||
cppast::visit(file,
|
cppast::visit(file, efilter,
|
||||||
[](const cppast::cpp_entity& e, cppast::cpp_access_specifier_kind access) {
|
|
||||||
// only visit non-templated class definitions
|
|
||||||
return (!cppast::is_templated(e) && !cppast::is_template(e.kind()) && e.kind() != cppast::cpp_entity_kind::class_template_t &&
|
|
||||||
access != cppast::cpp_private &&
|
|
||||||
(
|
|
||||||
(e.kind() == cppast::cpp_entity_kind::class_t && cppast::is_definition(e)) ||
|
|
||||||
(e.kind() == cppast::cpp_entity_kind::member_function_t && static_cast<const cppast::cpp_member_function_base&>(e).is_virtual()) ||
|
|
||||||
(e.kind() == cppast::cpp_entity_kind::constructor_t) ||
|
|
||||||
(e.kind() == cppast::cpp_entity_kind::destructor_t && static_cast<const cppast::cpp_destructor&>(e).is_virtual()) ||
|
|
||||||
e.kind() == cppast::cpp_entity_kind::base_class_t ||
|
|
||||||
e.kind() == cppast::cpp_entity_kind::macro_definition_t ||
|
|
||||||
e.kind() == cppast::cpp_entity_kind::type_alias_t
|
|
||||||
)
|
|
||||||
);
|
|
||||||
},
|
|
||||||
|
|
||||||
[&](const cppast::cpp_entity& e, cppast::visitor_info info) {
|
[&](const cppast::cpp_entity& e, cppast::visitor_info info) {
|
||||||
if (info.event == cppast::visitor_info::container_entity_enter) {
|
if (info.event == cppast::visitor_info::container_entity_enter) {
|
||||||
if (e.kind() == cppast::cpp_entity_kind::class_t) {
|
if (e.kind() == cppast::cpp_entity_kind::class_t && !in_class) {
|
||||||
|
|
||||||
if (e.name().empty()) {
|
if (e.name().empty()) {
|
||||||
// it was a fake exit event
|
// it was a fake exit event
|
||||||
//std::cerr << "FAAAAAAAAAAAKE\n";
|
//std::cerr << "FAAAAAAAAAAAKE\n";
|
||||||
|
|
@ -548,7 +585,25 @@ void print_ast(std::ostream& out, const cppast::cpp_file& file)
|
||||||
has_class_ending = true;
|
has_class_ending = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
else if (has_class_ending) {
|
else if (has_class_ending) { // EXIT CLASS
|
||||||
|
|
||||||
|
for (auto const& kv : members) {
|
||||||
|
auto& mf = kv.second;
|
||||||
|
std::cerr << "OUTPUTTING: " << current_class << " " << mf->name() << std::endl;
|
||||||
|
|
||||||
|
int j = 0;
|
||||||
|
for (auto& param : mf->parameters()) {
|
||||||
|
if (param.name().empty()) {
|
||||||
|
param.set_name("param" + std::to_string(j));
|
||||||
|
}
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
output_member_function_param(init_params, *mf, current_class);
|
||||||
|
output_member_function_var_init(var_init, prefix, *mf, current_class);
|
||||||
|
output_member_function_typedef(forward_decls, *mf, current_class);
|
||||||
|
output_member_function(class_stream, *mf, prefix, base_class, current_class);
|
||||||
|
}
|
||||||
|
|
||||||
auto param_str = init_params.str();
|
auto param_str = init_params.str();
|
||||||
auto var_init_str = var_init.str();
|
auto var_init_str = var_init.str();
|
||||||
if (param_str.length() >= 2) {
|
if (param_str.length() >= 2) {
|
||||||
|
|
@ -565,6 +620,7 @@ void print_ast(std::ostream& out, const cppast::cpp_file& file)
|
||||||
prefix.pop_back();
|
prefix.pop_back();
|
||||||
prefix.pop_back();
|
prefix.pop_back();
|
||||||
has_class_ending = false;
|
has_class_ending = false;
|
||||||
|
members.clear();
|
||||||
//std::cerr << "EXIT CLASS\n";
|
//std::cerr << "EXIT CLASS\n";
|
||||||
//std::cerr << current_class << "\n\n";
|
//std::cerr << current_class << "\n\n";
|
||||||
}
|
}
|
||||||
|
|
@ -579,6 +635,44 @@ void print_ast(std::ostream& out, const cppast::cpp_file& file)
|
||||||
class_stream << "public:\n";
|
class_stream << "public:\n";
|
||||||
prefix += PREFIX_SPACING;
|
prefix += PREFIX_SPACING;
|
||||||
in_class = true;
|
in_class = true;
|
||||||
|
|
||||||
|
// Record the methods of the classes and base classes
|
||||||
|
auto& mf = static_cast<const cppast::cpp_class&>(e);
|
||||||
|
std::vector<const cppast::cpp_entity*> stack;
|
||||||
|
|
||||||
|
std::cerr << "\nCLASS: " << mf.name() << std::endl;
|
||||||
|
|
||||||
|
for (auto& base : mf.bases()) {
|
||||||
|
auto entity = idx.lookup(*static_cast<const cppast::cpp_user_defined_type&>(base.type()).entity().id().data());
|
||||||
|
std::cerr << "BASENAME: " << base.name() << std::endl;
|
||||||
|
if (entity.has_value()) {
|
||||||
|
stack.push_back(&entity.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (!stack.empty()) {
|
||||||
|
auto entity = stack.back(); stack.pop_back();
|
||||||
|
auto& entclass = static_cast<const cppast::cpp_class&>(*entity);
|
||||||
|
if (entclass.name().empty()) continue;
|
||||||
|
std::cerr << "BASECLASS: " << entclass.name() << std::endl;
|
||||||
|
cppast::visit(entclass, method_filter,
|
||||||
|
[&](const cppast::cpp_entity& e, cppast::visitor_info info) {
|
||||||
|
auto& mf = static_cast<const cppast::cpp_member_function&>(e);
|
||||||
|
auto mname = hash_member_function(mf);
|
||||||
|
std::cerr << "METHOD NAME: " << mf.name() << " (" << mname << ")" << std::endl;
|
||||||
|
std::cerr << "IN MEMBERS: " << !members.count(mname) << std::endl;
|
||||||
|
if (!members.count(mname)) {
|
||||||
|
members[mname] = &mf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
for (auto& entbase : entclass.bases()) {
|
||||||
|
auto ent = idx.lookup(*static_cast<const cppast::cpp_user_defined_type&>(entbase.type()).entity().id().data());
|
||||||
|
if (ent.has_value()) {
|
||||||
|
stack.push_back(&ent.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (info.event == cppast::visitor_info::container_entity_exit)
|
else if (info.event == cppast::visitor_info::container_entity_exit)
|
||||||
|
|
@ -619,21 +713,11 @@ void print_ast(std::ostream& out, const cppast::cpp_file& file)
|
||||||
}
|
}
|
||||||
else if (e.kind() == cppast::cpp_entity_kind::member_function_t) {
|
else if (e.kind() == cppast::cpp_entity_kind::member_function_t) {
|
||||||
auto& mf = static_cast<const cppast::cpp_member_function&>(e);
|
auto& mf = static_cast<const cppast::cpp_member_function&>(e);
|
||||||
//std::cerr << sanitize_method_name(mf.name()) << "\n\n";
|
auto mname = hash_member_function(mf);
|
||||||
/* if (mf.is_definition()) { */
|
if (!members.count(mname)) {
|
||||||
/* return true; */
|
members[mname] = &mf;
|
||||||
/* } */
|
|
||||||
int j = 0;
|
|
||||||
for (auto& param : mf.parameters()) {
|
|
||||||
if (param.name().empty()) {
|
|
||||||
param.set_name("param" + std::to_string(j));
|
|
||||||
}
|
|
||||||
j++;
|
|
||||||
}
|
}
|
||||||
output_member_function_param(init_params, e, current_class);
|
|
||||||
output_member_function_var_init(var_init, prefix, e, current_class);
|
|
||||||
output_member_function_typedef(forward_decls, e, current_class);
|
|
||||||
output_member_function(class_stream, e, prefix, base_class, current_class);
|
|
||||||
}
|
}
|
||||||
/* else if (e.kind() == cppast::cpp_entity_kind::type_alias_t) { */
|
/* else if (e.kind() == cppast::cpp_entity_kind::type_alias_t) { */
|
||||||
/* auto& alias = static_cast<const cppast::cpp_type_alias&>(e); */
|
/* auto& alias = static_cast<const cppast::cpp_type_alias&>(e); */
|
||||||
|
|
@ -649,6 +733,23 @@ void print_ast(std::ostream& out, const cppast::cpp_file& file)
|
||||||
});
|
});
|
||||||
|
|
||||||
if (has_class_ending) {
|
if (has_class_ending) {
|
||||||
|
std::cerr << "HAS CLASS ENDING!!!!!!!!!!" << std::endl;
|
||||||
|
for (auto const& kv : members) {
|
||||||
|
auto& mf = kv.second;
|
||||||
|
std::cerr << "OUTPUTTING: " << current_class << " " << mf->name() << std::endl;
|
||||||
|
|
||||||
|
int j = 0;
|
||||||
|
for (auto& param : mf->parameters()) {
|
||||||
|
if (param.name().empty()) {
|
||||||
|
param.set_name("param" + std::to_string(j));
|
||||||
|
}
|
||||||
|
j++;
|
||||||
|
}
|
||||||
|
output_member_function_param(init_params, *mf, current_class);
|
||||||
|
output_member_function_var_init(var_init, prefix, *mf, current_class);
|
||||||
|
output_member_function_typedef(forward_decls, *mf, current_class);
|
||||||
|
output_member_function(class_stream, *mf, prefix, base_class, current_class);
|
||||||
|
}
|
||||||
auto param_str = init_params.str();
|
auto param_str = init_params.str();
|
||||||
auto var_init_str = var_init.str();
|
auto var_init_str = var_init.str();
|
||||||
if (param_str.length() >= 2) {
|
if (param_str.length() >= 2) {
|
||||||
|
|
@ -665,6 +766,7 @@ void print_ast(std::ostream& out, const cppast::cpp_file& file)
|
||||||
prefix.pop_back();
|
prefix.pop_back();
|
||||||
prefix.pop_back();
|
prefix.pop_back();
|
||||||
has_class_ending = false;
|
has_class_ending = false;
|
||||||
|
members.clear();
|
||||||
}
|
}
|
||||||
out << forward_decls.str() << "\n";
|
out << forward_decls.str() << "\n";
|
||||||
out << class_stream.str() << "\n\n";
|
out << class_stream.str() << "\n\n";
|
||||||
|
|
@ -675,11 +777,9 @@ void print_ast(std::ostream& out, const cppast::cpp_file& file)
|
||||||
// parse a file
|
// parse a file
|
||||||
std::unique_ptr<cppast::cpp_file> parse_file(const cppast::libclang_compile_config& config,
|
std::unique_ptr<cppast::cpp_file> parse_file(const cppast::libclang_compile_config& config,
|
||||||
const cppast::diagnostic_logger& logger,
|
const cppast::diagnostic_logger& logger,
|
||||||
const std::string& filename, bool fatal_error)
|
const std::string& filename, bool fatal_error,
|
||||||
|
cppast::cpp_entity_index& idx)
|
||||||
{
|
{
|
||||||
// the entity index is used to resolve cross references in the AST
|
|
||||||
// we don't need that, so it will not be needed afterwards
|
|
||||||
cppast::cpp_entity_index idx;
|
|
||||||
// the parser is used to parse the entity
|
// the parser is used to parse the entity
|
||||||
// there can be multiple parser implementations
|
// there can be multiple parser implementations
|
||||||
cppast::libclang_parser parser(type_safe::ref(logger));
|
cppast::libclang_parser parser(type_safe::ref(logger));
|
||||||
|
|
@ -690,6 +790,44 @@ std::unique_ptr<cppast::cpp_file> parse_file(const cppast::libclang_compile_conf
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool hasEnding (std::string const &fullString, std::string const &ending) {
|
||||||
|
if (fullString.length() >= ending.length()) {
|
||||||
|
return (0 == fullString.compare (fullString.length() - ending.length(), ending.length(), ending));
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class FileParser>
|
||||||
|
std::size_t resolve_includes2(FileParser& parser, const cppast::cpp_file& file,
|
||||||
|
typename FileParser::config config)
|
||||||
|
{
|
||||||
|
auto count = 0u;
|
||||||
|
for (auto& entity : file)
|
||||||
|
{
|
||||||
|
if (entity.kind() == cppast::cpp_include_directive::kind())
|
||||||
|
{
|
||||||
|
auto& include = static_cast<const cppast::cpp_include_directive&>(entity);
|
||||||
|
auto& path = include.full_path();
|
||||||
|
if (path.ends_with("button.h")) {
|
||||||
|
parser.parse(path, config);
|
||||||
|
++count;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void readFile(std::string filename, std::list<std::string>& lines)
|
||||||
|
{
|
||||||
|
lines.clear();
|
||||||
|
std::ifstream file(filename);
|
||||||
|
std::string s;
|
||||||
|
while (getline(file, s))
|
||||||
|
lines.push_back(s);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char* argv[])
|
int main(int argc, char* argv[])
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
@ -708,6 +846,8 @@ try
|
||||||
cxxopts::value<std::string>())
|
cxxopts::value<std::string>())
|
||||||
("database_file", "set the file name whose configuration will be used regardless of the current file name",
|
("database_file", "set the file name whose configuration will be used regardless of the current file name",
|
||||||
cxxopts::value<std::string>())
|
cxxopts::value<std::string>())
|
||||||
|
("file_list", "set the file name to get a list of files to process from, separated by newlines",
|
||||||
|
cxxopts::value<std::string>())
|
||||||
("std", "set the C++ standard (c++98, c++03, c++11, c++14, c++1z (experimental), c++17, c++2a, c++20)",
|
("std", "set the C++ standard (c++98, c++03, c++11, c++14, c++1z (experimental), c++17, c++2a, c++20)",
|
||||||
cxxopts::value<std::string>()->default_value(cppast::to_string(cppast::cpp_standard::cpp_latest)))
|
cxxopts::value<std::string>()->default_value(cppast::to_string(cppast::cpp_standard::cpp_latest)))
|
||||||
("I,include_directory", "add directory to include search path",
|
("I,include_directory", "add directory to include search path",
|
||||||
|
|
@ -825,12 +965,39 @@ try
|
||||||
cppast::stderr_diagnostic_logger logger;
|
cppast::stderr_diagnostic_logger logger;
|
||||||
if (options.count("verbose"))
|
if (options.count("verbose"))
|
||||||
logger.set_verbose(true);
|
logger.set_verbose(true);
|
||||||
|
// the entity index is used to resolve cross references in the AST
|
||||||
|
cppast::cpp_entity_index idx;
|
||||||
|
/* auto file = parse_file(config, logger, options["file"].as<std::string>(), */
|
||||||
|
/* options.count("fatal_errors") == 1, idx); */
|
||||||
|
|
||||||
|
cppast::simple_file_parser<cppast::libclang_parser> parser(type_safe::ref(idx));
|
||||||
|
|
||||||
|
std::list<std::string> fileList;
|
||||||
|
if (options.count("file_list")) {
|
||||||
|
auto fname = options["file_list"].as<std::string>();
|
||||||
|
readFile(fname, fileList);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fileList.push_back(options["file"].as<std::string>());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unordered_set<std::string> to_visit;
|
||||||
|
to_visit.insert(options["file"].as<std::string>());
|
||||||
|
/* for (auto f : files) { */
|
||||||
|
/* to_visit.insert(f); */
|
||||||
|
/* } */
|
||||||
|
cppast::parse_files(parser, fileList, config);
|
||||||
|
for (auto& f : parser.files()) {
|
||||||
|
std::cerr << "PARSING: " << f.name() << std::endl;
|
||||||
|
//resolve_includes2(parser, f, config);
|
||||||
|
/* if (f.name().ends_with("/button.h")) { */
|
||||||
|
/* print_ast(std::cout, f, idx); */
|
||||||
|
/* } */
|
||||||
|
if (!to_visit.count(f.name())) continue;
|
||||||
|
|
||||||
|
print_ast(std::cout, f, idx);
|
||||||
|
}
|
||||||
|
|
||||||
auto file = parse_file(config, logger, options["file"].as<std::string>(),
|
|
||||||
options.count("fatal_errors") == 1);
|
|
||||||
if (!file)
|
|
||||||
return 2;
|
|
||||||
print_ast(std::cout, *file);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (const cppast::libclang_error& ex)
|
catch (const cppast::libclang_error& ex)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue