diff --git a/object.h b/object.h index 428be7b..0dddfc3 100644 --- a/object.h +++ b/object.h @@ -136,6 +136,8 @@ typedef struct KrkClass { KrkObj * _exit; KrkObj * _delitem; KrkObj * _iter; + KrkObj * _getattr; + KrkObj * _dir; } KrkClass; typedef struct KrkInstance { diff --git a/test/testGetattrDir.krk b/test/testGetattrDir.krk new file mode 100644 index 0000000..3852076 --- /dev/null +++ b/test/testGetattrDir.krk @@ -0,0 +1,24 @@ +class Foo(): + def __getattr__(name): + if name in self._dict: + return self._dict[name] + else: + raise AttributeError(name) + def __init__(): + self._dict = {'foo': 1, 'bar': 42} + +let f = Foo() +print(f) +print(dir(f)) +print(f.foo) + +class Bar(object): + def __dir__(self): + let out = super().__dir__() + out.append("butts") + return out + +let b = Bar() +print(dir(b)) +try: + b.butts diff --git a/test/testGetattrDir.krk.expect b/test/testGetattrDir.krk.expect new file mode 100644 index 0000000..0275c62 --- /dev/null +++ b/test/testGetattrDir.krk.expect @@ -0,0 +1,4 @@ + +['__class__', '__str__', '__init__', '__dir__', '__repr__', '__getattr__', '_dict'] +1 +['__class__', '__str__', '__dir__', '__repr__', 'butts'] diff --git a/vm.c b/vm.c index 3cf27b4..7457c9c 100644 --- a/vm.c +++ b/vm.c @@ -303,6 +303,8 @@ void krk_finalizeClass(KrkClass * _class) { {&_class->_exit, METHOD_EXIT}, {&_class->_delitem, METHOD_DELITEM}, {&_class->_iter, METHOD_ITER}, + {&_class->_getattr, METHOD_GETATTR}, + {&_class->_dir, METHOD_DIR}, {NULL, 0}, }; @@ -2682,6 +2684,19 @@ static KrkValue _len(int argc, KrkValue argv[]) { return krk_callSimple(OBJECT_VAL(type->_len), 1, 0); } +static KrkValue _dir(int argc, KrkValue argv[]) { + if (argc != 1) { + krk_runtimeError(vm.exceptions.argumentError, "dir() takes exactly one argument"); + return NONE_VAL(); + } + KrkClass * type = AS_CLASS(krk_typeOf(1,&argv[0])); + if (!type->_dir) { + return krk_dirObject(argc,argv); /* Fallback */ + } + krk_push(argv[0]); + return krk_callSimple(OBJECT_VAL(type->_dir), 1, 0); +} + static KrkValue _repr(int argc, KrkValue argv[]) { if (argc != 1) { krk_runtimeError(vm.exceptions.argumentError, "repr() takes exactly one argument"); @@ -3105,6 +3120,8 @@ void krk_initVM(int flags) { vm.specialMethodNames[METHOD_EXIT] = OBJECT_VAL(S("__exit__")); vm.specialMethodNames[METHOD_DELITEM] = OBJECT_VAL(S("__delitem__")); /* delitem */ vm.specialMethodNames[METHOD_ITER] = OBJECT_VAL(S("__iter__")); + vm.specialMethodNames[METHOD_GETATTR] = OBJECT_VAL(S("__getattr__")); + vm.specialMethodNames[METHOD_DIR] = OBJECT_VAL(S("__dir__")); /* Create built-in class `object` */ vm.objectClass = krk_newClass(S("object")); @@ -3276,7 +3293,7 @@ void krk_initVM(int flags) { BUILTIN_FUNCTION("dictOf", krk_dict_of); /* Equivalent to dict() */ BUILTIN_FUNCTION("isinstance", krk_isinstance); BUILTIN_FUNCTION("globals", krk_globals); - BUILTIN_FUNCTION("dir", krk_dirObject); + BUILTIN_FUNCTION("dir", _dir); BUILTIN_FUNCTION("len", _len); BUILTIN_FUNCTION("repr", _repr); BUILTIN_FUNCTION("print", _print); @@ -3709,6 +3726,12 @@ static int valueGetProperty(KrkString * name) { return 1; } + if (objectClass->_getattr) { + krk_push(OBJECT_VAL(name)); + krk_push(krk_callSimple(OBJECT_VAL(objectClass->_getattr), 2, 0)); + return 1; + } + return 0; } diff --git a/vm.h b/vm.h index 0feb61e..ddcaf06 100644 --- a/vm.h +++ b/vm.h @@ -43,6 +43,8 @@ typedef enum { METHOD_EXIT, METHOD_DELITEM, METHOD_ITER, + METHOD_GETATTR, + METHOD_DIR, METHOD__MAX, } KrkSpecialMethods;