blueloveTH 2 jaren geleden
bovenliggende
commit
715c8670d1
7 gewijzigde bestanden met toevoegingen van 138 en 128 verwijderingen
  1. 2 2
      python/_long.py
  2. 5 4
      src/ceval.h
  3. 20 17
      src/cffi.h
  4. 1 1
      src/common.h
  5. 58 58
      src/pocketpy.h
  6. 47 45
      src/vm.h
  7. 5 1
      tests/09_long.py

+ 2 - 2
python/_long.py

@@ -307,8 +307,8 @@ class long:
     def __cmp__(self, other):
         if type(other) is int:
             other = long(other)
-        else:
-            assert type(other) is long
+        elif type(other) is not long:
+            return NotImplemented
         if self.sign > other.sign:
             return 1
         elif self.sign < other.sign:

+ 5 - 4
src/ceval.h

@@ -337,6 +337,7 @@ __NEXT_STEP:;
             _2 = get_unbound_method(_1, func, &self, false);        \
             if(_2 != nullptr) TOP() = call_method(self, _2, _0);    \
             else BinaryOptError(op);                                \
+            if(TOP() == NotImplemented) BinaryOptError(op);         \
         }
 
     TARGET(BINARY_TRUEDIV)
@@ -373,11 +374,11 @@ __NEXT_STEP:;
         DISPATCH()
     TARGET(COMPARE_LT)
         BINARY_OP_SPECIAL(__lt__);
-        if(TOP() == NotImplemented) BinaryOptError("<");
+        BINARY_OP_RSPECIAL("<", __gt__);
         DISPATCH()
     TARGET(COMPARE_LE)
         BINARY_OP_SPECIAL(__le__);
-        if(TOP() == NotImplemented) BinaryOptError("<=");
+        BINARY_OP_RSPECIAL("<=", __ge__);
         DISPATCH()
     TARGET(COMPARE_EQ)
         _1 = POPX();
@@ -391,11 +392,11 @@ __NEXT_STEP:;
         DISPATCH()
     TARGET(COMPARE_GT)
         BINARY_OP_SPECIAL(__gt__);
-        if(TOP() == NotImplemented) BinaryOptError(">");
+        BINARY_OP_RSPECIAL(">", __lt__);
         DISPATCH()
     TARGET(COMPARE_GE)
         BINARY_OP_SPECIAL(__ge__);
-        if(TOP() == NotImplemented) BinaryOptError(">=");
+        BINARY_OP_RSPECIAL(">=", __le__);
         DISPATCH()
     TARGET(BITWISE_LSHIFT)
         PREDICT_INT_OP(<<);

+ 20 - 17
src/cffi.h

@@ -45,6 +45,11 @@ struct VoidP{
     bool operator!=(const VoidP& other) const {
         return ptr != other.ptr || base_offset != other.base_offset;
     }
+    bool operator<(const VoidP& other) const { return ptr < other.ptr; }
+    bool operator<=(const VoidP& other) const { return ptr <= other.ptr; }
+    bool operator>(const VoidP& other) const { return ptr > other.ptr; }
+    bool operator>=(const VoidP& other) const { return ptr >= other.ptr; }
+
 
     Str hex() const{
         std::stringstream ss;
@@ -76,23 +81,20 @@ struct VoidP{
             return VAR(ss.str());
         });
 
-        vm->bind__eq__(OBJ_GET(Type, type), [](VM* vm, PyObject* lhs, PyObject* rhs){
-            if(!is_non_tagged_type(rhs, VoidP::_type(vm))) return false;
-            return _CAST(VoidP&, lhs) == _CAST(VoidP&, rhs);
-        });
-        vm->bind__gt__(OBJ_GET(Type, type), [](VM* vm, PyObject* lhs, PyObject* rhs){
-            return _CAST(VoidP&, lhs).ptr > CAST(VoidP&, rhs).ptr;
-        });
-        vm->bind__lt__(OBJ_GET(Type, type), [](VM* vm, PyObject* lhs, PyObject* rhs){
-            return _CAST(VoidP&, lhs).ptr < CAST(VoidP&, rhs).ptr;
-        });
-        vm->bind__ge__(OBJ_GET(Type, type), [](VM* vm, PyObject* lhs, PyObject* rhs){
-            return _CAST(VoidP&, lhs).ptr >= CAST(VoidP&, rhs).ptr;
-        });
-        vm->bind__le__(OBJ_GET(Type, type), [](VM* vm, PyObject* lhs, PyObject* rhs){
-            return _CAST(VoidP&, lhs).ptr <= CAST(VoidP&, rhs).ptr;
+#define BIND_CMP(name, op)  \
+        vm->bind##name(OBJ_GET(Type, type), [](VM* vm, PyObject* lhs, PyObject* rhs){       \
+            if(!is_non_tagged_type(rhs, VoidP::_type(vm))) return vm->NotImplemented;       \
+            return VAR(_CAST(VoidP&, lhs) op _CAST(VoidP&, rhs));                           \
         });
 
+        BIND_CMP(__eq__, ==)
+        BIND_CMP(__lt__, <)
+        BIND_CMP(__le__, <=)
+        BIND_CMP(__gt__, >)
+        BIND_CMP(__ge__, >=)
+
+#undef BIND_CMP
+
         vm->bind__hash__(OBJ_GET(Type, type), [](VM* vm, PyObject* obj){
             VoidP& self = _CAST(VoidP&, obj);
             return reinterpret_cast<i64>(self.ptr);
@@ -243,9 +245,10 @@ struct C99Struct{
 
         vm->bind__eq__(OBJ_GET(Type, type), [](VM* vm, PyObject* lhs, PyObject* rhs){
             C99Struct& self = _CAST(C99Struct&, lhs);
-            if(!is_non_tagged_type(rhs, C99Struct::_type(vm))) return false;
+            if(!is_non_tagged_type(rhs, C99Struct::_type(vm))) return vm->NotImplemented;
             C99Struct& other = _CAST(C99Struct&, rhs);
-            return self.size == other.size && memcmp(self.p, other.p, self.size) == 0;
+            bool ok = self.size == other.size && memcmp(self.p, other.p, self.size) == 0;
+            return VAR(ok);
         });
 
         // patch VoidP

+ 1 - 1
src/common.h

@@ -20,7 +20,7 @@
 #include <variant>
 #include <type_traits>
 
-#define PK_VERSION				"1.0.3"
+#define PK_VERSION				"1.0.4"
 
 #include "config.h"
 

+ 58 - 58
src/pocketpy.h

@@ -52,28 +52,24 @@ inline void init_builtins(VM* _vm) {
 
 #undef BIND_NUM_ARITH_OPT
 
-#define BIND_NUM_LOGICAL_OPT(name, op, is_eq)   \
+#define BIND_NUM_LOGICAL_OPT(name, op)   \
     _vm->bind##name(_vm->tp_int, [](VM* vm, PyObject* lhs, PyObject* rhs) { \
-        if(is_int(rhs))     return _CAST(i64, lhs) op _CAST(i64, rhs);      \
-        if(is_float(rhs))   return _CAST(i64, lhs) op _CAST(f64, rhs);      \
-        if constexpr(is_eq) return lhs op rhs;                              \
-        vm->TypeError("unsupported operand type(s) for " #op );             \
-        return false;                                                       \
+        if(is_int(rhs))     return VAR(_CAST(i64, lhs) op _CAST(i64, rhs)); \
+        if(is_float(rhs))   return VAR(_CAST(i64, lhs) op _CAST(f64, rhs)); \
+        return vm->NotImplemented;                                          \
     });                                                                     \
     _vm->bind##name(_vm->tp_float, [](VM* vm, PyObject* lhs, PyObject* rhs) {   \
-        if(is_int(rhs))     return _CAST(f64, lhs) op _CAST(i64, rhs);          \
-        if(is_float(rhs))   return _CAST(f64, lhs) op _CAST(f64, rhs);          \
-        if constexpr(is_eq) return lhs op rhs;                                  \
-        vm->TypeError("unsupported operand type(s) for " #op );                 \
-        return false;                                                           \
+        if(is_int(rhs))     return VAR(_CAST(f64, lhs) op _CAST(i64, rhs));     \
+        if(is_float(rhs))   return VAR(_CAST(f64, lhs) op _CAST(f64, rhs));     \
+        return vm->NotImplemented;                                              \
     });
 
-    BIND_NUM_LOGICAL_OPT(__lt__, <, false)
-    BIND_NUM_LOGICAL_OPT(__le__, <=, false)
-    BIND_NUM_LOGICAL_OPT(__gt__, >, false)
-    BIND_NUM_LOGICAL_OPT(__ge__, >=, false)
-    BIND_NUM_LOGICAL_OPT(__eq__, ==, true)
-
+    BIND_NUM_LOGICAL_OPT(__eq__, ==)
+    BIND_NUM_LOGICAL_OPT(__lt__, <)
+    BIND_NUM_LOGICAL_OPT(__le__, <=)
+    BIND_NUM_LOGICAL_OPT(__gt__, >)
+    BIND_NUM_LOGICAL_OPT(__ge__, >=)
+    
 #undef BIND_NUM_ARITH_OPT
 #undef BIND_NUM_LOGICAL_OPT
 
@@ -263,7 +259,7 @@ inline void init_builtins(VM* _vm) {
         return VAR(ss.str());
     });
 
-    _vm->bind__eq__(_vm->tp_object, [](VM* vm, PyObject* lhs, PyObject* rhs) { return lhs == rhs; });
+    _vm->bind__eq__(_vm->tp_object, [](VM* vm, PyObject* lhs, PyObject* rhs) { return VAR(lhs == rhs); });
     _vm->bind__hash__(_vm->tp_object, [](VM* vm, PyObject* obj) { return BITS(obj); });
 
     _vm->cached_object__new__ = _vm->bind_constructor<1>("object", [](VM* vm, ArgsView args) {
@@ -449,8 +445,7 @@ inline void init_builtins(VM* _vm) {
     });
     _vm->bind__contains__(_vm->tp_str, [](VM* vm, PyObject* lhs, PyObject* rhs) {
         const Str& self = _CAST(Str&, lhs);
-        const Str& other = CAST(Str&, rhs);
-        return self.index(other) != -1;
+        return VAR(self.index(CAST(Str&, rhs)) != -1);
     });
     _vm->bind__str__(_vm->tp_str, [](VM* vm, PyObject* obj) { return obj; });
     _vm->bind__iter__(_vm->tp_str, [](VM* vm, PyObject* obj) { return VAR_T(StringIter, obj); });
@@ -462,23 +457,20 @@ inline void init_builtins(VM* _vm) {
         const Str& self = _CAST(Str&, obj);
         return VAR(self.escape(false));
     });
-    _vm->bind__eq__(_vm->tp_str, [](VM* vm, PyObject* lhs, PyObject* rhs) {
-        if(!is_non_tagged_type(rhs, vm->tp_str)) return false;
-        return _CAST(Str&, lhs) == _CAST(Str&, rhs);
-    });
-    _vm->bind__gt__(_vm->tp_str, [](VM* vm, PyObject* lhs, PyObject* rhs) {
-        return _CAST(Str&, lhs) > CAST(Str&, rhs);
-    });
-    _vm->bind__lt__(_vm->tp_str, [](VM* vm, PyObject* lhs, PyObject* rhs) {
-        return _CAST(Str&, lhs) < CAST(Str&, rhs);
-    });
-    _vm->bind__ge__(_vm->tp_str, [](VM* vm, PyObject* lhs, PyObject* rhs) {
-        return _CAST(Str&, lhs) >= CAST(Str&, rhs);
-    });
-    _vm->bind__le__(_vm->tp_str, [](VM* vm, PyObject* lhs, PyObject* rhs) {
-        return _CAST(Str&, lhs) <= CAST(Str&, rhs);
+
+#define BIND_CMP_STR(name, op) \
+    _vm->bind##name(_vm->tp_str, [](VM* vm, PyObject* lhs, PyObject* rhs) { \
+        if(!is_non_tagged_type(rhs, vm->tp_str)) return vm->NotImplemented; \
+        return VAR(_CAST(Str&, lhs) op _CAST(Str&, rhs));                   \
     });
 
+    BIND_CMP_STR(__eq__, ==)
+    BIND_CMP_STR(__lt__, <)
+    BIND_CMP_STR(__le__, <=)
+    BIND_CMP_STR(__gt__, >)
+    BIND_CMP_STR(__ge__, >=)
+#undef BIND_CMP_STR
+
     _vm->bind__getitem__(_vm->tp_str, [](VM* vm, PyObject* obj, PyObject* index) {
         const Str& self = _CAST(Str&, obj);
         if(is_non_tagged_type(index, vm->tp_slice)){
@@ -572,8 +564,8 @@ inline void init_builtins(VM* _vm) {
 
     _vm->bind__contains__(_vm->tp_list, [](VM* vm, PyObject* obj, PyObject* item) {
         List& self = _CAST(List&, obj);
-        for(PyObject* i: self) if(vm->py_equals(i, item)) return true;
-        return false;
+        for(PyObject* i: self) if(vm->py_equals(i, item)) return vm->True;
+        return vm->False;
     });
 
     _vm->bind_method<1>("list", "count", [](VM* vm, ArgsView args) {
@@ -585,12 +577,13 @@ inline void init_builtins(VM* _vm) {
 
     _vm->bind__eq__(_vm->tp_list, [](VM* vm, PyObject* lhs, PyObject* rhs) {
         List& a = _CAST(List&, lhs);
+        if(!is_non_tagged_type(rhs, vm->tp_list)) return vm->NotImplemented;
         List& b = _CAST(List&, rhs);
-        if(a.size() != b.size()) return false;
+        if(a.size() != b.size()) return vm->False;
         for(int i=0; i<a.size(); i++){
-            if(!vm->py_equals(a[i], b[i])) return false;
+            if(!vm->py_equals(a[i], b[i])) return vm->False;
         }
-        return true;
+        return vm->True;
     });
 
     _vm->bind_method<1>("list", "index", [](VM* vm, ArgsView args) {
@@ -725,8 +718,8 @@ inline void init_builtins(VM* _vm) {
 
     _vm->bind__contains__(_vm->tp_tuple, [](VM* vm, PyObject* obj, PyObject* item) {
         Tuple& self = _CAST(Tuple&, obj);
-        for(PyObject* i: self) if(vm->py_equals(i, item)) return true;
-        return false;
+        for(PyObject* i: self) if(vm->py_equals(i, item)) return vm->True;
+        return vm->False;
     });
 
     _vm->bind_method<1>("tuple", "count", [](VM* vm, ArgsView args) {
@@ -738,12 +731,13 @@ inline void init_builtins(VM* _vm) {
 
     _vm->bind__eq__(_vm->tp_tuple, [](VM* vm, PyObject* lhs, PyObject* rhs) {
         const Tuple& self = _CAST(Tuple&, lhs);
-        const Tuple& other = CAST(Tuple&, rhs);
-        if(self.size() != other.size()) return false;
+        if(!is_non_tagged_type(rhs, vm->tp_tuple)) return vm->NotImplemented;
+        const Tuple& other = _CAST(Tuple&, rhs);
+        if(self.size() != other.size()) return vm->False;
         for(int i = 0; i < self.size(); i++) {
-            if(!vm->py_equals(self[i], other[i])) return false;
+            if(!vm->py_equals(self[i], other[i])) return vm->False;
         }
-        return true;
+        return vm->True;
     });
 
     _vm->bind__hash__(_vm->tp_tuple, [](VM* vm, PyObject* obj) {
@@ -790,10 +784,15 @@ inline void init_builtins(VM* _vm) {
         return VAR(_CAST(bool, lhs) != CAST(bool, rhs));
     });
     _vm->bind__eq__(_vm->tp_bool, [](VM* vm, PyObject* lhs, PyObject* rhs) {
-        return _CAST(bool, lhs) == CAST(bool, rhs);
+        if(is_non_tagged_type(rhs, vm->tp_bool)) return VAR(lhs == rhs);
+        if(is_int(rhs)) return VAR(_CAST(bool, lhs) == (bool)CAST(i64, rhs));
+        return vm->NotImplemented;
     });
     _vm->bind__repr__(_vm->_type("ellipsis"), [](VM* vm, PyObject* self) {
-        return VAR("Ellipsis");
+        return VAR("...");
+    });
+    _vm->bind__repr__(_vm->_type("NotImplementedType"), [](VM* vm, PyObject* self) {
+        return VAR("NotImplemented");
     });
 
     /************ bytes ************/
@@ -856,7 +855,8 @@ inline void init_builtins(VM* _vm) {
     });
 
     _vm->bind__eq__(_vm->tp_bytes, [](VM* vm, PyObject* lhs, PyObject* rhs) {
-        return _CAST(Bytes&, lhs) == _CAST(Bytes&, rhs);
+        if(!is_non_tagged_type(rhs, vm->tp_bytes)) return vm->NotImplemented;
+        return VAR(_CAST(Bytes&, lhs) == _CAST(Bytes&, rhs));
     });
     /************ slice ************/
     _vm->bind_constructor<4>("slice", [](VM* vm, ArgsView args) {
@@ -926,7 +926,7 @@ inline void init_builtins(VM* _vm) {
 
     _vm->bind__contains__(_vm->tp_mappingproxy, [](VM* vm, PyObject* obj, PyObject* key) {
         MappingProxy& self = _CAST(MappingProxy&, obj);
-        return self.attr().contains(CAST(Str&, key));
+        return VAR(self.attr().contains(CAST(Str&, key)));
     });
 
     /************ dict ************/
@@ -986,7 +986,7 @@ inline void init_builtins(VM* _vm) {
 
     _vm->bind__contains__(_vm->tp_dict, [](VM* vm, PyObject* obj, PyObject* key) {
         Dict& self = _CAST(Dict&, obj);
-        return self.contains(key);
+        return VAR(self.contains(key));
     });
 
     _vm->bind_method<-1>("dict", "get", [](VM* vm, ArgsView args) {
@@ -1080,15 +1080,15 @@ inline void init_builtins(VM* _vm) {
 
     _vm->bind__eq__(_vm->tp_dict, [](VM* vm, PyObject* a, PyObject* b) {
         Dict& self = _CAST(Dict&, a);
-        if(!is_non_tagged_type(b, vm->tp_dict)) return false;
+        if(!is_non_tagged_type(b, vm->tp_dict)) return vm->NotImplemented;
         Dict& other = _CAST(Dict&, b);
-        if(self.size() != other.size()) return false;
+        if(self.size() != other.size()) return vm->False;
         for(auto& item : self.items()){
             PyObject* value = other.try_get(item.first);
-            if(value == nullptr) return false;
-            if(!vm->py_equals(item.second, value)) return false;
+            if(value == nullptr) return vm->False;
+            if(!vm->py_equals(item.second, value)) return vm->False;
         }
-        return true;
+        return vm->True;
     });
     /************ property ************/
     _vm->bind_constructor<-1>("property", [](VM* vm, ArgsView args) {
@@ -1370,8 +1370,8 @@ inline void VM::post_init(){
     }));
 
     bind__eq__(tp_bound_method, [](VM* vm, PyObject* lhs, PyObject* rhs){
-        if(!is_non_tagged_type(rhs, vm->tp_bound_method)) return false;
-        return _CAST(BoundMethod&, lhs) == _CAST(BoundMethod&, rhs);
+        if(!is_non_tagged_type(rhs, vm->tp_bound_method)) return vm->NotImplemented;
+        return VAR(_CAST(BoundMethod&, lhs) == _CAST(BoundMethod&, rhs));
     });
     _t(tp_slice)->attr().set("start", property([](VM* vm, ArgsView args){
         return CAST(Slice&, args[0]).start;

+ 47 - 45
src/vm.h

@@ -44,6 +44,8 @@ namespace pkpy{
     inline PyObject* py_var(VM* vm, ctype&& value) { return vm->heap.gcnew(vm->ptype, std::move(value));}
 
 
+typedef PyObject* (*BinaryFuncC)(VM*, PyObject*, PyObject*);
+
 struct PyTypeInfo{
     PyObject* obj;
     Type base;
@@ -62,28 +64,28 @@ struct PyTypeInfo{
     PyObject* (*m__neg__)(VM* vm, PyObject*) = nullptr;
     PyObject* (*m__bool__)(VM* vm, PyObject*) = nullptr;
 
-    bool (*m__eq__)(VM* vm, PyObject*, PyObject*) = nullptr;
-    bool (*m__lt__)(VM* vm, PyObject*, PyObject*) = nullptr;
-    bool (*m__le__)(VM* vm, PyObject*, PyObject*) = nullptr;
-    bool (*m__gt__)(VM* vm, PyObject*, PyObject*) = nullptr;
-    bool (*m__ge__)(VM* vm, PyObject*, PyObject*) = nullptr;
-    bool (*m__contains__)(VM* vm, PyObject*, PyObject*) = nullptr;
+    BinaryFuncC m__eq__ = nullptr;
+    BinaryFuncC m__lt__ = nullptr;
+    BinaryFuncC m__le__ = nullptr;
+    BinaryFuncC m__gt__ = nullptr;
+    BinaryFuncC m__ge__ = nullptr;
+    BinaryFuncC m__contains__ = nullptr;
 
     // binary operators
-    PyObject* (*m__add__)(VM* vm, PyObject*, PyObject*) = nullptr;
-    PyObject* (*m__sub__)(VM* vm, PyObject*, PyObject*) = nullptr;
-    PyObject* (*m__mul__)(VM* vm, PyObject*, PyObject*) = nullptr;
-    PyObject* (*m__truediv__)(VM* vm, PyObject*, PyObject*) = nullptr;
-    PyObject* (*m__floordiv__)(VM* vm, PyObject*, PyObject*) = nullptr;
-    PyObject* (*m__mod__)(VM* vm, PyObject*, PyObject*) = nullptr;
-    PyObject* (*m__pow__)(VM* vm, PyObject*, PyObject*) = nullptr;
-    PyObject* (*m__matmul__)(VM* vm, PyObject*, PyObject*) = nullptr;
-
-    PyObject* (*m__lshift__)(VM* vm, PyObject*, PyObject*) = nullptr;
-    PyObject* (*m__rshift__)(VM* vm, PyObject*, PyObject*) = nullptr;
-    PyObject* (*m__and__)(VM* vm, PyObject*, PyObject*) = nullptr;
-    PyObject* (*m__or__)(VM* vm, PyObject*, PyObject*) = nullptr;
-    PyObject* (*m__xor__)(VM* vm, PyObject*, PyObject*) = nullptr;
+    BinaryFuncC m__add__ = nullptr;
+    BinaryFuncC m__sub__ = nullptr;
+    BinaryFuncC m__mul__ = nullptr;
+    BinaryFuncC m__truediv__ = nullptr;
+    BinaryFuncC m__floordiv__ = nullptr;
+    BinaryFuncC m__mod__ = nullptr;
+    BinaryFuncC m__pow__ = nullptr;
+    BinaryFuncC m__matmul__ = nullptr;
+
+    BinaryFuncC m__lshift__ = nullptr;
+    BinaryFuncC m__rshift__ = nullptr;
+    BinaryFuncC m__and__ = nullptr;
+    BinaryFuncC m__or__ = nullptr;
+    BinaryFuncC m__xor__ = nullptr;
 
     // indexer
     PyObject* (*m__getitem__)(VM* vm, PyObject*, PyObject*) = nullptr;
@@ -358,37 +360,23 @@ public:
 #undef BIND_UNARY_SPECIAL
 
 
-#define BIND_LOGICAL_SPECIAL(name)                                                      \
-    void bind##name(Type type, bool (*f)(VM*, PyObject*, PyObject*)){                   \
-        PyObject* obj = _t(type);                                                       \
-        _all_types[type].m##name = f;                                                   \
-        PyObject* nf = bind_method<1>(obj, #name, [](VM* vm, ArgsView args){            \
-            bool ok = lambda_get_userdata<bool(*)(VM*, PyObject*, PyObject*)>(args.begin())(vm, args[0], args[1]); \
-            return ok ? vm->True : vm->False;                                           \
-        });                                                                             \
-        OBJ_GET(NativeFunc, nf).set_userdata(f);                                        \
-    }
-
-    BIND_LOGICAL_SPECIAL(__eq__)
-    BIND_LOGICAL_SPECIAL(__lt__)
-    BIND_LOGICAL_SPECIAL(__le__)
-    BIND_LOGICAL_SPECIAL(__gt__)
-    BIND_LOGICAL_SPECIAL(__ge__)
-    BIND_LOGICAL_SPECIAL(__contains__)
-
-#undef BIND_LOGICAL_SPECIAL
-
-
 #define BIND_BINARY_SPECIAL(name)                                                       \
-    void bind##name(Type type, PyObject* (*f)(VM*, PyObject*, PyObject*)){              \
+    void bind##name(Type type, BinaryFuncC f){                                          \
         PyObject* obj = _t(type);                                                       \
         _all_types[type].m##name = f;                                                   \
         PyObject* nf = bind_method<1>(obj, #name, [](VM* vm, ArgsView args){            \
-            return lambda_get_userdata<PyObject*(*)(VM*, PyObject*, PyObject*)>(args.begin())(vm, args[0], args[1]); \
+            return lambda_get_userdata<BinaryFuncC>(args.begin())(vm, args[0], args[1]); \
         });                                                                             \
         OBJ_GET(NativeFunc, nf).set_userdata(f);                                        \
     }
 
+    BIND_BINARY_SPECIAL(__eq__)
+    BIND_BINARY_SPECIAL(__lt__)
+    BIND_BINARY_SPECIAL(__le__)
+    BIND_BINARY_SPECIAL(__gt__)
+    BIND_BINARY_SPECIAL(__ge__)
+    BIND_BINARY_SPECIAL(__contains__)
+
     BIND_BINARY_SPECIAL(__add__)
     BIND_BINARY_SPECIAL(__sub__)
     BIND_BINARY_SPECIAL(__mul__)
@@ -438,8 +426,22 @@ public:
     bool py_equals(PyObject* lhs, PyObject* rhs){
         if(lhs == rhs) return true;
         const PyTypeInfo* ti = _inst_type_info(lhs);
-        if(ti->m__eq__) return ti->m__eq__(this, lhs, rhs);
-        return call_method(lhs, __eq__, rhs) == True;
+        PyObject* res;
+        if(ti->m__eq__){
+            res = ti->m__eq__(this, lhs, rhs);
+            if(res != vm->NotImplemented) return res == vm->True;
+        }
+        res = call_method(lhs, __eq__, rhs);
+        if(res != vm->NotImplemented) return res == vm->True;
+
+        ti = _inst_type_info(rhs);
+        if(ti->m__eq__){
+            res = ti->m__eq__(this, rhs, lhs);
+            if(res != vm->NotImplemented) return res == vm->True;
+        }
+        res = call_method(rhs, __eq__, lhs);
+        if(res != vm->NotImplemented) return res == vm->True;
+        return false;
     }
 
     template<int ARGC>

+ 5 - 1
tests/09_long.py

@@ -1,4 +1,4 @@
-assert long(123) == long('123') == 123L == 123
+assert long(123) == long('123') == 123 == 123L
 
 a = long(2)
 assert a ** 0 == 1
@@ -32,3 +32,7 @@ while a != 0:
     s.append(r)
 
 assert s == [4, 6, 7, 2, 3]
+
+assert 1 < 2L < 3 < 6.6
+assert 1L < 2 < 9.6 >= 7 > 2L
+assert 1L < 2 < 3 < 6.6