diff --git a/src/ceval.h b/src/ceval.h index 9b50a9e8..6681479c 100644 --- a/src/ceval.h +++ b/src/ceval.h @@ -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(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(this, start);} if(stop != None) { s.stop = (int)py_cast_v(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; diff --git a/src/obj.h b/src/obj.h index 62b7284d..f3c0f9f2 100644 --- a/src/obj.h +++ b/src/obj.h @@ -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 { diff --git a/src/pocketpy.h b/src/pocketpy.h index d8d8d795..021b1c58 100644 --- a/src/pocketpy.h +++ b/src/pocketpy.h @@ -172,7 +172,7 @@ void init_builtins(VM* _vm) { case 3: r.start = py_cast_v(vm, args[0]); r.stop = py_cast_v(vm, args[1]); r.step = py_cast_v(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(vm, args[0])); if(is_type(args[1], vm->tp_slice)){ - Slice s = vm->PySlice_AS_C(args[1]); + Slice s = _py_cast_v(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(vm, args[0]); if(is_type(args[1], vm->tp_slice)){ - Slice s = vm->PySlice_AS_C(args[1]); + Slice s = _py_cast_v(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(vm, args[0]); if(is_type(args[1], vm->tp_slice)){ - Slice s = vm->PySlice_AS_C(args[1]); + Slice s = _py_cast_v(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(vm, args[0]).method; CodeObject_ code = py_cast(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(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) { diff --git a/src/ref.h b/src/ref.h index aa16f640..ac01b4b8 100644 --- a/src/ref.h +++ b/src/ref.h @@ -127,7 +127,7 @@ struct TupleRef : BaseRef { for(int i=0; itp_star_wrapper)){ - auto& star = vm->PyStarWrapper_AS_C(objs[i]); + auto& star = _py_cast(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); diff --git a/src/tuplelist.h b/src/tuplelist.h index 9cf1c4f9..b2523d0d 100644 --- a/src/tuplelist.h +++ b/src/tuplelist.h @@ -26,12 +26,6 @@ namespace pkpy { for(int i=0; i<_size; i++) _args[i] = other._args[i]; } - Args(std::initializer_list 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; diff --git a/src/vm.h b/src/vm.h index f06f4551..0399e19e 100644 --- a/src/vm.h +++ b/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(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>(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)...)); } - 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; iattr(__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 - 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(p->value())->get(); - if(!p->is_attr_valid()) TypeError("cannot set attribute"); - p->attr().set(name, std::forward(value)); - } - - template - void bind_method(PyVar obj, Str funcName, NativeFuncRaw fn) { - check_type(obj, tp_type); - setattr(obj, funcName, PyNativeFunc(NativeFunc(fn, ARGC, true))); - } - - template - void bind_func(PyVar obj, Str funcName, NativeFuncRaw fn) { - setattr(obj, funcName, PyNativeFunc(NativeFunc(fn, ARGC, false))); - } - template void bind_func(Str typeName, Str funcName, NativeFuncRaw fn) { bind_func(_types[typeName], funcName, fn); @@ -360,13 +246,6 @@ public: check_type(obj, tp_native_iterator); return static_cast(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){ @@ -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 + void setattr(PyVar& obj, StrName name, T&& value); + template + void bind_method(PyVar obj, Str funcName, NativeFuncRaw fn); + template + void bind_func(PyVar obj, Str funcName, NativeFuncRaw fn); + void _error(Exception e); + PyVar _exec(); template 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(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(this, args[i]); if(!star.rvalue) UNREACHABLE(); PyVar list = asList(star.obj); List& list_c = py_cast(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; iattr(__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 +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(p->value())->get(); + if(!p->is_attr_valid()) TypeError("cannot set attribute"); + p->attr().set(name, std::forward(value)); +} + +template +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 +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(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 \ No newline at end of file