This commit is contained in:
blueloveTH 2023-02-27 23:39:39 +08:00
parent 0926341e12
commit 6a82644f9a
6 changed files with 138 additions and 149 deletions

View File

@ -180,7 +180,7 @@ PyVar VM::run_frame(Frame* frame){
if(asBool(expr) != True) _error("AssertionError", msg);
} continue;
case OP_EXCEPTION_MATCH: {
const auto& e = PyException_AS_C(frame->top());
const auto& e = py_cast<Exception>(this, frame->top());
StrName name = frame->co->names[byte.arg].first;
frame->push(PyBool(e.match_type(name)));
} continue;
@ -212,10 +212,10 @@ PyVar VM::run_frame(Frame* frame){
case OP_DUP_TOP_VALUE: frame->push(frame->top_value(this)); continue;
case OP_UNARY_STAR: {
if(byte.arg > 0){ // rvalue
frame->top() = PyStarWrapper({frame->top_value(this), true});
frame->top() = py_object(this, StarWrapper(frame->top_value(this), true));
}else{
PyRef_AS_C(frame->top()); // check ref
frame->top() = PyStarWrapper({frame->top(), false});
frame->top() = py_object(this, StarWrapper(frame->top(), false));
}
} continue;
case OP_CALL_KWARGS_UNPACK: case OP_CALL_KWARGS: {
@ -286,7 +286,7 @@ PyVar VM::run_frame(Frame* frame){
Slice s;
if(start != None) { s.start = (int)py_cast_v<i64>(this, start);}
if(stop != None) { s.stop = (int)py_cast_v<i64>(this, stop);}
frame->push(PySlice(s));
frame->push(py_object(this, s));
} continue;
case OP_IMPORT_NAME: {
StrName name = frame->co->names[byte.arg].first;

View File

@ -46,6 +46,7 @@ struct Function {
struct BoundMethod {
PyVar obj;
PyVar method;
BoundMethod(const PyVar& obj, const PyVar& method) : obj(obj), method(method) {}
};
struct Range {

View File

@ -172,7 +172,7 @@ void init_builtins(VM* _vm) {
case 3: r.start = py_cast_v<i64>(vm, args[0]); r.stop = py_cast_v<i64>(vm, args[1]); r.step = py_cast_v<i64>(vm, args[2]); break;
default: vm->TypeError("expected 1-3 arguments, but got " + std::to_string(args.size()));
}
return vm->PyRange(r);
return py_object(vm, r);
});
_vm->bind_method<0>("range", "__iter__", CPP_LAMBDA(
@ -338,7 +338,7 @@ void init_builtins(VM* _vm) {
const Str& self (py_cast<Str>(vm, args[0]));
if(is_type(args[1], vm->tp_slice)){
Slice s = vm->PySlice_AS_C(args[1]);
Slice s = _py_cast_v<Slice>(vm, args[1]);
s.normalize(self.u8_length());
return py_object(vm, self.u8_substr(s.start, s.stop));
}
@ -458,7 +458,7 @@ void init_builtins(VM* _vm) {
const List& self = py_cast<List>(vm, args[0]);
if(is_type(args[1], vm->tp_slice)){
Slice s = vm->PySlice_AS_C(args[1]);
Slice s = _py_cast_v<Slice>(vm, args[1]);
s.normalize(self.size());
List new_list;
for(size_t i = s.start; i < s.stop; i++) new_list.push_back(self[i]);
@ -500,7 +500,7 @@ void init_builtins(VM* _vm) {
const Tuple& self = py_cast<Tuple>(vm, args[0]);
if(is_type(args[1], vm->tp_slice)){
Slice s = vm->PySlice_AS_C(args[1]);
Slice s = _py_cast_v<Slice>(vm, args[1]);
s.normalize(self.size());
List new_list;
for(size_t i = s.start; i < s.stop; i++) new_list.push_back(self[i]);
@ -608,7 +608,7 @@ void add_module_dis(VM* vm){
PyVar mod = vm->new_module("dis");
vm->bind_func<1>(mod, "dis", [](VM* vm, Args& args) {
PyVar f = args[0];
if(is_type(f, vm->tp_bound_method)) f = vm->PyBoundMethod_AS_C(args[0]).method;
if(is_type(f, vm->tp_bound_method)) f = py_cast<BoundMethod>(vm, args[0]).method;
CodeObject_ code = py_cast<Function>(vm, f).code;
(*vm->_stdout) << vm->disassemble(code);
return vm->None;
@ -693,7 +693,7 @@ struct ReMatch {
vm->bind_method<0>(type, "span", [](VM* vm, Args& args) {
auto& self = vm->_cast<ReMatch>(args[0]);
return py_object(vm, pkpy::Args({ py_object(vm, self.start), py_object(vm, self.end) }));
return py_object(vm, two_args(py_object(vm, self.start), py_object(vm, self.end)));
});
vm->bind_method<1>(type, "group", [](VM* vm, Args& args) {

View File

@ -127,7 +127,7 @@ struct TupleRef : BaseRef {
for(int i=0; i<objs.size(); i++){
PyVarOrNull x;
if(is_type(objs[i], vm->tp_star_wrapper)){
auto& star = vm->PyStarWrapper_AS_C(objs[i]);
auto& star = _py_cast<StarWrapper>(vm, objs[i]);
if(star.rvalue) vm->ValueError("can't use starred expression here");
if(i != objs.size()-1) vm->ValueError("* can only be used at the end");
auto ref = vm->PyRef_AS_C(star.obj);

View File

@ -26,12 +26,6 @@ namespace pkpy {
for(int i=0; i<_size; i++) _args[i] = other._args[i];
}
Args(std::initializer_list<PyVar> a){
_alloc(a.size());
int i = 0;
for(auto& v: a) _args[i++] = v;
}
Args(Args&& other) noexcept {
this->_args = other._args;
this->_size = other._size;

258
src/vm.h
View File

@ -5,14 +5,6 @@
namespace pkpy{
#define DEF_NATIVE(type, ctype, ptype) \
inline ctype& Py##type##_AS_C(const PyVar& obj) { \
check_type(obj, ptype); \
return OBJ_GET(ctype, obj); \
} \
inline PyVar Py##type(const ctype& value) { return new_object(ptype, value);} \
inline PyVar Py##type(ctype&& value) { return new_object(ptype, std::move(value));}
#define DEF_NATIVE_2(ctype, ptype) \
template<> ctype& py_cast<ctype>(VM* vm, const PyVar& obj) { \
vm->check_type(obj, vm->ptype); \
@ -166,48 +158,6 @@ public:
return _exec();
}
PyVar _exec(){
Frame* frame = top_frame();
i64 base_id = frame->id;
PyVar ret = nullptr;
bool need_raise = false;
while(true){
if(frame->id < base_id) UNREACHABLE();
try{
if(need_raise){ need_raise = false; _raise(); }
ret = run_frame(frame);
if(ret == _py_op_yield) return _py_op_yield;
if(ret != _py_op_call){
if(frame->id == base_id){ // [ frameBase<- ]
callstack.pop();
return ret;
}else{
callstack.pop();
frame = callstack.top().get();
frame->push(ret);
}
}else{
frame = callstack.top().get(); // [ frameBase, newFrame<- ]
}
}catch(HandledException& e){
continue;
}catch(UnhandledException& e){
PyVar obj = frame->pop();
Exception& _e = PyException_AS_C(obj);
_e.st_push(frame->snapshot());
callstack.pop();
if(callstack.empty()) throw _e;
frame = callstack.top().get();
frame->push(obj);
if(frame->id < base_id) throw ToBeRaisedException();
need_raise = true;
}catch(ToBeRaisedException& e){
need_raise = true;
}
}
}
Type _new_type_object(StrName name, Type base=0) {
PyVar obj = make_sp<PyObject, Py_<Type>>(tp_type, _all_types.size());
setattr(obj, __base__, _t(base));
@ -245,70 +195,6 @@ public:
return new_object(T::_type(this), T(std::forward<Args>(args)...));
}
PyVarOrNull getattr(const PyVar& obj, StrName name, bool throw_err=true) {
PyVar* val;
PyObject* cls;
if(is_type(obj, tp_super)){
const PyVar* root = &obj;
int depth = 1;
while(true){
root = &OBJ_GET(PyVar, *root);
if(!is_type(*root, tp_super)) break;
depth++;
}
cls = _t(*root).get();
for(int i=0; i<depth; i++) cls = cls->attr(__base__).get();
val = (*root)->attr().try_get(name);
if(val != nullptr) return *val;
}else{
if(!obj.is_tagged() && obj->is_attr_valid()){
val = obj->attr().try_get(name);
if(val != nullptr) return *val;
}
cls = _t(obj).get();
}
while(cls != None.get()) {
val = cls->attr().try_get(name);
if(val != nullptr){
PyVarOrNull descriptor = getattr(*val, __get__, false);
if(descriptor != nullptr){
return call(descriptor, one_arg(obj));
}
if(is_type(*val, tp_function) || is_type(*val, tp_native_function)){
return PyBoundMethod({obj, *val});
}else{
return *val;
}
}
cls = cls->attr(__base__).get();
}
if(throw_err) AttributeError(obj, name);
return nullptr;
}
template<typename T>
inline void setattr(PyVar& obj, StrName name, T&& value) {
if(obj.is_tagged()) TypeError("cannot set attribute");
PyObject* p = obj.get();
while(p->type == tp_super) p = static_cast<PyVar*>(p->value())->get();
if(!p->is_attr_valid()) TypeError("cannot set attribute");
p->attr().set(name, std::forward<T>(value));
}
template<int ARGC>
void bind_method(PyVar obj, Str funcName, NativeFuncRaw fn) {
check_type(obj, tp_type);
setattr(obj, funcName, PyNativeFunc(NativeFunc(fn, ARGC, true)));
}
template<int ARGC>
void bind_func(PyVar obj, Str funcName, NativeFuncRaw fn) {
setattr(obj, funcName, PyNativeFunc(NativeFunc(fn, ARGC, false)));
}
template<int ARGC>
void bind_func(Str typeName, Str funcName, NativeFuncRaw fn) {
bind_func<ARGC>(_types[typeName], funcName, fn);
@ -361,13 +247,6 @@ public:
return static_cast<BaseIter*>(obj->value());
}
DEF_NATIVE(NativeFunc, NativeFunc, tp_native_function)
DEF_NATIVE(BoundMethod, BoundMethod, tp_bound_method)
DEF_NATIVE(Range, Range, tp_range)
DEF_NATIVE(Slice, Slice, tp_slice)
DEF_NATIVE(Exception, Exception, tp_exception)
DEF_NATIVE(StarWrapper, StarWrapper, tp_star_wrapper)
// there is only one True/False, so no need to copy them!
inline bool PyBool_AS_C(const PyVar& obj){
check_type(obj, tp_bool);
@ -381,15 +260,6 @@ public:
_error(Exception(name, msg));
}
void _error(Exception e){
if(callstack.empty()){
e.is_re = false;
throw e;
}
top_frame()->push(PyException(e));
_raise();
}
void _raise(){
bool ok = top_frame()->jump_to_exception_handler();
if(ok) throw HandledException();
@ -461,6 +331,15 @@ public:
void init_builtin_types();
PyVar call(const PyVar& _callable, Args args, const Args& kwargs, bool opCall);
void unpack_args(Args& args);
PyVarOrNull getattr(const PyVar& obj, StrName name, bool throw_err=true);
template<typename T>
void setattr(PyVar& obj, StrName name, T&& value);
template<int ARGC>
void bind_method(PyVar obj, Str funcName, NativeFuncRaw fn);
template<int ARGC>
void bind_func(PyVar obj, Str funcName, NativeFuncRaw fn);
void _error(Exception e);
PyVar _exec();
template<typename P>
PyVarRef PyRef(P&& value);
@ -790,7 +669,7 @@ PyVar VM::call(const PyVar& _callable, Args args, const Args& kwargs, bool opCal
const PyVar* callable = &_callable;
if(is_type(*callable, tp_bound_method)){
auto& bm = PyBoundMethod_AS_C((*callable));
auto& bm = py_cast<BoundMethod>(this, *callable);
callable = &bm.method; // get unbound method
args.extend_self(bm.obj);
}
@ -855,7 +734,7 @@ void VM::unpack_args(Args& args){
List unpacked;
for(int i=0; i<args.size(); i++){
if(is_type(args[i], tp_star_wrapper)){
auto& star = PyStarWrapper_AS_C(args[i]);
auto& star = _py_cast<StarWrapper>(this, args[i]);
if(!star.rvalue) UNREACHABLE();
PyVar list = asList(star.obj);
List& list_c = py_cast<List>(this, list);
@ -867,4 +746,119 @@ void VM::unpack_args(Args& args){
args = Args::from_list(std::move(unpacked));
}
PyVarOrNull VM::getattr(const PyVar& obj, StrName name, bool throw_err) {
PyVar* val;
PyObject* cls;
if(is_type(obj, tp_super)){
const PyVar* root = &obj;
int depth = 1;
while(true){
root = &OBJ_GET(PyVar, *root);
if(!is_type(*root, tp_super)) break;
depth++;
}
cls = _t(*root).get();
for(int i=0; i<depth; i++) cls = cls->attr(__base__).get();
val = (*root)->attr().try_get(name);
if(val != nullptr) return *val;
}else{
if(!obj.is_tagged() && obj->is_attr_valid()){
val = obj->attr().try_get(name);
if(val != nullptr) return *val;
}
cls = _t(obj).get();
}
while(cls != None.get()) {
val = cls->attr().try_get(name);
if(val != nullptr){
PyVarOrNull descriptor = getattr(*val, __get__, false);
if(descriptor != nullptr){
return call(descriptor, one_arg(obj));
}
if(is_type(*val, tp_function) || is_type(*val, tp_native_function)){
return py_object(this, BoundMethod(obj, *val));
}else{
return *val;
}
}
cls = cls->attr(__base__).get();
}
if(throw_err) AttributeError(obj, name);
return nullptr;
}
template<typename T>
void VM::setattr(PyVar& obj, StrName name, T&& value) {
if(obj.is_tagged()) TypeError("cannot set attribute");
PyObject* p = obj.get();
while(p->type == tp_super) p = static_cast<PyVar*>(p->value())->get();
if(!p->is_attr_valid()) TypeError("cannot set attribute");
p->attr().set(name, std::forward<T>(value));
}
template<int ARGC>
void VM::bind_method(PyVar obj, Str funcName, NativeFuncRaw fn) {
check_type(obj, tp_type);
setattr(obj, funcName, py_object(this, NativeFunc(fn, ARGC, true)));
}
template<int ARGC>
void VM::bind_func(PyVar obj, Str funcName, NativeFuncRaw fn) {
setattr(obj, funcName, py_object(this, NativeFunc(fn, ARGC, false)));
}
void VM::_error(Exception e){
if(callstack.empty()){
e.is_re = false;
throw e;
}
top_frame()->push(py_object(this, e));
_raise();
}
PyVar VM::_exec(){
Frame* frame = top_frame();
i64 base_id = frame->id;
PyVar ret = nullptr;
bool need_raise = false;
while(true){
if(frame->id < base_id) UNREACHABLE();
try{
if(need_raise){ need_raise = false; _raise(); }
ret = run_frame(frame);
if(ret == _py_op_yield) return _py_op_yield;
if(ret != _py_op_call){
if(frame->id == base_id){ // [ frameBase<- ]
callstack.pop();
return ret;
}else{
callstack.pop();
frame = callstack.top().get();
frame->push(ret);
}
}else{
frame = callstack.top().get(); // [ frameBase, newFrame<- ]
}
}catch(HandledException& e){
continue;
}catch(UnhandledException& e){
PyVar obj = frame->pop();
Exception& _e = py_cast<Exception>(this, obj);
_e.st_push(frame->snapshot());
callstack.pop();
if(callstack.empty()) throw _e;
frame = callstack.top().get();
frame->push(obj);
if(frame->id < base_id) throw ToBeRaisedException();
need_raise = true;
}catch(ToBeRaisedException& e){
need_raise = true;
}
}
}
} // namespace pkpy