mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-21 20:10:17 +00:00
up
This commit is contained in:
parent
5d6d109164
commit
12419105bd
@ -72,7 +72,7 @@ __NEXT_STEP:;
|
|||||||
PyObject* a = frame->top();
|
PyObject* a = frame->top();
|
||||||
StrName name = frame->co->names[byte.arg];
|
StrName name = frame->co->names[byte.arg];
|
||||||
PyObject* self;
|
PyObject* self;
|
||||||
frame->top() = get_unbound_method(a, name, &self);
|
frame->top() = get_unbound_method(a, name, &self, true, true);
|
||||||
frame->push(self);
|
frame->push(self);
|
||||||
} DISPATCH();
|
} DISPATCH();
|
||||||
case OP_LOAD_SUBSCR: {
|
case OP_LOAD_SUBSCR: {
|
||||||
@ -271,11 +271,12 @@ __NEXT_STEP:;
|
|||||||
PyObject* kv = frame->popx();
|
PyObject* kv = frame->popx();
|
||||||
// we do copy here to avoid accidental gc in `kv`
|
// we do copy here to avoid accidental gc in `kv`
|
||||||
// TODO: optimize to avoid copy
|
// TODO: optimize to avoid copy
|
||||||
call(frame->top_1(), __setitem__, CAST(Tuple, kv));
|
Tuple& t = CAST(Tuple& ,kv);
|
||||||
|
fast_call(__setitem__, Args{frame->top_1(), t[0], t[1]});
|
||||||
} DISPATCH();
|
} DISPATCH();
|
||||||
case OP_SET_ADD: {
|
case OP_SET_ADD: {
|
||||||
PyObject* obj = frame->popx();
|
PyObject* obj = frame->popx();
|
||||||
call(frame->top_1(), m_add, Args{obj});
|
fast_call(m_add, Args{frame->top_1(), obj});
|
||||||
} DISPATCH();
|
} DISPATCH();
|
||||||
/*****************************************/
|
/*****************************************/
|
||||||
case OP_UNARY_NEGATIVE:
|
case OP_UNARY_NEGATIVE:
|
||||||
|
@ -115,7 +115,7 @@ inline void init_builtins(VM* _vm) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
_vm->bind_builtin_func<1>("repr", CPP_LAMBDA(vm->asRepr(args[0])));
|
_vm->bind_builtin_func<1>("repr", CPP_LAMBDA(vm->asRepr(args[0])));
|
||||||
_vm->bind_builtin_func<1>("len", CPP_LAMBDA(vm->call(args[0], __len__, no_arg())));
|
_vm->bind_builtin_func<1>("len", CPP_LAMBDA(vm->fast_call(__len__, Args{args[0]})));
|
||||||
|
|
||||||
_vm->bind_builtin_func<1>("hash", [](VM* vm, Args& args){
|
_vm->bind_builtin_func<1>("hash", [](VM* vm, Args& args){
|
||||||
i64 value = vm->hash(args[0]);
|
i64 value = vm->hash(args[0]);
|
||||||
@ -604,7 +604,7 @@ inline void add_module_json(VM* vm){
|
|||||||
return vm->_exec(code, vm->top_frame()->_module, vm->builtins, vm->top_frame()->_locals);
|
return vm->_exec(code, vm->top_frame()->_module, vm->builtins, vm->top_frame()->_locals);
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bind_func<1>(mod, "dumps", CPP_LAMBDA(vm->call(args[0], __json__, no_arg())));
|
vm->bind_func<1>(mod, "dumps", CPP_LAMBDA(vm->fast_call(__json__, Args{args[0]})));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void add_module_math(VM* vm){
|
inline void add_module_math(VM* vm){
|
||||||
@ -965,7 +965,7 @@ extern "C" {
|
|||||||
ss << f_header;
|
ss << f_header;
|
||||||
for(int i=0; i<args.size(); i++){
|
for(int i=0; i<args.size(); i++){
|
||||||
ss << ' ';
|
ss << ' ';
|
||||||
pkpy::PyObject* x = vm->call(args[i], pkpy::__json__, pkpy::no_arg());
|
pkpy::PyObject* x = vm->fast_call(pkpy::__json__, pkpy::Args{args[i]});
|
||||||
ss << pkpy::CAST(pkpy::Str&, x);
|
ss << pkpy::CAST(pkpy::Str&, x);
|
||||||
}
|
}
|
||||||
char* packet = strdup(ss.str().c_str());
|
char* packet = strdup(ss.str().c_str());
|
||||||
|
120
src/vm.h
120
src/vm.h
@ -5,6 +5,7 @@
|
|||||||
#include "error.h"
|
#include "error.h"
|
||||||
#include "gc.h"
|
#include "gc.h"
|
||||||
#include "obj.h"
|
#include "obj.h"
|
||||||
|
#include "str.h"
|
||||||
|
|
||||||
namespace pkpy{
|
namespace pkpy{
|
||||||
|
|
||||||
@ -102,15 +103,17 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
PyObject* asStr(PyObject* obj){
|
PyObject* asStr(PyObject* obj){
|
||||||
PyObject* f = getattr(obj, __str__, false, true);
|
PyObject* self;
|
||||||
if(f != nullptr) return call(f, no_arg());
|
PyObject* f = get_unbound_method(obj, __str__, &self, false);
|
||||||
|
if(self != _py_null) return call(f, Args{self});
|
||||||
return asRepr(obj);
|
return asRepr(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject* asIter(PyObject* obj){
|
PyObject* asIter(PyObject* obj){
|
||||||
if(is_type(obj, tp_iterator)) return obj;
|
if(is_type(obj, tp_iterator)) return obj;
|
||||||
PyObject* iter_f = getattr(obj, __iter__, false, true);
|
PyObject* self;
|
||||||
if(iter_f != nullptr) return call(iter_f, no_arg());
|
PyObject* iter_f = get_unbound_method(obj, __iter__, &self, false);
|
||||||
|
if(self != _py_null) return call(iter_f, Args{self});
|
||||||
TypeError(OBJ_NAME(_t(obj)).escape(true) + " object is not iterable");
|
TypeError(OBJ_NAME(_t(obj)).escape(true) + " object is not iterable");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@ -157,13 +160,6 @@ public:
|
|||||||
return call(callable, std::forward<ArgT>(args), no_arg(), false);
|
return call(callable, std::forward<ArgT>(args), no_arg(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename ArgT>
|
|
||||||
std::enable_if_t<std::is_same_v<std::decay_t<ArgT>, Args>, PyObject*>
|
|
||||||
call(PyObject* obj, const StrName name, ArgT&& args){
|
|
||||||
PyObject* callable = getattr(obj, name, true, true);
|
|
||||||
return call(callable, std::forward<ArgT>(args), no_arg(), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject* exec(Str source, Str filename, CompileMode mode, PyObject* _module=nullptr){
|
PyObject* exec(Str source, Str filename, CompileMode mode, PyObject* _module=nullptr){
|
||||||
if(_module == nullptr) _module = _main;
|
if(_module == nullptr) _module = _main;
|
||||||
try {
|
try {
|
||||||
@ -337,8 +333,8 @@ public:
|
|||||||
void init_builtin_types();
|
void init_builtin_types();
|
||||||
PyObject* call(PyObject* callable, Args args, const Args& kwargs, bool opCall);
|
PyObject* call(PyObject* callable, Args args, const Args& kwargs, bool opCall);
|
||||||
void unpack_args(Args& args);
|
void unpack_args(Args& args);
|
||||||
PyObject* getattr(PyObject* obj, StrName name, bool throw_err=true, bool class_only=false);
|
PyObject* getattr(PyObject* obj, StrName name, bool throw_err=true);
|
||||||
PyObject* get_unbound_method(PyObject* obj, StrName name, PyObject** self);
|
PyObject* get_unbound_method(PyObject* obj, StrName name, PyObject** self, bool throw_err=true, bool fallback=false);
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void setattr(PyObject* obj, StrName name, T&& value);
|
void setattr(PyObject* obj, StrName name, T&& value);
|
||||||
template<int ARGC>
|
template<int ARGC>
|
||||||
@ -513,9 +509,10 @@ inline bool VM::asBool(PyObject* obj){
|
|||||||
if(obj == None) return false;
|
if(obj == None) return false;
|
||||||
if(is_type(obj, tp_int)) return CAST(i64, obj) != 0;
|
if(is_type(obj, tp_int)) return CAST(i64, obj) != 0;
|
||||||
if(is_type(obj, tp_float)) return CAST(f64, obj) != 0.0;
|
if(is_type(obj, tp_float)) return CAST(f64, obj) != 0.0;
|
||||||
PyObject* len_f = getattr(obj, __len__, false, true);
|
PyObject* self;
|
||||||
if(len_f != nullptr){
|
PyObject* len_f = get_unbound_method(obj, __len__, &self, false);
|
||||||
PyObject* ret = call(len_f, no_arg());
|
if(self != _py_null){
|
||||||
|
PyObject* ret = call(len_f, Args{self});
|
||||||
return CAST(i64, ret) > 0;
|
return CAST(i64, ret) > 0;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -545,7 +542,8 @@ inline i64 VM::hash(PyObject* obj){
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline PyObject* VM::asRepr(PyObject* obj){
|
inline PyObject* VM::asRepr(PyObject* obj){
|
||||||
return call(obj, __repr__, no_arg());
|
// TODO: fastcall does not take care of super() proxy!
|
||||||
|
return fast_call(__repr__, Args{obj});
|
||||||
}
|
}
|
||||||
|
|
||||||
inline PyObject* VM::new_module(StrName name) {
|
inline PyObject* VM::new_module(StrName name) {
|
||||||
@ -699,8 +697,10 @@ inline PyObject* VM::call(PyObject* callable, Args args, const Args& kwargs, boo
|
|||||||
obj = call(new_f, std::move(args), kwargs, false);
|
obj = call(new_f, std::move(args), kwargs, false);
|
||||||
}else{
|
}else{
|
||||||
obj = heap.gcnew<DummyInstance>(OBJ_GET(Type, callable), {});
|
obj = heap.gcnew<DummyInstance>(OBJ_GET(Type, callable), {});
|
||||||
PyObject* init_f = getattr(obj, __init__, false, true);
|
PyObject* self;
|
||||||
if (init_f != nullptr) call(init_f, std::move(args), kwargs, false);
|
PyObject* init_f = get_unbound_method(obj, __init__, &self, false);
|
||||||
|
args.extend_self(self);
|
||||||
|
if (self != _py_null) call(init_f, std::move(args), kwargs, false);
|
||||||
}
|
}
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
@ -764,8 +764,10 @@ inline PyObject* VM::call(PyObject* callable, Args args, const Args& kwargs, boo
|
|||||||
return _exec();
|
return _exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject* call_f = getattr(callable, __call__, false, true);
|
PyObject* self;
|
||||||
if(call_f != nullptr){
|
PyObject* call_f = get_unbound_method(callable, __call__, &self, false);
|
||||||
|
if(self != _py_null){
|
||||||
|
args.extend_self(self);
|
||||||
return call(call_f, std::move(args), kwargs, false);
|
return call(call_f, std::move(args), kwargs, false);
|
||||||
}
|
}
|
||||||
TypeError(OBJ_NAME(_t(callable)).escape(true) + " object is not callable");
|
TypeError(OBJ_NAME(_t(callable)).escape(true) + " object is not callable");
|
||||||
@ -787,41 +789,7 @@ inline void VM::unpack_args(Args& args){
|
|||||||
}
|
}
|
||||||
|
|
||||||
// https://docs.python.org/3/howto/descriptor.html#invocation-from-an-instance
|
// https://docs.python.org/3/howto/descriptor.html#invocation-from-an-instance
|
||||||
inline PyObject* VM::getattr(PyObject* obj, StrName name, bool throw_err, bool class_only){
|
inline PyObject* VM::getattr(PyObject* obj, StrName name, bool throw_err){
|
||||||
// TODO: class_only impl may not be correct
|
|
||||||
PyObject* objtype = _t(obj);
|
|
||||||
// handle super() proxy
|
|
||||||
if(is_type(obj, tp_super)){
|
|
||||||
const Super& super = OBJ_GET(Super, obj);
|
|
||||||
obj = super.first;
|
|
||||||
objtype = _t(super.second);
|
|
||||||
}
|
|
||||||
PyObject* cls_var = find_name_in_mro(objtype, name);
|
|
||||||
if(cls_var != nullptr){
|
|
||||||
// handle descriptor
|
|
||||||
PyObject* descr_get = _t(cls_var)->attr().try_get(__get__);
|
|
||||||
if(descr_get != nullptr) return call(descr_get, Args{cls_var, obj});
|
|
||||||
}
|
|
||||||
// handle instance __dict__
|
|
||||||
if(!class_only && !is_tagged(obj) && obj->is_attr_valid()){
|
|
||||||
PyObject* val = obj->attr().try_get(name);
|
|
||||||
if(val != nullptr) return val;
|
|
||||||
}
|
|
||||||
if(cls_var != nullptr){
|
|
||||||
// bound method is non-data descriptor
|
|
||||||
if(is_type(cls_var, tp_function) || is_type(cls_var, tp_native_function)){
|
|
||||||
return VAR(BoundMethod(obj, cls_var));
|
|
||||||
}
|
|
||||||
return cls_var;
|
|
||||||
}
|
|
||||||
if(throw_err) AttributeError(obj, name);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
// used by OP_LOAD_METHOD
|
|
||||||
// try to load a unbound method (fallback to `getattr` if not found)
|
|
||||||
inline PyObject* VM::get_unbound_method(PyObject* obj, StrName name, PyObject** self){
|
|
||||||
*self = _py_null;
|
|
||||||
// TODO: class_only impl may not be correct
|
// TODO: class_only impl may not be correct
|
||||||
PyObject* objtype = _t(obj);
|
PyObject* objtype = _t(obj);
|
||||||
// handle super() proxy
|
// handle super() proxy
|
||||||
@ -841,13 +809,51 @@ inline PyObject* VM::get_unbound_method(PyObject* obj, StrName name, PyObject**
|
|||||||
PyObject* val = obj->attr().try_get(name);
|
PyObject* val = obj->attr().try_get(name);
|
||||||
if(val != nullptr) return val;
|
if(val != nullptr) return val;
|
||||||
}
|
}
|
||||||
|
if(cls_var != nullptr){
|
||||||
|
// bound method is non-data descriptor
|
||||||
|
if(is_type(cls_var, tp_function) || is_type(cls_var, tp_native_function)){
|
||||||
|
return VAR(BoundMethod(obj, cls_var));
|
||||||
|
}
|
||||||
|
return cls_var;
|
||||||
|
}
|
||||||
|
if(throw_err) AttributeError(obj, name);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// used by OP_LOAD_METHOD
|
||||||
|
// try to load a unbound method (fallback to `getattr` if not found)
|
||||||
|
inline PyObject* VM::get_unbound_method(PyObject* obj, StrName name, PyObject** self, bool throw_err, bool fallback){
|
||||||
|
*self = _py_null;
|
||||||
|
// TODO: class_only impl may not be correct
|
||||||
|
PyObject* objtype = _t(obj);
|
||||||
|
// handle super() proxy
|
||||||
|
if(is_type(obj, tp_super)){
|
||||||
|
const Super& super = OBJ_GET(Super, obj);
|
||||||
|
obj = super.first;
|
||||||
|
objtype = _t(super.second);
|
||||||
|
}
|
||||||
|
PyObject* cls_var = find_name_in_mro(objtype, name);
|
||||||
|
|
||||||
|
if(fallback){
|
||||||
|
if(cls_var != nullptr){
|
||||||
|
// handle descriptor
|
||||||
|
PyObject* descr_get = _t(cls_var)->attr().try_get(__get__);
|
||||||
|
if(descr_get != nullptr) return call(descr_get, Args{cls_var, obj});
|
||||||
|
}
|
||||||
|
// handle instance __dict__
|
||||||
|
if(!is_tagged(obj) && obj->is_attr_valid()){
|
||||||
|
PyObject* val = obj->attr().try_get(name);
|
||||||
|
if(val != nullptr) return val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(cls_var != nullptr){
|
if(cls_var != nullptr){
|
||||||
if(is_type(cls_var, tp_function) || is_type(cls_var, tp_native_function)){
|
if(is_type(cls_var, tp_function) || is_type(cls_var, tp_native_function)){
|
||||||
*self = obj;
|
*self = obj;
|
||||||
}
|
}
|
||||||
return cls_var;
|
return cls_var;
|
||||||
}
|
}
|
||||||
AttributeError(obj, name);
|
if(throw_err) AttributeError(obj, name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user