From f6ede536024079f29b75f61fdf9dd86feec66edb Mon Sep 17 00:00:00 2001 From: Andrii Verbytskyi Date: Mon, 26 Apr 2021 14:58:11 +0200 Subject: [PATCH 1/7] First attempt to bind constants --- source/CMakeLists.txt | 3 ++ source/binder.cpp | 10 ++++ source/const.cpp | 114 ++++++++++++++++++++++++++++++++++++++++ source/const.hpp | 63 ++++++++++++++++++++++ test/CMakeLists.txt | 47 +++++++++-------- test/T00.basic.ref | 3 ++ test/T60.const.hpp | 48 +++++++++++++++++ test/T60.const.ref | 119 ++++++++++++++++++++++++++++++++++++++++++ test/T60_const.cpp | 119 ++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 503 insertions(+), 23 deletions(-) create mode 100644 source/const.cpp create mode 100644 source/const.hpp create mode 100644 test/T60.const.hpp create mode 100644 test/T60.const.ref create mode 100644 test/T60_const.cpp diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 70a9f2df..b20a5879 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -21,6 +21,9 @@ add_clang_executable(binder enum.hpp enum.cpp + const.hpp + const.cpp + function.hpp function.cpp diff --git a/source/binder.cpp b/source/binder.cpp index 51de4043..e8721a95 100644 --- a/source/binder.cpp +++ b/source/binder.cpp @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -208,6 +209,15 @@ class BinderVisitor : public RecursiveASTVisitor return true; } + virtual bool VisitVarDecl(VarDecl *V) { + if( !V->getType().isConstQualified() ) return true; + if( !V->hasInit() ) return true; + if( V->getType().getTypePtr()->isArrayType()) return true; + if( V->isCXXInstanceMember() or V->isCXXClassMember() ) return true; + binder::BinderOP b = std::make_shared( V ); + context.add(b); + return true; + } void generate(void) { context.generate( Config::get() ); diff --git a/source/const.cpp b/source/const.cpp new file mode 100644 index 00000000..c39fbaf6 --- /dev/null +++ b/source/const.cpp @@ -0,0 +1,114 @@ +// -*- mode:c++;tab-width:2;indent-tabs-mode:t;show-trailing-whitespace:t;rm-trailing-spaces:t -*- +// vi: set ts=2 noet: +// +// Copyright (c) 2021 Sergey Lyskov +// +// All rights reserved. Use of this source code is governed by a +// MIT license that can be found in the LICENSE file. + +/// @file binder/const.cpp +/// @brief Binding generation for C++ constants +/// @author Sergey Lyskov, Andrii Verbytskyi + + +#include + +#include +#include + +#include + +#include + +using namespace llvm; +using namespace clang; +#include +using std::string; +using std::vector; + +using namespace fmt::literals; + +namespace binder { + +/// check if generator can create binding +bool is_bindable(VarDecl const *E) +{ + if ( !E->getType().isConstQualified() ) return false; + if ( !E->hasInit() ) return false; + if ( E->getType().getTypePtr()->isArrayType()) return false; + if( E->isCXXInstanceMember() or E->isCXXClassMember() ) return false; + if( E->isCXXInstanceMember() ) return false; + if ( standard_name( E->getType().getCanonicalType().getAsString() ) == "const std::string" ) return true; + if (E->getType().getTypePtr()->isRealFloatingType() ) return true; + if (E->getType().getTypePtr()->isIntegerType() ) return true; + if (E->getType().getTypePtr()->isBooleanType() ) return true; + return false; +} + +// Generate binding for given function: py::enum_(module, "MyEnum")... +std::string bind_const(std::string const & module, VarDecl const *E) +{ + string r=" "; + clang::Expr const* init = E->getInit(); + if (init){ + string name { E->getNameAsString() }; + std::string type = E->getType().getCanonicalType().getAsString(); + std::string pytype = ""; + bool pytype_set = false; +//This is a list of types that can bi binded with pybind, see https://pybind11.readthedocs.io/en/stable/advanced/pycpp/object.html*/ + if ( !pytype_set and standard_name( type ) == "const std::string" ) { pytype_set=true; pytype="str";} + if ( !pytype_set and E->getType().getTypePtr()->isRealFloatingType() ) { pytype_set=true; pytype="float_"; } + if ( !pytype_set and E->getType().getTypePtr()->isIntegerType() ) { pytype_set=true; pytype="int_"; } + if ( !pytype_set and E->getType().getTypePtr()->isBooleanType() ) { pytype_set=true; pytype="bool_"; } + if (pytype_set) { + std::string rhs; + llvm::raw_string_ostream rso(rhs); + clang::LangOptions lang_opts; + lang_opts.CPlusPlus = true; + clang::PrintingPolicy Policy(lang_opts); + init->printPretty(rso, NULL, Policy); + r = "\t{}.attr(\"{}\") = pybind11::{}({})\n"_format( module, name, pytype, rhs); + } + } + r.pop_back(); + return r; +} + + +/// Generate string id that uniquly identify C++ binding object. For functions this is function prototype and for classes forward declaration. +string ConstBinder::id() const +{ + return E->getQualifiedNameAsString(); +} + + +/// check if generator can create binding +bool ConstBinder::bindable() const +{ + return is_bindable(E); +} + +/// check if user requested binding for the given declaration +void ConstBinder::request_bindings_and_skipping(Config const &config) +{ + if( config.is_namespace_binding_requested( namespace_from_named_decl(E) ) ) Binder::request_bindings(); +} + + +/// extract include needed for this generator and add it to includes vector +void ConstBinder::add_relevant_includes(IncludeSet &includes) const +{ +} + +/// generate binding code for this object and all its dependencies +void ConstBinder::bind(Context &context) +{ + if( is_binded() ) return; + + string const module_variable_name = context.module_variable_name( namespace_from_named_decl(E) ); + + code() = "\t" + generate_comment_for_declaration(E); + code() += bind_const(module_variable_name, E) + ";\n\n"; +} + +} // namespace binder diff --git a/source/const.hpp b/source/const.hpp new file mode 100644 index 00000000..08b5c7de --- /dev/null +++ b/source/const.hpp @@ -0,0 +1,63 @@ +// -*- mode:c++;tab-width:2;indent-tabs-mode:t;show-trailing-whitespace:t;rm-trailing-spaces:t -*- +// vi: set ts=2 noet: +// +// Copyright (c) 2021 Sergey Lyskov +// +// All rights reserved. Use of this source code is governed by a +// MIT license that can be found in the LICENSE file. + +/// @file binder/const.hpp +/// @brief Binding generation for C++ constant expressions +/// @author Sergey Lyskov, Andrii Verbytskyi + + +#ifndef _INCLUDED_const_hpp_ +#define _INCLUDED_const_hpp_ + +#include + +#include + +#include + +namespace binder { + +/// check if generator can create binding +bool is_bindable(clang::VarDecl const *E); + + +// Generate binding for given function +std::string bind_const(std::string const & module, clang::VarDecl const *E); + + +class ConstBinder : public Binder +{ +public: + ConstBinder(clang::VarDecl const *e) : E(e) {} + + /// Generate string id that uniquly identify C++ binding object. For functions this is function prototype and for classes forward declaration. + string id() const override; + // return Clang AST NamedDecl pointer to original declaration used to create this Binder + clang::NamedDecl const * named_decl() const override { return E; }; + + /// check if generator can create binding + bool bindable() const override; + + /// check if user requested binding for the given declaration + virtual void request_bindings_and_skipping(Config const &) override; + + /// extract include needed for this generator and add it to includes vector + void add_relevant_includes(IncludeSet &includes) const override; + + /// generate binding code for this object and all its dependencies + void bind(Context &) override; + + +private: + clang::VarDecl const *E; +}; + + +} // namespace binder + +#endif // _INCLUDED_const_hpp_ diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a825585b..a42b7cf6 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -80,29 +80,30 @@ macro( binder_test testname vers) endmacro( binder_test testname vers) set( binder_tests T00.basic - T01.enum - T02.function - T05.default - T07.class - T08.constructor - T09.overload - T10.inheritance - T11.override - T12.operator - T15.copy - T15.inner_class - T17.anonymous - T20.template - T30.include - T31.include_for_class - T32.call_guard - T40.stl - T42.stl.names - T42.stl.names.map - T42.stl.names.set - T42.stl.names.multimap - T42.stl.names.multiset - T50.namespace_binder +# T01.enum +# T02.function +# T05.default +# T07.class +# T08.constructor +# T09.overload +# T10.inheritance +# T11.override +# T12.operator +# T15.copy +# T15.inner_class +# T17.anonymous +# T20.template +# T30.include +# T31.include_for_class +# T32.call_guard +# T40.stl +# T42.stl.names +# T42.stl.names.map +# T42.stl.names.set +# T42.stl.names.multimap +# T42.stl.names.multiset +# T50.namespace_binder + T60.const ) if (pybind11_VERSION VERSION_LESS 2.5.99) message(STATUS "pybind11 version ${pybind11_VERSION} is less than 2.5.99. Some tests will be disabled." ) diff --git a/test/T00.basic.ref b/test/T00.basic.ref index a983dd19..708a0a40 100644 --- a/test/T00.basic.ref +++ b/test/T00.basic.ref @@ -19,6 +19,9 @@ void bind_T00_basic(std::function< pybind11::module &(std::string const &namespace_) > &M) { + M("").attr("some_constant") = pybind11::int_(14); + + // foo() file:T00.basic.hpp line:25 M("").def("foo", (void (*)()) &foo, "C++: foo() --> void"); diff --git a/test/T60.const.hpp b/test/T60.const.hpp new file mode 100644 index 00000000..f04f508b --- /dev/null +++ b/test/T60.const.hpp @@ -0,0 +1,48 @@ +// -*- mode:c++;tab-width:2;indent-tabs-mode:t;show-trailing-whitespace:t;rm-trailing-spaces:t -*- +// vi: set ts=2 noet: +// +// Copyright (c) 2016 Sergey Lyskov +// +// All rights reserved. Use of this source code is governed by a +// MIT license that can be found in the LICENSE file. + +/// @file binder/test/T00.basic.hpp +/// @brief Binder self-test file. Basic functionality. +/// @author Sergey Lyskov + +#ifndef _INCLUDED_T60_basic_hpp_ +#define _INCLUDED_T60_basic_hpp_ +#include +#include + +const int global_int=1; +const long global_long=2; + +const unsigned int global_unsigned_int=3; +const unsigned long global_unsigned_long=4; + +const float global_float=5.0; +const double global_double=6.0; + +const std::string global_string1="Some test string"; + +const std::string global_string2=std::string("Some test string"); + + +const double expression_global_double=8.0+1.0/5.0; + +const double array_global_double[5]={1.0,2.0,3.0,4.0,5.0}; //This should not appear in bindings so far. + +const std::vector vector_global_double{1.0,2.0,3.0,4.0,5.0}; //This should not appear in bindings so far. + +int foo_char(char *) { return 0; } + +namespace foo +{ +const double foonamespaced_global_double=7.0; + +int foonamespaced_foo_char(char *) { return 0; } + +} + +#endif // _INCLUDED_T60_basic_hpp_ diff --git a/test/T60.const.ref b/test/T60.const.ref new file mode 100644 index 00000000..837ad2ca --- /dev/null +++ b/test/T60.const.ref @@ -0,0 +1,119 @@ +// File: T60_const.cpp +#include // foo_char + +#include +#include +#include + +#ifndef BINDER_PYBIND11_TYPE_CASTER + #define BINDER_PYBIND11_TYPE_CASTER + PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr) + PYBIND11_DECLARE_HOLDER_TYPE(T, T*) + PYBIND11_MAKE_OPAQUE(std::shared_ptr) +#endif + +void bind_T60_const(std::function< pybind11::module &(std::string const &namespace_) > &M) +{ + // global_int file:T60.const.hpp line:18 + M("").attr("global_int") = pybind11::int_(1); + + // global_long file:T60.const.hpp line:19 + M("").attr("global_long") = pybind11::int_(2); + + // global_unsigned_int file:T60.const.hpp line:21 + M("").attr("global_unsigned_int") = pybind11::int_(3); + + // global_unsigned_long file:T60.const.hpp line:22 + M("").attr("global_unsigned_long") = pybind11::int_(4); + + // global_float file:T60.const.hpp line:24 + M("").attr("global_float") = pybind11::float_(5.); + + // global_double file:T60.const.hpp line:25 + M("").attr("global_double") = pybind11::float_(6.); + + // global_string1 file:T60.const.hpp line:27 + M("").attr("global_string1") = pybind11::str("Some test string"); + + // global_string2 file:T60.const.hpp line:29 + M("").attr("global_string2") = pybind11::str(std::string("Some test string")); + + // expression_global_double file:T60.const.hpp line:32 + M("").attr("expression_global_double") = pybind11::float_(8. + 1. / 5.); + + // foo_char(char *) file:T60.const.hpp line:38 + M("").def("foo_char", (int (*)(char *)) &foo_char, "C++: foo_char(char *) --> int", pybind11::arg("")); + +} + + +// File: T60_const_1.cpp +#include // foo::foonamespaced_foo_char + +#include +#include +#include + +#ifndef BINDER_PYBIND11_TYPE_CASTER + #define BINDER_PYBIND11_TYPE_CASTER + PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr) + PYBIND11_DECLARE_HOLDER_TYPE(T, T*) + PYBIND11_MAKE_OPAQUE(std::shared_ptr) +#endif + +void bind_T60_const_1(std::function< pybind11::module &(std::string const &namespace_) > &M) +{ + // foo::foonamespaced_global_double file:T60.const.hpp line:42 + M("foo").attr("foonamespaced_global_double") = pybind11::float_(7.); + + // foo::foonamespaced_foo_char(char *) file:T60.const.hpp line:44 + M("foo").def("foonamespaced_foo_char", (int (*)(char *)) &foo::foonamespaced_foo_char, "C++: foo::foonamespaced_foo_char(char *) --> int", pybind11::arg("")); + +} + + +#include +#include +#include +#include +#include + +#include + +typedef std::function< pybind11::module & (std::string const &) > ModuleGetter; + +void bind_T60_const(std::function< pybind11::module &(std::string const &namespace_) > &M); +void bind_T60_const_1(std::function< pybind11::module &(std::string const &namespace_) > &M); + + +PYBIND11_MODULE(T60_const, root_module) { + root_module.doc() = "T60_const module"; + + std::map modules; + ModuleGetter M = [&](std::string const &namespace_) -> pybind11::module & { + auto it = modules.find(namespace_); + if( it == modules.end() ) throw std::runtime_error("Attempt to access pybind11::module for namespace " + namespace_ + " before it was created!!!"); + return it->second; + }; + + modules[""] = root_module; + + std::vector< std::pair > sub_modules { + {"", "foo"}, + }; + for(auto &p : sub_modules ) modules[p.first.size() ? p.first+"::"+p.second : p.second] = modules[p.first].def_submodule(p.second.c_str(), ("Bindings for " + p.first + "::" + p.second + " namespace").c_str() ); + + //pybind11::class_>(M(""), "_encapsulated_data_"); + + bind_T60_const(M); + bind_T60_const_1(M); + +} + +// Source list file: /home/andriish/Projects/binder/test//T60_const.sources +// T60_const.cpp +// T60_const.cpp +// T60_const_1.cpp + +// Modules list file: /home/andriish/Projects/binder/test//T60_const.modules +// foo diff --git a/test/T60_const.cpp b/test/T60_const.cpp new file mode 100644 index 00000000..837ad2ca --- /dev/null +++ b/test/T60_const.cpp @@ -0,0 +1,119 @@ +// File: T60_const.cpp +#include // foo_char + +#include +#include +#include + +#ifndef BINDER_PYBIND11_TYPE_CASTER + #define BINDER_PYBIND11_TYPE_CASTER + PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr) + PYBIND11_DECLARE_HOLDER_TYPE(T, T*) + PYBIND11_MAKE_OPAQUE(std::shared_ptr) +#endif + +void bind_T60_const(std::function< pybind11::module &(std::string const &namespace_) > &M) +{ + // global_int file:T60.const.hpp line:18 + M("").attr("global_int") = pybind11::int_(1); + + // global_long file:T60.const.hpp line:19 + M("").attr("global_long") = pybind11::int_(2); + + // global_unsigned_int file:T60.const.hpp line:21 + M("").attr("global_unsigned_int") = pybind11::int_(3); + + // global_unsigned_long file:T60.const.hpp line:22 + M("").attr("global_unsigned_long") = pybind11::int_(4); + + // global_float file:T60.const.hpp line:24 + M("").attr("global_float") = pybind11::float_(5.); + + // global_double file:T60.const.hpp line:25 + M("").attr("global_double") = pybind11::float_(6.); + + // global_string1 file:T60.const.hpp line:27 + M("").attr("global_string1") = pybind11::str("Some test string"); + + // global_string2 file:T60.const.hpp line:29 + M("").attr("global_string2") = pybind11::str(std::string("Some test string")); + + // expression_global_double file:T60.const.hpp line:32 + M("").attr("expression_global_double") = pybind11::float_(8. + 1. / 5.); + + // foo_char(char *) file:T60.const.hpp line:38 + M("").def("foo_char", (int (*)(char *)) &foo_char, "C++: foo_char(char *) --> int", pybind11::arg("")); + +} + + +// File: T60_const_1.cpp +#include // foo::foonamespaced_foo_char + +#include +#include +#include + +#ifndef BINDER_PYBIND11_TYPE_CASTER + #define BINDER_PYBIND11_TYPE_CASTER + PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr) + PYBIND11_DECLARE_HOLDER_TYPE(T, T*) + PYBIND11_MAKE_OPAQUE(std::shared_ptr) +#endif + +void bind_T60_const_1(std::function< pybind11::module &(std::string const &namespace_) > &M) +{ + // foo::foonamespaced_global_double file:T60.const.hpp line:42 + M("foo").attr("foonamespaced_global_double") = pybind11::float_(7.); + + // foo::foonamespaced_foo_char(char *) file:T60.const.hpp line:44 + M("foo").def("foonamespaced_foo_char", (int (*)(char *)) &foo::foonamespaced_foo_char, "C++: foo::foonamespaced_foo_char(char *) --> int", pybind11::arg("")); + +} + + +#include +#include +#include +#include +#include + +#include + +typedef std::function< pybind11::module & (std::string const &) > ModuleGetter; + +void bind_T60_const(std::function< pybind11::module &(std::string const &namespace_) > &M); +void bind_T60_const_1(std::function< pybind11::module &(std::string const &namespace_) > &M); + + +PYBIND11_MODULE(T60_const, root_module) { + root_module.doc() = "T60_const module"; + + std::map modules; + ModuleGetter M = [&](std::string const &namespace_) -> pybind11::module & { + auto it = modules.find(namespace_); + if( it == modules.end() ) throw std::runtime_error("Attempt to access pybind11::module for namespace " + namespace_ + " before it was created!!!"); + return it->second; + }; + + modules[""] = root_module; + + std::vector< std::pair > sub_modules { + {"", "foo"}, + }; + for(auto &p : sub_modules ) modules[p.first.size() ? p.first+"::"+p.second : p.second] = modules[p.first].def_submodule(p.second.c_str(), ("Bindings for " + p.first + "::" + p.second + " namespace").c_str() ); + + //pybind11::class_>(M(""), "_encapsulated_data_"); + + bind_T60_const(M); + bind_T60_const_1(M); + +} + +// Source list file: /home/andriish/Projects/binder/test//T60_const.sources +// T60_const.cpp +// T60_const.cpp +// T60_const_1.cpp + +// Modules list file: /home/andriish/Projects/binder/test//T60_const.modules +// foo From e1828c7c12f065965a19a8b3e5a109e204a991d4 Mon Sep 17 00:00:00 2001 From: Andrii Verbytskyi Date: Mon, 26 Apr 2021 15:06:44 +0200 Subject: [PATCH 2/7] Uncomments tests --- test/CMakeLists.txt | 46 ++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a42b7cf6..59c2227e 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -80,29 +80,29 @@ macro( binder_test testname vers) endmacro( binder_test testname vers) set( binder_tests T00.basic -# T01.enum -# T02.function -# T05.default -# T07.class -# T08.constructor -# T09.overload -# T10.inheritance -# T11.override -# T12.operator -# T15.copy -# T15.inner_class -# T17.anonymous -# T20.template -# T30.include -# T31.include_for_class -# T32.call_guard -# T40.stl -# T42.stl.names -# T42.stl.names.map -# T42.stl.names.set -# T42.stl.names.multimap -# T42.stl.names.multiset -# T50.namespace_binder + T01.enum + T02.function + T05.default + T07.class + T08.constructor + T09.overload + T10.inheritance + T11.override + T12.operator + T15.copy + T15.inner_class + T17.anonymous + T20.template + T30.include + T31.include_for_class + T32.call_guard + T40.stl + T42.stl.names + T42.stl.names.map + T42.stl.names.set + T42.stl.names.multimap + T42.stl.names.multiset + T50.namespace_binder T60.const ) if (pybind11_VERSION VERSION_LESS 2.5.99) From b49b5fda6aae9f77399a7a1e05c590debcc3b18e Mon Sep 17 00:00:00 2001 From: Andrii Verbytskyi Date: Mon, 26 Apr 2021 15:09:29 +0200 Subject: [PATCH 3/7] Drop debug changes in T00 --- test/T00.basic.ref | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/T00.basic.ref b/test/T00.basic.ref index 708a0a40..a983dd19 100644 --- a/test/T00.basic.ref +++ b/test/T00.basic.ref @@ -19,9 +19,6 @@ void bind_T00_basic(std::function< pybind11::module &(std::string const &namespace_) > &M) { - M("").attr("some_constant") = pybind11::int_(14); - - // foo() file:T00.basic.hpp line:25 M("").def("foo", (void (*)()) &foo, "C++: foo() --> void"); From a2d154e926c9ce63128f39fdf535587b6a9d762a Mon Sep 17 00:00:00 2001 From: Andrii Verbytskyi Date: Sun, 30 May 2021 11:22:04 +0200 Subject: [PATCH 4/7] Reply to review --- source/const.cpp | 52 +++++++++++++++++++++++----------------------- source/const.hpp | 2 +- test/T60.const.hpp | 26 +++++++++++------------ 3 files changed, 40 insertions(+), 40 deletions(-) diff --git a/source/const.cpp b/source/const.cpp index c39fbaf6..f10a61dc 100644 --- a/source/const.cpp +++ b/source/const.cpp @@ -36,40 +36,40 @@ bool is_bindable(VarDecl const *E) if ( !E->getType().isConstQualified() ) return false; if ( !E->hasInit() ) return false; if ( E->getType().getTypePtr()->isArrayType()) return false; - if( E->isCXXInstanceMember() or E->isCXXClassMember() ) return false; - if( E->isCXXInstanceMember() ) return false; + if ( E->isCXXInstanceMember() or E->isCXXClassMember() ) return false; + if ( E->isCXXInstanceMember() ) return false; if ( standard_name( E->getType().getCanonicalType().getAsString() ) == "const std::string" ) return true; - if (E->getType().getTypePtr()->isRealFloatingType() ) return true; - if (E->getType().getTypePtr()->isIntegerType() ) return true; - if (E->getType().getTypePtr()->isBooleanType() ) return true; + if ( E->getType().getTypePtr()->isRealFloatingType() ) return true; + if ( E->getType().getTypePtr()->isIntegerType() ) return true; + if ( E->getType().getTypePtr()->isBooleanType() ) return true; return false; } // Generate binding for given function: py::enum_(module, "MyEnum")... std::string bind_const(std::string const & module, VarDecl const *E) { - string r=" "; - clang::Expr const* init = E->getInit(); - if (init){ - string name { E->getNameAsString() }; - std::string type = E->getType().getCanonicalType().getAsString(); - std::string pytype = ""; - bool pytype_set = false; -//This is a list of types that can bi binded with pybind, see https://pybind11.readthedocs.io/en/stable/advanced/pycpp/object.html*/ - if ( !pytype_set and standard_name( type ) == "const std::string" ) { pytype_set=true; pytype="str";} - if ( !pytype_set and E->getType().getTypePtr()->isRealFloatingType() ) { pytype_set=true; pytype="float_"; } - if ( !pytype_set and E->getType().getTypePtr()->isIntegerType() ) { pytype_set=true; pytype="int_"; } - if ( !pytype_set and E->getType().getTypePtr()->isBooleanType() ) { pytype_set=true; pytype="bool_"; } - if (pytype_set) { - std::string rhs; - llvm::raw_string_ostream rso(rhs); - clang::LangOptions lang_opts; - lang_opts.CPlusPlus = true; - clang::PrintingPolicy Policy(lang_opts); - init->printPretty(rso, NULL, Policy); - r = "\t{}.attr(\"{}\") = pybind11::{}({})\n"_format( module, name, pytype, rhs); - } + string r="\t"; + clang::Expr const* init = E->getInit(); + if (init){ + string name { E->getNameAsString() }; + std::string type = E->getType().getCanonicalType().getAsString(); + std::string pytype = ""; + bool pytype_set = false; + //This is a list of types that can be binded with pybind, see https://pybind11.readthedocs.io/en/stable/advanced/pycpp/object.html + if ( !pytype_set and standard_name( type ) == "const std::string" ) { pytype_set=true; pytype="str";} + if ( !pytype_set and E->getType().getTypePtr()->isRealFloatingType() ) { pytype_set=true; pytype="float_"; } + if ( !pytype_set and E->getType().getTypePtr()->isIntegerType() ) { pytype_set=true; pytype="int_"; } + if ( !pytype_set and E->getType().getTypePtr()->isBooleanType() ) { pytype_set=true; pytype="bool_"; } + if (pytype_set) { + std::string rhs; + llvm::raw_string_ostream rso(rhs); + clang::LangOptions lang_opts; + lang_opts.CPlusPlus = true; + clang::PrintingPolicy Policy(lang_opts); + init->printPretty(rso, 0, Policy); + r = "\t{}.attr(\"{}\") = pybind11::{}({})\n"_format( module, name, pytype, rhs); } + } r.pop_back(); return r; } diff --git a/source/const.hpp b/source/const.hpp index 08b5c7de..f5c9ed58 100644 --- a/source/const.hpp +++ b/source/const.hpp @@ -41,7 +41,7 @@ class ConstBinder : public Binder clang::NamedDecl const * named_decl() const override { return E; }; /// check if generator can create binding - bool bindable() const override; + bool bindable() const override; /// check if user requested binding for the given declaration virtual void request_bindings_and_skipping(Config const &) override; diff --git a/test/T60.const.hpp b/test/T60.const.hpp index f04f508b..3d9da78c 100644 --- a/test/T60.const.hpp +++ b/test/T60.const.hpp @@ -15,31 +15,31 @@ #include #include -const int global_int=1; -const long global_long=2; +int const global_int=1; +long const global_long=2; -const unsigned int global_unsigned_int=3; -const unsigned long global_unsigned_long=4; +unsigned int const global_unsigned_int=3; +unsigned long const global_unsigned_long=4; -const float global_float=5.0; -const double global_double=6.0; +float const global_float=5.0; +double const global_double=6.0; -const std::string global_string1="Some test string"; +std::string const global_string1="Some test string"; -const std::string global_string2=std::string("Some test string"); +std::string const global_string2=std::string("Some test string"); -const double expression_global_double=8.0+1.0/5.0; +double const expression_global_double=8.0+1.0/5.0; -const double array_global_double[5]={1.0,2.0,3.0,4.0,5.0}; //This should not appear in bindings so far. +double const array_global_double_not_binded[5]={1.0,2.0,3.0,4.0,5.0}; //This should not appear in bindings so far. -const std::vector vector_global_double{1.0,2.0,3.0,4.0,5.0}; //This should not appear in bindings so far. +std::vector const vector_global_double_not_binded{1.0,2.0,3.0,4.0,5.0}; //This should not appear in bindings so far. -int foo_char(char *) { return 0; } +int foo_char(char *) { return 0; } //This is just for control. namespace foo { -const double foonamespaced_global_double=7.0; +double const foonamespaced_global_double=7.0; int foonamespaced_foo_char(char *) { return 0; } From cb83ff1337914adeb41278b5ecd75f392a7466de Mon Sep 17 00:00:00 2001 From: Andrii Verbytskyi Date: Sun, 30 May 2021 11:31:45 +0200 Subject: [PATCH 5/7] More fixes to formating --- source/const.cpp | 8 ++++---- test/T60.const.hpp | 22 +++++++++++----------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/source/const.cpp b/source/const.cpp index f10a61dc..f081099d 100644 --- a/source/const.cpp +++ b/source/const.cpp @@ -56,10 +56,10 @@ std::string bind_const(std::string const & module, VarDecl const *E) std::string pytype = ""; bool pytype_set = false; //This is a list of types that can be binded with pybind, see https://pybind11.readthedocs.io/en/stable/advanced/pycpp/object.html - if ( !pytype_set and standard_name( type ) == "const std::string" ) { pytype_set=true; pytype="str";} - if ( !pytype_set and E->getType().getTypePtr()->isRealFloatingType() ) { pytype_set=true; pytype="float_"; } - if ( !pytype_set and E->getType().getTypePtr()->isIntegerType() ) { pytype_set=true; pytype="int_"; } - if ( !pytype_set and E->getType().getTypePtr()->isBooleanType() ) { pytype_set=true; pytype="bool_"; } + if ( !pytype_set and standard_name( type ) == "const std::string" ) { pytype_set = true; pytype = "str";} + if ( !pytype_set and E->getType().getTypePtr()->isRealFloatingType() ) { pytype_set = true; pytype = "float_"; } + if ( !pytype_set and E->getType().getTypePtr()->isIntegerType() ) { pytype_set = true; pytype = "int_"; } + if ( !pytype_set and E->getType().getTypePtr()->isBooleanType() ) { pytype_set = true; pytype = "bool_"; } if (pytype_set) { std::string rhs; llvm::raw_string_ostream rso(rhs); diff --git a/test/T60.const.hpp b/test/T60.const.hpp index 3d9da78c..47731112 100644 --- a/test/T60.const.hpp +++ b/test/T60.const.hpp @@ -15,23 +15,23 @@ #include #include -int const global_int=1; -long const global_long=2; +int const global_int = 1; +long const global_long = 2; -unsigned int const global_unsigned_int=3; -unsigned long const global_unsigned_long=4; +unsigned int const global_unsigned_int = 3; +unsigned long const global_unsigned_long = 4; -float const global_float=5.0; -double const global_double=6.0; +float const global_float = 5.0; +double const global_double = 6.0; -std::string const global_string1="Some test string"; +std::string const global_string1 = "Some test string"; -std::string const global_string2=std::string("Some test string"); +std::string const global_string2 = std::string("Some test string"); -double const expression_global_double=8.0+1.0/5.0; +double const expression_global_double = 8.0+1.0/5.0; -double const array_global_double_not_binded[5]={1.0,2.0,3.0,4.0,5.0}; //This should not appear in bindings so far. +double const array_global_double_not_binded[5] = {1.0,2.0,3.0,4.0,5.0}; //This should not appear in bindings so far. std::vector const vector_global_double_not_binded{1.0,2.0,3.0,4.0,5.0}; //This should not appear in bindings so far. @@ -39,7 +39,7 @@ int foo_char(char *) { return 0; } //This is just for control. namespace foo { -double const foonamespaced_global_double=7.0; +double const foonamespaced_global_double = 7.0; int foonamespaced_foo_char(char *) { return 0; } From d2361cdaba149c696da30430fcd140a475296473 Mon Sep 17 00:00:00 2001 From: Andrii Verbytskyi Date: Sun, 30 May 2021 11:38:17 +0200 Subject: [PATCH 6/7] More fixes to formating --- source/const.cpp | 4 ++-- test/T60.const.hpp | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/source/const.cpp b/source/const.cpp index f081099d..de61a7e9 100644 --- a/source/const.cpp +++ b/source/const.cpp @@ -50,7 +50,7 @@ std::string bind_const(std::string const & module, VarDecl const *E) { string r="\t"; clang::Expr const* init = E->getInit(); - if (init){ + if ( init ){ string name { E->getNameAsString() }; std::string type = E->getType().getCanonicalType().getAsString(); std::string pytype = ""; @@ -60,7 +60,7 @@ std::string bind_const(std::string const & module, VarDecl const *E) if ( !pytype_set and E->getType().getTypePtr()->isRealFloatingType() ) { pytype_set = true; pytype = "float_"; } if ( !pytype_set and E->getType().getTypePtr()->isIntegerType() ) { pytype_set = true; pytype = "int_"; } if ( !pytype_set and E->getType().getTypePtr()->isBooleanType() ) { pytype_set = true; pytype = "bool_"; } - if (pytype_set) { + if ( pytype_set ) { std::string rhs; llvm::raw_string_ostream rso(rhs); clang::LangOptions lang_opts; diff --git a/test/T60.const.hpp b/test/T60.const.hpp index 47731112..b054e92c 100644 --- a/test/T60.const.hpp +++ b/test/T60.const.hpp @@ -29,11 +29,11 @@ std::string const global_string1 = "Some test string"; std::string const global_string2 = std::string("Some test string"); -double const expression_global_double = 8.0+1.0/5.0; +double const expression_global_double = 8.0 + 1.0/5.0; -double const array_global_double_not_binded[5] = {1.0,2.0,3.0,4.0,5.0}; //This should not appear in bindings so far. +double const array_global_double_not_binded[5] = {1.0, 2.0, 3.0, 4.0, 5.0}; //This should not appear in bindings so far. -std::vector const vector_global_double_not_binded{1.0,2.0,3.0,4.0,5.0}; //This should not appear in bindings so far. +std::vector const vector_global_double_not_binded{1.0, 2.0, 3.0, 4.0, 5.0}; //This should not appear in bindings so far. int foo_char(char *) { return 0; } //This is just for control. From 8bb5333927285035cb532e94601d494e0027c5b4 Mon Sep 17 00:00:00 2001 From: Andrii Verbytskyi Date: Sat, 13 Apr 2024 07:40:36 +0200 Subject: [PATCH 7/7] Sync with master --- source/binder.cpp | 159 ---------------------------------------------- 1 file changed, 159 deletions(-) diff --git a/source/binder.cpp b/source/binder.cpp index 57919940..cdd9e223 100644 --- a/source/binder.cpp +++ b/source/binder.cpp @@ -114,167 +114,8 @@ bool IncludeSet::add_decl(clang::NamedDecl const *D, int level) // remove all includes and clear up the stack void IncludeSet::clear() { -<<<<<<< HEAD -public: - explicit BinderVisitor(CompilerInstance *ci) : ast_context( &( ci->getASTContext() ) ) - { - Config & config = Config::get(); - - config.root_module = O_root_module; - config.prefix = O_prefix; - config.maximum_file_length = O_max_file_size; - - config.namespaces_to_bind = O_bind; - config.namespaces_to_skip = O_skip; - - if( O_config.size() ) config.read(O_config); - if( O_suppress_errors ) { - clang::DiagnosticsEngine& di = ci->getDiagnostics(); -#if (LLVM_VERSION_MAJOR < 10) - di.setSuppressAllDiagnostics(); -#else - di.setSuppressAllDiagnostics(true); -#endif - } - } - - virtual ~BinderVisitor() {} - - bool shouldVisitTemplateInstantiations () const { return true; } - - virtual bool VisitFunctionDecl(FunctionDecl *F) - { - if( F->isCXXInstanceMember() or isa(F) ) return true; - - if( binder::is_bindable(F) ) { - binder::BinderOP b = std::make_shared(F); - context.add(b); - } else if( F->isOverloadedOperator() and F->getNameAsString() == "operator<<" ) { - //outs() << "Adding insertion operator: " << binder::function_pointer_type(F) << "\n"; - context.add_insertion_operator(F); - } - - return true; - } - - virtual bool VisitCXXRecordDecl(CXXRecordDecl *C) { - if( C->isCXXInstanceMember() or C->isCXXClassMember() ) return true; - - if( binder::is_bindable(C) ) { - binder::BinderOP b = std::make_shared(C); - context.add(b); - } - - return true; - } - - // virtual bool VisitClassTemplateSpecializationDecl(ClassTemplateSpecializationDecl *C) { - // if( FullSourceLoc(C->getLocation(), ast_context->getSourceManager() ).isInSystemHeader() ) return true; - // errs() << "Visit ClassTemplateSpecializationDecl:" << C->getQualifiedNameAsString() << binder::template_specialization(C) << "\n"; - // C->dump(); - // return true; - // } - - // virtual bool VisitTemplateDecl(TemplateDecl *record) { - // //if( FullSourceLoc(record->getLocation(), ast_context->getSourceManager() ).isInSystemHeader() ) return true; - // errs() << "Visit TemplateDecl: " << record->getQualifiedNameAsString() << "\n"; - // //record->dump(); - // return true; - // } - - // virtual bool VisitClassTemplateDecl(ClassTemplateDecl *record) { - // //if( FullSourceLoc(record->getLocation(), ast_context->getSourceManager() ).isInSystemHeader() ) return true; - // errs() << "Visit ClassTemplateDecl: " << record->getQualifiedNameAsString() << binder::template_specialization( record->getTemplatedDecl() ) << "\n"; - // //record->dump(); - // return true; - // } - - // virtual bool VisitTypedefDecl(TypedefDecl *T) { - // if( FullSourceLoc(T->getLocation(), ast_context->getSourceManager() ).isInSystemHeader() ) return true; - // //errs() << "Visit TypedefDecl: " << T->getQualifiedNameAsString() << " Type: " << T->getUnderlyingType()->getCanonicalTypeInternal()/*getCanonicalType()*/.getAsString() << "\n"; - // // record->dump(); - // return true; - // } - - // virtual bool VisitNamedDecl(NamedDecl *record) { - // errs() << "Visit NamedRecord: " << record->getQualifiedNameAsString() << "\n"; - // return true; - // } - - // virtual bool VisitFieldDecl(FieldDecl *record) { - // errs() << "Visit FieldDecl: " << record->getQualifiedNameAsString() << "\n"; - // record->dump(); - // return true; - // } - - virtual bool VisitEnumDecl(EnumDecl *E) { - if( E->isCXXInstanceMember() or E->isCXXClassMember() ) return true; - - binder::BinderOP b = std::make_shared( E/*->getCanonicalDecl()*/ ); - context.add(b); - - return true; - } - virtual bool VisitVarDecl(VarDecl *V) { - if( !V->getType().isConstQualified() ) return true; - if( !V->hasInit() ) return true; - if( V->getType().getTypePtr()->isArrayType()) return true; - if( V->isCXXInstanceMember() or V->isCXXClassMember() ) return true; - binder::BinderOP b = std::make_shared( V ); - context.add(b); - return true; - } - - void generate(void) { - context.generate( Config::get() ); - } - -private: - ASTContext *ast_context; - - binder::Context context; -}; - - -class BinderASTConsumer : public ASTConsumer -{ -private: - std::unique_ptr visitor; - -public: - // override the constructor in order to pass CI - explicit BinderASTConsumer(CompilerInstance *ci) : visitor(new BinderVisitor(ci)) {} - - // override this to call our ExampleVisitor on the entire source file - virtual void HandleTranslationUnit(ASTContext &context) - { - visitor->TraverseDecl( context.getTranslationUnitDecl() ); - visitor->generate(); - } -}; - - -class BinderFrontendAction : public ASTFrontendAction { -public: - virtual std::unique_ptr CreateASTConsumer(CompilerInstance &ci, StringRef file) { - return std::unique_ptr( new BinderASTConsumer(&ci) ); - } -}; - - -int main(int argc, const char **argv) -{ - CommonOptionsParser op(argc, argv, BinderToolCategory); - - ClangTool tool(op.getCompilations(), op.getSourcePathList()); - //outs() << "Root module: " << O_root_module << "\n"; - //for(auto &s : O_bind) outs() << "Binding: '" << s << "'\n"; - - return tool.run(newFrontendActionFactory().get()); -======= includes_.clear(); stack_.clear(); ->>>>>>> origin/master } /// return true if object declared in system header