瀏覽代碼

fix bugs of __new__

some renames
blueloveTH 3 年之前
父節點
當前提交
299370a225
共有 4 個文件被更改,包括 33 次插入44 次删除
  1. 3 3
      src/codeobject.h
  2. 3 3
      src/obj.h
  3. 11 30
      src/pocketpy.h
  4. 16 8
      src/vm.h

+ 3 - 3
src/codeobject.h

@@ -106,12 +106,12 @@ private:
     std::vector<PyVar> s_data;
     int ip = 0;
 public:
-    StlDict* f_globals;
-    StlDict f_locals;
+    PyVarDict* f_globals;
+    PyVarDict f_locals;
 
     const CodeObject* code;
 
-    Frame(const CodeObject* code, StlDict locals, StlDict* globals)
+    Frame(const CodeObject* code, PyVarDict locals, PyVarDict* globals)
         : code(code), f_locals(locals), f_globals(globals) {}
 
     inline const ByteCode& readCode() {

+ 3 - 3
src/obj.h

@@ -18,7 +18,7 @@ class VM;
 typedef std::shared_ptr<PyObject> PyVar;
 typedef PyVar PyVarOrNull;
 typedef std::vector<PyVar> PyVarList;
-typedef std::unordered_map<_Str, PyVar> StlDict;
+typedef std::unordered_map<_Str, PyVar> PyVarDict;
 typedef std::shared_ptr<const BasePointer> _Pointer;
 
 typedef PyVar (*_CppFunc)(VM*, PyVarList);
@@ -29,7 +29,7 @@ struct _Func {
     _Code code;
     std::vector<_Str> args;
     _Str starredArg;        // empty if no *arg
-    StlDict kwArgs;         // empty if no k=v
+    PyVarDict kwArgs;         // empty if no k=v
     _Str doubleStarredArg;  // empty if no **kwargs
 
     bool hasName(const _Str& val) const {
@@ -81,7 +81,7 @@ typedef std::variant<int,float,bool,_Str,PyVarList,_CppFunc,_Func,std::shared_pt
 #define UNREACHABLE() throw std::runtime_error("Unreachable code")
 
 struct PyObject {
-    StlDict attribs;
+    PyVarDict attribs;
     _Value _native;
 
     inline bool isType(const PyVar& type){

+ 11 - 30
src/pocketpy.h

@@ -87,42 +87,24 @@ void __initializeBuiltinFunctions(VM* _vm) {
         return vm->PyList(ret);
     });
 
-    _vm->bindMethod("object", "__new__", [](VM* vm, PyVarList args) {
-        PyVar obj = vm->newObject(args.at(0), -1);
-        args.erase(args.begin());
-        PyVarOrNull init_fn = vm->getAttr(obj, __init__, false);
-        if (init_fn != nullptr) vm->call(init_fn, args);
-        return obj;
-    });
-
     _vm->bindMethod("object", "__repr__", [](VM* vm, PyVarList args) {
         PyVar _self = args[0];
         _Str s = "<" + _self->getTypeName() + " object at " + std::to_string((uintptr_t)_self.get()) + ">";
         return vm->PyStr(s);
     });
 
-    // a little buggy... e.g. dict() call this instead of obj.__new__
-    // _vm->bindMethod("type", "__new__", [](VM* vm, PyVarList args) {
-    //     return args.at(1)->attribs["__class__"];
-    // });
+    _vm->bindMethod("type", "__new__", [](VM* vm, PyVarList args) {
+        vm->_assert(args.size() == 1, "expected 1 argument");
+        return args.at(0)->attribs[__class__];
+    });
 
     _vm->bindMethod("range", "__new__", [](VM* vm, PyVarList args) {
         _Range r;
-        if( args.size() == 0 ) vm->_error("TypeError", "range expected 1 arguments, got 0");
-        else if (args.size() == 1+1) {
-            r.stop = vm->PyInt_AS_C(args[1]);
-        }
-        else if (args.size() == 2+1) {
-            r.start = vm->PyInt_AS_C(args[1]);
-            r.stop = vm->PyInt_AS_C(args[2]);
-        }
-        else if (args.size() == 3+1) {
-            r.start = vm->PyInt_AS_C(args[1]);
-            r.stop = vm->PyInt_AS_C(args[2]);
-            r.step = vm->PyInt_AS_C(args[3]);
-        }
-        else {
-            vm->_error("TypeError", "range expected 1 to 3 arguments, got " + std::to_string(args.size()-1));
+        switch (args.size()) {
+            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->_error("TypeError", "range expected 1-3 arguments, got " + std::to_string(args.size()));
         }
         return vm->PyRange(r);
     });
@@ -187,9 +169,8 @@ void __initializeBuiltinFunctions(VM* _vm) {
 
     /************ PyString ************/
     _vm->bindMethod("str", "__new__", [](VM* vm, PyVarList args) {
-        vm->_assert(args[0] == vm->_tp_str, "str.__new__ must be called with str as first argument");
-        vm->_assert(args.size() == 2, "str expected 1 argument");
-        return vm->asStr(args[1]);
+        vm->_assert(args.size() == 1, "expected 1 argument");
+        return vm->asStr(args[0]);
     });
 
     _vm->bindMethod("str", "__add__", [](VM* vm, PyVarList args) {

+ 16 - 8
src/vm.h

@@ -28,14 +28,14 @@ private:
     std::stack< std::shared_ptr<Frame> > callstack;
     std::vector<PyObject*> numPool;
 public:
-    StlDict _types;         // builtin types
+    PyVarDict _types;         // builtin types
     PyVar None, True, False;
 
     PrintFn printFn = [](auto s){};
     
     PyVar builtins;         // builtins module
     PyVar _main;            // __main__ module
-    StlDict _modules;       // 3rd modules
+    PyVarDict _modules;       // 3rd modules
 
     VM(){
         initializeBuiltinClasses();
@@ -99,9 +99,18 @@ public:
 
     PyVar call(PyVar callable, PyVarList args){
         if(callable->isType(_tp_type)){
-            // add type itself as the first argument
-            args.insert(args.begin(), callable);
-            callable = getAttr(callable, __new__);
+            auto it = callable->attribs.find(__new__);
+            PyVar obj;
+            if(it != callable->attribs.end()){
+                obj = call(it->second, args);
+            }else{
+                obj = newObject(callable, -1);
+            }
+            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)){
@@ -115,7 +124,7 @@ public:
             return f(this, args);
         } else if(callable->isType(_tp_function)){
             _Func fn = PyFunction_AS_C(callable);
-            StlDict locals;
+            PyVarDict locals;
             int i = 0;
             for(const auto& name : fn.args){
                 if(i < args.size()) {
@@ -412,7 +421,7 @@ public:
         return None;
     }
 
-    PyVar exec(const _Code& code, const StlDict& locals={}, PyVar _module=nullptr){
+    PyVar exec(const _Code& code, const PyVarDict& locals={}, PyVar _module=nullptr){
         if(_module == nullptr) _module = _main;
         auto frame = std::make_shared<Frame>(
             code.get(),
@@ -492,7 +501,6 @@ public:
             if(it != cls->attribs.end()){
                 PyVar valueFromCls = it->second;
                 if(valueFromCls->isType(_tp_function) || valueFromCls->isType(_tp_native_function)){
-                    if(name == __new__) return valueFromCls;
                     return PyBoundedMethod({obj, valueFromCls});
                 }else{
                     return valueFromCls;