blob: e5d23af2d50b25cd75be5f1b3fd2a78c5a214240 [file] [log] [blame]
Damiend99b0522013-12-21 18:17:45 +00001#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
13typedef 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/*
20type 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
29mp_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
50void 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
80void 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
91const 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
103mp_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}