mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 03:20:18 +00:00
...
This commit is contained in:
parent
fb3ffaa020
commit
d8d25894c7
@ -138,13 +138,14 @@ void _bind(VM* vm, PyObject* obj, const char* sig, Ret(T::*func)(Params...)){
|
||||
#define PY_STRUCT_LIKE(wT) \
|
||||
using vT = std::remove_pointer_t<decltype(std::declval<wT>()._())>; \
|
||||
static_assert(std::is_trivially_copyable<vT>::value); \
|
||||
type->attr().set("__struct__", vm->True); \
|
||||
vm->bind_func<1>(type, "from_struct", [](VM* vm, ArgsView args){ \
|
||||
C99Struct& s = CAST(C99Struct&, args[0]); \
|
||||
if(s.size != sizeof(vT)) vm->ValueError("size mismatch"); \
|
||||
PyObject* obj = vm->heap.gcnew<wT>(wT::_type(vm)); \
|
||||
memcpy(_CAST(wT&, obj)._(), s.p, sizeof(vT)); \
|
||||
return obj; \
|
||||
}); \
|
||||
}, {}, BindType::STATICMETHOD); \
|
||||
vm->bind_method<0>(type, "to_struct", [](VM* vm, ArgsView args){ \
|
||||
wT& self = _CAST(wT&, args[0]); \
|
||||
return VAR_T(C99Struct, self._(), sizeof(vT)); \
|
||||
|
@ -141,6 +141,7 @@ struct SStream{
|
||||
SStream& operator<<(std::string_view s);
|
||||
SStream& operator<<(char c);
|
||||
SStream& operator<<(StrName sn);
|
||||
void write_hex(unsigned char c);
|
||||
|
||||
template<typename T>
|
||||
SStream& operator<<(T val){
|
||||
|
@ -449,7 +449,7 @@ public:
|
||||
template<int ARGC>
|
||||
PyObject* bind_method(PyObject*, Str, NativeFuncC);
|
||||
template<int ARGC>
|
||||
PyObject* bind_func(PyObject*, Str, NativeFuncC);
|
||||
PyObject* bind_func(PyObject*, Str, NativeFuncC, UserData userdata={}, BindType bt=BindType::DEFAULT);
|
||||
void _error(PyObject*);
|
||||
PyObject* _run_top_frame();
|
||||
void post_init();
|
||||
@ -624,8 +624,14 @@ PyObject* VM::bind_method(PyObject* obj, Str name, NativeFuncC fn) {
|
||||
}
|
||||
|
||||
template<int ARGC>
|
||||
PyObject* VM::bind_func(PyObject* obj, Str name, NativeFuncC fn) {
|
||||
PyObject* VM::bind_func(PyObject* obj, Str name, NativeFuncC fn, UserData userdata, BindType bt) {
|
||||
PyObject* nf = VAR(NativeFunc(fn, ARGC, false));
|
||||
PK_OBJ_GET(NativeFunc, nf).set_userdata(userdata);
|
||||
switch(bt){
|
||||
case BindType::DEFAULT: break;
|
||||
case BindType::STATICMETHOD: nf = VAR(StaticMethod(nf)); break;
|
||||
case BindType::CLASSMETHOD: nf = VAR(ClassMethod(nf)); break;
|
||||
}
|
||||
obj->attr().set(name, nf);
|
||||
return nf;
|
||||
}
|
||||
|
@ -57,6 +57,10 @@ class struct:
|
||||
def __eq__(self, other: 'struct') -> bool: ...
|
||||
def __ne__(self, other: 'struct') -> bool: ...
|
||||
|
||||
def hex(self) -> str: ...
|
||||
@staticmethod
|
||||
def from_hex(s: str) -> 'struct': ...
|
||||
|
||||
def read_char(self, offset=0) -> int: ...
|
||||
def read_uchar(self, offset=0) -> int: ...
|
||||
def read_short(self, offset=0) -> int: ...
|
||||
|
@ -1,4 +1,5 @@
|
||||
import json
|
||||
from c import struct
|
||||
import builtins
|
||||
|
||||
_BASIC_TYPES = [int, float, str, bool, type(None)]
|
||||
@ -16,18 +17,20 @@ class _Pickler:
|
||||
self.raw_memo = {} # id -> int
|
||||
self.memo = [] # int -> object
|
||||
|
||||
def _type_id(self, o: type):
|
||||
assert type(o) is type
|
||||
name = o.__name__
|
||||
mod = o.__module__
|
||||
@staticmethod
|
||||
def _type_id(t: type):
|
||||
assert type(t) is type
|
||||
name = t.__name__
|
||||
mod = t.__module__
|
||||
if mod is not None:
|
||||
name = mod.__path__ + _MOD_T_SEP + name
|
||||
return name
|
||||
|
||||
def wrap(self, o):
|
||||
if type(o) in _BASIC_TYPES:
|
||||
o_t = type(o)
|
||||
if o_t in _BASIC_TYPES:
|
||||
return o
|
||||
if type(o) is type:
|
||||
if o_t is type:
|
||||
return ["type", self._type_id(o)]
|
||||
|
||||
index = self.raw_memo.get(id(o), None)
|
||||
@ -39,25 +42,29 @@ class _Pickler:
|
||||
self.memo.append(ret)
|
||||
self.raw_memo[id(o)] = index
|
||||
|
||||
if type(o) is tuple:
|
||||
if o_t is tuple:
|
||||
ret.append("tuple")
|
||||
ret.append([self.wrap(i) for i in o])
|
||||
return [index]
|
||||
if type(o) is bytes:
|
||||
if o_t is bytes:
|
||||
ret.append("bytes")
|
||||
ret.append([o[j] for j in range(len(o))])
|
||||
return [index]
|
||||
|
||||
if type(o) is list:
|
||||
if o_t is list:
|
||||
ret.append("list")
|
||||
ret.append([self.wrap(i) for i in o])
|
||||
return [index]
|
||||
if type(o) is dict:
|
||||
if o_t is dict:
|
||||
ret.append("dict")
|
||||
ret.append([[self.wrap(k), self.wrap(v)] for k,v in o.items()])
|
||||
return [index]
|
||||
|
||||
_0 = self._type_id(type(o))
|
||||
_0 = self._type_id(o_t)
|
||||
|
||||
if getattr(o_t, '__struct__', False):
|
||||
ret.append(_0)
|
||||
ret.append(o.to_struct().hex())
|
||||
return [index]
|
||||
|
||||
if hasattr(o, "__getnewargs__"):
|
||||
_1 = o.__getnewargs__() # an iterable
|
||||
@ -68,13 +75,11 @@ class _Pickler:
|
||||
if o.__dict__ is None:
|
||||
_2 = None
|
||||
else:
|
||||
_2 = {}
|
||||
for k,v in o.__dict__.items():
|
||||
_2[k] = self.wrap(v)
|
||||
_2 = {k: self.wrap(v) for k,v in o.__dict__.items()}
|
||||
|
||||
ret.append(_0)
|
||||
ret.append(_1)
|
||||
ret.append(_2)
|
||||
ret.append(_0) # type id
|
||||
ret.append(_1) # newargs
|
||||
ret.append(_2) # state
|
||||
return [index]
|
||||
|
||||
def run_pipe(self):
|
||||
@ -122,7 +127,6 @@ class _Unpickler:
|
||||
ret = bytes(o[1])
|
||||
self.tag(index, ret)
|
||||
return ret
|
||||
|
||||
if o[0] == "list":
|
||||
ret = []
|
||||
self.tag(index, ret)
|
||||
@ -137,21 +141,26 @@ class _Unpickler:
|
||||
return ret
|
||||
|
||||
# generic object
|
||||
cls, newargs, state = o
|
||||
cls = _find_class(o[0])
|
||||
# create uninitialized instance
|
||||
new_f = getattr(cls, "__new__")
|
||||
if newargs is not None:
|
||||
newargs = [self.unwrap(i) for i in newargs]
|
||||
inst = new_f(cls, *newargs)
|
||||
if getattr(cls, '__struct__', False):
|
||||
inst = cls.from_struct(struct.from_hex(o[1]))
|
||||
self.tag(index, inst)
|
||||
return inst
|
||||
else:
|
||||
inst = new_f(cls)
|
||||
self.tag(index, inst)
|
||||
# restore state
|
||||
if state is not None:
|
||||
for k,v in state.items():
|
||||
setattr(inst, k, self.unwrap(v))
|
||||
return inst
|
||||
_, newargs, state = o
|
||||
# create uninitialized instance
|
||||
new_f = getattr(cls, "__new__")
|
||||
if newargs is not None:
|
||||
newargs = [self.unwrap(i) for i in newargs]
|
||||
inst = new_f(cls, *newargs)
|
||||
else:
|
||||
inst = new_f(cls)
|
||||
self.tag(index, inst)
|
||||
# restore state
|
||||
if state is not None:
|
||||
for k,v in state.items():
|
||||
setattr(inst, k, self.unwrap(v))
|
||||
return inst
|
||||
|
||||
def run_pipe(self):
|
||||
return self.unwrap(self.obj)
|
||||
|
27
src/cffi.cpp
27
src/cffi.cpp
@ -44,6 +44,33 @@ namespace pkpy{
|
||||
return vm->heap.gcnew<C99Struct>(cls, size);
|
||||
});
|
||||
|
||||
vm->bind_method<0>(type, "hex", [](VM* vm, ArgsView args){
|
||||
const C99Struct& self = _CAST(C99Struct&, args[0]);
|
||||
SStream ss;
|
||||
ss << "0x";
|
||||
for(int i=0; i<self.size; i++) ss.write_hex((unsigned char)self.p[i]);
|
||||
return VAR(ss.str());
|
||||
});
|
||||
|
||||
// @staticmethod
|
||||
vm->bind_func<1>(type, "from_hex", [](VM* vm, ArgsView args){
|
||||
const Str& s = CAST(Str&, args[0]);
|
||||
if(s.size<4 || s[0]!='0' || s[1]!='x' || s.size%2!=0) vm->ValueError("invalid hex string");
|
||||
C99Struct buffer(s.size/2-1, false);
|
||||
for(int i=2; i<s.size; i+=2){
|
||||
char c = 0;
|
||||
if(s[i]>='0' && s[i]<='9') c += s[i]-'0';
|
||||
else if(s[i]>='A' && s[i]<='F') c += s[i]-'A'+10;
|
||||
else vm->ValueError(fmt("invalid hex char: '", s[i], "'"));
|
||||
c <<= 4;
|
||||
if(s[i+1]>='0' && s[i+1]<='9') c += s[i+1]-'0';
|
||||
else if(s[i+1]>='A' && s[i+1]<='F') c += s[i+1]-'A'+10;
|
||||
else vm->ValueError(fmt("invalid hex char: '", s[i+1], "'"));
|
||||
buffer.p[i/2-1] = c;
|
||||
}
|
||||
return VAR_T(C99Struct, std::move(buffer));
|
||||
}, {}, BindType::STATICMETHOD);
|
||||
|
||||
vm->bind__repr__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){
|
||||
C99Struct& self = _CAST(C99Struct&, obj);
|
||||
SStream ss;
|
||||
|
@ -105,11 +105,6 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, PyVec2& currentVelocity, float
|
||||
return vm->heap.gcnew<PyVec2>(PK_OBJ_GET(Type, args[0]), Vec2(x, y));
|
||||
});
|
||||
|
||||
vm->bind_method<0>(type, "__getnewargs__", [](VM* vm, ArgsView args){
|
||||
PyVec2& self = _CAST(PyVec2&, args[0]);
|
||||
return VAR(Tuple({ VAR(self.x), VAR(self.y) }));
|
||||
});
|
||||
|
||||
// @staticmethod
|
||||
vm->bind(type, "smooth_damp(current: vec2, target: vec2, current_velocity: vec2, smooth_time: float, max_speed: float, delta_time: float) -> vec2", [](VM* vm, ArgsView args){
|
||||
Vec2 current = CAST(Vec2, args[0]);
|
||||
@ -178,11 +173,6 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, PyVec2& currentVelocity, float
|
||||
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){
|
||||
PyVec3& self = _CAST(PyVec3&, args[0]);
|
||||
return VAR(Tuple({ VAR(self.x), VAR(self.y), VAR(self.z) }));
|
||||
});
|
||||
|
||||
vm->bind__repr__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){
|
||||
PyVec3& self = _CAST(PyVec3&, obj);
|
||||
std::stringstream ss;
|
||||
@ -218,11 +208,6 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, PyVec2& currentVelocity, float
|
||||
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){
|
||||
PyVec4& self = _CAST(PyVec4&, args[0]);
|
||||
return VAR(Tuple({ VAR(self.x), VAR(self.y), VAR(self.z), VAR(self.w) }));
|
||||
});
|
||||
|
||||
vm->bind__repr__(PK_OBJ_GET(Type, type), [](VM* vm, PyObject* obj){
|
||||
PyVec4& self = _CAST(PyVec4&, obj);
|
||||
std::stringstream ss;
|
||||
@ -275,13 +260,6 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, PyVec2& currentVelocity, float
|
||||
return vm->None;
|
||||
});
|
||||
|
||||
vm->bind_method<0>(type, "__getnewargs__", [](VM* vm, ArgsView args){
|
||||
PyMat3x3& self = _CAST(PyMat3x3&, args[0]);
|
||||
Tuple t(9);
|
||||
for(int i=0; i<9; i++) t[i] = VAR(self.v[i]);
|
||||
return VAR(std::move(t));
|
||||
});
|
||||
|
||||
vm->bind_method<1>(type, "assign", [](VM* vm, ArgsView args){
|
||||
PyMat3x3& self = _CAST(PyMat3x3&, args[0]);
|
||||
const PyMat3x3& other = CAST(PyMat3x3&, args[1]);
|
||||
|
@ -988,9 +988,8 @@ void init_builtins(VM* _vm) {
|
||||
SStream ss;
|
||||
ss << "b'";
|
||||
for(int i=0; i<self.size(); i++){
|
||||
ss << "\\x"; // << std::hex << std::setw(2) << std::setfill('0') << self[i];
|
||||
ss << "0123456789ABCDEF"[self[i] >> 4];
|
||||
ss << "0123456789ABCDEF"[self[i] & 0xf];
|
||||
ss << "\\x";
|
||||
ss.write_hex((unsigned char)self[i]);
|
||||
}
|
||||
ss << "'";
|
||||
return VAR(ss.str());
|
||||
|
@ -488,4 +488,10 @@ int utf8len(unsigned char c, bool suppress){
|
||||
std::reverse(begin, buffer.end());
|
||||
return *this;
|
||||
}
|
||||
|
||||
void SStream::write_hex(unsigned char c){
|
||||
*this << "0123456789ABCDEF"[c >> 4];
|
||||
*this << "0123456789ABCDEF"[c & 0xf];
|
||||
}
|
||||
|
||||
} // namespace pkpy
|
@ -62,3 +62,13 @@ assert p[4] == ord("o")
|
||||
assert p[5] == ord("!")
|
||||
assert p[6] == 0
|
||||
assert p.read_string() == "Hello!"
|
||||
|
||||
s = c.struct(67)
|
||||
for i in range(67):
|
||||
s.write_char(i, i)
|
||||
|
||||
s_hex = s.hex()
|
||||
s_r = c.struct.from_hex(s_hex)
|
||||
assert (s == s_r and s is not s_r), (s_hex, s_r.hex())
|
||||
assert s_hex == s_r.hex()
|
||||
|
||||
|
@ -58,11 +58,6 @@ static_test_vec3_int = vec3(278, -13919730938747, 1364223456756456)
|
||||
assert str(static_test_vec3_float).startswith('vec3(')
|
||||
assert str(static_test_vec3_int).startswith('vec3(')
|
||||
|
||||
# test __getnewargs__
|
||||
element_name_list = ['x', 'y', 'z']
|
||||
element_value_list = [getattr(test_vec3, attr) for attr in element_name_list]
|
||||
assert tuple(element_value_list) == test_vec3.__getnewargs__()
|
||||
|
||||
# test copy
|
||||
element_name_list = ['x', 'y', 'z']
|
||||
element_value_list = [getattr(test_vec3, attr) for attr in element_name_list]
|
||||
@ -81,13 +76,6 @@ static_test_vec4_int = vec4(278, -13919730938747, 1364223456756456, -37)
|
||||
assert str(static_test_vec4_float).startswith('vec4(')
|
||||
assert str(static_test_vec4_int).startswith('vec4(')
|
||||
|
||||
# test __getnewargs__
|
||||
element_name_list = ['x', 'y', 'z', 'w']
|
||||
element_value_list = [getattr(test_vec4, attr) for attr in element_name_list]
|
||||
_0 = tuple(element_value_list)
|
||||
_1 = test_vec4.__getnewargs__()
|
||||
assert (_0 == _1), (_0, _1)
|
||||
|
||||
# test copy
|
||||
element_name_list = ['x', 'y', 'z', 'w']
|
||||
element_value_list = [getattr(test_vec4, attr) for attr in element_name_list]
|
||||
@ -341,11 +329,6 @@ test_mat_copy.determinant()
|
||||
assert str(static_test_mat_float)
|
||||
assert str(static_test_mat_int)
|
||||
|
||||
# test __getnewargs__
|
||||
test_mat_copy = test_mat.copy()
|
||||
element_value_list = [getattr(test_mat, attr) for attr in element_name_list]
|
||||
assert tuple(element_value_list) == test_mat.__getnewargs__()
|
||||
|
||||
# test __truediv__
|
||||
test_mat_copy = test_mat.copy()
|
||||
result_mat = test_mat_copy.__truediv__(12.345)
|
||||
|
Loading…
x
Reference in New Issue
Block a user