This commit is contained in:
blueloveTH 2024-07-07 23:51:48 +08:00
parent a81563768d
commit 140255650d
11 changed files with 260 additions and 76 deletions

View File

@ -93,6 +93,7 @@ pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t argc, uint16_t kwargc, bo
const char* pk_opname(Opcode op);
py_TValue* pk_arrayview(py_Ref self, int* length);
int pk_arrayeq(py_TValue* lhs, int lhs_length, py_TValue* rhs, int rhs_length);
/// Assumes [a, b] are on the stack, performs a binary op.
/// The result is stored in `self->last_retval`.
@ -106,6 +107,7 @@ py_Type pk_str__register();
py_Type pk_str_iterator__register();
py_Type pk_bytes__register();
py_Type pk_list__register();
py_Type pk_tuple__register();
py_Type pk_function__register();
py_Type pk_nativefunc__register();
py_Type pk_range__register();

View File

@ -33,8 +33,10 @@ def test_dir(path):
else:
if not test_file(filepath):
print('-' * 50)
print("TEST FAILED! Press any key to continue...")
input()
print("TEST FAILED!")
exit(1)
# print("TEST FAILED! Press any key to continue...")
# input()
print('CPython:', str(sys.version).replace('\n', ''))
print('System:', '64-bit' if sys.maxsize > 2**32 else '32-bit')

View File

@ -179,10 +179,16 @@ bool StarredExpr__emit_store(Expr* self_, Ctx* ctx) {
return vtemit_store(self->child, ctx);
}
void StarredExpr__dtor(Expr* self_) {
StarredExpr* self = (StarredExpr*)self_;
vtdelete(self->child);
}
StarredExpr* StarredExpr__new(int line, Expr* child, int level) {
const static ExprVt Vt = {.emit_ = StarredExpr__emit_,
.emit_store = StarredExpr__emit_store,
.is_starred = true};
.is_starred = true,
.dtor = StarredExpr__dtor};
static_assert_expr_size(StarredExpr);
StarredExpr* self = PoolExpr_alloc();
self->vt = &Vt;

View File

@ -98,7 +98,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
break;
}
case tp_tuple: {
pk_sprintf(&buf, "tuple(%d)", py_list__len(p));
pk_sprintf(&buf, "tuple(%d)", py_tuple__len(p));
break;
}
case tp_function: {
@ -313,14 +313,15 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
py_Ref magic = py_tpfindmagic(SECOND()->type, __getitem__);
if(magic) {
if(magic->type == tp_nativefunc) {
py_TValue* next_sp = TOP();
bool ok = magic->_cfunc(2, SECOND());
if(!ok) goto __ERROR;
POP();
SP() = next_sp;
*TOP() = self->last_retval;
} else {
INSERT_THIRD(); // [?, a, b]
*THIRD() = *magic; // [__getitem__, a, b]
vectorcall_opcall(2, 0);
vectorcall_opcall(1, 0);
}
DISPATCH();
}
@ -366,14 +367,14 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
py_Ref magic = py_tpfindmagic(SECOND()->type, __setitem__);
if(magic) {
if(magic->type == tp_nativefunc) {
py_TValue* next_sp = THIRD();
bool ok = magic->_cfunc(3, THIRD());
if(!ok) goto __ERROR;
STACK_SHRINK(3);
SP() = next_sp;
*TOP() = self->last_retval;
} else {
INSERT_THIRD(); // [?, a, b]
*FOURTH() = *magic; // [__selitem__, a, b, val]
vectorcall_opcall(3, 0);
vectorcall_opcall(2, 0);
POP(); // discard retval
}
DISPATCH();
@ -437,13 +438,14 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
py_Ref magic = py_tpfindmagic(SECOND()->type, __delitem__);
if(magic) {
if(magic->type == tp_nativefunc) {
py_TValue* next_sp = SECOND();
bool ok = magic->_cfunc(2, SECOND());
if(!ok) goto __ERROR;
STACK_SHRINK(2);
SP() = next_sp;
} else {
INSERT_THIRD(); // [?, a, b]
*THIRD() = *magic; // [__delitem__, a, b]
vectorcall_opcall(2, 0);
vectorcall_opcall(1, 0);
POP(); // discard retval
}
DISPATCH();
@ -567,18 +569,19 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
DISPATCH();
}
case OP_CONTAINS_OP: {
// [b, a] -> b __contains__ a (a in b)
// [b, a] -> b __contains__ a (a in b) -> [retval]
py_Ref magic = py_tpfindmagic(SECOND()->type, __contains__);
if(magic) {
if(magic->type == tp_nativefunc) {
py_TValue* next_sp = TOP();
bool ok = magic->_cfunc(2, SECOND());
if(!ok) goto __ERROR;
POP();
SP() = next_sp;
*TOP() = self->last_retval;
} else {
INSERT_THIRD(); // [?, b, a]
*THIRD() = *magic; // [__contains__, a, b]
vectorcall_opcall(2, 0);
vectorcall_opcall(1, 0);
}
bool res = py_tobool(TOP());
if(byte.arg) py_newbool(TOP(), !res);
@ -713,6 +716,28 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
if(!stack_unpack_sequence(self, byte.arg)) goto __ERROR;
DISPATCH();
}
case OP_UNPACK_EX: {
int length;
py_TValue* p = pk_arrayview(TOP(), &length);
if(!p) {
TypeError("expected list or tuple to unpack, got '%t'", TOP()->type);
goto __ERROR;
}
int exceed = length - byte.arg;
if(exceed < 0) {
ValueError("not enough values to unpack");
goto __ERROR;
}
POP();
for(int i = 0; i < byte.arg; i++) {
PUSH(p + i);
}
py_newlistn(SP()++, exceed);
for(int i = 0; i < exceed; i++) {
py_list__setitem(TOP(), i, p + byte.arg + i);
}
DISPATCH();
}
///////////
case OP_RAISE_ASSERT: {
@ -781,7 +806,8 @@ static bool stack_unpack_sequence(pk_VM* self, uint16_t arg) {
if(!p) return TypeError("expected list or tuple to unpack, got '%t'", TOP()->type);
if(length != arg) return ValueError("expected %d values to unpack, got %d", arg, length);
POP();
for(int i = 0; i < length; i++)
for(int i = 0; i < length; i++) {
PUSH(p + i);
}
return true;
}

View File

@ -99,7 +99,7 @@ void pk_VM__ctor(pk_VM* self) {
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));
validate(tp_tuple, pk_tuple__register());
validate(tp_slice, pk_VM__new_type(self, "slice", tp_object, NULL, false));
validate(tp_range, pk_range__register());

View File

@ -3,6 +3,7 @@
#include "pocketpy/common/utils.h"
#include "pocketpy/objects/object.h"
#include "pocketpy/interpreter/vm.h"
#include "pocketpy/common/sstream.h"
typedef c11_vector List;
@ -68,25 +69,13 @@ static bool _py_list__len__(int argc, py_Ref argv) {
static bool _py_list__eq__(int argc, py_Ref argv) {
PY_CHECK_ARGC(2);
py_Ref _0 = py_arg(0);
py_Ref _1 = py_arg(1);
if(py_istype(_1, tp_list)) {
int length = py_list__len(_0);
if(length != py_list__len(_1)) {
py_newbool(py_retval(), false);
return true;
}
for(int i = 0; i < length; i++) {
py_Ref a = py_list__getitem(_0, i);
py_Ref b = py_list__getitem(_1, i);
int res = py_eq(a, b);
if(py_istype(py_arg(1), tp_list)) {
int length0, length1;
py_TValue* a0 = pk_arrayview(py_arg(0), &length0);
py_TValue* a1 = pk_arrayview(py_arg(1), &length1);
int res = pk_arrayeq(a0, length0, a1, length1);
if(res == -1) return false;
if(res == 0) {
py_newbool(py_retval(), false);
return true;
}
}
py_newbool(py_retval(), true);
py_newbool(py_retval(), res);
} else {
py_newnotimplemented(py_retval());
}
@ -225,6 +214,30 @@ static bool _py_list__append(int argc, py_Ref argv) {
return true;
}
static bool _py_list__repr__(int argc, py_Ref argv) {
List* self = py_touserdata(py_arg(0));
c11_sbuf buf;
c11_sbuf__ctor(&buf);
c11_sbuf__write_char(&buf, '[');
for(int i = 0; i < self->count; i++) {
py_TValue* val = c11__at(py_TValue, self, i);
bool ok = py_repr(val);
if(!ok) {
c11_sbuf__dtor(&buf);
return false;
}
int size;
const char* data = py_tostrn(py_retval(), &size);
c11_sbuf__write_cstrn(&buf, data, size);
if(i != self->count - 1) 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;
}
static bool _py_list__extend(int argc, py_Ref argv) {
PY_CHECK_ARGC(2);
List* self = py_touserdata(py_arg(0));
@ -384,6 +397,7 @@ py_Type pk_list__register() {
py_bindmagic(type, __add__, _py_list__add__);
py_bindmagic(type, __mul__, _py_list__mul__);
py_bindmagic(type, __rmul__, _py_list__rmul__);
py_bindmagic(type, __repr__, _py_list__repr__);
py_bindmethod(type, "append", _py_list__append);
py_bindmethod(type, "extend", _py_list__extend);

View File

@ -1,6 +1,7 @@
#include "pocketpy/pocketpy.h"
#include "pocketpy/common/utils.h"
#include "pocketpy/common/sstream.h"
#include "pocketpy/objects/object.h"
#include "pocketpy/interpreter/vm.h"
@ -12,14 +13,122 @@ void py_newtuple(py_Ref out, int n) {
out->_obj = obj;
}
py_Ref py_tuple__getitem(const py_Ref self, int i){
return py_getslot(self, i);
py_Ref py_tuple__getitem(const py_Ref self, int i) { return py_getslot(self, i); }
void py_tuple__setitem(py_Ref self, int i, const py_Ref val) { py_setslot(self, i, val); }
int py_tuple__len(const py_Ref self) { return self->_obj->slots; }
//////////////
static bool _py_tuple__len__(int argc, py_Ref argv) {
py_newint(py_retval(), py_tuple__len(argv));
return true;
}
void py_tuple__setitem(py_Ref self, int i, const py_Ref val){
py_setslot(self, i, val);
static bool _py_tuple__repr__(int argc, py_Ref argv) {
c11_sbuf buf;
c11_sbuf__ctor(&buf);
c11_sbuf__write_char(&buf, '(');
int length = py_tuple__len(argv);
for(int i = 0; i < length; i++) {
py_TValue* val = py_getslot(argv, i);
bool ok = py_repr(val);
if(!ok) {
c11_sbuf__dtor(&buf);
return false;
}
int size;
const char* data = py_tostrn(py_retval(), &size);
c11_sbuf__write_cstrn(&buf, data, size);
if(i != length - 1) c11_sbuf__write_cstr(&buf, ", ");
}
if(length == 1) c11_sbuf__write_char(&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;
}
int py_tuple__len(const py_Ref self){
return self->_obj->slots;
static bool _py_tuple__new__(int argc, py_Ref argv) {
if(argc == 1 + 0) {
py_newtuple(py_retval(), 0);
return true;
}
if(argc == 1 + 1) {
bool ok = py_tpcall(tp_list, 1, py_arg(1));
if(!ok) return false;
py_Ref tmp = py_pushtmp();
*tmp = *py_retval(); // backup the list
int length = py_list__len(tmp);
py_newtuple(py_retval(), length);
for(int i = 0; i < py_tuple__len(py_retval()); i++) {
py_tuple__setitem(py_retval(), i, py_list__getitem(tmp, i));
}
return true;
}
return TypeError("tuple() takes at most 1 argument");
}
static bool _py_tuple__getitem__(int argc, py_Ref argv) {
PY_CHECK_ARGC(2);
int length = py_tuple__len(argv);
py_Ref _1 = py_arg(1);
if(_1->type == tp_int) {
int index = py_toint(py_arg(1));
if(!pk__normalize_index(&index, length)) return false;
*py_retval() = *py_getslot(argv, index);
return true;
} else if(_1->type == tp_slice) {
int start, stop, step;
bool ok = pk__parse_int_slice(_1, length, &start, &stop, &step);
if(!ok) return false;
py_Ref tmp = py_pushtmp();
py_newlist(tmp);
PK_SLICE_LOOP(i, start, stop, step) py_list__append(tmp, py_getslot(argv, i));
// convert list to tuple
py_newtuple(py_retval(), py_list__len(tmp));
for(int i = 0; i < py_tuple__len(py_retval()); i++) {
py_tuple__setitem(py_retval(), i, py_list__getitem(tmp, i));
}
return true;
} else {
return TypeError("tuple indices must be integers");
}
}
static bool _py_tuple__eq__(int argc, py_Ref argv) {
PY_CHECK_ARGC(2);
if(py_istype(py_arg(1), tp_tuple)) {
int length0, length1;
py_TValue* a0 = pk_arrayview(py_arg(0), &length0);
py_TValue* a1 = pk_arrayview(py_arg(1), &length1);
int res = pk_arrayeq(a0, length0, a1, length1);
if(res == -1) return false;
py_newbool(py_retval(), res);
} else {
py_newnotimplemented(py_retval());
}
return true;
}
static bool _py_tuple__ne__(int argc, py_Ref argv) {
bool ok = _py_tuple__eq__(argc, argv);
if(!ok) return false;
py_Ref retval = py_retval();
py_newbool(retval, !py_tobool(retval));
return true;
}
py_Type pk_tuple__register() {
pk_VM* vm = pk_current_vm;
py_Type type = pk_VM__new_type(vm, "tuple", tp_object, NULL, false);
py_bindmagic(type, __len__, _py_tuple__len__);
py_bindmagic(type, __repr__, _py_tuple__repr__);
py_bindmagic(type, __new__, _py_tuple__new__);
py_bindmagic(type, __getitem__, _py_tuple__getitem__);
py_bindmagic(type, __eq__, _py_tuple__eq__);
py_bindmagic(type, __ne__, _py_tuple__ne__);
return type;
}

View File

@ -4,9 +4,7 @@
#include "pocketpy/objects/object.h"
#include "pocketpy/interpreter/vm.h"
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) {
assert(self && self->is_ptr);
@ -39,9 +37,7 @@ void py_setslot(py_Ref self, int i, const py_Ref 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, const py_Ref src) { *dst = *src; }
/* Stack References */
py_Ref py_peek(int i) {

View File

@ -42,11 +42,21 @@ py_TValue* pk_arrayview(py_Ref self, int* length) {
}
if(self->type == tp_tuple) {
*length = py_tuple__len(self);
return py_tuple__getitem(self, 0);
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));

View File

@ -133,6 +133,25 @@ assert sorted(a, key=key) == [9, 8, 4, 2, 2]
assert sorted(a, key=key, reverse=True) == [2, 2, 4, 8, 9]
assert a == [8, 2, 4, 2, 9]
# test unpack ex
a, *b = [1,2,3,4]
assert a == 1
assert b == [2,3,4]
a, b, *c = [1, 2]
assert a == 1
assert b == 2
assert c == []
a, b, c, *d = [1, 2, 3, 4, 5]
assert d == [4, 5]
# test repr
assert repr([1, 2, 3]) == "[1, 2, 3]"
assert repr([1, [2, 3], 4]) == "[1, [2, 3], 4]"
assert repr([1, [2, [3, 4]], 5]) == "[1, [2, [3, 4]], 5]"
assert repr([]) == "[]"
# b = [(1, 2), (3, 3), (5, 1)]
# b.sort(key=lambda x:x[1])
# assert b == [(5, 1), (1, 2), (3,3)]

View File

@ -7,15 +7,9 @@ assert a == 2
assert b == 1
assert len(tup) == 6
# unpacking builder
a = 1, 2, 3
b = *a, 4, 5
assert b == (1, 2, 3, 4, 5)
# empty tuple
a = tuple([])
b = *a, 1, 2, 3, *a, *a
assert b == (1, 2, 3)
assert len(a) == 0
assert (1,) == tuple([1])
assert (1,2,) == tuple([1,2])
@ -31,3 +25,9 @@ assert l[32:] == tuple([])
assert l[1:4] == (2,3,4)
assert l[-1:-3] == tuple([])
assert l[-3:-1] == (2,3)
# test repr
assert repr((1,)) == '(1,)'
assert repr((1,2,)) == '(1, 2)'
assert repr((1,2,(3,4))) == '(1, 2, (3, 4))'
assert repr(tuple()) == '()'