Damien | d99b052 | 2013-12-21 18:17:45 +0000 | [diff] [blame^] | 1 | #include <stdlib.h> |
| 2 | #include <stdint.h> |
| 3 | #include <string.h> |
| 4 | #include <assert.h> |
| 5 | |
| 6 | #include "nlr.h" |
| 7 | #include "misc.h" |
| 8 | #include "mpconfig.h" |
| 9 | #include "obj.h" |
| 10 | #include "runtime.h" |
| 11 | #include "map.h" |
| 12 | |
| 13 | typedef struct _mp_obj_instance_t { |
| 14 | mp_obj_base_t base; |
| 15 | mp_obj_base_t *class; // points to a "class" object |
| 16 | mp_map_t *members; |
| 17 | } mp_obj_instance_t; |
| 18 | |
| 19 | /* |
| 20 | type needs to be specified dynamically |
| 21 | case O_OBJ: |
| 22 | { |
| 23 | py_map_elem_t *qn = py_qstr_map_lookup(o->u_obj.class->u_class.locals, qstr_from_str_static("__qualname__"), false); assert(qn != NULL); |
| 24 | assert(IS_O(qn->value, O_STR)); |
| 25 | return qstr_str(((py_obj_base_t*)qn->value)->u_str); |
| 26 | } |
| 27 | */ |
| 28 | |
| 29 | mp_obj_t mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr) { |
| 30 | // logic: look in obj members then class locals (TODO check this against CPython) |
| 31 | mp_obj_instance_t *self = self_in; |
| 32 | mp_map_elem_t *elem = mp_qstr_map_lookup(self->members, attr, false); |
| 33 | if (elem != NULL) { |
| 34 | // object member, always treated as a value |
| 35 | return elem->value; |
| 36 | } |
| 37 | elem = mp_qstr_map_lookup(mp_obj_class_get_locals(self->class), attr, false); |
| 38 | if (elem != NULL) { |
| 39 | if (mp_obj_is_callable(elem->value)) { |
| 40 | // class member is callable so build a bound method |
| 41 | return mp_obj_new_bound_meth(self_in, elem->value); |
| 42 | } else { |
| 43 | // class member is a value, so just return that value |
| 44 | return elem->value; |
| 45 | } |
| 46 | } |
| 47 | nlr_jump(mp_obj_new_exception_msg_2_args(rt_q_AttributeError, "'%s' object has no attribute '%s'", mp_obj_get_type_str(self_in), qstr_str(attr))); |
| 48 | } |
| 49 | |
| 50 | void mp_obj_instance_load_method(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { |
| 51 | // logic: look in obj members then class locals (TODO check this against CPython) |
| 52 | mp_obj_instance_t *self = self_in; |
| 53 | mp_map_elem_t *elem = mp_qstr_map_lookup(self->members, attr, false); |
| 54 | if (elem != NULL) { |
| 55 | // object member, always treated as a value |
| 56 | dest[1] = elem->value; |
| 57 | dest[0] = NULL; |
| 58 | return; |
| 59 | } |
| 60 | elem = mp_qstr_map_lookup(mp_obj_class_get_locals(self->class), attr, false); |
| 61 | if (elem != NULL) { |
| 62 | if (mp_obj_is_callable(elem->value)) { |
| 63 | // class member is callable so build a bound method |
| 64 | dest[1] = elem->value; |
| 65 | dest[0] = self_in; |
| 66 | return; |
| 67 | } else { |
| 68 | // class member is a value, so just return that value |
| 69 | dest[1] = elem->value; |
| 70 | dest[0] = NULL; |
| 71 | return; |
| 72 | } |
| 73 | } |
| 74 | |
| 75 | // no such method, so fall back to load attr |
| 76 | dest[1] = rt_load_attr(self_in, attr); |
| 77 | dest[0] = NULL; |
| 78 | } |
| 79 | |
| 80 | void mp_obj_instance_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) { |
| 81 | // logic: look in class locals (no add) then obj members (add) (TODO check this against CPython) |
| 82 | mp_obj_instance_t *self = self_in; |
| 83 | mp_map_elem_t *elem = mp_qstr_map_lookup(mp_obj_class_get_locals(self->class), attr, false); |
| 84 | if (elem != NULL) { |
| 85 | elem->value = value; |
| 86 | } else { |
| 87 | mp_qstr_map_lookup(self->members, attr, true)->value = value; |
| 88 | } |
| 89 | } |
| 90 | |
| 91 | const mp_obj_type_t instance_type = { |
| 92 | { &mp_const_type }, |
| 93 | "instance", |
| 94 | NULL, // print |
| 95 | NULL, // call_n |
| 96 | NULL, // unary_op |
| 97 | NULL, // binary_op |
| 98 | NULL, // getiter |
| 99 | NULL, // iternext |
| 100 | {{NULL, NULL},}, // method list |
| 101 | }; |
| 102 | |
| 103 | mp_obj_t mp_obj_new_instance(mp_obj_t class) { |
| 104 | mp_obj_instance_t *o = m_new_obj(mp_obj_instance_t); |
| 105 | o->base.type = &instance_type; |
| 106 | o->class = class; |
| 107 | o->members = mp_map_new(MP_MAP_QSTR, 0); |
| 108 | return o; |
| 109 | } |