Skip to content

Commit

Permalink
fixing unary operators
Browse files Browse the repository at this point in the history
  • Loading branch information
zwimer authored Oct 12, 2022
1 parent 516b014 commit 956142d
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 46 deletions.
10 changes: 1 addition & 9 deletions documentation/limitations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,6 @@ The following operators will be ignored by binder:
Miscellaneous
-------------

1. The pre/post increment operators both map to ``plus_plus`, with the pre-increment operator being invoked via ``a.plus_plus()`` and post-increment via ``.plus_plus(0)``; just as the operators are technically defined in C++. The same is true for the pre/post decrement operators, both called ``minus_minus``.
1. The pre/post increment operators both map to ``plus_plus``, with the pre-increment operator being invoked via ``a.plus_plus()`` and post-increment via ``.plus_plus(0)``; just as the operators are technically defined in C++. The same is true for the pre/post decrement operators, both called ``minus_minus``.

2. User defined literals ``operator"" _foo`` end up being named as ``operator_foo``.

----------
Known Bugs
----------

1. The unary ``operator+`` and unary ``operator-`` currently map to ``__add__`` and ``__sub__`` rather than ``__pos__`` and ``__neg__``.

2. The unary ``operator*`` (dereference operator) will currently map to ``__mul__``.
87 changes: 51 additions & 36 deletions source/function.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,40 +40,53 @@ using namespace fmt::literals;

namespace binder {

static std::map<string, string > const cpp_python_operator_map{
{"operator+", "__add__"}, //
{"operator-", "__sub__"}, //
{"operator*", "__mul__"}, //
{"operator/", "__truediv__"}, //
{"operator%", "__mod__"}, //
{"operator~", "__invert__"}, //
{"operator|", "__or__"}, //
{"operator&", "__and__"}, //
{"operator^", "__xor__"}, //
{"operator<<", "__lshift__"}, //
{"operator>>", "__rshift__"}, //

{"operator+=", "__iadd__"}, //
{"operator-=", "__isub__"}, //
{"operator*=", "__imul__"}, //
{"operator/=", "__itruediv__"}, //
{"operator%=", "__imod__"}, //
{"operator|=", "__ior__"}, //
{"operator&=", "__iand__"}, //
{"operator^=", "__ixor__"}, //
{"operator<<=", "__ilshift__"}, //
{"operator>>=", "__irshift__"}, //

{"operator()", "__call__"}, //
{"operator==", "__eq__"}, //
{"operator!=", "__ne__"}, //
{"operator[]", "__getitem__"}, //
{"operator=", "assign"}, //
{"operator++", "plus_plus"}, //
{"operator--", "minus_minus"}, //

{"operator->", "arrow"}, //
};
// Return the python operator that maps to the C++ operator; returns "" if no mapping exists
// This correctly handles operators that have multiple meanings depending on their argument count
// For example, operator_(this, other) maps to __sub__ while operator-(this) maps to __neg__
string cpp_python_operator(const FunctionDecl & F) {
static std::map<string, vector<string>> const m {
{"operator+", {"__pos__", "__add__"}}, //
{"operator-", {"__neg__", "__sub__"}}, //
{"operator*", {"dereference", "__mul__"}}, //
{"operator/", {"__truediv__"}}, //
{"operator%", {"__mod__"}}, //
{"operator~", {"__invert__"}}, //
{"operator|", {"__or__"}}, //
{"operator&", {"__and__"}}, //
{"operator^", {"__xor__"}}, //
{"operator<<", {"__lshift__"}}, //
{"operator>>", {"__rshift__"}}, //

{"operator+=", {"__iadd__"}}, //
{"operator-=", {"__isub__"}}, //
{"operator*=", {"__imul__"}}, //
{"operator/=", {"__itruediv__"}}, //
{"operator%=", {"__imod__"}}, //
{"operator|=", {"__ior__"}}, //
{"operator&=", {"__iand__"}}, //
{"operator^=", {"__ixor__"}}, //
{"operator<<=", {"__ilshift__"}}, //
{"operator>>=", {"__irshift__"}}, //

{"operator()", {"__call__"}}, //
{"operator==", {"__eq__"}}, //
{"operator!=", {"__ne__"}}, //
{"operator[]", {"__getitem__"}}, //
{"operator=", {"assign"}}, //
{"operator++", {"plus_plus"}}, //
{"operator--", {"minus_minus"}}, //

{"operator->", {"arrow"}} //
};
const auto & found = m.find(F.getNameAsString());
if (found != m.end()) {
const auto & vec { found->second };
const auto n = F.getNumParams();
return n < vec.size() ? vec[n] : vec.back();
}
return {};
}


// Generate function argument list separate by comma: int, bool, std::string
string function_arguments(clang::FunctionDecl const *record)
Expand Down Expand Up @@ -211,7 +224,9 @@ string template_specialization(FunctionDecl const *F)
// generate string represetiong class name that could be used in python
string python_function_name(FunctionDecl const *F)
{
if( F->isOverloadedOperator() ) return cpp_python_operator_map.at(F->getNameAsString());
if( F->isOverloadedOperator() ) {
return cpp_python_operator(*F);
}
else {
// if( auto m = dyn_cast<CXXMethodDecl>(F) ) {
// }
Expand Down Expand Up @@ -481,7 +496,7 @@ bool is_bindable_raw(FunctionDecl const *F)

if( F->isOverloadedOperator() ) {
// outs() << "Operator: " << F->getNameAsString() << '\n';
if( !isa<CXXMethodDecl>(F) or !cpp_python_operator_map.count(F->getNameAsString()) ) return false;
if( !isa<CXXMethodDecl>(F) or (cpp_python_operator(*F).size() == 0) ) return false;
}

r &= F->getTemplatedKind() != FunctionDecl::TK_FunctionTemplate /*and !F->isOverloadedOperator()*/ and !isa<CXXConversionDecl>(F) and !F->isDeleted();
Expand Down
4 changes: 4 additions & 0 deletions test/T12.operator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ struct T
{
T &operator~() { return *this; }

T &operator+() { return *this; }
T &operator-() { return *this; }
T &operator*() { return *this; }

T &operator+(int) { return *this; }
T &operator-(int) { return *this; }
T &operator*(int) { return *this; }
Expand Down
5 changes: 4 additions & 1 deletion test/T12.operator.ref
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ void bind_T12_operator(std::function< pybind11::module &(std::string const &name
pybind11::class_<T, std::shared_ptr<T>> cl(M(""), "T", "");
cl.def( pybind11::init( [](){ return new T(); } ) );
cl.def("__invert__", (struct T & (T::*)()) &T::operator~, "C++: T::operator~() --> struct T &", pybind11::return_value_policy::automatic);
cl.def("__pos__", (struct T & (T::*)()) &T::operator+, "C++: T::operator+() --> struct T &", pybind11::return_value_policy::automatic);
cl.def("__neg__", (struct T & (T::*)()) &T::operator-, "C++: T::operator-() --> struct T &", pybind11::return_value_policy::automatic);
cl.def("dereference", (struct T & (T::*)()) &T::operator*, "C++: T::operator*() --> struct T &", pybind11::return_value_policy::automatic);
cl.def("__add__", (struct T & (T::*)(int)) &T::operator+, "C++: T::operator+(int) --> struct T &", pybind11::return_value_policy::automatic, pybind11::arg(""));
cl.def("__sub__", (struct T & (T::*)(int)) &T::operator-, "C++: T::operator-(int) --> struct T &", pybind11::return_value_policy::automatic, pybind11::arg(""));
cl.def("__mul__", (struct T & (T::*)(int)) &T::operator*, "C++: T::operator*(int) --> struct T &", pybind11::return_value_policy::automatic, pybind11::arg(""));
Expand Down Expand Up @@ -100,4 +103,4 @@ PYBIND11_MODULE(T12_operator, root_module) {
// T12_operator.cpp

// Modules list file: TEST/T12_operator.modules
//
//

0 comments on commit 956142d

Please sign in to comment.