diff --git a/docs/features/basic.md b/docs/features/basic.md index 1731c54f..a34a2e2b 100644 --- a/docs/features/basic.md +++ b/docs/features/basic.md @@ -44,7 +44,6 @@ The features marked with `YES` are supported, and the features marked with `NO` + `__iter__` + `__next__` + `__neg__` -+ `__bool__` (unused) #### Logical operators diff --git a/include/pocketpy/str.h b/include/pocketpy/str.h index 3bcf7c95..a21a9037 100644 --- a/include/pocketpy/str.h +++ b/include/pocketpy/str.h @@ -176,12 +176,11 @@ struct CString{ // unary operators const StrName __repr__ = StrName::get("__repr__"); const StrName __str__ = StrName::get("__str__"); -const StrName __hash__ = StrName::get("__hash__"); // unused +const StrName __hash__ = StrName::get("__hash__"); const StrName __len__ = StrName::get("__len__"); const StrName __iter__ = StrName::get("__iter__"); -const StrName __next__ = StrName::get("__next__"); // unused -const StrName __neg__ = StrName::get("__neg__"); // unused -const StrName __bool__ = StrName::get("__bool__"); // unused +const StrName __next__ = StrName::get("__next__"); +const StrName __neg__ = StrName::get("__neg__"); // logical operators const StrName __eq__ = StrName::get("__eq__"); const StrName __lt__ = StrName::get("__lt__"); diff --git a/include/pocketpy/vm.h b/include/pocketpy/vm.h index 2f10c573..ab04baa1 100644 --- a/include/pocketpy/vm.h +++ b/include/pocketpy/vm.h @@ -57,7 +57,6 @@ struct PyTypeInfo{ PyObject* (*m__iter__)(VM* vm, PyObject*) = nullptr; PyObject* (*m__next__)(VM* vm, PyObject*) = nullptr; PyObject* (*m__neg__)(VM* vm, PyObject*) = nullptr; - PyObject* (*m__bool__)(VM* vm, PyObject*) = nullptr; PyObject* (*m__invert__)(VM* vm, PyObject*) = nullptr; BinaryFuncC m__eq__ = nullptr; @@ -244,60 +243,37 @@ public: Type _new_type_object(StrName name, Type base=0, bool subclass_enabled=false); const PyTypeInfo* _inst_type_info(PyObject* obj); -#define BIND_UNARY_SPECIAL(name) \ - void bind##name(Type type, PyObject* (*f)(VM*, PyObject*)){ \ - _all_types[type].m##name = f; \ - PyObject* nf = bind_method<0>(_t(type), #name, [](VM* vm, ArgsView args){ \ - return lambda_get_userdata(args.begin())(vm, args[0]);\ - }); \ - PK_OBJ_GET(NativeFunc, nf).set_userdata(f); \ - } - - BIND_UNARY_SPECIAL(__repr__) - BIND_UNARY_SPECIAL(__str__) - BIND_UNARY_SPECIAL(__iter__) - BIND_UNARY_SPECIAL(__next__) - BIND_UNARY_SPECIAL(__neg__) - BIND_UNARY_SPECIAL(__bool__) - BIND_UNARY_SPECIAL(__invert__) - + void bind__repr__(Type type, PyObject* (*f)(VM*, PyObject*)); + void bind__str__(Type type, PyObject* (*f)(VM*, PyObject*)); + void bind__iter__(Type type, PyObject* (*f)(VM*, PyObject*)); + void bind__next__(Type type, PyObject* (*f)(VM*, PyObject*)); + void bind__neg__(Type type, PyObject* (*f)(VM*, PyObject*)); + void bind__invert__(Type type, PyObject* (*f)(VM*, PyObject*)); void bind__hash__(Type type, i64 (*f)(VM* vm, PyObject*)); void bind__len__(Type type, i64 (*f)(VM* vm, PyObject*)); -#undef BIND_UNARY_SPECIAL -#define BIND_BINARY_SPECIAL(name) \ - void bind##name(Type type, BinaryFuncC f){ \ - _all_types[type].m##name = f; \ - PyObject* nf = bind_method<1>(type, #name, [](VM* vm, ArgsView args){ \ - return lambda_get_userdata(args.begin())(vm, args[0], args[1]);\ - }); \ - PK_OBJ_GET(NativeFunc, nf).set_userdata(f); \ - } + void bind__eq__(Type type, BinaryFuncC f); + void bind__lt__(Type type, BinaryFuncC f); + void bind__le__(Type type, BinaryFuncC f); + void bind__gt__(Type type, BinaryFuncC f); + void bind__ge__(Type type, BinaryFuncC f); + void bind__contains__(Type type, BinaryFuncC f); - BIND_BINARY_SPECIAL(__eq__) - BIND_BINARY_SPECIAL(__lt__) - BIND_BINARY_SPECIAL(__le__) - BIND_BINARY_SPECIAL(__gt__) - BIND_BINARY_SPECIAL(__ge__) - BIND_BINARY_SPECIAL(__contains__) + void bind__add__(Type type, BinaryFuncC f); + void bind__sub__(Type type, BinaryFuncC f); + void bind__mul__(Type type, BinaryFuncC f); + void bind__truediv__(Type type, BinaryFuncC f); + void bind__floordiv__(Type type, BinaryFuncC f); + void bind__mod__(Type type, BinaryFuncC f); + void bind__pow__(Type type, BinaryFuncC f); + void bind__matmul__(Type type, BinaryFuncC f); - BIND_BINARY_SPECIAL(__add__) - BIND_BINARY_SPECIAL(__sub__) - BIND_BINARY_SPECIAL(__mul__) - BIND_BINARY_SPECIAL(__truediv__) - BIND_BINARY_SPECIAL(__floordiv__) - BIND_BINARY_SPECIAL(__mod__) - BIND_BINARY_SPECIAL(__pow__) - BIND_BINARY_SPECIAL(__matmul__) - - BIND_BINARY_SPECIAL(__lshift__) - BIND_BINARY_SPECIAL(__rshift__) - BIND_BINARY_SPECIAL(__and__) - BIND_BINARY_SPECIAL(__or__) - BIND_BINARY_SPECIAL(__xor__) - -#undef BIND_BINARY_SPECIAL + void bind__lshift__(Type type, BinaryFuncC f); + void bind__rshift__(Type type, BinaryFuncC f); + void bind__and__(Type type, BinaryFuncC f); + void bind__or__(Type type, BinaryFuncC f); + void bind__xor__(Type type, BinaryFuncC f); void bind__getitem__(Type type, PyObject* (*f)(VM*, PyObject*, PyObject*)); void bind__setitem__(Type type, void (*f)(VM*, PyObject*, PyObject*, PyObject*)); @@ -314,19 +290,12 @@ public: template PyObject* bind_constructor(__T&& type, NativeFuncC fn) { static_assert(ARGC==-1 || ARGC>=1); - return bind_func(std::forward<__T>(type), "__new__", fn); - } - - template - PyObject* bind_default_constructor(__T&& type) { - return bind_constructor<1>(std::forward<__T>(type), [](VM* vm, ArgsView args){ - return vm->heap.gcnew(PK_OBJ_GET(Type, args[0]), T()); - }); + return bind_func(std::forward<__T>(type), __new__, fn); } template PyObject* bind_notimplemented_constructor(__T&& type) { - return bind_constructor<-1>(std::forward<__T>(type), [](VM* vm, ArgsView args){ + return bind_func<-1>(std::forward<__T>(type), __new__, [](VM* vm, ArgsView args){ vm->NotImplementedError(); return vm->None; }); @@ -357,19 +326,8 @@ public: void KeyError(PyObject* obj){ _builtin_error("KeyError", obj); } void ImportError(const Str& msg){ _builtin_error("ImportError", msg); } - void BinaryOptError(const char* op, PyObject* _0, PyObject* _1) { - StrName name_0 = _type_name(vm, _tp(_0)); - StrName name_1 = _type_name(vm, _tp(_1)); - TypeError(_S("unsupported operand type(s) for ", op, ": ", name_0.escape(), " and ", name_1.escape())); - } - - void AttributeError(PyObject* obj, StrName name){ - if(isinstance(obj, vm->tp_type)){ - _builtin_error("AttributeError", _S("type object ", _type_name(vm, PK_OBJ_GET(Type, obj)).escape(), " has no attribute ", name.escape())); - }else{ - _builtin_error("AttributeError", _S(_type_name(vm, _tp(obj)).escape(), " object has no attribute ", name.escape())); - } - } + void BinaryOptError(const char* op, PyObject* _0, PyObject* _1); + void AttributeError(PyObject* obj, StrName name); void AttributeError(const Str& msg){ _builtin_error("AttributeError", msg); } void check_type(PyObject* obj, Type type){ @@ -447,11 +405,11 @@ public: PyObject* _format_string(Str, PyObject*); void setattr(PyObject* obj, StrName name, PyObject* value); template - PyObject* bind_method(Type, Str, NativeFuncC); + PyObject* bind_method(Type, StrName, NativeFuncC); template - PyObject* bind_method(PyObject*, Str, NativeFuncC); + PyObject* bind_method(PyObject*, StrName, NativeFuncC); template - PyObject* bind_func(PyObject*, Str, NativeFuncC, UserData userdata={}, BindType bt=BindType::DEFAULT); + PyObject* bind_func(PyObject*, StrName, NativeFuncC, UserData userdata={}, BindType bt=BindType::DEFAULT); void _error(PyObject*); PyObject* _run_top_frame(); void post_init(); @@ -615,20 +573,20 @@ __T _py_cast(VM* vm, PyObject* obj) { return _py_cast__internal<__T, false>(vm, template -PyObject* VM::bind_method(Type type, Str name, NativeFuncC fn) { +PyObject* VM::bind_method(Type type, StrName name, NativeFuncC fn) { PyObject* nf = VAR(NativeFunc(fn, ARGC, true)); _t(type)->attr().set(name, nf); return nf; } template -PyObject* VM::bind_method(PyObject* obj, Str name, NativeFuncC fn) { +PyObject* VM::bind_method(PyObject* obj, StrName name, NativeFuncC fn) { check_type(obj, tp_type); return bind_method(PK_OBJ_GET(Type, obj), name, fn); } template -PyObject* VM::bind_func(PyObject* obj, Str name, NativeFuncC fn, UserData userdata, BindType bt) { +PyObject* VM::bind_func(PyObject* obj, StrName name, NativeFuncC fn, UserData userdata, BindType bt) { PyObject* nf = VAR(NativeFunc(fn, ARGC, false)); PK_OBJ_GET(NativeFunc, nf).set_userdata(userdata); switch(bt){ diff --git a/src/cffi.cpp b/src/cffi.cpp index 2919bb21..21156abf 100644 --- a/src/cffi.cpp +++ b/src/cffi.cpp @@ -3,7 +3,7 @@ namespace pkpy{ void VoidP::_register(VM* vm, PyObject* mod, PyObject* type){ - vm->bind_constructor<2>(type, [](VM* vm, ArgsView args){ + vm->bind_func<2>(type, __new__, [](VM* vm, ArgsView args){ Type cls = PK_OBJ_GET(Type, args[0]); i64 addr = CAST(i64, args[1]); return vm->heap.gcnew(cls, reinterpret_cast(addr)); diff --git a/src/linalg.cpp b/src/linalg.cpp index f1b104fb..4ca2bbeb 100644 --- a/src/linalg.cpp +++ b/src/linalg.cpp @@ -264,7 +264,7 @@ static Vec2 SmoothDamp(Vec2 current, Vec2 target, Vec2& currentVelocity, float s void Mat3x3::_register(VM* vm, PyObject* mod, PyObject* type){ PY_STRUCT_LIKE(Mat3x3) - vm->bind_constructor<-1>(type, [](VM* vm, ArgsView args){ + vm->bind_func<-1>(type, __new__, [](VM* vm, ArgsView args){ if(args.size() == 1+0) return vm->heap.gcnew(PK_OBJ_GET(Type, args[0]), Mat3x3::zeros()); if(args.size() == 1+1){ const List& list = CAST(List&, args[1]); diff --git a/src/modules.cpp b/src/modules.cpp index 79594b7c..4fa8fb75 100644 --- a/src/modules.cpp +++ b/src/modules.cpp @@ -266,7 +266,10 @@ struct LineProfilerW{ LineProfiler profiler; static void _register(VM* vm, PyObject* mod, PyObject* type){ - vm->bind_default_constructor(type); + vm->bind_func<1>(type, __new__, [](VM* vm, ArgsView args){ + Type cls = PK_OBJ_GET(Type, args[0]); + return vm->heap.gcnew(cls); + }); vm->bind(type, "add_function(self, func)", [](VM* vm, ArgsView args){ LineProfilerW& self = PK_OBJ_GET(LineProfilerW, args[0]); diff --git a/src/random.cpp b/src/random.cpp index 3415ba58..811dcaf3 100644 --- a/src/random.cpp +++ b/src/random.cpp @@ -11,7 +11,10 @@ struct Random{ } static void _register(VM* vm, PyObject* mod, PyObject* type){ - vm->bind_default_constructor(type); + vm->bind_func<1>(type, __new__, [](VM* vm, ArgsView args){ + Type cls = PK_OBJ_GET(Type, args[0]); + return vm->heap.gcnew(cls); + }); vm->bind_method<1>(type, "seed", [](VM* vm, ArgsView args) { Random& self = _CAST(Random&, args[0]); diff --git a/src/vm.cpp b/src/vm.cpp index ef6724ae..ff063a70 100644 --- a/src/vm.cpp +++ b/src/vm.cpp @@ -1220,6 +1220,20 @@ void VM::_builtin_error(StrName type){ _error(call(builtins->attr(type))); } void VM::_builtin_error(StrName type, PyObject* arg){ _error(call(builtins->attr(type), arg)); } void VM::_builtin_error(StrName type, const Str& msg){ _builtin_error(type, VAR(msg)); } +void VM::BinaryOptError(const char* op, PyObject* _0, PyObject* _1) { + StrName name_0 = _type_name(vm, _tp(_0)); + StrName name_1 = _type_name(vm, _tp(_1)); + TypeError(_S("unsupported operand type(s) for ", op, ": ", name_0.escape(), " and ", name_1.escape())); +} + +void VM::AttributeError(PyObject* obj, StrName name){ + if(isinstance(obj, vm->tp_type)){ + _builtin_error("AttributeError", _S("type object ", _type_name(vm, PK_OBJ_GET(Type, obj)).escape(), " has no attribute ", name.escape())); + }else{ + _builtin_error("AttributeError", _S(_type_name(vm, _tp(obj)).escape(), " object has no attribute ", name.escape())); + } +} + void VM::_error(PyObject* e_obj){ PK_ASSERT(isinstance(e_obj, tp_exception)) Exception& e = PK_OBJ_GET(Exception, e_obj); @@ -1293,6 +1307,23 @@ void VM::bind__delitem__(Type type, void (*f)(VM*, PyObject*, PyObject*)){ PK_OBJ_GET(NativeFunc, nf).set_userdata(f); } +#define BIND_UNARY_SPECIAL(name) \ + void VM::bind##name(Type type, PyObject* (*f)(VM*, PyObject*)){ \ + _all_types[type].m##name = f; \ + PyObject* nf = bind_method<0>(_t(type), #name, [](VM* vm, ArgsView args){ \ + return lambda_get_userdata(args.begin())(vm, args[0]);\ + }); \ + PK_OBJ_GET(NativeFunc, nf).set_userdata(f); \ + } + + BIND_UNARY_SPECIAL(__repr__) + BIND_UNARY_SPECIAL(__str__) + BIND_UNARY_SPECIAL(__iter__) + BIND_UNARY_SPECIAL(__next__) + BIND_UNARY_SPECIAL(__neg__) + BIND_UNARY_SPECIAL(__invert__) +#undef BIND_UNARY_SPECIAL + void VM::bind__hash__(Type type, i64 (*f)(VM*, PyObject*)){ PyObject* obj = _t(type); _all_types[type].m__hash__ = f; @@ -1313,6 +1344,41 @@ void VM::bind__len__(Type type, i64 (*f)(VM*, PyObject*)){ PK_OBJ_GET(NativeFunc, nf).set_userdata(f); } + +#define BIND_BINARY_SPECIAL(name) \ + void VM::bind##name(Type type, BinaryFuncC f){ \ + _all_types[type].m##name = f; \ + PyObject* nf = bind_method<1>(type, #name, [](VM* vm, ArgsView args){ \ + return lambda_get_userdata(args.begin())(vm, args[0], args[1]);\ + }); \ + PK_OBJ_GET(NativeFunc, nf).set_userdata(f); \ + } + + BIND_BINARY_SPECIAL(__eq__) + BIND_BINARY_SPECIAL(__lt__) + BIND_BINARY_SPECIAL(__le__) + BIND_BINARY_SPECIAL(__gt__) + BIND_BINARY_SPECIAL(__ge__) + BIND_BINARY_SPECIAL(__contains__) + + BIND_BINARY_SPECIAL(__add__) + BIND_BINARY_SPECIAL(__sub__) + BIND_BINARY_SPECIAL(__mul__) + BIND_BINARY_SPECIAL(__truediv__) + BIND_BINARY_SPECIAL(__floordiv__) + BIND_BINARY_SPECIAL(__mod__) + BIND_BINARY_SPECIAL(__pow__) + BIND_BINARY_SPECIAL(__matmul__) + + BIND_BINARY_SPECIAL(__lshift__) + BIND_BINARY_SPECIAL(__rshift__) + BIND_BINARY_SPECIAL(__and__) + BIND_BINARY_SPECIAL(__or__) + BIND_BINARY_SPECIAL(__xor__) + +#undef BIND_BINARY_SPECIAL + + void Dict::_probe_0(PyObject *key, bool &ok, int &i) const{ ok = false; i64 hash = vm->py_hash(key);