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,
int count,
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
}

View File

@ -75,10 +75,10 @@ c11_array c11_vector__submit(c11_vector* self);
(self)->count--; \
} while(0)
#define c11_vector__reverse(T, self, start, end) \
#define c11__reverse(T, self) \
do { \
T* p = (T*)(self)->data + (start); \
T* q = (T*)(self)->data + (end); \
T* p = (T*)(self)->data; \
T* q = (T*)(self)->data + (self)->count - 1; \
while(p < q) { \
T tmp = *p; \
*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);
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
void pk_object__register();

View File

@ -118,9 +118,7 @@ typedef struct FuncDecl {
typedef FuncDecl* FuncDecl_;
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__gc_mark(const FuncDecl* self);
// runtime function
typedef struct Function {
@ -128,6 +126,7 @@ typedef struct Function {
PyObject* module; // weak ref
PyObject* clazz; // weak ref
pk_NameDict* closure; // strong ref
py_CFunction cfunc; // wrapped C function
} Function;
void Function__ctor(Function* self, FuncDecl_ decl, PyObject* module);

View File

@ -89,7 +89,7 @@ void py_newfunction2(py_Ref out,
const char* sig,
enum BindType bt,
const char* docstring,
const py_Ref upvalue);
int slots);
// old style argc-based function
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))
// new style decl-based bindings
py_TmpRef py_bind(py_Ref obj, const char* sig, py_CFunction f);
py_TmpRef py_bind2(py_Ref obj,
void py_bind(py_Ref obj, const char* sig, py_CFunction f);
void py_bind2(py_Ref obj,
const char* sig,
py_CFunction f,
enum BindType bt,
const char* docstring,
const py_Ref upvalue);
int slots);
// old style argc-based bindings
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);

View File

@ -8,9 +8,10 @@ static bool merge(char* a,
char* b_end,
char* r,
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) {
int res = f_lt(a, b);
int res = f_lt(a, b, extra);
// check error
if(res == -1) return false;
if(res) {
@ -34,14 +35,15 @@ static bool merge(char* a,
bool c11__stable_sort(void* ptr_,
int count,
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
char *ptr = ptr_, *tmp = malloc(count * elem_size);
for(int seg = 1; seg < count; seg *= 2) {
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;
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) {
free(tmp);
return false;

View File

@ -5,7 +5,6 @@
#include "pocketpy/pocketpy.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);
#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_bool: c11_sbuf__write_cstr(&buf, p->_bool ? "True" : "False"); 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: {
pk_sprintf(&buf, "<class '%t'>", py_totype(p));
break;
@ -541,7 +554,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
case OP_BINARY_OP: {
py_Name op = byte.arg & 0xFF;
py_Name rop = byte.arg >> 8;
if(!stack_binaryop(self, op, rop)) goto __ERROR;
if(!pk_stack_binaryop(self, op, rop)) goto __ERROR;
POP();
*TOP() = self->last_retval;
DISPATCH();
@ -728,10 +741,7 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
return RES_RETURN;
}
/// Assumes [a, b] are on the stack, performs a binary op.
/// 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) {
bool pk_stack_binaryop(pk_VM* self, py_Name op, py_Name rop) {
// [a, b]
py_Ref magic = py_tpfindmagic(SECOND()->type, op);
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;
PUSH(lhs);
PUSH(rhs);
bool ok = stack_binaryop(self, op, rop);
bool ok = pk_stack_binaryop(self, op, rop);
STACK_SHRINK(2);
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]);
for(int j = 0; j < kwargc; j += 2) {
py_Name key = py_toint(&p1[j]);
for(int j = 0; j < kwargc; j++) {
py_Name key = py_toint(&p1[2 * j]);
int index = c11_smallmap_n2i__get(&decl->kw_to_index, key, -1);
// if key is an explicit key, set as local variable
if(index >= 0) {
buffer[index] = p1[j + 1];
buffer[index] = p1[2 * j + 1];
} else {
// otherwise, set as **kwargs if possible
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...]
// ^p0 ^p1 ^_sp
#if 0
// handle boundmethod, do a patch
if(p0->type == tp_bound_method) {
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;
// [unbound, self, args..., kwargs...]
}
#endif
py_Ref argv = py_isnil(p0 + 1) ? p0 + 2 : p0 + 1;
int argc2 = argv - p0;
if(p0->type == tp_function) {
/*****************_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;
// copy buffer back to stack
self->stack.sp = argv + co->nlocals;
for(int j = 0; j < co->nlocals; j++)
argv[j] = self->__vectorcall_buffer[j];
break;
memcpy(argv, self->__vectorcall_buffer, co->nlocals * sizeof(py_TValue));
// submit the call
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:
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";
TypeError(fmt, co->name, fn->decl->args.count, argc2);
TypeError(fmt, co->name->data, fn->decl->args.count, p1 - argv);
return RES_ERROR;
}
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;
// initialize local variables to PY_NIL
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:
assert(false);
break;
@ -400,11 +410,7 @@ pk_FrameResult pk_VM__vectorcall(pk_VM* self, uint16_t argc, uint16_t kwargc, bo
default: c11__unreachedable();
};
// simple or normal
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);
c11__unreachedable();
/*****************_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;
}
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* self = malloc(sizeof(FuncDecl));
self->rc.count = 1;
@ -33,13 +40,6 @@ FuncDecl_ FuncDecl__rcnew(pk_SourceData_ src, c11_sv name) {
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) {
c11_smallmap_n2i__set(&self->kw_to_index, key, index);
FuncDeclKwArg item = {index, key, *value};
@ -99,6 +99,7 @@ void Function__ctor(Function* self, FuncDecl_ decl, PyObject* module) {
self->module = module;
self->clazz = NULL;
self->closure = NULL;
self->cfunc = NULL;
}
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", "");
}
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_Ref builtins = py_newmodule("builtins", NULL);
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, "iter", _py_builtins__iter);
py_bindnativefunc(builtins, "next", _py_builtins__next);
py_bind(builtins, "sorted(iterable, key=None, reverse=False)", _py_builtins__sorted);
return *builtins;
}

View File

@ -107,6 +107,16 @@ static bool _py_list__new__(int argc, py_Ref argv) {
return true;
}
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 list = py_pushtmp();
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) {
PY_CHECK_ARGC(1);
List* self = py_touserdata(py_arg(0));
for(int i = 0; i < self->count / 2; i++) {
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);
}
c11__reverse(py_TValue, self);
py_newnone(py_retval());
return true;
}
@ -319,10 +325,44 @@ static bool _py_list__insert(int argc, py_Ref argv) {
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) {
PY_CHECK_ARGC(1);
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());
return true;
}
@ -355,5 +395,7 @@ py_Type pk_list__register() {
py_bindmethod(type, "pop", _py_list__pop);
py_bindmethod(type, "insert", _py_list__insert);
py_bindmethod(type, "sort", _py_list__sort);
py_bind(py_tpobject(type), "sort(self, key=None, reverse=False)", _py_list__sort);
return type;
}

View File

@ -5,6 +5,7 @@
#include "pocketpy/common/utils.h"
#include "pocketpy/objects/object.h"
#include "pocketpy/interpreter/vm.h"
#include "pocketpy/compiler/compiler.h"
void py_newint(py_Ref out, int64_t val) {
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_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,
@ -51,7 +51,23 @@ void py_newfunction2(py_Ref out,
const char* sig,
enum BindType bt,
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) {
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);
}
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) {
py_newobject(out, tp_slice, 3, 0);
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) {
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; }

View File

@ -98,23 +98,51 @@ a = [0, 0, 0, 0, 1, 1, 3, -1]
assert a.sort() == None
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
a = [8, 2, 4, 2, 9]
assert sorted(a) == [2, 2, 4, 8, 9]
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]
b = [(1, 2), (3, 3), (5, 1)]
b.sort(key=lambda x:x[1])
assert b == [(5, 1), (1, 2), (3,3)]
# b = [(1, 2), (3, 3), (5, 1)]
# b.sort(key=lambda x:x[1])
# assert b == [(5, 1), (1, 2), (3,3)]
# test cyclic reference
a = []
a.append(0)
a.append([1, 2, a])
# a = []
# a.append(0)
# a.append([1, 2, a])
assert repr(a) == "[0, [1, 2, [...]]]"
# assert repr(a) == "[0, [1, 2, [...]]]"
# try:
# a.index(1, 1)