This commit is contained in:
blueloveTH 2024-07-07 19:11:59 +08:00
parent ed02a2b172
commit 83c54fbeac
14 changed files with 212 additions and 72 deletions

View File

@ -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
} }

View File

@ -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; \

View File

@ -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();

View File

@ -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);

View File

@ -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);

View File

@ -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;

View File

@ -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;
} }

View File

@ -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*****************/
} }

View File

@ -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) {

View File

@ -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;
} }

View File

@ -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;
} }

View File

@ -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;
@ -75,6 +91,14 @@ void py_bindnativefunc(py_Ref obj, const char *name, py_CFunction 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);

View File

@ -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; }

View File

@ -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)