diff --git a/.gitignore b/.gitignore index 26057a57..113e3775 100644 --- a/.gitignore +++ b/.gitignore @@ -21,4 +21,5 @@ plugins/macos/pocketpy/pocketpy.h plugins/godot/godot-cpp/ 123.txt src/_generated.h -profile.sh \ No newline at end of file +profile.sh +test diff --git a/src/ceval.h b/src/ceval.h index 2a2c59de..0b8638e4 100644 --- a/src/ceval.h +++ b/src/ceval.h @@ -18,12 +18,12 @@ PyVar VM::run_frame(Frame* frame){ case OP_LOAD_CONST: frame->push(frame->co->consts[byte.arg]); continue; case OP_LOAD_FUNCTION: { const PyVar obj = frame->co->consts[byte.arg]; - Function f = CAST_V(Function, obj); // copy + Function f = CAST(Function, obj); // copy f._module = frame->_module; frame->push(VAR(f)); } continue; case OP_SETUP_CLOSURE: { - Function& f = CAST(Function, frame->top()); // reference + Function& f = CAST(Function&, frame->top()); // reference f._closure = frame->_locals; } continue; case OP_LOAD_NAME_REF: { @@ -85,7 +85,7 @@ PyVar VM::run_frame(Frame* frame){ case OP_LOAD_EVAL_FN: frame->push(builtins->attr(m_eval)); continue; case OP_LIST_APPEND: { PyVar obj = frame->pop_value(this); - List& list = CAST(List, frame->top_1()); + List& list = CAST(List&, frame->top_1()); list.push_back(std::move(obj)); } continue; case OP_BEGIN_CLASS: { @@ -154,7 +154,7 @@ PyVar VM::run_frame(Frame* frame){ } continue; case OP_CONTAINS_OP: { PyVar rhs = frame->pop_value(this); - bool ret_c = CAST_V(bool, call(rhs, __contains__, one_arg(frame->pop_value(this)))); + bool ret_c = CAST(bool, call(rhs, __contains__, one_arg(frame->pop_value(this)))); if(byte.arg == 1) ret_c = !ret_c; frame->push(VAR(ret_c)); } continue; @@ -164,10 +164,10 @@ PyVar VM::run_frame(Frame* frame){ case OP_UNARY_NOT: { PyVar obj = frame->pop_value(this); const PyVar& obj_bool = asBool(obj); - frame->push(VAR(!_CAST_V(bool, obj_bool))); + frame->push(VAR(!_CAST(bool, obj_bool))); } continue; case OP_POP_JUMP_IF_FALSE: - if(!_CAST_V(bool, asBool(frame->pop_value(this)))) frame->jump_abs(byte.arg); + if(!_CAST(bool, asBool(frame->pop_value(this)))) frame->jump_abs(byte.arg); continue; case OP_LOAD_NONE: frame->push(None); continue; case OP_LOAD_TRUE: frame->push(True); continue; @@ -180,7 +180,7 @@ PyVar VM::run_frame(Frame* frame){ if(asBool(expr) != True) _error("AssertionError", msg); } continue; case OP_EXCEPTION_MATCH: { - const auto& e = CAST(Exception, frame->top()); + const auto& e = CAST(Exception&, frame->top()); StrName name = frame->co->names[byte.arg].first; frame->push(VAR(e.match_type(name))); } continue; @@ -284,8 +284,8 @@ PyVar VM::run_frame(Frame* frame){ PyVar stop = frame->pop_value(this); PyVar start = frame->pop_value(this); Slice s; - if(start != None) { s.start = (int)CAST_V(i64, start);} - if(stop != None) { s.stop = (int)CAST_V(i64, stop);} + if(start != None) { s.start = CAST(int, start);} + if(stop != None) { s.stop = CAST(int, stop);} frame->push(VAR(s)); } continue; case OP_IMPORT_NAME: { diff --git a/src/cffi.h b/src/cffi.h index 593b1cd2..ca9b6f3f 100644 --- a/src/cffi.h +++ b/src/cffi.h @@ -1,130 +1,179 @@ #pragma once +#include "common.h" #include "vm.h" +#include namespace pkpy { -struct CType{ - PY_CLASS(CType, c, type_) +template +struct ProxyFunction { + using T = Ret(*)(Params...); + static constexpr int N = sizeof...(Params); + T func; + ProxyFunction(T func) : func(func) {} - const char* name; // must be a literal - const int size; - const int index; - constexpr CType(const char name[], int size, int index) : name(name), size(size), index(index) {} + PyVar operator()(VM* vm, Args& args) { + if (args.size() != N) vm->TypeError("invalid number of arguments"); + return call(vm, args, std::make_index_sequence()); + } - static void _register(VM* vm, PyVar mod, PyVar type){ - vm->bind_static_method<-1>(type, "__new__", CPP_NOT_IMPLEMENTED()); - - vm->bind_method<0>(type, "__repr__", [](VM* vm, Args& args) { - CType& self = CAST(CType, args[0]); - StrStream ss; - ss << ""; - return VAR(ss.str()); - }); + template + PyVar call(VM* vm, Args& args, std::index_sequence) { + Ret ret = func(py_cast(vm, args[Is])...); + return VAR(std::move(ret)); } }; -constexpr CType kCTypes[] = { - CType("char_", sizeof(char), 0), CType("int_", sizeof(int), 1), - CType("float_", sizeof(float), 2), CType("double_", sizeof(double), 3), - CType("bool_", sizeof(bool), 4), CType("void_", 1, 5), - CType("int8_", sizeof(int8_t), 6), CType("int16_", sizeof(int16_t), 7), - CType("int32_", sizeof(int32_t), 8), CType("int64_", sizeof(int64_t), 9), - CType("uint8_", sizeof(uint8_t), 10), CType("uint16_", sizeof(uint16_t), 11), - CType("uint32_", sizeof(uint32_t), 12), CType("uint64_", sizeof(uint64_t), 13), - CType("void_p_", sizeof(intptr_t), 14), - // use macro here to do extension + +struct TypeInfo; + +struct MemberInfo{ + TypeInfo* type; + int offset; }; -const int kCTypeCount = sizeof(kCTypes) / sizeof(CType); +struct TypeInfo{ + const char* name; + int size; + int index; // for basic types only + std::map members; -constexpr int C_TYPE(const char name[]){ - for(int k=0; k members) + : name(name), size(size), index(-1), members(members) {} + TypeInfo() : name(nullptr), size(0), index(-1) {} +}; + +template +constexpr int type_index() { return -1; } +template<> constexpr int type_index() { return 0; } +template<> constexpr int type_index() { return 1; } +template<> constexpr int type_index() { return 2; } +template<> constexpr int type_index() { return 3; } +template<> constexpr int type_index() { return 4; } +template<> constexpr int type_index() { return 5; } +template<> constexpr int type_index() { return 6; } +template<> constexpr int type_index() { return 7; } +template<> constexpr int type_index() { return 8; } +template<> constexpr int type_index() { return 9; } +template<> constexpr int type_index() { return 10; } +template<> constexpr int type_index() { return 11; } +template<> constexpr int type_index() { return 12; } +template<> constexpr int type_index() { return 13; } + +struct Vec2 { + float x, y; +}; + +static std::map _type_infos; + +auto _ = [](){ + #define REGISTER_BASIC_TYPE(T) _type_infos[#T] = TypeInfo(#T, sizeof(T), type_index()) + _type_infos["void"] = TypeInfo("void", 1, type_index()); + REGISTER_BASIC_TYPE(char); + REGISTER_BASIC_TYPE(short); + REGISTER_BASIC_TYPE(int); + REGISTER_BASIC_TYPE(long); + REGISTER_BASIC_TYPE(long long); + REGISTER_BASIC_TYPE(unsigned char); + REGISTER_BASIC_TYPE(unsigned short); + REGISTER_BASIC_TYPE(unsigned int); + REGISTER_BASIC_TYPE(unsigned long); + REGISTER_BASIC_TYPE(unsigned long long); + REGISTER_BASIC_TYPE(float); + REGISTER_BASIC_TYPE(double); + REGISTER_BASIC_TYPE(bool); + #undef REGISTER_BASIC_TYPE + + _type_infos["Vec2"] = TypeInfo("Vec2", sizeof(Vec2), { + {"x", {&_type_infos["float"], offsetof(Vec2, x)}}, + {"y", {&_type_infos["float"], offsetof(Vec2, y)}}, + }); + return 0; +}(); -#define C_TYPE_T(x) (kCTypes[C_TYPE(x)]) struct Pointer{ PY_CLASS(Pointer, c, ptr_) - void* ptr; - CType ctype; // base type + char* ptr; + TypeInfo* ctype; + int level; // level of pointer - Pointer(void* ptr, CType ctype) : ptr(ptr), ctype(ctype) {} - - Pointer operator+(i64 offset) const { - return Pointer((int8_t*)ptr + offset * ctype.size, ctype); + i64 unit_size() const { + return level == 1 ? ctype->size : sizeof(void*); } - Pointer operator-(i64 offset) const { - return Pointer((int8_t*)ptr - offset * ctype.size, ctype); + bool type_equal(const Pointer& other) const { + return level == other.level && ctype == other.ctype; + } + + Pointer() : ptr(nullptr), ctype(&_type_infos["void"]), level(1) {} + Pointer(char* ptr, TypeInfo* ctype, int level=1) : ptr(ptr), ctype(ctype), level(level) {} + + Pointer operator+(i64 offset) const { + return Pointer(ptr + offset * unit_size(), ctype, level); + } + + Pointer operator-(i64 offset) const { + return Pointer(ptr - offset * unit_size(), ctype, level); } static void _register(VM* vm, PyVar mod, PyVar type){ vm->bind_static_method<-1>(type, "__new__", CPP_NOT_IMPLEMENTED()); vm->bind_method<0>(type, "__repr__", [](VM* vm, Args& args) { - Pointer& self = CAST(Pointer, args[0]); + Pointer& self = CAST(Pointer&, args[0]); StrStream ss; - ss << "<" << self.ctype.name << "* at " << (i64)self.ptr << ">"; + ss << "<" << self.ctype->name; + for(int i=0; i"; return VAR(ss.str()); }); vm->bind_method<1>(type, "__add__", [](VM* vm, Args& args) { - Pointer& self = CAST(Pointer, args[0]); + Pointer& self = CAST(Pointer&, args[0]); return VAR_T(Pointer, self + CAST(i64, args[1])); }); vm->bind_method<1>(type, "__sub__", [](VM* vm, Args& args) { - Pointer& self = CAST(Pointer, args[0]); - return VAR_T(Pointer, self - CAST_V(i64, args[1])); + Pointer& self = CAST(Pointer&, args[0]); + return VAR_T(Pointer, self - CAST(i64, args[1])); }); vm->bind_method<1>(type, "__eq__", [](VM* vm, Args& args) { - Pointer& self = CAST(Pointer, args[0]); - Pointer& other = CAST(Pointer, args[1]); + Pointer& self = CAST(Pointer&, args[0]); + Pointer& other = CAST(Pointer&, args[1]); return VAR(self.ptr == other.ptr); }); vm->bind_method<1>(type, "__ne__", [](VM* vm, Args& args) { - Pointer& self = CAST(Pointer, args[0]); - Pointer& other = CAST(Pointer, args[1]); + Pointer& self = CAST(Pointer&, args[0]); + Pointer& other = CAST(Pointer&, args[1]); return VAR(self.ptr != other.ptr); }); - // https://docs.python.org/zh-cn/3/library/ctypes.html vm->bind_method<1>(type, "__getitem__", [](VM* vm, Args& args) { - Pointer& self = CAST(Pointer, args[0]); - i64 index = CAST_V(i64, args[1]); + Pointer& self = CAST(Pointer&, args[0]); + i64 index = CAST(i64, args[1]); return (self+index).get(vm); }); vm->bind_method<2>(type, "__setitem__", [](VM* vm, Args& args) { - Pointer& self = CAST(Pointer, args[0]); - i64 index = CAST_V(i64, args[1]); + Pointer& self = CAST(Pointer&, args[0]); + i64 index = CAST(i64, args[1]); (self+index).set(vm, args[2]); return vm->None; }); - vm->bind_method<1>(type, "cast", [](VM* vm, Args& args) { - Pointer& self = CAST(Pointer, args[0]); - CType& ctype = CAST(CType, args[1]); - return VAR_T(Pointer, self.ptr, ctype); - }); - vm->bind_method<0>(type, "get", [](VM* vm, Args& args) { - Pointer& self = CAST(Pointer, args[0]); + Pointer& self = CAST(Pointer&, args[0]); return self.get(vm); }); vm->bind_method<1>(type, "set", [](VM* vm, Args& args) { - Pointer& self = CAST(Pointer, args[0]); + Pointer& self = CAST(Pointer&, args[0]); self.set(vm, args[1]); return vm->None; }); @@ -133,118 +182,88 @@ struct Pointer{ template inline T& ref() noexcept { return *reinterpret_cast(ptr); } - template - inline TP cast() noexcept { - static_assert(std::is_pointer_v); - return reinterpret_cast(ptr); - } - PyVar get(VM* vm){ - switch(ctype.index){ - case C_TYPE("char_"): return VAR(ref()); - case C_TYPE("int_"): return VAR(ref()); - case C_TYPE("float_"): return VAR(ref()); - case C_TYPE("double_"): return VAR(ref()); - case C_TYPE("bool_"): return VAR(ref()); - case C_TYPE("void_"): vm->ValueError("cannot get void*"); break; - case C_TYPE("int8_"): return VAR(ref()); - case C_TYPE("int16_"): return VAR(ref()); - case C_TYPE("int32_"): return VAR(ref()); - case C_TYPE("int64_"): return VAR(ref()); - case C_TYPE("uint8_"): return VAR(ref()); - case C_TYPE("uint16_"): return VAR(ref()); - case C_TYPE("uint32_"): return VAR(ref()); - case C_TYPE("uint64_"): return VAR(ref()); - case C_TYPE("void_p_"): return VAR_T(Pointer, ref(), C_TYPE_T("void_")); - // use macro here to do extension - default: UNREACHABLE(); + if(level > 1) return VAR_T(Pointer, ptr, ctype, level-1); + switch(ctype->index){ +#define CASE(T) case type_index(): return VAR(ref()) + case type_index(): vm->ValueError("cannot get void*"); break; + CASE(char); + CASE(short); + CASE(int); + CASE(long); + CASE(long long); + CASE(unsigned char); + CASE(unsigned short); + CASE(unsigned int); + CASE(unsigned long); + CASE(unsigned long long); + CASE(float); + CASE(double); + CASE(bool); +#undef CASE } - return vm->None; + return VAR_T(Pointer, *this); } void set(VM* vm, const PyVar& val){ - switch(ctype.index){ - case C_TYPE("char_"): ref() = CAST_V(i64, val); break; - case C_TYPE("int_"): ref() = CAST_V(i64, val); break; - case C_TYPE("float_"): ref() = CAST_V(f64, val); break; - case C_TYPE("double_"): ref() = CAST_V(f64, val); break; - case C_TYPE("bool_"): ref() = CAST_V(bool, val); break; - case C_TYPE("void_"): vm->ValueError("cannot set void*"); break; - case C_TYPE("int8_"): ref() = CAST_V(i64, val); break; - case C_TYPE("int16_"): ref() = CAST_V(i64, val); break; - case C_TYPE("int32_"): ref() = CAST_V(i64, val); break; - case C_TYPE("int64_"): ref() = CAST_V(i64, val); break; - case C_TYPE("uint8_"): ref() = CAST_V(i64, val); break; - case C_TYPE("uint16_"): ref() = CAST_V(i64, val); break; - case C_TYPE("uint32_"): ref() = CAST_V(i64, val); break; - case C_TYPE("uint64_"): ref() = CAST_V(i64, val); break; - case C_TYPE("void_p_"): ref() = CAST(Pointer, val).ptr; break; - // use macro here to do extension - default: UNREACHABLE(); + if(level > 1) { + Pointer& p = CAST(Pointer&, val); + ref() = p.ptr; // We don't check the type, just copy the underlying address + return; } + switch(ctype->index){ +#define CASE(T1, T2) case type_index(): ref() = CAST(T2, val); break + case type_index(): vm->ValueError("cannot set void*"); break; + CASE(char, i64); + CASE(short, i64); + CASE(int, i64); + CASE(long, i64); + CASE(long long, i64); + CASE(unsigned char, i64); + CASE(unsigned short, i64); + CASE(unsigned int, i64); + CASE(unsigned long, i64); + CASE(unsigned long long, i64); + CASE(float, f64); + CASE(double, f64); + CASE(bool, bool); +#undef CASE + } + UNREACHABLE(); + } + + Pointer address(VM* vm, StrName name){ + auto it = ctype->members.find(name); + if(it == ctype->members.end()){ + vm->AttributeError(Str("struct '") + ctype->name + "' has no member " + name.str().escape(true)); + } + MemberInfo& info = it->second; + return {ptr+info.offset, info.type, level}; } }; -struct StructMemberInfo { - int offset; - CType type; -}; - -struct StructMetaInfo { - Str name; - std::map members; -}; - -struct Point2{ - int x; - int y; -}; - -static const StructMetaInfo _Point2_info = { - "Point2", - { - {StrName("x"), {offsetof(Point2, x), C_TYPE_T("int_")}}, - {StrName("y"), {offsetof(Point2, y), C_TYPE_T("int_")}}, - } -}; struct Struct { PY_CLASS(Struct, c, struct_) - const StructMetaInfo* info; - int8_t* _data; // store any `struct` + char* data; + Pointer head; - Struct(const StructMetaInfo* info, int8_t* data) : info(info), _data(data) {} - Struct(){ - info = &_Point2_info; - _data = new int8_t[sizeof(Point2)]; - } - ~Struct(){ delete[] _data; } + TypeInfo* ctype() const { return head.ctype; } - Pointer address(VM* vm, StrName name){ - auto it = info->members.find(name); - if(it == info->members.end()) vm->AttributeError("struct " + info->name + " has no member " + name.str()); - const StructMemberInfo& info = it->second; - return {_data+info.offset, info.type}; - } - - PyVarOrNull __getattr__(VM* vm, StrName name){ - return address(vm, name).get(vm); - } - - void __setattr__(VM* vm, StrName name, const PyVar& val){ - address(vm, name).set(vm, val); + Struct(const Pointer& head) { + data = new char[head.ctype->size]; + memcpy(data, head.ptr, head.ctype->size); + this->head = Pointer(data, head.ctype, head.level); } static void _register(VM* vm, PyVar mod, PyVar type){ - vm->bind_static_method<-1>(type, "__new__", [](VM* vm, Args& args) { - return VAR_T(Struct); - }); + vm->bind_static_method<-1>(type, "__new__", CPP_NOT_IMPLEMENTED()); vm->bind_method<0>(type, "__repr__", [](VM* vm, Args& args) { - Struct& self = CAST(Struct, args[0]); + Struct& self = CAST(Struct&, args[0]); StrStream ss; - ss << self.info->name << "(" << ")"; + ss << self.ctype()->name << "(" << ")"; return VAR(ss.str()); }); } @@ -253,69 +272,36 @@ struct Struct { void add_module_c(VM* vm){ PyVar mod = vm->new_module("c"); PyVar ptr_t = Pointer::register_class(vm, mod); - CType::register_class(vm, mod); Struct::register_class(vm, mod); - for(int i=0; isetattr(mod, kCTypes[i].name, VAR_T(CType, kCTypes[i])); - } - vm->setattr(mod, "nullptr", VAR_T(Pointer, nullptr, C_TYPE_T("void_"))); + vm->setattr(mod, "nullptr", VAR_T(Pointer, nullptr, &_type_infos["void"])); vm->bind_func<1>(mod, "malloc", [](VM* vm, Args& args) { - i64 size = CAST_V(i64, args[0]); - return VAR_T(Pointer, malloc(size), C_TYPE_T("void_")); + i64 size = CAST(i64, args[0]); + return VAR_T(Pointer, (char*)malloc(size), &_type_infos["void"]); }); vm->bind_func<1>(mod, "free", [](VM* vm, Args& args) { - Pointer& self = CAST(Pointer, args[0]); + Pointer& self = CAST(Pointer&, args[0]); free(self.ptr); return vm->None; }); - vm->bind_func<1>(mod, "sizeof", [](VM* vm, Args& args) { - CType& ctype = CAST(CType, args[0]); - return VAR(ctype.size); - }); - vm->bind_func<3>(mod, "memcpy", [](VM* vm, Args& args) { - Pointer& dst = CAST(Pointer, args[0]); - Pointer& src = CAST(Pointer, args[1]); - i64 size = CAST_V(i64, args[2]); + Pointer& dst = CAST(Pointer&, args[0]); + Pointer& src = CAST(Pointer&, args[1]); + i64 size = CAST(i64, args[2]); memcpy(dst.ptr, src.ptr, size); return vm->None; }); vm->bind_func<3>(mod, "memset", [](VM* vm, Args& args) { - Pointer& dst = CAST(Pointer, args[0]); - i64 val = CAST_V(i64, args[1]); - i64 size = CAST_V(i64, args[2]); + Pointer& dst = CAST(Pointer&, args[0]); + i64 val = CAST(i64, args[1]); + i64 size = CAST(i64, args[2]); memset(dst.ptr, (int)val, size); return vm->None; }); - - vm->bind_func<1>(mod, "strdup", [ptr_t](VM* vm, Args& args) { - if(is_type(args[0], vm->tp_str)){ - const Str& s = CAST(Str, args[0]); - return VAR_T(Pointer, strdup(s.c_str()), C_TYPE_T("char_")); - }else if(is_type(args[0], OBJ_GET(Type, ptr_t))){ - Pointer& p = CAST(Pointer, args[0]); - return VAR_T(Pointer, strdup(p.cast()), C_TYPE_T("char_")); - }else{ - vm->TypeError("strdup() argument must be 'str' or 'char*'"); - return vm->None; - } - }); - - vm->bind_func<2>(mod, "strcmp", [](VM* vm, Args& args) { - Pointer& p1 = CAST(Pointer, args[0]); - Pointer& p2 = CAST(Pointer, args[1]); - return VAR(strcmp(p1.cast(), p2.cast())); - }); - - vm->bind_func<1>(mod, "strlen", [](VM* vm, Args& args) { - Pointer& p = CAST(Pointer, args[0]); - return VAR(strlen(p.cast())); - }); } } // namespace pkpy \ No newline at end of file diff --git a/src/common.h b/src/common.h index a8ec0df0..58a715c7 100644 --- a/src/common.h +++ b/src/common.h @@ -74,8 +74,6 @@ struct Type { #define UNREACHABLE() throw std::runtime_error( __FILE__ + std::string(":") + std::to_string(__LINE__) + " UNREACHABLE()!"); #endif -#define RAW(T) std::remove_const_t> - const float kLocalsLoadFactor = 0.67; const float kInstAttrLoadFactor = 0.67; const float kTypeAttrLoadFactor = 0.5; diff --git a/src/obj.h b/src/obj.h index 52930f2b..f091ce1a 100644 --- a/src/obj.h +++ b/src/obj.h @@ -1,5 +1,6 @@ #pragma once +#include "common.h" #include "namedict.h" #include "tuplelist.h" @@ -173,16 +174,12 @@ union __8B { template struct is_py_class : std::false_type {}; template struct is_py_class> : std::true_type {}; -template -T py_cast_v(VM* vm, const PyVar& var) { UNREACHABLE(); } -template -T _py_cast_v(VM* vm, const PyVar& var) { UNREACHABLE(); } - template void _check_py_class(VM* vm, const PyVar& var); -template -T& py_cast(VM* vm, const PyVar& obj) { +template +__T py_cast(VM* vm, const PyVar& obj) { + using T = std::decay_t<__T>; if constexpr(is_py_class::value){ _check_py_class(vm, obj); return OBJ_GET(T, obj); @@ -190,8 +187,9 @@ T& py_cast(VM* vm, const PyVar& obj) { throw std::runtime_error("bad py_cast() call"); } } -template -T& _py_cast(VM* vm, const PyVar& obj) { +template +__T _py_cast(VM* vm, const PyVar& obj) { + using T = std::decay_t<__T>; if constexpr(is_py_class::value){ return OBJ_GET(T, obj); }else{ @@ -202,8 +200,6 @@ T& _py_cast(VM* vm, const PyVar& obj) { #define VAR(x) py_var(vm, x) #define VAR_T(T, ...) vm->new_object(T::_type(vm), T(__VA_ARGS__)) #define CAST(T, x) py_cast(vm, x) -#define CAST_V(T, x) py_cast_v(vm, x) #define _CAST(T, x) _py_cast(vm, x) -#define _CAST_V(T, x) _py_cast_v(vm, x) } // namespace pkpy \ No newline at end of file diff --git a/src/pocketpy.h b/src/pocketpy.h index 9270548a..1cce096f 100644 --- a/src/pocketpy.h +++ b/src/pocketpy.h @@ -23,7 +23,7 @@ CodeObject_ VM::compile(Str source, Str filename, CompileMode mode) { #define BIND_NUM_ARITH_OPT(name, op) \ _vm->_bind_methods<1>({"int","float"}, #name, [](VM* vm, Args& args){ \ if(is_both_int(args[0], args[1])){ \ - return VAR(_CAST_V(i64, args[0]) op _CAST_V(i64, args[1])); \ + return VAR(_CAST(i64, args[0]) op _CAST(i64, args[1])); \ }else{ \ return VAR(vm->num_to_float(args[0]) op vm->num_to_float(args[1])); \ } \ @@ -36,7 +36,7 @@ CodeObject_ VM::compile(Str source, Str filename, CompileMode mode) { vm->TypeError("unsupported operand type(s) for " #op ); \ } \ if(is_both_int(args[0], args[1])) \ - return VAR(_CAST_V(i64, args[0]) op _CAST_V(i64, args[1])); \ + return VAR(_CAST(i64, args[0]) op _CAST(i64, args[1])); \ return VAR(vm->num_to_float(args[0]) op vm->num_to_float(args[1])); \ }); @@ -57,7 +57,7 @@ void init_builtins(VM* _vm) { #undef BIND_NUM_LOGICAL_OPT _vm->bind_builtin_func<1>("__sys_stdout_write", [](VM* vm, Args& args) { - (*vm->_stdout) << CAST(Str, args[0]); + (*vm->_stdout) << CAST(Str&, args[0]); return vm->None; }); @@ -74,19 +74,19 @@ void init_builtins(VM* _vm) { }); _vm->bind_builtin_func<1>("eval", [](VM* vm, Args& args) { - CodeObject_ code = vm->compile(CAST(Str, args[0]), "", EVAL_MODE); + CodeObject_ code = vm->compile(CAST(Str&, args[0]), "", EVAL_MODE); return vm->_exec(code, vm->top_frame()->_module, vm->top_frame()->_locals); }); _vm->bind_builtin_func<1>("exec", [](VM* vm, Args& args) { - CodeObject_ code = vm->compile(CAST(Str, args[0]), "", EXEC_MODE); + CodeObject_ code = vm->compile(CAST(Str&, args[0]), "", EXEC_MODE); vm->_exec(code, vm->top_frame()->_module, vm->top_frame()->_locals); return vm->None; }); _vm->bind_builtin_func<-1>("exit", [](VM* vm, Args& args) { if(args.size() == 0) std::exit(0); - else if(args.size() == 1) std::exit((int)CAST_V(i64, args[0])); + else if(args.size() == 1) std::exit(CAST(int, args[0])); else vm->TypeError("exit() takes at most 1 argument"); return vm->None; }); @@ -101,34 +101,34 @@ void init_builtins(VM* _vm) { }); _vm->bind_builtin_func<1>("chr", [](VM* vm, Args& args) { - i64 i = CAST_V(i64, args[0]); + i64 i = CAST(i64, args[0]); if (i < 0 || i > 128) vm->ValueError("chr() arg not in range(128)"); return VAR(std::string(1, (char)i)); }); _vm->bind_builtin_func<1>("ord", [](VM* vm, Args& args) { - Str s = CAST(Str, args[0]); + const Str& s = CAST(Str&, args[0]); if (s.size() != 1) vm->TypeError("ord() expected an ASCII character"); return VAR((i64)(s.c_str()[0])); }); _vm->bind_builtin_func<2>("hasattr", [](VM* vm, Args& args) { - return VAR(vm->getattr(args[0], CAST(Str, args[1]), false) != nullptr); + return VAR(vm->getattr(args[0], CAST(Str&, args[1]), false) != nullptr); }); _vm->bind_builtin_func<3>("setattr", [](VM* vm, Args& args) { - vm->setattr(args[0], CAST(Str, args[1]), args[2]); + vm->setattr(args[0], CAST(Str&, args[1]), args[2]); return vm->None; }); _vm->bind_builtin_func<2>("getattr", [](VM* vm, Args& args) { - Str name = CAST(Str, args[1]); + const Str& name = CAST(Str&, args[1]); return vm->getattr(args[0], name); }); _vm->bind_builtin_func<1>("hex", [](VM* vm, Args& args) { std::stringstream ss; - ss << std::hex << CAST_V(i64, args[0]); + ss << std::hex << CAST(i64, args[0]); return VAR("0x" + ss.str()); }); @@ -163,9 +163,9 @@ void init_builtins(VM* _vm) { _vm->bind_static_method<-1>("range", "__new__", [](VM* vm, Args& args) { Range r; switch (args.size()) { - case 1: r.stop = CAST_V(i64, args[0]); break; - case 2: r.start = CAST_V(i64, args[0]); r.stop = CAST_V(i64, args[1]); break; - case 3: r.start = CAST_V(i64, args[0]); r.stop = CAST_V(i64, args[1]); r.step = CAST_V(i64, args[2]); break; + case 1: r.stop = CAST(i64, args[0]); break; + case 2: r.start = CAST(i64, args[0]); r.stop = CAST(i64, args[1]); break; + case 3: r.start = CAST(i64, args[0]); r.stop = CAST(i64, args[1]); r.step = CAST(i64, args[2]); break; default: vm->TypeError("expected 1-3 arguments, but got " + std::to_string(args.size())); } return VAR(r); @@ -186,8 +186,8 @@ void init_builtins(VM* _vm) { _vm->_bind_methods<1>({"int", "float"}, "__pow__", [](VM* vm, Args& args) { if(is_both_int(args[0], args[1])){ - i64 lhs = _CAST_V(i64, args[0]); - i64 rhs = _CAST_V(i64, args[1]); + i64 lhs = _CAST(i64, args[0]); + i64 rhs = _CAST(i64, args[1]); bool flag = false; if(rhs < 0) {flag = true; rhs = -rhs;} i64 ret = 1; @@ -206,10 +206,10 @@ void init_builtins(VM* _vm) { /************ PyInt ************/ _vm->bind_static_method<1>("int", "__new__", [](VM* vm, Args& args) { if (is_type(args[0], vm->tp_int)) return args[0]; - if (is_type(args[0], vm->tp_float)) return VAR((i64)CAST_V(f64, args[0])); - if (is_type(args[0], vm->tp_bool)) return VAR(_CAST_V(bool, args[0]) ? 1 : 0); + if (is_type(args[0], vm->tp_float)) return VAR((i64)CAST(f64, args[0])); + if (is_type(args[0], vm->tp_bool)) return VAR(_CAST(bool, args[0]) ? 1 : 0); if (is_type(args[0], vm->tp_str)) { - const Str& s = CAST(Str, args[0]); + const Str& s = CAST(Str&, args[0]); try{ size_t parsed = 0; i64 val = S_TO_INT(s, &parsed, 10); @@ -224,22 +224,22 @@ void init_builtins(VM* _vm) { }); _vm->bind_method<1>("int", "__floordiv__", [](VM* vm, Args& args) { - i64 rhs = CAST_V(i64, args[1]); + i64 rhs = CAST(i64, args[1]); if(rhs == 0) vm->ZeroDivisionError(); - return VAR(CAST_V(i64, args[0]) / rhs); + return VAR(CAST(i64, args[0]) / rhs); }); _vm->bind_method<1>("int", "__mod__", [](VM* vm, Args& args) { - i64 rhs = CAST_V(i64, args[1]); + i64 rhs = CAST(i64, args[1]); if(rhs == 0) vm->ZeroDivisionError(); - return VAR(CAST_V(i64, args[0]) % rhs); + return VAR(CAST(i64, args[0]) % rhs); }); - _vm->bind_method<0>("int", "__repr__", CPP_LAMBDA(VAR(std::to_string(CAST_V(i64, args[0]))))); - _vm->bind_method<0>("int", "__json__", CPP_LAMBDA(VAR(std::to_string(CAST_V(i64, args[0]))))); + _vm->bind_method<0>("int", "__repr__", CPP_LAMBDA(VAR(std::to_string(CAST(i64, args[0]))))); + _vm->bind_method<0>("int", "__json__", CPP_LAMBDA(VAR(std::to_string(CAST(i64, args[0]))))); #define INT_BITWISE_OP(name,op) \ - _vm->bind_method<1>("int", #name, CPP_LAMBDA(VAR(CAST_V(i64, args[0]) op CAST_V(i64, args[1])))); + _vm->bind_method<1>("int", #name, CPP_LAMBDA(VAR(CAST(i64, args[0]) op CAST(i64, args[1])))); INT_BITWISE_OP(__lshift__, <<) INT_BITWISE_OP(__rshift__, >>) @@ -251,11 +251,11 @@ void init_builtins(VM* _vm) { /************ PyFloat ************/ _vm->bind_static_method<1>("float", "__new__", [](VM* vm, Args& args) { - if (is_type(args[0], vm->tp_int)) return VAR((f64)CAST_V(i64, args[0])); + if (is_type(args[0], vm->tp_int)) return VAR((f64)CAST(i64, args[0])); if (is_type(args[0], vm->tp_float)) return args[0]; - if (is_type(args[0], vm->tp_bool)) return VAR(_CAST_V(bool, args[0]) ? 1.0 : 0.0); + if (is_type(args[0], vm->tp_bool)) return VAR(_CAST(bool, args[0]) ? 1.0 : 0.0); if (is_type(args[0], vm->tp_str)) { - const Str& s = CAST(Str, args[0]); + const Str& s = CAST(Str&, args[0]); if(s == "inf") return VAR(INFINITY); if(s == "-inf") return VAR(-INFINITY); try{ @@ -270,7 +270,7 @@ void init_builtins(VM* _vm) { }); _vm->bind_method<0>("float", "__repr__", [](VM* vm, Args& args) { - f64 val = CAST_V(f64, args[0]); + f64 val = CAST(f64, args[0]); if(std::isinf(val) || std::isnan(val)) return VAR(std::to_string(val)); StrStream ss; ss << std::setprecision(std::numeric_limits::max_digits10-1-2) << val; @@ -280,7 +280,7 @@ void init_builtins(VM* _vm) { }); _vm->bind_method<0>("float", "__json__", [](VM* vm, Args& args) { - f64 val = CAST_V(f64, args[0]); + f64 val = CAST(f64, args[0]); if(std::isinf(val) || std::isnan(val)) vm->ValueError("cannot jsonify 'nan' or 'inf'"); return VAR(std::to_string(val)); }); @@ -289,19 +289,19 @@ void init_builtins(VM* _vm) { _vm->bind_static_method<1>("str", "__new__", CPP_LAMBDA(vm->asStr(args[0]))); _vm->bind_method<1>("str", "__add__", [](VM* vm, Args& args) { - const Str& lhs = CAST(Str, args[0]); - const Str& rhs = CAST(Str, args[1]); + const Str& lhs = CAST(Str&, args[0]); + const Str& rhs = CAST(Str&, args[1]); return VAR(lhs + rhs); }); _vm->bind_method<0>("str", "__len__", [](VM* vm, Args& args) { - const Str& self = CAST(Str, args[0]); + const Str& self = CAST(Str&, args[0]); return VAR(self.u8_length()); }); _vm->bind_method<1>("str", "__contains__", [](VM* vm, Args& args) { - const Str& self = CAST(Str, args[0]); - const Str& other = CAST(Str, args[1]); + const Str& self = CAST(Str&, args[0]); + const Str& other = CAST(Str&, args[1]); return VAR(self.find(other) != Str::npos); }); @@ -309,59 +309,58 @@ void init_builtins(VM* _vm) { _vm->bind_method<0>("str", "__iter__", CPP_LAMBDA(vm->PyIter(StringIter(vm, args[0])))); _vm->bind_method<0>("str", "__repr__", [](VM* vm, Args& args) { - const Str& _self = CAST(Str, args[0]); + const Str& _self = CAST(Str&, args[0]); return VAR(_self.escape(true)); }); _vm->bind_method<0>("str", "__json__", [](VM* vm, Args& args) { - const Str& _self = CAST(Str, args[0]); - return VAR(_self.escape(false)); + const Str& self = CAST(Str&, args[0]); + return VAR(self.escape(false)); }); _vm->bind_method<1>("str", "__eq__", [](VM* vm, Args& args) { if(is_type(args[0], vm->tp_str) && is_type(args[1], vm->tp_str)) - return VAR(CAST(Str, args[0]) == CAST(Str, args[1])); + return VAR(CAST(Str&, args[0]) == CAST(Str&, args[1])); return VAR(args[0] == args[1]); }); _vm->bind_method<1>("str", "__ne__", [](VM* vm, Args& args) { if(is_type(args[0], vm->tp_str) && is_type(args[1], vm->tp_str)) - return VAR(CAST(Str, args[0]) != CAST(Str, args[1])); + return VAR(CAST(Str&, args[0]) != CAST(Str&, args[1])); return VAR(args[0] != args[1]); }); _vm->bind_method<1>("str", "__getitem__", [](VM* vm, Args& args) { - const Str& self (CAST(Str, args[0])); + const Str& self (CAST(Str&, args[0])); if(is_type(args[1], vm->tp_slice)){ - Slice s = _CAST_V(Slice, args[1]); + Slice s = _CAST(Slice, args[1]); s.normalize(self.u8_length()); return VAR(self.u8_substr(s.start, s.stop)); } - int index = (int)CAST_V(i64, args[1]); + int index = CAST(int, args[1]); index = vm->normalized_index(index, self.u8_length()); return VAR(self.u8_getitem(index)); }); _vm->bind_method<1>("str", "__gt__", [](VM* vm, Args& args) { - const Str& self (CAST(Str, args[0])); - const Str& obj (CAST(Str, args[1])); + const Str& self (CAST(Str&, args[0])); + const Str& obj (CAST(Str&, args[1])); return VAR(self > obj); }); _vm->bind_method<1>("str", "__lt__", [](VM* vm, Args& args) { - const Str& self (CAST(Str, args[0])); - const Str& obj (CAST(Str, args[1])); + const Str& self (CAST(Str&, args[0])); + const Str& obj (CAST(Str&, args[1])); return VAR(self < obj); }); _vm->bind_method<2>("str", "replace", [](VM* vm, Args& args) { - const Str& _self = CAST(Str, args[0]); - const Str& _old = CAST(Str, args[1]); - const Str& _new = CAST(Str, args[2]); + const Str& _self = CAST(Str&, args[0]); + const Str& _old = CAST(Str&, args[1]); + const Str& _new = CAST(Str&, args[2]); Str _copy = _self; - // replace all occurences of _old with _new in _copy size_t pos = 0; while ((pos = _copy.find(_old, pos)) != std::string::npos) { _copy.replace(pos, _old.length(), _new); @@ -371,45 +370,45 @@ void init_builtins(VM* _vm) { }); _vm->bind_method<1>("str", "startswith", [](VM* vm, Args& args) { - const Str& _self = CAST(Str, args[0]); - const Str& _prefix = CAST(Str, args[1]); - return VAR(_self.find(_prefix) == 0); + const Str& self = CAST(Str&, args[0]); + const Str& prefix = CAST(Str&, args[1]); + return VAR(self.find(prefix) == 0); }); _vm->bind_method<1>("str", "endswith", [](VM* vm, Args& args) { - const Str& _self = CAST(Str, args[0]); - const Str& _suffix = CAST(Str, args[1]); - return VAR(_self.rfind(_suffix) == _self.length() - _suffix.length()); + const Str& self = CAST(Str&, args[0]); + const Str& suffix = CAST(Str&, args[1]); + return VAR(self.rfind(suffix) == self.length() - suffix.length()); }); _vm->bind_method<1>("str", "join", [](VM* vm, Args& args) { - const Str& self = CAST(Str, args[0]); + const Str& self = CAST(Str&, args[0]); StrStream ss; PyVar obj = vm->asList(args[1]); - const List& list = CAST(List, obj); + const List& list = CAST(List&, obj); for (int i = 0; i < list.size(); ++i) { if (i > 0) ss << self; - ss << CAST(Str, list[i]); + ss << CAST(Str&, list[i]); } return VAR(ss.str()); }); /************ PyList ************/ _vm->bind_method<1>("list", "append", [](VM* vm, Args& args) { - List& self = CAST(List, args[0]); + List& self = CAST(List&, args[0]); self.push_back(args[1]); return vm->None; }); _vm->bind_method<0>("list", "reverse", [](VM* vm, Args& args) { - List& self = CAST(List, args[0]); + List& self = CAST(List&, args[0]); std::reverse(self.begin(), self.end()); return vm->None; }); _vm->bind_method<1>("list", "__mul__", [](VM* vm, Args& args) { - const List& self = CAST(List, args[0]); - int n = (int)CAST_V(i64, args[1]); + const List& self = CAST(List&, args[0]); + int n = CAST(int, args[1]); List result; result.reserve(self.size() * n); for(int i = 0; i < n; i++) result.insert(result.end(), self.begin(), self.end()); @@ -417,8 +416,8 @@ void init_builtins(VM* _vm) { }); _vm->bind_method<2>("list", "insert", [](VM* vm, Args& args) { - List& self = CAST(List, args[0]); - int index = (int)CAST_V(i64, args[1]); + List& self = CAST(List&, args[0]); + int index = CAST(int, args[1]); if(index < 0) index += self.size(); if(index < 0) index = 0; if(index > self.size()) index = self.size(); @@ -427,22 +426,22 @@ void init_builtins(VM* _vm) { }); _vm->bind_method<0>("list", "clear", [](VM* vm, Args& args) { - CAST(List, args[0]).clear(); + CAST(List&, args[0]).clear(); return vm->None; }); _vm->bind_method<0>("list", "copy", CPP_LAMBDA(VAR(CAST(List, args[0])))); _vm->bind_method<1>("list", "__add__", [](VM* vm, Args& args) { - const List& self = CAST(List, args[0]); - const List& obj = CAST(List, args[1]); + const List& self = CAST(List&, args[0]); + const List& obj = CAST(List&, args[1]); List new_list = self; new_list.insert(new_list.end(), obj.begin(), obj.end()); return VAR(new_list); }); _vm->bind_method<0>("list", "__len__", [](VM* vm, Args& args) { - const List& self = CAST(List, args[0]); + const List& self = CAST(List&, args[0]); return VAR(self.size()); }); @@ -451,32 +450,32 @@ void init_builtins(VM* _vm) { }); _vm->bind_method<1>("list", "__getitem__", [](VM* vm, Args& args) { - const List& self = CAST(List, args[0]); + const List& self = CAST(List&, args[0]); if(is_type(args[1], vm->tp_slice)){ - Slice s = _CAST_V(Slice, args[1]); + Slice s = _CAST(Slice, args[1]); s.normalize(self.size()); List new_list; for(size_t i = s.start; i < s.stop; i++) new_list.push_back(self[i]); return VAR(std::move(new_list)); } - int index = (int)CAST_V(i64, args[1]); + int index = CAST(int, args[1]); index = vm->normalized_index(index, self.size()); return self[index]; }); _vm->bind_method<2>("list", "__setitem__", [](VM* vm, Args& args) { - List& self = CAST(List, args[0]); - int index = (int)CAST_V(i64, args[1]); + List& self = CAST(List&, args[0]); + int index = CAST(int, args[1]); index = vm->normalized_index(index, self.size()); self[index] = args[2]; return vm->None; }); _vm->bind_method<1>("list", "__delitem__", [](VM* vm, Args& args) { - List& self = CAST(List, args[0]); - int index = (int)CAST_V(i64, args[1]); + List& self = CAST(List&, args[0]); + int index = CAST(int, args[1]); index = vm->normalized_index(index, self.size()); self.erase(self.begin() + index); return vm->None; @@ -493,23 +492,23 @@ void init_builtins(VM* _vm) { }); _vm->bind_method<1>("tuple", "__getitem__", [](VM* vm, Args& args) { - const Tuple& self = CAST(Tuple, args[0]); + const Tuple& self = CAST(Tuple&, args[0]); if(is_type(args[1], vm->tp_slice)){ - Slice s = _CAST_V(Slice, args[1]); + Slice s = _CAST(Slice, args[1]); s.normalize(self.size()); List new_list; for(size_t i = s.start; i < s.stop; i++) new_list.push_back(self[i]); return VAR(std::move(new_list)); } - int index = (int)CAST_V(i64, args[1]); + int index = CAST(int, args[1]); index = vm->normalized_index(index, self.size()); return self[index]; }); _vm->bind_method<0>("tuple", "__len__", [](VM* vm, Args& args) { - const Tuple& self = CAST(Tuple, args[0]); + const Tuple& self = CAST(Tuple&, args[0]); return VAR(self.size()); }); @@ -517,18 +516,18 @@ void init_builtins(VM* _vm) { _vm->bind_static_method<1>("bool", "__new__", CPP_LAMBDA(vm->asBool(args[0]))); _vm->bind_method<0>("bool", "__repr__", [](VM* vm, Args& args) { - bool val = CAST_V(bool, args[0]); + bool val = CAST(bool, args[0]); return VAR(val ? "True" : "False"); }); _vm->bind_method<0>("bool", "__json__", [](VM* vm, Args& args) { - bool val = CAST_V(bool, args[0]); + bool val = CAST(bool, args[0]); return VAR(val ? "true" : "false"); }); _vm->bind_method<1>("bool", "__xor__", [](VM* vm, Args& args) { - bool self = CAST_V(bool, args[0]); - bool other = CAST_V(bool, args[1]); + bool self = CAST(bool, args[0]); + bool other = CAST(bool, args[1]); return VAR(self ^ other); }); @@ -563,7 +562,7 @@ void add_module_sys(VM* vm){ vm->bind_func<0>(mod, "getrecursionlimit", CPP_LAMBDA(VAR(vm->recursionlimit))); vm->bind_func<1>(mod, "setrecursionlimit", [](VM* vm, Args& args) { - vm->recursionlimit = (int)CAST_V(i64, args[0]); + vm->recursionlimit = CAST(int, args[0]); return vm->None; }); } @@ -571,7 +570,7 @@ void add_module_sys(VM* vm){ void add_module_json(VM* vm){ PyVar mod = vm->new_module("json"); vm->bind_func<1>(mod, "loads", [](VM* vm, Args& args) { - const Str& expr = CAST(Str, args[0]); + const Str& expr = CAST(Str&, args[0]); CodeObject_ code = vm->compile(expr, "", JSON_MODE); return vm->_exec(code, vm->top_frame()->_module, vm->top_frame()->_locals); }); @@ -635,26 +634,26 @@ struct FileIO { }); vm->bind_method<0>(type, "read", [](VM* vm, Args& args){ - FileIO& io = CAST(FileIO, args[0]); + FileIO& io = CAST(FileIO&, args[0]); std::string buffer; io._fs >> buffer; return VAR(buffer); }); vm->bind_method<1>(type, "write", [](VM* vm, Args& args){ - FileIO& io = CAST(FileIO, args[0]); - io._fs << CAST(Str, args[1]); + FileIO& io = CAST(FileIO&, args[0]); + io._fs << CAST(Str&, args[1]); return vm->None; }); vm->bind_method<0>(type, "close", [](VM* vm, Args& args){ - FileIO& io = CAST(FileIO, args[0]); + FileIO& io = CAST(FileIO&, args[0]); io._fs.close(); return vm->None; }); vm->bind_method<0>(type, "__exit__", [](VM* vm, Args& args){ - FileIO& io = CAST(FileIO, args[0]); + FileIO& io = CAST(FileIO&, args[0]); io._fs.close(); return vm->None; }); @@ -682,17 +681,17 @@ struct ReMatch { static void _register(VM* vm, PyVar mod, PyVar type){ vm->bind_method<-1>(type, "__init__", CPP_NOT_IMPLEMENTED()); - vm->bind_method<0>(type, "start", CPP_LAMBDA(VAR(CAST(ReMatch, args[0]).start))); - vm->bind_method<0>(type, "end", CPP_LAMBDA(VAR(CAST(ReMatch, args[0]).end))); + vm->bind_method<0>(type, "start", CPP_LAMBDA(VAR(CAST(ReMatch&, args[0]).start))); + vm->bind_method<0>(type, "end", CPP_LAMBDA(VAR(CAST(ReMatch&, args[0]).end))); vm->bind_method<0>(type, "span", [](VM* vm, Args& args) { - auto& self = CAST(ReMatch, args[0]); + auto& self = CAST(ReMatch&, args[0]); return VAR(two_args(VAR(self.start), VAR(self.end))); }); vm->bind_method<1>(type, "group", [](VM* vm, Args& args) { - auto& self = CAST(ReMatch, args[0]); - int index = (int)CAST_V(i64, args[1]); + auto& self = CAST(ReMatch&, args[0]); + int index = CAST(int, args[1]); index = vm->normalized_index(index, self.m.size()); return VAR(self.m[index].str()); }); @@ -716,28 +715,28 @@ void add_module_re(VM* vm){ ReMatch::register_class(vm, mod); vm->bind_func<2>(mod, "match", [](VM* vm, Args& args) { - const Str& pattern = CAST(Str, args[0]); - const Str& string = CAST(Str, args[1]); + const Str& pattern = CAST(Str&, args[0]); + const Str& string = CAST(Str&, args[1]); return _regex_search(pattern, string, true, vm); }); vm->bind_func<2>(mod, "search", [](VM* vm, Args& args) { - const Str& pattern = CAST(Str, args[0]); - const Str& string = CAST(Str, args[1]); + const Str& pattern = CAST(Str&, args[0]); + const Str& string = CAST(Str&, args[1]); return _regex_search(pattern, string, false, vm); }); vm->bind_func<3>(mod, "sub", [](VM* vm, Args& args) { - const Str& pattern = CAST(Str, args[0]); - const Str& repl = CAST(Str, args[1]); - const Str& string = CAST(Str, args[2]); + const Str& pattern = CAST(Str&, args[0]); + const Str& repl = CAST(Str&, args[1]); + const Str& string = CAST(Str&, args[2]); std::regex re(pattern); return VAR(std::regex_replace(string, re, repl)); }); vm->bind_func<2>(mod, "split", [](VM* vm, Args& args) { - const Str& pattern = CAST(Str, args[0]); - const Str& string = CAST(Str, args[1]); + const Str& pattern = CAST(Str&, args[0]); + const Str& string = CAST(Str&, args[1]); std::regex re(pattern); std::sregex_token_iterator it(string.begin(), string.end(), re, -1); std::sregex_token_iterator end; @@ -753,21 +752,21 @@ void add_module_random(VM* vm){ PyVar mod = vm->new_module("random"); std::srand(std::time(0)); vm->bind_func<1>(mod, "seed", [](VM* vm, Args& args) { - std::srand((unsigned int)CAST_V(i64, args[0])); + std::srand((unsigned int)CAST(i64, args[0])); return vm->None; }); vm->bind_func<0>(mod, "random", CPP_LAMBDA(VAR(std::rand() / (f64)RAND_MAX))); vm->bind_func<2>(mod, "randint", [](VM* vm, Args& args) { - i64 a = CAST_V(i64, args[0]); - i64 b = CAST_V(i64, args[1]); + i64 a = CAST(i64, args[0]); + i64 b = CAST(i64, args[1]); if(a > b) std::swap(a, b); return VAR(a + std::rand() % (b - a + 1)); }); vm->bind_func<2>(mod, "uniform", [](VM* vm, Args& args) { - f64 a = CAST_V(f64, args[0]); - f64 b = CAST_V(f64, args[1]); + f64 a = CAST(f64, args[0]); + f64 b = CAST(f64, args[1]); if(a > b) std::swap(a, b); return VAR(a + (b - a) * std::rand() / (f64)RAND_MAX); }); @@ -866,8 +865,8 @@ extern "C" { pkpy::PyVar* val = vm->_main->attr().try_get(name); if(val == nullptr) return nullptr; try{ - pkpy::Str& _repr = pkpy::CAST(pkpy::Str, vm->asRepr(*val)); - return strdup(_repr.c_str()); + pkpy::Str repr = pkpy::CAST(pkpy::Str, vm->asRepr(*val)); + return strdup(repr.c_str()); }catch(...){ return nullptr; } @@ -882,8 +881,8 @@ extern "C" { pkpy::PyVarOrNull ret = vm->exec(source, "", pkpy::EVAL_MODE); if(ret == nullptr) return nullptr; try{ - pkpy::Str& _repr = pkpy::CAST(pkpy::Str, vm->asRepr(ret)); - return strdup(_repr.c_str()); + pkpy::Str repr = pkpy::CAST(pkpy::Str, vm->asRepr(ret)); + return strdup(repr.c_str()); }catch(...){ return nullptr; } @@ -969,7 +968,7 @@ extern "C" { for(int i=0; icall(args[i], pkpy::__json__); - ss << pkpy::CAST(pkpy::Str, x); + ss << pkpy::CAST(pkpy::Str&, x); } char* packet = strdup(ss.str().c_str()); switch(ret_code){ diff --git a/src/ref.h b/src/ref.h index 493c8a3b..9719d218 100644 --- a/src/ref.h +++ b/src/ref.h @@ -127,7 +127,7 @@ struct TupleRef : BaseRef { for(int i=0; itp_star_wrapper)){ - auto& star = _CAST(StarWrapper, objs[i]); + auto& star = _CAST(StarWrapper&, objs[i]); if(star.rvalue) vm->ValueError("can't use starred expression here"); if(i != objs.size()-1) vm->ValueError("* can only be used at the end"); auto ref = vm->PyRef_AS_C(star.obj); @@ -153,7 +153,7 @@ struct TupleRef : BaseRef { template PyVarRef VM::PyRef(P&& value) { - static_assert(std::is_base_of_v); + static_assert(std::is_base_of_v>); return new_object(tp_ref, std::forward

(value)); } diff --git a/src/test.cpp b/src/test.cpp new file mode 100644 index 00000000..f516a6f1 --- /dev/null +++ b/src/test.cpp @@ -0,0 +1,18 @@ +#include "cffi.h" +#include "pocketpy.h" + +using namespace pkpy; + +double add(int a, double b){ + return a + b; +} + +int main(){ + VM* vm = pkpy_new_vm(true); + + vm->bind_builtin_func<2>("add", ProxyFunction(&add)); + pkpy_vm_exec(vm, "print( add(1, 2.0) )"); + + pkpy_delete(vm); + return 0; +} \ No newline at end of file diff --git a/src/vm.h b/src/vm.h index befb73d1..53da8946 100644 --- a/src/vm.h +++ b/src/vm.h @@ -6,18 +6,18 @@ namespace pkpy{ #define DEF_NATIVE_2(ctype, ptype) \ - template<> ctype& py_cast(VM* vm, const PyVar& obj) { \ + template<> ctype py_cast(VM* vm, const PyVar& obj) { \ vm->check_type(obj, vm->ptype); \ return OBJ_GET(ctype, obj); \ } \ - template<> ctype& _py_cast(VM* vm, const PyVar& obj) { \ + template<> ctype _py_cast(VM* vm, const PyVar& obj) { \ return OBJ_GET(ctype, obj); \ } \ - template<> ctype py_cast_v(VM* vm, const PyVar& obj) { \ + template<> ctype& py_cast(VM* vm, const PyVar& obj) { \ vm->check_type(obj, vm->ptype); \ return OBJ_GET(ctype, obj); \ } \ - template<> ctype _py_cast_v(VM* vm, const PyVar& obj) { \ + template<> ctype& _py_cast(VM* vm, const PyVar& obj) { \ return OBJ_GET(ctype, obj); \ } \ PyVar py_var(VM* vm, const ctype& value) { return vm->new_object(vm->ptype, value);} \ @@ -114,13 +114,13 @@ public: } template - inline std::enable_if_t, PyVar> + inline std::enable_if_t, Args>, PyVar> call(const PyVar& _callable, ArgT&& args){ return call(_callable, std::forward(args), no_arg(), false); } template - inline std::enable_if_t, PyVar> + inline std::enable_if_t, Args>, PyVar> call(const PyVar& obj, const StrName name, ArgT&& args){ return call(getattr(obj, name), std::forward(args), no_arg(), false); } @@ -173,23 +173,23 @@ public: #ifdef PK_EXTRA_CHECK if(!is_type(type, tp_type)) UNREACHABLE(); #endif - return make_sp>(OBJ_GET(Type, type), _value); + return make_sp>>(OBJ_GET(Type, type), _value); } template inline PyVar new_object(const PyVar& type, T&& _value) { #ifdef PK_EXTRA_CHECK if(!is_type(type, tp_type)) UNREACHABLE(); #endif - return make_sp>(OBJ_GET(Type, type), std::move(_value)); + return make_sp>>(OBJ_GET(Type, type), std::move(_value)); } template inline PyVar new_object(Type type, const T& _value) { - return make_sp>(type, _value); + return make_sp>>(type, _value); } template inline PyVar new_object(Type type, T&& _value) { - return make_sp>(type, std::move(_value)); + return make_sp>>(type, std::move(_value)); } template @@ -234,7 +234,7 @@ public: template inline PyVar PyIter(P&& value) { - static_assert(std::is_base_of_v); + static_assert(std::is_base_of_v>); return new_object(tp_native_iterator, std::forward

(value)); } @@ -373,7 +373,7 @@ DEF_NATIVE_2(Exception, tp_exception) DEF_NATIVE_2(StarWrapper, tp_star_wrapper) template -std::enable_if_t && !std::is_same_v, PyVar> py_var(VM* vm, T _val){ +std::enable_if_t && !std::is_same_v, bool>, PyVar> py_var(VM* vm, T _val){ i64 val = static_cast(_val); if(((val << 2) >> 2) != val){ vm->_error("OverflowError", std::to_string(val) + " is out of range"); @@ -381,21 +381,28 @@ std::enable_if_t && !std::is_same_v, PyVar> val = (val << 2) | 0b01; return PyVar(reinterpret_cast(val)); } -template<> i64 py_cast_v(VM* vm, const PyVar& obj){ +template<> i64 py_cast(VM* vm, const PyVar& obj){ vm->check_type(obj, vm->tp_int); return obj.bits >> 2; } -template<> i64 _py_cast_v(VM* vm, const PyVar& obj){ +template<> i64 _py_cast(VM* vm, const PyVar& obj){ + return obj.bits >> 2; +} +template<> int py_cast(VM* vm, const PyVar& obj){ + vm->check_type(obj, vm->tp_int); + return obj.bits >> 2; +} +template<> int _py_cast(VM* vm, const PyVar& obj){ return obj.bits >> 2; } -template<> f64 py_cast_v(VM* vm, const PyVar& obj){ +template<> f64 py_cast(VM* vm, const PyVar& obj){ vm->check_type(obj, vm->tp_float); i64 bits = obj.bits; bits = (bits >> 2) << 2; return __8B(bits)._float; } -template<> f64 _py_cast_v(VM* vm, const PyVar& obj){ +template<> f64 _py_cast(VM* vm, const PyVar& obj){ i64 bits = obj.bits; bits = (bits >> 2) << 2; return __8B(bits)._float; @@ -414,11 +421,11 @@ const PyVar& py_var(VM* vm, bool val){ return val ? vm->True : vm->False; } -template<> bool py_cast_v(VM* vm, const PyVar& obj){ +template<> bool py_cast(VM* vm, const PyVar& obj){ vm->check_type(obj, vm->tp_bool); return obj == vm->True; } -template<> bool _py_cast_v(VM* vm, const PyVar& obj){ +template<> bool _py_cast(VM* vm, const PyVar& obj){ return obj == vm->True; } @@ -433,9 +440,9 @@ void _check_py_class(VM* vm, const PyVar& obj){ PyVar VM::num_negated(const PyVar& obj){ if (is_int(obj)){ - return VAR(-CAST_V(i64, obj)); + return VAR(-CAST(i64, obj)); }else if(is_float(obj)){ - return VAR(-CAST_V(f64, obj)); + return VAR(-CAST(f64, obj)); } TypeError("expected 'int' or 'float', got " + OBJ_NAME(_t(obj)).escape(true)); return nullptr; @@ -443,9 +450,9 @@ PyVar VM::num_negated(const PyVar& obj){ f64 VM::num_to_float(const PyVar& obj){ if(is_float(obj)){ - return CAST_V(f64, obj); + return CAST(f64, obj); } else if (is_int(obj)){ - return (f64)CAST_V(i64, obj); + return (f64)CAST(i64, obj); } TypeError("expected 'int' or 'float', got " + OBJ_NAME(_t(obj)).escape(true)); return 0; @@ -454,22 +461,22 @@ f64 VM::num_to_float(const PyVar& obj){ const PyVar& VM::asBool(const PyVar& obj){ if(is_type(obj, tp_bool)) return obj; if(obj == None) return False; - if(is_type(obj, tp_int)) return VAR(CAST_V(i64, obj) != 0); - if(is_type(obj, tp_float)) return VAR(CAST_V(f64, obj) != 0.0); + if(is_type(obj, tp_int)) return VAR(CAST(i64, obj) != 0); + if(is_type(obj, tp_float)) return VAR(CAST(f64, obj) != 0.0); PyVarOrNull len_fn = getattr(obj, __len__, false); if(len_fn != nullptr){ PyVar ret = call(len_fn); - return VAR(CAST_V(i64, ret) > 0); + return VAR(CAST(i64, ret) > 0); } return True; } i64 VM::hash(const PyVar& obj){ - if (is_type(obj, tp_str)) return CAST(Str, obj).hash(); - if (is_int(obj)) return CAST_V(i64, obj); + if (is_type(obj, tp_str)) return CAST(Str&, obj).hash(); + if (is_int(obj)) return CAST(i64, obj); if (is_type(obj, tp_tuple)) { i64 x = 1000003; - const Tuple& items = CAST(Tuple, obj); + const Tuple& items = CAST(Tuple&, obj); for (int i=0; i> 2)); // recommended by Github Copilot @@ -477,9 +484,9 @@ i64 VM::hash(const PyVar& obj){ return x; } if (is_type(obj, tp_type)) return obj.bits; - if (is_type(obj, tp_bool)) return _CAST_V(bool, obj) ? 1 : 0; + if (is_type(obj, tp_bool)) return _CAST(bool, obj) ? 1 : 0; if (is_float(obj)){ - f64 val = CAST_V(f64, obj); + f64 val = CAST(f64, obj); return (i64)std::hash()(val); } TypeError("unhashable type: " + OBJ_NAME(_t(obj)).escape(true)); @@ -572,7 +579,7 @@ Str VM::disassemble(CodeObject_ co){ for(int i=0; iconsts.size(); i++){ PyVar obj = co->consts[i]; if(is_type(obj, tp_function)){ - const auto& f = CAST(Function, obj); + const auto& f = CAST(Function&, obj); ss << disassemble(f.code); } } @@ -652,7 +659,7 @@ PyVar VM::call(const PyVar& _callable, Args args, const Args& kwargs, bool opCal const PyVar* callable = &_callable; if(is_type(*callable, tp_bound_method)){ - auto& bm = CAST(BoundMethod, *callable); + auto& bm = CAST(BoundMethod&, *callable); callable = &bm.method; // get unbound method args.extend_self(bm.obj); } @@ -662,7 +669,7 @@ PyVar VM::call(const PyVar& _callable, Args args, const Args& kwargs, bool opCal if(kwargs.size() != 0) TypeError("native_function does not accept keyword arguments"); return f(this, args); } else if(is_type(*callable, tp_function)){ - const Function& fn = CAST(Function, *callable); + const Function& fn = CAST(Function&, *callable); NameDict_ locals = make_sp( fn.code->perfect_locals_capacity, kLocalsLoadFactor, @@ -696,7 +703,7 @@ PyVar VM::call(const PyVar& _callable, Args args, const Args& kwargs, bool opCal } for(int i=0; ipop(); - Exception& _e = CAST(Exception, obj); + Exception& _e = CAST(Exception&, obj); _e.st_push(frame->snapshot()); callstack.pop(); if(callstack.empty()) throw _e; diff --git a/tests/_c.py b/tests/_c.py deleted file mode 100644 index eb1a829b..00000000 --- a/tests/_c.py +++ /dev/null @@ -1,12 +0,0 @@ -from c import * - -p = malloc(10 * sizeof(int_)) -p = p.cast(int_) - -for i in range(10): - p[i] = i - -for i in range(10): - assert p[i] == i - -free(p) \ No newline at end of file