This commit is contained in:
blueloveTH 2024-01-15 14:40:24 +08:00
parent fb3ffaa020
commit d8d25894c7
11 changed files with 101 additions and 77 deletions

View File

@ -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)); \

View File

@ -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){

View File

@ -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;
}

View File

@ -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: ...

View File

@ -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)

View File

@ -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;

View File

@ -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]);

View File

@ -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());

View File

@ -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

View File

@ -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()

View File

@ -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)