summaryrefslogtreecommitdiffstatshomepage
path: root/py
diff options
context:
space:
mode:
Diffstat (limited to 'py')
-rw-r--r--py/obj.c4
-rw-r--r--py/obj.h24
-rw-r--r--py/objdict.c120
-rw-r--r--py/objtype.c74
-rw-r--r--py/runtime.c17
5 files changed, 144 insertions, 95 deletions
diff --git a/py/obj.c b/py/obj.c
index dfb450fb8d..81b5c69f7a 100644
--- a/py/obj.c
+++ b/py/obj.c
@@ -231,7 +231,7 @@ uint mp_get_index(const mp_obj_type_t *type, machine_uint_t len, mp_obj_t index)
}
}
-// may return NULL
+// may return MP_OBJ_NULL
mp_obj_t mp_obj_len_maybe(mp_obj_t o_in) {
mp_small_int_t len = 0;
if (MP_OBJ_IS_TYPE(o_in, &str_type)) {
@@ -249,7 +249,7 @@ mp_obj_t mp_obj_len_maybe(mp_obj_t o_in) {
} else if (MP_OBJ_IS_TYPE(o_in, &dict_type)) {
len = mp_obj_dict_len(o_in);
} else {
- return NULL;
+ return MP_OBJ_NULL;
}
return MP_OBJ_NEW_SMALL_INT(len);
}
diff --git a/py/obj.h b/py/obj.h
index 8d236008ee..b92f1e2a7e 100644
--- a/py/obj.h
+++ b/py/obj.h
@@ -59,6 +59,15 @@ typedef struct _mp_obj_base_t mp_obj_base_t;
#define MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(obj_name, n_args_min, n_args_max, fun_name) MP_DEFINE_CONST_FUN_OBJ_VOID_PTR(obj_name, false, n_args_min, n_args_max, (mp_fun_var_t)fun_name)
#define MP_DEFINE_CONST_FUN_OBJ_KW(obj_name, fun_name) MP_DEFINE_CONST_FUN_OBJ_VOID_PTR(obj_name, true, 0, (~((machine_uint_t)0)), (mp_fun_kw_t)fun_name)
+// 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_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}
+
// Need to declare this here so we are not dependent on map.h
struct _mp_map_t;
struct _mp_map_elem_t;
@@ -316,3 +325,18 @@ extern const mp_obj_type_t gen_instance_type;
extern const mp_obj_type_t module_type;
mp_obj_t mp_obj_new_module(qstr module_name);
struct _mp_map_t *mp_obj_module_get_globals(mp_obj_t self_in);
+
+// staticmethod and classmethod types; defined here so we can make const versions
+
+extern const mp_obj_type_t mp_type_staticmethod;
+extern const mp_obj_type_t mp_type_classmethod;
+
+typedef struct _mp_obj_staticmethod_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;
diff --git a/py/objdict.c b/py/objdict.c
index 8902e1020c..6dbb1f316b 100644
--- a/py/objdict.c
+++ b/py/objdict.c
@@ -139,6 +139,35 @@ static mp_obj_t dict_copy(mp_obj_t self_in) {
}
static MP_DEFINE_CONST_FUN_OBJ_1(dict_copy_obj, dict_copy);
+// this is a classmethod
+static mp_obj_t dict_fromkeys(int n_args, const mp_obj_t *args) {
+ assert(2 <= n_args && n_args <= 3);
+ mp_obj_t iter = rt_getiter(args[1]);
+ mp_obj_t len = mp_obj_len_maybe(iter);
+ mp_obj_t value = mp_const_none;
+ mp_obj_t next = NULL;
+ mp_obj_dict_t *self = NULL;
+
+ if (n_args > 2) {
+ value = args[2];
+ }
+
+ if (len == MP_OBJ_NULL) {
+ /* object's type doesn't have a __len__ slot */
+ self = mp_obj_new_dict(0);
+ } else {
+ self = mp_obj_new_dict(MP_OBJ_SMALL_INT_VALUE(len));
+ }
+
+ while ((next = rt_iternext(iter)) != mp_const_stop_iteration) {
+ mp_map_lookup(&self->map, next, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;
+ }
+
+ return self;
+}
+static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(dict_fromkeys_fun_obj, 2, 3, dict_fromkeys);
+static MP_DEFINE_CONST_CLASSMETHOD_OBJ(dict_fromkeys_obj, (const mp_obj_t)&dict_fromkeys_fun_obj);
+
static mp_obj_t dict_get_helper(mp_map_t *self, mp_obj_t key, mp_obj_t deflt, mp_map_lookup_kind_t lookup_kind) {
mp_map_elem_t *elem = mp_map_lookup(self, key, lookup_kind);
mp_obj_t value;
@@ -280,23 +309,18 @@ static mp_obj_t dict_view_it_iternext(mp_obj_t self_in) {
if (next != NULL) {
switch (self->kind) {
- case MP_DICT_VIEW_ITEMS:
- {
- mp_obj_t items[] = {next->key, next->value};
- return mp_obj_new_tuple(2, items);
- }
- case MP_DICT_VIEW_KEYS:
- {
- return next->key;
- }
- case MP_DICT_VIEW_VALUES:
- {
- return next->value;
- }
- default:
- {
- assert(0); /* can't happen */
- }
+ case MP_DICT_VIEW_ITEMS:
+ {
+ mp_obj_t items[] = {next->key, next->value};
+ return mp_obj_new_tuple(2, items);
+ }
+ case MP_DICT_VIEW_KEYS:
+ return next->key;
+ case MP_DICT_VIEW_VALUES:
+ return next->value;
+ default:
+ assert(0); /* can't happen */
+ return mp_const_none;
}
} else {
return mp_const_stop_iteration;
@@ -320,7 +344,6 @@ static mp_obj_t dict_view_getiter(mp_obj_t view_in) {
return o;
}
-
static void dict_view_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in) {
assert(MP_OBJ_IS_TYPE(self_in, &dict_view_type));
mp_obj_dict_view_t *self = self_in;
@@ -354,7 +377,6 @@ mp_obj_t mp_obj_new_dict_view(mp_obj_dict_t *dict, mp_dict_view_kind_t kind) {
return o;
}
-
static mp_obj_t dict_view(mp_obj_t self_in, mp_dict_view_kind_t kind) {
assert(MP_OBJ_IS_TYPE(self_in, &dict_type));
mp_obj_dict_t *self = self_in;
@@ -376,67 +398,13 @@ static mp_obj_t dict_values(mp_obj_t self_in) {
}
static MP_DEFINE_CONST_FUN_OBJ_1(dict_values_obj, dict_values);
-
-/******************************************************************************/
-/* dict metaclass */
-
-static mp_obj_t dict_fromkeys(int n_args, const mp_obj_t *args) {
- assert(2 <= n_args && n_args <= 3);
- mp_obj_t iter = rt_getiter(args[1]);
- mp_obj_t len = mp_obj_len_maybe(iter);
- mp_obj_t value = mp_const_none;
- mp_obj_t next = NULL;
- mp_obj_dict_t *self = NULL;
-
- if (n_args > 2) {
- value = args[2];
- }
-
- if (len == NULL) {
- /* object's type doesn't have a __len__ slot */
- self = mp_obj_new_dict(0);
- } else {
- self = mp_obj_new_dict(MP_OBJ_SMALL_INT_VALUE(len));
- }
-
- while ((next = rt_iternext(iter)) != mp_const_stop_iteration) {
- mp_map_lookup(&self->map, next, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;
- }
-
- return self;
-}
-static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(dict_fromkeys_obj, 2, 3, dict_fromkeys);
-
-static const mp_method_t dict_class_methods[] = {
- { "fromkeys", &dict_fromkeys_obj },
- { NULL, NULL }, // end-of-list sentinel
-};
-
-/* this should be unnecessary when inheritance works */
-static void dict_class_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in) {
- print(env, "<class 'dict'>");
-}
-
-/* this should be unnecessary when inheritance works */
-static mp_obj_t dict_class_call_n(mp_obj_t self_in, int n_args, const mp_obj_t *args) {
- return rt_build_map(0);
-}
-
-static const mp_obj_type_t dict_class = {
- { &mp_const_type },
- "dict_class",
- .print = dict_class_print,
- .methods = dict_class_methods,
- .call_n = dict_class_call_n,
-};
-
-
/******************************************************************************/
-/* dict constructors & etc */
+/* dict constructors & public C API */
static const mp_method_t dict_type_methods[] = {
{ "clear", &dict_clear_obj },
{ "copy", &dict_copy_obj },
+ { "fromkeys", &dict_fromkeys_obj },
{ "get", &dict_get_obj },
{ "items", &dict_items_obj },
{ "keys", &dict_keys_obj },
@@ -449,7 +417,7 @@ static const mp_method_t dict_type_methods[] = {
};
const mp_obj_type_t dict_type = {
- { &dict_class },
+ { &mp_const_type },
"dict",
.print = dict_print,
.make_new = dict_make_new,
diff --git a/py/objtype.c b/py/objtype.c
index 6c89c1ff2b..011ee43552 100644
--- a/py/objtype.c
+++ b/py/objtype.c
@@ -27,15 +27,13 @@ static mp_obj_t mp_obj_new_class(mp_obj_t class) {
return o;
}
-static mp_map_elem_t *mp_obj_class_lookup(mp_obj_t self_in, qstr attr, mp_map_lookup_kind_t lookup_kind) {
+static mp_map_elem_t *mp_obj_class_lookup(const mp_obj_type_t *type, qstr attr, mp_map_lookup_kind_t lookup_kind) {
for (;;) {
- assert(MP_OBJ_IS_TYPE(self_in, &mp_const_type));
- mp_obj_type_t *self = self_in;
- if (self->locals_dict == NULL) {
+ if (type->locals_dict == NULL) {
return NULL;
}
- assert(MP_OBJ_IS_TYPE(self->locals_dict, &dict_type)); // Micro Python restriction, for now
- mp_map_t *locals_map = ((void*)self->locals_dict + sizeof(mp_obj_base_t)); // XXX hack to get map object from dict object
+ assert(MP_OBJ_IS_TYPE(type->locals_dict, &dict_type)); // Micro Python restriction, for now
+ mp_map_t *locals_map = ((void*)type->locals_dict + sizeof(mp_obj_base_t)); // XXX hack to get map object from dict object
mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), lookup_kind);
if (elem != NULL) {
return elem;
@@ -44,25 +42,27 @@ static mp_map_elem_t *mp_obj_class_lookup(mp_obj_t self_in, qstr attr, mp_map_lo
// attribute not found, keep searching base classes
// for a const struct, this entry might be NULL
- if (self->bases_tuple == MP_OBJ_NULL) {
+ if (type->bases_tuple == MP_OBJ_NULL) {
return NULL;
}
uint len;
mp_obj_t *items;
- mp_obj_tuple_get(self->bases_tuple, &len, &items);
+ mp_obj_tuple_get(type->bases_tuple, &len, &items);
if (len == 0) {
return NULL;
}
for (uint i = 0; i < len - 1; i++) {
- elem = mp_obj_class_lookup(items[i], attr, lookup_kind);
+ assert(MP_OBJ_IS_TYPE(items[i], &mp_const_type));
+ elem = mp_obj_class_lookup((mp_obj_type_t*)items[i], attr, lookup_kind);
if (elem != NULL) {
return elem;
}
}
// search last base (simple tail recursion elimination)
- self_in = items[len - 1];
+ assert(MP_OBJ_IS_TYPE(items[len - 1], &mp_const_type));
+ type = (mp_obj_type_t*)items[len - 1];
}
}
@@ -73,11 +73,12 @@ static void class_print(void (*print)(void *env, const char *fmt, ...), void *en
// args are reverse in the array
static mp_obj_t class_make_new(mp_obj_t self_in, int n_args, const mp_obj_t *args) {
assert(MP_OBJ_IS_TYPE(self_in, &mp_const_type));
+ mp_obj_type_t *self = self_in;
mp_obj_t o = mp_obj_new_class(self_in);
// look for __init__ function
- mp_map_elem_t *init_fn = mp_obj_class_lookup(self_in, MP_QSTR___init__, MP_MAP_LOOKUP);
+ mp_map_elem_t *init_fn = mp_obj_class_lookup(self, MP_QSTR___init__, MP_MAP_LOOKUP);
if (init_fn != NULL) {
// call __init__ function
@@ -114,7 +115,7 @@ static void class_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
dest[1] = elem->value;
return;
}
- elem = mp_obj_class_lookup((mp_obj_t)self->base.type, attr, MP_MAP_LOOKUP);
+ elem = mp_obj_class_lookup(self->base.type, attr, MP_MAP_LOOKUP);
if (elem != NULL) {
if (mp_obj_is_callable(elem->value)) {
// class member is callable so build a bound method
@@ -132,7 +133,7 @@ static void class_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
static bool class_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_class_t *self = self_in;
- mp_map_elem_t *elem = mp_obj_class_lookup((mp_obj_t)self->base.type, attr, MP_MAP_LOOKUP);
+ mp_map_elem_t *elem = mp_obj_class_lookup(self->base.type, attr, MP_MAP_LOOKUP);
if (elem != NULL) {
elem->value = value;
} else {
@@ -188,17 +189,47 @@ static mp_obj_t type_call_n(mp_obj_t self_in, int n_args, const mp_obj_t *args)
// for fail, do nothing; for attr, dest[1] = value; for method, dest[0] = self, dest[1] = method
static void type_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
- mp_map_elem_t *elem = mp_obj_class_lookup(self_in, attr, MP_MAP_LOOKUP);
+ assert(MP_OBJ_IS_TYPE(self_in, &mp_const_type));
+ mp_obj_type_t *self = self_in;
+ mp_map_elem_t *elem = mp_obj_class_lookup(self, attr, MP_MAP_LOOKUP);
if (elem != NULL) {
dest[1] = elem->value;
return;
}
+
+ // generic method lookup
+ // this is a lookup in the class itself (ie not the classes type or instance)
+ const mp_method_t *meth = self->methods;
+ if (meth != NULL) {
+ for (; meth->name != NULL; meth++) {
+ if (strcmp(meth->name, qstr_str(attr)) == 0) {
+ // check if the methods are functions, static or class methods
+ // 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[1] = ((mp_obj_staticmethod_t*)meth->fun)->fun;
+ } else if (MP_OBJ_IS_TYPE(meth->fun, &mp_type_classmethod)) {
+ // return a bound method, with self being this class
+ dest[1] = ((mp_obj_classmethod_t*)meth->fun)->fun;
+ dest[0] = self_in;
+ } else {
+ // return just the function
+ // TODO need to wrap in a type check for the first argument; eg list.append(1,1) needs to throw an exception
+ dest[1] = (mp_obj_t)meth->fun;
+ }
+ return;
+ }
+ }
+ }
}
static bool type_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) {
+ assert(MP_OBJ_IS_TYPE(self_in, &mp_const_type));
+ mp_obj_type_t *self = self_in;
+
// TODO CPython allows STORE_ATTR to a class, but is this the correct implementation?
- mp_map_elem_t *elem = mp_obj_class_lookup(self_in, attr, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
+ mp_map_elem_t *elem = mp_obj_class_lookup(self, attr, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
if (elem != NULL) {
elem->value = value;
return true;
@@ -284,3 +315,16 @@ static mp_obj_t mp_builtin_isinstance(mp_obj_t object, mp_obj_t classinfo) {
}
MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_isinstance_obj, mp_builtin_isinstance);
+
+/******************************************************************************/
+// staticmethod and classmethod types (probably should go in a different file)
+
+const mp_obj_type_t mp_type_staticmethod = {
+ { &mp_const_type },
+ "staticmethod",
+};
+
+const mp_obj_type_t mp_type_classmethod = {
+ { &mp_const_type },
+ "classmethod",
+};
diff --git a/py/runtime.c b/py/runtime.c
index 29571a44b8..409d1d8262 100644
--- a/py/runtime.c
+++ b/py/runtime.c
@@ -774,12 +774,25 @@ void rt_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest) {
dest[0] = base;
} else {
// generic method lookup
+ // this is a lookup in the object (ie not class or type)
const mp_method_t *meth = type->methods;
if (meth != NULL) {
for (; meth->name != NULL; meth++) {
if (strcmp(meth->name, qstr_str(attr)) == 0) {
- dest[1] = (mp_obj_t)meth->fun;
- dest[0] = base;
+ // check if the methods are functions, static or class methods
+ // 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[1] = ((mp_obj_staticmethod_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[1] = ((mp_obj_classmethod_t*)meth->fun)->fun;
+ dest[0] = mp_obj_get_type(base);
+ } else {
+ // return a bound method, with self being this object
+ dest[1] = (mp_obj_t)meth->fun;
+ dest[0] = base;
+ }
break;
}
}