mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 11:30:18 +00:00
...
This commit is contained in:
parent
a81563768d
commit
140255650d
@ -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();
|
||||
|
@ -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')
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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());
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -4,13 +4,11 @@
|
||||
#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){
|
||||
py_Ref py_getdict(const py_Ref self, py_Name name) {
|
||||
assert(self && self->is_ptr);
|
||||
if(self->type == tp_type && py_ismagicname(name)){
|
||||
if(self->type == tp_type && py_ismagicname(name)) {
|
||||
py_Type* ud = py_touserdata(self);
|
||||
py_Ref slot = py_tpmagic(*ud, name);
|
||||
return py_isnil(slot) ? NULL : slot;
|
||||
@ -18,58 +16,56 @@ py_Ref py_getdict(const py_Ref self, py_Name name){
|
||||
return pk_NameDict__try_get(PyObject__dict(self->_obj), name);
|
||||
}
|
||||
|
||||
void py_setdict(py_Ref self, py_Name name, const py_Ref val){
|
||||
void py_setdict(py_Ref self, py_Name name, const py_Ref val) {
|
||||
assert(self && self->is_ptr);
|
||||
if(self->type == tp_type && py_ismagicname(name)){
|
||||
if(self->type == tp_type && py_ismagicname(name)) {
|
||||
py_Type* ud = py_touserdata(self);
|
||||
*py_tpmagic(*ud, name) = *val;
|
||||
}
|
||||
pk_NameDict__set(PyObject__dict(self->_obj), name, *val);
|
||||
}
|
||||
|
||||
py_Ref py_getslot(const py_Ref self, int i){
|
||||
py_Ref py_getslot(const py_Ref self, int i) {
|
||||
assert(self && self->is_ptr);
|
||||
assert(i >= 0 && i < self->_obj->slots);
|
||||
return PyObject__slots(self->_obj) + i;
|
||||
}
|
||||
|
||||
void py_setslot(py_Ref self, int i, const py_Ref val){
|
||||
void py_setslot(py_Ref self, int i, const py_Ref val) {
|
||||
assert(self && self->is_ptr);
|
||||
assert(i >= 0 && i < self->_obj->slots);
|
||||
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){
|
||||
py_Ref py_peek(int i) {
|
||||
assert(i < 0);
|
||||
return pk_current_vm->stack.sp + i;
|
||||
}
|
||||
|
||||
void py_pop(){
|
||||
void py_pop() {
|
||||
pk_VM* vm = pk_current_vm;
|
||||
vm->stack.sp--;
|
||||
}
|
||||
|
||||
void py_shrink(int n){
|
||||
void py_shrink(int n) {
|
||||
pk_VM* vm = pk_current_vm;
|
||||
vm->stack.sp -= n;
|
||||
}
|
||||
|
||||
void py_push(const py_Ref src){
|
||||
void py_push(const py_Ref src) {
|
||||
pk_VM* vm = pk_current_vm;
|
||||
*vm->stack.sp++ = *src;
|
||||
}
|
||||
|
||||
void py_pushnil(){
|
||||
void py_pushnil() {
|
||||
pk_VM* vm = pk_current_vm;
|
||||
py_newnil(vm->stack.sp++);
|
||||
}
|
||||
|
||||
py_Ref py_pushtmp(){
|
||||
py_Ref py_pushtmp() {
|
||||
pk_VM* vm = pk_current_vm;
|
||||
py_newnil(vm->stack.sp++);
|
||||
return py_gettop();
|
||||
|
@ -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));
|
||||
|
@ -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)]
|
||||
|
@ -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()) == '()'
|
Loading…
x
Reference in New Issue
Block a user