blueloveTH 1 год назад
Родитель
Сommit
8edb46afb4

+ 2 - 2
include/pocketpy/interpreter/vm.hpp

@@ -242,7 +242,7 @@ public:
     List py_list(PyVar);                                // x -> list(x)
     bool py_callable(PyVar obj);                        // x -> callable(x)
     bool py_bool(PyVar obj){                            // x -> bool(x)
-        if(obj.type == tp_bool) return obj._bool;
+        if(obj.type == tp_bool) return (bool)obj.extra;
         return __py_bool_non_trivial(obj);
     }
     i64 py_hash(PyVar obj);                             // x -> hash(x)
@@ -604,7 +604,7 @@ __T _py_cast__internal(VM* vm, PyVar obj) {
                 vm->TypeError("expected 'bool', got " + _type_name(vm, vm->_tp(obj)).escape());
             }
         }
-        return obj._bool;
+        return (bool)obj.extra;
     } else if constexpr(is_integral_v<T>) {
         static_assert(!std::is_reference_v<__T>);
         // int

+ 12 - 11
include/pocketpy/objects/base.h

@@ -41,17 +41,18 @@ typedef struct PyVar{
 
 static_assert(sizeof(PyVar) == 16, "sizeof(PyVar) != 16");
 
-extern const pkpy_Type tp_object, tp_type;
-extern const pkpy_Type tp_int, tp_float, tp_bool, tp_str;
-extern const pkpy_Type tp_list, tp_tuple;
-extern const pkpy_Type tp_slice, tp_range, tp_module;
-extern const pkpy_Type tp_function, tp_native_func, tp_bound_method;
-extern const pkpy_Type tp_super, tp_exception, tp_bytes, tp_mappingproxy;
-extern const pkpy_Type tp_dict, tp_property, tp_star_wrapper;
-extern const pkpy_Type tp_staticmethod, tp_classmethod;
-extern const pkpy_Type tp_none_type, tp_not_implemented_type;
-extern const pkpy_Type tp_ellipsis;
-extern const pkpy_Type tp_op_call, tp_op_yield;
+/* predefined vars */
+static const pkpy_Type tp_object = 1, tp_type = 2;
+static const pkpy_Type tp_int = 3, tp_float = 4, tp_bool = 5, tp_str = 6;
+static const pkpy_Type tp_list = 7, tp_tuple = 8;
+static const pkpy_Type tp_slice = 9, tp_range = 10, tp_module = 11;
+static const pkpy_Type tp_function = 12, tp_native_func = 13, tp_bound_method = 14;
+static const pkpy_Type tp_super = 15, tp_exception = 16, tp_bytes = 17, tp_mappingproxy = 18;
+static const pkpy_Type tp_dict = 19, tp_property = 20, tp_star_wrapper = 21;
+static const pkpy_Type tp_staticmethod = 22, tp_classmethod = 23;
+static const pkpy_Type tp_none_type = 24, tp_not_implemented_type = 25;
+static const pkpy_Type tp_ellipsis = 26;
+static const pkpy_Type tp_op_call = 27, tp_op_yield = 28;
 
 PK_INLINE bool PyVar__is_null(const PyVar* self) { return self->type == 0; }
 PK_INLINE int64_t PyVar__hash(const PyVar* self) { return self->extra + self->_i64; }

+ 4 - 4
src/interpreter/ceval.cpp

@@ -67,25 +67,25 @@ void VM::__op_unpack_sequence(uint16_t arg) {
 bool VM::py_lt(PyVar _0, PyVar _1) {
     BINARY_F_COMPARE(__lt__, "<", __gt__);
     assert(ret.type == tp_bool);
-    return ret._bool;
+    return ret.extra;
 }
 
 bool VM::py_le(PyVar _0, PyVar _1) {
     BINARY_F_COMPARE(__le__, "<=", __ge__);
     assert(ret.type == tp_bool);
-    return ret._bool;
+    return ret.extra;
 }
 
 bool VM::py_gt(PyVar _0, PyVar _1) {
     BINARY_F_COMPARE(__gt__, ">", __lt__);
     assert(ret.type == tp_bool);
-    return ret._bool;
+    return ret.extra;
 }
 
 bool VM::py_ge(PyVar _0, PyVar _1) {
     BINARY_F_COMPARE(__ge__, ">=", __le__);
     assert(ret.type == tp_bool);
-    return ret._bool;
+    return ret.extra;
 }
 
 #undef BINARY_F_COMPARE

+ 5 - 5
src/interpreter/vm.cpp

@@ -60,7 +60,7 @@ struct JsonSerializer {
             if(std::isinf(val) || std::isnan(val)) vm->ValueError("cannot jsonify 'nan' or 'inf'");
             ss << val;
         } else if(obj_t == vm->tp_bool) {
-            ss << (obj._bool ? "true" : "false");
+            ss << (obj.extra ? "true" : "false");
         } else if(obj_t == vm->tp_str) {
             ss << _CAST(Str&, obj).escape('"');
         } else if(obj_t == vm->tp_list) {
@@ -235,18 +235,18 @@ bool VM::py_eq(PyVar lhs, PyVar rhs) {
     PyVar res;
     if(ti->m__eq__) {
         res = ti->m__eq__(this, lhs, rhs);
-        if(!is_not_implemented(res)) return res._bool;
+        if(!is_not_implemented(res)) return res.extra;
     }
     res = call_method(lhs, __eq__, rhs);
-    if(!is_not_implemented(res)) return res._bool;
+    if(!is_not_implemented(res)) return res.extra;
 
     ti = _tp_info(rhs);
     if(ti->m__eq__) {
         res = ti->m__eq__(this, rhs, lhs);
-        if(!is_not_implemented(res)) return res._bool;
+        if(!is_not_implemented(res)) return res.extra;
     }
     res = call_method(rhs, __eq__, lhs);
-    if(!is_not_implemented(res)) return res._bool;
+    if(!is_not_implemented(res)) return res.extra;
     return false;
 }
 

+ 0 - 18
src/objects/base.c

@@ -1,23 +1,5 @@
 #include "pocketpy/objects/base.h"
 
-/* predefined vars */
-const pkpy_Type tp_object = 1, tp_type = 2;
-const pkpy_Type tp_int = 3, tp_float = 4, tp_bool = 5, tp_str = 6;
-const pkpy_Type tp_list = 7, tp_tuple = 8;
-const pkpy_Type tp_slice = 9, tp_range = 10, tp_module = 11;
-const pkpy_Type tp_function = 12, tp_native_func = 13, tp_bound_method = 14;
-const pkpy_Type tp_super = 15, tp_exception = 16, tp_bytes = 17, tp_mappingproxy = 18;
-const pkpy_Type tp_dict = 19, tp_property = 20, tp_star_wrapper = 21;
-const pkpy_Type tp_staticmethod = 22, tp_classmethod = 23;
-const pkpy_Type tp_none_type = 24, tp_not_implemented_type = 25;
-const pkpy_Type tp_ellipsis = 26;
-const pkpy_Type tp_op_call = 27, tp_op_yield = 28;
-
-PyVar pkpy_True = {.type=tp_bool, .is_ptr=false, ._bool=true};
-PyVar pkpy_False = {.type=tp_bool, .is_ptr=false, ._bool=false};
-PyVar pkpy_None = {.type=tp_none_type, .is_ptr=false};
-PyVar pkpy_NotImplemented = {.type=tp_not_implemented_type, .is_ptr=false};
-PyVar pkpy_Ellipsis = {.type=tp_ellipsis, .is_ptr=false};
 PyVar pkpy_NULL = {.type=0, .is_ptr=false};
 PyVar pkpy_OP_CALL = {.type=tp_op_call, .is_ptr=false};
 PyVar pkpy_OP_YIELD = {.type=tp_op_yield, .is_ptr=false};

+ 13 - 0
src/objects/object.c

@@ -6,3 +6,16 @@ void PyVar__ctor3(PyVar* self, PyObject* existing){
     self->is_ptr = true;
     self->_obj = existing;
 }
+
+static PyObject __true_obj = {.type=tp_bool, .gc_is_large=false, .gc_marked=false, ._attr=NULL};
+static PyObject __false_obj = {.type=tp_bool, .gc_is_large=false, .gc_marked=false, ._attr=NULL};
+static PyObject __none_obj = {.type=tp_none_type, .gc_is_large=false, .gc_marked=false, ._attr=NULL};
+static PyObject __not_implemented_obj = {.type=tp_not_implemented_type, .gc_is_large=false, .gc_marked=false, ._attr=NULL};
+static PyObject __ellipsis_obj = {.type=tp_ellipsis, .gc_is_large=false, .gc_marked=false, ._attr=NULL};
+
+/* Must be heap objects to support `==` and `is` and `is not` */
+PyVar pkpy_True = {.type=tp_bool, .is_ptr=true, .extra=1, ._obj=&__true_obj};
+PyVar pkpy_False = {.type=tp_bool, .is_ptr=true, .extra=0, ._obj=&__false_obj};
+PyVar pkpy_None = {.type=tp_none_type, .is_ptr=true, ._obj=&__none_obj};
+PyVar pkpy_NotImplemented = {.type=tp_not_implemented_type, .is_ptr=true, ._obj=&__not_implemented_obj};
+PyVar pkpy_Ellipsis = {.type=tp_ellipsis, .is_ptr=true, ._obj=&__ellipsis_obj};

+ 6 - 4
src/pocketpy.cpp

@@ -375,7 +375,9 @@ void __init_builtins(VM* _vm) {
     });
 
     _vm->bind__eq__(VM::tp_object, [](VM* vm, PyVar _0, PyVar _1) {
-        return PyVar__IS_OP(&_0, &_1) ? vm->True : vm->False;
+        if(!_0.is_ptr) vm->TypeError("cannot compare tagged object: _0");
+        if(!_1.is_ptr) vm->TypeError("cannot compare tagged object: _1");
+        return _0._obj == _1._obj ? vm->True : vm->False;
     });
 
     _vm->__cached_object_new = _vm->bind_func(VM::tp_object, __new__, 1, [](VM* vm, ArgsView args) {
@@ -462,7 +464,7 @@ void __init_builtins(VM* _vm) {
             switch(vm->_tp(args[1])) {
                 case VM::tp_float: return VAR((i64)_CAST(f64, args[1]));
                 case VM::tp_int: return args[1];
-                case VM::tp_bool: return VAR(args[1]._bool ? 1 : 0);
+                case VM::tp_bool: return VAR(args[1].extra ? 1 : 0);
                 case VM::tp_str: break;
                 default: vm->TypeError("invalid arguments for int()");
             }
@@ -543,7 +545,7 @@ void __init_builtins(VM* _vm) {
         switch(vm->_tp(args[1])) {
             case VM::tp_int: return VAR((f64)CAST(i64, args[1]));
             case VM::tp_float: return args[1];
-            case VM::tp_bool: return VAR(args[1]._bool ? 1.0 : 0.0);
+            case VM::tp_bool: return VAR(args[1].extra ? 1.0 : 0.0);
             case VM::tp_str: break;
             default: vm->TypeError("invalid arguments for float()");
         }
@@ -1151,7 +1153,7 @@ void __init_builtins(VM* _vm) {
         return VAR(_CAST(bool, _0) != CAST(bool, _1));
     });
     _vm->bind__eq__(VM::tp_bool, [](VM* vm, PyVar _0, PyVar _1) {
-        if(is_type(_1, vm->tp_bool)) return VAR(_0._bool == _1._bool);
+        if(is_type(_1, vm->tp_bool)) return VAR(_0.extra == _1.extra);
         if(is_int(_1)) return VAR(_CAST(bool, _0) == (bool)CAST(i64, _1));
         return vm->NotImplemented;
     });

+ 6 - 1
tests/03_bool.py

@@ -17,4 +17,9 @@ assert bool(1) == True
 assert bool([]) == False
 assert bool("abc") == True
 assert bool([1,2]) == True
-assert bool('') == False
+assert bool('') == False
+
+# extra compare for None
+assert None == None
+assert ... == ...
+assert NotImplemented == NotImplemented

+ 4 - 2
tests/99_bugs.py

@@ -42,9 +42,11 @@ if not inq:
 else:
     assert False
 
-if inq is   not 1:
+a = object()
+b = object()
+if a is   not b:
     assert True
-if inq  is  not  0:
+if a  is  0:
     assert False
 
 def g(x):