From e9fc527aff4f9fc32adf8f51741fc09ddc406d59 Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Sun, 20 Nov 2022 17:22:24 +0800 Subject: [PATCH] add ArgList up --- scripts/run_tests.py | 2 + src/obj.h | 2 +- src/pocketpy.h | 148 ++++++++++++++++++++++--------------------- src/safestl.h | 104 +++++++++++++++++++++++++++++- src/vm.h | 48 ++++++++------ 5 files changed, 209 insertions(+), 95 deletions(-) diff --git a/scripts/run_tests.py b/scripts/run_tests.py index 2b383ca3..6f2bba61 100644 --- a/scripts/run_tests.py +++ b/scripts/run_tests.py @@ -8,6 +8,8 @@ def test_dir(path): has_error = False for filename in os.listdir(path): if filename.endswith('.py'): + if(filename == '1.py'): + continue filepath = os.path.join(path, filename) code = test_file(filepath) if not code: diff --git a/src/obj.h b/src/obj.h index 7c79c600..a6aa4efd 100644 --- a/src/obj.h +++ b/src/obj.h @@ -18,7 +18,7 @@ class VM; class PkExportedResource {}; typedef std::shared_ptr _Pointer; -typedef PyVar (*_CppFunc)(VM*, PyVarList); +typedef PyVar (*_CppFunc)(VM*, const pkpy::ArgList&); typedef std::shared_ptr _Code; struct Function { diff --git a/src/pocketpy.h b/src/pocketpy.h index 905e8753..29f84e3d 100644 --- a/src/pocketpy.h +++ b/src/pocketpy.h @@ -5,7 +5,7 @@ #include "repl.h" #define BIND_NUM_ARITH_OPT(name, op) \ - _vm->bindMethodMulti({"int","float"}, #name, [](VM* vm, PyVarList args){ \ + _vm->bindMethodMulti({"int","float"}, #name, [](VM* vm, const pkpy::ArgList& args){ \ if(!vm->isIntOrFloat(args[0], args[1])) \ vm->typeError("unsupported operand type(s) for " #op ); \ if(args[0]->isType(vm->_tp_int) && args[1]->isType(vm->_tp_int)){ \ @@ -16,7 +16,7 @@ }); #define BIND_NUM_LOGICAL_OPT(name, op, fallback) \ - _vm->bindMethodMulti({"int","float"}, #name, [](VM* vm, PyVarList args){ \ + _vm->bindMethodMulti({"int","float"}, #name, [](VM* vm, const pkpy::ArgList& args){ \ if(!vm->isIntOrFloat(args[0], args[1])){ \ if constexpr(fallback) return vm->PyBool(args[0] op args[1]); \ vm->typeError("unsupported operand type(s) for " #op ); \ @@ -39,14 +39,16 @@ void __initializeBuiltinFunctions(VM* _vm) { #undef BIND_NUM_ARITH_OPT #undef BIND_NUM_LOGICAL_OPT - _vm->bindBuiltinFunc("print", [](VM* vm, PyVarList args) { + _vm->bindBuiltinFunc("print", [](VM* vm, const pkpy::ArgList& args) { _StrStream ss; - for (auto& arg : args) ss << vm->PyStr_AS_C(vm->asStr(arg)) << " "; + for(int i=0; iPyStr_AS_C(vm->asStr(args[i])) << " "; + } (*vm->_stdout) << ss.str() << '\n'; return vm->None; }); - _vm->bindBuiltinFunc("input", [](VM* vm, PyVarList args) { + _vm->bindBuiltinFunc("input", [](VM* vm, const pkpy::ArgList& args) { vm->__checkArgSize(args, 0); ThreadedVM* tvm = dynamic_cast(vm); if(tvm == nullptr) vm->typeError("input() can only be called in threaded mode"); @@ -54,7 +56,7 @@ void __initializeBuiltinFunctions(VM* _vm) { return vm->PyStr(tvm->readStdin()); }); - _vm->bindBuiltinFunc("eval", [](VM* vm, PyVarList args) { + _vm->bindBuiltinFunc("eval", [](VM* vm, const pkpy::ArgList& args) { vm->__checkArgSize(args, 1); const _Str& expr = vm->PyStr_AS_C(args[0]); _Code code = compile(vm, expr.c_str(), "", EVAL_MODE); @@ -62,36 +64,36 @@ void __initializeBuiltinFunctions(VM* _vm) { return vm->_exec(code, vm->topFrame()->_module, vm->topFrame()->f_locals); }); - _vm->bindBuiltinFunc("isinstance", [](VM* vm, PyVarList args) { + _vm->bindBuiltinFunc("isinstance", [](VM* vm, const pkpy::ArgList& args) { vm->__checkArgSize(args, 2); return vm->PyBool(vm->isInstance(args[0], args[1])); }); - _vm->bindBuiltinFunc("repr", [](VM* vm, PyVarList args) { + _vm->bindBuiltinFunc("repr", [](VM* vm, const pkpy::ArgList& args) { vm->__checkArgSize(args, 1); return vm->asRepr(args[0]); }); - _vm->bindBuiltinFunc("hash", [](VM* vm, PyVarList args) { + _vm->bindBuiltinFunc("hash", [](VM* vm, const pkpy::ArgList& args) { vm->__checkArgSize(args, 1); return vm->PyInt(vm->hash(args[0])); }); - _vm->bindBuiltinFunc("chr", [](VM* vm, PyVarList args) { + _vm->bindBuiltinFunc("chr", [](VM* vm, const pkpy::ArgList& args) { vm->__checkArgSize(args, 1); _Int i = vm->PyInt_AS_C(args[0]); if (i < 0 || i > 128) vm->valueError("chr() arg not in range(128)"); return vm->PyStr(_Str(1, (char)i)); }); - _vm->bindBuiltinFunc("ord", [](VM* vm, PyVarList args) { + _vm->bindBuiltinFunc("ord", [](VM* vm, const pkpy::ArgList& args) { vm->__checkArgSize(args, 1); _Str s = vm->PyStr_AS_C(args[0]); if (s.size() != 1) vm->typeError("ord() expected an ASCII character"); return vm->PyInt((_Int)s[0]); }); - _vm->bindBuiltinFunc("globals", [](VM* vm, PyVarList args) { + _vm->bindBuiltinFunc("globals", [](VM* vm, const pkpy::ArgList& args) { vm->__checkArgSize(args, 0); const auto& d = vm->topFrame()->f_globals(); PyVar obj = vm->call(vm->builtins->attribs["dict"], {}); @@ -101,7 +103,7 @@ void __initializeBuiltinFunctions(VM* _vm) { return obj; }); - _vm->bindBuiltinFunc("locals", [](VM* vm, PyVarList args) { + _vm->bindBuiltinFunc("locals", [](VM* vm, const pkpy::ArgList& args) { vm->__checkArgSize(args, 0); const auto& d = vm->topFrame()->f_locals; PyVar obj = vm->call(vm->builtins->attribs["dict"], {}); @@ -111,25 +113,25 @@ void __initializeBuiltinFunctions(VM* _vm) { return obj; }); - _vm->bindBuiltinFunc("dir", [](VM* vm, PyVarList args) { + _vm->bindBuiltinFunc("dir", [](VM* vm, const pkpy::ArgList& args) { vm->__checkArgSize(args, 1); PyVarList ret; for (auto& [k, _] : args[0]->attribs) ret.push_back(vm->PyStr(k)); return vm->PyList(ret); }); - _vm->bindMethod("object", "__repr__", [](VM* vm, PyVarList args) { + _vm->bindMethod("object", "__repr__", [](VM* vm, const pkpy::ArgList& args) { PyVar _self = args[0]; _Str s = "<" + _self->getTypeName() + " object at " + std::to_string((uintptr_t)_self.get()) + ">"; return vm->PyStr(s); }); - _vm->bindMethod("type", "__new__", [](VM* vm, PyVarList args) { + _vm->bindMethod("type", "__new__", [](VM* vm, const pkpy::ArgList& args) { vm->__checkArgSize(args, 1); return args[0]->_type; }); - _vm->bindMethod("range", "__new__", [](VM* vm, PyVarList args) { + _vm->bindMethod("range", "__new__", [](VM* vm, const pkpy::ArgList& args) { _Range r; switch (args.size()) { case 1: r.stop = vm->PyInt_AS_C(args[0]); break; @@ -140,21 +142,21 @@ void __initializeBuiltinFunctions(VM* _vm) { return vm->PyRange(r); }); - _vm->bindMethod("range", "__iter__", [](VM* vm, PyVarList args) { + _vm->bindMethod("range", "__iter__", [](VM* vm, const pkpy::ArgList& args) { vm->__checkType(args[0], vm->_tp_range); auto iter = std::make_shared(vm, args[0]); return vm->PyIter(iter); }); - _vm->bindMethod("NoneType", "__repr__", [](VM* vm, PyVarList args) { + _vm->bindMethod("NoneType", "__repr__", [](VM* vm, const pkpy::ArgList& args) { return vm->PyStr("None"); }); - _vm->bindMethod("NoneType", "__json__", [](VM* vm, PyVarList args) { + _vm->bindMethod("NoneType", "__json__", [](VM* vm, const pkpy::ArgList& args) { return vm->PyStr("null"); }); - _vm->bindMethodMulti({"int", "float"}, "__truediv__", [](VM* vm, PyVarList args) { + _vm->bindMethodMulti({"int", "float"}, "__truediv__", [](VM* vm, const pkpy::ArgList& args) { if(!vm->isIntOrFloat(args[0], args[1])) vm->typeError("unsupported operand type(s) for " "/" ); _Float rhs = vm->numToFloat(args[1]); @@ -162,7 +164,7 @@ void __initializeBuiltinFunctions(VM* _vm) { return vm->PyFloat(vm->numToFloat(args[0]) / rhs); }); - _vm->bindMethodMulti({"int", "float"}, "__pow__", [](VM* vm, PyVarList args) { + _vm->bindMethodMulti({"int", "float"}, "__pow__", [](VM* vm, const pkpy::ArgList& args) { if(!vm->isIntOrFloat(args[0], args[1])) vm->typeError("unsupported operand type(s) for " "**" ); if(args[0]->isType(vm->_tp_int) && args[1]->isType(vm->_tp_int)){ @@ -173,7 +175,7 @@ void __initializeBuiltinFunctions(VM* _vm) { }); /************ PyInt ************/ - _vm->bindMethod("int", "__new__", [](VM* vm, PyVarList args) { + _vm->bindMethod("int", "__new__", [](VM* vm, const pkpy::ArgList& args) { if(args.size() == 0) return vm->PyInt(0); vm->__checkArgSize(args, 1); if (args[0]->isType(vm->_tp_int)) return args[0]; @@ -192,7 +194,7 @@ void __initializeBuiltinFunctions(VM* _vm) { return vm->None; }); - _vm->bindMethod("int", "__floordiv__", [](VM* vm, PyVarList args) { + _vm->bindMethod("int", "__floordiv__", [](VM* vm, const pkpy::ArgList& args) { if(!args[0]->isType(vm->_tp_int) || !args[1]->isType(vm->_tp_int)) vm->typeError("unsupported operand type(s) for " "//" ); _Int rhs = vm->PyInt_AS_C(args[1]); @@ -200,7 +202,7 @@ void __initializeBuiltinFunctions(VM* _vm) { return vm->PyInt(vm->PyInt_AS_C(args[0]) / rhs); }); - _vm->bindMethod("int", "__mod__", [](VM* vm, PyVarList args) { + _vm->bindMethod("int", "__mod__", [](VM* vm, const pkpy::ArgList& args) { if(!args[0]->isType(vm->_tp_int) || !args[1]->isType(vm->_tp_int)) vm->typeError("unsupported operand type(s) for " "%" ); _Int rhs = vm->PyInt_AS_C(args[1]); @@ -208,16 +210,16 @@ void __initializeBuiltinFunctions(VM* _vm) { return vm->PyInt(vm->PyInt_AS_C(args[0]) % rhs); }); - _vm->bindMethod("int", "__repr__", [](VM* vm, PyVarList args) { + _vm->bindMethod("int", "__repr__", [](VM* vm, const pkpy::ArgList& args) { return vm->PyStr(std::to_string(vm->PyInt_AS_C(args[0]))); }); - _vm->bindMethod("int", "__json__", [](VM* vm, PyVarList args) { + _vm->bindMethod("int", "__json__", [](VM* vm, const pkpy::ArgList& args) { return vm->PyStr(std::to_string((int)vm->PyInt_AS_C(args[0]))); }); #define __INT_BITWISE_OP(name,op) \ - _vm->bindMethod("int", #name, [](VM* vm, PyVarList args) { \ + _vm->bindMethod("int", #name, [](VM* vm, const pkpy::ArgList& args) { \ if(!args[0]->isType(vm->_tp_int) || !args[1]->isType(vm->_tp_int)) \ vm->typeError("unsupported operand type(s) for " #op ); \ return vm->PyInt(vm->PyInt_AS_C(args[0]) op vm->PyInt_AS_C(args[1])); \ @@ -231,14 +233,14 @@ void __initializeBuiltinFunctions(VM* _vm) { #undef __INT_BITWISE_OP - _vm->bindMethod("int", "__xor__", [](VM* vm, PyVarList args) { + _vm->bindMethod("int", "__xor__", [](VM* vm, const pkpy::ArgList& args) { if(!args[0]->isType(vm->_tp_int) || !args[1]->isType(vm->_tp_int)) vm->typeError("unsupported operand type(s) for " "^" ); return vm->PyInt(vm->PyInt_AS_C(args[0]) ^ vm->PyInt_AS_C(args[1])); }); /************ PyFloat ************/ - _vm->bindMethod("float", "__new__", [](VM* vm, PyVarList args) { + _vm->bindMethod("float", "__new__", [](VM* vm, const pkpy::ArgList& args) { if(args.size() == 0) return vm->PyFloat(0.0); vm->__checkArgSize(args, 1); if (args[0]->isType(vm->_tp_int)) return vm->PyFloat((_Float)vm->PyInt_AS_C(args[0])); @@ -259,7 +261,7 @@ void __initializeBuiltinFunctions(VM* _vm) { return vm->None; }); - _vm->bindMethod("float", "__repr__", [](VM* vm, PyVarList args) { + _vm->bindMethod("float", "__repr__", [](VM* vm, const pkpy::ArgList& args) { _Float val = vm->PyFloat_AS_C(args[0]); if(std::isinf(val) || std::isnan(val)) return vm->PyStr(std::to_string(val)); _StrStream ss; @@ -269,17 +271,17 @@ void __initializeBuiltinFunctions(VM* _vm) { return vm->PyStr(s); }); - _vm->bindMethod("float", "__json__", [](VM* vm, PyVarList args) { + _vm->bindMethod("float", "__json__", [](VM* vm, const pkpy::ArgList& args) { return vm->PyStr(std::to_string((float)vm->PyFloat_AS_C(args[0]))); }); /************ PyString ************/ - _vm->bindMethod("str", "__new__", [](VM* vm, PyVarList args) { + _vm->bindMethod("str", "__new__", [](VM* vm, const pkpy::ArgList& args) { vm->__checkArgSize(args, 1); return vm->asStr(args[0]); }); - _vm->bindMethod("str", "__add__", [](VM* vm, PyVarList args) { + _vm->bindMethod("str", "__add__", [](VM* vm, const pkpy::ArgList& args) { if(!args[0]->isType(vm->_tp_str) || !args[1]->isType(vm->_tp_str)) vm->typeError("unsupported operand type(s) for " "+" ); const _Str& lhs = vm->PyStr_AS_C(args[0]); @@ -287,43 +289,43 @@ void __initializeBuiltinFunctions(VM* _vm) { return vm->PyStr(lhs + rhs); }); - _vm->bindMethod("str", "__len__", [](VM* vm, PyVarList args) { + _vm->bindMethod("str", "__len__", [](VM* vm, const pkpy::ArgList& args) { const _Str& _self = vm->PyStr_AS_C(args[0]); return vm->PyInt(_self.u8_length()); }); - _vm->bindMethod("str", "__contains__", [](VM* vm, PyVarList args) { + _vm->bindMethod("str", "__contains__", [](VM* vm, const pkpy::ArgList& args) { const _Str& _self = vm->PyStr_AS_C(args[0]); const _Str& _other = vm->PyStr_AS_C(args[1]); return vm->PyBool(_self.str().find(_other.str()) != _Str::npos); }); - _vm->bindMethod("str", "__str__", [](VM* vm, PyVarList args) { + _vm->bindMethod("str", "__str__", [](VM* vm, const pkpy::ArgList& args) { return args[0]; // str is immutable }); - _vm->bindMethod("str", "__iter__", [](VM* vm, PyVarList args) { + _vm->bindMethod("str", "__iter__", [](VM* vm, const pkpy::ArgList& args) { auto it = std::make_shared(vm, args[0]); return vm->PyIter(it); }); - _vm->bindMethod("str", "__repr__", [](VM* vm, PyVarList args) { + _vm->bindMethod("str", "__repr__", [](VM* vm, const pkpy::ArgList& args) { const _Str& _self = vm->PyStr_AS_C(args[0]); return vm->PyStr(_self.__escape(true)); }); - _vm->bindMethod("str", "__json__", [](VM* vm, PyVarList args) { + _vm->bindMethod("str", "__json__", [](VM* vm, const pkpy::ArgList& args) { const _Str& _self = vm->PyStr_AS_C(args[0]); return vm->PyStr(_self.__escape(false)); }); - _vm->bindMethod("str", "__eq__", [](VM* vm, PyVarList args) { + _vm->bindMethod("str", "__eq__", [](VM* vm, const pkpy::ArgList& args) { if(args[0]->isType(vm->_tp_str) && args[1]->isType(vm->_tp_str)) return vm->PyBool(vm->PyStr_AS_C(args[0]) == vm->PyStr_AS_C(args[1])); return vm->PyBool(args[0] == args[1]); // fallback }); - _vm->bindMethod("str", "__getitem__", [](VM* vm, PyVarList args) { + _vm->bindMethod("str", "__getitem__", [](VM* vm, const pkpy::ArgList& args) { const _Str& _self (vm->PyStr_AS_C(args[0])); if(args[1]->isType(vm->_tp_slice)){ @@ -337,19 +339,19 @@ void __initializeBuiltinFunctions(VM* _vm) { return vm->PyStr(_self.u8_getitem(_index)); }); - _vm->bindMethod("str", "__gt__", [](VM* vm, PyVarList args) { + _vm->bindMethod("str", "__gt__", [](VM* vm, const pkpy::ArgList& args) { const _Str& _self (vm->PyStr_AS_C(args[0])); const _Str& _obj (vm->PyStr_AS_C(args[1])); return vm->PyBool(_self > _obj); }); - _vm->bindMethod("str", "__lt__", [](VM* vm, PyVarList args) { + _vm->bindMethod("str", "__lt__", [](VM* vm, const pkpy::ArgList& args) { const _Str& _self (vm->PyStr_AS_C(args[0])); const _Str& _obj (vm->PyStr_AS_C(args[1])); return vm->PyBool(_self < _obj); }); - _vm->bindMethod("str", "upper", [](VM* vm, PyVarList args) { + _vm->bindMethod("str", "upper", [](VM* vm, const pkpy::ArgList& args) { vm->__checkArgSize(args, 1, true); const _Str& _self (vm->PyStr_AS_C(args[0])); _StrStream ss; @@ -357,7 +359,7 @@ void __initializeBuiltinFunctions(VM* _vm) { return vm->PyStr(ss.str()); }); - _vm->bindMethod("str", "lower", [](VM* vm, PyVarList args) { + _vm->bindMethod("str", "lower", [](VM* vm, const pkpy::ArgList& args) { vm->__checkArgSize(args, 1, true); const _Str& _self (vm->PyStr_AS_C(args[0])); _StrStream ss; @@ -365,7 +367,7 @@ void __initializeBuiltinFunctions(VM* _vm) { return vm->PyStr(ss.str()); }); - _vm->bindMethod("str", "replace", [](VM* vm, PyVarList args) { + _vm->bindMethod("str", "replace", [](VM* vm, const pkpy::ArgList& args) { vm->__checkArgSize(args, 3, true); const _Str& _self = vm->PyStr_AS_C(args[0]); const _Str& _old = vm->PyStr_AS_C(args[1]); @@ -380,21 +382,21 @@ void __initializeBuiltinFunctions(VM* _vm) { return vm->PyStr(_copy); }); - _vm->bindMethod("str", "startswith", [](VM* vm, PyVarList args) { + _vm->bindMethod("str", "startswith", [](VM* vm, const pkpy::ArgList& args) { vm->__checkArgSize(args, 2, true); const _Str& _self = vm->PyStr_AS_C(args[0]); const _Str& _prefix = vm->PyStr_AS_C(args[1]); return vm->PyBool(_self.str().find(_prefix.str()) == 0); }); - _vm->bindMethod("str", "endswith", [](VM* vm, PyVarList args) { + _vm->bindMethod("str", "endswith", [](VM* vm, const pkpy::ArgList& args) { vm->__checkArgSize(args, 2, true); const _Str& _self = vm->PyStr_AS_C(args[0]); const _Str& _suffix = vm->PyStr_AS_C(args[1]); return vm->PyBool(_self.str().rfind(_suffix.str()) == _self.str().length() - _suffix.str().length()); }); - _vm->bindMethod("str", "join", [](VM* vm, PyVarList args) { + _vm->bindMethod("str", "join", [](VM* vm, const pkpy::ArgList& args) { vm->__checkArgSize(args, 2, true); const _Str& _self = vm->PyStr_AS_C(args[0]); const PyVarList& _list = vm->PyList_AS_C(args[1]); @@ -407,20 +409,20 @@ void __initializeBuiltinFunctions(VM* _vm) { }); /************ PyList ************/ - _vm->bindMethod("list", "__iter__", [](VM* vm, PyVarList args) { + _vm->bindMethod("list", "__iter__", [](VM* vm, const pkpy::ArgList& args) { vm->__checkType(args[0], vm->_tp_list); auto iter = std::make_shared(vm, args[0]); return vm->PyIter(iter); }); - _vm->bindMethod("list", "append", [](VM* vm, PyVarList args) { + _vm->bindMethod("list", "append", [](VM* vm, const pkpy::ArgList& args) { vm->__checkArgSize(args, 2, true); PyVarList& _self = vm->PyList_AS_C(args[0]); _self.push_back(args[1]); return vm->None; }); - _vm->bindMethod("list", "insert", [](VM* vm, PyVarList args) { + _vm->bindMethod("list", "insert", [](VM* vm, const pkpy::ArgList& args) { vm->__checkArgSize(args, 3, true); PyVarList& _self = vm->PyList_AS_C(args[0]); int _index = vm->PyInt_AS_C(args[1]); @@ -431,18 +433,18 @@ void __initializeBuiltinFunctions(VM* _vm) { return vm->None; }); - _vm->bindMethod("list", "clear", [](VM* vm, PyVarList args) { + _vm->bindMethod("list", "clear", [](VM* vm, const pkpy::ArgList& args) { vm->__checkArgSize(args, 1, true); vm->PyList_AS_C(args[0]).clear(); return vm->None; }); - _vm->bindMethod("list", "copy", [](VM* vm, PyVarList args) { + _vm->bindMethod("list", "copy", [](VM* vm, const pkpy::ArgList& args) { vm->__checkArgSize(args, 1, true); return vm->PyList(vm->PyList_AS_C(args[0])); }); - _vm->bindMethod("list", "pop", [](VM* vm, PyVarList args) { + _vm->bindMethod("list", "pop", [](VM* vm, const pkpy::ArgList& args) { vm->__checkArgSize(args, 1, true); PyVarList& _self = vm->PyList_AS_C(args[0]); if(_self.empty()) vm->indexError("pop from empty list"); @@ -451,7 +453,7 @@ void __initializeBuiltinFunctions(VM* _vm) { return ret; }); - _vm->bindMethod("list", "__add__", [](VM* vm, PyVarList args) { + _vm->bindMethod("list", "__add__", [](VM* vm, const pkpy::ArgList& args) { const PyVarList& _self = vm->PyList_AS_C(args[0]); const PyVarList& _obj = vm->PyList_AS_C(args[1]); PyVarList _new_list = _self; @@ -459,12 +461,12 @@ void __initializeBuiltinFunctions(VM* _vm) { return vm->PyList(_new_list); }); - _vm->bindMethod("list", "__len__", [](VM* vm, PyVarList args) { + _vm->bindMethod("list", "__len__", [](VM* vm, const pkpy::ArgList& args) { const PyVarList& _self = vm->PyList_AS_C(args[0]); return vm->PyInt(_self.size()); }); - _vm->bindMethod("list", "__getitem__", [](VM* vm, PyVarList args) { + _vm->bindMethod("list", "__getitem__", [](VM* vm, const pkpy::ArgList& args) { const PyVarList& _self = vm->PyList_AS_C(args[0]); if(args[1]->isType(vm->_tp_slice)){ @@ -481,7 +483,7 @@ void __initializeBuiltinFunctions(VM* _vm) { return _self[_index]; }); - _vm->bindMethod("list", "__setitem__", [](VM* vm, PyVarList args) { + _vm->bindMethod("list", "__setitem__", [](VM* vm, const pkpy::ArgList& args) { PyVarList& _self = vm->PyList_AS_C(args[0]); int _index = vm->PyInt_AS_C(args[1]); _index = vm->normalizedIndex(_index, _self.size()); @@ -489,7 +491,7 @@ void __initializeBuiltinFunctions(VM* _vm) { return vm->None; }); - _vm->bindMethod("list", "__delitem__", [](VM* vm, PyVarList args) { + _vm->bindMethod("list", "__delitem__", [](VM* vm, const pkpy::ArgList& args) { PyVarList& _self = vm->PyList_AS_C(args[0]); int _index = vm->PyInt_AS_C(args[1]); _index = vm->normalizedIndex(_index, _self.size()); @@ -498,24 +500,24 @@ void __initializeBuiltinFunctions(VM* _vm) { }); /************ PyTuple ************/ - _vm->bindMethod("tuple", "__new__", [](VM* vm, PyVarList args) { + _vm->bindMethod("tuple", "__new__", [](VM* vm, const pkpy::ArgList& args) { vm->__checkArgSize(args, 1); PyVarList _list = vm->PyList_AS_C(vm->call(vm->builtins->attribs["list"], args)); return vm->PyTuple(_list); }); - _vm->bindMethod("tuple", "__iter__", [](VM* vm, PyVarList args) { + _vm->bindMethod("tuple", "__iter__", [](VM* vm, const pkpy::ArgList& args) { vm->__checkType(args[0], vm->_tp_tuple); auto iter = std::make_shared(vm, args[0]); return vm->PyIter(iter); }); - _vm->bindMethod("tuple", "__len__", [](VM* vm, PyVarList args) { + _vm->bindMethod("tuple", "__len__", [](VM* vm, const pkpy::ArgList& args) { const PyVarList& _self = vm->PyTuple_AS_C(args[0]); return vm->PyInt(_self.size()); }); - _vm->bindMethod("tuple", "__getitem__", [](VM* vm, PyVarList args) { + _vm->bindMethod("tuple", "__getitem__", [](VM* vm, const pkpy::ArgList& args) { const PyVarList& _self = vm->PyTuple_AS_C(args[0]); int _index = vm->PyInt_AS_C(args[1]); _index = vm->normalizedIndex(_index, _self.size()); @@ -523,21 +525,21 @@ void __initializeBuiltinFunctions(VM* _vm) { }); /************ PyBool ************/ - _vm->bindMethod("bool", "__repr__", [](VM* vm, PyVarList args) { + _vm->bindMethod("bool", "__repr__", [](VM* vm, const pkpy::ArgList& args) { bool val = vm->PyBool_AS_C(args[0]); return vm->PyStr(val ? "True" : "False"); }); - _vm->bindMethod("bool", "__json__", [](VM* vm, PyVarList args) { + _vm->bindMethod("bool", "__json__", [](VM* vm, const pkpy::ArgList& args) { bool val = vm->PyBool_AS_C(args[0]); return vm->PyStr(val ? "true" : "false"); }); - _vm->bindMethod("bool", "__eq__", [](VM* vm, PyVarList args) { + _vm->bindMethod("bool", "__eq__", [](VM* vm, const pkpy::ArgList& args) { return vm->PyBool(args[0] == args[1]); }); - _vm->bindMethod("bool", "__xor__", [](VM* vm, PyVarList args) { + _vm->bindMethod("bool", "__xor__", [](VM* vm, const pkpy::ArgList& args) { bool _self = vm->PyBool_AS_C(args[0]); bool _obj = vm->PyBool_AS_C(args[1]); return vm->PyBool(_self ^ _obj); @@ -557,7 +559,7 @@ void __initializeBuiltinFunctions(VM* _vm) { void __addModuleTime(VM* vm){ PyVar mod = vm->newModule("time"); - vm->bindFunc(mod, "time", [](VM* vm, PyVarList args) { + vm->bindFunc(mod, "time", [](VM* vm, const pkpy::ArgList& args) { auto now = std::chrono::high_resolution_clock::now(); return vm->PyFloat(std::chrono::duration_cast(now.time_since_epoch()).count() / 1000000.0); }); @@ -565,17 +567,17 @@ void __addModuleTime(VM* vm){ void __addModuleSys(VM* vm){ PyVar mod = vm->newModule("sys"); - vm->bindFunc(mod, "getrefcount", [](VM* vm, PyVarList args) { + vm->bindFunc(mod, "getrefcount", [](VM* vm, const pkpy::ArgList& args) { vm->__checkArgSize(args, 1); return vm->PyInt(args[0].use_count()); }); - vm->bindFunc(mod, "getrecursionlimit", [](VM* vm, PyVarList args) { + vm->bindFunc(mod, "getrecursionlimit", [](VM* vm, const pkpy::ArgList& args) { vm->__checkArgSize(args, 0); return vm->PyInt(vm->maxRecursionDepth); }); - vm->bindFunc(mod, "setrecursionlimit", [](VM* vm, PyVarList args) { + vm->bindFunc(mod, "setrecursionlimit", [](VM* vm, const pkpy::ArgList& args) { vm->__checkArgSize(args, 1); vm->maxRecursionDepth = vm->PyInt_AS_C(args[0]); return vm->None; diff --git a/src/safestl.h b/src/safestl.h index b3fedf09..b6bfe292 100644 --- a/src/safestl.h +++ b/src/safestl.h @@ -51,4 +51,106 @@ public: // define constructors the same as std::unordered_map using std::unordered_map<_Str, PyVar>::unordered_map; -}; \ No newline at end of file +}; + + +namespace pkpy { + const size_t MAX_POOLING_N = 16; + static std::deque* _poolArgList = new std::deque[MAX_POOLING_N]; + + class ArgList { + PyVar* _args = nullptr; + size_t _size = 0; + + inline void __checkIndex(size_t i) const { + if (i >= _size){ + auto msg = "pkpy:ArgList index out of range, " + std::to_string(i) + " not in [0, " + std::to_string(size()) + ")"; + throw std::out_of_range(msg); + } + } + + void __tryAlloc(size_t n){ + if(n >= MAX_POOLING_N || _poolArgList[n].empty()){ + this->_size = n; + this->_args = new PyVar[n]; + }else{ + this->_args = _poolArgList[n].front(); + this->_size = n; + _poolArgList[n].pop_front(); + } + } + + void __tryRelease(){ + if(_size == 0 || _args == nullptr) return; + if(_size >= MAX_POOLING_N){ + delete[] _args; + }else{ + for(int i = 0; i < _size; i++) _args[i].reset(); + _poolArgList[_size].push_back(_args); + } + } + + public: + ArgList(int n){ + __tryAlloc(n); + } + + ArgList(const ArgList& other){ + __tryAlloc(other._size); + for(int i=0; i<_size; i++){ + _args[i] = other._args[i]; + } + } + + ArgList(ArgList&& other){ + this->_args = other._args; + this->_size = other._size; + other._args = nullptr; + other._size = 0; + } + + ArgList(PyVarList&& other){ + __tryAlloc(other.size()); + for(int i=0; i<_size; i++){ + _args[i] = std::move(other[i]); + } + other.clear(); + } + + ArgList(std::initializer_list&& args){ + __tryAlloc(args.size()); + int i = 0; + for(auto& arg: args) this->_args[i++] = arg; + } + + PyVar& operator[](size_t i){ + __checkIndex(i); + return _args[i]; + } + + const PyVar& operator[](size_t i) const { + __checkIndex(i); + return _args[i]; + } + + // overload = for && + ArgList& operator=(ArgList&& other){ + if(this != &other){ + __tryRelease(); + this->_args = other._args; + this->_size = other._size; + other._args = nullptr; + other._size = 0; + } + return *this; + } + + size_t size() const { + return _size; + } + + ~ArgList(){ + __tryRelease(); + } + }; +} \ No newline at end of file diff --git a/src/vm.h b/src/vm.h index 7fe41d59..6a417e2c 100644 --- a/src/vm.h +++ b/src/vm.h @@ -381,7 +381,7 @@ public: return True; } - PyVar fastCall(const PyVar& obj, const _Str& name, PyVarList&& args){ + PyVar fastCall(const PyVar& obj, const _Str& name, pkpy::ArgList&& args){ PyObject* cls = obj->_type.get(); while(cls != None.get()) { auto it = cls->attribs.find(name); @@ -394,34 +394,38 @@ public: return nullptr; } - PyVar call(PyVar callable, PyVarList args, bool opCall=false){ - if(callable->isType(_tp_type)){ - auto it = callable->attribs.find(__new__); + PyVar call(const PyVar& _callable, pkpy::ArgList args, bool opCall=false){ + if(_callable->isType(_tp_type)){ + auto it = _callable->attribs.find(__new__); PyVar obj; - if(it != callable->attribs.end()){ + if(it != _callable->attribs.end()){ obj = call(it->second, args); }else{ - obj = newObject(callable, (_Int)-1); + obj = newObject(_callable, (_Int)-1); } - if(obj->isType(callable)){ + if(obj->isType(_callable)){ PyVarOrNull init_fn = getAttr(obj, __init__, false); if (init_fn != nullptr) call(init_fn, args); } return obj; } - if(callable->isType(_tp_bounded_method)){ - auto& bm = PyBoundedMethod_AS_C(callable); + const PyVar* callable = &_callable; + if((*callable)->isType(_tp_bounded_method)){ + auto& bm = PyBoundedMethod_AS_C((*callable)); // TODO: avoid insertion here, bad performance - args.insert(args.begin(), bm.obj); - callable = bm.method; + pkpy::ArgList new_args(args.size()+1); + new_args[0] = bm.obj; + for(int i=0; iisType(_tp_native_function)){ - const auto& f = std::get<_CppFunc>(callable->_native); + if((*callable)->isType(_tp_native_function)){ + const auto& f = std::get<_CppFunc>((*callable)->_native); return f(this, args); - } else if(callable->isType(_tp_function)){ - const _Func& fn = PyFunction_AS_C(callable); + } else if((*callable)->isType(_tp_function)){ + const _Func& fn = PyFunction_AS_C((*callable)); PyVarDict locals; int i = 0; for(const auto& name : fn->args){ @@ -448,19 +452,23 @@ public: if(i < args.size()) typeError("too many arguments"); - auto it_m = callable->attribs.find(__module__); - PyVar _module = it_m != callable->attribs.end() ? it_m->second : topFrame()->_module; + auto it_m = (*callable)->attribs.find(__module__); + PyVar _module = it_m != (*callable)->attribs.end() ? it_m->second : topFrame()->_module; if(opCall){ __pushNewFrame(fn->code, _module, locals); return __py2py_call_signal; } return _exec(fn->code, _module, locals); } - typeError("'" + callable->getTypeName() + "' object is not callable"); + typeError("'" + (*callable)->getTypeName() + "' object is not callable"); return None; } - inline PyVar call(const PyVar& obj, const _Str& func, PyVarList args){ + 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); } @@ -789,7 +797,7 @@ public: if(!obj->isType(type)) typeError("expected '" + type->getName() + "', but got '" + obj->getTypeName() + "'"); } - inline void __checkArgSize(const PyVarList& args, int size, bool method=false){ + inline void __checkArgSize(const pkpy::ArgList& args, int size, bool method=false){ if(args.size() == size) return; if(method) typeError(args.size()>size ? "too many arguments" : "too few arguments"); else typeError("expected " + std::to_string(size) + " arguments, but got " + std::to_string(args.size()));