mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 03:20:18 +00:00
fix list
This commit is contained in:
parent
ed02a2b172
commit
83c54fbeac
@ -40,7 +40,8 @@ extern "C" {
|
|||||||
bool c11__stable_sort(void* ptr,
|
bool c11__stable_sort(void* ptr,
|
||||||
int count,
|
int count,
|
||||||
int elem_size,
|
int elem_size,
|
||||||
int (*f_le)(const void* a, const void* b));
|
int (*f_lt)(const void* a, const void* b, void* extra),
|
||||||
|
void* extra);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -75,10 +75,10 @@ c11_array c11_vector__submit(c11_vector* self);
|
|||||||
(self)->count--; \
|
(self)->count--; \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
#define c11_vector__reverse(T, self, start, end) \
|
#define c11__reverse(T, self) \
|
||||||
do { \
|
do { \
|
||||||
T* p = (T*)(self)->data + (start); \
|
T* p = (T*)(self)->data; \
|
||||||
T* q = (T*)(self)->data + (end); \
|
T* q = (T*)(self)->data + (self)->count - 1; \
|
||||||
while(p < q) { \
|
while(p < q) { \
|
||||||
T tmp = *p; \
|
T tmp = *p; \
|
||||||
*p = *q; \
|
*p = *q; \
|
||||||
|
@ -91,7 +91,13 @@ py_Type pk_VM__new_type(pk_VM* self,
|
|||||||
pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t argc, uint16_t kwargc, bool opcall);
|
pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t argc, uint16_t kwargc, bool opcall);
|
||||||
|
|
||||||
const char* pk_opname(Opcode op);
|
const char* pk_opname(Opcode op);
|
||||||
py_TValue* pk_arrayview(py_Ref self, int* size);
|
|
||||||
|
py_TValue* pk_arrayview(py_Ref self, int* length);
|
||||||
|
|
||||||
|
/// Assumes [a, b] are on the stack, performs a binary op.
|
||||||
|
/// The result is stored in `self->last_retval`.
|
||||||
|
/// The stack remains unchanged.
|
||||||
|
bool pk_stack_binaryop(pk_VM* self, py_Name op, py_Name rop);
|
||||||
|
|
||||||
// type registration
|
// type registration
|
||||||
void pk_object__register();
|
void pk_object__register();
|
||||||
|
@ -118,9 +118,7 @@ typedef struct FuncDecl {
|
|||||||
typedef FuncDecl* FuncDecl_;
|
typedef FuncDecl* FuncDecl_;
|
||||||
|
|
||||||
FuncDecl_ FuncDecl__rcnew(pk_SourceData_ src, c11_sv name);
|
FuncDecl_ FuncDecl__rcnew(pk_SourceData_ src, c11_sv name);
|
||||||
void FuncDecl__dtor(FuncDecl* self);
|
|
||||||
void FuncDecl__add_kwarg(FuncDecl* self, int index, uint16_t key, const py_TValue* value);
|
void FuncDecl__add_kwarg(FuncDecl* self, int index, uint16_t key, const py_TValue* value);
|
||||||
void FuncDecl__gc_mark(const FuncDecl* self);
|
|
||||||
|
|
||||||
// runtime function
|
// runtime function
|
||||||
typedef struct Function {
|
typedef struct Function {
|
||||||
@ -128,6 +126,7 @@ typedef struct Function {
|
|||||||
PyObject* module; // weak ref
|
PyObject* module; // weak ref
|
||||||
PyObject* clazz; // weak ref
|
PyObject* clazz; // weak ref
|
||||||
pk_NameDict* closure; // strong ref
|
pk_NameDict* closure; // strong ref
|
||||||
|
py_CFunction cfunc; // wrapped C function
|
||||||
} Function;
|
} Function;
|
||||||
|
|
||||||
void Function__ctor(Function* self, FuncDecl_ decl, PyObject* module);
|
void Function__ctor(Function* self, FuncDecl_ decl, PyObject* module);
|
||||||
|
@ -89,7 +89,7 @@ void py_newfunction2(py_Ref out,
|
|||||||
const char* sig,
|
const char* sig,
|
||||||
enum BindType bt,
|
enum BindType bt,
|
||||||
const char* docstring,
|
const char* docstring,
|
||||||
const py_Ref upvalue);
|
int slots);
|
||||||
// old style argc-based function
|
// old style argc-based function
|
||||||
void py_newnativefunc(py_Ref out, py_CFunction);
|
void py_newnativefunc(py_Ref out, py_CFunction);
|
||||||
|
|
||||||
@ -134,13 +134,13 @@ py_GlobalRef py_tpmagic(py_Type type, py_Name name);
|
|||||||
#define py_bindmagic(type, __magic__, f) py_newnativefunc(py_tpmagic((type), __magic__), (f))
|
#define py_bindmagic(type, __magic__, f) py_newnativefunc(py_tpmagic((type), __magic__), (f))
|
||||||
|
|
||||||
// new style decl-based bindings
|
// new style decl-based bindings
|
||||||
py_TmpRef py_bind(py_Ref obj, const char* sig, py_CFunction f);
|
void py_bind(py_Ref obj, const char* sig, py_CFunction f);
|
||||||
py_TmpRef py_bind2(py_Ref obj,
|
void py_bind2(py_Ref obj,
|
||||||
const char* sig,
|
const char* sig,
|
||||||
py_CFunction f,
|
py_CFunction f,
|
||||||
enum BindType bt,
|
enum BindType bt,
|
||||||
const char* docstring,
|
const char* docstring,
|
||||||
const py_Ref upvalue);
|
int slots);
|
||||||
// old style argc-based bindings
|
// old style argc-based bindings
|
||||||
void py_bindmethod(py_Type type, const char* name, py_CFunction f);
|
void py_bindmethod(py_Type type, const char* name, py_CFunction f);
|
||||||
void py_bindmethod2(py_Type type, const char* name, py_CFunction f, enum BindType bt);
|
void py_bindmethod2(py_Type type, const char* name, py_CFunction f, enum BindType bt);
|
||||||
|
@ -8,9 +8,10 @@ static bool merge(char* a,
|
|||||||
char* b_end,
|
char* b_end,
|
||||||
char* r,
|
char* r,
|
||||||
int elem_size,
|
int elem_size,
|
||||||
int (*f_lt)(const void* a, const void* b)) {
|
int (*f_lt)(const void* a, const void* b, void* extra),
|
||||||
|
void* extra) {
|
||||||
while(a < a_end && b < b_end) {
|
while(a < a_end && b < b_end) {
|
||||||
int res = f_lt(a, b);
|
int res = f_lt(a, b, extra);
|
||||||
// check error
|
// check error
|
||||||
if(res == -1) return false;
|
if(res == -1) return false;
|
||||||
if(res) {
|
if(res) {
|
||||||
@ -34,14 +35,15 @@ static bool merge(char* a,
|
|||||||
bool c11__stable_sort(void* ptr_,
|
bool c11__stable_sort(void* ptr_,
|
||||||
int count,
|
int count,
|
||||||
int elem_size,
|
int elem_size,
|
||||||
int (*f_lt)(const void* a, const void* b)) {
|
int (*f_lt)(const void* a, const void* b, void* extra),
|
||||||
|
void* extra) {
|
||||||
// merge sort
|
// merge sort
|
||||||
char *ptr = ptr_, *tmp = malloc(count * elem_size);
|
char *ptr = ptr_, *tmp = malloc(count * elem_size);
|
||||||
for(int seg = 1; seg < count; seg *= 2) {
|
for(int seg = 1; seg < count; seg *= 2) {
|
||||||
for(char* a = ptr; a < ptr + (count - seg) * elem_size; a += 2 * seg * elem_size) {
|
for(char* a = ptr; a < ptr + (count - seg) * elem_size; a += 2 * seg * elem_size) {
|
||||||
char *b = a + seg * elem_size, *a_end = b, *b_end = b + seg * elem_size;
|
char *b = a + seg * elem_size, *a_end = b, *b_end = b + seg * elem_size;
|
||||||
if(b_end > ptr + count * elem_size) b_end = ptr + count * elem_size;
|
if(b_end > ptr + count * elem_size) b_end = ptr + count * elem_size;
|
||||||
bool ok = merge(a, a_end, b, b_end, tmp, elem_size, f_lt);
|
bool ok = merge(a, a_end, b, b_end, tmp, elem_size, f_lt, extra);
|
||||||
if(!ok) {
|
if(!ok) {
|
||||||
free(tmp);
|
free(tmp);
|
||||||
return false;
|
return false;
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
#include "pocketpy/pocketpy.h"
|
#include "pocketpy/pocketpy.h"
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
static bool stack_binaryop(pk_VM* self, py_Name op, py_Name rop);
|
|
||||||
static bool stack_unpack_sequence(pk_VM* self, uint16_t arg);
|
static bool stack_unpack_sequence(pk_VM* self, uint16_t arg);
|
||||||
|
|
||||||
#define DISPATCH() \
|
#define DISPATCH() \
|
||||||
@ -94,6 +93,20 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
|
|||||||
case tp_float: c11_sbuf__write_f64(&buf, p->_f64, -1); break;
|
case tp_float: c11_sbuf__write_f64(&buf, p->_f64, -1); break;
|
||||||
case tp_bool: c11_sbuf__write_cstr(&buf, p->_bool ? "True" : "False"); break;
|
case tp_bool: c11_sbuf__write_cstr(&buf, p->_bool ? "True" : "False"); break;
|
||||||
case tp_none_type: c11_sbuf__write_cstr(&buf, "None"); break;
|
case tp_none_type: c11_sbuf__write_cstr(&buf, "None"); break;
|
||||||
|
case tp_list: {
|
||||||
|
pk_sprintf(&buf, "list(%d)", py_list__len(p));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case tp_tuple: {
|
||||||
|
pk_sprintf(&buf, "tuple(%d)", py_list__len(p));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case tp_function: {
|
||||||
|
Function* ud = py_touserdata(p);
|
||||||
|
c11_sbuf__write_cstr(&buf, ud->decl->code.name->data);
|
||||||
|
c11_sbuf__write_cstr(&buf, "()");
|
||||||
|
break;
|
||||||
|
}
|
||||||
case tp_type: {
|
case tp_type: {
|
||||||
pk_sprintf(&buf, "<class '%t'>", py_totype(p));
|
pk_sprintf(&buf, "<class '%t'>", py_totype(p));
|
||||||
break;
|
break;
|
||||||
@ -541,7 +554,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
|
|||||||
case OP_BINARY_OP: {
|
case OP_BINARY_OP: {
|
||||||
py_Name op = byte.arg & 0xFF;
|
py_Name op = byte.arg & 0xFF;
|
||||||
py_Name rop = byte.arg >> 8;
|
py_Name rop = byte.arg >> 8;
|
||||||
if(!stack_binaryop(self, op, rop)) goto __ERROR;
|
if(!pk_stack_binaryop(self, op, rop)) goto __ERROR;
|
||||||
POP();
|
POP();
|
||||||
*TOP() = self->last_retval;
|
*TOP() = self->last_retval;
|
||||||
DISPATCH();
|
DISPATCH();
|
||||||
@ -728,10 +741,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
|
|||||||
return RES_RETURN;
|
return RES_RETURN;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Assumes [a, b] are on the stack, performs a binary op.
|
bool pk_stack_binaryop(pk_VM* self, py_Name op, py_Name rop) {
|
||||||
/// The result is stored in `self->last_retval`.
|
|
||||||
/// The stack remains unchanged.
|
|
||||||
static bool stack_binaryop(pk_VM* self, py_Name op, py_Name rop) {
|
|
||||||
// [a, b]
|
// [a, b]
|
||||||
py_Ref magic = py_tpfindmagic(SECOND()->type, op);
|
py_Ref magic = py_tpfindmagic(SECOND()->type, op);
|
||||||
if(magic) {
|
if(magic) {
|
||||||
@ -760,7 +770,7 @@ bool py_binaryop(const py_Ref lhs, const py_Ref rhs, py_Name op, py_Name rop) {
|
|||||||
pk_VM* self = pk_current_vm;
|
pk_VM* self = pk_current_vm;
|
||||||
PUSH(lhs);
|
PUSH(lhs);
|
||||||
PUSH(rhs);
|
PUSH(rhs);
|
||||||
bool ok = stack_binaryop(self, op, rop);
|
bool ok = pk_stack_binaryop(self, op, rop);
|
||||||
STACK_SHRINK(2);
|
STACK_SHRINK(2);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
@ -307,12 +307,12 @@ bool __prepare_py_call(py_TValue* buffer,
|
|||||||
|
|
||||||
if(decl->starred_kwarg != -1) py_newdict(&buffer[decl->starred_kwarg]);
|
if(decl->starred_kwarg != -1) py_newdict(&buffer[decl->starred_kwarg]);
|
||||||
|
|
||||||
for(int j = 0; j < kwargc; j += 2) {
|
for(int j = 0; j < kwargc; j++) {
|
||||||
py_Name key = py_toint(&p1[j]);
|
py_Name key = py_toint(&p1[2 * j]);
|
||||||
int index = c11_smallmap_n2i__get(&decl->kw_to_index, key, -1);
|
int index = c11_smallmap_n2i__get(&decl->kw_to_index, key, -1);
|
||||||
// if key is an explicit key, set as local variable
|
// if key is an explicit key, set as local variable
|
||||||
if(index >= 0) {
|
if(index >= 0) {
|
||||||
buffer[index] = p1[j + 1];
|
buffer[index] = p1[2 * j + 1];
|
||||||
} else {
|
} else {
|
||||||
// otherwise, set as **kwargs if possible
|
// otherwise, set as **kwargs if possible
|
||||||
if(decl->starred_kwarg == -1) {
|
if(decl->starred_kwarg == -1) {
|
||||||
@ -336,6 +336,7 @@ pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t argc, uint16_t kwargc, bo
|
|||||||
// [callable, <self>, args..., kwargs...]
|
// [callable, <self>, args..., kwargs...]
|
||||||
// ^p0 ^p1 ^_sp
|
// ^p0 ^p1 ^_sp
|
||||||
|
|
||||||
|
#if 0
|
||||||
// handle boundmethod, do a patch
|
// handle boundmethod, do a patch
|
||||||
if(p0->type == tp_bound_method) {
|
if(p0->type == tp_bound_method) {
|
||||||
assert(false);
|
assert(false);
|
||||||
@ -347,9 +348,9 @@ pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t argc, uint16_t kwargc, bo
|
|||||||
// p1[-(ARGC + 1)] = bm.self;
|
// p1[-(ARGC + 1)] = bm.self;
|
||||||
// [unbound, self, args..., kwargs...]
|
// [unbound, self, args..., kwargs...]
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
py_Ref argv = py_isnil(p0 + 1) ? p0 + 2 : p0 + 1;
|
py_Ref argv = py_isnil(p0 + 1) ? p0 + 2 : p0 + 1;
|
||||||
int argc2 = argv - p0;
|
|
||||||
|
|
||||||
if(p0->type == tp_function) {
|
if(p0->type == tp_function) {
|
||||||
/*****************_py_call*****************/
|
/*****************_py_call*****************/
|
||||||
@ -368,14 +369,21 @@ pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t argc, uint16_t kwargc, bo
|
|||||||
if(!ok) return RES_ERROR;
|
if(!ok) return RES_ERROR;
|
||||||
// copy buffer back to stack
|
// copy buffer back to stack
|
||||||
self->stack.sp = argv + co->nlocals;
|
self->stack.sp = argv + co->nlocals;
|
||||||
for(int j = 0; j < co->nlocals; j++)
|
memcpy(argv, self->__vectorcall_buffer, co->nlocals * sizeof(py_TValue));
|
||||||
argv[j] = self->__vectorcall_buffer[j];
|
// submit the call
|
||||||
break;
|
if(!fn->cfunc) {
|
||||||
|
pk_VM__push_frame(self, Frame__new(co, fn->module, p0, p0, argv, co));
|
||||||
|
return opcall ? RES_CALL : pk_VM__run_top_frame(self);
|
||||||
|
} else {
|
||||||
|
bool ok = fn->cfunc(co->nlocals, argv);
|
||||||
|
self->stack.sp = p0;
|
||||||
|
return ok ? RES_RETURN : RES_ERROR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
case FuncType_SIMPLE:
|
case FuncType_SIMPLE:
|
||||||
if(argc2 != fn->decl->args.count) {
|
if(p1 - argv != fn->decl->args.count) {
|
||||||
const char* fmt = "%s() takes %d positional arguments but %d were given";
|
const char* fmt = "%s() takes %d positional arguments but %d were given";
|
||||||
TypeError(fmt, co->name, fn->decl->args.count, argc2);
|
TypeError(fmt, co->name->data, fn->decl->args.count, p1 - argv);
|
||||||
return RES_ERROR;
|
return RES_ERROR;
|
||||||
}
|
}
|
||||||
if(kwargc) {
|
if(kwargc) {
|
||||||
@ -387,7 +395,9 @@ pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t argc, uint16_t kwargc, bo
|
|||||||
self->stack.sp = argv + co->nlocals;
|
self->stack.sp = argv + co->nlocals;
|
||||||
// initialize local variables to PY_NIL
|
// initialize local variables to PY_NIL
|
||||||
memset(p1, 0, (char*)self->stack.sp - (char*)p1);
|
memset(p1, 0, (char*)self->stack.sp - (char*)p1);
|
||||||
break;
|
// submit the call
|
||||||
|
pk_VM__push_frame(self, Frame__new(co, fn->module, p0, p0, argv, co));
|
||||||
|
return opcall ? RES_CALL : pk_VM__run_top_frame(self);
|
||||||
case FuncType_GENERATOR:
|
case FuncType_GENERATOR:
|
||||||
assert(false);
|
assert(false);
|
||||||
break;
|
break;
|
||||||
@ -400,11 +410,7 @@ pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t argc, uint16_t kwargc, bo
|
|||||||
default: c11__unreachedable();
|
default: c11__unreachedable();
|
||||||
};
|
};
|
||||||
|
|
||||||
// simple or normal
|
c11__unreachedable();
|
||||||
Frame* frame = Frame__new(co, fn->module, p0, p0, argv, co);
|
|
||||||
pk_VM__push_frame(self, frame);
|
|
||||||
if(opcall) return RES_CALL;
|
|
||||||
return pk_VM__run_top_frame(self);
|
|
||||||
/*****************_py_call*****************/
|
/*****************_py_call*****************/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,6 +13,13 @@ bool Bytecode__is_forward_jump(const Bytecode* self) {
|
|||||||
return self->op >= OP_JUMP_FORWARD && self->op <= OP_LOOP_BREAK;
|
return self->op >= OP_JUMP_FORWARD && self->op <= OP_LOOP_BREAK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void FuncDecl__dtor(FuncDecl* self) {
|
||||||
|
CodeObject__dtor(&self->code);
|
||||||
|
c11_vector__dtor(&self->args);
|
||||||
|
c11_vector__dtor(&self->kwargs);
|
||||||
|
c11_smallmap_n2i__dtor(&self->kw_to_index);
|
||||||
|
}
|
||||||
|
|
||||||
FuncDecl_ FuncDecl__rcnew(pk_SourceData_ src, c11_sv name) {
|
FuncDecl_ FuncDecl__rcnew(pk_SourceData_ src, c11_sv name) {
|
||||||
FuncDecl* self = malloc(sizeof(FuncDecl));
|
FuncDecl* self = malloc(sizeof(FuncDecl));
|
||||||
self->rc.count = 1;
|
self->rc.count = 1;
|
||||||
@ -33,13 +40,6 @@ FuncDecl_ FuncDecl__rcnew(pk_SourceData_ src, c11_sv name) {
|
|||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
void FuncDecl__dtor(FuncDecl* self) {
|
|
||||||
CodeObject__dtor(&self->code);
|
|
||||||
c11_vector__dtor(&self->args);
|
|
||||||
c11_vector__dtor(&self->kwargs);
|
|
||||||
c11_smallmap_n2i__dtor(&self->kw_to_index);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FuncDecl__add_kwarg(FuncDecl* self, int index, uint16_t key, const py_TValue* value) {
|
void FuncDecl__add_kwarg(FuncDecl* self, int index, uint16_t key, const py_TValue* value) {
|
||||||
c11_smallmap_n2i__set(&self->kw_to_index, key, index);
|
c11_smallmap_n2i__set(&self->kw_to_index, key, index);
|
||||||
FuncDeclKwArg item = {index, key, *value};
|
FuncDeclKwArg item = {index, key, *value};
|
||||||
@ -99,6 +99,7 @@ void Function__ctor(Function* self, FuncDecl_ decl, PyObject* module) {
|
|||||||
self->module = module;
|
self->module = module;
|
||||||
self->clazz = NULL;
|
self->clazz = NULL;
|
||||||
self->closure = NULL;
|
self->closure = NULL;
|
||||||
|
self->cfunc = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Function__dtor(Function* self) {
|
void Function__dtor(Function* self) {
|
||||||
|
@ -121,6 +121,25 @@ static bool _py_builtins__next(int argc, py_Ref argv) {
|
|||||||
return py_exception("StopIteration", "");
|
return py_exception("StopIteration", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool _py_builtins__sorted(int argc, py_Ref argv) {
|
||||||
|
PY_CHECK_ARGC(3);
|
||||||
|
// convert _0 to list object
|
||||||
|
if(!py_tpcall(tp_list, 1, argv)) return false;
|
||||||
|
py_Ref retval = py_pushtmp();
|
||||||
|
py_Ref sort = py_pushtmp();
|
||||||
|
py_Ref self = py_pushtmp();
|
||||||
|
py_Ref key = py_pushtmp();
|
||||||
|
py_Ref reverse = py_pushtmp();
|
||||||
|
*self = *retval = *py_retval();
|
||||||
|
bool ok = py_getunboundmethod(self, py_name("sort"), sort, self);
|
||||||
|
if(!ok) return false;
|
||||||
|
*key = argv[1];
|
||||||
|
*reverse = argv[2];
|
||||||
|
if(!py_vectorcall(2, 0)) return false;
|
||||||
|
*py_retval() = *retval;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
py_TValue pk_builtins__register() {
|
py_TValue pk_builtins__register() {
|
||||||
py_Ref builtins = py_newmodule("builtins", NULL);
|
py_Ref builtins = py_newmodule("builtins", NULL);
|
||||||
py_bindnativefunc(builtins, "repr", _py_builtins__repr);
|
py_bindnativefunc(builtins, "repr", _py_builtins__repr);
|
||||||
@ -129,6 +148,8 @@ py_TValue pk_builtins__register() {
|
|||||||
py_bindnativefunc(builtins, "hex", _py_builtins__hex);
|
py_bindnativefunc(builtins, "hex", _py_builtins__hex);
|
||||||
py_bindnativefunc(builtins, "iter", _py_builtins__iter);
|
py_bindnativefunc(builtins, "iter", _py_builtins__iter);
|
||||||
py_bindnativefunc(builtins, "next", _py_builtins__next);
|
py_bindnativefunc(builtins, "next", _py_builtins__next);
|
||||||
|
|
||||||
|
py_bind(builtins, "sorted(iterable, key=None, reverse=False)", _py_builtins__sorted);
|
||||||
return *builtins;
|
return *builtins;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,6 +107,16 @@ static bool _py_list__new__(int argc, py_Ref argv) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if(argc == 2) {
|
if(argc == 2) {
|
||||||
|
int length;
|
||||||
|
py_TValue* p = pk_arrayview(py_arg(1), &length);
|
||||||
|
if(p) {
|
||||||
|
py_newlistn(py_retval(), length);
|
||||||
|
for(int i = 0; i < length; i++) {
|
||||||
|
py_list__setitem(py_retval(), i, p + i);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
py_Ref iter = py_pushtmp();
|
py_Ref iter = py_pushtmp();
|
||||||
py_Ref list = py_pushtmp();
|
py_Ref list = py_pushtmp();
|
||||||
if(!py_iter(py_arg(1))) return false;
|
if(!py_iter(py_arg(1))) return false;
|
||||||
@ -274,11 +284,7 @@ static bool _py_list__index(int argc, py_Ref argv) {
|
|||||||
static bool _py_list__reverse(int argc, py_Ref argv) {
|
static bool _py_list__reverse(int argc, py_Ref argv) {
|
||||||
PY_CHECK_ARGC(1);
|
PY_CHECK_ARGC(1);
|
||||||
List* self = py_touserdata(py_arg(0));
|
List* self = py_touserdata(py_arg(0));
|
||||||
for(int i = 0; i < self->count / 2; i++) {
|
c11__reverse(py_TValue, self);
|
||||||
py_TValue tmp = c11__getitem(py_TValue, self, i);
|
|
||||||
c11__setitem(py_TValue, self, i, c11__getitem(py_TValue, self, self->count - i - 1));
|
|
||||||
c11__setitem(py_TValue, self, self->count - i - 1, tmp);
|
|
||||||
}
|
|
||||||
py_newnone(py_retval());
|
py_newnone(py_retval());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -319,10 +325,44 @@ static bool _py_list__insert(int argc, py_Ref argv) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int _py_lt_with_key(py_TValue* a, py_TValue* b, py_TValue* key) {
|
||||||
|
if(!key) return py_lt(a, b);
|
||||||
|
pk_VM* vm = pk_current_vm;
|
||||||
|
// project a
|
||||||
|
py_push(key);
|
||||||
|
py_pushnil();
|
||||||
|
py_push(a);
|
||||||
|
if(!py_vectorcall(1, 0)) return -1;
|
||||||
|
py_push(py_retval());
|
||||||
|
// project b
|
||||||
|
py_push(key);
|
||||||
|
py_pushnil();
|
||||||
|
py_push(b);
|
||||||
|
if(!py_vectorcall(1, 0)) return -1;
|
||||||
|
py_push(py_retval());
|
||||||
|
// binary op
|
||||||
|
bool ok = pk_stack_binaryop(vm, __lt__, __gt__);
|
||||||
|
if(!ok) return -1;
|
||||||
|
py_shrink(2);
|
||||||
|
return py_tobool(py_retval());
|
||||||
|
}
|
||||||
|
|
||||||
|
// sort(self, key=None, reverse=False)
|
||||||
static bool _py_list__sort(int argc, py_Ref argv) {
|
static bool _py_list__sort(int argc, py_Ref argv) {
|
||||||
PY_CHECK_ARGC(1);
|
|
||||||
List* self = py_touserdata(py_arg(0));
|
List* self = py_touserdata(py_arg(0));
|
||||||
c11__stable_sort(self->data, self->count, sizeof(py_TValue), (int (*)(const void*, const void*))py_lt);
|
|
||||||
|
py_Ref key = py_arg(1);
|
||||||
|
if(py_isnone(key)) key = NULL;
|
||||||
|
|
||||||
|
c11__stable_sort(self->data,
|
||||||
|
self->count,
|
||||||
|
sizeof(py_TValue),
|
||||||
|
(int (*)(const void*, const void*, void*))_py_lt_with_key,
|
||||||
|
key);
|
||||||
|
|
||||||
|
PY_CHECK_ARG_TYPE(2, tp_bool);
|
||||||
|
bool reverse = py_tobool(py_arg(2));
|
||||||
|
if(reverse) c11__reverse(py_TValue, self);
|
||||||
py_newnone(py_retval());
|
py_newnone(py_retval());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -355,5 +395,7 @@ py_Type pk_list__register() {
|
|||||||
py_bindmethod(type, "pop", _py_list__pop);
|
py_bindmethod(type, "pop", _py_list__pop);
|
||||||
py_bindmethod(type, "insert", _py_list__insert);
|
py_bindmethod(type, "insert", _py_list__insert);
|
||||||
py_bindmethod(type, "sort", _py_list__sort);
|
py_bindmethod(type, "sort", _py_list__sort);
|
||||||
|
|
||||||
|
py_bind(py_tpobject(type), "sort(self, key=None, reverse=False)", _py_list__sort);
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
@ -5,6 +5,7 @@
|
|||||||
#include "pocketpy/common/utils.h"
|
#include "pocketpy/common/utils.h"
|
||||||
#include "pocketpy/objects/object.h"
|
#include "pocketpy/objects/object.h"
|
||||||
#include "pocketpy/interpreter/vm.h"
|
#include "pocketpy/interpreter/vm.h"
|
||||||
|
#include "pocketpy/compiler/compiler.h"
|
||||||
|
|
||||||
void py_newint(py_Ref out, int64_t val) {
|
void py_newint(py_Ref out, int64_t val) {
|
||||||
out->type = tp_int;
|
out->type = tp_int;
|
||||||
@ -41,9 +42,8 @@ void py_newellipsis(py_Ref out) {
|
|||||||
|
|
||||||
void py_newnil(py_Ref out) { out->type = 0; }
|
void py_newnil(py_Ref out) { out->type = 0; }
|
||||||
|
|
||||||
|
|
||||||
void py_newfunction(py_Ref out, py_CFunction f, const char* sig) {
|
void py_newfunction(py_Ref out, py_CFunction f, const char* sig) {
|
||||||
py_newfunction2(out, f, sig, BindType_FUNCTION, NULL, NULL);
|
py_newfunction2(out, f, sig, BindType_FUNCTION, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void py_newfunction2(py_Ref out,
|
void py_newfunction2(py_Ref out,
|
||||||
@ -51,7 +51,23 @@ void py_newfunction2(py_Ref out,
|
|||||||
const char* sig,
|
const char* sig,
|
||||||
enum BindType bt,
|
enum BindType bt,
|
||||||
const char* docstring,
|
const char* docstring,
|
||||||
const py_Ref upvalue) {}
|
int slots) {
|
||||||
|
char buffer[256];
|
||||||
|
snprintf(buffer, sizeof(buffer), "def %s: pass", sig);
|
||||||
|
// fn(a, b, *c, d=1) -> None
|
||||||
|
CodeObject code;
|
||||||
|
pk_SourceData_ source = pk_SourceData__rcnew(buffer, "<bind>", EXEC_MODE, false);
|
||||||
|
Error* err = pk_compile(source, &code);
|
||||||
|
if(err) abort();
|
||||||
|
if(code.func_decls.count != 1) abort();
|
||||||
|
FuncDecl_ decl = c11__getitem(FuncDecl_, &code.func_decls, 0);
|
||||||
|
// construct the function
|
||||||
|
Function* ud = py_newobject(out, tp_function, slots, sizeof(Function));
|
||||||
|
Function__ctor(ud, decl, NULL);
|
||||||
|
ud->cfunc = f;
|
||||||
|
CodeObject__dtor(&code);
|
||||||
|
PK_DECREF(source);
|
||||||
|
}
|
||||||
|
|
||||||
void py_newnativefunc(py_Ref out, py_CFunction f) {
|
void py_newnativefunc(py_Ref out, py_CFunction f) {
|
||||||
out->type = tp_nativefunc;
|
out->type = tp_nativefunc;
|
||||||
@ -59,22 +75,30 @@ void py_newnativefunc(py_Ref out, py_CFunction f) {
|
|||||||
out->_cfunc = f;
|
out->_cfunc = f;
|
||||||
}
|
}
|
||||||
|
|
||||||
void py_bindmethod(py_Type type, const char *name, py_CFunction f){
|
void py_bindmethod(py_Type type, const char* name, py_CFunction f) {
|
||||||
py_bindmethod2(type, name, f, BindType_FUNCTION);
|
py_bindmethod2(type, name, f, BindType_FUNCTION);
|
||||||
}
|
}
|
||||||
|
|
||||||
void py_bindmethod2(py_Type type, const char *name, py_CFunction f, enum BindType bt){
|
void py_bindmethod2(py_Type type, const char* name, py_CFunction f, enum BindType bt) {
|
||||||
py_TValue tmp;
|
py_TValue tmp;
|
||||||
py_newnativefunc(&tmp, f);
|
py_newnativefunc(&tmp, f);
|
||||||
py_setdict(py_tpobject(type), py_name(name), &tmp);
|
py_setdict(py_tpobject(type), py_name(name), &tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void py_bindnativefunc(py_Ref obj, const char *name, py_CFunction f){
|
void py_bindnativefunc(py_Ref obj, const char* name, py_CFunction f) {
|
||||||
py_TValue tmp;
|
py_TValue tmp;
|
||||||
py_newnativefunc(&tmp, f);
|
py_newnativefunc(&tmp, f);
|
||||||
py_setdict(obj, py_name(name), &tmp);
|
py_setdict(obj, py_name(name), &tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void py_bind(py_Ref obj, const char* sig, py_CFunction f) {
|
||||||
|
py_TValue tmp;
|
||||||
|
py_newfunction(&tmp, f, sig);
|
||||||
|
Function* ud = py_touserdata(&tmp);
|
||||||
|
py_Name name = py_name(ud->decl->code.name->data);
|
||||||
|
py_setdict(obj, name, &tmp);
|
||||||
|
}
|
||||||
|
|
||||||
void py_newslice(py_Ref out, const py_Ref start, const py_Ref stop, const py_Ref step) {
|
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_newobject(out, tp_slice, 3, 0);
|
||||||
py_setslot(out, 0, start);
|
py_setslot(out, 0, start);
|
||||||
|
@ -219,7 +219,7 @@ bool py_callmethod(py_Ref self, py_Name name, int argc, py_Ref argv) { return -1
|
|||||||
|
|
||||||
bool py_vectorcall(uint16_t argc, uint16_t kwargc) {
|
bool py_vectorcall(uint16_t argc, uint16_t kwargc) {
|
||||||
pk_VM* vm = pk_current_vm;
|
pk_VM* vm = pk_current_vm;
|
||||||
return pk_VM__vectorcall(vm, argc, kwargc, false) == RES_ERROR;
|
return pk_VM__vectorcall(vm, argc, kwargc, false) != RES_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
py_Ref py_retval() { return &pk_current_vm->last_retval; }
|
py_Ref py_retval() { return &pk_current_vm->last_retval; }
|
||||||
|
@ -98,23 +98,51 @@ a = [0, 0, 0, 0, 1, 1, 3, -1]
|
|||||||
assert a.sort() == None
|
assert a.sort() == None
|
||||||
assert a == [-1, 0, 0, 0, 0, 1, 1, 3]
|
assert a == [-1, 0, 0, 0, 0, 1, 1, 3]
|
||||||
|
|
||||||
|
a = [3, 2, 2, 1]
|
||||||
|
a.sort()
|
||||||
|
assert a == [1, 2, 2, 3]
|
||||||
|
|
||||||
|
# test reverse
|
||||||
|
a = [3, 2, 2, 1]
|
||||||
|
a.sort(reverse=True)
|
||||||
|
assert a == [3, 2, 2, 1]
|
||||||
|
|
||||||
|
a = [1, 3, 2, 2]
|
||||||
|
a.sort(reverse=True)
|
||||||
|
assert a == [3, 2, 2, 1]
|
||||||
|
|
||||||
|
# test key
|
||||||
|
key = lambda x: -x
|
||||||
|
assert key(1) == -1
|
||||||
|
a = [1, 3, 2, 2]
|
||||||
|
a.sort(key=key)
|
||||||
|
assert a == [3, 2, 2, 1]
|
||||||
|
|
||||||
|
a = [1, 3, 2, 2]
|
||||||
|
a.sort(key=key, reverse=True)
|
||||||
|
assert a == [1, 2, 2, 3]
|
||||||
|
|
||||||
# test sorted
|
# test sorted
|
||||||
|
a = [8, 2, 4, 2, 9]
|
||||||
assert sorted(a) == [2, 2, 4, 8, 9]
|
assert sorted(a) == [2, 2, 4, 8, 9]
|
||||||
assert sorted(a, reverse=True) == [9, 8, 4, 2, 2]
|
assert sorted(a, reverse=True) == [9, 8, 4, 2, 2]
|
||||||
|
|
||||||
assert sorted(a, key=lambda x:-x, reverse=True) == [2, 2, 4, 8, 9]
|
def key(x): return -x;
|
||||||
|
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]
|
assert a == [8, 2, 4, 2, 9]
|
||||||
|
|
||||||
b = [(1, 2), (3, 3), (5, 1)]
|
# b = [(1, 2), (3, 3), (5, 1)]
|
||||||
b.sort(key=lambda x:x[1])
|
# b.sort(key=lambda x:x[1])
|
||||||
assert b == [(5, 1), (1, 2), (3,3)]
|
# assert b == [(5, 1), (1, 2), (3,3)]
|
||||||
|
|
||||||
# test cyclic reference
|
# test cyclic reference
|
||||||
a = []
|
# a = []
|
||||||
a.append(0)
|
# a.append(0)
|
||||||
a.append([1, 2, a])
|
# a.append([1, 2, a])
|
||||||
|
|
||||||
assert repr(a) == "[0, [1, 2, [...]]]"
|
# assert repr(a) == "[0, [1, 2, [...]]]"
|
||||||
|
|
||||||
# try:
|
# try:
|
||||||
# a.index(1, 1)
|
# a.index(1, 1)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user