diff --git a/include/pocketpy/interpreter/vm.h b/include/pocketpy/interpreter/vm.h index 1a628994..ac683785 100644 --- a/include/pocketpy/interpreter/vm.h +++ b/include/pocketpy/interpreter/vm.h @@ -63,7 +63,7 @@ void pk_VM__dtor(pk_VM* self); void pk_VM__push_frame(pk_VM* self, Frame* frame); void pk_VM__pop_frame(pk_VM* self); -bool pk__parse_int_slice(const py_Ref slice, int length, int* start, int* stop, int* step); +bool pk__parse_int_slice(py_Ref slice, int length, int* start, int* stop, int* step); bool pk__normalize_index(int* index, int length); void pk_list__mark(void* ud, void (*marker)(py_TValue*)); @@ -90,8 +90,9 @@ pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t argc, uint16_t kwargc, bo const char* pk_opname(Opcode op); py_TValue* pk_arrayview(py_Ref self, int* length); -int pk_arrayeq(py_TValue* lhs, int lhs_length, py_TValue* rhs, int rhs_length); +int pk_arrayequal(py_TValue* lhs, int lhs_length, py_TValue* rhs, int rhs_length); bool pk_arrayiter(py_Ref val); +bool pk_arraycontains(py_Ref self, py_Ref val); /// Assumes [a, b] are on the stack, performs a binary op. /// The result is stored in `self->last_retval`. diff --git a/include/pocketpy/pocketpy.h b/include/pocketpy/pocketpy.h index 1e4a87cd..762e6e00 100644 --- a/include/pocketpy/pocketpy.h +++ b/include/pocketpy/pocketpy.h @@ -105,17 +105,17 @@ py_Type py_newtype(const char* name, py_Type base, const py_GlobalRef module, vo /// @param udsize size of your userdata. You can use `py_touserdata()` to get the pointer to it. void* py_newobject(py_Ref out, py_Type type, int slots, int udsize); /************* Type Cast *************/ -py_i64 py_toint(const py_Ref); -py_f64 py_tofloat(const py_Ref); -bool py_castfloat(const py_Ref, py_f64* out); -bool py_tobool(const py_Ref); -py_Type py_totype(const py_Ref); -const char* py_tostr(const py_Ref); -const char* py_tostrn(const py_Ref, int* size); -c11_sv py_tosv(const py_Ref); -unsigned char* py_tobytes(const py_Ref, int* size); +py_i64 py_toint(py_Ref); +py_f64 py_tofloat(py_Ref); +bool py_castfloat(py_Ref, py_f64* out); +bool py_tobool(py_Ref); +py_Type py_totype(py_Ref); +const char* py_tostr(py_Ref); +const char* py_tostrn(py_Ref, int* size); +c11_sv py_tosv(py_Ref); +unsigned char* py_tobytes(py_Ref, int* size); -void* py_touserdata(const py_Ref); +void* py_touserdata(py_Ref); #define py_isint(self) py_istype(self, tp_int) #define py_isfloat(self) py_istype(self, tp_float) @@ -125,8 +125,8 @@ void* py_touserdata(const py_Ref); #define py_istuple(self) py_istype(self, tp_tuple) #define py_isdict(self) py_istype(self, tp_dict) -bool py_istype(const py_Ref, py_Type); -bool py_isinstance(const py_Ref obj, py_Type type); +bool py_istype(py_Ref, py_Type); +bool py_isinstance(py_Ref obj, py_Type type); bool py_issubclass(py_Type derived, py_Type base); extern py_GlobalRef py_True; @@ -182,35 +182,35 @@ py_GlobalRef py_reg(int i); /// Get the reference of the object's `__dict__`. /// The object must have a `__dict__`. /// Returns a reference to the value or NULL if not found. -py_ObjectRef py_getdict(const py_Ref self, py_Name name); -void py_setdict(py_Ref self, py_Name name, const py_Ref val); +py_ObjectRef py_getdict(py_Ref self, py_Name name); +void py_setdict(py_Ref self, py_Name name, py_Ref val); bool py_deldict(py_Ref self, py_Name name); /// Get the reference of the i-th slot of the object. /// The object must have slots and `i` must be in range. -py_ObjectRef py_getslot(const py_Ref self, int i); -void py_setslot(py_Ref self, int i, const py_Ref val); +py_ObjectRef py_getslot(py_Ref self, int i); +void py_setslot(py_Ref self, int i, py_Ref val); py_TmpRef py_getupvalue(py_StackRef argv); -void py_setupvalue(py_StackRef argv, const py_Ref val); +void py_setupvalue(py_StackRef argv, py_Ref val); /// Gets the attribute of the object. bool py_getattr(py_Ref self, py_Name name); /// Sets the attribute of the object. -bool py_setattr(py_Ref self, py_Name name, const py_Ref val); +bool py_setattr(py_Ref self, py_Name name, py_Ref val); /// Deletes the attribute of the object. bool py_delattr(py_Ref self, py_Name name); /// Gets the unbound method of the object. bool py_getunboundmethod(py_Ref self, py_Name name, py_Ref out, py_Ref out_self); -bool py_getitem(const py_Ref self, const py_Ref key); -bool py_setitem(py_Ref self, const py_Ref key, const py_Ref val); -bool py_delitem(py_Ref self, const py_Ref key); +bool py_getitem(py_Ref self, py_Ref key); +bool py_setitem(py_Ref self, py_Ref key, py_Ref val); +bool py_delitem(py_Ref self, py_Ref key); /// Perform a binary operation on the stack. /// It assumes `lhs` and `rhs` are already pushed to the stack. /// The result will be set to `py_retval()`. -bool py_binaryop(const py_Ref lhs, const py_Ref rhs, py_Name op, py_Name rop); +bool py_binaryop(py_Ref lhs, py_Ref rhs, py_Name op, py_Name rop); #define py_binaryadd(lhs, rhs) py_binaryop(lhs, rhs, __add__, __radd__) #define py_binarysub(lhs, rhs) py_binaryop(lhs, rhs, __sub__, __rsub__) @@ -228,14 +228,14 @@ bool py_binaryop(const py_Ref lhs, const py_Ref rhs, py_Name op, py_Name rop); #define py_binarymatmul(lhs, rhs) py_binaryop(lhs, rhs, __matmul__, 0) /// Equivalent to `*dst = *src`. -void py_assign(py_Ref dst, const py_Ref src); +void py_assign(py_Ref dst, py_Ref src); /************* Stack Operations *************/ /// Return a reference to the i-th object from the top of the stack. /// i should be negative, e.g. (-1) means TOS. py_StackRef py_peek(int i); /// Push the object to the stack. -void py_push(const py_Ref src); +void py_push(py_Ref src); /// Push a nil object to the stack. void py_pushnil(); /// Pop an object from the stack. @@ -286,7 +286,7 @@ bool KeyError(py_Ref key); /// Equivalent to `bool(val)`. /// Returns 1 if `val` is truthy, otherwise 0. /// Returns -1 if an error occurred. -int py_bool(const py_Ref val); +int py_bool(py_Ref val); #define py_eq(lhs, rhs) py_binaryop(lhs, rhs, __eq__, __eq__) #define py_ne(lhs, rhs) py_binaryop(lhs, rhs, __ne__, __ne__) @@ -295,19 +295,19 @@ int py_bool(const py_Ref val); #define py_gt(lhs, rhs) py_binaryop(lhs, rhs, __gt__, __lt__) #define py_ge(lhs, rhs) py_binaryop(lhs, rhs, __ge__, __le__) -int py_equal(const py_Ref lhs, const py_Ref rhs); -int py_less(const py_Ref lhs, const py_Ref rhs); +int py_equal(py_Ref lhs, py_Ref rhs); +int py_less(py_Ref lhs, py_Ref rhs); -bool py_hash(const py_Ref, py_i64* out); +bool py_hash(py_Ref, py_i64* out); /// Get the iterator of the object. -bool py_iter(const py_Ref); +bool py_iter(py_Ref); /// Get the next element from the iterator. /// 1: success, 0: StopIteration, -1: error -int py_next(const py_Ref); +int py_next(py_Ref); /// Python equivalent to `lhs is rhs`. -bool py_isidentical(const py_Ref, const py_Ref); +bool py_isidentical(py_Ref, py_Ref); /// A stack operation that calls a function. /// It assumes `argc + kwargc` arguments are already pushed to the stack. @@ -344,30 +344,28 @@ py_GlobalRef py_retval(); /* tuple */ // unchecked functions, if self is not a tuple, the behavior is undefined -py_ObjectRef py_tuple__data(const py_Ref self); -py_ObjectRef py_tuple__getitem(const py_Ref self, int i); -void py_tuple__setitem(py_Ref self, int i, const py_Ref val); -int py_tuple__len(const py_Ref self); +py_ObjectRef py_tuple__data(py_Ref self); +py_ObjectRef py_tuple__getitem(py_Ref self, int i); +void py_tuple__setitem(py_Ref self, int i, py_Ref val); +int py_tuple__len(py_Ref self); // unchecked functions, if self is not a list, the behavior is undefined -py_TmpRef py_list__data(const py_Ref self); -py_TmpRef py_list__getitem(const py_Ref self, int i); -void py_list__setitem(py_Ref self, int i, const py_Ref val); +py_TmpRef py_list__data(py_Ref self); +py_TmpRef py_list__getitem(py_Ref self, int i); +void py_list__setitem(py_Ref self, int i, py_Ref val); void py_list__delitem(py_Ref self, int i); -int py_list__len(const py_Ref self); -void py_list__append(py_Ref self, const py_Ref val); +int py_list__len(py_Ref self); +void py_list__append(py_Ref self, py_Ref val); void py_list__clear(py_Ref self); -void py_list__insert(py_Ref self, int i, const py_Ref val); +void py_list__insert(py_Ref self, int i, py_Ref val); void py_list__reverse(py_Ref self); // unchecked functions, if self is not a dict, the behavior is undefined -py_TmpRef py_dict__getitem(const py_Ref self, const py_Ref key); -void py_dict__setitem(py_Ref self, const py_Ref key, const py_Ref val); -bool py_dict__contains(const py_Ref self, const py_Ref key); -int py_dict__len(const py_Ref self); -bool py_dict__apply(const py_Ref self, - bool (*f)(const py_Ref key, const py_Ref val, void* ctx), - void* ctx); +py_TmpRef py_dict__getitem(py_Ref self, py_Ref key); +void py_dict__setitem(py_Ref self, py_Ref key, py_Ref val); +bool py_dict__contains(py_Ref self, py_Ref key); +int py_dict__len(py_Ref self); +bool py_dict__apply(py_Ref self, bool (*f)(py_Ref key, py_Ref val, void* ctx), void* ctx); /// Search the magic method from the given type to the base type. /// Return the reference or NULL if not found. @@ -387,7 +385,7 @@ const char* py_tpname(py_Type type); bool py_tpcall(py_Type type, int argc, py_Ref argv); /// Check if the object is an instance of the given type. -bool py_checktype(const py_Ref self, py_Type type); +bool py_checktype(py_Ref self, py_Type type); #define py_checkint(self) py_checktype(self, tp_int) #define py_checkfloat(self) py_checktype(self, tp_float) diff --git a/src/interpreter/ceval.c b/src/interpreter/ceval.c index e0db36fe..747879ac 100644 --- a/src/interpreter/ceval.c +++ b/src/interpreter/ceval.c @@ -60,7 +60,7 @@ static bool format_object(py_Ref obj, c11_sv spec); } \ } while(0) -static bool unpack_dict_to_buffer(const py_Ref key, const py_Ref val, void* ctx) { +static bool unpack_dict_to_buffer(py_Ref key, py_Ref val, void* ctx) { py_TValue** p = ctx; if(py_isstr(key)) { py_Name name = py_namev(py_tosv(key)); @@ -553,8 +553,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { if(byte.arg) py_newbool(TOP(), !res); DISPATCH(); } - // TODO: fallback to __iter__? - TypeError("argument of type '%t' is not iterable", SECOND()->type); + TypeError("'%t' type does not support '__contains__'", SECOND()->type); goto __ERROR; } /*****************************************/ @@ -922,7 +921,7 @@ bool pk_stack_binaryop(pk_VM* self, py_Name op, py_Name rop) { return py_exception("TypeError", "unsupported operand type(s) for '%n'", op); } -bool py_binaryop(const py_Ref lhs, const py_Ref rhs, py_Name op, py_Name rop) { +bool py_binaryop(py_Ref lhs, py_Ref rhs, py_Name op, py_Name rop) { pk_VM* self = pk_current_vm; PUSH(lhs); PUSH(rhs); diff --git a/src/interpreter/vm.c b/src/interpreter/vm.c index b351608c..74d2ee7d 100644 --- a/src/interpreter/vm.c +++ b/src/interpreter/vm.c @@ -200,7 +200,7 @@ static void _clip_int(int* value, int min, int max) { if(*value > max) *value = max; } -bool pk__parse_int_slice(const py_Ref slice, int length, int* start, int* stop, int* step) { +bool pk__parse_int_slice(py_Ref slice, int length, int* start, int* stop, int* step) { py_Ref s_start = py_getslot(slice, 0); py_Ref s_stop = py_getslot(slice, 1); py_Ref s_step = py_getslot(slice, 2); diff --git a/src/public/cast.c b/src/public/cast.c index 1dee7d68..833f74b6 100644 --- a/src/public/cast.c +++ b/src/public/cast.c @@ -5,17 +5,17 @@ #include "pocketpy/objects/object.h" #include "pocketpy/interpreter/vm.h" -int64_t py_toint(const py_Ref self) { +int64_t py_toint(py_Ref self) { assert(self->type == tp_int); return self->_i64; } -double py_tofloat(const py_Ref self) { +double py_tofloat(py_Ref self) { assert(self->type == tp_float); return self->_f64; } -bool py_castfloat(const py_Ref self, double* out) { +bool py_castfloat(py_Ref self, double* out) { switch(self->type) { case tp_int: *out = (double)self->_i64; return true; case tp_float: *out = self->_f64; return true; @@ -23,25 +23,25 @@ bool py_castfloat(const py_Ref self, double* out) { } } -bool py_tobool(const py_Ref self) { +bool py_tobool(py_Ref self) { assert(self->type == tp_bool); return self->_bool; } -py_Type py_totype(const py_Ref self) { +py_Type py_totype(py_Ref self) { assert(self->type == tp_type); py_Type* ud = py_touserdata(self); return *ud; } -void* py_touserdata(const py_Ref self) { +void* py_touserdata(py_Ref self) { assert(self && self->is_ptr); return PyObject__userdata(self->_obj); } -bool py_istype(const py_Ref self, py_Type type) { return self->type == type; } +bool py_istype(py_Ref self, py_Type type) { return self->type == type; } -bool py_checktype(const py_Ref self, py_Type type) { +bool py_checktype(py_Ref self, py_Type type) { if(self->type != type) { return TypeError("expected %t, got %t", type, self->type); } diff --git a/src/public/py_array.c b/src/public/py_array.c index 8c0047dc..c38bc318 100644 --- a/src/public/py_array.c +++ b/src/public/py_array.c @@ -23,7 +23,7 @@ py_TValue* pk_arrayview(py_Ref self, int* length) { return NULL; } -int pk_arrayeq(py_TValue* lhs, int lhs_length, py_TValue* rhs, int rhs_length) { +int pk_arrayequal(py_TValue* lhs, int lhs_length, py_TValue* rhs, int rhs_length) { if(lhs_length != rhs_length) return false; for(int i = 0; i < lhs_length; i++) { int res = py_equal(lhs + i, rhs + i); @@ -45,6 +45,22 @@ bool pk_arrayiter(py_Ref val) { return true; } +bool pk_arraycontains(py_Ref self, py_Ref val) { + int length; + py_TValue* p = pk_arrayview(self, &length); + if(!p) return TypeError("expected list or tuple, got %t", self->type); + for(int i = 0; i < length; i++) { + int res = py_equal(p + i, val); + if(res == -1) return false; + if(res) { + py_newbool(py_retval(), true); + return true; + } + } + py_newbool(py_retval(), false); + return true; +} + static bool _py_array_iterator__iter__(int argc, py_Ref argv) { PY_CHECK_ARGC(1); *py_retval() = *argv; diff --git a/src/public/py_dict.c b/src/public/py_dict.c index 1f1f96b0..43c1cfe8 100644 --- a/src/public/py_dict.c +++ b/src/public/py_dict.c @@ -491,7 +491,7 @@ void py_newdict(py_Ref out) { Dict__ctor(ud, 8); } -py_Ref py_dict__getitem(const py_Ref self, const py_Ref key) { +py_Ref py_dict__getitem(py_Ref self, py_Ref key) { assert(py_isdict(self)); Dict* ud = py_touserdata(self); DictEntry* entry; @@ -500,13 +500,13 @@ py_Ref py_dict__getitem(const py_Ref self, const py_Ref key) { return NULL; } -void py_dict__setitem(py_Ref self, const py_Ref key, const py_Ref val) { +void py_dict__setitem(py_Ref self, py_Ref key, py_Ref val) { assert(py_isdict(self)); Dict* ud = py_touserdata(self); Dict__set(ud, key, val); } -bool py_dict__contains(const py_Ref self, const py_Ref key) { +bool py_dict__contains(py_Ref self, py_Ref key) { assert(py_isdict(self)); Dict* ud = py_touserdata(self); DictEntry* entry; @@ -514,13 +514,13 @@ bool py_dict__contains(const py_Ref self, const py_Ref key) { return ok && entry != NULL; } -int py_dict__len(const py_Ref self) { +int py_dict__len(py_Ref self) { assert(py_isdict(self)); Dict* ud = py_touserdata(self); return ud->length; } -bool py_dict__apply(const py_Ref self, bool (*f)(const py_Ref, const py_Ref, void *), void *ctx){ +bool py_dict__apply(py_Ref self, bool (*f)(py_Ref, py_Ref, void *), void *ctx){ Dict* ud = py_touserdata(self); for(int i = 0; i < ud->entries.count; i++) { DictEntry* entry = c11__at(DictEntry, &ud->entries, i); diff --git a/src/public/py_list.c b/src/public/py_list.c index 18ba60fe..250f10ef 100644 --- a/src/public/py_list.c +++ b/src/public/py_list.c @@ -19,17 +19,17 @@ void py_newlistn(py_Ref out, int n) { userdata->count = n; } -py_Ref py_list__data(const py_Ref self) { +py_Ref py_list__data(py_Ref self) { List* userdata = py_touserdata(self); return userdata->data; } -py_Ref py_list__getitem(const py_Ref self, int i) { +py_Ref py_list__getitem(py_Ref self, int i) { List* userdata = py_touserdata(self); return c11__at(py_TValue, userdata, i); } -void py_list__setitem(py_Ref self, int i, const py_Ref val) { +void py_list__setitem(py_Ref self, int i, py_Ref val) { List* userdata = py_touserdata(self); c11__setitem(py_TValue, userdata, i, *val); } @@ -39,12 +39,12 @@ void py_list__delitem(py_Ref self, int i) { c11_vector__erase(py_TValue, userdata, i); } -int py_list__len(const py_Ref self) { +int py_list__len(py_Ref self) { List* userdata = py_touserdata(self); return userdata->count; } -void py_list__append(py_Ref self, const py_Ref val) { +void py_list__append(py_Ref self, py_Ref val) { List* userdata = py_touserdata(self); c11_vector__push(py_TValue, userdata, *val); } @@ -54,7 +54,7 @@ void py_list__clear(py_Ref self) { c11_vector__clear(userdata); } -void py_list__insert(py_Ref self, int i, const py_Ref val) { +void py_list__insert(py_Ref self, int i, py_Ref val) { List* userdata = py_touserdata(self); c11_vector__insert(py_TValue, userdata, i, *val); } @@ -78,7 +78,7 @@ static bool _py_list__eq__(int argc, py_Ref argv) { int length0, length1; py_TValue* a0 = pk_arrayview(py_arg(0), &length0); py_TValue* a1 = pk_arrayview(py_arg(1), &length1); - int res = pk_arrayeq(a0, length0, a1, length1); + int res = pk_arrayequal(a0, length0, a1, length1); if(res == -1) return false; py_newbool(py_retval(), res); } else { @@ -401,6 +401,11 @@ static bool _py_list__iter__(int argc, py_Ref argv) { return pk_arrayiter(argv); } +static bool _py_list__contains__(int argc, py_Ref argv) { + PY_CHECK_ARGC(2); + return pk_arraycontains(py_arg(0), py_arg(1)); +} + py_Type pk_list__register() { py_Type type = pk_newtype("list", tp_object, NULL, (void (*)(void*))c11_vector__dtor, false, true); @@ -417,6 +422,7 @@ py_Type pk_list__register() { py_bindmagic(type, __rmul__, _py_list__rmul__); py_bindmagic(type, __repr__, _py_list__repr__); py_bindmagic(type, __iter__, _py_list__iter__); + py_bindmagic(type, __contains__, _py_list__contains__); py_bindmethod(type, "append", _py_list__append); py_bindmethod(type, "extend", _py_list__extend); diff --git a/src/public/py_ops.c b/src/public/py_ops.c index 7aa96305..755b1be2 100644 --- a/src/public/py_ops.c +++ b/src/public/py_ops.c @@ -2,7 +2,7 @@ #include "pocketpy/objects/base.h" #include "pocketpy/pocketpy.h" -bool py_isidentical(const py_Ref lhs, const py_Ref rhs) { +bool py_isidentical(py_Ref lhs, py_Ref rhs) { if(lhs->type != rhs->type) return false; switch(lhs->type) { case tp_int: return lhs->_i64 == rhs->_i64; @@ -17,7 +17,7 @@ bool py_isidentical(const py_Ref lhs, const py_Ref rhs) { } } -int py_bool(const py_Ref val) { +int py_bool(py_Ref val) { switch(val->type) { case tp_bool: return val->_bool; case tp_int: return val->_i64 != 0; @@ -43,7 +43,7 @@ int py_bool(const py_Ref val) { } } -bool py_hash(const py_Ref val, int64_t* out) { +bool py_hash(py_Ref val, int64_t* out) { py_Type t = val->type; pk_TypeInfo* types = (pk_TypeInfo*)pk_current_vm->types.data; do { @@ -61,13 +61,13 @@ bool py_hash(const py_Ref val, int64_t* out) { return TypeError("unhashable type: '%t'", val->type); } -bool py_iter(const py_Ref val) { +bool py_iter(py_Ref val) { py_Ref tmp = py_tpfindmagic(val->type, __iter__); if(!tmp) return TypeError("'%t' object is not iterable", val->type); return py_call(tmp, 1, val); } -int py_next(const py_Ref val) { +int py_next(py_Ref val) { pk_VM* vm = pk_current_vm; vm->is_stopiteration = false; py_Ref tmp = py_tpfindmagic(val->type, __next__); @@ -134,7 +134,7 @@ bool py_getattr(py_Ref self, py_Name name) { return AttributeError(self, name); } -bool py_setattr(py_Ref self, py_Name name, const py_Ref val) { +bool py_setattr(py_Ref self, py_Name name, py_Ref val) { py_Type type = self->type; // handle super() proxy if(py_istype(self, tp_super)) { @@ -175,7 +175,7 @@ bool py_delattr(py_Ref self, py_Name name) { return TypeError("cannot delete attribute"); } -bool py_getitem(const py_Ref self, const py_Ref key) { +bool py_getitem(py_Ref self, py_Ref key) { py_push(self); py_push(key); bool ok = py_callmagic(__getitem__, 2, py_peek(-2)); @@ -183,7 +183,7 @@ bool py_getitem(const py_Ref self, const py_Ref key) { return ok; } -bool py_setitem(py_Ref self, const py_Ref key, const py_Ref val) { +bool py_setitem(py_Ref self, py_Ref key, py_Ref val) { py_push(self); py_push(key); py_push(val); @@ -192,7 +192,7 @@ bool py_setitem(py_Ref self, const py_Ref key, const py_Ref val) { return ok; } -bool py_delitem(py_Ref self, const py_Ref key) { +bool py_delitem(py_Ref self, py_Ref key) { py_push(self); py_push(key); bool ok = py_callmagic(__delitem__, 2, py_peek(-2)); @@ -200,12 +200,12 @@ bool py_delitem(py_Ref self, const py_Ref key) { return ok; } -int py_equal(const py_Ref lhs, const py_Ref rhs){ +int py_equal(py_Ref lhs, py_Ref rhs){ if(!py_eq(lhs, rhs)) return -1; return py_bool(py_retval()); } -int py_less(const py_Ref lhs, const py_Ref rhs){ +int py_less(py_Ref lhs, py_Ref rhs){ if(!py_lt(lhs, rhs)) return -1; return py_bool(py_retval()); } \ No newline at end of file diff --git a/src/public/py_str.c b/src/public/py_str.c index a5ec3f93..e4031b12 100644 --- a/src/public/py_str.c +++ b/src/public/py_str.c @@ -31,26 +31,26 @@ unsigned char* py_newbytes(py_Ref out, int size) { return ud->data; } -const char* py_tostr(const py_Ref self) { +const char* py_tostr(py_Ref self) { assert(self->type == tp_str); c11_string* ud = PyObject__userdata(self->_obj); return ud->data; } -const char* py_tostrn(const py_Ref self, int* size) { +const char* py_tostrn(py_Ref self, int* size) { assert(self->type == tp_str); c11_string* ud = PyObject__userdata(self->_obj); *size = ud->size; return ud->data; } -c11_sv py_tosv(const py_Ref self) { +c11_sv py_tosv(py_Ref self) { assert(self->type == tp_str); c11_string* ud = PyObject__userdata(self->_obj); return c11_string__sv(ud); } -unsigned char* py_tobytes(const py_Ref self, int* size) { +unsigned char* py_tobytes(py_Ref self, int* size) { assert(self->type == tp_bytes); c11_bytes* ud = PyObject__userdata(self->_obj); *size = ud->size; diff --git a/src/public/py_tuple.c b/src/public/py_tuple.c index 7ff55d87..cd264905 100644 --- a/src/public/py_tuple.c +++ b/src/public/py_tuple.c @@ -13,13 +13,13 @@ void py_newtuple(py_Ref out, int n) { out->_obj = obj; } -py_Ref py_tuple__getitem(const py_Ref self, int i) { return py_getslot(self, i); } +py_Ref py_tuple__getitem(py_Ref self, int i) { return py_getslot(self, i); } -py_Ref py_tuple__data(const py_Ref self) { return PyObject__slots(self->_obj); } +py_Ref py_tuple__data(py_Ref self) { return PyObject__slots(self->_obj); } -void py_tuple__setitem(py_Ref self, int i, const py_Ref val) { py_setslot(self, i, val); } +void py_tuple__setitem(py_Ref self, int i, py_Ref val) { py_setslot(self, i, val); } -int py_tuple__len(const py_Ref self) { return self->_obj->slots; } +int py_tuple__len(py_Ref self) { return self->_obj->slots; } ////////////// static bool _py_tuple__len__(int argc, py_Ref argv) { @@ -103,7 +103,7 @@ static bool _py_tuple__eq__(int argc, py_Ref argv) { int length0, length1; py_TValue* a0 = pk_arrayview(py_arg(0), &length0); py_TValue* a1 = pk_arrayview(py_arg(1), &length1); - int res = pk_arrayeq(a0, length0, a1, length1); + int res = pk_arrayequal(a0, length0, a1, length1); if(res == -1) return false; py_newbool(py_retval(), res); } else { @@ -126,6 +126,11 @@ static bool _py_tuple__iter__(int argc, py_Ref argv) { return pk_arrayiter(argv); } +static bool _py_tuple__contains__(int argc, py_Ref argv) { + PY_CHECK_ARGC(2); + return pk_arraycontains(py_arg(0), py_arg(1)); +} + py_Type pk_tuple__register() { py_Type type = pk_newtype("tuple", tp_object, NULL, NULL, false, true); @@ -136,5 +141,6 @@ py_Type pk_tuple__register() { py_bindmagic(type, __eq__, _py_tuple__eq__); py_bindmagic(type, __ne__, _py_tuple__ne__); py_bindmagic(type, __iter__, _py_tuple__iter__); + py_bindmagic(type, __contains__, _py_tuple__contains__); return type; } diff --git a/src/public/stack_ops.c b/src/public/stack_ops.c index 1bfb860b..8e416573 100644 --- a/src/public/stack_ops.c +++ b/src/public/stack_ops.c @@ -6,7 +6,7 @@ py_Ref py_reg(int i) { return pk_current_vm->reg + i; } -py_Ref py_getdict(const py_Ref self, py_Name name) { +py_Ref py_getdict(py_Ref self, py_Name name) { assert(self && self->is_ptr); if(!py_ismagicname(name) || self->type != tp_type) { return pk_NameDict__try_get(PyObject__dict(self->_obj), name); @@ -17,7 +17,7 @@ py_Ref py_getdict(const py_Ref self, py_Name name) { } } -void py_setdict(py_Ref self, py_Name name, const py_Ref val) { +void py_setdict(py_Ref self, py_Name name, py_Ref val) { assert(self && self->is_ptr); if(!py_ismagicname(name) || self->type != tp_type) { pk_NameDict__set(PyObject__dict(self->_obj), name, *val); @@ -39,19 +39,19 @@ bool py_deldict(py_Ref self, py_Name name) { } } -py_Ref py_getslot(const py_Ref self, int i) { +py_Ref py_getslot(py_Ref self, int i) { assert(self && self->is_ptr); assert(i >= 0 && i < self->_obj->slots); return PyObject__slots(self->_obj) + i; } -void py_setslot(py_Ref self, int i, const py_Ref val) { +void py_setslot(py_Ref self, int i, py_Ref val) { assert(self && self->is_ptr); assert(i >= 0 && i < self->_obj->slots); PyObject__slots(self->_obj)[i] = *val; } -void py_assign(py_Ref dst, const py_Ref src) { *dst = *src; } +void py_assign(py_Ref dst, py_Ref src) { *dst = *src; } /* Stack References */ py_Ref py_peek(int i) { @@ -69,7 +69,7 @@ void py_shrink(int n) { vm->stack.sp -= n; } -void py_push(const py_Ref src) { +void py_push(py_Ref src) { pk_VM* vm = pk_current_vm; *vm->stack.sp++ = *src; } diff --git a/tests/05_list.py b/tests/05_list.py index 2b3d589f..a6d16e45 100644 --- a/tests/05_list.py +++ b/tests/05_list.py @@ -152,9 +152,13 @@ assert repr([1, [2, 3], 4]) == "[1, [2, 3], 4]" assert repr([1, [2, [3, 4]], 5]) == "[1, [2, [3, 4]], 5]" assert repr([]) == "[]" -# b = [(1, 2), (3, 3), (5, 1)] -# b.sort(key=lambda x:x[1]) -# assert b == [(5, 1), (1, 2), (3,3)] +# test in and not in +assert 1 in [1, 2, 3] +assert 4 not in [1, 2, 3] + +b = [(1, 2), (3, 3), (5, 1)] +b.sort(key=lambda x:x[1]) +assert b == [(5, 1), (1, 2), (3,3)] # test cyclic reference # a = [] diff --git a/tests/06_tuple.py b/tests/06_tuple.py index 8c07a0b5..1a45eb49 100644 --- a/tests/06_tuple.py +++ b/tests/06_tuple.py @@ -30,4 +30,8 @@ assert l[-3:-1] == (2,3) assert repr((1,)) == '(1,)' assert repr((1,2,)) == '(1, 2)' assert repr((1,2,(3,4))) == '(1, 2, (3, 4))' -assert repr(tuple()) == '()' \ No newline at end of file +assert repr(tuple()) == '()' + +# test in and not in +assert 1 in (1, 2, 3) +assert 4 not in (1, 2, 3)