mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 19:40:18 +00:00
up
This commit is contained in:
parent
0926341e12
commit
6a82644f9a
@ -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;
|
||||
|
@ -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 {
|
||||
|
@ -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) {
|
||||
|
@ -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);
|
||||
|
@ -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
258
src/vm.h
@ -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
|
Loading…
x
Reference in New Issue
Block a user