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;
|
using namespace pkpy;
|
||||||
|
|
||||||
|
typedef int (*LuaStyleFuncC)(VM*);
|
||||||
|
|
||||||
struct LuaStack: public ValueStackImpl<32>{
|
struct LuaStack: public ValueStackImpl<32>{
|
||||||
PyObject*& at(int i) {
|
PyObject*& at(int i) {
|
||||||
if(i < 0 || i >= size()){
|
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) {
|
PyObject* c_function_wrapper(VM* vm, ArgsView args) {
|
||||||
LuaStyleFuncC f;
|
LuaStyleFuncC f = lambda_get_userdata<LuaStyleFuncC>(args.begin());
|
||||||
if(args[-1] != PY_NULL){
|
|
||||||
f = _py_cast<NativeFunc&>(vm, args[-1])._lua_f;
|
|
||||||
} else {
|
|
||||||
f = _py_cast<NativeFunc&>(vm, args[-2])._lua_f;
|
|
||||||
}
|
|
||||||
CVM* cvm = (CVM*) vm;
|
CVM* cvm = (CVM*) vm;
|
||||||
|
|
||||||
//setup c stack
|
//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) {
|
bool pkpy_push_function(pkpy_vm* vm_handle, pkpy_function f, int argc) {
|
||||||
CVM* vm = (CVM*) vm_handle;
|
CVM* vm = (CVM*) vm_handle;
|
||||||
NativeFunc nf = NativeFunc(c_function_wrapper, argc, false);
|
NativeFunc nf = NativeFunc(c_function_wrapper, argc, false);
|
||||||
nf._lua_f = (LuaStyleFuncC) f;
|
nf.set_userdata(f);
|
||||||
ERRHANDLER_OPEN
|
ERRHANDLER_OPEN
|
||||||
vm->c_data->safe_push(py_var(vm, nf));
|
vm->c_data->safe_push(py_var(vm, nf));
|
||||||
ERRHANDLER_CLOSE
|
ERRHANDLER_CLOSE
|
||||||
|
@ -98,14 +98,13 @@ __NEXT_STEP:;
|
|||||||
TARGET(LOAD_ELLIPSIS) PUSH(Ellipsis); DISPATCH();
|
TARGET(LOAD_ELLIPSIS) PUSH(Ellipsis); DISPATCH();
|
||||||
TARGET(LOAD_FUNCTION) {
|
TARGET(LOAD_FUNCTION) {
|
||||||
FuncDecl_ decl = co->func_decls[byte.arg];
|
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;
|
PyObject* obj;
|
||||||
if(decl->nested){
|
if(decl->nested){
|
||||||
NameDict_ captured = frame->_locals.to_namedict();
|
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);
|
captured->set(decl->code->name, obj);
|
||||||
}else{
|
}else{
|
||||||
obj = VAR(Function({decl, is_simple, frame->_module}));
|
obj = VAR(Function({decl, frame->_module}));
|
||||||
}
|
}
|
||||||
PUSH(obj);
|
PUSH(obj);
|
||||||
} DISPATCH();
|
} DISPATCH();
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
#include <variant>
|
#include <variant>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
#define PK_VERSION "1.0.5"
|
#define PK_VERSION "1.0.7"
|
||||||
|
|
||||||
#include "config.h"
|
#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);
|
typedef PyObject* (*NativeFuncC)(VM*, ArgsView);
|
||||||
#endif
|
#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 {
|
struct NativeFunc {
|
||||||
NativeFuncC f;
|
NativeFuncC f;
|
||||||
int argc;
|
int argc;
|
||||||
|
|
||||||
// this is designed for lua style C bindings
|
FuncDecl_ decl; // if this is not null, use ex call
|
||||||
LuaStyleFuncC _lua_f;
|
|
||||||
|
|
||||||
using UserData = char[32];
|
using UserData = char[32];
|
||||||
UserData _userdata;
|
UserData _userdata;
|
||||||
@ -53,39 +68,22 @@ struct NativeFunc {
|
|||||||
this->f = f;
|
this->f = f;
|
||||||
this->argc = argc;
|
this->argc = argc;
|
||||||
if(argc != -1) this->argc += (int)method;
|
if(argc != -1) this->argc += (int)method;
|
||||||
_lua_f = nullptr;
|
|
||||||
_has_userdata = false;
|
_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{
|
struct Function{
|
||||||
FuncDecl_ decl;
|
FuncDecl_ decl;
|
||||||
bool is_simple;
|
|
||||||
PyObject* _module;
|
PyObject* _module;
|
||||||
NameDict_ _closure;
|
NameDict_ _closure;
|
||||||
};
|
};
|
||||||
|
162
src/vm.h
162
src/vm.h
@ -690,15 +690,16 @@ public:
|
|||||||
PyObject* _py_generator(Frame&& frame, ArgsView buffer);
|
PyObject* _py_generator(Frame&& frame, ArgsView buffer);
|
||||||
// new style binding api
|
// new style binding api
|
||||||
PyObject* bind(PyObject*, const Str&, NativeFuncC);
|
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) {
|
if(args.size() != argc && argc != -1) {
|
||||||
vm->TypeError(fmt("expected ", argc, " arguments, got ", args.size()));
|
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);
|
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){
|
inline PyObject* VM::vectorcall(int ARGC, int KWARGC, bool op_call){
|
||||||
PyObject** p1 = s_data._sp - KWARGC*2;
|
PyObject** p1 = s_data._sp - KWARGC*2;
|
||||||
PyObject** p0 = p1 - ARGC - 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 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)){
|
if(is_non_tagged_type(callable, tp_native_func)){
|
||||||
const auto& f = PK_OBJ_GET(NativeFunc, callable);
|
const auto& f = PK_OBJ_GET(NativeFunc, callable);
|
||||||
if(KWARGC != 0) TypeError("native_func does not accept keyword arguments");
|
PyObject* ret;
|
||||||
PyObject* ret = f(this, args);
|
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);
|
s_data.reset(p0);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
ArgsView kwargs(p1, s_data._sp);
|
|
||||||
|
|
||||||
if(false){ // native_func_ex
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if(is_non_tagged_type(callable, tp_function)){
|
if(is_non_tagged_type(callable, tp_function)){
|
||||||
/*****************_py_call*****************/
|
/*****************_py_call*****************/
|
||||||
// callable must be a `function` object
|
// callable must be a `function` object
|
||||||
if(s_data.is_overflow()) StackOverflowError();
|
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;
|
const FuncDecl_& decl = fn.decl;
|
||||||
int decl_argc = decl->args.size();
|
const CodeObject* co = decl->code.get();
|
||||||
const CodeObject* co = fn.decl->code.get();
|
|
||||||
int co_nlocals = co->varnames.size();
|
int co_nlocals = co->varnames.size();
|
||||||
|
|
||||||
if(args.size() < decl_argc){
|
_prepare_py_call(buffer, args, kwargs, decl);
|
||||||
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];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(co->is_generator){
|
if(co->is_generator){
|
||||||
s_data.reset(p0);
|
s_data.reset(p0);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user