eb7bfcb286
Qstr's are now split into a linked-list of qstr pools. This has 2 benefits: the first pool can be in ROM (huge benefit, since we no longer use RAM for the core qstrs), and subsequent pools use m_new for the next pool instead of m_renew (thus avoiding a huge single table for all the qstrs). Still would be better to use a hash table, but this scheme takes us part of the way (eventually convert the pools to hash tables). Also fixed bug with import. Also improved the way the module code is referenced (not magic number 1 anymore).
111 lines
3.6 KiB
C
111 lines
3.6 KiB
C
#include <stdlib.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
|
|
#include "nlr.h"
|
|
#include "misc.h"
|
|
#include "mpconfig.h"
|
|
#include "mpqstr.h"
|
|
#include "obj.h"
|
|
#include "runtime.h"
|
|
#include "map.h"
|
|
|
|
typedef struct _mp_obj_instance_t {
|
|
mp_obj_base_t base;
|
|
mp_obj_base_t *class; // points to a "class" object
|
|
mp_map_t *members;
|
|
} mp_obj_instance_t;
|
|
|
|
/*
|
|
type needs to be specified dynamically
|
|
case O_OBJ:
|
|
{
|
|
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);
|
|
assert(IS_O(qn->value, O_STR));
|
|
return qstr_str(((py_obj_base_t*)qn->value)->u_str);
|
|
}
|
|
*/
|
|
|
|
mp_obj_t mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr) {
|
|
// logic: look in obj members then class locals (TODO check this against CPython)
|
|
mp_obj_instance_t *self = self_in;
|
|
mp_map_elem_t *elem = mp_qstr_map_lookup(self->members, attr, false);
|
|
if (elem != NULL) {
|
|
// object member, always treated as a value
|
|
return elem->value;
|
|
}
|
|
elem = mp_qstr_map_lookup(mp_obj_class_get_locals(self->class), attr, false);
|
|
if (elem != NULL) {
|
|
if (mp_obj_is_callable(elem->value)) {
|
|
// class member is callable so build a bound method
|
|
return mp_obj_new_bound_meth(self_in, elem->value);
|
|
} else {
|
|
// class member is a value, so just return that value
|
|
return elem->value;
|
|
}
|
|
}
|
|
nlr_jump(mp_obj_new_exception_msg_2_args(MP_QSTR_AttributeError, "'%s' object has no attribute '%s'", mp_obj_get_type_str(self_in), qstr_str(attr)));
|
|
}
|
|
|
|
void mp_obj_instance_load_method(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
|
|
// logic: look in obj members then class locals (TODO check this against CPython)
|
|
mp_obj_instance_t *self = self_in;
|
|
mp_map_elem_t *elem = mp_qstr_map_lookup(self->members, attr, false);
|
|
if (elem != NULL) {
|
|
// object member, always treated as a value
|
|
dest[1] = elem->value;
|
|
dest[0] = NULL;
|
|
return;
|
|
}
|
|
elem = mp_qstr_map_lookup(mp_obj_class_get_locals(self->class), attr, false);
|
|
if (elem != NULL) {
|
|
if (mp_obj_is_callable(elem->value)) {
|
|
// class member is callable so build a bound method
|
|
dest[1] = elem->value;
|
|
dest[0] = self_in;
|
|
return;
|
|
} else {
|
|
// class member is a value, so just return that value
|
|
dest[1] = elem->value;
|
|
dest[0] = NULL;
|
|
return;
|
|
}
|
|
}
|
|
|
|
// no such method, so fall back to load attr
|
|
dest[1] = rt_load_attr(self_in, attr);
|
|
dest[0] = NULL;
|
|
}
|
|
|
|
void mp_obj_instance_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_instance_t *self = self_in;
|
|
mp_map_elem_t *elem = mp_qstr_map_lookup(mp_obj_class_get_locals(self->class), attr, false);
|
|
if (elem != NULL) {
|
|
elem->value = value;
|
|
} else {
|
|
mp_qstr_map_lookup(self->members, attr, true)->value = value;
|
|
}
|
|
}
|
|
|
|
const mp_obj_type_t instance_type = {
|
|
{ &mp_const_type },
|
|
"instance",
|
|
NULL, // print
|
|
NULL, // call_n
|
|
NULL, // unary_op
|
|
NULL, // binary_op
|
|
NULL, // getiter
|
|
NULL, // iternext
|
|
{{NULL, NULL},}, // method list
|
|
};
|
|
|
|
mp_obj_t mp_obj_new_instance(mp_obj_t class) {
|
|
mp_obj_instance_t *o = m_new_obj(mp_obj_instance_t);
|
|
o->base.type = &instance_type;
|
|
o->class = class;
|
|
o->members = mp_map_new(MP_MAP_QSTR, 0);
|
|
return o;
|
|
}
|