diff --git a/extmod/moductypes.c b/extmod/moductypes.c index 7e7128a269..f9f0ca79bc 100644 --- a/extmod/moductypes.c +++ b/extmod/moductypes.c @@ -482,13 +482,17 @@ STATIC mp_obj_t uctypes_struct_attr_op(mp_obj_t self_in, qstr attr, mp_obj_t set return MP_OBJ_NULL; } -STATIC void uctypes_struct_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { - mp_obj_t val = uctypes_struct_attr_op(self_in, attr, MP_OBJ_NULL); - *dest = val; -} - -STATIC bool uctypes_struct_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t val) { - return uctypes_struct_attr_op(self_in, attr, val) != MP_OBJ_NULL; +STATIC void uctypes_struct_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { + if (dest[0] == MP_OBJ_NULL) { + // load attribute + mp_obj_t val = uctypes_struct_attr_op(self_in, attr, MP_OBJ_NULL); + dest[0] = val; + } else { + // delete/store attribute + if (uctypes_struct_attr_op(self_in, attr, dest[1]) != MP_OBJ_NULL) { + dest[0] = MP_OBJ_NULL; // indicate success + } + } } STATIC mp_obj_t uctypes_struct_subscr(mp_obj_t self_in, mp_obj_t index_in, mp_obj_t value) { @@ -589,8 +593,7 @@ STATIC const mp_obj_type_t uctypes_struct_type = { .name = MP_QSTR_struct, .print = uctypes_struct_print, .make_new = uctypes_struct_make_new, - .load_attr = uctypes_struct_load_attr, - .store_attr = uctypes_struct_store_attr, + .attr = uctypes_struct_attr, .subscr = uctypes_struct_subscr, }; diff --git a/py/obj.h b/py/obj.h index 448db762af..a5423f0824 100644 --- a/py/obj.h +++ b/py/obj.h @@ -265,8 +265,7 @@ typedef mp_obj_t (*mp_make_new_fun_t)(mp_obj_t type_in, mp_uint_t n_args, mp_uin typedef mp_obj_t (*mp_call_fun_t)(mp_obj_t fun, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args); typedef mp_obj_t (*mp_unary_op_fun_t)(mp_uint_t op, mp_obj_t); typedef mp_obj_t (*mp_binary_op_fun_t)(mp_uint_t op, mp_obj_t, mp_obj_t); -typedef void (*mp_load_attr_fun_t)(mp_obj_t self_in, qstr attr, mp_obj_t *dest); // for fail, do nothing; for attr, dest[0] = value; for method, dest[0] = method, dest[1] = self -typedef bool (*mp_store_attr_fun_t)(mp_obj_t self_in, qstr attr, mp_obj_t value); // return true if store succeeded; if value==MP_OBJ_NULL then delete +typedef void (*mp_attr_fun_t)(mp_obj_t self_in, qstr attr, mp_obj_t *dest); typedef mp_obj_t (*mp_subscr_fun_t)(mp_obj_t self_in, mp_obj_t index, mp_obj_t value); typedef struct _mp_method_t { @@ -330,8 +329,18 @@ struct _mp_obj_type_t { mp_unary_op_fun_t unary_op; // can return MP_OBJ_NULL if op not supported mp_binary_op_fun_t binary_op; // can return MP_OBJ_NULL if op not supported - mp_load_attr_fun_t load_attr; - mp_store_attr_fun_t store_attr; // if value is MP_OBJ_NULL, then delete that attribute + // implements load, store and delete attribute + // + // dest[0] = MP_OBJ_NULL means load + // return: for fail, do nothing + // for attr, dest[0] = value + // for method, dest[0] = method, dest[1] = self + // + // dest[0,1] = {MP_OBJ_SENTINEL, MP_OBJ_NULL} means delete + // dest[0,1] = {MP_OBJ_SENTINEL, object} means store + // return: for fail, do nothing + // for success set dest[0] = MP_OBJ_NULL + mp_attr_fun_t attr; mp_subscr_fun_t subscr; // implements load, store, delete subscripting // value=MP_OBJ_NULL means delete, value=MP_OBJ_SENTINEL means load, else store diff --git a/py/objboundmeth.c b/py/objboundmeth.c index 84d201277f..0f9ff08c81 100644 --- a/py/objboundmeth.c +++ b/py/objboundmeth.c @@ -71,7 +71,11 @@ STATIC mp_obj_t bound_meth_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_ } #if MICROPY_PY_FUNCTION_ATTRS -STATIC void bound_meth_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { +STATIC void bound_meth_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { + if (dest[0] != MP_OBJ_NULL) { + // not load attribute + return; + } if (attr == MP_QSTR___name__) { mp_obj_bound_meth_t *o = self_in; dest[0] = MP_OBJ_NEW_QSTR(mp_obj_fun_get_name(o->meth)); @@ -87,7 +91,7 @@ STATIC const mp_obj_type_t mp_type_bound_meth = { #endif .call = bound_meth_call, #if MICROPY_PY_FUNCTION_ATTRS - .load_attr = bound_meth_load_attr, + .attr = bound_meth_attr, #endif }; diff --git a/py/objcomplex.c b/py/objcomplex.c index 1415068438..f4a68851a5 100644 --- a/py/objcomplex.c +++ b/py/objcomplex.c @@ -141,7 +141,11 @@ STATIC mp_obj_t complex_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_in return mp_obj_complex_binary_op(op, lhs->real, lhs->imag, rhs_in); } -STATIC void complex_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { +STATIC void complex_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { + if (dest[0] != MP_OBJ_NULL) { + // not load attribute + return; + } mp_obj_complex_t *self = self_in; if (attr == MP_QSTR_real) { dest[0] = mp_obj_new_float(self->real); @@ -157,7 +161,7 @@ const mp_obj_type_t mp_type_complex = { .make_new = complex_make_new, .unary_op = complex_unary_op, .binary_op = complex_binary_op, - .load_attr = complex_load_attr, + .attr = complex_attr, }; mp_obj_t mp_obj_new_complex(mp_float_t real, mp_float_t imag) { diff --git a/py/objexcept.c b/py/objexcept.c index 987a54fda7..2d23f160a2 100644 --- a/py/objexcept.c +++ b/py/objexcept.c @@ -140,7 +140,11 @@ mp_obj_t mp_obj_exception_get_value(mp_obj_t self_in) { } } -STATIC void exception_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { +STATIC void exception_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { + if (dest[0] != MP_OBJ_NULL) { + // not load attribute + return; + } mp_obj_exception_t *self = self_in; if (attr == MP_QSTR_args) { dest[0] = self->args; @@ -168,7 +172,7 @@ const mp_obj_type_t mp_type_BaseException = { .name = MP_QSTR_BaseException, .print = mp_obj_exception_print, .make_new = mp_obj_exception_make_new, - .load_attr = exception_load_attr, + .attr = exception_attr, .locals_dict = (mp_obj_t)&exc_locals_dict, }; @@ -181,7 +185,7 @@ const mp_obj_type_t mp_type_ ## exc_name = { \ .name = MP_QSTR_ ## exc_name, \ .print = mp_obj_exception_print, \ .make_new = mp_obj_exception_make_new, \ - .load_attr = exception_load_attr, \ + .attr = exception_attr, \ .bases_tuple = (mp_obj_t)&mp_type_ ## base_name ## _base_tuple, \ }; diff --git a/py/objfun.c b/py/objfun.c index 76adfef500..f00a90a089 100644 --- a/py/objfun.c +++ b/py/objfun.c @@ -296,7 +296,11 @@ STATIC mp_obj_t fun_bc_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, } #if MICROPY_PY_FUNCTION_ATTRS -STATIC void fun_bc_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { +STATIC void fun_bc_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { + if (dest[0] != MP_OBJ_NULL) { + // not load attribute + return; + } if (attr == MP_QSTR___name__) { dest[0] = MP_OBJ_NEW_QSTR(mp_obj_fun_get_name(self_in)); } @@ -311,7 +315,7 @@ const mp_obj_type_t mp_type_fun_bc = { #endif .call = fun_bc_call, #if MICROPY_PY_FUNCTION_ATTRS - .load_attr = fun_bc_load_attr, + .attr = fun_bc_attr, #endif }; diff --git a/py/objmodule.c b/py/objmodule.c index 02292ff785..971c7f38c5 100644 --- a/py/objmodule.c +++ b/py/objmodule.c @@ -51,48 +51,48 @@ STATIC void module_print(void (*print)(void *env, const char *fmt, ...), void *e print(env, "", name); } -STATIC void module_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { +STATIC void module_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { mp_obj_module_t *self = self_in; - mp_map_elem_t *elem = mp_map_lookup(&self->globals->map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP); - if (elem != NULL) { - dest[0] = elem->value; - } -} - -STATIC bool module_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) { - mp_obj_module_t *self = self_in; - mp_obj_dict_t *dict = self->globals; - if (dict->map.is_fixed) { - #if MICROPY_CAN_OVERRIDE_BUILTINS - if (dict == &mp_module_builtins_globals) { - if (MP_STATE_VM(mp_module_builtins_override_dict) == NULL) { - MP_STATE_VM(mp_module_builtins_override_dict) = mp_obj_new_dict(1); - } - dict = MP_STATE_VM(mp_module_builtins_override_dict); - } else - #endif - { - // can't delete or store to fixed map - return false; + if (dest[0] == MP_OBJ_NULL) { + // load attribute + mp_map_elem_t *elem = mp_map_lookup(&self->globals->map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP); + if (elem != NULL) { + dest[0] = elem->value; } - } - if (value == MP_OBJ_NULL) { - // delete attribute - mp_obj_dict_delete(dict, MP_OBJ_NEW_QSTR(attr)); } else { - // store attribute - // TODO CPython allows STORE_ATTR to a module, but is this the correct implementation? - mp_obj_dict_store(dict, MP_OBJ_NEW_QSTR(attr), value); + // delete/store attribute + mp_obj_dict_t *dict = self->globals; + if (dict->map.is_fixed) { + #if MICROPY_CAN_OVERRIDE_BUILTINS + if (dict == &mp_module_builtins_globals) { + if (MP_STATE_VM(mp_module_builtins_override_dict) == NULL) { + MP_STATE_VM(mp_module_builtins_override_dict) = mp_obj_new_dict(1); + } + dict = MP_STATE_VM(mp_module_builtins_override_dict); + } else + #endif + { + // can't delete or store to fixed map + return; + } + } + if (dest[1] == MP_OBJ_NULL) { + // delete attribute + mp_obj_dict_delete(dict, MP_OBJ_NEW_QSTR(attr)); + } else { + // store attribute + // TODO CPython allows STORE_ATTR to a module, but is this the correct implementation? + mp_obj_dict_store(dict, MP_OBJ_NEW_QSTR(attr), dest[1]); + } + dest[0] = MP_OBJ_NULL; // indicate success } - return true; } const mp_obj_type_t mp_type_module = { { &mp_type_type }, .name = MP_QSTR_module, .print = module_print, - .load_attr = module_load_attr, - .store_attr = module_store_attr, + .attr = module_attr, }; mp_obj_t mp_obj_new_module(qstr module_name) { diff --git a/py/objnamedtuple.c b/py/objnamedtuple.c index 1996b41219..9cc6da1b7a 100644 --- a/py/objnamedtuple.c +++ b/py/objnamedtuple.c @@ -68,20 +68,20 @@ STATIC void namedtuple_print(void (*print)(void *env, const char *fmt, ...), voi print(env, ")"); } -STATIC void namedtuple_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { - mp_obj_namedtuple_t *self = self_in; - int id = namedtuple_find_field((mp_obj_namedtuple_type_t*)self->tuple.base.type, attr); - if (id == -1) { - return; +STATIC void namedtuple_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { + if (dest[0] == MP_OBJ_NULL) { + // load attribute + mp_obj_namedtuple_t *self = self_in; + int id = namedtuple_find_field((mp_obj_namedtuple_type_t*)self->tuple.base.type, attr); + if (id == -1) { + return; + } + dest[0] = self->tuple.items[id]; + } else { + // delete/store attribute + // provide more detailed error message than we'd get by just returning + nlr_raise(mp_obj_new_exception_msg(&mp_type_AttributeError, "can't set attribute")); } - dest[0] = self->tuple.items[id]; -} - -STATIC bool namedtuple_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) { - (void)self_in; - (void)attr; - (void)value; - nlr_raise(mp_obj_new_exception_msg(&mp_type_AttributeError, "can't set attribute")); } STATIC mp_obj_t namedtuple_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) { @@ -154,8 +154,7 @@ STATIC mp_obj_t mp_obj_new_namedtuple_type(qstr name, mp_uint_t n_fields, mp_obj o->base.make_new = namedtuple_make_new; o->base.unary_op = mp_obj_tuple_unary_op; o->base.binary_op = mp_obj_tuple_binary_op; - o->base.load_attr = namedtuple_load_attr; - o->base.store_attr = namedtuple_store_attr; + o->base.attr = namedtuple_attr; o->base.subscr = mp_obj_tuple_subscr; o->base.getiter = mp_obj_tuple_getiter; o->base.bases_tuple = (mp_obj_t)&namedtuple_base_tuple; diff --git a/py/objrange.c b/py/objrange.c index ff62cc5b81..9f7e6591e1 100644 --- a/py/objrange.c +++ b/py/objrange.c @@ -168,7 +168,11 @@ STATIC mp_obj_t range_getiter(mp_obj_t o_in) { #if MICROPY_PY_BUILTINS_RANGE_ATTRS -STATIC void range_load_attr(mp_obj_t o_in, qstr attr, mp_obj_t *dest) { +STATIC void range_attr(mp_obj_t o_in, qstr attr, mp_obj_t *dest) { + if (dest[0] != MP_OBJ_NULL) { + // not load attribute + return; + } mp_obj_range_t *o = o_in; if (attr == MP_QSTR_start) { dest[0] = mp_obj_new_int(o->start); @@ -189,6 +193,6 @@ const mp_obj_type_t mp_type_range = { .subscr = range_subscr, .getiter = range_getiter, #if MICROPY_PY_BUILTINS_RANGE_ATTRS - .load_attr = range_load_attr, + .attr = range_attr, #endif }; diff --git a/py/objtype.c b/py/objtype.c index a5fb17f2ce..cb7110572d 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -440,7 +440,7 @@ STATIC mp_obj_t instance_binary_op(mp_uint_t op, mp_obj_t lhs_in, mp_obj_t rhs_i } } -void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { +STATIC void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { // logic: look in instance members then class locals assert(is_instance_type(mp_obj_get_type(self_in))); mp_obj_instance_t *self = self_in; @@ -512,7 +512,7 @@ void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { } } -bool mp_obj_instance_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) { +STATIC bool mp_obj_instance_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) { mp_obj_instance_t *self = self_in; #if MICROPY_PY_BUILTINS_PROPERTY || MICROPY_PY_DESCRIPTORS @@ -602,6 +602,16 @@ bool mp_obj_instance_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) { } } +void mp_obj_instance_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { + if (dest[0] == MP_OBJ_NULL) { + mp_obj_instance_load_attr(self_in, attr, dest); + } else { + if (mp_obj_instance_store_attr(self_in, attr, dest[1])) { + dest[0] = MP_OBJ_NULL; // indicate success + } + } +} + STATIC mp_obj_t instance_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) { mp_obj_instance_t *self = self_in; mp_obj_t member[2] = {MP_OBJ_NULL}; @@ -774,52 +784,52 @@ STATIC mp_obj_t type_call(mp_obj_t self_in, mp_uint_t n_args, mp_uint_t n_kw, co return o; } -// for fail, do nothing; for attr, dest[0] = value; for method, dest[0] = method, dest[1] = self -STATIC void type_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { - assert(MP_OBJ_IS_TYPE(self_in, &mp_type_type)); - mp_obj_type_t *self = self_in; -#if MICROPY_CPYTHON_COMPAT - if (attr == MP_QSTR___name__) { - dest[0] = MP_OBJ_NEW_QSTR(self->name); - return; - } -#endif - struct class_lookup_data lookup = { - .obj = self_in, - .attr = attr, - .meth_offset = 0, - .dest = dest, - .is_type = true, - }; - mp_obj_class_lookup(&lookup, self); -} - -STATIC bool type_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) { +STATIC void type_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { assert(MP_OBJ_IS_TYPE(self_in, &mp_type_type)); mp_obj_type_t *self = self_in; - // TODO CPython allows STORE_ATTR to a class, but is this the correct implementation? + if (dest[0] == MP_OBJ_NULL) { + // load attribute + #if MICROPY_CPYTHON_COMPAT + if (attr == MP_QSTR___name__) { + dest[0] = MP_OBJ_NEW_QSTR(self->name); + return; + } + #endif + struct class_lookup_data lookup = { + .obj = self_in, + .attr = attr, + .meth_offset = 0, + .dest = dest, + .is_type = true, + }; + mp_obj_class_lookup(&lookup, self); + } else { + // delete/store attribute - if (self->locals_dict != NULL) { - assert(MP_OBJ_IS_TYPE(self->locals_dict, &mp_type_dict)); // Micro Python restriction, for now - mp_map_t *locals_map = mp_obj_dict_get_map(self->locals_dict); - if (value == MP_OBJ_NULL) { - // delete attribute - mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_REMOVE_IF_FOUND); - // note that locals_map may be in ROM, so remove will fail in that case - return elem != NULL; - } else { - // store attribute - mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); - // note that locals_map may be in ROM, so add will fail in that case - if (elem != NULL) { - elem->value = value; - return true; + // TODO CPython allows STORE_ATTR to a class, but is this the correct implementation? + + if (self->locals_dict != NULL) { + assert(MP_OBJ_IS_TYPE(self->locals_dict, &mp_type_dict)); // Micro Python restriction, for now + mp_map_t *locals_map = mp_obj_dict_get_map(self->locals_dict); + if (dest[1] == MP_OBJ_NULL) { + // delete attribute + mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_REMOVE_IF_FOUND); + // note that locals_map may be in ROM, so remove will fail in that case + if (elem != NULL) { + dest[0] = MP_OBJ_NULL; // indicate success + } + } else { + // store attribute + mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND); + // note that locals_map may be in ROM, so add will fail in that case + if (elem != NULL) { + elem->value = dest[1]; + dest[0] = MP_OBJ_NULL; // indicate success + } } } } - - return false; } const mp_obj_type_t mp_type_type = { @@ -828,8 +838,7 @@ const mp_obj_type_t mp_type_type = { .print = type_print, .make_new = type_make_new, .call = type_call, - .load_attr = type_load_attr, - .store_attr = type_store_attr, + .attr = type_attr, }; mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) { @@ -865,8 +874,7 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) o->call = mp_obj_instance_call; o->unary_op = instance_unary_op; o->binary_op = instance_binary_op; - o->load_attr = mp_obj_instance_load_attr; - o->store_attr = mp_obj_instance_store_attr; + o->attr = mp_obj_instance_attr; o->subscr = instance_subscr; o->getiter = instance_getiter; //o->iternext = ; not implemented @@ -921,8 +929,12 @@ STATIC mp_obj_t super_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_k return mp_obj_new_super(args[0], args[1]); } -// for fail, do nothing; for attr, dest[0] = value; for method, dest[0] = method, dest[1] = self -STATIC void super_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { +STATIC void super_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { + if (dest[0] != MP_OBJ_NULL) { + // not load attribute + return; + } + assert(MP_OBJ_IS_TYPE(self_in, &mp_type_super)); mp_obj_super_t *self = self_in; @@ -960,7 +972,7 @@ const mp_obj_type_t mp_type_super = { .name = MP_QSTR_super, .print = super_print, .make_new = super_make_new, - .load_attr = super_load_attr, + .attr = super_attr, }; mp_obj_t mp_obj_new_super(mp_obj_t type, mp_obj_t obj) { diff --git a/py/objtype.h b/py/objtype.h index 176e802d24..de1909b1e1 100644 --- a/py/objtype.h +++ b/py/objtype.h @@ -37,9 +37,8 @@ typedef struct _mp_obj_instance_t { // TODO maybe cache __getattr__ and __setattr__ for efficient lookup of them } mp_obj_instance_t; -// these need to be exposed for MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE to work -void mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest); -bool mp_obj_instance_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value); +// this needs to be exposed for MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE to work +void mp_obj_instance_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest); // these need to be exposed so mp_obj_is_callable can work correctly bool mp_obj_instance_is_callable(mp_obj_t self_in); diff --git a/py/runtime.c b/py/runtime.c index 2bb9a02641..b04a4af139 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -917,9 +917,9 @@ void mp_load_method_maybe(mp_obj_t obj, qstr attr, mp_obj_t *dest) { dest[0] = (mp_obj_t)&mp_builtin_next_obj; dest[1] = obj; - } else if (type->load_attr != NULL) { + } else if (type->attr != NULL) { // this type can do its own load, so call it - type->load_attr(obj, attr, dest); + type->attr(obj, attr, dest); } else if (type->locals_dict != NULL) { // generic method lookup @@ -961,8 +961,11 @@ void mp_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest) { void mp_store_attr(mp_obj_t base, qstr attr, mp_obj_t value) { DEBUG_OP_printf("store attr %p.%s <- %p\n", base, qstr_str(attr), value); mp_obj_type_t *type = mp_obj_get_type(base); - if (type->store_attr != NULL) { - if (type->store_attr(base, attr, value)) { + if (type->attr != NULL) { + mp_obj_t dest[2] = {MP_OBJ_SENTINEL, value}; + type->attr(base, attr, dest); + if (dest[0] == MP_OBJ_NULL) { + // success return; } } diff --git a/py/vm.c b/py/vm.c index d81f5580e2..55203b0748 100644 --- a/py/vm.c +++ b/py/vm.c @@ -315,7 +315,7 @@ dispatch_loop: MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; mp_obj_t top = TOP(); - if (mp_obj_get_type(top)->load_attr == mp_obj_instance_load_attr) { + if (mp_obj_get_type(top)->attr == mp_obj_instance_attr) { mp_obj_instance_t *self = top; mp_uint_t x = *ip; mp_obj_t key = MP_OBJ_NEW_QSTR(qst); @@ -405,7 +405,7 @@ dispatch_loop: MARK_EXC_IP_SELECTIVE(); DECODE_QSTR; mp_obj_t top = TOP(); - if (mp_obj_get_type(top)->store_attr == mp_obj_instance_store_attr && sp[-1] != MP_OBJ_NULL) { + if (mp_obj_get_type(top)->attr == mp_obj_instance_attr && sp[-1] != MP_OBJ_NULL) { mp_obj_instance_t *self = top; mp_uint_t x = *ip; mp_obj_t key = MP_OBJ_NEW_QSTR(qst);