diff --git a/py/obj.h b/py/obj.h index 2f4d441264..660ac6627c 100644 --- a/py/obj.h +++ b/py/obj.h @@ -66,11 +66,11 @@ typedef struct _mp_obj_base_t mp_obj_base_t; // These macros are used to declare and define constant staticmethond and classmethod objects // You can put "static" in front of the definitions to make them local -#define MP_DECLARE_CONST_STATICMETHOD_OBJ(obj_name) extern const mp_obj_staticmethod_t obj_name -#define MP_DECLARE_CONST_CLASSMETHOD_OBJ(obj_name) extern const mp_obj_classmethod_t obj_name +#define MP_DECLARE_CONST_STATICMETHOD_OBJ(obj_name) extern const mp_obj_static_class_method_t obj_name +#define MP_DECLARE_CONST_CLASSMETHOD_OBJ(obj_name) extern const mp_obj_static_class_method_t obj_name -#define MP_DEFINE_CONST_STATICMETHOD_OBJ(obj_name, fun_name) const mp_obj_staticmethod_t obj_name = {{&mp_type_staticmethod}, fun_name} -#define MP_DEFINE_CONST_CLASSMETHOD_OBJ(obj_name, fun_name) const mp_obj_classmethod_t obj_name = {{&mp_type_classmethod}, fun_name} +#define MP_DEFINE_CONST_STATICMETHOD_OBJ(obj_name, fun_name) const mp_obj_static_class_method_t obj_name = {{&mp_type_staticmethod}, fun_name} +#define MP_DEFINE_CONST_CLASSMETHOD_OBJ(obj_name, fun_name) const mp_obj_static_class_method_t obj_name = {{&mp_type_classmethod}, fun_name} // Need to declare this here so we are not dependent on map.h struct _mp_map_t; @@ -180,7 +180,6 @@ struct _mp_obj_type_t { abs float complex hash bool int none str equal int str - less int get_array_n tuple list unpack seq list tuple @@ -389,15 +388,11 @@ struct _mp_map_t *mp_obj_module_get_globals(mp_obj_t self_in); extern const mp_obj_type_t mp_type_staticmethod; extern const mp_obj_type_t mp_type_classmethod; -typedef struct _mp_obj_staticmethod_t { +// this structure is used for instances of both staticmethod and classmethod +typedef struct _mp_obj_static_class_method_t { mp_obj_base_t base; mp_obj_t fun; -} mp_obj_staticmethod_t; - -typedef struct _mp_obj_classmethod_t { - mp_obj_base_t base; - mp_obj_t fun; -} mp_obj_classmethod_t; +} mp_obj_static_class_method_t; // sequence helpers void mp_seq_multiply(const void *items, uint item_sz, uint len, uint times, void *dest); diff --git a/py/objtype.c b/py/objtype.c index 6934cb354d..6ff18b47bf 100644 --- a/py/objtype.c +++ b/py/objtype.c @@ -212,10 +212,10 @@ static void class_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { // TODO check that this is the correct place to have this logic if (MP_OBJ_IS_TYPE(member, &mp_type_staticmethod)) { // return just the function - dest[0] = ((mp_obj_staticmethod_t*)member)->fun; + dest[0] = ((mp_obj_static_class_method_t*)member)->fun; } else if (MP_OBJ_IS_TYPE(member, &mp_type_classmethod)) { // return a bound method, with self being the type of this object - dest[0] = ((mp_obj_classmethod_t*)member)->fun; + dest[0] = ((mp_obj_static_class_method_t*)member)->fun; dest[1] = mp_obj_get_type(self_in); } else { // return a bound method, with self being this object @@ -304,10 +304,10 @@ static void type_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { // see http://docs.python.org/3.3/howto/descriptor.html if (MP_OBJ_IS_TYPE(member, &mp_type_staticmethod)) { // return just the function - dest[0] = ((mp_obj_staticmethod_t*)member)->fun; + dest[0] = ((mp_obj_static_class_method_t*)member)->fun; } else if (MP_OBJ_IS_TYPE(member, &mp_type_classmethod)) { // return a bound method, with self being this class - dest[0] = ((mp_obj_classmethod_t*)member)->fun; + dest[0] = ((mp_obj_static_class_method_t*)member)->fun; dest[1] = self_in; } else { // return just the function @@ -417,10 +417,10 @@ static void super_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) { // TODO check that this is the correct place to have this logic if (MP_OBJ_IS_TYPE(member, &mp_type_staticmethod)) { // return just the function - dest[0] = ((mp_obj_staticmethod_t*)member)->fun; + dest[0] = ((mp_obj_static_class_method_t*)member)->fun; } else if (MP_OBJ_IS_TYPE(member, &mp_type_classmethod)) { // return a bound method, with self being the type of this object - dest[0] = ((mp_obj_classmethod_t*)member)->fun; + dest[0] = ((mp_obj_static_class_method_t*)member)->fun; dest[1] = mp_obj_get_type(self->obj); } else { // return a bound method, with self being this object @@ -507,12 +507,26 @@ MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_isinstance_obj, mp_builtin_isinstance); /******************************************************************************/ // staticmethod and classmethod types (probably should go in a different file) +static mp_obj_t static_class_method_make_new(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) { + assert(self_in == &mp_type_staticmethod || self_in == &mp_type_classmethod); + + if (n_args != 1 || n_kw != 0) { + nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "function takes 1 positional argument but %d were given", (void*)(machine_int_t)n_args)); + } + + mp_obj_static_class_method_t *o = m_new_obj(mp_obj_static_class_method_t); + *o = (mp_obj_static_class_method_t){{(mp_obj_type_t*)self_in}, args[0]}; + return o; +} + const mp_obj_type_t mp_type_staticmethod = { { &mp_const_type }, "staticmethod", + .make_new = static_class_method_make_new }; const mp_obj_type_t mp_type_classmethod = { { &mp_const_type }, "classmethod", + .make_new = static_class_method_make_new }; diff --git a/py/qstrdefs.h b/py/qstrdefs.h index dcd4ba42c0..b90c5023de 100644 --- a/py/qstrdefs.h +++ b/py/qstrdefs.h @@ -51,6 +51,7 @@ Q(bytearray) Q(bytes) Q(callable) Q(chr) +Q(classmethod) Q(complex) Q(dict) Q(dir) @@ -80,6 +81,7 @@ Q(range) Q(repr) Q(set) Q(sorted) +Q(staticmethod) Q(sum) Q(super) Q(str) diff --git a/py/runtime.c b/py/runtime.c index fc18c01510..6790da4e59 100644 --- a/py/runtime.c +++ b/py/runtime.c @@ -134,6 +134,9 @@ void rt_init(void) { mp_map_add_qstr(&map_builtins, MP_QSTR_type, (mp_obj_t)&mp_const_type); mp_map_add_qstr(&map_builtins, MP_QSTR_zip, (mp_obj_t)&zip_type); + mp_map_add_qstr(&map_builtins, MP_QSTR_classmethod, (mp_obj_t)&mp_type_classmethod); + mp_map_add_qstr(&map_builtins, MP_QSTR_staticmethod, (mp_obj_t)&mp_type_staticmethod); + mp_obj_t m_array = mp_obj_new_module(MP_QSTR_array); rt_store_attr(m_array, MP_QSTR_array, (mp_obj_t)&array_type); @@ -876,10 +879,10 @@ static void rt_load_method_maybe(mp_obj_t base, qstr attr, mp_obj_t *dest) { // 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[0] = ((mp_obj_staticmethod_t*)meth->fun)->fun; + dest[0] = ((mp_obj_static_class_method_t*)meth->fun)->fun; } else if (MP_OBJ_IS_TYPE(meth->fun, &mp_type_classmethod)) { // return a bound method, with self being the type of this object - dest[0] = ((mp_obj_classmethod_t*)meth->fun)->fun; + dest[0] = ((mp_obj_static_class_method_t*)meth->fun)->fun; dest[1] = mp_obj_get_type(base); } else { // return a bound method, with self being this object @@ -970,6 +973,8 @@ mp_obj_t rt_iternext(mp_obj_t o_in) { } mp_obj_t rt_import_name(qstr name, mp_obj_t fromlist, mp_obj_t level) { + DEBUG_printf("import name %s\n", qstr_str(name)); + // build args array mp_obj_t args[5]; args[0] = MP_OBJ_NEW_QSTR(name); @@ -983,6 +988,8 @@ mp_obj_t rt_import_name(qstr name, mp_obj_t fromlist, mp_obj_t level) { } mp_obj_t rt_import_from(mp_obj_t module, qstr name) { + DEBUG_printf("import from %p %s\n", module, qstr_str(name)); + mp_obj_t x = rt_load_attr(module, name); /* TODO convert AttributeError to ImportError if (fail) {