This commit is contained in:
blueloveTH 2024-07-21 21:01:12 +08:00
parent 29a989f09a
commit 2605382a79
14 changed files with 141 additions and 107 deletions

View File

@ -63,7 +63,7 @@ void pk_VM__dtor(pk_VM* self);
void pk_VM__push_frame(pk_VM* self, Frame* frame); void pk_VM__push_frame(pk_VM* self, Frame* frame);
void pk_VM__pop_frame(pk_VM* self); 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); bool pk__normalize_index(int* index, int length);
void pk_list__mark(void* ud, void (*marker)(py_TValue*)); 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); const char* pk_opname(Opcode op);
py_TValue* pk_arrayview(py_Ref self, int* length); 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_arrayiter(py_Ref val);
bool pk_arraycontains(py_Ref self, py_Ref val);
/// Assumes [a, b] are on the stack, performs a binary op. /// Assumes [a, b] are on the stack, performs a binary op.
/// The result is stored in `self->last_retval`. /// The result is stored in `self->last_retval`.

View File

@ -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. /// @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); void* py_newobject(py_Ref out, py_Type type, int slots, int udsize);
/************* Type Cast *************/ /************* Type Cast *************/
py_i64 py_toint(const py_Ref); py_i64 py_toint(py_Ref);
py_f64 py_tofloat(const py_Ref); py_f64 py_tofloat(py_Ref);
bool py_castfloat(const py_Ref, py_f64* out); bool py_castfloat(py_Ref, py_f64* out);
bool py_tobool(const py_Ref); bool py_tobool(py_Ref);
py_Type py_totype(const py_Ref); py_Type py_totype(py_Ref);
const char* py_tostr(const py_Ref); const char* py_tostr(py_Ref);
const char* py_tostrn(const py_Ref, int* size); const char* py_tostrn(py_Ref, int* size);
c11_sv py_tosv(const py_Ref); c11_sv py_tosv(py_Ref);
unsigned char* py_tobytes(const py_Ref, int* size); 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_isint(self) py_istype(self, tp_int)
#define py_isfloat(self) py_istype(self, tp_float) #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_istuple(self) py_istype(self, tp_tuple)
#define py_isdict(self) py_istype(self, tp_dict) #define py_isdict(self) py_istype(self, tp_dict)
bool py_istype(const py_Ref, py_Type); bool py_istype(py_Ref, py_Type);
bool py_isinstance(const py_Ref obj, py_Type type); bool py_isinstance(py_Ref obj, py_Type type);
bool py_issubclass(py_Type derived, py_Type base); bool py_issubclass(py_Type derived, py_Type base);
extern py_GlobalRef py_True; extern py_GlobalRef py_True;
@ -182,35 +182,35 @@ py_GlobalRef py_reg(int i);
/// Get the reference of the object's `__dict__`. /// Get the reference of the object's `__dict__`.
/// The object must have a `__dict__`. /// The object must have a `__dict__`.
/// Returns a reference to the value or NULL if not found. /// Returns a reference to the value or NULL if not found.
py_ObjectRef py_getdict(const py_Ref self, py_Name name); py_ObjectRef py_getdict(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);
bool py_deldict(py_Ref self, py_Name name); bool py_deldict(py_Ref self, py_Name name);
/// Get the reference of the i-th slot of the object. /// Get the reference of the i-th slot of the object.
/// The object must have slots and `i` must be in range. /// The object must have slots and `i` must be in range.
py_ObjectRef py_getslot(const py_Ref self, int i); py_ObjectRef py_getslot(py_Ref self, int i);
void py_setslot(py_Ref self, int i, const py_Ref val); void py_setslot(py_Ref self, int i, py_Ref val);
py_TmpRef py_getupvalue(py_StackRef argv); 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. /// Gets the attribute of the object.
bool py_getattr(py_Ref self, py_Name name); bool py_getattr(py_Ref self, py_Name name);
/// Sets the attribute of the object. /// 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. /// Deletes the attribute of the object.
bool py_delattr(py_Ref self, py_Name name); bool py_delattr(py_Ref self, py_Name name);
/// Gets the unbound method of the object. /// 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_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_getitem(py_Ref self, py_Ref key);
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);
bool py_delitem(py_Ref self, const py_Ref key); bool py_delitem(py_Ref self, py_Ref key);
/// Perform a binary operation on the stack. /// Perform a binary operation on the stack.
/// It assumes `lhs` and `rhs` are already pushed to the stack. /// It assumes `lhs` and `rhs` are already pushed to the stack.
/// The result will be set to `py_retval()`. /// 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_binaryadd(lhs, rhs) py_binaryop(lhs, rhs, __add__, __radd__)
#define py_binarysub(lhs, rhs) py_binaryop(lhs, rhs, __sub__, __rsub__) #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) #define py_binarymatmul(lhs, rhs) py_binaryop(lhs, rhs, __matmul__, 0)
/// Equivalent to `*dst = *src`. /// 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 *************/ /************* Stack Operations *************/
/// Return a reference to the i-th object from the top of the stack. /// Return a reference to the i-th object from the top of the stack.
/// i should be negative, e.g. (-1) means TOS. /// i should be negative, e.g. (-1) means TOS.
py_StackRef py_peek(int i); py_StackRef py_peek(int i);
/// Push the object to the stack. /// 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. /// Push a nil object to the stack.
void py_pushnil(); void py_pushnil();
/// Pop an object from the stack. /// Pop an object from the stack.
@ -286,7 +286,7 @@ bool KeyError(py_Ref key);
/// Equivalent to `bool(val)`. /// Equivalent to `bool(val)`.
/// Returns 1 if `val` is truthy, otherwise 0. /// Returns 1 if `val` is truthy, otherwise 0.
/// Returns -1 if an error occurred. /// 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_eq(lhs, rhs) py_binaryop(lhs, rhs, __eq__, __eq__)
#define py_ne(lhs, rhs) py_binaryop(lhs, rhs, __ne__, __ne__) #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_gt(lhs, rhs) py_binaryop(lhs, rhs, __gt__, __lt__)
#define py_ge(lhs, rhs) py_binaryop(lhs, rhs, __ge__, __le__) #define py_ge(lhs, rhs) py_binaryop(lhs, rhs, __ge__, __le__)
int py_equal(const py_Ref lhs, const py_Ref rhs); int py_equal(py_Ref lhs, py_Ref rhs);
int py_less(const py_Ref lhs, const 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. /// Get the iterator of the object.
bool py_iter(const py_Ref); bool py_iter(py_Ref);
/// Get the next element from the iterator. /// Get the next element from the iterator.
/// 1: success, 0: StopIteration, -1: error /// 1: success, 0: StopIteration, -1: error
int py_next(const py_Ref); int py_next(py_Ref);
/// Python equivalent to `lhs is rhs`. /// 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. /// A stack operation that calls a function.
/// It assumes `argc + kwargc` arguments are already pushed to the stack. /// It assumes `argc + kwargc` arguments are already pushed to the stack.
@ -344,30 +344,28 @@ py_GlobalRef py_retval();
/* tuple */ /* tuple */
// unchecked functions, if self is not a tuple, the behavior is undefined // 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__data(py_Ref self);
py_ObjectRef py_tuple__getitem(const py_Ref self, int i); py_ObjectRef py_tuple__getitem(py_Ref self, int i);
void py_tuple__setitem(py_Ref self, int i, const py_Ref val); void py_tuple__setitem(py_Ref self, int i, py_Ref val);
int py_tuple__len(const py_Ref self); int py_tuple__len(py_Ref self);
// unchecked functions, if self is not a list, the behavior is undefined // 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__data(py_Ref self);
py_TmpRef py_list__getitem(const py_Ref self, int i); py_TmpRef py_list__getitem(py_Ref self, int 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);
void py_list__delitem(py_Ref self, int i); void py_list__delitem(py_Ref self, int i);
int py_list__len(const py_Ref self); int py_list__len(py_Ref self);
void py_list__append(py_Ref self, const py_Ref val); void py_list__append(py_Ref self, py_Ref val);
void py_list__clear(py_Ref self); 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); void py_list__reverse(py_Ref self);
// unchecked functions, if self is not a dict, the behavior is undefined // 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); py_TmpRef py_dict__getitem(py_Ref self, py_Ref key);
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);
bool py_dict__contains(const py_Ref self, const py_Ref key); bool py_dict__contains(py_Ref self, py_Ref key);
int py_dict__len(const py_Ref self); int py_dict__len(py_Ref self);
bool py_dict__apply(const py_Ref self, bool py_dict__apply(py_Ref self, bool (*f)(py_Ref key, py_Ref val, void* ctx), void* ctx);
bool (*f)(const py_Ref key, const py_Ref val, void* ctx),
void* ctx);
/// Search the magic method from the given type to the base type. /// Search the magic method from the given type to the base type.
/// Return the reference or NULL if not found. /// 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); bool py_tpcall(py_Type type, int argc, py_Ref argv);
/// Check if the object is an instance of the given type. /// 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_checkint(self) py_checktype(self, tp_int)
#define py_checkfloat(self) py_checktype(self, tp_float) #define py_checkfloat(self) py_checktype(self, tp_float)

View File

@ -60,7 +60,7 @@ static bool format_object(py_Ref obj, c11_sv spec);
} \ } \
} while(0) } 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; py_TValue** p = ctx;
if(py_isstr(key)) { if(py_isstr(key)) {
py_Name name = py_namev(py_tosv(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); if(byte.arg) py_newbool(TOP(), !res);
DISPATCH(); DISPATCH();
} }
// TODO: fallback to __iter__? TypeError("'%t' type does not support '__contains__'", SECOND()->type);
TypeError("argument of type '%t' is not iterable", SECOND()->type);
goto __ERROR; 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); 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; pk_VM* self = pk_current_vm;
PUSH(lhs); PUSH(lhs);
PUSH(rhs); PUSH(rhs);

View File

@ -200,7 +200,7 @@ static void _clip_int(int* value, int min, int max) {
if(*value > max) *value = 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_start = py_getslot(slice, 0);
py_Ref s_stop = py_getslot(slice, 1); py_Ref s_stop = py_getslot(slice, 1);
py_Ref s_step = py_getslot(slice, 2); py_Ref s_step = py_getslot(slice, 2);

View File

@ -5,17 +5,17 @@
#include "pocketpy/objects/object.h" #include "pocketpy/objects/object.h"
#include "pocketpy/interpreter/vm.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); assert(self->type == tp_int);
return self->_i64; return self->_i64;
} }
double py_tofloat(const py_Ref self) { double py_tofloat(py_Ref self) {
assert(self->type == tp_float); assert(self->type == tp_float);
return self->_f64; return self->_f64;
} }
bool py_castfloat(const py_Ref self, double* out) { bool py_castfloat(py_Ref self, double* out) {
switch(self->type) { switch(self->type) {
case tp_int: *out = (double)self->_i64; return true; case tp_int: *out = (double)self->_i64; return true;
case tp_float: *out = self->_f64; 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); assert(self->type == tp_bool);
return self->_bool; return self->_bool;
} }
py_Type py_totype(const py_Ref self) { py_Type py_totype(py_Ref self) {
assert(self->type == tp_type); assert(self->type == tp_type);
py_Type* ud = py_touserdata(self); py_Type* ud = py_touserdata(self);
return *ud; return *ud;
} }
void* py_touserdata(const py_Ref self) { void* py_touserdata(py_Ref self) {
assert(self && self->is_ptr); assert(self && self->is_ptr);
return PyObject__userdata(self->_obj); 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) { if(self->type != type) {
return TypeError("expected %t, got %t", type, self->type); return TypeError("expected %t, got %t", type, self->type);
} }

View File

@ -23,7 +23,7 @@ py_TValue* pk_arrayview(py_Ref self, int* length) {
return NULL; 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; if(lhs_length != rhs_length) return false;
for(int i = 0; i < lhs_length; i++) { for(int i = 0; i < lhs_length; i++) {
int res = py_equal(lhs + i, rhs + i); int res = py_equal(lhs + i, rhs + i);
@ -45,6 +45,22 @@ bool pk_arrayiter(py_Ref val) {
return true; 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) { static bool _py_array_iterator__iter__(int argc, py_Ref argv) {
PY_CHECK_ARGC(1); PY_CHECK_ARGC(1);
*py_retval() = *argv; *py_retval() = *argv;

View File

@ -491,7 +491,7 @@ void py_newdict(py_Ref out) {
Dict__ctor(ud, 8); 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)); assert(py_isdict(self));
Dict* ud = py_touserdata(self); Dict* ud = py_touserdata(self);
DictEntry* entry; DictEntry* entry;
@ -500,13 +500,13 @@ py_Ref py_dict__getitem(const py_Ref self, const py_Ref key) {
return NULL; 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)); assert(py_isdict(self));
Dict* ud = py_touserdata(self); Dict* ud = py_touserdata(self);
Dict__set(ud, key, val); 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)); assert(py_isdict(self));
Dict* ud = py_touserdata(self); Dict* ud = py_touserdata(self);
DictEntry* entry; DictEntry* entry;
@ -514,13 +514,13 @@ bool py_dict__contains(const py_Ref self, const py_Ref key) {
return ok && entry != NULL; return ok && entry != NULL;
} }
int py_dict__len(const py_Ref self) { int py_dict__len(py_Ref self) {
assert(py_isdict(self)); assert(py_isdict(self));
Dict* ud = py_touserdata(self); Dict* ud = py_touserdata(self);
return ud->length; 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); Dict* ud = py_touserdata(self);
for(int i = 0; i < ud->entries.count; i++) { for(int i = 0; i < ud->entries.count; i++) {
DictEntry* entry = c11__at(DictEntry, &ud->entries, i); DictEntry* entry = c11__at(DictEntry, &ud->entries, i);

View File

@ -19,17 +19,17 @@ void py_newlistn(py_Ref out, int n) {
userdata->count = 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); List* userdata = py_touserdata(self);
return userdata->data; 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); List* userdata = py_touserdata(self);
return c11__at(py_TValue, userdata, i); 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); List* userdata = py_touserdata(self);
c11__setitem(py_TValue, userdata, i, *val); 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); 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); List* userdata = py_touserdata(self);
return userdata->count; 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); List* userdata = py_touserdata(self);
c11_vector__push(py_TValue, userdata, *val); c11_vector__push(py_TValue, userdata, *val);
} }
@ -54,7 +54,7 @@ void py_list__clear(py_Ref self) {
c11_vector__clear(userdata); 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); List* userdata = py_touserdata(self);
c11_vector__insert(py_TValue, userdata, i, *val); 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; int length0, length1;
py_TValue* a0 = pk_arrayview(py_arg(0), &length0); py_TValue* a0 = pk_arrayview(py_arg(0), &length0);
py_TValue* a1 = pk_arrayview(py_arg(1), &length1); 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; if(res == -1) return false;
py_newbool(py_retval(), res); py_newbool(py_retval(), res);
} else { } else {
@ -401,6 +401,11 @@ static bool _py_list__iter__(int argc, py_Ref argv) {
return pk_arrayiter(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 pk_list__register() {
py_Type type = py_Type type =
pk_newtype("list", tp_object, NULL, (void (*)(void*))c11_vector__dtor, false, true); 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, __rmul__, _py_list__rmul__);
py_bindmagic(type, __repr__, _py_list__repr__); py_bindmagic(type, __repr__, _py_list__repr__);
py_bindmagic(type, __iter__, _py_list__iter__); py_bindmagic(type, __iter__, _py_list__iter__);
py_bindmagic(type, __contains__, _py_list__contains__);
py_bindmethod(type, "append", _py_list__append); py_bindmethod(type, "append", _py_list__append);
py_bindmethod(type, "extend", _py_list__extend); py_bindmethod(type, "extend", _py_list__extend);

View File

@ -2,7 +2,7 @@
#include "pocketpy/objects/base.h" #include "pocketpy/objects/base.h"
#include "pocketpy/pocketpy.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; if(lhs->type != rhs->type) return false;
switch(lhs->type) { switch(lhs->type) {
case tp_int: return lhs->_i64 == rhs->_i64; 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) { switch(val->type) {
case tp_bool: return val->_bool; case tp_bool: return val->_bool;
case tp_int: return val->_i64 != 0; 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; py_Type t = val->type;
pk_TypeInfo* types = (pk_TypeInfo*)pk_current_vm->types.data; pk_TypeInfo* types = (pk_TypeInfo*)pk_current_vm->types.data;
do { do {
@ -61,13 +61,13 @@ bool py_hash(const py_Ref val, int64_t* out) {
return TypeError("unhashable type: '%t'", val->type); 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__); py_Ref tmp = py_tpfindmagic(val->type, __iter__);
if(!tmp) return TypeError("'%t' object is not iterable", val->type); if(!tmp) return TypeError("'%t' object is not iterable", val->type);
return py_call(tmp, 1, val); 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; pk_VM* vm = pk_current_vm;
vm->is_stopiteration = false; vm->is_stopiteration = false;
py_Ref tmp = py_tpfindmagic(val->type, __next__); 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); 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; py_Type type = self->type;
// handle super() proxy // handle super() proxy
if(py_istype(self, tp_super)) { if(py_istype(self, tp_super)) {
@ -175,7 +175,7 @@ bool py_delattr(py_Ref self, py_Name name) {
return TypeError("cannot delete attribute"); 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(self);
py_push(key); py_push(key);
bool ok = py_callmagic(__getitem__, 2, py_peek(-2)); 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; 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(self);
py_push(key); py_push(key);
py_push(val); py_push(val);
@ -192,7 +192,7 @@ bool py_setitem(py_Ref self, const py_Ref key, const py_Ref val) {
return ok; 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(self);
py_push(key); py_push(key);
bool ok = py_callmagic(__delitem__, 2, py_peek(-2)); 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; 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; if(!py_eq(lhs, rhs)) return -1;
return py_bool(py_retval()); 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; if(!py_lt(lhs, rhs)) return -1;
return py_bool(py_retval()); return py_bool(py_retval());
} }

View File

@ -31,26 +31,26 @@ unsigned char* py_newbytes(py_Ref out, int size) {
return ud->data; return ud->data;
} }
const char* py_tostr(const py_Ref self) { const char* py_tostr(py_Ref self) {
assert(self->type == tp_str); assert(self->type == tp_str);
c11_string* ud = PyObject__userdata(self->_obj); c11_string* ud = PyObject__userdata(self->_obj);
return ud->data; 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); assert(self->type == tp_str);
c11_string* ud = PyObject__userdata(self->_obj); c11_string* ud = PyObject__userdata(self->_obj);
*size = ud->size; *size = ud->size;
return ud->data; return ud->data;
} }
c11_sv py_tosv(const py_Ref self) { c11_sv py_tosv(py_Ref self) {
assert(self->type == tp_str); assert(self->type == tp_str);
c11_string* ud = PyObject__userdata(self->_obj); c11_string* ud = PyObject__userdata(self->_obj);
return c11_string__sv(ud); 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); assert(self->type == tp_bytes);
c11_bytes* ud = PyObject__userdata(self->_obj); c11_bytes* ud = PyObject__userdata(self->_obj);
*size = ud->size; *size = ud->size;

View File

@ -13,13 +13,13 @@ void py_newtuple(py_Ref out, int n) {
out->_obj = obj; 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) { 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; int length0, length1;
py_TValue* a0 = pk_arrayview(py_arg(0), &length0); py_TValue* a0 = pk_arrayview(py_arg(0), &length0);
py_TValue* a1 = pk_arrayview(py_arg(1), &length1); 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; if(res == -1) return false;
py_newbool(py_retval(), res); py_newbool(py_retval(), res);
} else { } else {
@ -126,6 +126,11 @@ static bool _py_tuple__iter__(int argc, py_Ref argv) {
return pk_arrayiter(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 pk_tuple__register() {
py_Type type = pk_newtype("tuple", tp_object, NULL, NULL, false, true); 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, __eq__, _py_tuple__eq__);
py_bindmagic(type, __ne__, _py_tuple__ne__); py_bindmagic(type, __ne__, _py_tuple__ne__);
py_bindmagic(type, __iter__, _py_tuple__iter__); py_bindmagic(type, __iter__, _py_tuple__iter__);
py_bindmagic(type, __contains__, _py_tuple__contains__);
return type; return type;
} }

View File

@ -6,7 +6,7 @@
py_Ref py_reg(int i) { return pk_current_vm->reg + i; } 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); assert(self && self->is_ptr);
if(!py_ismagicname(name) || self->type != tp_type) { if(!py_ismagicname(name) || self->type != tp_type) {
return pk_NameDict__try_get(PyObject__dict(self->_obj), name); 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); assert(self && self->is_ptr);
if(!py_ismagicname(name) || self->type != tp_type) { if(!py_ismagicname(name) || self->type != tp_type) {
pk_NameDict__set(PyObject__dict(self->_obj), name, *val); 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(self && self->is_ptr);
assert(i >= 0 && i < self->_obj->slots); assert(i >= 0 && i < self->_obj->slots);
return PyObject__slots(self->_obj) + i; 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(self && self->is_ptr);
assert(i >= 0 && i < self->_obj->slots); assert(i >= 0 && i < self->_obj->slots);
PyObject__slots(self->_obj)[i] = *val; 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 */ /* Stack References */
py_Ref py_peek(int i) { py_Ref py_peek(int i) {
@ -69,7 +69,7 @@ void py_shrink(int n) {
vm->stack.sp -= n; vm->stack.sp -= n;
} }
void py_push(const py_Ref src) { void py_push(py_Ref src) {
pk_VM* vm = pk_current_vm; pk_VM* vm = pk_current_vm;
*vm->stack.sp++ = *src; *vm->stack.sp++ = *src;
} }

View File

@ -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([1, [2, [3, 4]], 5]) == "[1, [2, [3, 4]], 5]"
assert repr([]) == "[]" assert repr([]) == "[]"
# b = [(1, 2), (3, 3), (5, 1)] # test in and not in
# b.sort(key=lambda x:x[1]) assert 1 in [1, 2, 3]
# assert b == [(5, 1), (1, 2), (3,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 # test cyclic reference
# a = [] # a = []

View File

@ -31,3 +31,7 @@ assert repr((1,)) == '(1,)'
assert repr((1,2,)) == '(1, 2)' assert repr((1,2,)) == '(1, 2)'
assert repr((1,2,(3,4))) == '(1, 2, (3, 4))' assert repr((1,2,(3,4))) == '(1, 2, (3, 4))'
assert repr(tuple()) == '()' assert repr(tuple()) == '()'
# test in and not in
assert 1 in (1, 2, 3)
assert 4 not in (1, 2, 3)