This commit is contained in:
blueloveTH 2023-08-05 15:44:23 +08:00
parent 2745194c72
commit f16f98fcf8
10 changed files with 104 additions and 167 deletions

View File

@ -122,8 +122,8 @@ class Body:
def apply_force(self, force: vec2, point: vec2): ... def apply_force(self, force: vec2, point: vec2): ...
def apply_force_to_center(self, force: vec2): ... def apply_force_to_center(self, force: vec2): ...
def apply_torque(self, torque: float): ... def apply_torque(self, torque: float): ...
def apply_linear_impulse(self, impulse: vec2, point: vec2): ... def apply_impulse(self, impulse: vec2, point: vec2): ...
def apply_linear_impulse_to_center(self, impulse: vec2): ... def apply_impulse_to_center(self, impulse: vec2): ...
def apply_angular_impulse(self, impulse: float): ... def apply_angular_impulse(self, impulse: float): ...
def get_node(self) -> _NodeLike: def get_node(self) -> _NodeLike:

View File

@ -67,7 +67,7 @@ a property is a python's `property` that attached to a type instance with a gett
You can use `@property` to create python property or use `vm->property` to create native property. You can use `@property` to create python property or use `vm->property` to create native property.
You can also use `vm->bind_property()`, the new style property binding function. Use `vm->bind_property()`, the new style property binding function.
```cpp ```cpp
struct Point { struct Point {
@ -86,15 +86,16 @@ struct Point {
}); });
// getter and setter of property `x` // getter and setter of property `x`
type->attr().set("x", vm->property([](VM* vm, ArgsView args){ vm->bind_property(type, "x: int",
Point& self = CAST(Point&, args[0]); [](VM* vm, ArgsView args){
return VAR(self.x); Point& self = CAST(Point&, args[0]);
}, return VAR(self.x);
[](VM* vm, ArgsView args){ },
Point& self = CAST(Point&, args[0]); [](VM* vm, ArgsView args){
self.x = CAST(int, args[1]); Point& self = CAST(Point&, args[0]);
return vm->None; self.x = CAST(int, args[1]);
})); return vm->None;
});
} }
}; };
``` ```

View File

@ -65,33 +65,6 @@ struct NativeProxyMethodC final: NativeProxyFuncCBase {
} }
}; };
template<typename _OpaqueT, typename Ret, typename T, typename... Params>
struct NativeProxyOpaqueMethodC final: NativeProxyFuncCBase {
static_assert(std::is_base_of_v<OpaquePointer<T>, _OpaqueT>);
static constexpr int N = sizeof...(Params);
using _Fp = Ret(T::*)(Params...);
_Fp func;
NativeProxyOpaqueMethodC(_Fp func) : func(func) {}
PyObject* operator()(VM* vm, ArgsView args) override {
PK_ASSERT(args.size() == N+1);
return call<Ret>(vm, args, std::make_index_sequence<N>());
}
template<typename __Ret, size_t... Is>
PyObject* call(VM* vm, ArgsView args, std::index_sequence<Is...>){
OpaquePointer<T>& _opa_self = py_cast<_OpaqueT&>(vm, args[0]);
T& self = *_opa_self.ptr;
if constexpr(std::is_void_v<__Ret>){
(self.*func)(py_cast<Params>(vm, args[Is+1])...);
return vm->None;
}else{
__Ret ret = (self.*func)(py_cast<Params>(vm, args[Is+1])...);
return VAR(std::move(ret));
}
}
};
inline PyObject* proxy_wrapper(VM* vm, ArgsView args){ inline PyObject* proxy_wrapper(VM* vm, ArgsView args){
NativeProxyFuncCBase* pf = lambda_get_userdata<NativeProxyFuncCBase*>(args.begin()); NativeProxyFuncCBase* pf = lambda_get_userdata<NativeProxyFuncCBase*>(args.begin());
return (*pf)(vm, args); return (*pf)(vm, args);
@ -108,56 +81,44 @@ void _bind(VM* vm, PyObject* obj, const char* sig, Ret(T::*func)(Params...)){
auto proxy = new NativeProxyMethodC<Ret, T, Params...>(func); auto proxy = new NativeProxyMethodC<Ret, T, Params...>(func);
vm->bind(obj, sig, proxy_wrapper, proxy); vm->bind(obj, sig, proxy_wrapper, proxy);
} }
template<typename _OpaqueT, typename Ret, typename T, typename... Params>
void _bind_opaque(VM* vm, PyObject* obj, const char* sig, Ret(T::*func)(Params...)){
auto proxy = new NativeProxyOpaqueMethodC<_OpaqueT, Ret, T, Params...>(func);
vm->bind(obj, sig, proxy_wrapper, proxy);
}
/*****************************************************************/ /*****************************************************************/
#define PK_REGISTER_FIELD(T, NAME) \ #define PK_REGISTER_FIELD(T, NAME, REF, EXPR) \
type->attr().set(#NAME, vm->property( \ vm->bind_property(type, NAME, \
[](VM* vm, ArgsView args){ \ [](VM* vm, ArgsView args){ \
T& self = _CAST(T&, args[0]); \ T& self = _CAST(T&, args[0]); \
return VAR(self->NAME); \ return VAR(self.REF().EXPR); \
}, \ }, \
[](VM* vm, ArgsView args){ \ [](VM* vm, ArgsView args){ \
T& self = _CAST(T&, args[0]); \ T& self = _CAST(T&, args[0]); \
self->NAME = CAST(decltype(self->NAME), args[1]); \ self.REF().EXPR = CAST(decltype(self.REF().EXPR), args[1]); \
return vm->None; \ return vm->None; \
})); });
#define PK_REGISTER_READONLY_FIELD(T, NAME) \ #define PK_REGISTER_READONLY_FIELD(T, NAME, REF, EXPR) \
type->attr().set(#NAME, vm->property( \ vm->bind_property(type, NAME, \
[](VM* vm, ArgsView args){ \ [](VM* vm, ArgsView args){ \
T& self = _CAST(T&, args[0]); \ T& self = _CAST(T&, args[0]); \
return VAR(self->NAME); \ return VAR(self.REF().EXPR); \
})); });
#define PK_REGISTER_PROPERTY(T, NAME, __tp) \ #define PK_REGISTER_PROPERTY(T, NAME, REF, FGET, FSET) \
type->attr().set(#NAME, vm->property( \ vm->bind_property(type, NAME, \
[](VM* vm, ArgsView args){ \ [](VM* vm, ArgsView args){ \
T& self = _CAST(T&, args[0]); \ T& self = _CAST(T&, args[0]); \
return VAR(self->get_##NAME()); \ return VAR(self.REF().FGET()); \
}, \ }, \
[](VM* vm, ArgsView args){ \ [](VM* vm, ArgsView args){ \
T& self = _CAST(T&, args[0]); \ T& self = _CAST(T&, args[0]); \
using __NT = decltype(self->get_##NAME()); \ using __NT = decltype(self.REF().FGET()); \
self->set_##NAME(CAST(__NT, args[1])); \ self.REF().FSET(CAST(__NT, args[1])); \
return vm->None; \ return vm->None; \
}, __tp)); });
#define PK_REGISTER_READONLY_PROPERTY(T, NAME, __tp) \ #define PK_REGISTER_READONLY_PROPERTY(T, NAME, REF, FGET) \
type->attr().set(#NAME, vm->property( \ vm->bind_property(type, NAME, \
[](VM* vm, ArgsView args){ \ [](VM* vm, ArgsView args){ \
T& self = _CAST(T&, args[0]); \ T& self = _CAST(T&, args[0]); \
return VAR(self->get_##NAME()); \ return VAR(self.REF().FGET()); \
}, nullptr, __tp)); });
#define PK_REGISTER_CONSTRUCTOR(T, T0) \
vm->bind_constructor<2>(type, [](VM* vm, ArgsView args){ \
void* p = CAST(void*, args[0]); \
return VAR_T(T, (T0*)p); \
});
} // namespace pkpy } // namespace pkpy

View File

@ -31,8 +31,8 @@ struct BoundMethod {
struct Property{ struct Property{
PyObject* getter; PyObject* getter;
PyObject* setter; PyObject* setter;
const char* type_hint; Str type_hint;
Property(PyObject* getter, PyObject* setter, const char* type_hint) : getter(getter), setter(setter), type_hint(type_hint) {} Property(PyObject* getter, PyObject* setter, Str type_hint) : getter(getter), setter(setter), type_hint(type_hint) {}
}; };
struct Range { struct Range {

View File

@ -3,6 +3,7 @@
#include "common.h" #include "common.h"
#include "memory.h" #include "memory.h"
#include "vector.h" #include "vector.h"
#include <cstddef>
namespace pkpy { namespace pkpy {
@ -22,6 +23,7 @@ struct Str{
Str(int size, bool is_ascii); Str(int size, bool is_ascii);
Str(const std::string& s); Str(const std::string& s);
Str(std::string_view s); Str(std::string_view s);
Str(std::nullptr_t) { FATAL_ERROR(); }
Str(const char* s); Str(const char* s);
Str(const char* s, int len); Str(const char* s, int len);
Str(const Str& other); Str(const Str& other);

View File

@ -203,7 +203,6 @@ public:
return call_method(self, callable, args...); return call_method(self, callable, args...);
} }
PyObject* property(NativeFuncC fget, NativeFuncC fset=nullptr, const char* type_hint=nullptr);
PyObject* new_type_object(PyObject* mod, StrName name, Type base, bool subclass_enabled=true); PyObject* new_type_object(PyObject* mod, StrName name, Type base, bool subclass_enabled=true);
Type _new_type_object(StrName name, Type base=0); Type _new_type_object(StrName name, Type base=0);
PyObject* _find_type_object(const Str& type); PyObject* _find_type_object(const Str& type);
@ -462,7 +461,7 @@ public:
// new style binding api // new style binding api
PyObject* bind(PyObject*, const char*, const char*, NativeFuncC, UserData userdata={}); PyObject* bind(PyObject*, const char*, const char*, NativeFuncC, UserData userdata={});
PyObject* bind(PyObject*, const char*, NativeFuncC, UserData userdata={}); PyObject* bind(PyObject*, const char*, NativeFuncC, UserData userdata={});
PyObject* bind_property(PyObject*, StrName name, const char* type_hint, NativeFuncC fget, NativeFuncC fset=nullptr); PyObject* bind_property(PyObject*, Str, NativeFuncC fget, NativeFuncC fset=nullptr);
}; };
DEF_NATIVE_2(Str, tp_str) DEF_NATIVE_2(Str, tp_str)

View File

@ -36,14 +36,15 @@ namespace pkpy{
}); });
#define BIND_VEC_FIELD(D, name) \ #define BIND_VEC_FIELD(D, name) \
type->attr().set(#name, vm->property([](VM* vm, ArgsView args){ \ vm->bind_property(type, #name, \
[](VM* vm, ArgsView args){ \
PyVec##D& self = _CAST(PyVec##D&, args[0]); \ PyVec##D& self = _CAST(PyVec##D&, args[0]); \
return VAR(self.name); \ return VAR(self.name); \
}, [](VM* vm, ArgsView args){ \ }, [](VM* vm, ArgsView args){ \
PyVec##D& self = _CAST(PyVec##D&, args[0]); \ PyVec##D& self = _CAST(PyVec##D&, args[0]); \
self.name = CAST(f64, args[1]); \ self.name = CAST(f64, args[1]); \
return vm->None; \ return vm->None; \
})); });
void PyVec2::_register(VM* vm, PyObject* mod, PyObject* type){ void PyVec2::_register(VM* vm, PyObject* mod, PyObject* type){
@ -284,14 +285,15 @@ namespace pkpy{
}); });
#define PROPERTY_FIELD(field) \ #define PROPERTY_FIELD(field) \
type->attr().set(#field, vm->property([](VM* vm, ArgsView args){ \ vm->bind_property(type, #field ": float", \
[](VM* vm, ArgsView args){ \
PyMat3x3& self = _CAST(PyMat3x3&, args[0]); \ PyMat3x3& self = _CAST(PyMat3x3&, args[0]); \
return VAR(self.field); \ return VAR(self.field); \
}, [](VM* vm, ArgsView args){ \ }, [](VM* vm, ArgsView args){ \
PyMat3x3& self = _CAST(PyMat3x3&, args[0]); \ PyMat3x3& self = _CAST(PyMat3x3&, args[0]); \
self.field = CAST(f64, args[1]); \ self.field = CAST(f64, args[1]); \
return vm->None; \ return vm->None; \
})); });
PROPERTY_FIELD(_11) PROPERTY_FIELD(_11)
PROPERTY_FIELD(_12) PROPERTY_FIELD(_12)

View File

@ -149,36 +149,6 @@ void init_builtins(VM* _vm) {
} }
}); });
_vm->bind_builtin_func<3>("pow", [](VM* vm, ArgsView args) {
i64 lhs = CAST(i64, args[0]); // assume lhs>=0
i64 rhs = CAST(i64, args[1]); // assume rhs>=0
i64 mod = CAST(i64, args[2]); // assume mod>0, mod*mod should not overflow
if(rhs <= 0){
vm->ValueError("pow(): rhs should be positive");
}
PK_LOCAL_STATIC const auto _mul = [](i64 a, i64 b, i64 c){
if(c < 16384) return (a%c) * (b%c) % c;
i64 res = 0;
while(b > 0){
if(b & 1) res = (res + a) % c;
a = (a << 1) % c;
b >>= 1;
}
return res;
};
i64 res = 1;
lhs %= mod;
while(rhs){
if(rhs & 1) res = _mul(res, lhs, mod);
lhs = _mul(lhs, lhs, mod);
rhs >>= 1;
}
return VAR(res);
});
_vm->bind_builtin_func<1>("id", [](VM* vm, ArgsView args) { _vm->bind_builtin_func<1>("id", [](VM* vm, ArgsView args) {
PyObject* obj = args[0]; PyObject* obj = args[0];
if(is_tagged(obj)) return vm->None; if(is_tagged(obj)) return vm->None;
@ -1216,41 +1186,41 @@ void init_builtins(VM* _vm) {
/************ property ************/ /************ property ************/
_vm->bind_constructor<-1>("property", [](VM* vm, ArgsView args) { _vm->bind_constructor<-1>("property", [](VM* vm, ArgsView args) {
if(args.size() == 1+1){ if(args.size() == 1+1){
return VAR(Property(args[1], vm->None, nullptr)); return VAR(Property(args[1], vm->None, ""));
}else if(args.size() == 1+2){ }else if(args.size() == 1+2){
return VAR(Property(args[1], args[2], nullptr)); return VAR(Property(args[1], args[2], ""));
} }
vm->TypeError("property() takes at most 2 arguments"); vm->TypeError("property() takes at most 2 arguments");
return vm->None; return vm->None;
}); });
_vm->bind_property(_vm->_t(_vm->tp_property), "type_hint", "str", [](VM* vm, ArgsView args){ _vm->bind_property(_vm->_t(_vm->tp_property), "type_hint: str", [](VM* vm, ArgsView args){
Property& self = _CAST(Property&, args[0]); Property& self = _CAST(Property&, args[0]);
if(self.type_hint == nullptr) return vm->None;
return VAR(self.type_hint); return VAR(self.type_hint);
}); });
_vm->_t(_vm->tp_function)->attr().set("__doc__", _vm->property([](VM* vm, ArgsView args) {
_vm->bind_property(_vm->_t(_vm->tp_function), "__doc__", [](VM* vm, ArgsView args) {
Function& func = _CAST(Function&, args[0]); Function& func = _CAST(Function&, args[0]);
return VAR(func.decl->docstring); return VAR(func.decl->docstring);
})); });
_vm->_t(_vm->tp_native_func)->attr().set("__doc__", _vm->property([](VM* vm, ArgsView args) { _vm->bind_property(_vm->_t(_vm->tp_native_func), "__doc__", [](VM* vm, ArgsView args) {
NativeFunc& func = _CAST(NativeFunc&, args[0]); NativeFunc& func = _CAST(NativeFunc&, args[0]);
if(func.decl != nullptr) return VAR(func.decl->docstring); if(func.decl != nullptr) return VAR(func.decl->docstring);
return VAR(""); return VAR("");
})); });
_vm->_t(_vm->tp_function)->attr().set("__signature__", _vm->property([](VM* vm, ArgsView args) { _vm->bind_property(_vm->_t(_vm->tp_function), "__signature__", [](VM* vm, ArgsView args) {
Function& func = _CAST(Function&, args[0]); Function& func = _CAST(Function&, args[0]);
return VAR(func.decl->signature); return VAR(func.decl->signature);
})); });
_vm->_t(_vm->tp_native_func)->attr().set("__signature__", _vm->property([](VM* vm, ArgsView args) { _vm->bind_property(_vm->_t(_vm->tp_native_func), "__signature__", [](VM* vm, ArgsView args) {
NativeFunc& func = _CAST(NativeFunc&, args[0]); NativeFunc& func = _CAST(NativeFunc&, args[0]);
if(func.decl != nullptr) return VAR(func.decl->signature); if(func.decl != nullptr) return VAR(func.decl->signature);
return VAR("unknown(*args, **kwargs)"); return VAR("unknown(*args, **kwargs)");
})); });
RangeIter::register_class(_vm, _vm->builtins); RangeIter::register_class(_vm, _vm->builtins);
ArrayIter::register_class(_vm, _vm->builtins); ArrayIter::register_class(_vm, _vm->builtins);
@ -1520,41 +1490,41 @@ void add_module_gc(VM* vm){
void VM::post_init(){ void VM::post_init(){
init_builtins(this); init_builtins(this);
_t(tp_object)->attr().set("__class__", property(PK_LAMBDA(vm->_t(args[0])))); bind_property(_t(tp_object), "__class__", PK_LAMBDA(VAR(vm->_t(args[0]))));
_t(tp_type)->attr().set("__base__", property([](VM* vm, ArgsView args){ bind_property(_t(tp_type), "__base__", [](VM* vm, ArgsView args){
const PyTypeInfo& info = vm->_all_types[PK_OBJ_GET(Type, args[0])]; const PyTypeInfo& info = vm->_all_types[PK_OBJ_GET(Type, args[0])];
return info.base.index == -1 ? vm->None : vm->_all_types[info.base].obj; return info.base.index == -1 ? vm->None : vm->_all_types[info.base].obj;
})); });
_t(tp_type)->attr().set("__name__", property([](VM* vm, ArgsView args){ bind_property(_t(tp_type), "__name__", [](VM* vm, ArgsView args){
const PyTypeInfo& info = vm->_all_types[PK_OBJ_GET(Type, args[0])]; const PyTypeInfo& info = vm->_all_types[PK_OBJ_GET(Type, args[0])];
return VAR(info.name); return VAR(info.name);
})); });
bind_property(_t(tp_bound_method), "__self__", [](VM* vm, ArgsView args){
_t(tp_bound_method)->attr().set("__self__", property([](VM* vm, ArgsView args){
return CAST(BoundMethod&, args[0]).self; return CAST(BoundMethod&, args[0]).self;
})); });
_t(tp_bound_method)->attr().set("__func__", property([](VM* vm, ArgsView args){ bind_property(_t(tp_bound_method), "__func__", [](VM* vm, ArgsView args){
return CAST(BoundMethod&, args[0]).func; return CAST(BoundMethod&, args[0]).func;
})); });
bind__eq__(tp_bound_method, [](VM* vm, PyObject* lhs, PyObject* rhs){ bind__eq__(tp_bound_method, [](VM* vm, PyObject* lhs, PyObject* rhs){
if(!is_non_tagged_type(rhs, vm->tp_bound_method)) return vm->NotImplemented; if(!is_non_tagged_type(rhs, vm->tp_bound_method)) return vm->NotImplemented;
return VAR(_CAST(BoundMethod&, lhs) == _CAST(BoundMethod&, rhs)); return VAR(_CAST(BoundMethod&, lhs) == _CAST(BoundMethod&, rhs));
}); });
_t(tp_slice)->attr().set("start", property([](VM* vm, ArgsView args){
return CAST(Slice&, args[0]).start;
}));
_t(tp_slice)->attr().set("stop", property([](VM* vm, ArgsView args){
return CAST(Slice&, args[0]).stop;
}));
_t(tp_slice)->attr().set("step", property([](VM* vm, ArgsView args){
return CAST(Slice&, args[0]).step;
}));
_t(tp_object)->attr().set("__dict__", property([](VM* vm, ArgsView args){ bind_property(_t(tp_slice), "start", [](VM* vm, ArgsView args){
return CAST(Slice&, args[0]).start;
});
bind_property(_t(tp_slice), "stop", [](VM* vm, ArgsView args){
return CAST(Slice&, args[0]).stop;
});
bind_property(_t(tp_slice), "step", [](VM* vm, ArgsView args){
return CAST(Slice&, args[0]).step;
});
bind_property(_t(tp_object), "__dict__", [](VM* vm, ArgsView args){
if(is_tagged(args[0]) || !args[0]->is_attr_valid()) return vm->None; if(is_tagged(args[0]) || !args[0]->is_attr_valid()) return vm->None;
return VAR(MappingProxy(args[0])); return VAR(MappingProxy(args[0]));
})); });
#if !PK_DEBUG_NO_BUILTINS #if !PK_DEBUG_NO_BUILTINS
add_module_sys(this); add_module_sys(this);

View File

@ -113,13 +113,6 @@ namespace pkpy{
return nullptr; return nullptr;
} }
PyObject* VM::property(NativeFuncC fget, NativeFuncC fset, const char* type_hint){
PyObject* _0 = heap.gcnew<NativeFunc>(tp_native_func, fget, 1, false);
PyObject* _1 = vm->None;
if(fset != nullptr) _1 = heap.gcnew<NativeFunc>(tp_native_func, fset, 2, false);
return VAR(Property(_0, _1, type_hint));
}
PyObject* VM::new_type_object(PyObject* mod, StrName name, Type base, bool subclass_enabled){ PyObject* VM::new_type_object(PyObject* mod, StrName name, Type base, bool subclass_enabled){
PyObject* obj = heap._new<Type>(tp_type, _all_types.size()); PyObject* obj = heap._new<Type>(tp_type, _all_types.size());
const PyTypeInfo& base_info = _all_types[base]; const PyTypeInfo& base_info = _all_types[base];
@ -979,8 +972,17 @@ PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, Native
return f_obj; return f_obj;
} }
PyObject* VM::bind_property(PyObject* obj, StrName name, const char* type_hint, NativeFuncC fget, NativeFuncC fset){ PyObject* VM::bind_property(PyObject* obj, Str name, NativeFuncC fget, NativeFuncC fset){
PyObject* prop = property(fget, fset, type_hint); PyObject* _0 = heap.gcnew<NativeFunc>(tp_native_func, fget, 1, false);
PyObject* _1 = vm->None;
if(fset != nullptr) _1 = heap.gcnew<NativeFunc>(tp_native_func, fset, 2, false);
Str type_hint;
int pos = name.index(":");
if(pos > 0){
type_hint = name.substr(pos + 1).strip();
name = name.substr(0, pos).strip();
}
PyObject* prop = VAR(Property(_0, _1, type_hint));
obj->attr().set(name, prop); obj->attr().set(name, prop);
return prop; return prop;
} }

View File

@ -31,7 +31,7 @@ if inq is not 1:
if inq is not 0: if inq is not 0:
assert False assert False
assert pow(2,5000,2**59-1) == 17592186044416 # assert pow(2,5000,2**59-1) == 17592186044416
def g(x): def g(x):
return x return x