some test

This commit is contained in:
blueloveTH 2024-06-30 14:10:17 +08:00
parent cde78ea481
commit 4860c08e03
6 changed files with 163 additions and 148 deletions

View File

@ -10,12 +10,18 @@ typedef uint16_t py_Name;
typedef int16_t py_Type;
typedef py_TValue* py_Ref;
typedef struct py_Str py_Str;
typedef int (*py_CFunction)(int argc, py_Ref argv);
typedef struct py_Error {
py_Type type;
} py_Error;
/// Native function signature.
/// @param argc number of arguments.
/// @param argv array of arguments. Use `py_arg(i)` macro to get the i-th argument.
/// @param out output reference to the result.
/// @return true if the function is successful.
typedef bool (*py_CFunction)(int argc, py_TValue* argv, py_TValue* out);
typedef enum BindType {
BindType_FUNCTION,
BindType_STATICMETHOD,
@ -64,6 +70,8 @@ void py_newnativefunc2(py_Ref out,
const char* docstring,
const py_Ref upvalue);
void py_newnotimplemented(py_Ref out);
/// Create a new object.
/// @param out output reference.
/// @param type type of the object.
@ -79,7 +87,6 @@ void py_pushstrn(const char*, int);
void py_pushnone();
void py_pushnull();
void py_push_notimplemented();
/************* Type Cast *************/
int64_t py_toint(const py_Ref);
@ -120,9 +127,9 @@ bool py_getattr(const py_Ref self, py_Name name, py_Ref out);
/// Gets the unbound method of the object.
bool py_getunboundmethod(const py_Ref self, py_Name name, bool fallback, py_Ref out, py_Ref out_self);
/// Sets the attribute of the object.
int py_setattr(py_Ref self, py_Name name, const py_Ref val);
bool py_setattr(py_Ref self, py_Name name, const py_Ref val);
/// Deletes the attribute of the object.
int py_delattr(py_Ref self, py_Name name);
bool py_delattr(py_Ref self, py_Name name);
/// Equivalent to `*dst = *src`.
void py_assign(py_Ref dst, const py_Ref src);
@ -163,14 +170,18 @@ void py_Error__print(py_Error*);
/************* Operators *************/
int py_eq(const py_Ref, const py_Ref);
int py_le(const py_Ref, const py_Ref);
int py_hash(const py_Ref, int64_t* out);
bool py_hash(const py_Ref, int64_t* out);
int py_str(const py_Ref);
int py_repr(const py_Ref);
bool py_str(const py_Ref, py_Ref out);
bool py_repr(const py_Ref, py_Ref out);
int py_vectorcall(int argc, int kwargc);
int py_call(py_Ref f, ...);
int py_callmethod(py_Ref self, py_Name name, ...);
/// A stack operation that calls a function.
/// It consumes `argc + kwargc` arguments from the stack.
/// The result will be set to `vm->last_retval`.
int pk_vectorcall(int argc, int kwargc, bool op_call);
bool py_call(py_Ref f, ...);
bool py_callmethod(py_Ref self, py_Name name, ...);
#define py_isnull(self) ((self)->type == 0)

View File

@ -38,28 +38,19 @@ int NameError(py_Name name) { return -1; }
#define POPX() (*--self->stack.sp)
#define SP() (self->stack.sp)
static void pack_stack_values(int n) {
assert(n > 1);
pk_VM* self = pk_current_vm;
py_TValue tmp;
py_newtuple(&tmp, n);
for(int i = 0; i < n; i++)
py_tuple__setitem(&tmp, i, SP() - n + i);
STACK_SHRINK(n);
PUSH(&tmp);
}
// n == 1 is the most likely result
#define HANDLE_RETVAL(n) \
if(n != 1) { \
if(n == 0) { \
PUSH(&self->None); \
} else if(n > 1) { \
pack_stack_values(n); \
} else { \
goto __ERROR; \
#define vectorcall_opcall(n) \
do { \
pk_FrameResult res = pk_vectorcall(n, 0, true); \
switch(res) { \
case RES_RETURN: PUSH(&self->last_retval); break; \
case RES_CALL: \
frame = self->top_frame; \
PUSH(&self->last_retval); \
goto __NEXT_FRAME; \
case RES_ERROR: goto __ERROR; \
default: PK_UNREACHABLE(); \
} \
}
} while(0)
pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
Frame* frame = self->top_frame;
@ -113,10 +104,8 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
}
case OP_PRINT_EXPR:
if(TOP()->type != tp_none_type) {
int err = py_repr(TOP());
if(err) goto __ERROR;
self->_stdout("%s\n", py_tostr(TOP()));
POP();
py_TValue tmp;
if(py_repr(TOP(), &tmp)) self->_stdout("%s\n", py_tostr(&tmp));
}
POP();
DISPATCH();
@ -258,11 +247,21 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
}
case OP_LOAD_SUBSCR: {
// [a, b] -> a[b]
int n = py_callmethod(SECOND(), __getitem__, TOP());
HANDLE_RETVAL(n);
// [a, b, retval]
*THIRD() = *TOP(); // [retval, b, retval]
STACK_SHRINK(2); // [retval]
pk_TypeInfo* ti = pk_tpinfo(SECOND());
if(ti->m__getitem__) {
if(!ti->m__getitem__(2, SECOND(), SECOND())) goto __ERROR;
} else {
if(!py_callmethod(SECOND(), __getitem__, TOP())) goto __ERROR;
// // [a, b] -> [?, a, b]
// PUSH(TOP()); // [a, b, b]
// *SECOND() = *THIRD(); // [a, a, b]
// bool ok = py_getunboundmethod(SECOND(), __getitem__, false, THIRD(),
// SECOND()); if(!ok) {
// // __getitem__ not found
// goto __ERROR;
// }
// py_vectorcall(2, 0, );
}
DISPATCH();
}
case OP_STORE_FAST: frame->locals[byte.arg] = POPX(); DISPATCH();
@ -300,17 +299,18 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
}
case OP_STORE_SUBSCR: {
// [val, a, b] -> a[b] = val
py_TValue* backup = SP();
pk_TypeInfo* ti = pk_tpinfo(SECOND());
PUSH(THIRD()); // [val, a, b, val]
if(ti->m__setitem__) {
if(!ti->m__setitem__(3, THIRD(), FOURTH())) goto __ERROR;
STACK_SHRINK(3); // [retval]
} else {
bool ok = py_getunboundmethod(THIRD(), __setitem__, false, FOURTH(), THIRD());
if(!ok) {
// __setitem__ not found
goto __ERROR;
}
if(!ok) goto __ERROR;
// [__setitem__, self, b, val]
int n = py_vectorcall(3, 0);
if(n < 0) goto __ERROR;
SP() = backup; // discard retval if any
vectorcall_opcall(3);
POP(); // discard retval
}
DISPATCH();
}
case OP_DELETE_FAST: {
@ -359,32 +359,36 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
}
case OP_DELETE_ATTR: {
int err = py_delattr(TOP(), byte.arg);
if(err) goto __ERROR;
POP();
if(!py_delattr(TOP(), byte.arg)) goto __ERROR;
DISPATCH();
}
case OP_DELETE_SUBSCR: {
// [a, b] -> del a[b]
py_Ref backup = SP();
int n = py_callmethod(SECOND(), __delitem__, TOP());
if(n < 0) { goto __ERROR; }
SP() = backup; // discard retval if any
pk_TypeInfo* ti = pk_tpinfo(SECOND());
if(ti->m__delitem__) {
if(!ti->m__delitem__(2, SECOND(), SECOND())) goto __ERROR;
POP();
} else {
PUSH(TOP()); // [a, b, b]
*SECOND() = *THIRD(); // [a, a, b]
bool ok = py_getunboundmethod(SECOND(), __delitem__, false, THIRD(), SECOND());
// [__delitem__, self, b]
if(!ok) goto __ERROR;
vectorcall_opcall(2);
POP(); // discard retval
}
DISPATCH();
}
/*****************************************/
case OP_BUILD_LONG: {
py_Ref _0 = py_getdict(&self->builtins, pk_id_long);
assert(_0 != NULL);
int n = py_call(_0, TOP());
if(n < 0) goto __ERROR;
assert(n == 1);
// [x, long(x)]
*SECOND() = *TOP(); // [long(x), long(x)]
POP(); // [long(x)]
// [x]
py_Ref f = py_getdict(&self->builtins, pk_id_long);
assert(f != NULL);
if(!py_call(f, TOP())) goto __ERROR;
*TOP() = self->last_retval;
DISPATCH();
}
@ -393,19 +397,15 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
assert(_0 != NULL);
py_TValue zero;
py_newint(&zero, 0);
int n = py_call(_0, &zero, TOP());
if(n < 0) goto __ERROR;
assert(n == 1);
// [x, complex(0, x)]
*SECOND() = *TOP(); // [complex(0, x), complex(0, x)]
POP(); // [complex(0, x)]
if(!py_call(_0, &zero, TOP())) goto __ERROR;
*TOP() = self->last_retval;
DISPATCH();
}
case OP_BUILD_BYTES: {
py_Str* s = py_touserdata(TOP());
unsigned char* p = (unsigned char*)malloc(s->size);
memcpy(p, py_Str__data(s), s->size);
py_newbytes(SP()++, p, s->size);
py_newbytes(TOP(), p, s->size);
DISPATCH();
}
case OP_BUILD_TUPLE: {
@ -461,14 +461,13 @@ pk_FrameResult pk_VM__run_top_frame(pk_VM* self) {
// }
/**************************** */
case OP_RETURN_VALUE: {
py_TValue tmp = byte.arg == BC_NOARG ? POPX() : self->None;
self->last_retval = byte.arg == BC_NOARG ? POPX() : self->None;
pk_VM__pop_frame(self);
if(frame == base_frame) { // [ frameBase<- ]
self->last_retval = tmp;
return RES_RETURN;
} else {
frame = self->top_frame;
PUSH(&tmp);
PUSH(&self->last_retval);
goto __NEXT_FRAME;
}
DISPATCH();

View File

@ -40,29 +40,29 @@
// }
#define DEF_NUM_BINARY_OP(name, op) \
static int _py_int##name(int argc, py_Ref argv) { \
static bool _py_int##name(int argc, py_Ref argv, py_Ref out) { \
if(py_isint(&argv[1])) { \
int64_t lhs = py_toint(&argv[0]); \
int64_t rhs = py_toint(&argv[1]); \
py_pushint(lhs op rhs); \
py_newint(out, lhs op rhs); \
} else if(py_isfloat(&argv[1])) { \
int64_t lhs = py_toint(&argv[0]); \
double rhs = py_tofloat(&argv[1]); \
py_pushfloat(lhs op rhs); \
py_newfloat(out, lhs op rhs); \
} else { \
py_push_notimplemented(); \
py_newnotimplemented(out); \
} \
return 1; \
return true; \
} \
static int _py_float##name(int argc, py_Ref argv) { \
static bool _py_float##name(int argc, py_Ref argv, py_Ref out) { \
double lhs = py_tofloat(&argv[0]); \
double rhs; \
if(py_castfloat(&argv[1], &rhs)) { \
py_pushfloat(lhs op rhs); \
py_newfloat(out, lhs op rhs); \
} else { \
py_push_notimplemented(); \
py_newnotimplemented(out); \
} \
return 1; \
return true; \
}
DEF_NUM_BINARY_OP(__add__, +)
@ -77,51 +77,51 @@ DEF_NUM_BINARY_OP(__ge__, >=)
#undef DEF_NUM_BINARY_OP
static int _py_int__neg__(int argc, py_Ref argv) {
static bool _py_int__neg__(int argc, py_Ref argv, py_Ref out) {
int64_t val = py_toint(&argv[0]);
py_pushint(-val);
return 1;
py_newint(out, -val);
return true;
}
static int _py_float__neg__(int argc, py_Ref argv) {
static bool _py_float__neg__(int argc, py_Ref argv, py_Ref out) {
double val = py_tofloat(&argv[0]);
py_pushfloat(-val);
return 1;
py_newfloat(out, -val);
return true;
}
static int _py_int__truediv__(int argc, py_Ref argv) {
static bool _py_int__truediv__(int argc, py_Ref argv, py_Ref out) {
int64_t lhs = py_toint(&argv[0]);
double rhs;
if(py_castfloat(&argv[1], &rhs)) {
py_pushfloat(lhs / rhs);
py_newfloat(out, lhs / rhs);
} else {
py_push_notimplemented();
py_newnotimplemented(out);
}
return 1;
return true;
}
static int _py_float__truediv__(int argc, py_Ref argv) {
static bool _py_float__truediv__(int argc, py_Ref argv, py_Ref out) {
double lhs = py_tofloat(&argv[0]);
double rhs;
if(py_castfloat(&argv[1], &rhs)) {
py_pushfloat(lhs / rhs);
py_newfloat(out, lhs / rhs);
} else {
py_push_notimplemented();
py_newnotimplemented(out);
}
return 1;
return true;
}
static int _py_number__pow__(int argc, py_Ref argv) {
#define ZeroDivisionError(msg) false
static bool _py_number__pow__(int argc, py_Ref argv, py_Ref out) {
if(py_isint(&argv[0]) && py_isint(&argv[1])) {
int64_t lhs = py_toint(&argv[0]);
int64_t rhs = py_toint(&argv[1]);
if(rhs < 0) {
if(lhs == 0) {
// py_pusherror("0.0 cannot be raised to a negative power");
// TODO: ZeroDivisionError
return -1;
return ZeroDivisionError("0.0 cannot be raised to a negative power");
} else {
py_pushfloat(pow(lhs, rhs));
py_newfloat(out, pow(lhs, rhs));
}
} else {
int64_t ret = 1;
@ -130,51 +130,51 @@ static int _py_number__pow__(int argc, py_Ref argv) {
lhs *= lhs;
rhs >>= 1;
}
py_pushint(ret);
py_newint(out, ret);
}
} else {
double lhs, rhs;
py_castfloat(&argv[0], &lhs);
if(py_castfloat(&argv[1], &rhs)) {
py_pushfloat(pow(lhs, rhs));
py_newfloat(out, pow(lhs, rhs));
} else {
py_push_notimplemented();
py_newnotimplemented(out);
}
}
return 1;
return true;
}
static int _py_int__floordiv__(int argc, py_Ref argv) {
static bool _py_int__floordiv__(int argc, py_Ref argv, py_Ref out) {
int64_t lhs = py_toint(&argv[0]);
if(py_isint(&argv[1])) {
int64_t rhs = py_toint(&argv[1]);
if(rhs == 0) return -1;
py_pushint(lhs / rhs);
py_newint(out, lhs / rhs);
} else {
py_push_notimplemented();
py_newnotimplemented(out);
}
return 1;
return true;
}
static int _py_int__mod__(int argc, py_Ref argv) {
static bool _py_int__mod__(int argc, py_Ref argv, py_Ref out) {
int64_t lhs = py_toint(&argv[0]);
if(py_isint(&argv[1])) {
int64_t rhs = py_toint(&argv[1]);
if(rhs == 0) return -1;
py_pushint(lhs % rhs);
if(rhs == 0) return ZeroDivisionError("integer division or modulo by zero");
py_newint(out, lhs % rhs);
} else {
py_push_notimplemented();
py_newnotimplemented(out);
}
return 1;
return true;
}
static int _py_int__invert__(int argc, py_Ref argv) {
static bool _py_int__invert__(int argc, py_Ref argv, py_Ref out) {
int64_t val = py_toint(&argv[0]);
py_pushint(~val);
return 1;
py_newint(out, ~val);
return true;
}
static int _py_int__bit_length(int argc, py_Ref argv) {
static bool _py_int__bit_length(int argc, py_Ref argv, py_Ref out) {
int64_t x = py_toint(py_arg(0));
if(x < 0) x = -x;
int bits = 0;
@ -182,20 +182,20 @@ static int _py_int__bit_length(int argc, py_Ref argv) {
x >>= 1;
bits++;
}
py_pushint(bits);
return 1;
py_newint(out, bits);
return true;
}
#define DEF_INT_BITWISE_OP(name, op) \
static int _py_int##name(int argc, py_Ref argv) { \
static bool _py_int##name(int argc, py_Ref argv, py_Ref out) { \
int64_t lhs = py_toint(&argv[0]); \
if(py_isint(&argv[1])) { \
int64_t rhs = py_toint(&argv[1]); \
py_pushint(lhs op rhs); \
py_newint(out, lhs op rhs); \
} else { \
py_push_notimplemented(); \
py_newnotimplemented(out); \
} \
return 1; \
return true; \
}
DEF_INT_BITWISE_OP(__and__, &)

View File

@ -5,24 +5,23 @@ int py_eq(const py_Ref lhs, const py_Ref rhs) { return 0; }
int py_le(const py_Ref lhs, const py_Ref rhs) { return 0; }
int py_hash(const py_Ref val, int64_t* out) { return 0; }
bool py_hash(const py_Ref val, int64_t* out) { return 0; }
int py_str(const py_Ref val) { return 0; }
bool py_str(const py_Ref val, py_Ref out) { return 0; }
int py_repr(const py_Ref val) {
const pk_TypeInfo* ti = c11__at(pk_TypeInfo, &pk_current_vm->types, val->type);
if(ti->m__repr__) return ti->m__repr__(1, val);
return py_callmethod(val, __repr__);
}
bool py_getattr(const py_Ref self, py_Name name, py_Ref out){
bool py_repr(const py_Ref val, py_Ref out) {
const pk_TypeInfo* ti = pk_tpinfo(val);
if(ti->m__repr__) return ti->m__repr__(1, val, out);
bool ok = py_callmethod(val, __repr__);
if(ok) {
*out = pk_current_vm->last_retval;
return true;
}
int py_setattr(py_Ref self, py_Name name, const py_Ref val){
return -1;
return false;
}
int py_delattr(py_Ref self, py_Name name){
return -1;
}
bool py_getattr(const py_Ref self, py_Name name, py_Ref out) { return true; }
bool py_setattr(py_Ref self, py_Name name, const py_Ref val) { return -1; }
bool py_delattr(py_Ref self, py_Name name) { return -1; }

View File

@ -80,6 +80,11 @@ void py_newnativefunc2(py_Ref out,
const char* docstring,
const py_Ref upvalue) {}
void py_newnotimplemented(py_Ref out) {
pk_VM* vm = pk_current_vm;
*out = vm->NotImplemented;
}
void py_newobject(py_Ref out, py_Type type, int slots, int udsize){
pk_ManagedHeap* heap = &pk_current_vm->heap;
PyObject* obj = pk_ManagedHeap__gcnew(heap, type, slots, udsize);
@ -103,7 +108,3 @@ void py_pushnone() { py_newnone(pk_current_vm->stack.sp++); }
void py_pushnull() { py_newnull(pk_current_vm->stack.sp++); }
void py_push_notimplemented() {
pk_VM* vm = pk_current_vm;
*vm->stack.sp++ = vm->NotImplemented;
}

View File

@ -47,18 +47,23 @@ int py_eval(const char* source, py_Ref out) {
PK_UNREACHABLE();
}
int py_call(py_Ref callable, ...){
bool py_call(py_Ref callable, ...){
return -1;
}
int py_callmethod(py_Ref self, py_Name name, ...){
bool py_callmethod(py_Ref self, py_Name name, ...){
return -1;
}
int py_vectorcall(int argc, int kwargc){
int pk_vectorcall(int argc, int kwargc, bool op_call){
return -1;
}
bool py_getunboundmethod(const py_Ref self, py_Name name, bool fallback, py_Ref out, py_Ref out_self){
return -1;
}
pk_TypeInfo* pk_tpinfo(const py_Ref self){
pk_VM* vm = pk_current_vm;
return c11__at(pk_TypeInfo, &vm->types, self->type);
}