blueloveTH 2 лет назад
Родитель
Сommit
e7f947c987
3 измененных файлов с 22 добавлено и 21 удалено
  1. 7 8
      docs/features/differences.md
  2. 10 0
      src/pocketpy.cpp
  3. 5 13
      src/vm.cpp

+ 7 - 8
docs/features/differences.md

@@ -20,14 +20,12 @@ The easiest way to test a feature is to [try it on your browser](https://pocketp
 
 ## Unimplemented features
 
-1. `__getattr__` and `__setattr__`.
-2. Descriptor protocol `__get__` and `__set__`. However, `@property` is implemented.
-3. `__slots__` in class definition.
-4. Access the exception object in try..except.
-5.  `else` clause in try..except.
-6.  Inplace methods like `__iadd__` and `__imul__`.
-7. `__del__` in class definition.
-8. Multiple inheritance.
+1. Descriptor protocol `__get__` and `__set__`. However, `@property` is implemented.
+2. `__slots__` in class definition.
+3. `else` clause in try..except.
+4.  Inplace methods like `__iadd__` and `__imul__`.
+5. `__del__` in class definition.
+6. Multiple inheritance.
 
 ## Different behaviors
 
@@ -42,3 +40,4 @@ The easiest way to test a feature is to [try it on your browser](https://pocketp
 9. A `Tab` is equivalent to 4 spaces. You can mix `Tab` and spaces in indentation, but it is not recommended.
 10. `%`, `&`, `//`, `^` and `|` for `int` behave the same as C, not python.
 11. `str.split` and `str.splitlines` will remove all empty entries.
+12. `__getattr__` and `__setattr__` can only be set in cpp.

+ 10 - 0
src/pocketpy.cpp

@@ -1604,6 +1604,16 @@ void VM::post_init(){
         return vm->None;
     });
 
+    _all_types[tp_module].m__getattr__ = [](VM* vm, PyObject* obj, StrName name) -> PyObject*{
+        const Str& path = CAST(Str&, obj->attr(__path__));
+        PyObject* mod = vm->py_import(fmt(path, ".", name.sv()), false);
+        if(mod != nullptr){
+            obj->attr().set(name, mod);
+            return mod;
+        }
+        return nullptr;
+    };
+
     bind_method<1>(tp_property, "setter", [](VM* vm, ArgsView args) {
         Property& self = _CAST(Property&, args[0]);
         // The setter's name is not necessary to be the same as the property's name

+ 5 - 13
src/vm.cpp

@@ -1041,17 +1041,8 @@ PyObject* VM::getattr(PyObject* obj, StrName name, bool throw_err){
 
     const PyTypeInfo* ti = &_all_types[objtype];
     if(ti->m__getattr__){
-        return ti->m__getattr__(this, obj, name);
-    }
-    
-    if(is_non_tagged_type(obj, tp_module)){
-        Str path = CAST(Str&, obj->attr(__path__));
-        path = path + "." + name.sv();
-        PyObject* mod = py_import(path, false);
-        if(mod != nullptr){
-            obj->attr().set(name, mod);
-            return mod;
-        }
+        PyObject* ret = ti->m__getattr__(this, obj, name);
+        if(ret) return ret;
     }
 
     if(throw_err) AttributeError(obj, name);
@@ -1120,8 +1111,9 @@ PyObject* VM::get_unbound_method(PyObject* obj, StrName name, PyObject** self, b
     }
 
     const PyTypeInfo* ti = &_all_types[objtype];
-    if(fallback && ti->m__getattr__){
-        return ti->m__getattr__(this, obj, name);
+    if(ti->m__getattr__){
+        PyObject* ret = ti->m__getattr__(this, obj, name);
+        if(ret) return ret;
     }
 
     if(throw_err) AttributeError(obj, name);