mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 03:20:18 +00:00
...
This commit is contained in:
parent
22e74a16a3
commit
3de3e625ee
@ -3,6 +3,8 @@
|
||||
|
||||
using namespace pkpy;
|
||||
|
||||
typedef int (*LuaStyleFuncC)(VM*);
|
||||
|
||||
struct LuaStack: public ValueStackImpl<32>{
|
||||
PyObject*& at(int i) {
|
||||
if(i < 0 || i >= size()){
|
||||
@ -177,12 +179,7 @@ void pkpy_vm_destroy(pkpy_vm* vm_handle) {
|
||||
}
|
||||
|
||||
PyObject* c_function_wrapper(VM* vm, ArgsView args) {
|
||||
LuaStyleFuncC f;
|
||||
if(args[-1] != PY_NULL){
|
||||
f = _py_cast<NativeFunc&>(vm, args[-1])._lua_f;
|
||||
} else {
|
||||
f = _py_cast<NativeFunc&>(vm, args[-2])._lua_f;
|
||||
}
|
||||
LuaStyleFuncC f = lambda_get_userdata<LuaStyleFuncC>(args.begin());
|
||||
CVM* cvm = (CVM*) vm;
|
||||
|
||||
//setup c stack
|
||||
@ -225,7 +222,7 @@ PyObject* c_function_wrapper(VM* vm, ArgsView args) {
|
||||
bool pkpy_push_function(pkpy_vm* vm_handle, pkpy_function f, int argc) {
|
||||
CVM* vm = (CVM*) vm_handle;
|
||||
NativeFunc nf = NativeFunc(c_function_wrapper, argc, false);
|
||||
nf._lua_f = (LuaStyleFuncC) f;
|
||||
nf.set_userdata(f);
|
||||
ERRHANDLER_OPEN
|
||||
vm->c_data->safe_push(py_var(vm, nf));
|
||||
ERRHANDLER_CLOSE
|
||||
|
@ -98,14 +98,13 @@ __NEXT_STEP:;
|
||||
TARGET(LOAD_ELLIPSIS) PUSH(Ellipsis); DISPATCH();
|
||||
TARGET(LOAD_FUNCTION) {
|
||||
FuncDecl_ decl = co->func_decls[byte.arg];
|
||||
bool is_simple = decl->starred_kwarg==-1 && decl->starred_arg==-1 && decl->kwargs.size()==0 && !decl->code->is_generator;
|
||||
PyObject* obj;
|
||||
if(decl->nested){
|
||||
NameDict_ captured = frame->_locals.to_namedict();
|
||||
obj = VAR(Function({decl, is_simple, frame->_module, captured}));
|
||||
obj = VAR(Function({decl, frame->_module, captured}));
|
||||
captured->set(decl->code->name, obj);
|
||||
}else{
|
||||
obj = VAR(Function({decl, is_simple, frame->_module}));
|
||||
obj = VAR(Function({decl, frame->_module}));
|
||||
}
|
||||
PUSH(obj);
|
||||
} DISPATCH();
|
||||
|
@ -20,7 +20,7 @@
|
||||
#include <variant>
|
||||
#include <type_traits>
|
||||
|
||||
#define PK_VERSION "1.0.5"
|
||||
#define PK_VERSION "1.0.7"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
|
56
src/obj.h
56
src/obj.h
@ -17,14 +17,29 @@ using NativeFuncC = std::function<PyObject*(VM*, ArgsView)>;
|
||||
typedef PyObject* (*NativeFuncC)(VM*, ArgsView);
|
||||
#endif
|
||||
|
||||
typedef int (*LuaStyleFuncC)(VM*);
|
||||
typedef shared_ptr<CodeObject> CodeObject_;
|
||||
|
||||
struct FuncDecl {
|
||||
struct KwArg {
|
||||
int key; // index in co->varnames
|
||||
PyObject* value; // default value
|
||||
};
|
||||
CodeObject_ code; // code object of this function
|
||||
pod_vector<int> args; // indices in co->varnames
|
||||
pod_vector<KwArg> kwargs; // indices in co->varnames
|
||||
int starred_arg = -1; // index in co->varnames, -1 if no *arg
|
||||
int starred_kwarg = -1; // index in co->varnames, -1 if no **kwarg
|
||||
bool nested = false; // whether this function is nested
|
||||
void _gc_mark() const;
|
||||
};
|
||||
|
||||
using FuncDecl_ = shared_ptr<FuncDecl>;
|
||||
|
||||
struct NativeFunc {
|
||||
NativeFuncC f;
|
||||
int argc;
|
||||
|
||||
// this is designed for lua style C bindings
|
||||
LuaStyleFuncC _lua_f;
|
||||
FuncDecl_ decl; // if this is not null, use ex call
|
||||
|
||||
using UserData = char[32];
|
||||
UserData _userdata;
|
||||
@ -53,39 +68,22 @@ struct NativeFunc {
|
||||
this->f = f;
|
||||
this->argc = argc;
|
||||
if(argc != -1) this->argc += (int)method;
|
||||
_lua_f = nullptr;
|
||||
_has_userdata = false;
|
||||
}
|
||||
|
||||
PyObject* operator()(VM* vm, ArgsView args) const;
|
||||
NativeFunc(NativeFuncC f, FuncDecl_ decl){
|
||||
this->f = f;
|
||||
this->argc = -1;
|
||||
this->decl = decl;
|
||||
_has_userdata = false;
|
||||
}
|
||||
|
||||
void check_size(VM* vm, ArgsView args) const;
|
||||
PyObject* call(VM* vm, ArgsView args) const;
|
||||
};
|
||||
|
||||
|
||||
struct NativeFuncEx{
|
||||
NativeFuncC f;
|
||||
};
|
||||
|
||||
typedef shared_ptr<CodeObject> CodeObject_;
|
||||
|
||||
struct FuncDecl {
|
||||
struct KwArg {
|
||||
int key; // index in co->varnames
|
||||
PyObject* value; // default value
|
||||
};
|
||||
CodeObject_ code; // code object of this function
|
||||
pod_vector<int> args; // indices in co->varnames
|
||||
pod_vector<KwArg> kwargs; // indices in co->varnames
|
||||
int starred_arg = -1; // index in co->varnames, -1 if no *arg
|
||||
int starred_kwarg = -1; // index in co->varnames, -1 if no **kwarg
|
||||
bool nested = false; // whether this function is nested
|
||||
void _gc_mark() const;
|
||||
};
|
||||
|
||||
using FuncDecl_ = shared_ptr<FuncDecl>;
|
||||
|
||||
struct Function{
|
||||
FuncDecl_ decl;
|
||||
bool is_simple;
|
||||
PyObject* _module;
|
||||
NameDict_ _closure;
|
||||
};
|
||||
|
162
src/vm.h
162
src/vm.h
@ -690,15 +690,16 @@ public:
|
||||
PyObject* _py_generator(Frame&& frame, ArgsView buffer);
|
||||
// new style binding api
|
||||
PyObject* bind(PyObject*, const Str&, NativeFuncC);
|
||||
void _prepare_py_call(PyObject**, ArgsView, ArgsView, const FuncDecl_&);
|
||||
};
|
||||
|
||||
inline PyObject* NativeFunc::operator()(VM* vm, ArgsView args) const{
|
||||
inline void NativeFunc::check_size(VM* vm, ArgsView args) const{
|
||||
if(args.size() != argc && argc != -1) {
|
||||
vm->TypeError(fmt("expected ", argc, " arguments, got ", args.size()));
|
||||
}
|
||||
#if PK_DEBUG_EXTRA_CHECK
|
||||
if(f == nullptr) FATAL_ERROR();
|
||||
#endif
|
||||
}
|
||||
|
||||
inline PyObject* NativeFunc::call(VM *vm, ArgsView args) const {
|
||||
return f(vm, args);
|
||||
}
|
||||
|
||||
@ -1238,6 +1239,64 @@ inline void VM::_unpack_as_dict(ArgsView args, Dict& dict){
|
||||
}
|
||||
}
|
||||
|
||||
inline void VM::_prepare_py_call(PyObject** buffer, ArgsView args, ArgsView kwargs, const FuncDecl_& decl){
|
||||
const CodeObject* co = decl->code.get();
|
||||
int co_nlocals = co->varnames.size();
|
||||
int decl_argc = decl->args.size();
|
||||
|
||||
if(args.size() < decl_argc){
|
||||
vm->TypeError(fmt(
|
||||
"expected ", decl_argc, " positional arguments, got ", args.size(),
|
||||
" (", co->name, ')'
|
||||
));
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
// prepare args
|
||||
for(int index: decl->args) buffer[index] = args[i++];
|
||||
// set extra varnames to nullptr
|
||||
for(int j=i; j<co_nlocals; j++) buffer[j] = PY_NULL;
|
||||
// prepare kwdefaults
|
||||
for(auto& kv: decl->kwargs) buffer[kv.key] = kv.value;
|
||||
|
||||
// handle *args
|
||||
if(decl->starred_arg != -1){
|
||||
ArgsView vargs(args.begin() + i, args.end());
|
||||
buffer[decl->starred_arg] = VAR(vargs.to_tuple());
|
||||
i += vargs.size();
|
||||
}else{
|
||||
// kwdefaults override
|
||||
for(auto& kv: decl->kwargs){
|
||||
if(i >= args.size()) break;
|
||||
buffer[kv.key] = args[i++];
|
||||
}
|
||||
if(i < args.size()) TypeError(fmt("too many arguments", " (", decl->code->name, ')'));
|
||||
}
|
||||
|
||||
PyObject* vkwargs;
|
||||
if(decl->starred_kwarg != -1){
|
||||
vkwargs = VAR(Dict(this));
|
||||
buffer[decl->starred_kwarg] = vkwargs;
|
||||
}else{
|
||||
vkwargs = nullptr;
|
||||
}
|
||||
|
||||
for(int j=0; j<kwargs.size(); j+=2){
|
||||
StrName key(CAST(int, kwargs[j]));
|
||||
int index = co->varnames_inv.try_get(key);
|
||||
if(index < 0){
|
||||
if(vkwargs == nullptr){
|
||||
TypeError(fmt(key.escape(), " is an invalid keyword argument for ", co->name, "()"));
|
||||
}else{
|
||||
Dict& dict = _CAST(Dict&, vkwargs);
|
||||
dict.set(VAR(key.sv()), kwargs[j+1]);
|
||||
}
|
||||
}else{
|
||||
buffer[index] = kwargs[j+1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline PyObject* VM::vectorcall(int ARGC, int KWARGC, bool op_call){
|
||||
PyObject** p1 = s_data._sp - KWARGC*2;
|
||||
PyObject** p0 = p1 - ARGC - 2;
|
||||
@ -1258,97 +1317,40 @@ inline PyObject* VM::vectorcall(int ARGC, int KWARGC, bool op_call){
|
||||
}
|
||||
|
||||
ArgsView args(p1 - ARGC - int(method_call), p1);
|
||||
ArgsView kwargs(p1, s_data._sp);
|
||||
|
||||
static THREAD_LOCAL PyObject* buffer[PK_MAX_CO_VARNAMES];
|
||||
|
||||
if(is_non_tagged_type(callable, tp_native_func)){
|
||||
const auto& f = PK_OBJ_GET(NativeFunc, callable);
|
||||
if(KWARGC != 0) TypeError("native_func does not accept keyword arguments");
|
||||
PyObject* ret = f(this, args);
|
||||
PyObject* ret;
|
||||
if(f.decl != nullptr){
|
||||
int co_nlocals = f.decl->code->varnames.size();
|
||||
_prepare_py_call(buffer, args, kwargs, f.decl);
|
||||
// copy buffer back to stack
|
||||
s_data.reset(args.begin());
|
||||
for(int j=0; j<co_nlocals; j++) PUSH(buffer[j]);
|
||||
ret = f.call(vm, ArgsView(s_data._sp - co_nlocals, s_data._sp));
|
||||
}else{
|
||||
if(KWARGC != 0) TypeError("old-style native_func does not accept keyword arguments");
|
||||
f.check_size(this, args);
|
||||
ret = f.call(this, args);
|
||||
}
|
||||
s_data.reset(p0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ArgsView kwargs(p1, s_data._sp);
|
||||
|
||||
if(false){ // native_func_ex
|
||||
|
||||
}
|
||||
|
||||
if(is_non_tagged_type(callable, tp_function)){
|
||||
/*****************_py_call*****************/
|
||||
// callable must be a `function` object
|
||||
if(s_data.is_overflow()) StackOverflowError();
|
||||
|
||||
const Function& fn = CAST(Function&, callable);
|
||||
|
||||
const Function& fn = PK_OBJ_GET(Function, callable);
|
||||
const FuncDecl_& decl = fn.decl;
|
||||
int decl_argc = decl->args.size();
|
||||
const CodeObject* co = fn.decl->code.get();
|
||||
const CodeObject* co = decl->code.get();
|
||||
int co_nlocals = co->varnames.size();
|
||||
|
||||
if(args.size() < decl_argc){
|
||||
vm->TypeError(fmt(
|
||||
"expected ", decl_argc, " positional arguments, got ", args.size(),
|
||||
" (", co->name, ')'
|
||||
));
|
||||
}
|
||||
|
||||
// if this function is simple, a.k.a, no kwargs and no *args and not a generator
|
||||
// we can use a fast path to avoid using buffer copy
|
||||
if(fn.is_simple){
|
||||
if(args.size() > decl_argc) TypeError("too many positional arguments");
|
||||
int spaces = co_nlocals - decl_argc;
|
||||
for(int j=0; j<spaces; j++) PUSH(PY_NULL);
|
||||
callstack.emplace(&s_data, p0, co, fn._module, callable, FastLocals(co, args.begin()));
|
||||
if(op_call) return PY_OP_CALL;
|
||||
return _run_top_frame();
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
static THREAD_LOCAL PyObject* buffer[PK_MAX_CO_VARNAMES];
|
||||
|
||||
// prepare args
|
||||
for(int index: decl->args) buffer[index] = args[i++];
|
||||
// set extra varnames to nullptr
|
||||
for(int j=i; j<co_nlocals; j++) buffer[j] = PY_NULL;
|
||||
// prepare kwdefaults
|
||||
for(auto& kv: decl->kwargs) buffer[kv.key] = kv.value;
|
||||
|
||||
// handle *args
|
||||
if(decl->starred_arg != -1){
|
||||
ArgsView vargs(args.begin() + i, args.end());
|
||||
buffer[decl->starred_arg] = VAR(vargs.to_tuple());
|
||||
i += vargs.size();
|
||||
}else{
|
||||
// kwdefaults override
|
||||
for(auto& kv: decl->kwargs){
|
||||
if(i >= args.size()) break;
|
||||
buffer[kv.key] = args[i++];
|
||||
}
|
||||
if(i < args.size()) TypeError(fmt("too many arguments", " (", decl->code->name, ')'));
|
||||
}
|
||||
|
||||
PyObject* vkwargs;
|
||||
if(decl->starred_kwarg != -1){
|
||||
vkwargs = VAR(Dict(this));
|
||||
buffer[decl->starred_kwarg] = vkwargs;
|
||||
}else{
|
||||
vkwargs = nullptr;
|
||||
}
|
||||
|
||||
for(int j=0; j<kwargs.size(); j+=2){
|
||||
StrName key(CAST(int, kwargs[j]));
|
||||
int index = co->varnames_inv.try_get(key);
|
||||
if(index < 0){
|
||||
if(vkwargs == nullptr){
|
||||
TypeError(fmt(key.escape(), " is an invalid keyword argument for ", co->name, "()"));
|
||||
}else{
|
||||
Dict& dict = _CAST(Dict&, vkwargs);
|
||||
dict.set(VAR(key.sv()), kwargs[j+1]);
|
||||
}
|
||||
}else{
|
||||
buffer[index] = kwargs[j+1];
|
||||
}
|
||||
}
|
||||
_prepare_py_call(buffer, args, kwargs, decl);
|
||||
|
||||
if(co->is_generator){
|
||||
s_data.reset(p0);
|
||||
|
Loading…
x
Reference in New Issue
Block a user