blueloveTH 1 年之前
父節點
當前提交
29aa3e5eed
共有 8 個文件被更改,包括 164 次插入12 次删除
  1. 1 0
      include/pocketpy/interpreter/vm.h
  2. 13 1
      include/pocketpy/pocketpy.h
  3. 1 0
      src/interpreter/vm.c
  4. 27 0
      src/public/py_list.c
  5. 18 0
      src/public/py_ops.c
  6. 89 2
      src/public/py_str.c
  7. 7 1
      src/public/vm.c
  8. 8 8
      tests/04_str.py

+ 1 - 0
include/pocketpy/interpreter/vm.h

@@ -96,6 +96,7 @@ const char* pk_opname(Opcode op);
 void pk_object__register();
 void pk_object__register();
 void pk_number__register();
 void pk_number__register();
 py_Type pk_str__register();
 py_Type pk_str__register();
+py_Type pk_str_iterator__register();
 py_Type pk_bytes__register();
 py_Type pk_bytes__register();
 py_Type pk_list__register();
 py_Type pk_list__register();
 py_Type pk_function__register();
 py_Type pk_function__register();

+ 13 - 1
include/pocketpy/pocketpy.h

@@ -244,6 +244,8 @@ void py_formatexc(char* out);
 #define TypeError(...) py_exception("TypeError", __VA_ARGS__)
 #define TypeError(...) py_exception("TypeError", __VA_ARGS__)
 #define ValueError(...) py_exception("ValueError", __VA_ARGS__)
 #define ValueError(...) py_exception("ValueError", __VA_ARGS__)
 #define IndexError(...) py_exception("IndexError", __VA_ARGS__)
 #define IndexError(...) py_exception("IndexError", __VA_ARGS__)
+#define StopIteration() py_exception("StopIteration", "")
+#define NotImplementedError() py_exception("NotImplementedError", "")
 #define AttributeError(self, n)                                                                    \
 #define AttributeError(self, n)                                                                    \
     py_exception("AttributeError", "'%t' object has no attribute '%n'", (self)->type, (n))
     py_exception("AttributeError", "'%t' object has no attribute '%n'", (self)->type, (n))
 #define UnboundLocalError(n)                                                                       \
 #define UnboundLocalError(n)                                                                       \
@@ -264,6 +266,12 @@ int py_gt(const py_Ref, const py_Ref);
 
 
 bool py_hash(const py_Ref, py_i64* out);
 bool py_hash(const py_Ref, py_i64* out);
 
 
+/// Get the iterator of the object.
+bool py_iter(const py_Ref);
+/// Get the next element from the iterator.
+/// 1: success, 0: StopIteration, -1: error
+int py_next(const 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(const py_Ref, const py_Ref);
 
 
@@ -332,6 +340,9 @@ py_GlobalRef py_tpobject(py_Type type);
 /// Get the type name.
 /// Get the type name.
 const char* py_tpname(py_Type type);
 const char* py_tpname(py_Type type);
 
 
+/// Call a type to create a new instance.
+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(const py_Ref self, py_Type type);
 
 
@@ -369,6 +380,7 @@ enum py_PredefinedTypes {
     tp_float,
     tp_float,
     tp_bool,
     tp_bool,
     tp_str,
     tp_str,
+    tp_str_iterator,
     tp_list,   // c11_vector
     tp_list,   // c11_vector
     tp_tuple,  // N slots
     tp_tuple,  // N slots
     tp_slice,  // 3 slots (start, stop, step)
     tp_slice,  // 3 slots (start, stop, step)
@@ -390,7 +402,7 @@ enum py_PredefinedTypes {
     tp_not_implemented_type,
     tp_not_implemented_type,
     tp_ellipsis,
     tp_ellipsis,
     tp_syntax_error,
     tp_syntax_error,
-    tp_stop_iteration
+    tp_stop_iteration,
 };
 };
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus

+ 1 - 0
src/interpreter/vm.c

@@ -96,6 +96,7 @@ void pk_VM__ctor(pk_VM* self) {
     pk_number__register();
     pk_number__register();
 
 
     validate(tp_str, pk_str__register());
     validate(tp_str, pk_str__register());
+    validate(tp_str_iterator, pk_str_iterator__register());
 
 
     validate(tp_list, pk_list__register());
     validate(tp_list, pk_list__register());
     validate(tp_tuple, pk_VM__new_type(self, "tuple", tp_object, NULL, false));
     validate(tp_tuple, pk_VM__new_type(self, "tuple", tp_object, NULL, false));

+ 27 - 0
src/public/py_list.c

@@ -101,6 +101,32 @@ static bool _py_list__ne__(int argc, py_Ref argv) {
     return true;
     return true;
 }
 }
 
 
+static bool _py_list__new__(int argc, py_Ref argv) {
+    if(argc == 1) {
+        py_newlist(py_retval());
+        return true;
+    }
+    if(argc == 2) {
+        py_Ref iter = py_pushtmp();
+        py_Ref list = py_pushtmp();
+        if(!py_iter(py_arg(1))) return false;
+        *iter = *py_retval();
+        py_newlist(list);
+        while(true) {
+            int res = py_next(iter);
+            if(res == -1) return false;
+            if(res) {
+                py_list__append(list, py_retval());
+            } else {
+                break;
+            }
+        }
+        *py_retval() = *list;
+        return true;
+    }
+    return TypeError("list() takes at most 1 argument");
+}
+
 py_Type pk_list__register() {
 py_Type pk_list__register() {
     pk_VM* vm = pk_current_vm;
     pk_VM* vm = pk_current_vm;
     py_Type type = pk_VM__new_type(vm, "list", tp_object, NULL, false);
     py_Type type = pk_VM__new_type(vm, "list", tp_object, NULL, false);
@@ -110,5 +136,6 @@ py_Type pk_list__register() {
     py_bindmagic(type, __len__, _py_list__len__);
     py_bindmagic(type, __len__, _py_list__len__);
     py_bindmagic(type, __eq__, _py_list__eq__);
     py_bindmagic(type, __eq__, _py_list__eq__);
     py_bindmagic(type, __ne__, _py_list__ne__);
     py_bindmagic(type, __ne__, _py_list__ne__);
+    py_bindmagic(type, __new__, _py_list__new__);
     return type;
     return type;
 }
 }

+ 18 - 0
src/public/py_ops.c

@@ -60,6 +60,24 @@ 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) {
+    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) {
+    py_Ref tmp = py_tpfindmagic(val->type, __next__);
+    if(!tmp) return TypeError("'%t' object is not an iterator", val->type);
+    bool ok = py_call(tmp, 1, val);
+    if(ok) {
+        py_Ref retval = py_retval();
+        bool is_end = retval->type == tp_type && py_totype(retval) == tp_stop_iteration;
+        return !is_end;
+    }
+    return -1;
+}
+
 int py_getattr(const py_Ref self, py_Name name, py_Ref out) { return -1; }
 int py_getattr(const py_Ref self, py_Name name, py_Ref out) { return -1; }
 
 
 bool py_setattr(py_Ref self, py_Name name, const py_Ref val) { return false; }
 bool py_setattr(py_Ref self, py_Name name, const py_Ref val) { return false; }

+ 89 - 2
src/public/py_str.c

@@ -158,8 +158,7 @@ static bool _py_str__repr__(int argc, py_Ref argv) {
 
 
 static bool _py_str__iter__(int argc, py_Ref argv) {
 static bool _py_str__iter__(int argc, py_Ref argv) {
     PY_CHECK_ARGC(1);
     PY_CHECK_ARGC(1);
-    assert(false);
-    return false;
+    return py_tpcall(tp_str_iterator, 1, argv);
 }
 }
 
 
 static bool _py_str__getitem__(int argc, py_Ref argv) {
 static bool _py_str__getitem__(int argc, py_Ref argv) {
@@ -391,6 +390,52 @@ static bool _py_str__zfill(int argc, py_Ref argv) {
     return true;
     return true;
 }
 }
 
 
+static bool _py_str__widthjust_impl(bool left, int argc, py_Ref argv) {
+    if(argc > 1 + 2) return TypeError("expected at most 2 arguments");
+    char pad;
+    if(argc == 1 + 1) {
+        pad = ' ';
+    } else {
+        if(!py_checkstr(&argv[2])) return false;
+        c11_string* padstr = py_touserdata(&argv[2]);
+        if(padstr->size != 1)
+            return TypeError("The fill character must be exactly one character long");
+        pad = padstr->data[0];
+    }
+    c11_sv self = c11_string__sv(py_touserdata(&argv[0]));
+    PY_CHECK_ARG_TYPE(1, tp_int);
+    int width = py_toint(py_arg(1));
+    if(width <= self.size) {
+        *py_retval() = argv[0];
+        return true;
+    }
+    c11_sbuf buf;
+    c11_sbuf__ctor(&buf);
+    if(left) {
+        c11_sbuf__write_sv(&buf, self);
+        for(int i = 0; i < width - self.size; i++) {
+            c11_sbuf__write_char(&buf, pad);
+        }
+    } else {
+        for(int i = 0; i < width - self.size; i++) {
+            c11_sbuf__write_char(&buf, pad);
+        }
+        c11_sbuf__write_sv(&buf, self);
+    }
+    c11_string* res = c11_sbuf__submit(&buf);
+    py_newstrn(py_retval(), res->data, res->size);
+    c11_string__delete(res);
+    return true;
+}
+
+static bool _py_str__ljust(int argc, py_Ref argv) {
+    return _py_str__widthjust_impl(true, argc, argv);
+}
+
+static bool _py_str__rjust(int argc, py_Ref argv) {
+    return _py_str__widthjust_impl(false, argc, argv);
+}
+
 py_Type pk_str__register() {
 py_Type pk_str__register() {
     pk_VM* vm = pk_current_vm;
     pk_VM* vm = pk_current_vm;
     py_Type type = pk_VM__new_type(vm, "str", tp_object, NULL, false);
     py_Type type = pk_VM__new_type(vm, "str", tp_object, NULL, false);
@@ -427,6 +472,48 @@ py_Type pk_str__register() {
     py_bindmethod(tp_str, "lstrip", _py_str__lstrip);
     py_bindmethod(tp_str, "lstrip", _py_str__lstrip);
     py_bindmethod(tp_str, "rstrip", _py_str__rstrip);
     py_bindmethod(tp_str, "rstrip", _py_str__rstrip);
     py_bindmethod(tp_str, "zfill", _py_str__zfill);
     py_bindmethod(tp_str, "zfill", _py_str__zfill);
+    py_bindmethod(tp_str, "ljust", _py_str__ljust);
+    py_bindmethod(tp_str, "rjust", _py_str__rjust);
+    return type;
+}
+
+static bool _py_str_iterator__new__(int argc, py_Ref argv) {
+    PY_CHECK_ARGC(2);
+    PY_CHECK_ARG_TYPE(1, tp_str);
+    int* ud = py_newobject(py_retval(), tp_str_iterator, 1, sizeof(int));
+    *ud = 0;
+    py_setslot(py_retval(), 0, &argv[1]);
+    return true;
+}
+
+static bool _py_str_iterator__iter__(int argc, py_Ref argv) {
+    PY_CHECK_ARGC(1);
+    *py_retval() = argv[0];
+    return true;
+}
+
+static bool _py_str_iterator__next__(int argc, py_Ref argv) {
+    PY_CHECK_ARGC(1);
+    int* ud = py_touserdata(&argv[0]);
+    int size;
+    const char* data = py_tostrn(py_getslot(argv, 0), &size);
+    if(*ud == size) {
+        *py_retval() = pk_current_vm->StopIteration;
+        return true;
+    }
+    int start = *ud;
+    int len = c11__u8_header(data[*ud], false);
+    *ud += len;
+    py_newstrn(py_retval(), data + start, len);
+    return true;
+}
+
+py_Type pk_str_iterator__register() {
+    pk_VM* vm = pk_current_vm;
+    py_Type type = pk_VM__new_type(vm, "str_iterator", tp_object, NULL, false);
+    py_bindmagic(type, __new__, _py_str_iterator__new__);
+    py_bindmagic(type, __iter__, _py_str_iterator__iter__);
+    py_bindmagic(type, __next__, _py_str_iterator__next__);
     return type;
     return type;
 }
 }
 
 

+ 7 - 1
src/public/vm.c

@@ -197,7 +197,9 @@ bool py_call(py_Ref f, int argc, py_Ref argv) {
         py_pushnil();
         py_pushnil();
         for(int i = 0; i < argc; i++)
         for(int i = 0; i < argc; i++)
             py_push(py_offset(argv, i));
             py_push(py_offset(argv, i));
-        return pk_VM__vectorcall(vm, argc, 0, false) == RES_ERROR;
+        pk_FrameResult res = pk_VM__vectorcall(vm, argc, 0, false);
+        assert(res == RES_ERROR || res == RES_RETURN);
+        return res == RES_RETURN;
     }
     }
 }
 }
 
 
@@ -292,6 +294,10 @@ const char* py_tpname(py_Type type) {
     return py_name2str(name);
     return py_name2str(name);
 }
 }
 
 
+bool py_tpcall(py_Type type, int argc, py_Ref argv){
+    return py_call(py_tpobject(type), argc, argv);
+}
+
 bool py_callmagic(py_Name name, int argc, py_Ref argv) {
 bool py_callmagic(py_Name name, int argc, py_Ref argv) {
     assert(argc >= 1);
     assert(argc >= 1);
     assert(py_ismagicname(name));
     assert(py_ismagicname(name));

+ 8 - 8
tests/04_str.py

@@ -116,14 +116,6 @@ assert a[2:5:2] == "lo"
 assert a[5:2:-1] == ",ol"
 assert a[5:2:-1] == ",ol"
 assert a[5:2:-2] == ",l"
 assert a[5:2:-2] == ",l"
 
 
-b = list(a)
-assert b == ['H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!']
-assert b[::-1] == ['!', 'd', 'l', 'r', 'o', 'W', ' ', ',', 'o', 'l', 'l', 'e', 'H']
-assert b[::2] == ['H', 'l', 'o', ' ', 'o', 'l', '!']
-assert b[2:5:2] == ['l', 'o']
-assert b[5:2:-1] == [',', 'o', 'l']
-assert b[5:2:-2] == [',', 'l']
-
 a = '123'
 a = '123'
 assert a.rjust(5) == '  123'
 assert a.rjust(5) == '  123'
 assert a.rjust(5, '0') == '00123'
 assert a.rjust(5, '0') == '00123'
@@ -134,6 +126,14 @@ assert '\x30\x31\x32' == '012'
 assert '\b\b\b' == '\x08\x08\x08'
 assert '\b\b\b' == '\x08\x08\x08'
 assert repr('\x1f\x1e\x1f') == '\'\\x1f\\x1e\\x1f\''
 assert repr('\x1f\x1e\x1f') == '\'\\x1f\\x1e\\x1f\''
 
 
+b = list("Hello, World!")
+assert b == ['H', 'e', 'l', 'l', 'o', ',', ' ', 'W', 'o', 'r', 'l', 'd', '!']
+assert b[::-1] == ['!', 'd', 'l', 'r', 'o', 'W', ' ', ',', 'o', 'l', 'l', 'e', 'H']
+assert b[::2] == ['H', 'l', 'o', ' ', 'o', 'l', '!']
+assert b[2:5:2] == ['l', 'o']
+assert b[5:2:-1] == [',', 'o', 'l']
+assert b[5:2:-2] == [',', 'l']
+
 assert hex(-42) == '-0x2a'
 assert hex(-42) == '-0x2a'
 assert hex(42) == '0x2a'
 assert hex(42) == '0x2a'