summaryrefslogtreecommitdiffstatshomepage
path: root/py/objtype.c
diff options
context:
space:
mode:
authorDamien George <damien.p.george@gmail.com>2014-01-11 19:22:29 +0000
committerDamien George <damien.p.george@gmail.com>2014-01-11 19:22:29 +0000
commiteae16445d5f6ca4bcd693422fc93ccf4fd7e215e (patch)
treec07206dcad354d366c1a42d6fa81d6a1868de2e1 /py/objtype.c
parentbcbeea0a477ed977a668e67f6f5402260d26ceb9 (diff)
downloadmicropython-eae16445d5f6ca4bcd693422fc93ccf4fd7e215e.tar.gz
micropython-eae16445d5f6ca4bcd693422fc93ccf4fd7e215e.zip
py: Implement staticmethod and classmethod (internally).
Still need to make built-ins by these names, and write tests.
Diffstat (limited to 'py/objtype.c')
-rw-r--r--py/objtype.c74
1 files changed, 59 insertions, 15 deletions
diff --git a/py/objtype.c b/py/objtype.c
index 6c89c1ff2b..011ee43552 100644
--- a/py/objtype.c
+++ b/py/objtype.c
@@ -27,15 +27,13 @@ static mp_obj_t mp_obj_new_class(mp_obj_t class) {
return o;
}
-static mp_map_elem_t *mp_obj_class_lookup(mp_obj_t self_in, qstr attr, mp_map_lookup_kind_t lookup_kind) {
+static mp_map_elem_t *mp_obj_class_lookup(const mp_obj_type_t *type, qstr attr, mp_map_lookup_kind_t lookup_kind) {
for (;;) {
- assert(MP_OBJ_IS_TYPE(self_in, &mp_const_type));
- mp_obj_type_t *self = self_in;
- if (self->locals_dict == NULL) {
+ if (type->locals_dict == NULL) {
return NULL;
}
- assert(MP_OBJ_IS_TYPE(self->locals_dict, &dict_type)); // Micro Python restriction, for now
- mp_map_t *locals_map = ((void*)self->locals_dict + sizeof(mp_obj_base_t)); // XXX hack to get map object from dict object
+ assert(MP_OBJ_IS_TYPE(type->locals_dict, &dict_type)); // Micro Python restriction, for now
+ mp_map_t *locals_map = ((void*)type->locals_dict + sizeof(mp_obj_base_t)); // XXX hack to get map object from dict object
mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), lookup_kind);
if (elem != NULL) {
return elem;
@@ -44,25 +42,27 @@ static mp_map_elem_t *mp_obj_class_lookup(mp_obj_t self_in, qstr attr, mp_map_lo
// attribute not found, keep searching base classes
// for a const struct, this entry might be NULL
- if (self->bases_tuple == MP_OBJ_NULL) {
+ if (type->bases_tuple == MP_OBJ_NULL) {
return NULL;
}
uint len;
mp_obj_t *items;
- mp_obj_tuple_get(self->bases_tuple, &len, &items);
+ mp_obj_tuple_get(type->bases_tuple, &len, &items);
if (len == 0) {
return NULL;
}
for (uint i = 0; i < len - 1; i++) {
- elem = mp_obj_class_lookup(items[i], attr, lookup_kind);
+ assert(MP_OBJ_IS_TYPE(items[i], &mp_const_type));
+ elem = mp_obj_class_lookup((mp_obj_type_t*)items[i], attr, lookup_kind);
if (elem != NULL) {
return elem;
}
}
// search last base (simple tail recursion elimination)
- self_in = items[len - 1];
+ assert(MP_OBJ_IS_TYPE(items[len - 1], &mp_const_type));
+ type = (mp_obj_type_t*)items[len - 1];
}
}
@@ -73,11 +73,12 @@ static void class_print(void (*print)(void *env, const char *fmt, ...), void *en
// args are reverse in the array
static mp_obj_t class_make_new(mp_obj_t self_in, int n_args, const mp_obj_t *args) {
assert(MP_OBJ_IS_TYPE(self_in, &mp_const_type));
+ mp_obj_type_t *self = self_in;
mp_obj_t o = mp_obj_new_class(self_in);
// look for __init__ function
- mp_map_elem_t *init_fn = mp_obj_class_lookup(self_in, MP_QSTR___init__, MP_MAP_LOOKUP);
+ mp_map_elem_t *init_fn = mp_obj_class_lookup(self, MP_QSTR___init__, MP_MAP_LOOKUP);
if (init_fn != NULL) {
// call __init__ function
@@ -114,7 +115,7 @@ static void class_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
dest[1] = elem->value;
return;
}
- elem = mp_obj_class_lookup((mp_obj_t)self->base.type, attr, MP_MAP_LOOKUP);
+ elem = mp_obj_class_lookup(self->base.type, attr, MP_MAP_LOOKUP);
if (elem != NULL) {
if (mp_obj_is_callable(elem->value)) {
// class member is callable so build a bound method
@@ -132,7 +133,7 @@ static void class_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
static bool class_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) {
// logic: look in class locals (no add) then obj members (add) (TODO check this against CPython)
mp_obj_class_t *self = self_in;
- mp_map_elem_t *elem = mp_obj_class_lookup((mp_obj_t)self->base.type, attr, MP_MAP_LOOKUP);
+ mp_map_elem_t *elem = mp_obj_class_lookup(self->base.type, attr, MP_MAP_LOOKUP);
if (elem != NULL) {
elem->value = value;
} else {
@@ -188,17 +189,47 @@ static mp_obj_t type_call_n(mp_obj_t self_in, int n_args, const mp_obj_t *args)
// for fail, do nothing; for attr, dest[1] = value; for method, dest[0] = self, dest[1] = method
static void type_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
- mp_map_elem_t *elem = mp_obj_class_lookup(self_in, attr, MP_MAP_LOOKUP);
+ assert(MP_OBJ_IS_TYPE(self_in, &mp_const_type));
+ mp_obj_type_t *self = self_in;
+ mp_map_elem_t *elem = mp_obj_class_lookup(self, attr, MP_MAP_LOOKUP);
if (elem != NULL) {
dest[1] = elem->value;
return;
}
+
+ // generic method lookup
+ // this is a lookup in the class itself (ie not the classes type or instance)
+ const mp_method_t *meth = self->methods;
+ if (meth != NULL) {
+ for (; meth->name != NULL; meth++) {
+ if (strcmp(meth->name, qstr_str(attr)) == 0) {
+ // check if the methods are functions, static or class methods
+ // see http://docs.python.org/3.3/howto/descriptor.html
+ if (MP_OBJ_IS_TYPE(meth->fun, &mp_type_staticmethod)) {
+ // return just the function
+ dest[1] = ((mp_obj_staticmethod_t*)meth->fun)->fun;
+ } else if (MP_OBJ_IS_TYPE(meth->fun, &mp_type_classmethod)) {
+ // return a bound method, with self being this class
+ dest[1] = ((mp_obj_classmethod_t*)meth->fun)->fun;
+ dest[0] = self_in;
+ } else {
+ // return just the function
+ // TODO need to wrap in a type check for the first argument; eg list.append(1,1) needs to throw an exception
+ dest[1] = (mp_obj_t)meth->fun;
+ }
+ return;
+ }
+ }
+ }
}
static bool type_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) {
+ assert(MP_OBJ_IS_TYPE(self_in, &mp_const_type));
+ mp_obj_type_t *self = self_in;
+
// TODO CPython allows STORE_ATTR to a class, but is this the correct implementation?
- mp_map_elem_t *elem = mp_obj_class_lookup(self_in, attr, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
+ mp_map_elem_t *elem = mp_obj_class_lookup(self, attr, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
if (elem != NULL) {
elem->value = value;
return true;
@@ -284,3 +315,16 @@ static mp_obj_t mp_builtin_isinstance(mp_obj_t object, mp_obj_t classinfo) {
}
MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_isinstance_obj, mp_builtin_isinstance);
+
+/******************************************************************************/
+// staticmethod and classmethod types (probably should go in a different file)
+
+const mp_obj_type_t mp_type_staticmethod = {
+ { &mp_const_type },
+ "staticmethod",
+};
+
+const mp_obj_type_t mp_type_classmethod = {
+ { &mp_const_type },
+ "classmethod",
+};