From 29aa3e5eede933aea1f2af96a886e4aeca5fd5e5 Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Sun, 7 Jul 2024 03:27:07 +0800 Subject: [PATCH] some fix --- include/pocketpy/interpreter/vm.h | 1 + include/pocketpy/pocketpy.h | 14 ++++- src/interpreter/vm.c | 1 + src/public/py_list.c | 27 +++++++++ src/public/py_ops.c | 18 ++++++ src/public/py_str.c | 91 ++++++++++++++++++++++++++++++- src/public/vm.c | 8 ++- tests/04_str.py | 16 +++--- 8 files changed, 164 insertions(+), 12 deletions(-) diff --git a/include/pocketpy/interpreter/vm.h b/include/pocketpy/interpreter/vm.h index 23ef009c..c5fd7fb2 100644 --- a/include/pocketpy/interpreter/vm.h +++ b/include/pocketpy/interpreter/vm.h @@ -96,6 +96,7 @@ const char* pk_opname(Opcode op); void pk_object__register(); void pk_number__register(); py_Type pk_str__register(); +py_Type pk_str_iterator__register(); py_Type pk_bytes__register(); py_Type pk_list__register(); py_Type pk_function__register(); diff --git a/include/pocketpy/pocketpy.h b/include/pocketpy/pocketpy.h index db3ec960..d008fad7 100644 --- a/include/pocketpy/pocketpy.h +++ b/include/pocketpy/pocketpy.h @@ -244,6 +244,8 @@ void py_formatexc(char* out); #define TypeError(...) py_exception("TypeError", __VA_ARGS__) #define ValueError(...) py_exception("ValueError", __VA_ARGS__) #define IndexError(...) py_exception("IndexError", __VA_ARGS__) +#define StopIteration() py_exception("StopIteration", "") +#define NotImplementedError() py_exception("NotImplementedError", "") #define AttributeError(self, n) \ py_exception("AttributeError", "'%t' object has no attribute '%n'", (self)->type, (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); +/// 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`. bool py_isidentical(const py_Ref, const py_Ref); @@ -332,6 +340,9 @@ py_GlobalRef py_tpobject(py_Type type); /// Get the type name. 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. bool py_checktype(const py_Ref self, py_Type type); @@ -369,6 +380,7 @@ enum py_PredefinedTypes { tp_float, tp_bool, tp_str, + tp_str_iterator, tp_list, // c11_vector tp_tuple, // N slots tp_slice, // 3 slots (start, stop, step) @@ -390,7 +402,7 @@ enum py_PredefinedTypes { tp_not_implemented_type, tp_ellipsis, tp_syntax_error, - tp_stop_iteration + tp_stop_iteration, }; #ifdef __cplusplus diff --git a/src/interpreter/vm.c b/src/interpreter/vm.c index db7ab432..da5fe077 100644 --- a/src/interpreter/vm.c +++ b/src/interpreter/vm.c @@ -96,6 +96,7 @@ void pk_VM__ctor(pk_VM* self) { pk_number__register(); validate(tp_str, pk_str__register()); + validate(tp_str_iterator, pk_str_iterator__register()); validate(tp_list, pk_list__register()); validate(tp_tuple, pk_VM__new_type(self, "tuple", tp_object, NULL, false)); diff --git a/src/public/py_list.c b/src/public/py_list.c index 1c97f467..1ae0c17a 100644 --- a/src/public/py_list.c +++ b/src/public/py_list.c @@ -101,6 +101,32 @@ static bool _py_list__ne__(int argc, py_Ref argv) { 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() { pk_VM* vm = pk_current_vm; 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, __eq__, _py_list__eq__); py_bindmagic(type, __ne__, _py_list__ne__); + py_bindmagic(type, __new__, _py_list__new__); return type; } \ No newline at end of file diff --git a/src/public/py_ops.c b/src/public/py_ops.c index 759514cb..13a5cfc0 100644 --- a/src/public/py_ops.c +++ b/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); } +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; } bool py_setattr(py_Ref self, py_Name name, const py_Ref val) { return false; } diff --git a/src/public/py_str.c b/src/public/py_str.c index ea4bdaac..d53f20d7 100644 --- a/src/public/py_str.c +++ b/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) { 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) { @@ -391,6 +390,52 @@ static bool _py_str__zfill(int argc, py_Ref argv) { 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() { pk_VM* vm = pk_current_vm; 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, "rstrip", _py_str__rstrip); 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; } diff --git a/src/public/vm.c b/src/public/vm.c index 94673095..c8e7ae7e 100644 --- a/src/public/vm.c +++ b/src/public/vm.c @@ -197,7 +197,9 @@ bool py_call(py_Ref f, int argc, py_Ref argv) { py_pushnil(); for(int i = 0; i < argc; 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); } +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) { assert(argc >= 1); assert(py_ismagicname(name)); diff --git a/tests/04_str.py b/tests/04_str.py index 14e1efaa..de293689 100644 --- a/tests/04_str.py +++ b/tests/04_str.py @@ -116,14 +116,6 @@ assert a[2:5:2] == "lo" assert a[5:2:-1] == ",ol" 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' assert a.rjust(5) == ' 123' assert a.rjust(5, '0') == '00123' @@ -134,6 +126,14 @@ assert '\x30\x31\x32' == '012' assert '\b\b\b' == '\x08\x08\x08' 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'