From a61315d1f7aa5a1533b4c046f1cf1cf3a01046d1 Mon Sep 17 00:00:00 2001 From: blueloveTH Date: Thu, 10 Nov 2022 15:48:08 +0800 Subject: [PATCH] add arg size check --- src/builtins.h | 7 +++++++ src/pocketpy.h | 42 +++++++++++++++++++++++++++--------------- src/vm.h | 10 ++++++++-- 3 files changed, 42 insertions(+), 17 deletions(-) diff --git a/src/builtins.h b/src/builtins.h index a8bc1931..bf013aca 100644 --- a/src/builtins.h +++ b/src/builtins.h @@ -118,6 +118,13 @@ class dict: def items(self): return [kv for kv in self._a if kv is not None] + def copy(self): + d = dict() + for kv in self._a: + if kv is not None: + d[kv[0]] = kv[1] + return d + def __repr__(self): a = [repr(k)+': '+repr(v) for k,v in self.items()] return '{'+ ', '.join(a) + '}' diff --git a/src/pocketpy.h b/src/pocketpy.h index f9826cfc..e157c4ad 100644 --- a/src/pocketpy.h +++ b/src/pocketpy.h @@ -4,11 +4,7 @@ #include "compiler.h" #include - -inline _Int _round(_Float f){ - if(f > 0) return (_Int)(f + 0.5); - return (_Int)(f - 0.5); -} +#include #define BIND_NUM_ARITH_OPT(name, op) \ _vm->bindMethodMulti({"int","float"}, #name, [](VM* vm, PyVarList args){ \ @@ -52,39 +48,44 @@ void __initializeBuiltinFunctions(VM* _vm) { }); _vm->bindBuiltinFunc("eval", [](VM* vm, PyVarList args) { - if (args.size() != 1) vm->typeError("eval() takes exactly one argument"); - if (!args[0]->isType(vm->_tp_str)) vm->typeError("eval() argument must be a string"); + vm->__checkArgSize(args, 1); const _Str& expr = vm->PyStr_AS_C(args[0]); _Code code = compile(vm, expr, "", EVAL_MODE); if(code == nullptr) return vm->None; return vm->_exec(code); // not working in function }); + _vm->bindBuiltinFunc("isinstance", [](VM* vm, PyVarList args) { + vm->__checkArgSize(args, 2); + return vm->PyBool(vm->isInstance(args[0], args[1])); + }); + _vm->bindBuiltinFunc("repr", [](VM* vm, PyVarList args) { + vm->__checkArgSize(args, 1); return vm->asRepr(args[0]); }); _vm->bindBuiltinFunc("hash", [](VM* vm, PyVarList args) { + vm->__checkArgSize(args, 1); return vm->PyInt(vm->hash(args[0])); }); _vm->bindBuiltinFunc("chr", [](VM* vm, PyVarList 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("round", [](VM* vm, PyVarList args) { - return vm->PyInt(_round(vm->numToFloat(args[0]))); - }); - _vm->bindBuiltinFunc("ord", [](VM* vm, PyVarList 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("dir", [](VM* vm, PyVarList args) { + vm->__checkArgSize(args, 1); PyVarList ret; for (auto& [k, _] : args[0]->attribs) ret.push_back(vm->PyStr(k)); return vm->PyList(ret); @@ -97,7 +98,7 @@ void __initializeBuiltinFunctions(VM* _vm) { }); _vm->bindMethod("type", "__new__", [](VM* vm, PyVarList args) { - vm->_assert(args.size() == 1, "expected 1 argument"); + vm->__checkArgSize(args, 1); return args[0]->attribs[__class__]; }); @@ -107,7 +108,7 @@ void __initializeBuiltinFunctions(VM* _vm) { case 1: r.stop = vm->PyInt_AS_C(args[0]); break; case 2: r.start = vm->PyInt_AS_C(args[0]); r.stop = vm->PyInt_AS_C(args[1]); break; case 3: r.start = vm->PyInt_AS_C(args[0]); r.stop = vm->PyInt_AS_C(args[1]); r.step = vm->PyInt_AS_C(args[2]); break; - default: vm->typeError("range expected 1-3 arguments, got " + std::to_string(args.size())); + default: vm->typeError("expected 1-3 arguments, but got " + std::to_string(args.size())); } return vm->PyRange(r); }); @@ -134,7 +135,7 @@ void __initializeBuiltinFunctions(VM* _vm) { 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)){ - return vm->PyInt(_round(pow(vm->PyInt_AS_C(args[0]), vm->PyInt_AS_C(args[1])))); + return vm->PyInt((_Int)round(pow(vm->PyInt_AS_C(args[0]), vm->PyInt_AS_C(args[1])))); }else{ return vm->PyFloat((_Float)pow(vm->numToFloat(args[0]), vm->numToFloat(args[1]))); } @@ -182,7 +183,7 @@ void __initializeBuiltinFunctions(VM* _vm) { /************ PyString ************/ _vm->bindMethod("str", "__new__", [](VM* vm, PyVarList args) { - vm->_assert(args.size() == 1, "expected 1 argument"); + vm->__checkArgSize(args, 1); return vm->asStr(args[0]); }); @@ -248,6 +249,7 @@ void __initializeBuiltinFunctions(VM* _vm) { }); _vm->bindMethod("str", "upper", [](VM* vm, PyVarList args) { + vm->__checkArgSize(args, 1, true); const _Str& _self (vm->PyStr_AS_C(args[0])); _StrStream ss; for(auto c : _self.str()) ss << (char)toupper(c); @@ -255,6 +257,7 @@ void __initializeBuiltinFunctions(VM* _vm) { }); _vm->bindMethod("str", "lower", [](VM* vm, PyVarList args) { + vm->__checkArgSize(args, 1, true); const _Str& _self (vm->PyStr_AS_C(args[0])); _StrStream ss; for(auto c : _self.str()) ss << (char)tolower(c); @@ -262,6 +265,7 @@ void __initializeBuiltinFunctions(VM* _vm) { }); _vm->bindMethod("str", "replace", [](VM* vm, PyVarList args) { + vm->__checkArgSize(args, 3, true); const _Str& _self = vm->PyStr_AS_C(args[0]); const _Str& _old = vm->PyStr_AS_C(args[1]); const _Str& _new = vm->PyStr_AS_C(args[2]); @@ -276,18 +280,21 @@ void __initializeBuiltinFunctions(VM* _vm) { }); _vm->bindMethod("str", "startswith", [](VM* vm, PyVarList 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->__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->__checkArgSize(args, 2, true); const _Str& _self = vm->PyStr_AS_C(args[0]); const PyVarList& _list = vm->PyList_AS_C(args[1]); _StrStream ss; @@ -306,12 +313,14 @@ void __initializeBuiltinFunctions(VM* _vm) { }); _vm->bindMethod("list", "append", [](VM* vm, PyVarList 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->__checkArgSize(args, 3, true); PyVarList& _self = vm->PyList_AS_C(args[0]); int _index = vm->PyInt_AS_C(args[1]); _index = vm->normalizedIndex(_index, _self.size()); @@ -320,15 +329,18 @@ void __initializeBuiltinFunctions(VM* _vm) { }); _vm->bindMethod("list", "clear", [](VM* vm, PyVarList 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->__checkArgSize(args, 1, true); return vm->PyList(vm->PyList_AS_C(args[0])); }); _vm->bindMethod("list", "pop", [](VM* vm, PyVarList args) { + vm->__checkArgSize(args, 1, true); PyVarList& _self = vm->PyList_AS_C(args[0]); if(_self.empty()) vm->indexError("pop from empty list"); PyVar ret = _self.back(); diff --git a/src/vm.h b/src/vm.h index 1eb1a929..717b6541 100644 --- a/src/vm.h +++ b/src/vm.h @@ -450,8 +450,7 @@ public: } PyVar newNumber(PyVar type, _Value _native) { - if(type != _tp_int && type != _tp_float) - systemError("type is not a number type"); + if(type != _tp_int && type != _tp_float) UNREACHABLE(); PyObject* _raw = nullptr; if(numPool.size() > 0) { _raw = numPool.back(); @@ -522,6 +521,7 @@ public: } bool isInstance(PyVar obj, PyVar type){ + __checkType(type, _tp_type); PyVar t = obj->attribs[__class__]; while (t != None){ if (t == type) return true; @@ -687,6 +687,12 @@ public: if(!obj->isType(type)) typeError("expected '" + type->getName() + "', but got '" + obj->getTypeName() + "'"); } + inline void __checkArgSize(const PyVarList& 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())); + } + void _assert(bool val, const _Str& msg){ if (!val) _error("AssertionError", msg); }