ソースを参照

add arg size check

blueloveTH 3 年 前
コミット
a61315d1f7
3 ファイル変更42 行追加17 行削除
  1. 7 0
      src/builtins.h
  2. 27 15
      src/pocketpy.h
  3. 8 2
      src/vm.h

+ 7 - 0
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) + '}'

+ 27 - 15
src/pocketpy.h

@@ -4,11 +4,7 @@
 #include "compiler.h"
 
 #include <iomanip>
-
-inline _Int _round(_Float f){
-    if(f > 0) return (_Int)(f + 0.5);
-    return (_Int)(f - 0.5);
-}
+#include <cmath>
 
 #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>", 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();

+ 8 - 2
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);
     }