vm.h 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594
  1. #pragma once
  2. #include "codeobject.h"
  3. #include "common.h"
  4. #include "frame.h"
  5. #include "error.h"
  6. #include "gc.h"
  7. #include "memory.h"
  8. #include "obj.h"
  9. #include "str.h"
  10. #include "tuplelist.h"
  11. #include "dict.h"
  12. #include "profiler.h"
  13. namespace pkpy{
  14. /* Stack manipulation macros */
  15. // https://github.com/python/cpython/blob/3.9/Python/ceval.c#L1123
  16. #define TOP() (s_data.top())
  17. #define SECOND() (s_data.second())
  18. #define THIRD() (s_data.third())
  19. #define STACK_SHRINK(n) (s_data.shrink(n))
  20. #define PUSH(v) (s_data.push(v))
  21. #define POP() (s_data.pop())
  22. #define POPX() (s_data.popx())
  23. #define STACK_VIEW(n) (s_data.view(n))
  24. typedef PyObject* (*BinaryFuncC)(VM*, PyObject*, PyObject*);
  25. #if PK_ENABLE_PROFILER
  26. struct NextBreakpoint{
  27. int callstack_size;
  28. int lineno;
  29. bool should_step_into;
  30. NextBreakpoint(): callstack_size(0) {}
  31. NextBreakpoint(int callstack_size, int lineno, bool should_step_into): callstack_size(callstack_size), lineno(lineno), should_step_into(should_step_into) {}
  32. void _step(VM* vm);
  33. bool empty() const { return callstack_size == 0; }
  34. };
  35. #endif
  36. struct PyTypeInfo{
  37. PyObject* obj; // never be garbage collected
  38. Type base;
  39. PyObject* mod; // never be garbage collected
  40. StrName name;
  41. bool subclass_enabled;
  42. std::vector<StrName> annotated_fields = {};
  43. // cached special methods
  44. // unary operators
  45. PyObject* (*m__repr__)(VM* vm, PyObject*) = nullptr;
  46. PyObject* (*m__str__)(VM* vm, PyObject*) = nullptr;
  47. i64 (*m__hash__)(VM* vm, PyObject*) = nullptr;
  48. i64 (*m__len__)(VM* vm, PyObject*) = nullptr;
  49. PyObject* (*m__iter__)(VM* vm, PyObject*) = nullptr;
  50. unsigned (*m__next__)(VM* vm, PyObject*) = nullptr;
  51. PyObject* (*m__neg__)(VM* vm, PyObject*) = nullptr;
  52. PyObject* (*m__invert__)(VM* vm, PyObject*) = nullptr;
  53. BinaryFuncC m__eq__ = nullptr;
  54. BinaryFuncC m__lt__ = nullptr;
  55. BinaryFuncC m__le__ = nullptr;
  56. BinaryFuncC m__gt__ = nullptr;
  57. BinaryFuncC m__ge__ = nullptr;
  58. BinaryFuncC m__contains__ = nullptr;
  59. // binary operators
  60. BinaryFuncC m__add__ = nullptr;
  61. BinaryFuncC m__sub__ = nullptr;
  62. BinaryFuncC m__mul__ = nullptr;
  63. BinaryFuncC m__truediv__ = nullptr;
  64. BinaryFuncC m__floordiv__ = nullptr;
  65. BinaryFuncC m__mod__ = nullptr;
  66. BinaryFuncC m__pow__ = nullptr;
  67. BinaryFuncC m__matmul__ = nullptr;
  68. BinaryFuncC m__lshift__ = nullptr;
  69. BinaryFuncC m__rshift__ = nullptr;
  70. BinaryFuncC m__and__ = nullptr;
  71. BinaryFuncC m__or__ = nullptr;
  72. BinaryFuncC m__xor__ = nullptr;
  73. // indexer
  74. PyObject* (*m__getitem__)(VM* vm, PyObject*, PyObject*) = nullptr;
  75. void (*m__setitem__)(VM* vm, PyObject*, PyObject*, PyObject*) = nullptr;
  76. void (*m__delitem__)(VM* vm, PyObject*, PyObject*) = nullptr;
  77. // attributes
  78. void (*m__setattr__)(VM* vm, PyObject*, StrName, PyObject*) = nullptr;
  79. PyObject* (*m__getattr__)(VM* vm, PyObject*, StrName) = nullptr;
  80. bool (*m__delattr__)(VM* vm, PyObject*, StrName) = nullptr;
  81. // backdoors
  82. void (*on_end_subclass)(VM* vm, PyTypeInfo*) = nullptr;
  83. };
  84. struct ImportContext{
  85. PK_ALWAYS_PASS_BY_POINTER(ImportContext)
  86. std::vector<Str> pending;
  87. std::vector<bool> pending_is_init; // a.k.a __init__.py
  88. ImportContext() {}
  89. struct Temp{
  90. PK_ALWAYS_PASS_BY_POINTER(Temp)
  91. ImportContext* ctx;
  92. Temp(ImportContext* ctx, Str name, bool is_init) : ctx(ctx){
  93. ctx->pending.push_back(name);
  94. ctx->pending_is_init.push_back(is_init);
  95. }
  96. ~Temp(){
  97. ctx->pending.pop_back();
  98. ctx->pending_is_init.pop_back();
  99. }
  100. };
  101. Temp scope(Str name, bool is_init){
  102. return {this, name, is_init};
  103. }
  104. };
  105. class VM {
  106. PK_ALWAYS_PASS_BY_POINTER(VM)
  107. VM* vm; // self reference for simplify code
  108. public:
  109. ManagedHeap heap;
  110. ValueStack s_data;
  111. CallStack callstack;
  112. std::vector<PyTypeInfo> _all_types;
  113. NameDict _modules; // loaded modules
  114. std::map<StrName, Str> _lazy_modules; // lazy loaded modules
  115. struct{
  116. PyObject* error;
  117. stack_no_copy<ArgsView> s_view;
  118. } _c;
  119. PyObject *None, *True, *False, *NotImplemented;
  120. PyObject *StopIteration, *Ellipsis;
  121. PyObject *builtins, *_main;
  122. // typeid -> Type
  123. std::map<const std::type_index, Type> _cxx_typeid_map;
  124. // this is for repr() recursion detection (no need to mark)
  125. std::set<PyObject*> _repr_recursion_set;
  126. ImportContext __import_context; // for import
  127. PyObject* __last_exception; // last exception
  128. PyObject* __curr_class; // current class being defined
  129. PyObject* __cached_object_new;
  130. std::map<std::string_view, CodeObject_> __cached_codes;
  131. void (*_ceval_on_step)(VM*, Frame*, Bytecode bc) = nullptr;
  132. #if PK_ENABLE_PROFILER
  133. LineProfiler* _profiler = nullptr;
  134. NextBreakpoint _next_breakpoint;
  135. #endif
  136. void(*_stdout)(const char*, int);
  137. void(*_stderr)(const char*, int);
  138. unsigned char* (*_import_handler)(const char*, int, int*);
  139. // for quick access
  140. static constexpr Type tp_object=0, tp_type=1;
  141. static constexpr Type tp_int=kTpIntIndex, tp_float=kTpFloatIndex, tp_bool=4, tp_str=5;
  142. static constexpr Type tp_list=6, tp_tuple=7;
  143. static constexpr Type tp_slice=8, tp_range=9, tp_module=10;
  144. static constexpr Type tp_function=11, tp_native_func=12, tp_bound_method=13;
  145. static constexpr Type tp_super=14, tp_exception=15, tp_bytes=16, tp_mappingproxy=17;
  146. static constexpr Type tp_dict=18, tp_property=19, tp_star_wrapper=20;
  147. static constexpr Type tp_staticmethod=21, tp_classmethod=22;
  148. const bool enable_os;
  149. VM(bool enable_os=true);
  150. /********** py_xxx **********/
  151. PyObject* py_str(PyObject* obj);
  152. PyObject* py_repr(PyObject* obj);
  153. PyObject* py_json(PyObject* obj);
  154. PyObject* py_iter(PyObject* obj);
  155. PyObject* py_next(PyObject*);
  156. PyObject* _py_next(const PyTypeInfo*, PyObject*);
  157. PyObject* py_import(Str path, bool throw_err=true);
  158. PyObject* py_negate(PyObject* obj);
  159. PyObject* py_list(PyObject*);
  160. bool py_callable(PyObject* obj);
  161. bool py_bool(PyObject* obj);
  162. i64 py_hash(PyObject* obj);
  163. bool py_eq(PyObject* lhs, PyObject* rhs);
  164. // new in v1.2.9
  165. bool py_lt(PyObject* lhs, PyObject* rhs);
  166. bool py_le(PyObject* lhs, PyObject* rhs);
  167. bool py_gt(PyObject* lhs, PyObject* rhs);
  168. bool py_ge(PyObject* lhs, PyObject* rhs);
  169. bool py_ne(PyObject* lhs, PyObject* rhs) { return !py_eq(lhs, rhs); }
  170. /********** utils **********/
  171. PyObject* new_module(Str name, Str package="");
  172. ArgsView cast_array_view(PyObject* obj);
  173. void set_main_argv(int argc, char** argv);
  174. i64 normalized_index(i64 index, int size);
  175. Str disassemble(CodeObject_ co);
  176. void parse_int_slice(const Slice& s, int length, int& start, int& stop, int& step);
  177. /********** name lookup **********/
  178. PyObject* find_name_in_mro(Type cls, StrName name);
  179. PyObject* getattr(PyObject* obj, StrName name, bool throw_err=true);
  180. void delattr(PyObject* obj, StrName name);
  181. PyObject* get_unbound_method(PyObject* obj, StrName name, PyObject** self, bool throw_err=true, bool fallback=false);
  182. void setattr(PyObject* obj, StrName name, PyObject* value);
  183. /********** execution **********/
  184. CodeObject_ compile(std::string_view source, const Str& filename, CompileMode mode, bool unknown_global_scope=false);
  185. Str precompile(std::string_view source, const Str& filename, CompileMode mode);
  186. PyObject* exec(std::string_view source, Str filename, CompileMode mode, PyObject* _module=nullptr);
  187. PyObject* exec(std::string_view source);
  188. PyObject* eval(std::string_view source);
  189. template<typename ...Args>
  190. PyObject* _exec(Args&&... args){
  191. callstack.emplace(s_data._sp, std::forward<Args>(args)...);
  192. return __run_top_frame();
  193. }
  194. /********** invocation **********/
  195. PyObject* vectorcall(int ARGC, int KWARGC=0, bool op_call=false);
  196. template<typename... Args>
  197. PyObject* call(PyObject* callable, Args&&... args){
  198. PUSH(callable); PUSH(PY_NULL);
  199. __push_varargs(args...);
  200. return vectorcall(sizeof...(args));
  201. }
  202. template<typename... Args>
  203. PyObject* call_method(PyObject* self, PyObject* callable, Args&&... args){
  204. PUSH(callable); PUSH(self);
  205. __push_varargs(args...);
  206. return vectorcall(sizeof...(args));
  207. }
  208. template<typename... Args>
  209. PyObject* call_method(PyObject* self, StrName name, Args&&... args){
  210. PyObject* callable = get_unbound_method(self, name, &self);
  211. return call_method(self, callable, args...);
  212. }
  213. /********** io **********/
  214. virtual void stdout_write(const Str& s){ _stdout(s.data, s.size); }
  215. virtual void stderr_write(const Str& s){ _stderr(s.data, s.size); }
  216. /********** bindings **********/
  217. void bind__repr__(Type type, PyObject* (*f)(VM*, PyObject*));
  218. void bind__str__(Type type, PyObject* (*f)(VM*, PyObject*));
  219. void bind__iter__(Type type, PyObject* (*f)(VM*, PyObject*));
  220. void bind__next__(Type type, unsigned (*f)(VM*, PyObject*));
  221. [[deprecated]] void bind__next__(Type type, PyObject* (*f)(VM*, PyObject*));
  222. void bind__neg__(Type type, PyObject* (*f)(VM*, PyObject*));
  223. void bind__invert__(Type type, PyObject* (*f)(VM*, PyObject*));
  224. void bind__hash__(Type type, i64 (*f)(VM* vm, PyObject*));
  225. void bind__len__(Type type, i64 (*f)(VM* vm, PyObject*));
  226. void bind__eq__(Type type, BinaryFuncC f);
  227. void bind__lt__(Type type, BinaryFuncC f);
  228. void bind__le__(Type type, BinaryFuncC f);
  229. void bind__gt__(Type type, BinaryFuncC f);
  230. void bind__ge__(Type type, BinaryFuncC f);
  231. void bind__contains__(Type type, BinaryFuncC f);
  232. void bind__add__(Type type, BinaryFuncC f);
  233. void bind__sub__(Type type, BinaryFuncC f);
  234. void bind__mul__(Type type, BinaryFuncC f);
  235. void bind__truediv__(Type type, BinaryFuncC f);
  236. void bind__floordiv__(Type type, BinaryFuncC f);
  237. void bind__mod__(Type type, BinaryFuncC f);
  238. void bind__pow__(Type type, BinaryFuncC f);
  239. void bind__matmul__(Type type, BinaryFuncC f);
  240. void bind__lshift__(Type type, BinaryFuncC f);
  241. void bind__rshift__(Type type, BinaryFuncC f);
  242. void bind__and__(Type type, BinaryFuncC f);
  243. void bind__or__(Type type, BinaryFuncC f);
  244. void bind__xor__(Type type, BinaryFuncC f);
  245. void bind__getitem__(Type type, PyObject* (*f)(VM*, PyObject*, PyObject*));
  246. void bind__setitem__(Type type, void (*f)(VM*, PyObject*, PyObject*, PyObject*));
  247. void bind__delitem__(Type type, void (*f)(VM*, PyObject*, PyObject*));
  248. template<int ARGC>
  249. PyObject* bind_func(PyObject*, StrName, NativeFuncC, UserData userdata={}, BindType bt=BindType::DEFAULT);
  250. // new style binding api
  251. PyObject* bind_func(PyObject* obj, StrName name, int argc, NativeFuncC fn, UserData userdata={}, BindType bt=BindType::DEFAULT);
  252. PyObject* bind_func(Type type, StrName name, int argc, NativeFuncC fn, UserData userdata={}, BindType bt=BindType::DEFAULT){
  253. return bind_func(_t(type), name, argc, fn, userdata, bt);
  254. }
  255. PyObject* bind(PyObject*, const char*, const char*, NativeFuncC, UserData userdata={}, BindType bt=BindType::DEFAULT);
  256. PyObject* bind(PyObject*, const char*, NativeFuncC, UserData userdata={}, BindType bt=BindType::DEFAULT);
  257. PyObject* bind_property(PyObject*, const char*, NativeFuncC fget, NativeFuncC fset=nullptr);
  258. template<typename T, typename F, bool ReadOnly=false>
  259. PyObject* bind_field(PyObject*, const char*, F T::*);
  260. template<typename T, typename __T>
  261. PyObject* bind_notimplemented_constructor(__T&& type) {
  262. return bind_func<-1>(std::forward<__T>(type), __new__, [](VM* vm, ArgsView args){
  263. vm->NotImplementedError();
  264. return vm->None;
  265. });
  266. }
  267. /********** error **********/
  268. void _error(PyObject*);
  269. void StackOverflowError() { __builtin_error("StackOverflowError"); }
  270. void IOError(const Str& msg) { __builtin_error("IOError", msg); }
  271. void NotImplementedError(){ __builtin_error("NotImplementedError"); }
  272. void TypeError(const Str& msg){ __builtin_error("TypeError", msg); }
  273. void TypeError(Type expected, Type actual) { TypeError("expected " + _type_name(vm, expected).escape() + ", got " + _type_name(vm, actual).escape()); }
  274. void IndexError(const Str& msg){ __builtin_error("IndexError", msg); }
  275. void ValueError(const Str& msg){ __builtin_error("ValueError", msg); }
  276. void RuntimeError(const Str& msg){ __builtin_error("RuntimeError", msg); }
  277. void ZeroDivisionError(const Str& msg){ __builtin_error("ZeroDivisionError", msg); }
  278. void ZeroDivisionError(){ __builtin_error("ZeroDivisionError", "division by zero"); }
  279. void NameError(StrName name){ __builtin_error("NameError", _S("name ", name.escape() + " is not defined")); }
  280. void UnboundLocalError(StrName name){ __builtin_error("UnboundLocalError", _S("local variable ", name.escape() + " referenced before assignment")); }
  281. void KeyError(PyObject* obj){ __builtin_error("KeyError", obj); }
  282. void ImportError(const Str& msg){ __builtin_error("ImportError", msg); }
  283. void AssertionError(const Str& msg){ __builtin_error("AssertionError", msg); }
  284. void AssertionError(){ __builtin_error("AssertionError"); }
  285. void BinaryOptError(const char* op, PyObject* _0, PyObject* _1);
  286. void AttributeError(PyObject* obj, StrName name);
  287. void AttributeError(const Str& msg){ __builtin_error("AttributeError", msg); }
  288. /********** type **********/
  289. PyObject* new_type_object(PyObject* mod, StrName name, Type base, bool subclass_enabled=true);
  290. const PyTypeInfo* _inst_type_info(PyObject* obj);
  291. bool isinstance(PyObject* obj, Type base);
  292. bool issubclass(Type cls, Type base);
  293. void check_type(PyObject* obj, Type type){ if(!is_type(obj, type)) TypeError(type, _tp(obj)); }
  294. void check_compatible_type(PyObject* obj, Type type){ if(!isinstance(obj, type)) TypeError(type, _tp(obj)); }
  295. PyObject* _t(PyObject* obj){ return _all_types[_tp(obj)].obj; }
  296. PyObject* _t(Type t){ return _all_types[t.index].obj; }
  297. Type _tp(PyObject* obj){ return is_small_int(obj) ? tp_int : obj->type; }
  298. /********** user type **********/
  299. template<typename T>
  300. Type _tp_user(){ return _find_type_in_cxx_typeid_map<T>(); }
  301. template<typename T>
  302. bool is_user_type(PyObject* obj){ return _tp(obj) == _tp_user<T>(); }
  303. template<typename T>
  304. PyObject* register_user_class(PyObject* mod, StrName name, bool subclass_enabled=false){
  305. PyObject* type = new_type_object(mod, name, 0, subclass_enabled);
  306. mod->attr().set(name, type);
  307. _cxx_typeid_map[typeid(T)] = PK_OBJ_GET(Type, type);
  308. T::_register(vm, mod, type);
  309. return type;
  310. }
  311. template<typename T, typename ...Args>
  312. PyObject* new_user_object(Args&&... args){
  313. return heap.gcnew<T>(_tp_user<T>(), std::forward<Args>(args)...);
  314. }
  315. template<typename T>
  316. Type _find_type_in_cxx_typeid_map(){
  317. auto it = _cxx_typeid_map.find(typeid(T));
  318. if(it == _cxx_typeid_map.end()){
  319. #if __GNUC__ || __clang__
  320. throw std::runtime_error(__PRETTY_FUNCTION__ + std::string(" failed: T not found"));
  321. #elif _MSC_VER
  322. throw std::runtime_error(__FUNCSIG__ + std::string(" failed: T not found"));
  323. #else
  324. throw std::runtime_error("_find_type_in_cxx_typeid_map() failed: T not found");
  325. #endif
  326. }
  327. return it->second;
  328. }
  329. /********** private **********/
  330. virtual ~VM();
  331. #if PK_DEBUG_CEVAL_STEP
  332. void __log_s_data(const char* title = nullptr);
  333. #endif
  334. void __breakpoint();
  335. PyObject* __format_object(PyObject*, Str);
  336. PyObject* __run_top_frame();
  337. void __pop_frame();
  338. PyObject* __py_generator(Frame&& frame, ArgsView buffer);
  339. void __op_unpack_sequence(uint16_t arg);
  340. void __prepare_py_call(PyObject**, ArgsView, ArgsView, const FuncDecl_&);
  341. void __unpack_as_list(ArgsView args, List& list);
  342. void __unpack_as_dict(ArgsView args, Dict& dict);
  343. void __raise_exc(bool re_raise=false);
  344. void __init_builtin_types();
  345. void __post_init_builtin_types();
  346. void __builtin_error(StrName type);
  347. void __builtin_error(StrName type, PyObject* arg);
  348. void __builtin_error(StrName type, const Str& msg);
  349. void __push_varargs(){}
  350. void __push_varargs(PyObject* _0){ PUSH(_0); }
  351. void __push_varargs(PyObject* _0, PyObject* _1){ PUSH(_0); PUSH(_1); }
  352. void __push_varargs(PyObject* _0, PyObject* _1, PyObject* _2){ PUSH(_0); PUSH(_1); PUSH(_2); }
  353. void __push_varargs(PyObject* _0, PyObject* _1, PyObject* _2, PyObject* _3){ PUSH(_0); PUSH(_1); PUSH(_2); PUSH(_3); }
  354. PyObject* __pack_next_retval(unsigned);
  355. PyObject* __minmax_reduce(bool (VM::*op)(PyObject*, PyObject*), PyObject* args, PyObject* key);
  356. };
  357. template<typename T>
  358. inline constexpr bool is_immutable_v = is_integral_v<T> || is_floating_point_v<T>
  359. || std::is_same_v<T, Str> || std::is_same_v<T, Tuple> || std::is_same_v<T, Bytes> || std::is_same_v<T, bool>
  360. || std::is_same_v<T, Range> || std::is_same_v<T, Slice>
  361. || std::is_pointer_v<T> || std::is_enum_v<T>;
  362. template<typename T> constexpr Type _find_type_in_const_cxx_typeid_map(){ return -1; }
  363. template<> constexpr Type _find_type_in_const_cxx_typeid_map<Str>(){ return VM::tp_str; }
  364. template<> constexpr Type _find_type_in_const_cxx_typeid_map<List>(){ return VM::tp_list; }
  365. template<> constexpr Type _find_type_in_const_cxx_typeid_map<Tuple>(){ return VM::tp_tuple; }
  366. template<> constexpr Type _find_type_in_const_cxx_typeid_map<Function>(){ return VM::tp_function; }
  367. template<> constexpr Type _find_type_in_const_cxx_typeid_map<NativeFunc>(){ return VM::tp_native_func; }
  368. template<> constexpr Type _find_type_in_const_cxx_typeid_map<BoundMethod>(){ return VM::tp_bound_method; }
  369. template<> constexpr Type _find_type_in_const_cxx_typeid_map<Range>(){ return VM::tp_range; }
  370. template<> constexpr Type _find_type_in_const_cxx_typeid_map<Slice>(){ return VM::tp_slice; }
  371. template<> constexpr Type _find_type_in_const_cxx_typeid_map<Exception>(){ return VM::tp_exception; }
  372. template<> constexpr Type _find_type_in_const_cxx_typeid_map<Bytes>(){ return VM::tp_bytes; }
  373. template<> constexpr Type _find_type_in_const_cxx_typeid_map<MappingProxy>(){ return VM::tp_mappingproxy; }
  374. template<> constexpr Type _find_type_in_const_cxx_typeid_map<Dict>(){ return VM::tp_dict; }
  375. template<> constexpr Type _find_type_in_const_cxx_typeid_map<Property>(){ return VM::tp_property; }
  376. template<> constexpr Type _find_type_in_const_cxx_typeid_map<StarWrapper>(){ return VM::tp_star_wrapper; }
  377. template<> constexpr Type _find_type_in_const_cxx_typeid_map<StaticMethod>(){ return VM::tp_staticmethod; }
  378. template<> constexpr Type _find_type_in_const_cxx_typeid_map<ClassMethod>(){ return VM::tp_classmethod; }
  379. template<typename __T>
  380. PyObject* py_var(VM* vm, __T&& value){
  381. using T = std::decay_t<__T>;
  382. static_assert(!std::is_same_v<T, PyObject*>, "py_var(VM*, PyObject*) is not allowed");
  383. if constexpr(std::is_same_v<T, const char*> || std::is_same_v<T, std::string> || std::is_same_v<T, std::string_view>){
  384. // str (shortcuts)
  385. return VAR(Str(std::forward<__T>(value)));
  386. }else if constexpr(std::is_same_v<T, NoReturn>){
  387. // NoneType
  388. return vm->None;
  389. }else if constexpr(std::is_same_v<T, bool>){
  390. // bool
  391. return value ? vm->True : vm->False;
  392. }else if constexpr(is_integral_v<T>){
  393. // int
  394. i64 val = static_cast<i64>(std::forward<__T>(value));
  395. if(val >= Number::kMinSmallInt && val <= Number::kMaxSmallInt){
  396. val = (val << 2) | 0b10;
  397. return reinterpret_cast<PyObject*>(val);
  398. }else{
  399. return vm->heap.gcnew<i64>(vm->tp_int, val);
  400. }
  401. }else if constexpr(is_floating_point_v<T>){
  402. // float
  403. f64 val = static_cast<f64>(std::forward<__T>(value));
  404. return vm->heap.gcnew<f64>(vm->tp_float, val);
  405. }else if constexpr(std::is_pointer_v<T>){
  406. return from_void_p(vm, (void*)value);
  407. }else{
  408. constexpr Type const_type = _find_type_in_const_cxx_typeid_map<T>();
  409. if constexpr(const_type.index >= 0){
  410. return vm->heap.gcnew<T>(const_type, std::forward<__T>(value));
  411. }
  412. }
  413. Type type = vm->_find_type_in_cxx_typeid_map<T>();
  414. return vm->heap.gcnew<T>(type, std::forward<__T>(value));
  415. }
  416. template<typename __T, bool with_check>
  417. __T _py_cast__internal(VM* vm, PyObject* obj) {
  418. static_assert(!std::is_rvalue_reference_v<__T>, "rvalue reference is not allowed");
  419. using T = std::decay_t<__T>;
  420. if constexpr(std::is_same_v<T, const char*> || std::is_same_v<T, CString>){
  421. static_assert(!std::is_reference_v<__T>);
  422. // str (shortcuts)
  423. if(obj == vm->None) return nullptr;
  424. if constexpr(with_check) vm->check_type(obj, vm->tp_str);
  425. return PK_OBJ_GET(Str, obj).c_str();
  426. }else if constexpr(std::is_same_v<T, bool>){
  427. static_assert(!std::is_reference_v<__T>);
  428. // bool
  429. if constexpr(with_check){
  430. if(obj == vm->True) return true;
  431. if(obj == vm->False) return false;
  432. vm->TypeError("expected 'bool', got " + _type_name(vm, vm->_tp(obj)).escape());
  433. }else{
  434. return obj == vm->True;
  435. }
  436. }else if constexpr(is_integral_v<T>){
  437. static_assert(!std::is_reference_v<__T>);
  438. // int
  439. if constexpr(with_check){
  440. if(is_small_int(obj)) return (T)(PK_BITS(obj) >> 2);
  441. if(is_heap_int(obj)) return (T)PK_OBJ_GET(i64, obj);
  442. vm->TypeError("expected 'int', got " + _type_name(vm, vm->_tp(obj)).escape());
  443. }else{
  444. if(is_small_int(obj)) return (T)(PK_BITS(obj) >> 2);
  445. return (T)PK_OBJ_GET(i64, obj);
  446. }
  447. }else if constexpr(is_floating_point_v<T>){
  448. static_assert(!std::is_reference_v<__T>);
  449. // float
  450. if(is_float(obj)) return PK_OBJ_GET(f64, obj);
  451. i64 bits;
  452. if(try_cast_int(obj, &bits)) return (float)bits;
  453. vm->TypeError("expected 'int' or 'float', got " + _type_name(vm, vm->_tp(obj)).escape());
  454. }else if constexpr(std::is_enum_v<T>){
  455. static_assert(!std::is_reference_v<__T>);
  456. return (__T)_py_cast__internal<i64, with_check>(vm, obj);
  457. }else if constexpr(std::is_pointer_v<T>){
  458. static_assert(!std::is_reference_v<__T>);
  459. return to_void_p<T>(vm, obj);
  460. }else{
  461. constexpr Type const_type = _find_type_in_const_cxx_typeid_map<T>();
  462. if constexpr(const_type.index >= 0){
  463. if constexpr(with_check){
  464. if constexpr(std::is_same_v<T, Exception>){
  465. // Exception is `subclass_enabled`
  466. vm->check_compatible_type(obj, const_type);
  467. }else{
  468. vm->check_type(obj, const_type);
  469. }
  470. }
  471. return PK_OBJ_GET(T, obj);
  472. }
  473. }
  474. Type type = vm->_find_type_in_cxx_typeid_map<T>();
  475. if constexpr(with_check) vm->check_compatible_type(obj, type);
  476. return PK_OBJ_GET(T, obj);
  477. }
  478. template<typename __T>
  479. __T py_cast(VM* vm, PyObject* obj) { return _py_cast__internal<__T, true>(vm, obj); }
  480. template<typename __T>
  481. __T _py_cast(VM* vm, PyObject* obj) { return _py_cast__internal<__T, false>(vm, obj); }
  482. template<int ARGC>
  483. PyObject* VM::bind_func(PyObject* obj, StrName name, NativeFuncC fn, UserData userdata, BindType bt) {
  484. PyObject* nf = VAR(NativeFunc(fn, ARGC, false));
  485. PK_OBJ_GET(NativeFunc, nf).set_userdata(userdata);
  486. switch(bt){
  487. case BindType::DEFAULT: break;
  488. case BindType::STATICMETHOD: nf = VAR(StaticMethod(nf)); break;
  489. case BindType::CLASSMETHOD: nf = VAR(ClassMethod(nf)); break;
  490. }
  491. obj->attr().set(name, nf);
  492. return nf;
  493. }
  494. template<typename T, typename F, bool ReadOnly>
  495. PyObject* VM::bind_field(PyObject* obj, const char* name, F T::*field){
  496. static_assert(!std::is_reference_v<F>);
  497. std::string_view name_sv(name); int pos = name_sv.find(':');
  498. if(pos > 0) name_sv = name_sv.substr(0, pos);
  499. auto fget = [](VM* vm, ArgsView args) -> PyObject*{
  500. T& self = PK_OBJ_GET(T, args[0]);
  501. F T::*field = lambda_get_userdata<F T::*>(args.begin());
  502. return VAR(self.*field);
  503. };
  504. PyObject* _0 = heap.gcnew<NativeFunc>(tp_native_func, fget, 1, false);
  505. PK_OBJ_GET(NativeFunc, _0).set_userdata(field);
  506. PyObject* _1 = vm->None;
  507. if constexpr (!ReadOnly){
  508. auto fset = [](VM* vm, ArgsView args){
  509. T& self = PK_OBJ_GET(T, args[0]);
  510. F T::*field = lambda_get_userdata<F T::*>(args.begin());
  511. self.*field = py_cast<F>(vm, args[1]);
  512. return vm->None;
  513. };
  514. _1 = heap.gcnew<NativeFunc>(tp_native_func, fset, 2, false);
  515. PK_OBJ_GET(NativeFunc, _1).set_userdata(field);
  516. }
  517. PyObject* prop = VAR(Property(_0, _1));
  518. obj->attr().set(StrName(name_sv), prop);
  519. return prop;
  520. }
  521. } // namespace pkpy