mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 03:20:18 +00:00
This commit is contained in:
parent
094fac8f72
commit
7a386fa218
@ -92,7 +92,7 @@ class mat3x3(_StructLike['mat3x3']):
|
||||
@overload
|
||||
def __init__(self, _11, _12, _13, _21, _22, _23, _31, _32, _33) -> None: ...
|
||||
@overload
|
||||
def __init__(self, a: list[list]): ...
|
||||
def __init__(self, a: list[float]): ...
|
||||
|
||||
def set_zeros(self) -> None: ...
|
||||
def set_ones(self) -> None: ...
|
||||
|
@ -108,7 +108,7 @@ struct FuncDecl {
|
||||
};
|
||||
|
||||
struct UserData{
|
||||
char data[15];
|
||||
char data[12];
|
||||
bool empty;
|
||||
|
||||
UserData(): empty(true) {}
|
||||
|
@ -21,7 +21,7 @@
|
||||
#include <random>
|
||||
#include <deque>
|
||||
|
||||
#define PK_VERSION "1.3.7"
|
||||
#define PK_VERSION "1.3.8"
|
||||
|
||||
#include "config.h"
|
||||
#include "export.h"
|
||||
|
@ -15,17 +15,26 @@ using NativeFuncC = std::function<PyObject*(VM*, ArgsView)>;
|
||||
typedef PyObject* (*NativeFuncC)(VM*, ArgsView);
|
||||
#endif
|
||||
|
||||
enum class BindType{
|
||||
DEFAULT,
|
||||
STATICMETHOD,
|
||||
CLASSMETHOD,
|
||||
};
|
||||
|
||||
struct BoundMethod {
|
||||
PyObject* self;
|
||||
PyObject* func;
|
||||
BoundMethod(PyObject* self, PyObject* func) : self(self), func(func) {}
|
||||
};
|
||||
|
||||
bool operator==(const BoundMethod& rhs) const noexcept {
|
||||
return self == rhs.self && func == rhs.func;
|
||||
}
|
||||
bool operator!=(const BoundMethod& rhs) const noexcept {
|
||||
return self != rhs.self || func != rhs.func;
|
||||
}
|
||||
struct StaticMethod{
|
||||
PyObject* func;
|
||||
StaticMethod(PyObject* func) : func(func) {}
|
||||
};
|
||||
|
||||
struct ClassMethod{
|
||||
PyObject* func;
|
||||
ClassMethod(PyObject* func) : func(func) {}
|
||||
};
|
||||
|
||||
struct Property{
|
||||
@ -323,6 +332,26 @@ struct Py_<StarWrapper> final: PyObject {
|
||||
void* _value_ptr() override { return &_value; }
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Py_<StaticMethod> final: PyObject {
|
||||
StaticMethod _value;
|
||||
Py_(Type type, StaticMethod val): PyObject(type), _value(val) {}
|
||||
void _obj_gc_mark() override {
|
||||
PK_OBJ_MARK(_value.func);
|
||||
}
|
||||
void* _value_ptr() override { return &_value; }
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Py_<ClassMethod> final: PyObject {
|
||||
ClassMethod _value;
|
||||
Py_(Type type, ClassMethod val): PyObject(type), _value(val) {}
|
||||
void _obj_gc_mark() override {
|
||||
PK_OBJ_MARK(_value.func);
|
||||
}
|
||||
void* _value_ptr() override { return &_value; }
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Py_<Property> final: PyObject {
|
||||
Property _value;
|
||||
|
@ -158,6 +158,7 @@ public:
|
||||
|
||||
static constexpr Type tp_super=14, tp_exception=15, tp_bytes=16, tp_mappingproxy=17;
|
||||
static constexpr Type tp_dict=18, tp_property=19, tp_star_wrapper=20;
|
||||
static constexpr Type tp_staticmethod=21, tp_classmethod=22;
|
||||
|
||||
PyObject* cached_object__new__;
|
||||
|
||||
@ -475,8 +476,8 @@ public:
|
||||
PyObject* _py_generator(Frame&& frame, ArgsView buffer);
|
||||
void _prepare_py_call(PyObject**, ArgsView, ArgsView, const FuncDecl_&);
|
||||
// new style binding api
|
||||
PyObject* bind(PyObject*, const char*, const char*, NativeFuncC, UserData userdata={});
|
||||
PyObject* bind(PyObject*, const char*, NativeFuncC, UserData userdata={});
|
||||
PyObject* bind(PyObject*, const char*, const char*, NativeFuncC, UserData userdata={}, BindType bt=BindType::DEFAULT);
|
||||
PyObject* bind(PyObject*, const char*, NativeFuncC, UserData userdata={}, BindType bt=BindType::DEFAULT);
|
||||
PyObject* bind_property(PyObject*, Str, NativeFuncC fget, NativeFuncC fset=nullptr);
|
||||
};
|
||||
|
||||
@ -494,6 +495,8 @@ DEF_NATIVE_2(MappingProxy, tp_mappingproxy)
|
||||
DEF_NATIVE_2(Dict, tp_dict)
|
||||
DEF_NATIVE_2(Property, tp_property)
|
||||
DEF_NATIVE_2(StarWrapper, tp_star_wrapper)
|
||||
DEF_NATIVE_2(StaticMethod, tp_staticmethod)
|
||||
DEF_NATIVE_2(ClassMethod, tp_classmethod)
|
||||
|
||||
#undef DEF_NATIVE_2
|
||||
|
||||
|
@ -82,7 +82,7 @@ class mat3x3(_StructLike['mat3x3']):
|
||||
@overload
|
||||
def __init__(self, _11, _12, _13, _21, _22, _23, _31, _32, _33) -> None: ...
|
||||
@overload
|
||||
def __init__(self, a: list[list]): ...
|
||||
def __init__(self, a: list[float]): ...
|
||||
|
||||
def set_zeros(self) -> None: ...
|
||||
def set_ones(self) -> None: ...
|
||||
|
@ -5,17 +5,6 @@ def print(*args, sep=' ', end='\n'):
|
||||
s = sep.join([str(i) for i in args])
|
||||
_sys.stdout.write(s + end)
|
||||
|
||||
def issubclass(cls, base):
|
||||
if type(cls) is not type:
|
||||
raise TypeError('issubclass() arg 1 must be a class')
|
||||
if type(base) is not type:
|
||||
raise TypeError('issubclass() arg 2 must be a class')
|
||||
while cls is not None:
|
||||
if cls is base:
|
||||
return True
|
||||
cls = cls.__base__
|
||||
return False
|
||||
|
||||
def _minmax_reduce(op, args, key):
|
||||
if key is None:
|
||||
if len(args) == 2:
|
||||
@ -267,16 +256,6 @@ def help(obj):
|
||||
print(obj.__signature__)
|
||||
print(obj.__doc__)
|
||||
|
||||
|
||||
class classmethod:
|
||||
def __init__(self, f):
|
||||
self.f = f
|
||||
raise NotImplementedError
|
||||
|
||||
def staticmethod(f):
|
||||
return f
|
||||
|
||||
|
||||
def complex(*args, **kwargs):
|
||||
import cmath
|
||||
return cmath.complex(*args, **kwargs)
|
||||
|
@ -10,14 +10,6 @@ def _find_class(path: str):
|
||||
modpath, name = path.split(_MOD_T_SEP)
|
||||
return __import__(modpath).__dict__[name]
|
||||
|
||||
def _find__new__(cls):
|
||||
while cls is not None:
|
||||
d = cls.__dict__
|
||||
if "__new__" in d:
|
||||
return d["__new__"]
|
||||
cls = cls.__base__
|
||||
assert False
|
||||
|
||||
class _Pickler:
|
||||
def __init__(self, obj) -> None:
|
||||
self.obj = obj
|
||||
@ -148,7 +140,7 @@ class _Unpickler:
|
||||
cls, newargs, state = o
|
||||
cls = _find_class(o[0])
|
||||
# create uninitialized instance
|
||||
new_f = _find__new__(cls)
|
||||
new_f = getattr(cls, "__new__")
|
||||
if newargs is not None:
|
||||
newargs = [self.unwrap(i) for i in newargs]
|
||||
inst = new_f(cls, *newargs)
|
||||
|
@ -102,7 +102,7 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, PyVec2& currentVelocity, float
|
||||
vm->bind_constructor<3>(type, [](VM* vm, ArgsView args){
|
||||
float x = CAST_F(args[1]);
|
||||
float y = CAST_F(args[2]);
|
||||
return VAR(Vec2(x, y));
|
||||
return vm->heap.gcnew<PyVec2>(PK_OBJ_GET(Type, args[0]), Vec2(x, y));
|
||||
});
|
||||
|
||||
vm->bind_method<0>(type, "__getnewargs__", [](VM* vm, ArgsView args){
|
||||
@ -120,7 +120,7 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, PyVec2& currentVelocity, float
|
||||
float delta_time = CAST_F(args[5]);
|
||||
Vec2 ret = SmoothDamp(current, target, current_velocity, smooth_time, max_speed, delta_time);
|
||||
return VAR(ret);
|
||||
});
|
||||
}, {}, BindType::STATICMETHOD);
|
||||
|
||||
// @staticmethod
|
||||
vm->bind(type, "angle(__from: vec2, __to: vec2) -> float", [](VM* vm, ArgsView args){
|
||||
@ -131,7 +131,7 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, PyVec2& currentVelocity, float
|
||||
if(val > PI) val -= 2*PI;
|
||||
if(val < -PI) val += 2*PI;
|
||||
return VAR(val);
|
||||
});
|
||||
}, {}, BindType::STATICMETHOD);
|
||||
|
||||
vm->bind__repr__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){
|
||||
PyVec2& self = _CAST(PyVec2&, obj);
|
||||
@ -174,7 +174,7 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, PyVec2& currentVelocity, float
|
||||
float x = CAST_F(args[1]);
|
||||
float y = CAST_F(args[2]);
|
||||
float z = CAST_F(args[3]);
|
||||
return VAR(Vec3(x, y, z));
|
||||
return vm->heap.gcnew<PyVec3>(PK_OBJ_GET(Type, args[0]), Vec3(x, y, z));
|
||||
});
|
||||
|
||||
vm->bind_method<0>(type, "__getnewargs__", [](VM* vm, ArgsView args){
|
||||
@ -213,7 +213,7 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, PyVec2& currentVelocity, float
|
||||
float y = CAST_F(args[2]);
|
||||
float z = CAST_F(args[3]);
|
||||
float w = CAST_F(args[4]);
|
||||
return VAR(Vec4(x, y, z, w));
|
||||
return vm->heap.gcnew<PyVec4>(PK_OBJ_GET(Type, args[0]), Vec4(x, y, z, w));
|
||||
});
|
||||
|
||||
vm->bind_method<0>(type, "__getnewargs__", [](VM* vm, ArgsView args){
|
||||
@ -255,24 +255,18 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, PyVec2& currentVelocity, float
|
||||
PY_STRUCT_LIKE(PyMat3x3)
|
||||
|
||||
vm->bind_constructor<-1>(type, [](VM* vm, ArgsView args){
|
||||
if(args.size() == 1+0) return VAR_T(PyMat3x3, Mat3x3::zeros());
|
||||
if(args.size() == 1+0) return vm->heap.gcnew<PyMat3x3>(PK_OBJ_GET(Type, args[0]), Mat3x3::zeros());
|
||||
if(args.size() == 1+1){
|
||||
const List& list = CAST(List&, args[1]);
|
||||
if(list.size() != 9) vm->TypeError("Mat3x3.__new__ takes a list of 9 floats");
|
||||
Mat3x3 mat;
|
||||
for(int i=0; i<9; i++) mat.v[i] = CAST_F(list[i]);
|
||||
return vm->heap.gcnew<PyMat3x3>(PK_OBJ_GET(Type, args[0]), mat);
|
||||
}
|
||||
if(args.size() == 1+9){
|
||||
Mat3x3 mat;
|
||||
for(int i=0; i<9; i++) mat.v[i] = CAST_F(args[1+i]);
|
||||
return VAR_T(PyMat3x3, mat);
|
||||
}
|
||||
if(args.size() == 1+1){
|
||||
List& a = CAST(List&, args[1]);
|
||||
if(a.size() != 3) vm->ValueError("Mat3x3.__new__ takes 3x3 list");
|
||||
Mat3x3 mat;
|
||||
for(int i=0; i<3; i++){
|
||||
List& b = CAST(List&, a[i]);
|
||||
if(b.size() != 3) vm->ValueError("Mat3x3.__new__ takes 3x3 list");
|
||||
for(int j=0; j<3; j++){
|
||||
mat.m[i][j] = CAST_F(b[j]);
|
||||
}
|
||||
}
|
||||
return VAR_T(PyMat3x3, mat);
|
||||
return vm->heap.gcnew<PyMat3x3>(PK_OBJ_GET(Type, args[0]), mat);
|
||||
}
|
||||
vm->TypeError(fmt("Mat3x3.__new__ takes 0 or 1 or 9 arguments, got ", args.size()-1));
|
||||
return vm->None;
|
||||
@ -424,28 +418,32 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, PyVec2& currentVelocity, float
|
||||
return VAR_T(PyMat3x3, ret);
|
||||
});
|
||||
|
||||
vm->bind_func<0>(type, "zeros", [](VM* vm, ArgsView args){
|
||||
// @staticmethod
|
||||
vm->bind(type, "zeros()", [](VM* vm, ArgsView args){
|
||||
PK_UNUSED(args);
|
||||
return VAR_T(PyMat3x3, Mat3x3::zeros());
|
||||
});
|
||||
}, {}, BindType::STATICMETHOD);
|
||||
|
||||
vm->bind_func<0>(type, "ones", [](VM* vm, ArgsView args){
|
||||
// @staticmethod
|
||||
vm->bind(type, "ones()", [](VM* vm, ArgsView args){
|
||||
PK_UNUSED(args);
|
||||
return VAR_T(PyMat3x3, Mat3x3::ones());
|
||||
});
|
||||
}, {}, BindType::STATICMETHOD);
|
||||
|
||||
vm->bind_func<0>(type, "identity", [](VM* vm, ArgsView args){
|
||||
// @staticmethod
|
||||
vm->bind(type, "identity()", [](VM* vm, ArgsView args){
|
||||
PK_UNUSED(args);
|
||||
return VAR_T(PyMat3x3, Mat3x3::identity());
|
||||
});
|
||||
}, {}, BindType::STATICMETHOD);
|
||||
|
||||
/*************** affine transformations ***************/
|
||||
vm->bind_func<3>(type, "trs", [](VM* vm, ArgsView args){
|
||||
// @staticmethod
|
||||
vm->bind(type, "trs(t: vec2, r: float, s: vec2)", [](VM* vm, ArgsView args){
|
||||
PyVec2& t = CAST(PyVec2&, args[0]);
|
||||
f64 r = CAST_F(args[1]);
|
||||
PyVec2& s = CAST(PyVec2&, args[2]);
|
||||
return VAR_T(PyMat3x3, Mat3x3::trs(t, r, s));
|
||||
});
|
||||
}, {}, BindType::STATICMETHOD);
|
||||
|
||||
vm->bind_method<0>(type, "is_affine", [](VM* vm, ArgsView args){
|
||||
PyMat3x3& self = _CAST(PyMat3x3&, args[0]);
|
||||
|
@ -76,6 +76,18 @@ void init_builtins(VM* _vm) {
|
||||
return vm->heap.gcnew<Super>(vm->tp_super, self_arg, vm->_all_types[type].base);
|
||||
});
|
||||
|
||||
_vm->bind_builtin_func<1>("staticmethod", [](VM* vm, ArgsView args) {
|
||||
PyObject* func = args[0];
|
||||
vm->check_non_tagged_type(func, vm->tp_function);
|
||||
return vm->heap.gcnew<StaticMethod>(vm->tp_staticmethod, args[0]);
|
||||
});
|
||||
|
||||
_vm->bind_builtin_func<1>("classmethod", [](VM* vm, ArgsView args) {
|
||||
PyObject* func = args[0];
|
||||
vm->check_non_tagged_type(func, vm->tp_function);
|
||||
return vm->heap.gcnew<ClassMethod>(vm->tp_classmethod, args[0]);
|
||||
});
|
||||
|
||||
_vm->bind_builtin_func<2>("isinstance", [](VM* vm, ArgsView args) {
|
||||
if(is_non_tagged_type(args[1], vm->tp_tuple)){
|
||||
Tuple& types = _CAST(Tuple&, args[1]);
|
||||
@ -90,6 +102,12 @@ void init_builtins(VM* _vm) {
|
||||
return VAR(vm->isinstance(args[0], type));
|
||||
});
|
||||
|
||||
_vm->bind_builtin_func<2>("issubclass", [](VM* vm, ArgsView args) {
|
||||
vm->check_non_tagged_type(args[0], vm->tp_type);
|
||||
vm->check_non_tagged_type(args[1], vm->tp_type);
|
||||
return VAR(vm->issubclass(PK_OBJ_GET(Type, args[0]), PK_OBJ_GET(Type, args[1])));
|
||||
});
|
||||
|
||||
_vm->bind_builtin_func<0>("globals", [](VM* vm, ArgsView args) {
|
||||
PyObject* mod = vm->top_frame()->_module;
|
||||
return VAR(MappingProxy(mod));
|
||||
@ -124,11 +142,12 @@ void init_builtins(VM* _vm) {
|
||||
|
||||
_vm->bind_builtin_func<1>("callable", [](VM* vm, ArgsView args) {
|
||||
PyObject* cls = vm->_t(args[0]);
|
||||
Type t = PK_OBJ_GET(Type, cls);
|
||||
if(t == vm->tp_function) return vm->True;
|
||||
if(t == vm->tp_native_func) return vm->True;
|
||||
if(t == vm->tp_bound_method) return vm->True;
|
||||
if(t == vm->tp_type) return vm->True;
|
||||
switch(PK_OBJ_GET(Type, cls).index){
|
||||
case VM::tp_function.index: return vm->True;
|
||||
case VM::tp_native_func.index: return vm->True;
|
||||
case VM::tp_bound_method.index: return vm->True;
|
||||
case VM::tp_type.index: return vm->True;
|
||||
}
|
||||
bool ok = vm->find_name_in_mro(cls, __call__) != nullptr;
|
||||
return VAR(ok);
|
||||
});
|
||||
@ -217,9 +236,15 @@ void init_builtins(VM* _vm) {
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
_vm->bind_builtin_func<2>("getattr", [](VM* vm, ArgsView args) {
|
||||
const Str& name = CAST(Str&, args[1]);
|
||||
return vm->getattr(args[0], name);
|
||||
_vm->bind_builtin_func<-1>("getattr", [](VM* vm, ArgsView args) {
|
||||
if(args.size()!=2 && args.size()!=3) vm->TypeError("getattr() takes 2 or 3 arguments");
|
||||
StrName name = CAST(Str&, args[1]);
|
||||
PyObject* val = vm->getattr(args[0], name, false);
|
||||
if(val == nullptr){
|
||||
if(args.size()==2) vm->AttributeError(args[0], name);
|
||||
return args[2];
|
||||
}
|
||||
return val;
|
||||
});
|
||||
|
||||
_vm->bind_builtin_func<2>("delattr", [](VM* vm, ArgsView args) {
|
||||
@ -1277,20 +1302,12 @@ void init_builtins(VM* _vm) {
|
||||
return VAR(func.decl->signature);
|
||||
});
|
||||
|
||||
// _vm->bind_property(_vm->_t(_vm->tp_function), "__call__", [](VM* vm, ArgsView args) {
|
||||
// return args[0];
|
||||
// });
|
||||
|
||||
_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("");
|
||||
});
|
||||
|
||||
// _vm->bind_property(_vm->_t(_vm->tp_native_func), "__call__", [](VM* vm, ArgsView args) {
|
||||
// return args[0];
|
||||
// });
|
||||
|
||||
// Exception
|
||||
_vm->bind_constructor<-1>("Exception", [](VM* vm, ArgsView args){
|
||||
Type cls = PK_OBJ_GET(Type, args[0]);
|
||||
@ -1647,7 +1664,9 @@ void VM::post_init(){
|
||||
|
||||
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));
|
||||
const BoundMethod& _0 = PK_OBJ_GET(BoundMethod, lhs);
|
||||
const BoundMethod& _1 = PK_OBJ_GET(BoundMethod, rhs);
|
||||
return VAR(_0.self == _1.self && _0.func == _1.func);
|
||||
});
|
||||
|
||||
bind_property(_t(tp_slice), "start", [](VM* vm, ArgsView args){
|
||||
|
124
src/vm.cpp
124
src/vm.cpp
@ -705,28 +705,31 @@ void VM::init_builtin_types(){
|
||||
_all_types.push_back({heap._new<Type>(Type(1), Type(0)), -1, nullptr, "object", true});
|
||||
_all_types.push_back({heap._new<Type>(Type(1), Type(1)), 0, nullptr, "type", false});
|
||||
|
||||
PK_ASSERT(tp_int == _new_type_object("int"));
|
||||
PK_ASSERT(tp_float == _new_type_object("float"));
|
||||
if(tp_int != _new_type_object("int")) exit(-3);
|
||||
if((tp_float != _new_type_object("float"))) exit(-3);
|
||||
|
||||
PK_ASSERT(tp_bool == _new_type_object("bool"));
|
||||
PK_ASSERT(tp_str == _new_type_object("str"));
|
||||
PK_ASSERT(tp_list == _new_type_object("list"));
|
||||
PK_ASSERT(tp_tuple == _new_type_object("tuple"));
|
||||
if(tp_bool != _new_type_object("bool")) exit(-3);
|
||||
if(tp_str != _new_type_object("str")) exit(-3);
|
||||
if(tp_list != _new_type_object("list")) exit(-3);
|
||||
if(tp_tuple != _new_type_object("tuple")) exit(-3);
|
||||
|
||||
PK_ASSERT(tp_slice == _new_type_object("slice"));
|
||||
PK_ASSERT(tp_range == _new_type_object("range"));
|
||||
PK_ASSERT(tp_module == _new_type_object("module"));
|
||||
PK_ASSERT(tp_function == _new_type_object("function"));
|
||||
PK_ASSERT(tp_native_func == _new_type_object("native_func"));
|
||||
PK_ASSERT(tp_bound_method == _new_type_object("bound_method"));
|
||||
if(tp_slice != _new_type_object("slice")) exit(-3);
|
||||
if(tp_range != _new_type_object("range")) exit(-3);
|
||||
if(tp_module != _new_type_object("module")) exit(-3);
|
||||
if(tp_function != _new_type_object("function")) exit(-3);
|
||||
if(tp_native_func != _new_type_object("native_func")) exit(-3);
|
||||
if(tp_bound_method != _new_type_object("bound_method")) exit(-3);
|
||||
|
||||
PK_ASSERT(tp_super == _new_type_object("super"));
|
||||
PK_ASSERT(tp_exception == _new_type_object("Exception", 0, true));
|
||||
PK_ASSERT(tp_bytes == _new_type_object("bytes"));
|
||||
PK_ASSERT(tp_mappingproxy == _new_type_object("mappingproxy"));
|
||||
PK_ASSERT(tp_dict == _new_type_object("dict"));
|
||||
PK_ASSERT(tp_property == _new_type_object("property"));
|
||||
PK_ASSERT(tp_star_wrapper == _new_type_object("_star_wrapper"));
|
||||
if(tp_super != _new_type_object("super")) exit(-3);
|
||||
if(tp_exception != _new_type_object("Exception", 0, true)) exit(-3);
|
||||
if(tp_bytes != _new_type_object("bytes")) exit(-3);
|
||||
if(tp_mappingproxy != _new_type_object("mappingproxy")) exit(-3);
|
||||
if(tp_dict != _new_type_object("dict")) exit(-3);
|
||||
if(tp_property != _new_type_object("property")) exit(-3);
|
||||
if(tp_star_wrapper != _new_type_object("_star_wrapper")) exit(-3);
|
||||
|
||||
if(tp_staticmethod != _new_type_object("staticmethod")) exit(-3);
|
||||
if(tp_classmethod != _new_type_object("classmethod")) exit(-3);
|
||||
|
||||
this->None = heap._new<Dummy>(_new_type_object("NoneType"));
|
||||
this->NotImplemented = heap._new<Dummy>(_new_type_object("NotImplementedType"));
|
||||
@ -866,7 +869,7 @@ PyObject* VM::vectorcall(int ARGC, int KWARGC, bool op_call){
|
||||
// handle boundmethod, do a patch
|
||||
if(is_non_tagged_type(callable, tp_bound_method)){
|
||||
if(method_call) PK_FATAL_ERROR();
|
||||
auto& bm = CAST(BoundMethod&, callable);
|
||||
BoundMethod& bm = PK_OBJ_GET(BoundMethod, callable);
|
||||
callable = bm.func; // get unbound method
|
||||
p1[-(ARGC + 2)] = bm.func;
|
||||
p1[-(ARGC + 1)] = bm.self;
|
||||
@ -997,7 +1000,7 @@ __FAST_CALL:
|
||||
return vectorcall(ARGC, KWARGC, false);
|
||||
}
|
||||
TypeError(OBJ_NAME(_t(callable)).escape() + " object is not callable");
|
||||
return nullptr;
|
||||
PK_UNREACHABLE()
|
||||
}
|
||||
|
||||
void VM::delattr(PyObject *_0, StrName _name){
|
||||
@ -1020,19 +1023,38 @@ PyObject* VM::getattr(PyObject* obj, StrName name, bool throw_err){
|
||||
if(cls_var != nullptr){
|
||||
// handle descriptor
|
||||
if(is_non_tagged_type(cls_var, tp_property)){
|
||||
const Property& prop = _CAST(Property&, cls_var);
|
||||
const Property& prop = PK_OBJ_GET(Property, cls_var);
|
||||
return call(prop.getter, obj);
|
||||
}
|
||||
}
|
||||
// handle instance __dict__
|
||||
if(!is_tagged(obj) && obj->is_attr_valid()){
|
||||
PyObject* val = obj->attr().try_get_likely_found(name);
|
||||
if(val != nullptr) return val;
|
||||
PyObject* val;
|
||||
if(obj->type == tp_type){
|
||||
val = find_name_in_mro(obj, name);
|
||||
}else{
|
||||
val = obj->attr().try_get_likely_found(name);
|
||||
}
|
||||
if(val != nullptr){
|
||||
if(is_tagged(val)) return val;
|
||||
if(val->type == tp_staticmethod) return PK_OBJ_GET(StaticMethod, val).func;
|
||||
if(val->type == tp_classmethod) return VAR(BoundMethod(obj, PK_OBJ_GET(ClassMethod, val).func));
|
||||
return val;
|
||||
}
|
||||
}
|
||||
if(cls_var != nullptr){
|
||||
// bound method is non-data descriptor
|
||||
if(is_non_tagged_type(cls_var, tp_function) || is_non_tagged_type(cls_var, tp_native_func)){
|
||||
return VAR(BoundMethod(obj, cls_var));
|
||||
if(!is_tagged(cls_var)){
|
||||
switch(cls_var->type){
|
||||
case tp_function.index:
|
||||
return VAR(BoundMethod(obj, cls_var));
|
||||
case tp_native_func.index:
|
||||
return VAR(BoundMethod(obj, cls_var));
|
||||
case tp_staticmethod.index:
|
||||
return PK_OBJ_GET(StaticMethod, cls_var).func;
|
||||
case tp_classmethod.index:
|
||||
return VAR(BoundMethod(objtype, PK_OBJ_GET(ClassMethod, cls_var).func));
|
||||
}
|
||||
}
|
||||
return cls_var;
|
||||
}
|
||||
@ -1070,20 +1092,43 @@ PyObject* VM::get_unbound_method(PyObject* obj, StrName name, PyObject** self, b
|
||||
if(cls_var != nullptr){
|
||||
// handle descriptor
|
||||
if(is_non_tagged_type(cls_var, tp_property)){
|
||||
const Property& prop = _CAST(Property&, cls_var);
|
||||
const Property& prop = PK_OBJ_GET(Property, cls_var);
|
||||
return call(prop.getter, obj);
|
||||
}
|
||||
}
|
||||
// handle instance __dict__
|
||||
if(!is_tagged(obj) && obj->is_attr_valid()){
|
||||
PyObject* val = obj->attr().try_get(name);
|
||||
if(val != nullptr) return val;
|
||||
PyObject* val;
|
||||
if(obj->type == tp_type){
|
||||
val = find_name_in_mro(obj, name);
|
||||
}else{
|
||||
val = obj->attr().try_get_likely_found(name);
|
||||
}
|
||||
if(val != nullptr){
|
||||
if(is_tagged(val)) return val;
|
||||
if(val->type == tp_staticmethod) return PK_OBJ_GET(StaticMethod, val).func;
|
||||
if(val->type == tp_classmethod) return VAR(BoundMethod(obj, PK_OBJ_GET(ClassMethod, val).func));
|
||||
return val;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(cls_var != nullptr){
|
||||
if(is_non_tagged_type(cls_var, tp_function) || is_non_tagged_type(cls_var, tp_native_func)){
|
||||
*self = obj;
|
||||
if(!is_tagged(cls_var)){
|
||||
switch(cls_var->type){
|
||||
case tp_function.index:
|
||||
*self = obj;
|
||||
break;
|
||||
case tp_native_func.index:
|
||||
*self = obj;
|
||||
break;
|
||||
case tp_staticmethod.index:
|
||||
*self = PY_NULL;
|
||||
return PK_OBJ_GET(StaticMethod, cls_var).func;
|
||||
case tp_classmethod.index:
|
||||
*self = objtype;
|
||||
return PK_OBJ_GET(ClassMethod, cls_var).func;
|
||||
}
|
||||
}
|
||||
return cls_var;
|
||||
}
|
||||
@ -1119,11 +1164,11 @@ void VM::setattr(PyObject* obj, StrName name, PyObject* value){
|
||||
obj->attr().set(name, value);
|
||||
}
|
||||
|
||||
PyObject* VM::bind(PyObject* obj, const char* sig, NativeFuncC fn, UserData userdata){
|
||||
return bind(obj, sig, nullptr, fn, userdata);
|
||||
PyObject* VM::bind(PyObject* obj, const char* sig, NativeFuncC fn, UserData userdata, BindType bt){
|
||||
return bind(obj, sig, nullptr, fn, userdata, bt);
|
||||
}
|
||||
|
||||
PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, NativeFuncC fn, UserData userdata){
|
||||
PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, NativeFuncC fn, UserData userdata, BindType bt){
|
||||
CodeObject_ co;
|
||||
try{
|
||||
// fn(a, b, *c, d=1) -> None
|
||||
@ -1141,6 +1186,17 @@ PyObject* VM::bind(PyObject* obj, const char* sig, const char* docstring, Native
|
||||
}
|
||||
PyObject* f_obj = VAR(NativeFunc(fn, decl));
|
||||
PK_OBJ_GET(NativeFunc, f_obj).set_userdata(userdata);
|
||||
|
||||
switch(bt){
|
||||
case BindType::STATICMETHOD:
|
||||
f_obj = VAR(StaticMethod(f_obj));
|
||||
break;
|
||||
case BindType::CLASSMETHOD:
|
||||
f_obj = VAR(ClassMethod(f_obj));
|
||||
break;
|
||||
case BindType::DEFAULT:
|
||||
break;
|
||||
}
|
||||
if(obj != nullptr) obj->attr().set(decl->code->name, f_obj);
|
||||
return f_obj;
|
||||
}
|
||||
|
@ -126,3 +126,35 @@ else:
|
||||
pass
|
||||
|
||||
assert TrueClass
|
||||
|
||||
# staticmethod and classmethod
|
||||
class A():
|
||||
dd = 2
|
||||
|
||||
def __init__(self):
|
||||
self.a = 1
|
||||
|
||||
@staticmethod
|
||||
def static_method(txt):
|
||||
return txt
|
||||
|
||||
@classmethod
|
||||
def class_method(cls, txt):
|
||||
return cls.__name__ + txt
|
||||
|
||||
assert A.static_method(123) == 123
|
||||
assert A.class_method('123') == 'A123'
|
||||
assert A().static_method(123) == 123
|
||||
assert A().class_method('123') == 'A123'
|
||||
assert A.dd == 2
|
||||
assert A().dd == 2
|
||||
|
||||
class B(A): pass
|
||||
|
||||
assert B.dd == 2
|
||||
assert B().dd == 2
|
||||
|
||||
assert B.static_method(123) == 123
|
||||
assert B.class_method('123') == 'B123'
|
||||
assert B().static_method(123) == 123
|
||||
assert B().class_method('123') == 'B123'
|
||||
|
@ -14,3 +14,11 @@ a = object()
|
||||
setattr(a, 'b', 1)
|
||||
assert a.b == 1
|
||||
assert getattr(a, 'b') == 1
|
||||
|
||||
try:
|
||||
getattr(a, 'xxx')
|
||||
exit(1)
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
assert getattr(a, 'xxx', 1) == 1
|
||||
|
@ -185,21 +185,21 @@ def row_operation(matrix, target_row, source_row, scale):
|
||||
# 生成随机测试目标
|
||||
min_num = -10.0
|
||||
max_num = 10.0
|
||||
test_mat = mat3x3([[random.uniform(min_num, max_num) for _ in range(3)] for _ in range(3)])
|
||||
static_test_mat_float= mat3x3([
|
||||
[7.264189733952545, -5.432187523625671, 1.8765304152872613],
|
||||
[-2.4910524352374734, 8.989660807513068, -0.7168824333280513],
|
||||
[9.558042327611506, -3.336280256662496, 4.951381528057387]]
|
||||
)
|
||||
test_mat = mat3x3([random.uniform(min_num, max_num) for _ in range(9)])
|
||||
static_test_mat_float= mat3x3(
|
||||
7.264189733952545, -5.432187523625671, 1.8765304152872613,
|
||||
-2.4910524352374734, 8.989660807513068, -0.7168824333280513,
|
||||
9.558042327611506, -3.336280256662496, 4.951381528057387
|
||||
)
|
||||
|
||||
static_test_mat_float_inv = mat3x3([[ 0.32265243, 0.15808159, -0.09939472],
|
||||
[ 0.04199553, 0.13813096, 0.00408326],
|
||||
[-0.59454451, -0.21208362, 0.39658464]])
|
||||
static_test_mat_float_inv = mat3x3( 0.32265243, 0.15808159, -0.09939472,
|
||||
0.04199553, 0.13813096, 0.00408326,
|
||||
-0.59454451, -0.21208362, 0.39658464)
|
||||
|
||||
static_test_mat_int = mat3x3([
|
||||
[1, 2, 3],
|
||||
[4, 5, 6],
|
||||
[7, 8, 9]]
|
||||
1, 2, 3,
|
||||
4, 5, 6,
|
||||
7, 8, 9]
|
||||
)
|
||||
|
||||
# test incorrect number of parameters is passed
|
||||
@ -236,17 +236,19 @@ assert test_mat == test_mat_copy
|
||||
# test setzeros
|
||||
test_mat_copy = test_mat.copy()
|
||||
test_mat_copy.set_zeros()
|
||||
assert test_mat_copy == mat3x3([[0,0,0],[0,0,0],[0,0,0]])
|
||||
assert test_mat_copy == mat3x3.zeros()
|
||||
|
||||
# test set_ones
|
||||
test_mat_copy = test_mat.copy()
|
||||
test_mat_copy.set_ones()
|
||||
assert test_mat_copy == mat3x3([[1,1,1],[1,1,1],[1,1,1]])
|
||||
assert test_mat_copy == mat3x3.ones()
|
||||
|
||||
# test set_identity
|
||||
test_mat_copy = test_mat.copy()
|
||||
test_mat_copy.set_identity()
|
||||
assert test_mat_copy == mat3x3([[1, 0, 0],[0, 1, 0],[0, 0, 1]])
|
||||
assert test_mat_copy == mat3x3([1, 0, 0,
|
||||
0, 1, 0,
|
||||
0, 0, 1])
|
||||
|
||||
# test __getitem__
|
||||
for i, element in enumerate([getattr(test_mat, e) for e in element_name_list]):
|
||||
@ -268,7 +270,9 @@ except:
|
||||
test_mat_copy = test_mat.copy()
|
||||
for i, element in enumerate([getattr(test_mat_copy, e) for e in element_name_list]):
|
||||
test_mat_copy[int(i/3), i%3] = list(range(9))[i]
|
||||
assert test_mat_copy == mat3x3([[0,1,2], [3,4,5], [6,7,8]])
|
||||
assert test_mat_copy == mat3x3([0,1,2,
|
||||
3,4,5,
|
||||
6,7,8])
|
||||
|
||||
try:
|
||||
test_mat[1,2,3] = 1
|
||||
@ -380,25 +384,19 @@ assert test_mat_copy.transpose() == test_mat_copy.transpose().transpose().transp
|
||||
assert ~static_test_mat_float == static_test_mat_float_inv
|
||||
|
||||
try:
|
||||
mat3x3([[1, 2, 3], [2, 4, 6], [3, 6, 9]]).inverse()
|
||||
~mat3x3([1, 2, 3, 2, 4, 6, 3, 6, 9])
|
||||
raise Exception('未能拦截错误 ValueError("matrix is not invertible") 在 test_mat_copy 的行列式为0')
|
||||
except:
|
||||
pass
|
||||
|
||||
try:
|
||||
~mat3x3([[1, 2, 3], [2, 4, 6], [3, 6, 9]])
|
||||
raise Exception('未能拦截错误 ValueError("matrix is not invertible") 在 test_mat_copy 的行列式为0')
|
||||
except:
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
# test zeros
|
||||
assert mat3x3([[0 for _ in range(3)] for _ in range(3)]) == mat3x3.zeros()
|
||||
assert mat3x3([0 for _ in range(9)]) == mat3x3.zeros()
|
||||
|
||||
# test ones
|
||||
assert mat3x3([[1 for _ in range(3)] for _ in range(3)]) == mat3x3.ones()
|
||||
assert mat3x3([1 for _ in range(9)]) == mat3x3.ones()
|
||||
|
||||
# test identity
|
||||
assert mat3x3([[1,0,0],[0,1,0],[0,0,1]]) == mat3x3.identity()
|
||||
assert mat3x3([1,0,0,0,1,0,0,0,1]) == mat3x3.identity()
|
||||
|
||||
|
||||
# test affine transformations-----------------------------------------------
|
||||
@ -471,3 +469,13 @@ assert vec2.from_struct(b) == a
|
||||
|
||||
val = vec2.angle(vec2(-1, 0), vec2(0, -1))
|
||||
assert 1.57 < val < 1.58
|
||||
|
||||
# test about staticmethod
|
||||
class mymat3x3(mat3x3):
|
||||
def f(self):
|
||||
_0 = self.zeros()
|
||||
_1 = super().zeros()
|
||||
_2 = mat3x3.zeros()
|
||||
return _0 == _1 == _2
|
||||
|
||||
assert mymat3x3().f()
|
||||
|
@ -95,22 +95,6 @@ try:
|
||||
except:
|
||||
pass
|
||||
|
||||
|
||||
class A():
|
||||
def __init__(self):
|
||||
self.a = 1
|
||||
|
||||
@staticmethod
|
||||
def static_method(txt):
|
||||
return txt
|
||||
|
||||
# @classmethod
|
||||
# def class_method(cls, txt):
|
||||
# return cls.__name__ + txt
|
||||
|
||||
assert A.static_method(123) == 123
|
||||
# assert A.class_method(123) == 'A123'
|
||||
|
||||
# 无法测试 -----------------------------------------------
|
||||
# 248: 192: _vm->bind_builtin_func<1>("__import__", [](VM* vm, ArgsView args) {
|
||||
# 67: 193: const Str& name = CAST(Str&, args[0]);
|
||||
|
Loading…
x
Reference in New Issue
Block a user