mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 11:30:18 +00:00
...
This commit is contained in:
parent
2745194c72
commit
f16f98fcf8
@ -122,8 +122,8 @@ class Body:
|
||||
def apply_force(self, force: vec2, point: vec2): ...
|
||||
def apply_force_to_center(self, force: vec2): ...
|
||||
def apply_torque(self, torque: float): ...
|
||||
def apply_linear_impulse(self, impulse: vec2, point: vec2): ...
|
||||
def apply_linear_impulse_to_center(self, impulse: vec2): ...
|
||||
def apply_impulse(self, impulse: vec2, point: vec2): ...
|
||||
def apply_impulse_to_center(self, impulse: vec2): ...
|
||||
def apply_angular_impulse(self, impulse: float): ...
|
||||
|
||||
def get_node(self) -> _NodeLike:
|
||||
|
@ -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 also use `vm->bind_property()`, the new style property binding function.
|
||||
Use `vm->bind_property()`, the new style property binding function.
|
||||
|
||||
```cpp
|
||||
struct Point {
|
||||
@ -86,7 +86,8 @@ struct Point {
|
||||
});
|
||||
|
||||
// getter and setter of property `x`
|
||||
type->attr().set("x", vm->property([](VM* vm, ArgsView args){
|
||||
vm->bind_property(type, "x: int",
|
||||
[](VM* vm, ArgsView args){
|
||||
Point& self = CAST(Point&, args[0]);
|
||||
return VAR(self.x);
|
||||
},
|
||||
@ -94,7 +95,7 @@ struct Point {
|
||||
Point& self = CAST(Point&, args[0]);
|
||||
self.x = CAST(int, args[1]);
|
||||
return vm->None;
|
||||
}));
|
||||
});
|
||||
}
|
||||
};
|
||||
```
|
||||
|
@ -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){
|
||||
NativeProxyFuncCBase* pf = lambda_get_userdata<NativeProxyFuncCBase*>(args.begin());
|
||||
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);
|
||||
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) \
|
||||
type->attr().set(#NAME, vm->property( \
|
||||
#define PK_REGISTER_FIELD(T, NAME, REF, EXPR) \
|
||||
vm->bind_property(type, NAME, \
|
||||
[](VM* vm, ArgsView args){ \
|
||||
T& self = _CAST(T&, args[0]); \
|
||||
return VAR(self->NAME); \
|
||||
return VAR(self.REF().EXPR); \
|
||||
}, \
|
||||
[](VM* vm, ArgsView args){ \
|
||||
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; \
|
||||
}));
|
||||
});
|
||||
|
||||
#define PK_REGISTER_READONLY_FIELD(T, NAME) \
|
||||
type->attr().set(#NAME, vm->property( \
|
||||
#define PK_REGISTER_READONLY_FIELD(T, NAME, REF, EXPR) \
|
||||
vm->bind_property(type, NAME, \
|
||||
[](VM* vm, ArgsView args){ \
|
||||
T& self = _CAST(T&, args[0]); \
|
||||
return VAR(self->NAME); \
|
||||
}));
|
||||
return VAR(self.REF().EXPR); \
|
||||
});
|
||||
|
||||
#define PK_REGISTER_PROPERTY(T, NAME, __tp) \
|
||||
type->attr().set(#NAME, vm->property( \
|
||||
#define PK_REGISTER_PROPERTY(T, NAME, REF, FGET, FSET) \
|
||||
vm->bind_property(type, NAME, \
|
||||
[](VM* vm, ArgsView args){ \
|
||||
T& self = _CAST(T&, args[0]); \
|
||||
return VAR(self->get_##NAME()); \
|
||||
return VAR(self.REF().FGET()); \
|
||||
}, \
|
||||
[](VM* vm, ArgsView args){ \
|
||||
T& self = _CAST(T&, args[0]); \
|
||||
using __NT = decltype(self->get_##NAME()); \
|
||||
self->set_##NAME(CAST(__NT, args[1])); \
|
||||
using __NT = decltype(self.REF().FGET()); \
|
||||
self.REF().FSET(CAST(__NT, args[1])); \
|
||||
return vm->None; \
|
||||
}, __tp));
|
||||
});
|
||||
|
||||
#define PK_REGISTER_READONLY_PROPERTY(T, NAME, __tp) \
|
||||
type->attr().set(#NAME, vm->property( \
|
||||
#define PK_REGISTER_READONLY_PROPERTY(T, NAME, REF, FGET) \
|
||||
vm->bind_property(type, NAME, \
|
||||
[](VM* vm, ArgsView args){ \
|
||||
T& self = _CAST(T&, args[0]); \
|
||||
return VAR(self->get_##NAME()); \
|
||||
}, 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); \
|
||||
return VAR(self.REF().FGET()); \
|
||||
});
|
||||
|
||||
} // namespace pkpy
|
@ -31,8 +31,8 @@ struct BoundMethod {
|
||||
struct Property{
|
||||
PyObject* getter;
|
||||
PyObject* setter;
|
||||
const char* type_hint;
|
||||
Property(PyObject* getter, PyObject* setter, const char* type_hint) : getter(getter), setter(setter), type_hint(type_hint) {}
|
||||
Str type_hint;
|
||||
Property(PyObject* getter, PyObject* setter, Str type_hint) : getter(getter), setter(setter), type_hint(type_hint) {}
|
||||
};
|
||||
|
||||
struct Range {
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include "common.h"
|
||||
#include "memory.h"
|
||||
#include "vector.h"
|
||||
#include <cstddef>
|
||||
|
||||
namespace pkpy {
|
||||
|
||||
@ -22,6 +23,7 @@ struct Str{
|
||||
Str(int size, bool is_ascii);
|
||||
Str(const std::string& s);
|
||||
Str(std::string_view s);
|
||||
Str(std::nullptr_t) { FATAL_ERROR(); }
|
||||
Str(const char* s);
|
||||
Str(const char* s, int len);
|
||||
Str(const Str& other);
|
||||
|
@ -203,7 +203,6 @@ public:
|
||||
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);
|
||||
Type _new_type_object(StrName name, Type base=0);
|
||||
PyObject* _find_type_object(const Str& type);
|
||||
@ -462,7 +461,7 @@ public:
|
||||
// new style binding api
|
||||
PyObject* bind(PyObject*, const char*, 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)
|
||||
|
@ -36,14 +36,15 @@ namespace pkpy{
|
||||
});
|
||||
|
||||
#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]); \
|
||||
return VAR(self.name); \
|
||||
}, [](VM* vm, ArgsView args){ \
|
||||
PyVec##D& self = _CAST(PyVec##D&, args[0]); \
|
||||
self.name = CAST(f64, args[1]); \
|
||||
return vm->None; \
|
||||
}));
|
||||
});
|
||||
|
||||
|
||||
void PyVec2::_register(VM* vm, PyObject* mod, PyObject* type){
|
||||
@ -284,14 +285,15 @@ namespace pkpy{
|
||||
});
|
||||
|
||||
#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]); \
|
||||
return VAR(self.field); \
|
||||
}, [](VM* vm, ArgsView args){ \
|
||||
PyMat3x3& self = _CAST(PyMat3x3&, args[0]); \
|
||||
self.field = CAST(f64, args[1]); \
|
||||
return vm->None; \
|
||||
}));
|
||||
});
|
||||
|
||||
PROPERTY_FIELD(_11)
|
||||
PROPERTY_FIELD(_12)
|
||||
|
@ -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) {
|
||||
PyObject* obj = args[0];
|
||||
if(is_tagged(obj)) return vm->None;
|
||||
@ -1216,41 +1186,41 @@ void init_builtins(VM* _vm) {
|
||||
/************ property ************/
|
||||
_vm->bind_constructor<-1>("property", [](VM* vm, ArgsView args) {
|
||||
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){
|
||||
return VAR(Property(args[1], args[2], nullptr));
|
||||
return VAR(Property(args[1], args[2], ""));
|
||||
}
|
||||
vm->TypeError("property() takes at most 2 arguments");
|
||||
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]);
|
||||
if(self.type_hint == nullptr) return vm->None;
|
||||
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]);
|
||||
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]);
|
||||
if(func.decl != nullptr) return VAR(func.decl->docstring);
|
||||
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]);
|
||||
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]);
|
||||
if(func.decl != nullptr) return VAR(func.decl->signature);
|
||||
return VAR("unknown(*args, **kwargs)");
|
||||
}));
|
||||
});
|
||||
|
||||
RangeIter::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(){
|
||||
init_builtins(this);
|
||||
|
||||
_t(tp_object)->attr().set("__class__", property(PK_LAMBDA(vm->_t(args[0]))));
|
||||
_t(tp_type)->attr().set("__base__", property([](VM* vm, ArgsView args){
|
||||
bind_property(_t(tp_object), "__class__", PK_LAMBDA(VAR(vm->_t(args[0]))));
|
||||
bind_property(_t(tp_type), "__base__", [](VM* vm, ArgsView args){
|
||||
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;
|
||||
}));
|
||||
_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])];
|
||||
return VAR(info.name);
|
||||
}));
|
||||
|
||||
_t(tp_bound_method)->attr().set("__self__", property([](VM* vm, ArgsView args){
|
||||
});
|
||||
bind_property(_t(tp_bound_method), "__self__", [](VM* vm, ArgsView args){
|
||||
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;
|
||||
}));
|
||||
});
|
||||
|
||||
bind__eq__(tp_bound_method, [](VM* vm, PyObject* lhs, PyObject* rhs){
|
||||
if(!is_non_tagged_type(rhs, vm->tp_bound_method)) return vm->NotImplemented;
|
||||
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;
|
||||
return VAR(MappingProxy(args[0]));
|
||||
}));
|
||||
});
|
||||
|
||||
#if !PK_DEBUG_NO_BUILTINS
|
||||
add_module_sys(this);
|
||||
|
20
src/vm.cpp
20
src/vm.cpp
@ -113,13 +113,6 @@ namespace pkpy{
|
||||
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* obj = heap._new<Type>(tp_type, _all_types.size());
|
||||
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;
|
||||
}
|
||||
|
||||
PyObject* VM::bind_property(PyObject* obj, StrName name, const char* type_hint, NativeFuncC fget, NativeFuncC fset){
|
||||
PyObject* prop = property(fget, fset, type_hint);
|
||||
PyObject* VM::bind_property(PyObject* obj, Str name, NativeFuncC fget, NativeFuncC fset){
|
||||
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);
|
||||
return prop;
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ if inq is not 1:
|
||||
if inq is not 0:
|
||||
assert False
|
||||
|
||||
assert pow(2,5000,2**59-1) == 17592186044416
|
||||
# assert pow(2,5000,2**59-1) == 17592186044416
|
||||
|
||||
def g(x):
|
||||
return x
|
||||
|
Loading…
x
Reference in New Issue
Block a user