mirror of
https://github.com/pocketpy/pocketpy
synced 2025-10-20 19:40:18 +00:00
impl kwargs
This commit is contained in:
parent
88e1a56150
commit
16f46dec82
@ -133,11 +133,15 @@ public:
|
|||||||
|
|
||||||
uint64_t id;
|
uint64_t id;
|
||||||
|
|
||||||
|
inline PyVarDict copy_f_locals(){
|
||||||
|
return f_locals;
|
||||||
|
}
|
||||||
|
|
||||||
inline PyVarDict& f_globals(){
|
inline PyVarDict& f_globals(){
|
||||||
return _module->attribs;
|
return _module->attribs;
|
||||||
}
|
}
|
||||||
|
|
||||||
Frame(const CodeObject* code, PyVar _module, const PyVarDict& locals)
|
Frame(const CodeObject* code, PyVar _module, PyVarDict&& locals)
|
||||||
: code(code), _module(_module), f_locals(locals) {
|
: code(code), _module(_module), f_locals(locals) {
|
||||||
|
|
||||||
static uint64_t frame_id = 1;
|
static uint64_t frame_id = 1;
|
||||||
|
@ -276,10 +276,16 @@ public:
|
|||||||
parser->setNextToken(TK("@eof"));
|
parser->setNextToken(TK("@eof"));
|
||||||
}
|
}
|
||||||
|
|
||||||
_TokenType peek() {
|
inline _TokenType peek() {
|
||||||
return parser->current.type;
|
return parser->current.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// not sure this will work
|
||||||
|
_TokenType peekNext() {
|
||||||
|
if(parser->nexts.empty()) return TK("@eof");
|
||||||
|
return parser->nexts.front().type;
|
||||||
|
}
|
||||||
|
|
||||||
bool match(_TokenType expected) {
|
bool match(_TokenType expected) {
|
||||||
if (peek() != expected) return false;
|
if (peek() != expected) return false;
|
||||||
lexToken();
|
lexToken();
|
||||||
@ -545,15 +551,26 @@ __LISTCOMP:
|
|||||||
|
|
||||||
void exprCall() {
|
void exprCall() {
|
||||||
int ARGC = 0;
|
int ARGC = 0;
|
||||||
|
int KWARGC = 0;
|
||||||
do {
|
do {
|
||||||
matchNewLines(mode()==SINGLE_MODE);
|
matchNewLines(mode()==SINGLE_MODE);
|
||||||
if (peek() == TK(")")) break;
|
if (peek() == TK(")")) break;
|
||||||
|
if(peek() == TK("@id") && peekNext() == TK("=")) {
|
||||||
|
consume(TK("@id"));
|
||||||
|
const _Str& key = parser->previous.str();
|
||||||
|
emitCode(OP_LOAD_CONST, getCode()->addConst(vm->PyStr(key)));
|
||||||
|
consume(TK("="));
|
||||||
|
EXPR();
|
||||||
|
KWARGC++;
|
||||||
|
} else{
|
||||||
|
if(KWARGC > 0) syntaxError("positional argument follows keyword argument");
|
||||||
EXPR();
|
EXPR();
|
||||||
ARGC++;
|
ARGC++;
|
||||||
|
}
|
||||||
matchNewLines(mode()==SINGLE_MODE);
|
matchNewLines(mode()==SINGLE_MODE);
|
||||||
} while (match(TK(",")));
|
} while (match(TK(",")));
|
||||||
consume(TK(")"));
|
consume(TK(")"));
|
||||||
emitCode(OP_CALL, ARGC);
|
emitCode(OP_CALL, (KWARGC << 16) | ARGC);
|
||||||
}
|
}
|
||||||
|
|
||||||
void exprName() {
|
void exprName() {
|
||||||
|
@ -23,7 +23,9 @@ struct SourceMetadata {
|
|||||||
|
|
||||||
_Str getLine(int lineno) const {
|
_Str getLine(int lineno) const {
|
||||||
if(lineno == -1) return "<?>";
|
if(lineno == -1) return "<?>";
|
||||||
const char* _start = lineStarts.at(lineno-1);
|
lineno -= 1;
|
||||||
|
if(lineno < 0) lineno = 0;
|
||||||
|
const char* _start = lineStarts.at(lineno);
|
||||||
const char* i = _start;
|
const char* i = _start;
|
||||||
while(*i != '\n' && *i != '\0') i++;
|
while(*i != '\n' && *i != '\0') i++;
|
||||||
return _Str(_start, i-_start);
|
return _Str(_start, i-_start);
|
||||||
|
@ -3,8 +3,8 @@
|
|||||||
|
|
||||||
#include "pocketpy.h"
|
#include "pocketpy.h"
|
||||||
|
|
||||||
#define PK_DEBUG_TIME
|
//#define PK_DEBUG_TIME
|
||||||
//#define PK_DEBUG_THREADED
|
#define PK_DEBUG_THREADED
|
||||||
|
|
||||||
struct Timer{
|
struct Timer{
|
||||||
const char* title;
|
const char* title;
|
||||||
@ -46,6 +46,7 @@ void _tvm_dispatch(ThreadedVM* vm){
|
|||||||
while(pkpy_tvm_get_state(vm) != THREAD_FINISHED){
|
while(pkpy_tvm_get_state(vm) != THREAD_FINISHED){
|
||||||
if(pkpy_tvm_get_state(vm) == THREAD_SUSPENDED){
|
if(pkpy_tvm_get_state(vm) == THREAD_SUSPENDED){
|
||||||
char* obj = pkpy_tvm_read_jsonrpc_request(vm);
|
char* obj = pkpy_tvm_read_jsonrpc_request(vm);
|
||||||
|
// this is not safe, but it's ok for demo
|
||||||
bool is_input_call = std::string_view(obj).find("\"input\"") != std::string::npos;
|
bool is_input_call = std::string_view(obj).find("\"input\"") != std::string::npos;
|
||||||
if(is_input_call){
|
if(is_input_call){
|
||||||
std::string line;
|
std::string line;
|
||||||
|
@ -56,7 +56,7 @@ void __initializeBuiltinFunctions(VM* _vm) {
|
|||||||
vm->__checkArgSize(args, 1);
|
vm->__checkArgSize(args, 1);
|
||||||
const _Str& expr = vm->PyStr_AS_C(args[0]);
|
const _Str& expr = vm->PyStr_AS_C(args[0]);
|
||||||
_Code code = compile(vm, expr.c_str(), "<eval>", EVAL_MODE, false);
|
_Code code = compile(vm, expr.c_str(), "<eval>", EVAL_MODE, false);
|
||||||
return vm->_exec(code, vm->topFrame()->_module, vm->topFrame()->f_locals);
|
return vm->_exec(code, vm->topFrame()->_module, vm->topFrame()->copy_f_locals());
|
||||||
});
|
});
|
||||||
|
|
||||||
_vm->bindBuiltinFunc("isinstance", [](VM* vm, const pkpy::ArgList& args) {
|
_vm->bindBuiltinFunc("isinstance", [](VM* vm, const pkpy::ArgList& args) {
|
||||||
@ -91,9 +91,9 @@ void __initializeBuiltinFunctions(VM* _vm) {
|
|||||||
_vm->bindBuiltinFunc("globals", [](VM* vm, const pkpy::ArgList& args) {
|
_vm->bindBuiltinFunc("globals", [](VM* vm, const pkpy::ArgList& args) {
|
||||||
vm->__checkArgSize(args, 0);
|
vm->__checkArgSize(args, 0);
|
||||||
const auto& d = vm->topFrame()->f_globals();
|
const auto& d = vm->topFrame()->f_globals();
|
||||||
PyVar obj = vm->call(vm->builtins->attribs["dict"], {});
|
PyVar obj = vm->call(vm->builtins->attribs["dict"]);
|
||||||
for (const auto& [k, v] : d) {
|
for (const auto& [k, v] : d) {
|
||||||
vm->call(obj, __setitem__, {vm->PyStr(k), v});
|
vm->call(obj, __setitem__, pkpy::twoArgs(vm->PyStr(k), v));
|
||||||
}
|
}
|
||||||
return obj;
|
return obj;
|
||||||
});
|
});
|
||||||
@ -101,9 +101,9 @@ void __initializeBuiltinFunctions(VM* _vm) {
|
|||||||
_vm->bindBuiltinFunc("locals", [](VM* vm, const pkpy::ArgList& args) {
|
_vm->bindBuiltinFunc("locals", [](VM* vm, const pkpy::ArgList& args) {
|
||||||
vm->__checkArgSize(args, 0);
|
vm->__checkArgSize(args, 0);
|
||||||
const auto& d = vm->topFrame()->f_locals;
|
const auto& d = vm->topFrame()->f_locals;
|
||||||
PyVar obj = vm->call(vm->builtins->attribs["dict"], {});
|
PyVar obj = vm->call(vm->builtins->attribs["dict"]);
|
||||||
for (const auto& [k, v] : d) {
|
for (const auto& [k, v] : d) {
|
||||||
vm->call(obj, __setitem__, {vm->PyStr(k), v});
|
vm->call(obj, __setitem__, pkpy::twoArgs(vm->PyStr(k), v));
|
||||||
}
|
}
|
||||||
return obj;
|
return obj;
|
||||||
});
|
});
|
||||||
@ -642,7 +642,7 @@ void __addModuleJson(VM* vm){
|
|||||||
vm->__checkArgSize(args, 1);
|
vm->__checkArgSize(args, 1);
|
||||||
const _Str& expr = vm->PyStr_AS_C(args[0]);
|
const _Str& expr = vm->PyStr_AS_C(args[0]);
|
||||||
_Code code = compile(vm, expr.c_str(), "<json>", JSON_MODE, false);
|
_Code code = compile(vm, expr.c_str(), "<json>", JSON_MODE, false);
|
||||||
return vm->_exec(code, vm->topFrame()->_module, vm->topFrame()->f_locals);
|
return vm->_exec(code, vm->topFrame()->_module, vm->topFrame()->copy_f_locals());
|
||||||
});
|
});
|
||||||
|
|
||||||
vm->bindFunc(mod, "dumps", [](VM* vm, const pkpy::ArgList& args) {
|
vm->bindFunc(mod, "dumps", [](VM* vm, const pkpy::ArgList& args) {
|
||||||
|
@ -58,7 +58,7 @@ public:
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
PyVarDict() : emhash8::HashMap<_Str, PyVar>() {}
|
using emhash8::HashMap<_Str, PyVar>::HashMap;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -128,13 +128,6 @@ namespace pkpy {
|
|||||||
other.clear();
|
other.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
// deprecated, this is very slow, do not use it!!!
|
|
||||||
ArgList(std::initializer_list<PyVar> args){
|
|
||||||
__tryAlloc(args.size());
|
|
||||||
uint8_t i = 0;
|
|
||||||
for(auto& arg: args) this->_args[i++] = arg;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyVar& operator[](uint8_t i){
|
PyVar& operator[](uint8_t i){
|
||||||
__checkIndex(i);
|
__checkIndex(i);
|
||||||
return _args[i];
|
return _args[i];
|
||||||
@ -161,7 +154,7 @@ namespace pkpy {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t size() const {
|
inline uint8_t size() const {
|
||||||
return _size;
|
return _size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,4 +179,35 @@ namespace pkpy {
|
|||||||
__tryRelease();
|
__tryRelease();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const ArgList& noArg(){
|
||||||
|
static ArgList ret(0);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArgList oneArg(PyVar&& a) {
|
||||||
|
ArgList ret(1);
|
||||||
|
ret[0] = std::move(a);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArgList oneArg(const PyVar& a) {
|
||||||
|
ArgList ret(1);
|
||||||
|
ret[0] = a;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArgList twoArgs(PyVar&& a, PyVar&& b) {
|
||||||
|
ArgList ret(2);
|
||||||
|
ret[0] = std::move(a);
|
||||||
|
ret[1] = std::move(b);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
ArgList twoArgs(const PyVar& a, const PyVar& b) {
|
||||||
|
ArgList ret(2);
|
||||||
|
ret[0] = a;
|
||||||
|
ret[1] = b;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
144
src/vm.h
144
src/vm.h
@ -77,7 +77,7 @@ protected:
|
|||||||
} break;
|
} break;
|
||||||
case OP_BUILD_INDEX_PTR: {
|
case OP_BUILD_INDEX_PTR: {
|
||||||
PyVar index = frame->popValue(this);
|
PyVar index = frame->popValue(this);
|
||||||
PyVar obj = frame->popValue(this);
|
VarRef obj = frame->popValue(this);
|
||||||
frame->push(PyPointer(IndexPointer(obj, index)));
|
frame->push(PyPointer(IndexPointer(obj, index)));
|
||||||
} break;
|
} break;
|
||||||
case OP_STORE_PTR: {
|
case OP_STORE_PTR: {
|
||||||
@ -182,8 +182,7 @@ protected:
|
|||||||
case OP_CONTAINS_OP:
|
case OP_CONTAINS_OP:
|
||||||
{
|
{
|
||||||
PyVar rhs = frame->popValue(this);
|
PyVar rhs = frame->popValue(this);
|
||||||
PyVar lhs = frame->popValue(this);
|
bool ret_c = PyBool_AS_C(call(rhs, __contains__, pkpy::oneArg(frame->popValue(this))));
|
||||||
bool ret_c = PyBool_AS_C(call(rhs, __contains__, {std::move(lhs)}));
|
|
||||||
if(byte.arg == 1) ret_c = !ret_c;
|
if(byte.arg == 1) ret_c = !ret_c;
|
||||||
frame->push(PyBool(ret_c));
|
frame->push(PyBool(ret_c));
|
||||||
} break;
|
} break;
|
||||||
@ -241,18 +240,22 @@ protected:
|
|||||||
case OP_BUILD_MAP:
|
case OP_BUILD_MAP:
|
||||||
{
|
{
|
||||||
pkpy::ArgList items = frame->popNValuesReversed(this, byte.arg*2);
|
pkpy::ArgList items = frame->popNValuesReversed(this, byte.arg*2);
|
||||||
PyVar obj = call(builtins->attribs["dict"], {});
|
PyVar obj = call(builtins->attribs["dict"]);
|
||||||
for(int i=0; i<items.size(); i+=2){
|
for(int i=0; i<items.size(); i+=2){
|
||||||
call(obj, __setitem__, {items[i], items[i+1]});
|
call(obj, __setitem__, pkpy::twoArgs(items[i], items[i+1]));
|
||||||
}
|
}
|
||||||
frame->push(obj);
|
frame->push(obj);
|
||||||
} break;
|
} break;
|
||||||
case OP_DUP_TOP: frame->push(frame->topValue(this)); break;
|
case OP_DUP_TOP: frame->push(frame->topValue(this)); break;
|
||||||
case OP_CALL:
|
case OP_CALL:
|
||||||
{
|
{
|
||||||
pkpy::ArgList args = frame->popNValuesReversed(this, byte.arg);
|
int ARGC = byte.arg & 0xFFFF;
|
||||||
|
int KWARGC = (byte.arg >> 16) & 0xFFFF;
|
||||||
|
pkpy::ArgList kwargs(0);
|
||||||
|
if(KWARGC > 0) kwargs = frame->popNValuesReversed(this, KWARGC*2);
|
||||||
|
pkpy::ArgList args = frame->popNValuesReversed(this, ARGC);
|
||||||
PyVar callable = frame->popValue(this);
|
PyVar callable = frame->popValue(this);
|
||||||
PyVar ret = call(std::move(callable), std::move(args), true);
|
PyVar ret = call(callable, std::move(args), kwargs, true);
|
||||||
if(ret == __py2py_call_signal) return ret;
|
if(ret == __py2py_call_signal) return ret;
|
||||||
frame->push(std::move(ret));
|
frame->push(std::move(ret));
|
||||||
} break;
|
} break;
|
||||||
@ -272,7 +275,7 @@ protected:
|
|||||||
PyVar obj = frame->popValue(this);
|
PyVar obj = frame->popValue(this);
|
||||||
PyVarOrNull iter_fn = getAttr(obj, __iter__, false);
|
PyVarOrNull iter_fn = getAttr(obj, __iter__, false);
|
||||||
if(iter_fn != nullptr){
|
if(iter_fn != nullptr){
|
||||||
PyVar tmp = call(iter_fn, {obj});
|
PyVar tmp = call(iter_fn, pkpy::oneArg(obj));
|
||||||
VarRef var = frame->__pop();
|
VarRef var = frame->__pop();
|
||||||
__checkType(var, _tp_pointer);
|
__checkType(var, _tp_pointer);
|
||||||
PyIter_AS_C(tmp)->var = var;
|
PyIter_AS_C(tmp)->var = var;
|
||||||
@ -333,18 +336,8 @@ protected:
|
|||||||
frame->push(it->second);
|
frame->push(it->second);
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case OP_WITH_ENTER:
|
case OP_WITH_ENTER: call(frame->popValue(this), "__enter__"_c); break;
|
||||||
{
|
case OP_WITH_EXIT: call(frame->popValue(this), "__exit__"_c); break;
|
||||||
PyVar obj = frame->popValue(this);
|
|
||||||
PyVar enter_fn = getAttr(obj, "__enter__"_c);
|
|
||||||
call(enter_fn, {});
|
|
||||||
} break;
|
|
||||||
case OP_WITH_EXIT:
|
|
||||||
{
|
|
||||||
PyVar obj = frame->popValue(this);
|
|
||||||
PyVar exit_fn = getAttr(obj, "__exit__"_c);
|
|
||||||
call(exit_fn, {});
|
|
||||||
} break;
|
|
||||||
default:
|
default:
|
||||||
systemError(_Str("opcode ") + OP_NAMES[byte.op] + " is not implemented");
|
systemError(_Str("opcode ") + OP_NAMES[byte.op] + " is not implemented");
|
||||||
break;
|
break;
|
||||||
@ -404,7 +397,7 @@ public:
|
|||||||
|
|
||||||
PyVar asStr(const PyVar& obj){
|
PyVar asStr(const PyVar& obj){
|
||||||
PyVarOrNull str_fn = getAttr(obj, __str__, false);
|
PyVarOrNull str_fn = getAttr(obj, __str__, false);
|
||||||
if(str_fn != nullptr) return call(str_fn, {});
|
if(str_fn != nullptr) return call(str_fn);
|
||||||
return asRepr(obj);
|
return asRepr(obj);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -424,11 +417,11 @@ public:
|
|||||||
|
|
||||||
PyVar asRepr(const PyVar& obj){
|
PyVar asRepr(const PyVar& obj){
|
||||||
if(obj->isType(_tp_type)) return PyStr("<class '" + UNION_GET(_Str, obj->attribs[__name__]) + "'>");
|
if(obj->isType(_tp_type)) return PyStr("<class '" + UNION_GET(_Str, obj->attribs[__name__]) + "'>");
|
||||||
return call(obj, __repr__, {});
|
return call(obj, __repr__);
|
||||||
}
|
}
|
||||||
|
|
||||||
PyVar asJson(const PyVar& obj){
|
PyVar asJson(const PyVar& obj){
|
||||||
return call(obj, __json__, {});
|
return call(obj, __json__);
|
||||||
}
|
}
|
||||||
|
|
||||||
const PyVar& asBool(const PyVar& obj){
|
const PyVar& asBool(const PyVar& obj){
|
||||||
@ -438,7 +431,7 @@ public:
|
|||||||
if(obj->_type == _tp_float) return PyBool(PyFloat_AS_C(obj) != 0.0);
|
if(obj->_type == _tp_float) return PyBool(PyFloat_AS_C(obj) != 0.0);
|
||||||
PyVarOrNull len_fn = getAttr(obj, __len__, false);
|
PyVarOrNull len_fn = getAttr(obj, __len__, false);
|
||||||
if(len_fn != nullptr){
|
if(len_fn != nullptr){
|
||||||
PyVar ret = call(std::move(len_fn), {});
|
PyVar ret = call(len_fn);
|
||||||
return PyBool(PyInt_AS_C(ret) > 0);
|
return PyBool(PyInt_AS_C(ret) > 0);
|
||||||
}
|
}
|
||||||
return True;
|
return True;
|
||||||
@ -449,25 +442,39 @@ public:
|
|||||||
PyObject* cls = obj->_type.get();
|
PyObject* cls = obj->_type.get();
|
||||||
while(cls != None.get()) {
|
while(cls != None.get()) {
|
||||||
auto it = cls->attribs.find(name);
|
auto it = cls->attribs.find(name);
|
||||||
if(it != cls->attribs.end()){
|
if(it != cls->attribs.end()) return call(it->second, std::move(args));
|
||||||
return call(it->second, args);
|
|
||||||
}
|
|
||||||
cls = cls->attribs[__base__].get();
|
cls = cls->attribs[__base__].get();
|
||||||
}
|
}
|
||||||
attributeError(obj, name);
|
attributeError(obj, name);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyVar call(const PyVar& _callable, pkpy::ArgList args, bool opCall=false){
|
inline PyVar call(const PyVar& _callable){
|
||||||
|
return call(_callable, pkpy::noArg(), pkpy::noArg(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline PyVar call(const PyVar& _callable, pkpy::ArgList args){
|
||||||
|
return call(_callable, args, pkpy::noArg(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline PyVar call(const PyVar& obj, const _Str& func, pkpy::ArgList args){
|
||||||
|
return call(getAttr(obj, func), args, pkpy::noArg(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline PyVar call(const PyVar& obj, const _Str& func){
|
||||||
|
return call(getAttr(obj, func), pkpy::noArg(), pkpy::noArg(), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
PyVar call(const PyVar& _callable, pkpy::ArgList args, const pkpy::ArgList& kwargs, bool opCall){
|
||||||
if(_callable->isType(_tp_type)){
|
if(_callable->isType(_tp_type)){
|
||||||
auto it = _callable->attribs.find(__new__);
|
auto it = _callable->attribs.find(__new__);
|
||||||
PyVar obj;
|
PyVar obj;
|
||||||
if(it != _callable->attribs.end()){
|
if(it != _callable->attribs.end()){
|
||||||
obj = call(it->second, args);
|
obj = call(it->second, args, kwargs, false);
|
||||||
}else{
|
}else{
|
||||||
obj = newObject(_callable, (_Int)-1);
|
obj = newObject(_callable, (_Int)-1);
|
||||||
PyVarOrNull init_fn = getAttr(obj, __init__, false);
|
PyVarOrNull init_fn = getAttr(obj, __init__, false);
|
||||||
if (init_fn != nullptr) call(init_fn, args);
|
if (init_fn != nullptr) call(init_fn, args, kwargs, false);
|
||||||
}
|
}
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
@ -485,6 +492,7 @@ public:
|
|||||||
|
|
||||||
if((*callable)->isType(_tp_native_function)){
|
if((*callable)->isType(_tp_native_function)){
|
||||||
const auto& f = UNION_GET(_CppFunc, *callable);
|
const auto& f = UNION_GET(_CppFunc, *callable);
|
||||||
|
// _CppFunc do not support kwargs
|
||||||
return f(this, args);
|
return f(this, args);
|
||||||
} else if((*callable)->isType(_tp_function)){
|
} else if((*callable)->isType(_tp_function)){
|
||||||
const _Func& fn = PyFunction_AS_C((*callable));
|
const _Func& fn = PyFunction_AS_C((*callable));
|
||||||
@ -492,47 +500,59 @@ public:
|
|||||||
int i = 0;
|
int i = 0;
|
||||||
for(const auto& name : fn->args){
|
for(const auto& name : fn->args){
|
||||||
if(i < args.size()){
|
if(i < args.size()){
|
||||||
locals[name] = args[i++];
|
locals.emplace(name, args[i++]);
|
||||||
}else{
|
continue;
|
||||||
|
}
|
||||||
typeError("missing positional argument '" + name + "'");
|
typeError("missing positional argument '" + name + "'");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
// handle *args
|
locals.insert(fn->kwArgs.begin(), fn->kwArgs.end());
|
||||||
|
|
||||||
|
std::vector<_Str> positional_overrided_keys;
|
||||||
if(!fn->starredArg.empty()){
|
if(!fn->starredArg.empty()){
|
||||||
|
// handle *args
|
||||||
PyVarList vargs;
|
PyVarList vargs;
|
||||||
while(i < args.size()) vargs.push_back(args[i++]);
|
while(i < args.size()) vargs.push_back(args[i++]);
|
||||||
locals[fn->starredArg] = PyTuple(vargs);
|
locals.emplace(fn->starredArg, PyTuple(std::move(vargs)));
|
||||||
}
|
|
||||||
// handle keyword arguments
|
|
||||||
for(const _Str& name : fn->kwArgsOrder){
|
|
||||||
if(i < args.size()) {
|
|
||||||
locals[name] = args[i++];
|
|
||||||
}else{
|
}else{
|
||||||
locals[name] = fn->kwArgs[name];
|
for(const auto& key : fn->kwArgsOrder){
|
||||||
|
if(i < args.size()){
|
||||||
|
locals[key] = args[i++];
|
||||||
|
positional_overrided_keys.push_back(key);
|
||||||
|
}else{
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if(i < args.size()) typeError("too many arguments");
|
||||||
|
}
|
||||||
|
|
||||||
if(i < args.size()) typeError("too many arguments");
|
for(int i=0; i<kwargs.size(); i+=2){
|
||||||
|
const _Str& key = PyStr_AS_C(kwargs[i]);
|
||||||
|
if(fn->kwArgs.find(key) == fn->kwArgs.end()){
|
||||||
|
typeError(key.__escape(true) + " is an invalid keyword argument for " + fn->name + "()");
|
||||||
|
}
|
||||||
|
const PyVar& val = kwargs[i+1];
|
||||||
|
if(!positional_overrided_keys.empty()){
|
||||||
|
auto it = std::find(positional_overrided_keys.begin(), positional_overrided_keys.end(), key);
|
||||||
|
if(it != positional_overrided_keys.end()){
|
||||||
|
typeError("multiple values for argument '" + key + "'");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
locals[key] = val;
|
||||||
|
}
|
||||||
|
|
||||||
auto it_m = (*callable)->attribs.find(__module__);
|
auto it_m = (*callable)->attribs.find(__module__);
|
||||||
PyVar _module = it_m != (*callable)->attribs.end() ? it_m->second : topFrame()->_module;
|
PyVar _module = it_m != (*callable)->attribs.end() ? it_m->second : topFrame()->_module;
|
||||||
if(opCall){
|
if(opCall){
|
||||||
__pushNewFrame(fn->code, _module, locals);
|
__pushNewFrame(fn->code, _module, std::move(locals));
|
||||||
return __py2py_call_signal;
|
return __py2py_call_signal;
|
||||||
}
|
}
|
||||||
return _exec(fn->code, _module, locals);
|
return _exec(fn->code, _module, std::move(locals));
|
||||||
}
|
}
|
||||||
typeError("'" + UNION_TP_NAME(*callable) + "' object is not callable");
|
typeError("'" + UNION_TP_NAME(*callable) + "' object is not callable");
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline PyVar call(const PyVar& obj, const _Str& func, const pkpy::ArgList& args){
|
|
||||||
return call(getAttr(obj, func), args);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline PyVar call(const PyVar& obj, const _Str& func, pkpy::ArgList&& args){
|
|
||||||
return call(getAttr(obj, func), args);
|
|
||||||
}
|
|
||||||
|
|
||||||
// repl mode is only for setting `frame->id` to 0
|
// repl mode is only for setting `frame->id` to 0
|
||||||
virtual PyVarOrNull exec(const _Code& code, PyVar _module=nullptr){
|
virtual PyVarOrNull exec(const _Code& code, PyVar _module=nullptr){
|
||||||
@ -552,18 +572,18 @@ public:
|
|||||||
exec(code);
|
exec(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
Frame* __pushNewFrame(const _Code& code, PyVar _module, const PyVarDict& locals){
|
Frame* __pushNewFrame(const _Code& code, PyVar _module, PyVarDict&& locals){
|
||||||
if(code == nullptr) UNREACHABLE();
|
if(code == nullptr) UNREACHABLE();
|
||||||
if(callstack.size() > maxRecursionDepth){
|
if(callstack.size() > maxRecursionDepth){
|
||||||
throw RuntimeError("RecursionError", "maximum recursion depth exceeded", _cleanErrorAndGetSnapshots());
|
throw RuntimeError("RecursionError", "maximum recursion depth exceeded", _cleanErrorAndGetSnapshots());
|
||||||
}
|
}
|
||||||
Frame* frame = new Frame(code.get(), _module, locals);
|
Frame* frame = new Frame(code.get(), _module, std::move(locals));
|
||||||
callstack.emplace_back(pkpy::unique_ptr<Frame>(frame));
|
callstack.emplace_back(pkpy::unique_ptr<Frame>(frame));
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
PyVar _exec(const _Code& code, PyVar _module, const PyVarDict& locals){
|
PyVar _exec(const _Code& code, PyVar _module, PyVarDict&& locals){
|
||||||
Frame* frame = __pushNewFrame(code, _module, locals);
|
Frame* frame = __pushNewFrame(code, _module, std::move(locals));
|
||||||
if(code->mode() == SINGLE_MODE) frame->id = 0;
|
if(code->mode() == SINGLE_MODE) frame->id = 0;
|
||||||
Frame* frameBase = frame;
|
Frame* frameBase = frame;
|
||||||
PyVar ret = nullptr;
|
PyVar ret = nullptr;
|
||||||
@ -710,10 +730,10 @@ public:
|
|||||||
|
|
||||||
bool isInstance(PyVar obj, PyVar type){
|
bool isInstance(PyVar obj, PyVar type){
|
||||||
__checkType(type, _tp_type);
|
__checkType(type, _tp_type);
|
||||||
PyVar t = obj->_type;
|
PyObject* t = obj->_type.get();
|
||||||
while (t != None){
|
while (t != None.get()){
|
||||||
if (t == type) return true;
|
if (t == type.get()) return true;
|
||||||
t = t->attribs[__base__];
|
t = t->attribs[__base__].get();
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -1008,15 +1028,15 @@ void AttrPointer::del(VM* vm, Frame* frame) const{
|
|||||||
}
|
}
|
||||||
|
|
||||||
PyVar IndexPointer::get(VM* vm, Frame* frame) const{
|
PyVar IndexPointer::get(VM* vm, Frame* frame) const{
|
||||||
return vm->call(obj, __getitem__, {index});
|
return vm->call(obj, __getitem__, pkpy::oneArg(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
void IndexPointer::set(VM* vm, Frame* frame, PyVar val) const{
|
void IndexPointer::set(VM* vm, Frame* frame, PyVar val) const{
|
||||||
vm->call(obj, __setitem__, {index, val});
|
vm->call(obj, __setitem__, pkpy::twoArgs(index, val));
|
||||||
}
|
}
|
||||||
|
|
||||||
void IndexPointer::del(VM* vm, Frame* frame) const{
|
void IndexPointer::del(VM* vm, Frame* frame) const{
|
||||||
vm->call(obj, __delitem__, {index});
|
vm->call(obj, __delitem__, pkpy::oneArg(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
PyVar CompoundPointer::get(VM* vm, Frame* frame) const{
|
PyVar CompoundPointer::get(VM* vm, Frame* frame) const{
|
||||||
|
@ -17,3 +17,24 @@ def fact(n):
|
|||||||
return n * fact(n - 1)
|
return n * fact(n - 1)
|
||||||
assert fact(5)==120
|
assert fact(5)==120
|
||||||
|
|
||||||
|
def f(a=1, b=-1):
|
||||||
|
return a + b
|
||||||
|
|
||||||
|
assert f() == 0
|
||||||
|
assert f(1, 2) == 3
|
||||||
|
assert f(-5) == -6
|
||||||
|
assert f(b=5) == 6
|
||||||
|
assert f(a=5) == 4
|
||||||
|
assert f(b=5, a=5) == 10
|
||||||
|
|
||||||
|
def f(a, b, *c, d=2, e=5):
|
||||||
|
return a + b + d + e + sum(c)
|
||||||
|
|
||||||
|
assert f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) == 62
|
||||||
|
assert f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, d=1, e=2) == 58
|
||||||
|
assert f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, e=1, d=2) == 58
|
||||||
|
assert f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, d=1) == 61
|
||||||
|
assert f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, e=1) == 58
|
||||||
|
assert f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20) == 217
|
||||||
|
assert f(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, d=1, e=2) == 213
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user