blueloveTH 1 year ago
parent
commit
40d6f1a19f

+ 2 - 0
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();

+ 2 - 1
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,

+ 4 - 1
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();

+ 2 - 1
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));

+ 75 - 0
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;
+}

+ 6 - 0
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);

+ 2 - 2
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;
 }
 

+ 55 - 0
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;
+}

+ 6 - 0
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);

+ 6 - 0
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;
 }

+ 0 - 7
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);

+ 0 - 22
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));