This commit is contained in:
blueloveTH 2024-05-05 10:51:06 +08:00
parent 10f886bb9b
commit 0f47105b27
6 changed files with 84 additions and 68 deletions

View File

@ -109,6 +109,8 @@ struct Type {
#define PK_VAR_LAMBDA(x) ([](VM* vm, ArgsView args) { return VAR(x); })
#define PK_ACTION(x) ([](VM* vm, ArgsView args) { x; return vm->None; })
#define PK_REGION(name) 1
#ifdef POCKETPY_H
#define PK_FATAL_ERROR() throw std::runtime_error( "L" + std::to_string(__LINE__) + " FATAL_ERROR()!");
#else

View File

@ -128,7 +128,7 @@ struct ImportContext{
class VM {
PK_ALWAYS_PASS_BY_POINTER(VM)
VM* vm; // self reference for simplify code
VM* vm; // self reference to simplify code
public:
ManagedHeap heap;
ValueStack s_data;
@ -152,9 +152,9 @@ public:
// this is for repr() recursion detection (no need to mark)
std::set<PyObject*> _repr_recursion_set;
ImportContext __import_context; // for import
PyObject* __last_exception; // last exception
PyObject* __curr_class; // current class being defined
ImportContext __import_context;
PyObject* __last_exception;
PyObject* __curr_class;
PyObject* __cached_object_new;
std::map<std::string_view, CodeObject_> __cached_codes;
@ -182,45 +182,50 @@ public:
const bool enable_os;
VM(bool enable_os=true);
/********** py_xxx **********/
PyObject* py_str(PyObject* obj);
PyObject* py_repr(PyObject* obj);
PyObject* py_json(PyObject* obj);
PyObject* py_iter(PyObject* obj);
PyObject* py_next(PyObject*);
PyObject* _py_next(const PyTypeInfo*, PyObject*);
PyObject* py_import(Str path, bool throw_err=true);
PyObject* py_negate(PyObject* obj);
#if PK_REGION("Python Equivalents")
PyObject* py_str(PyObject* obj); // x -> str(x)
PyObject* py_repr(PyObject* obj); // x -> repr(x)
PyObject* py_json(PyObject* obj); // x -> json.dumps(x)
PyObject* py_iter(PyObject* obj); // x -> iter(x)
PyObject* py_next(PyObject*); // x -> next(x)
PyObject* _py_next(const PyTypeInfo*, PyObject*); // x -> next(x) with type info cache
PyObject* py_import(Str path, bool throw_err=true); // x -> __import__(x)
PyObject* py_negate(PyObject* obj); // x -> -x
List py_list(PyObject*);
bool py_callable(PyObject* obj);
bool py_bool(PyObject* obj);
i64 py_hash(PyObject* obj);
List py_list(PyObject*); // x -> list(x)
bool py_callable(PyObject* obj); // x -> callable(x)
bool py_bool(PyObject* obj); // x -> bool(x)
i64 py_hash(PyObject* obj); // x -> hash(x)
bool py_eq(PyObject* lhs, PyObject* rhs);
// new in v1.2.9
bool py_lt(PyObject* lhs, PyObject* rhs);
bool py_le(PyObject* lhs, PyObject* rhs);
bool py_gt(PyObject* lhs, PyObject* rhs);
bool py_ge(PyObject* lhs, PyObject* rhs);
bool py_ne(PyObject* lhs, PyObject* rhs) { return !py_eq(lhs, rhs); }
bool py_eq(PyObject* lhs, PyObject* rhs); // (lhs, rhs) -> lhs == rhs
bool py_lt(PyObject* lhs, PyObject* rhs); // (lhs, rhs) -> lhs < rhs
bool py_le(PyObject* lhs, PyObject* rhs); // (lhs, rhs) -> lhs <= rhs
bool py_gt(PyObject* lhs, PyObject* rhs); // (lhs, rhs) -> lhs > rhs
bool py_ge(PyObject* lhs, PyObject* rhs); // (lhs, rhs) -> lhs >= rhs
bool py_ne(PyObject* lhs, PyObject* rhs) { // (lhs, rhs) -> lhs != rhs
return !py_eq(lhs, rhs);
}
#endif
/********** utils **********/
#if PK_REGION("Utility Methods")
PyObject* new_module(Str name, Str package="");
PyObject* new_type_object(PyObject* mod, StrName name, Type base, bool subclass_enabled=true);
ArgsView cast_array_view(PyObject* obj);
void set_main_argv(int argc, char** argv);
i64 normalized_index(i64 index, int size);
Str disassemble(CodeObject_ co);
void parse_int_slice(const Slice& s, int length, int& start, int& stop, int& step);
#endif
/********** name lookup **********/
#if PK_REGION("Name Lookup Methods")
PyObject* find_name_in_mro(Type cls, StrName name);
PyObject* get_unbound_method(PyObject* obj, StrName name, PyObject** self, bool throw_err=true, bool fallback=false);
PyObject* getattr(PyObject* obj, StrName name, bool throw_err=true);
void delattr(PyObject* obj, StrName name);
PyObject* get_unbound_method(PyObject* obj, StrName name, PyObject** self, bool throw_err=true, bool fallback=false);
void setattr(PyObject* obj, StrName name, PyObject* value);
#endif
/********** execution **********/
#if PK_REGION("Source Execution Methods")
CodeObject_ compile(std::string_view source, const Str& filename, CompileMode mode, bool unknown_global_scope=false);
Str precompile(std::string_view source, const Str& filename, CompileMode mode);
PyObject* exec(std::string_view source, Str filename, CompileMode mode, PyObject* _module=nullptr);
@ -232,8 +237,9 @@ public:
callstack.emplace(s_data._sp, std::forward<Args>(args)...);
return __run_top_frame();
}
#endif
/********** invocation **********/
#if PK_REGION("Invocation Methods")
PyObject* vectorcall(int ARGC, int KWARGC=0, bool op_call=false);
template<typename... Args>
@ -255,12 +261,14 @@ public:
PyObject* callable = get_unbound_method(self, name, &self);
return call_method(self, callable, args...);
}
#endif
/********** io **********/
#if PK_REGION("Logging Methods")
virtual void stdout_write(const Str& s){ _stdout(s.data, s.size); }
virtual void stderr_write(const Str& s){ _stderr(s.data, s.size); }
#endif
/********** bindings **********/
#if PK_REGION("Magic Bindings")
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*));
@ -296,7 +304,9 @@ public:
void bind__getitem__(Type type, PyObject* (*f)(VM*, PyObject*, PyObject*));
void bind__setitem__(Type type, void (*f)(VM*, PyObject*, PyObject*, PyObject*));
void bind__delitem__(Type type, void (*f)(VM*, PyObject*, PyObject*));
// new style binding api
#endif
#if PK_REGION("General Bindings")
PyObject* bind_func(PyObject* obj, StrName name, int argc, NativeFuncC fn, UserData userdata={}, BindType bt=BindType::DEFAULT);
PyObject* bind_func(Type type, StrName name, int argc, NativeFuncC fn, UserData userdata={}, BindType bt=BindType::DEFAULT){
return bind_func(_t(type), name, argc, fn, userdata, bt);
@ -304,19 +314,21 @@ public:
PyObject* bind_property(PyObject*, const char*, NativeFuncC fget, NativeFuncC fset=nullptr);
template<typename T, typename F, bool ReadOnly=false>
PyObject* bind_field(PyObject*, const char*, F T::*);
// without docstring
PyObject* bind(PyObject*, const char*, NativeFuncC, UserData userdata={}, BindType bt=BindType::DEFAULT);
template<typename Ret, typename... Params>
PyObject* bind(PyObject*, const char*, Ret(*)(Params...), BindType bt=BindType::DEFAULT);
template<typename Ret, typename T, typename... Params>
PyObject* bind(PyObject*, const char*, Ret(T::*)(Params...), BindType bt=BindType::DEFAULT);
// with docstring
PyObject* bind(PyObject*, const char*, const char*, NativeFuncC, UserData userdata={}, BindType bt=BindType::DEFAULT);
template<typename Ret, typename... Params>
PyObject* bind(PyObject*, const char*, const char*, Ret(*)(Params...), BindType bt=BindType::DEFAULT);
template<typename Ret, typename T, typename... Params>
PyObject* bind(PyObject*, const char*, const char*, Ret(T::*)(Params...), BindType bt=BindType::DEFAULT);
/********** error **********/
#endif
#if PK_REGION("Error Reporting Methods")
void _error(PyObject*);
void StackOverflowError() { __builtin_error("StackOverflowError"); }
void IOError(const Str& msg) { __builtin_error("IOError", msg); }
@ -337,10 +349,9 @@ public:
void BinaryOptError(const char* op, PyObject* _0, PyObject* _1);
void AttributeError(PyObject* obj, StrName name);
void AttributeError(const Str& msg){ __builtin_error("AttributeError", msg); }
#endif
/********** type **********/
PyObject* new_type_object(PyObject* mod, StrName name, Type base, bool subclass_enabled=true);
const PyTypeInfo* _inst_type_info(PyObject* obj);
#if PK_REGION("Type Checking Methods")
bool isinstance(PyObject* obj, Type base);
bool issubclass(Type cls, Type base);
void check_type(PyObject* obj, Type type){ if(!is_type(obj, type)) TypeError(type, _tp(obj)); }
@ -348,8 +359,10 @@ public:
PyObject* _t(PyObject* obj){ return _all_types[_tp(obj)].obj; }
PyObject* _t(Type t){ return _all_types[t.index].obj; }
Type _tp(PyObject* obj){ return is_small_int(obj) ? tp_int : obj->type; }
const PyTypeInfo* _tp_info(PyObject* obj);
#endif
/********** user type **********/
#if PK_REGION("User Type Registration")
template<typename T>
Type _tp_user(){ return _find_type_in_cxx_typeid_map<T>(); }
template<typename T>
@ -379,6 +392,7 @@ public:
}
return it->second;
}
#endif
/********** private **********/
virtual ~VM();

View File

@ -17,7 +17,7 @@ namespace pkpy{
#define BINARY_F_COMPARE(func, op, rfunc) \
PyObject* ret; \
const PyTypeInfo* _ti = _inst_type_info(_0); \
const PyTypeInfo* _ti = _tp_info(_0); \
if(_ti->m##func){ \
ret = _ti->m##func(this, _0, _1); \
}else{ \
@ -48,7 +48,7 @@ void VM::__op_unpack_sequence(uint16_t arg){
}else{
auto _lock = heap.gc_scope_lock(); // lock the gc via RAII!!
_0 = py_iter(_0);
const PyTypeInfo* ti = _inst_type_info(_0);
const PyTypeInfo* ti = _tp_info(_0);
for(int i=0; i<arg; i++){
PyObject* _1 = _py_next(ti, _0);
if(_1 == StopIteration) ValueError("not enough values to unpack");
@ -224,7 +224,7 @@ __NEXT_STEP:;
case OP_LOAD_SUBSCR:{
PyObject* _1 = POPX(); // b
PyObject* _0 = TOP(); // a
auto _ti = _inst_type_info(_0);
auto _ti = _tp_info(_0);
if(_ti->m__getitem__){
TOP() = _ti->m__getitem__(this, _0, _1);
}else{
@ -235,7 +235,7 @@ __NEXT_STEP:;
PyObject* _1 = frame->_locals[byte.arg];
if(_1 == PY_NULL) vm->UnboundLocalError(co->varnames[byte.arg]);
PyObject* _0 = TOP(); // a
auto _ti = _inst_type_info(_0);
auto _ti = _tp_info(_0);
if(_ti->m__getitem__){
TOP() = _ti->m__getitem__(this, _0, _1);
}else{
@ -245,7 +245,7 @@ __NEXT_STEP:;
case OP_LOAD_SUBSCR_SMALL_INT:{
PyObject* _1 = (PyObject*)(uintptr_t)byte.arg;
PyObject* _0 = TOP(); // a
auto _ti = _inst_type_info(_0);
auto _ti = _tp_info(_0);
if(_ti->m__getitem__){
TOP() = _ti->m__getitem__(this, _0, _1);
}else{
@ -279,7 +279,7 @@ __NEXT_STEP:;
PyObject* _2 = POPX(); // b
PyObject* _1 = POPX(); // a
PyObject* _0 = POPX(); // val
auto _ti = _inst_type_info(_1);
auto _ti = _tp_info(_1);
if(_ti->m__setitem__){
_ti->m__setitem__(this, _1, _2, _0);
}else{
@ -291,7 +291,7 @@ __NEXT_STEP:;
if(_2 == PY_NULL) vm->UnboundLocalError(co->varnames[byte.arg]);
PyObject* _1 = POPX(); // a
PyObject* _0 = POPX(); // val
auto _ti = _inst_type_info(_1);
auto _ti = _tp_info(_1);
if(_ti->m__setitem__){
_ti->m__setitem__(this, _1, _2, _0);
}else{
@ -324,7 +324,7 @@ __NEXT_STEP:;
case OP_DELETE_SUBSCR:{
PyObject* _1 = POPX();
PyObject* _0 = POPX();
auto _ti = _inst_type_info(_0);
auto _ti = _tp_info(_0);
if(_ti->m__delitem__){
_ti->m__delitem__(this, _0, _1);
}else{
@ -423,7 +423,7 @@ __NEXT_STEP:;
} DISPATCH()
/*****************************************/
#define BINARY_OP_SPECIAL(func) \
_ti = _inst_type_info(_0); \
_ti = _tp_info(_0); \
if(_ti->m##func){ \
TOP() = _ti->m##func(this, _0, _1); \
}else{ \
@ -589,7 +589,7 @@ __NEXT_STEP:;
} DISPATCH()
case OP_CONTAINS_OP:{
// a in b -> b __contains__ a
auto _ti = _inst_type_info(TOP());
auto _ti = _tp_info(TOP());
PyObject* _0;
if(_ti->m__contains__){
_0 = _ti->m__contains__(this, TOP(), SECOND());
@ -749,7 +749,7 @@ __NEXT_STEP:;
DISPATCH()
case OP_UNARY_INVERT:{
PyObject* _0;
auto _ti = _inst_type_info(TOP());
auto _ti = _tp_info(TOP());
if(_ti->m__invert__) _0 = _ti->m__invert__(this, TOP());
else _0 = call_method(TOP(), __invert__);
TOP() = _0;
@ -790,7 +790,7 @@ __NEXT_STEP:;
} DISPATCH()
case OP_FOR_ITER_UNPACK:{
PyObject* _0 = TOP();
const PyTypeInfo* _ti = _inst_type_info(_0);
const PyTypeInfo* _ti = _tp_info(_0);
if(_ti->m__next__){
unsigned n = _ti->m__next__(this, _0);
if(n == 0){
@ -850,7 +850,7 @@ __NEXT_STEP:;
case OP_UNPACK_EX: {
auto _lock = heap.gc_scope_lock(); // lock the gc via RAII!!
PyObject* _0 = py_iter(POPX());
const PyTypeInfo* _ti = _inst_type_info(_0);
const PyTypeInfo* _ti = _tp_info(_0);
PyObject* _1;
for(int i=0; i<byte.arg; i++){
_1 = _py_next(_ti, _0);

View File

@ -104,7 +104,7 @@ void add_module_dataclasses(VM* vm){
});
vm->bind_func(mod, "asdict", 1, [](VM* vm, ArgsView args){
const auto& fields = vm->_inst_type_info(args[0])->annotated_fields;
const auto& fields = vm->_tp_info(args[0])->annotated_fields;
const NameDict& obj_d = args[0]->attr();
Dict d(vm);
for(StrName field: fields){

View File

@ -249,7 +249,7 @@ void __init_builtins(VM* _vm) {
});
_vm->bind_func(_vm->builtins, "len", 1, [](VM* vm, ArgsView args){
const PyTypeInfo* ti = vm->_inst_type_info(args[0]);
const PyTypeInfo* ti = vm->_tp_info(args[0]);
if(ti->m__len__) return VAR(ti->m__len__(vm, args[0]));
return vm->call_method(args[0], __len__);
});
@ -691,7 +691,7 @@ void __init_builtins(VM* _vm) {
const Str& self = _CAST(Str&, args[0]);
SStream ss;
PyObject* it = vm->py_iter(args[1]); // strong ref
const PyTypeInfo* info = vm->_inst_type_info(args[1]);
const PyTypeInfo* info = vm->_tp_info(args[1]);
PyObject* obj = vm->_py_next(info, it);
while(obj != vm->StopIteration){
if(!ss.empty()) ss << self;
@ -913,7 +913,7 @@ void __init_builtins(VM* _vm) {
auto _lock = vm->heap.gc_scope_lock();
List& self = _CAST(List&, args[0]);
PyObject* it = vm->py_iter(args[1]); // strong ref
const PyTypeInfo* info = vm->_inst_type_info(args[1]);
const PyTypeInfo* info = vm->_tp_info(args[1]);
PyObject* obj = vm->_py_next(info, it);
while(obj != vm->StopIteration){
self.push_back(obj);

View File

@ -84,7 +84,7 @@ namespace pkpy{
}
PyObject* VM::py_str(PyObject* obj){
const PyTypeInfo* ti = _inst_type_info(obj);
const PyTypeInfo* ti = _tp_info(obj);
if(ti->m__str__) return ti->m__str__(this, obj);
PyObject* self;
PyObject* f = get_unbound_method(obj, __str__, &self, false);
@ -93,7 +93,7 @@ namespace pkpy{
}
PyObject* VM::py_repr(PyObject* obj){
const PyTypeInfo* ti = _inst_type_info(obj);
const PyTypeInfo* ti = _tp_info(obj);
if(ti->m__repr__) return ti->m__repr__(this, obj);
return call_method(obj, __repr__);
}
@ -104,7 +104,7 @@ namespace pkpy{
}
PyObject* VM::py_iter(PyObject* obj){
const PyTypeInfo* ti = _inst_type_info(obj);
const PyTypeInfo* ti = _tp_info(obj);
if(ti->m__iter__) return ti->m__iter__(this, obj);
PyObject* self;
PyObject* iter_f = get_unbound_method(obj, __iter__, &self, false);
@ -212,14 +212,14 @@ namespace pkpy{
return obj;
}
const PyTypeInfo* VM::_inst_type_info(PyObject* obj){
const PyTypeInfo* VM::_tp_info(PyObject* obj){
if(is_small_int(obj)) return &_all_types[tp_int];
return &_all_types[obj->type];
}
bool VM::py_eq(PyObject* lhs, PyObject* rhs){
if(lhs == rhs) return true;
const PyTypeInfo* ti = _inst_type_info(lhs);
const PyTypeInfo* ti = _tp_info(lhs);
PyObject* res;
if(ti->m__eq__){
res = ti->m__eq__(this, lhs, rhs);
@ -228,7 +228,7 @@ namespace pkpy{
res = call_method(lhs, __eq__, rhs);
if(res != vm->NotImplemented) return res == vm->True;
ti = _inst_type_info(rhs);
ti = _tp_info(rhs);
if(ti->m__eq__){
res = ti->m__eq__(this, rhs, lhs);
if(res != vm->NotImplemented) return res == vm->True;
@ -255,7 +255,7 @@ namespace pkpy{
}
PyObject* VM::py_next(PyObject* obj){
const PyTypeInfo* ti = _inst_type_info(obj);
const PyTypeInfo* ti = _tp_info(obj);
return _py_next(ti, obj);
}
@ -394,7 +394,7 @@ namespace pkpy{
}
PyObject* VM::py_negate(PyObject* obj){
const PyTypeInfo* ti = _inst_type_info(obj);
const PyTypeInfo* ti = _tp_info(obj);
if(ti->m__neg__) return ti->m__neg__(this, obj);
return call_method(obj, __neg__);
}
@ -418,7 +418,7 @@ List VM::py_list(PyObject* it){
auto _lock = heap.gc_scope_lock();
it = py_iter(it);
List list;
const PyTypeInfo* info = _inst_type_info(it);
const PyTypeInfo* info = _tp_info(it);
PyObject* obj = _py_next(info, it);
while(obj != StopIteration){
list.push_back(obj);
@ -473,7 +473,7 @@ void VM::parse_int_slice(const Slice& s, int length, int& start, int& stop, int&
i64 VM::py_hash(PyObject* obj){
// https://docs.python.org/3.10/reference/datamodel.html#object.__hash__
const PyTypeInfo* ti = _inst_type_info(obj);
const PyTypeInfo* ti = _tp_info(obj);
if(ti->m__hash__) return ti->m__hash__(this, obj);
PyObject* self;
@ -814,7 +814,7 @@ void VM::__unpack_as_list(ArgsView args, List& list){
// maybe this check should be done in the compile time
if(w.level != 1) TypeError("expected level 1 star wrapper");
PyObject* _0 = py_iter(w.obj);
const PyTypeInfo* info = _inst_type_info(_0);
const PyTypeInfo* info = _tp_info(_0);
PyObject* _1 = _py_next(info, _0);
while(_1 != StopIteration){
list.push_back(_1);
@ -1048,7 +1048,7 @@ PyObject* VM::vectorcall(int ARGC, int KWARGC, bool op_call){
}
void VM::delattr(PyObject *_0, StrName _name){
const PyTypeInfo* ti = _inst_type_info(_0);
const PyTypeInfo* ti = _tp_info(_0);
if(ti->m__delattr__ && ti->m__delattr__(this, _0, _name)) return;
if(is_tagged(_0) || !_0->is_attr_valid()) TypeError("cannot delete attribute");
if(!_0->attr().del(_name)) AttributeError(_0, _name);