diff --git a/include/pocketpy/interpreter/vm.h b/include/pocketpy/interpreter/vm.h index b2d107c0..33e79713 100644 --- a/include/pocketpy/interpreter/vm.h +++ b/include/pocketpy/interpreter/vm.h @@ -108,6 +108,8 @@ py_Type pk_str_iterator__register(); py_Type pk_bytes__register(); py_Type pk_list__register(); py_Type pk_tuple__register(); +py_Type pk_array_iterator__register(); +py_Type pk_slice__register(); py_Type pk_function__register(); py_Type pk_nativefunc__register(); py_Type pk_range__register(); diff --git a/include/pocketpy/pocketpy.h b/include/pocketpy/pocketpy.h index b42b2897..bebe6815 100644 --- a/include/pocketpy/pocketpy.h +++ b/include/pocketpy/pocketpy.h @@ -88,7 +88,7 @@ bool py_ismagicname(py_Name); // opaque types void py_newdict(py_Ref); void py_newset(py_Ref); -void py_newslice(py_Ref, const py_Ref start, const py_Ref stop, const py_Ref step); +void py_newslice(py_Ref); // old style argc-based function void py_newnativefunc(py_Ref out, py_CFunction); @@ -400,6 +400,7 @@ enum py_PredefinedTypes { tp_str_iterator, tp_list, // c11_vector tp_tuple, // N slots + tp_array_iterator, tp_slice, // 3 slots (start, stop, step) tp_range, tp_range_iterator, diff --git a/src/interpreter/ceval.c b/src/interpreter/ceval.c index 4ed88457..ae9332a6 100644 --- a/src/interpreter/ceval.c +++ b/src/interpreter/ceval.c @@ -531,7 +531,10 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) { case OP_BUILD_SLICE: { // [start, stop, step] py_TValue tmp; - py_newslice(&tmp, THIRD(), SECOND(), TOP()); + py_newslice(&tmp); + py_setslot(&tmp, 0, THIRD()); + py_setslot(&tmp, 1, SECOND()); + py_setslot(&tmp, 2, TOP()); STACK_SHRINK(3); PUSH(&tmp); DISPATCH(); diff --git a/src/interpreter/vm.c b/src/interpreter/vm.c index 01dc2e8f..1ac51238 100644 --- a/src/interpreter/vm.c +++ b/src/interpreter/vm.c @@ -100,8 +100,9 @@ void pk_VM__ctor(pk_VM* self) { validate(tp_list, pk_list__register()); validate(tp_tuple, pk_tuple__register()); + validate(tp_array_iterator, pk_array_iterator__register()); - validate(tp_slice, pk_VM__new_type(self, "slice", tp_object, NULL, false)); + validate(tp_slice, pk_slice__register()); validate(tp_range, pk_range__register()); validate(tp_range_iterator, pk_range_iterator__register()); validate(tp_module, pk_VM__new_type(self, "module", tp_object, NULL, false)); diff --git a/src/public/py_array.c b/src/public/py_array.c new file mode 100644 index 00000000..ebf6b3c8 --- /dev/null +++ b/src/public/py_array.c @@ -0,0 +1,75 @@ +#include "pocketpy/pocketpy.h" + +#include "pocketpy/common/utils.h" +#include "pocketpy/objects/object.h" +#include "pocketpy/interpreter/vm.h" +#include "pocketpy/common/sstream.h" + +typedef struct array_iterator { + py_TValue* p; + int length; + int index; +} array_iterator; + +py_TValue* pk_arrayview(py_Ref self, int* length) { + if(self->type == tp_list) { + *length = py_list__len(self); + return py_list__data(self); + } + if(self->type == tp_tuple) { + *length = py_tuple__len(self); + return PyObject__slots(self->_obj); + } + return NULL; +} + +int pk_arrayeq(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_eq(lhs + i, rhs + i); + if(res == -1) return -1; + if(!res) return false; + } + return true; +} + +static bool _py_array_iterator__new__(int argc, py_Ref argv) { + PY_CHECK_ARGC(2); + int length; + py_TValue* p = pk_arrayview(py_arg(1), &length); + if(!p) return TypeError("expected list or tuple, got %t", py_arg(1)->type); + array_iterator* ud = py_newobject(py_retval(), tp_array_iterator, 1, sizeof(array_iterator)); + ud->p = p; + ud->length = length; + ud->index = 0; + // keep a reference to the object + py_setslot(py_retval(), 0, py_arg(1)); + return true; +} + +static bool _py_array_iterator__iter__(int argc, py_Ref argv) { + PY_CHECK_ARGC(1); + *py_retval() = *argv; + return true; +} + +static bool _py_array_iterator__next__(int argc, py_Ref argv) { + PY_CHECK_ARGC(1); + array_iterator* ud = py_touserdata(argv); + if(ud->index < ud->length) { + *py_retval() = ud->p[ud->index++]; + return true; + } + return StopIteration(); +} + +py_Type pk_array_iterator__register() { + pk_VM* vm = pk_current_vm; + py_Type type = pk_VM__new_type(vm, "array_iterator", tp_object, NULL, false); + + py_bindmagic(type, __new__, _py_array_iterator__new__); + py_bindmagic(type, __iter__, _py_array_iterator__iter__); + py_bindmagic(type, __next__, _py_array_iterator__next__); + + return type; +} \ No newline at end of file diff --git a/src/public/py_list.c b/src/public/py_list.c index acd705f5..71546025 100644 --- a/src/public/py_list.c +++ b/src/public/py_list.c @@ -386,6 +386,11 @@ static bool _py_list__sort(int argc, py_Ref argv) { return true; } +static bool _py_list__iter__(int argc, py_Ref argv) { + PY_CHECK_ARGC(1); + return py_tpcall(tp_array_iterator, 1, argv); +} + py_Type pk_list__register() { pk_VM* vm = pk_current_vm; py_Type type = pk_VM__new_type(vm, "list", tp_object, NULL, false); @@ -403,6 +408,7 @@ py_Type pk_list__register() { py_bindmagic(type, __mul__, _py_list__mul__); py_bindmagic(type, __rmul__, _py_list__rmul__); py_bindmagic(type, __repr__, _py_list__repr__); + py_bindmagic(type, __iter__, _py_list__iter__); py_bindmethod(type, "append", _py_list__append); py_bindmethod(type, "extend", _py_list__extend); diff --git a/src/public/py_range.c b/src/public/py_range.c index 1c0be65b..891b9e17 100644 --- a/src/public/py_range.c +++ b/src/public/py_range.c @@ -35,9 +35,9 @@ static bool _py_range__new__(int argc, py_Ref argv) { ud->stop = py_toint(py_arg(2)); ud->step = py_toint(py_arg(3)); break; - default: return TypeError("range() expected at most 3 arguments, got %d", argc - 1); + default: return TypeError("range() expected at most 4 arguments, got %d", argc); } - if(ud->step == 0) return ValueError("range() arg 3 must not be zero"); + if(ud->step == 0) return ValueError("range() step must not be zero"); return true; } diff --git a/src/public/py_slice.c b/src/public/py_slice.c new file mode 100644 index 00000000..32602ca3 --- /dev/null +++ b/src/public/py_slice.c @@ -0,0 +1,55 @@ +#include "pocketpy/pocketpy.h" + +#include "pocketpy/common/utils.h" +#include "pocketpy/common/sstream.h" +#include "pocketpy/objects/object.h" +#include "pocketpy/interpreter/vm.h" + + +void py_newslice(py_Ref out){ + pk_VM* vm = pk_current_vm; + PyObject* obj = pk_ManagedHeap__gcnew(&vm->heap, tp_slice, 3, 0); + out->type = tp_slice; + out->is_ptr = true; + out->_obj = obj; +} + +static bool _py_slice__new__(int argc, py_Ref argv){ + PY_CHECK_ARGC(1+3); + py_Ref slice = py_retval(); + py_newslice(slice); + py_setslot(slice, 0, py_arg(1)); + py_setslot(slice, 1, py_arg(2)); + py_setslot(slice, 2, py_arg(3)); + return true; +} + +static bool _py_slice__repr__(int argc, py_Ref argv){ + c11_sbuf buf; + c11_sbuf__ctor(&buf); + c11_sbuf__write_cstr(&buf, "slice("); + for(int i = 0; i < 3; i++) { + py_TValue* val = py_getslot(argv, i); + bool ok = py_repr(val); + if(!ok) { + c11_sbuf__dtor(&buf); + return false; + } + c11_sbuf__write_sv(&buf, py_tosv(py_retval())); + if(i != 2) c11_sbuf__write_cstr(&buf, ", "); + } + c11_sbuf__write_char(&buf, ')'); + c11_string* res = c11_sbuf__submit(&buf); + py_newstrn(py_retval(), res->data, res->size); + c11_string__delete(res); + return true; +} + +py_Type pk_slice__register(){ + pk_VM* vm = pk_current_vm; + py_Type type = pk_VM__new_type(vm, "slice", tp_object, NULL, false); + + py_bindmagic(type, __new__, _py_slice__new__); + py_bindmagic(type, __repr__, _py_slice__repr__); + return type; +} \ No newline at end of file diff --git a/src/public/py_str.c b/src/public/py_str.c index c129cb1c..818243f9 100644 --- a/src/public/py_str.c +++ b/src/public/py_str.c @@ -44,6 +44,12 @@ const char* py_tostrn(const py_Ref self, int* size) { return ud->data; } +c11_sv py_tosv(const 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) { assert(self->type == tp_bytes); c11_bytes* ud = PyObject__userdata(self->_obj); diff --git a/src/public/py_tuple.c b/src/public/py_tuple.c index 87c05409..8aeef3b4 100644 --- a/src/public/py_tuple.c +++ b/src/public/py_tuple.c @@ -120,6 +120,11 @@ static bool _py_tuple__ne__(int argc, py_Ref argv) { return true; } +static bool _py_tuple__iter__(int argc, py_Ref argv) { + PY_CHECK_ARGC(1); + return py_tpcall(tp_array_iterator, 1, argv); +} + py_Type pk_tuple__register() { pk_VM* vm = pk_current_vm; py_Type type = pk_VM__new_type(vm, "tuple", tp_object, NULL, false); @@ -130,5 +135,6 @@ py_Type pk_tuple__register() { py_bindmagic(type, __getitem__, _py_tuple__getitem__); py_bindmagic(type, __eq__, _py_tuple__eq__); py_bindmagic(type, __ne__, _py_tuple__ne__); + py_bindmagic(type, __iter__, _py_tuple__iter__); return type; } diff --git a/src/public/values.c b/src/public/values.c index abbb0d3d..ed40a3e7 100644 --- a/src/public/values.c +++ b/src/public/values.c @@ -88,13 +88,6 @@ void py_bind(py_Ref obj, const char* sig, py_CFunction f) { py_setdict(obj, name, &tmp); } -void py_newslice(py_Ref out, const py_Ref start, const py_Ref stop, const py_Ref step) { - py_newobject(out, tp_slice, 3, 0); - py_setslot(out, 0, start); - py_setslot(out, 1, stop); - py_setslot(out, 2, step); -} - void* py_newobject(py_Ref out, py_Type type, int slots, int udsize) { pk_ManagedHeap* heap = &pk_current_vm->heap; PyObject* obj = pk_ManagedHeap__gcnew(heap, type, slots, udsize); diff --git a/src/public/vm.c b/src/public/vm.c index af9f5cd1..779d26e2 100644 --- a/src/public/vm.c +++ b/src/public/vm.c @@ -35,28 +35,6 @@ const char* pk_opname(Opcode op) { return OP_NAMES[op]; } -py_TValue* pk_arrayview(py_Ref self, int* length) { - if(self->type == tp_list) { - *length = py_list__len(self); - return py_list__data(self); - } - if(self->type == tp_tuple) { - *length = py_tuple__len(self); - return PyObject__slots(self->_obj); - } - return NULL; -} - -int pk_arrayeq(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_eq(lhs + i, rhs + i); - if(res == -1) return -1; - if(!res) return false; - } - return true; -} - static void disassemble(CodeObject* co) { c11_vector /*T=int*/ jumpTargets; c11_vector__ctor(&jumpTargets, sizeof(int));