Improved type/class/instance code; mp_obj_type_t now has load_attr, store_attr.
Creating of classes (types) and instances is much more like CPython now. You can use "type('name', (), {...})" to create classes.
This commit is contained in:
parent
d944a66ead
commit
062478e66d
12
py/builtin.c
12
py/builtin.c
@ -23,8 +23,8 @@ mp_obj_t mp_builtin___build_class__(int n_args, const mp_obj_t *args) {
|
|||||||
|
|
||||||
// we differ from CPython: we set the new __locals__ object here
|
// we differ from CPython: we set the new __locals__ object here
|
||||||
mp_map_t *old_locals = rt_locals_get();
|
mp_map_t *old_locals = rt_locals_get();
|
||||||
mp_map_t *class_locals = mp_map_new(0);
|
mp_obj_t class_locals = mp_obj_new_dict(0);
|
||||||
rt_locals_set(class_locals);
|
rt_locals_set(mp_obj_dict_get_map(class_locals));
|
||||||
|
|
||||||
// call the class code
|
// call the class code
|
||||||
mp_obj_t cell = rt_call_function_1(args[0], (mp_obj_t)0xdeadbeef);
|
mp_obj_t cell = rt_call_function_1(args[0], (mp_obj_t)0xdeadbeef);
|
||||||
@ -32,7 +32,6 @@ mp_obj_t mp_builtin___build_class__(int n_args, const mp_obj_t *args) {
|
|||||||
// restore old __locals__ object
|
// restore old __locals__ object
|
||||||
rt_locals_set(old_locals);
|
rt_locals_set(old_locals);
|
||||||
|
|
||||||
/*
|
|
||||||
// get the class type (meta object) from the base objects
|
// get the class type (meta object) from the base objects
|
||||||
mp_obj_t meta;
|
mp_obj_t meta;
|
||||||
if (n_args == 2) {
|
if (n_args == 2) {
|
||||||
@ -42,21 +41,16 @@ mp_obj_t mp_builtin___build_class__(int n_args, const mp_obj_t *args) {
|
|||||||
// use type of first base object
|
// use type of first base object
|
||||||
meta = mp_obj_get_type(args[2]);
|
meta = mp_obj_get_type(args[2]);
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
// TODO do proper metaclass resolution for multiple base objects
|
// TODO do proper metaclass resolution for multiple base objects
|
||||||
|
|
||||||
/*
|
|
||||||
// create the new class using a call to the meta object
|
// create the new class using a call to the meta object
|
||||||
// (arguments must be backwards in the array)
|
// (arguments must be backwards in the array)
|
||||||
mp_obj_t meta_args[3];
|
mp_obj_t meta_args[3];
|
||||||
meta_args[2] = args[1]; // class name
|
meta_args[2] = args[1]; // class name
|
||||||
meta_args[1] = mp_obj_new_tuple(n_args - 2, args + 2); // tuple of bases
|
meta_args[1] = mp_obj_new_tuple(n_args - 2, args + 2); // tuple of bases
|
||||||
meta_args[0] = class_locals; // dict of members TODO, currently is a map
|
meta_args[0] = class_locals; // dict of members
|
||||||
mp_obj_t new_class = rt_call_function_n(meta, 3, meta_args);
|
mp_obj_t new_class = rt_call_function_n(meta, 3, meta_args);
|
||||||
*/
|
|
||||||
// create the new class
|
|
||||||
mp_obj_t new_class = mp_obj_new_class(class_locals);
|
|
||||||
|
|
||||||
// store into cell if neede
|
// store into cell if neede
|
||||||
if (cell != mp_const_none) {
|
if (cell != mp_const_none) {
|
||||||
|
2
py/map.h
2
py/map.h
@ -18,7 +18,7 @@ typedef struct _mp_set_t {
|
|||||||
mp_obj_t *table;
|
mp_obj_t *table;
|
||||||
} mp_set_t;
|
} mp_set_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum _mp_map_lookup_kind_t {
|
||||||
MP_MAP_LOOKUP,
|
MP_MAP_LOOKUP,
|
||||||
MP_MAP_LOOKUP_ADD_IF_NOT_FOUND,
|
MP_MAP_LOOKUP_ADD_IF_NOT_FOUND,
|
||||||
MP_MAP_LOOKUP_REMOVE_IF_FOUND,
|
MP_MAP_LOOKUP_REMOVE_IF_FOUND,
|
||||||
|
28
py/obj.h
28
py/obj.h
@ -61,6 +61,8 @@ typedef struct _mp_obj_base_t mp_obj_base_t;
|
|||||||
|
|
||||||
// Need to declare this here so we are not dependent on map.h
|
// Need to declare this here so we are not dependent on map.h
|
||||||
struct _mp_map_t;
|
struct _mp_map_t;
|
||||||
|
struct _mp_map_elem_t;
|
||||||
|
enum _mp_map_lookup_kind_t;
|
||||||
|
|
||||||
// Type definitions for methods
|
// Type definitions for methods
|
||||||
|
|
||||||
@ -78,6 +80,8 @@ typedef mp_obj_t (*mp_call_n_fun_t)(mp_obj_t fun, int n_args, const mp_obj_t *ar
|
|||||||
typedef mp_obj_t (*mp_call_n_kw_fun_t)(mp_obj_t fun, int n_args, int n_kw, const mp_obj_t *args); // args are in reverse order in the array
|
typedef mp_obj_t (*mp_call_n_kw_fun_t)(mp_obj_t fun, int n_args, int n_kw, const mp_obj_t *args); // args are in reverse order in the array
|
||||||
typedef mp_obj_t (*mp_unary_op_fun_t)(int op, mp_obj_t);
|
typedef mp_obj_t (*mp_unary_op_fun_t)(int op, mp_obj_t);
|
||||||
typedef mp_obj_t (*mp_binary_op_fun_t)(int op, mp_obj_t, mp_obj_t);
|
typedef mp_obj_t (*mp_binary_op_fun_t)(int 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[1] = value; for method, dest[0] = self, dest[1] = method
|
||||||
|
typedef bool (*mp_store_attr_fun_t)(mp_obj_t self_in, qstr attr, mp_obj_t value); // return true if store succeeded
|
||||||
|
|
||||||
typedef struct _mp_method_t {
|
typedef struct _mp_method_t {
|
||||||
const char *name;
|
const char *name;
|
||||||
@ -141,15 +145,14 @@ struct _mp_obj_type_t {
|
|||||||
|
|
||||||
const mp_method_t *methods;
|
const mp_method_t *methods;
|
||||||
|
|
||||||
|
mp_load_attr_fun_t load_attr;
|
||||||
|
mp_store_attr_fun_t store_attr;
|
||||||
|
mp_obj_t locals;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
What we might need to add here:
|
What we might need to add here:
|
||||||
|
|
||||||
dynamic_type instance
|
|
||||||
|
|
||||||
compare_op
|
compare_op
|
||||||
load_attr module instance class list
|
|
||||||
load_method instance str gen list user
|
|
||||||
store_attr module instance class
|
|
||||||
store_subscr list dict
|
store_subscr list dict
|
||||||
|
|
||||||
len str tuple list map
|
len str tuple list map
|
||||||
@ -160,7 +163,6 @@ struct _mp_obj_type_t {
|
|||||||
get_array_n tuple list
|
get_array_n tuple list
|
||||||
|
|
||||||
unpack seq list tuple
|
unpack seq list tuple
|
||||||
__next__ gen-instance
|
|
||||||
*/
|
*/
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -178,6 +180,7 @@ extern const mp_obj_t mp_const_stop_iteration; // special object indicating end
|
|||||||
|
|
||||||
// General API for objects
|
// General API for objects
|
||||||
|
|
||||||
|
mp_obj_t mp_obj_new_type(qstr name, mp_obj_t local_dict);
|
||||||
mp_obj_t mp_obj_new_none(void);
|
mp_obj_t mp_obj_new_none(void);
|
||||||
mp_obj_t mp_obj_new_bool(bool value);
|
mp_obj_t mp_obj_new_bool(bool value);
|
||||||
mp_obj_t mp_obj_new_cell(mp_obj_t obj);
|
mp_obj_t mp_obj_new_cell(mp_obj_t obj);
|
||||||
@ -207,8 +210,6 @@ mp_obj_t mp_obj_new_dict(int n_args);
|
|||||||
mp_obj_t mp_obj_new_set(int n_args, mp_obj_t *items);
|
mp_obj_t mp_obj_new_set(int n_args, mp_obj_t *items);
|
||||||
mp_obj_t mp_obj_new_slice(mp_obj_t start, mp_obj_t stop, mp_obj_t step);
|
mp_obj_t mp_obj_new_slice(mp_obj_t start, mp_obj_t stop, mp_obj_t step);
|
||||||
mp_obj_t mp_obj_new_bound_meth(mp_obj_t self, mp_obj_t meth);
|
mp_obj_t mp_obj_new_bound_meth(mp_obj_t self, mp_obj_t meth);
|
||||||
mp_obj_t mp_obj_new_class(struct _mp_map_t *class_locals);
|
|
||||||
mp_obj_t mp_obj_new_instance(mp_obj_t clas);
|
|
||||||
mp_obj_t mp_obj_new_module(qstr module_name);
|
mp_obj_t mp_obj_new_module(qstr module_name);
|
||||||
|
|
||||||
mp_obj_t mp_obj_get_type(mp_obj_t o_in);
|
mp_obj_t mp_obj_get_type(mp_obj_t o_in);
|
||||||
@ -278,6 +279,7 @@ void mp_obj_list_store(mp_obj_t self_in, mp_obj_t index, mp_obj_t value);
|
|||||||
extern const mp_obj_type_t dict_type;
|
extern const mp_obj_type_t dict_type;
|
||||||
uint mp_obj_dict_len(mp_obj_t self_in);
|
uint mp_obj_dict_len(mp_obj_t self_in);
|
||||||
mp_obj_t mp_obj_dict_store(mp_obj_t self_in, mp_obj_t key, mp_obj_t value);
|
mp_obj_t mp_obj_dict_store(mp_obj_t self_in, mp_obj_t key, mp_obj_t value);
|
||||||
|
struct _mp_map_t *mp_obj_dict_get_map(mp_obj_t self_in);
|
||||||
|
|
||||||
// set
|
// set
|
||||||
extern const mp_obj_type_t set_type;
|
extern const mp_obj_type_t set_type;
|
||||||
@ -307,15 +309,7 @@ void mp_obj_fun_bc_get(mp_obj_t self_in, int *n_args, uint *n_state, const byte
|
|||||||
extern const mp_obj_type_t gen_instance_type;
|
extern const mp_obj_type_t gen_instance_type;
|
||||||
|
|
||||||
// class
|
// class
|
||||||
extern const mp_obj_type_t class_type;
|
struct _mp_map_elem_t *mp_obj_class_lookup(mp_obj_t self_in, qstr attr, enum _mp_map_lookup_kind_t lookup_kind);
|
||||||
extern const mp_obj_t gen_instance_next_obj;
|
|
||||||
struct _mp_map_t *mp_obj_class_get_locals(mp_obj_t self_in);
|
|
||||||
|
|
||||||
// instance
|
|
||||||
extern const mp_obj_type_t instance_type;
|
|
||||||
mp_obj_t mp_obj_instance_load_attr(mp_obj_t self_in, qstr attr);
|
|
||||||
void mp_obj_instance_load_method(mp_obj_t self_in, qstr attr, mp_obj_t *dest);
|
|
||||||
void mp_obj_instance_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value);
|
|
||||||
|
|
||||||
// module
|
// module
|
||||||
extern const mp_obj_type_t module_type;
|
extern const mp_obj_type_t module_type;
|
||||||
|
@ -1,74 +0,0 @@
|
|||||||
#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_class_t {
|
|
||||||
mp_obj_base_t base;
|
|
||||||
mp_map_t *locals;
|
|
||||||
} mp_obj_class_t;
|
|
||||||
|
|
||||||
// args are in reverse order in the array
|
|
||||||
mp_obj_t class_call_n(mp_obj_t self_in, int n_args, const mp_obj_t *args) {
|
|
||||||
// instantiate an instance of a class
|
|
||||||
|
|
||||||
mp_obj_class_t *self = self_in;
|
|
||||||
|
|
||||||
// make instance
|
|
||||||
mp_obj_t o = mp_obj_new_instance(self_in);
|
|
||||||
|
|
||||||
// look for __init__ function
|
|
||||||
mp_map_elem_t *init_fn = mp_map_lookup(self->locals, MP_OBJ_NEW_QSTR(MP_QSTR___init__), MP_MAP_LOOKUP);
|
|
||||||
|
|
||||||
if (init_fn != NULL) {
|
|
||||||
// call __init__ function
|
|
||||||
mp_obj_t init_ret;
|
|
||||||
if (n_args == 0) {
|
|
||||||
init_ret = rt_call_function_n(init_fn->value, 1, (mp_obj_t*)&o);
|
|
||||||
} else {
|
|
||||||
mp_obj_t *args2 = m_new(mp_obj_t, n_args + 1);
|
|
||||||
memcpy(args2, args, n_args * sizeof(mp_obj_t));
|
|
||||||
args2[n_args] = o;
|
|
||||||
init_ret = rt_call_function_n(init_fn->value, n_args + 1, args2);
|
|
||||||
m_del(mp_obj_t, args2, n_args + 1);
|
|
||||||
}
|
|
||||||
if (init_ret != mp_const_none) {
|
|
||||||
nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "__init__() should return None, not '%s'", mp_obj_get_type_str(init_ret)));
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// TODO
|
|
||||||
if (n_args != 0) {
|
|
||||||
nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "function takes 0 positional arguments but %d were given", (void*)(machine_int_t)n_args));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return o;
|
|
||||||
}
|
|
||||||
|
|
||||||
mp_map_t *mp_obj_class_get_locals(mp_obj_t self_in) {
|
|
||||||
assert(MP_OBJ_IS_TYPE(self_in, &class_type));
|
|
||||||
mp_obj_class_t *self = self_in;
|
|
||||||
return self->locals;
|
|
||||||
}
|
|
||||||
|
|
||||||
const mp_obj_type_t class_type = {
|
|
||||||
{ &mp_const_type },
|
|
||||||
"class",
|
|
||||||
.call_n = class_call_n,
|
|
||||||
};
|
|
||||||
|
|
||||||
mp_obj_t mp_obj_new_class(mp_map_t *class_locals) {
|
|
||||||
mp_obj_class_t *o = m_new_obj(mp_obj_class_t);
|
|
||||||
o->base.type = &class_type;
|
|
||||||
o->locals = class_locals;
|
|
||||||
return o;
|
|
||||||
}
|
|
@ -287,3 +287,9 @@ mp_obj_t mp_obj_dict_store(mp_obj_t self_in, mp_obj_t key, mp_obj_t value) {
|
|||||||
mp_map_lookup(&self->map, key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;
|
mp_map_lookup(&self->map, key, MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;
|
||||||
return self_in;
|
return self_in;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mp_map_t *mp_obj_dict_get_map(mp_obj_t self_in) {
|
||||||
|
assert(MP_OBJ_IS_TYPE(self_in, &dict_type));
|
||||||
|
mp_obj_dict_t *self = self_in;
|
||||||
|
return &self->map;
|
||||||
|
}
|
||||||
|
103
py/objinstance.c
103
py/objinstance.c
@ -1,103 +0,0 @@
|
|||||||
#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_map_lookup(self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP);
|
|
||||||
if (elem != NULL) {
|
|
||||||
// object member, always treated as a value
|
|
||||||
return elem->value;
|
|
||||||
}
|
|
||||||
elem = mp_map_lookup(mp_obj_class_get_locals(self->class), MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP);
|
|
||||||
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_map_lookup(self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP);
|
|
||||||
if (elem != NULL) {
|
|
||||||
// object member, always treated as a value
|
|
||||||
dest[1] = elem->value;
|
|
||||||
dest[0] = NULL;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
elem = mp_map_lookup(mp_obj_class_get_locals(self->class), MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP);
|
|
||||||
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_map_lookup(mp_obj_class_get_locals(self->class), MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP);
|
|
||||||
if (elem != NULL) {
|
|
||||||
elem->value = value;
|
|
||||||
} else {
|
|
||||||
mp_map_lookup(self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const mp_obj_type_t instance_type = {
|
|
||||||
{ &mp_const_type },
|
|
||||||
"instance",
|
|
||||||
};
|
|
||||||
|
|
||||||
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(0);
|
|
||||||
return o;
|
|
||||||
}
|
|
@ -17,15 +17,32 @@ typedef struct _mp_obj_module_t {
|
|||||||
mp_map_t *globals;
|
mp_map_t *globals;
|
||||||
} mp_obj_module_t;
|
} mp_obj_module_t;
|
||||||
|
|
||||||
void module_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in) {
|
static void module_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in) {
|
||||||
mp_obj_module_t *self = self_in;
|
mp_obj_module_t *self = self_in;
|
||||||
print(env, "<module '%s' from '-unknown-file-'>", qstr_str(self->name));
|
print(env, "<module '%s' from '-unknown-file-'>", qstr_str(self->name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void module_load_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, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP);
|
||||||
|
if (elem != NULL) {
|
||||||
|
dest[1] = 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;
|
||||||
|
// TODO CPython allows STORE_ATTR to a module, but is this the correct implementation?
|
||||||
|
mp_map_lookup(self->globals, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
const mp_obj_type_t module_type = {
|
const mp_obj_type_t module_type = {
|
||||||
{ &mp_const_type },
|
{ &mp_const_type },
|
||||||
"module",
|
"module",
|
||||||
.print = module_print,
|
.print = module_print,
|
||||||
|
.load_attr = module_load_attr,
|
||||||
|
.store_attr = module_store_attr,
|
||||||
};
|
};
|
||||||
|
|
||||||
mp_obj_t mp_obj_new_module(qstr module_name) {
|
mp_obj_t mp_obj_new_module(qstr module_name) {
|
||||||
|
171
py/objtype.c
171
py/objtype.c
@ -1,11 +1,123 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
#include "nlr.h"
|
#include "nlr.h"
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
#include "mpconfig.h"
|
#include "mpconfig.h"
|
||||||
#include "mpqstr.h"
|
#include "mpqstr.h"
|
||||||
#include "obj.h"
|
#include "obj.h"
|
||||||
|
#include "map.h"
|
||||||
|
#include "runtime.h"
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
// class object
|
||||||
|
// creating an instance of a class makes one of these objects
|
||||||
|
|
||||||
|
typedef struct _mp_obj_class_t {
|
||||||
|
mp_obj_base_t base;
|
||||||
|
mp_map_t members;
|
||||||
|
} mp_obj_class_t;
|
||||||
|
|
||||||
|
static mp_obj_t mp_obj_new_class(mp_obj_t class) {
|
||||||
|
mp_obj_class_t *o = m_new_obj(mp_obj_class_t);
|
||||||
|
o->base.type = class;
|
||||||
|
mp_map_init(&o->members, 0);
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void class_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in) {
|
||||||
|
print(env, "<%s object at %p>", mp_obj_get_type_str(self_in), self_in);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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_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);
|
||||||
|
|
||||||
|
if (init_fn != NULL) {
|
||||||
|
// call __init__ function
|
||||||
|
mp_obj_t init_ret;
|
||||||
|
if (n_args == 0) {
|
||||||
|
init_ret = rt_call_function_n(init_fn->value, 1, (mp_obj_t*)&o);
|
||||||
|
} else {
|
||||||
|
mp_obj_t *args2 = m_new(mp_obj_t, n_args + 1);
|
||||||
|
memcpy(args2, args, n_args * sizeof(mp_obj_t));
|
||||||
|
args2[n_args] = o;
|
||||||
|
init_ret = rt_call_function_n(init_fn->value, n_args + 1, args2);
|
||||||
|
m_del(mp_obj_t, args2, n_args + 1);
|
||||||
|
}
|
||||||
|
if (init_ret != mp_const_none) {
|
||||||
|
nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "__init__() should return None, not '%s'", mp_obj_get_type_str(init_ret)));
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// TODO
|
||||||
|
if (n_args != 0) {
|
||||||
|
nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "function takes 0 positional arguments but %d were given", (void*)(machine_int_t)n_args));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void class_load_attr(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_class_t *self = self_in;
|
||||||
|
mp_map_elem_t *elem = mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP);
|
||||||
|
if (elem != NULL) {
|
||||||
|
// object member, always treated as a value
|
||||||
|
dest[1] = elem->value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
elem = mp_obj_class_lookup((mp_obj_t)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
|
||||||
|
dest[1] = elem->value;
|
||||||
|
dest[0] = self_in;
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
// class member is a value, so just return that value
|
||||||
|
dest[1] = elem->value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
if (elem != NULL) {
|
||||||
|
elem->value = value;
|
||||||
|
} else {
|
||||||
|
mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
mp_map_elem_t *mp_obj_class_lookup(mp_obj_t self_in, qstr attr, mp_map_lookup_kind_t lookup_kind) {
|
||||||
|
assert(MP_OBJ_IS_TYPE(self_in, &mp_const_type));
|
||||||
|
mp_obj_type_t *self = self_in;
|
||||||
|
if (self->locals == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
assert(MP_OBJ_IS_TYPE(self->locals, &dict_type)); // Micro Python restriction, for now
|
||||||
|
mp_map_t *locals_map = ((void*)self->locals + sizeof(mp_obj_base_t)); // XXX hack to get map object from dict object
|
||||||
|
return mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), lookup_kind);
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
// type object
|
||||||
|
// - the struct is mp_obj_type_t and is defined in obj.h so const types can be made
|
||||||
|
// - there is a constant mp_obj_type_t (called mp_const_type) for the 'type' object
|
||||||
|
// - creating a new class (a new type) creates a new mp_obj_type_t
|
||||||
|
|
||||||
static void type_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in) {
|
static void type_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in) {
|
||||||
mp_obj_type_t *self = self_in;
|
mp_obj_type_t *self = self_in;
|
||||||
@ -24,13 +136,7 @@ static mp_obj_t type_make_new(mp_obj_t type_in, int n_args, const mp_obj_t *args
|
|||||||
// args[1] = bases tuple
|
// args[1] = bases tuple
|
||||||
// args[0] = locals dict
|
// args[0] = locals dict
|
||||||
|
|
||||||
mp_obj_type_t *new_type = m_new0(mp_obj_type_t, 1);
|
return mp_obj_new_type(mp_obj_get_qstr(args[2]), args[0]);
|
||||||
new_type->base.type = &mp_const_type;
|
|
||||||
new_type->name = qstr_str(mp_obj_get_qstr(args[2]));
|
|
||||||
return new_type;
|
|
||||||
|
|
||||||
//mp_obj_t new_class = mp_obj_new_class(mp_obj_get_qstr(args[2]), args[0]);
|
|
||||||
//return new_class;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -38,14 +144,42 @@ static mp_obj_t type_make_new(mp_obj_t type_in, int n_args, const mp_obj_t *args
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// args are in reverse order in the array
|
||||||
static mp_obj_t type_call_n(mp_obj_t self_in, int n_args, const mp_obj_t *args) {
|
static mp_obj_t type_call_n(mp_obj_t self_in, int n_args, const mp_obj_t *args) {
|
||||||
|
// instantiate an instance of a class
|
||||||
|
|
||||||
mp_obj_type_t *self = self_in;
|
mp_obj_type_t *self = self_in;
|
||||||
if (self->make_new != NULL) {
|
|
||||||
// TODO we need to init the object if it's an instance of a type
|
if (self->make_new == NULL) {
|
||||||
return self->make_new(self, n_args, args);
|
|
||||||
} else {
|
|
||||||
nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "cannot create '%s' instances", self->name));
|
nlr_jump(mp_obj_new_exception_msg_1_arg(MP_QSTR_TypeError, "cannot create '%s' instances", self->name));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// make new instance
|
||||||
|
mp_obj_t o = self->make_new(self, n_args, args);
|
||||||
|
|
||||||
|
// return new instance
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
if (elem != NULL) {
|
||||||
|
dest[1] = elem->value;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool type_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) {
|
||||||
|
// 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);
|
||||||
|
if (elem != NULL) {
|
||||||
|
elem->value = value;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const mp_obj_type_t mp_const_type = {
|
const mp_obj_type_t mp_const_type = {
|
||||||
@ -54,4 +188,19 @@ const mp_obj_type_t mp_const_type = {
|
|||||||
.print = type_print,
|
.print = type_print,
|
||||||
.make_new = type_make_new,
|
.make_new = type_make_new,
|
||||||
.call_n = type_call_n,
|
.call_n = type_call_n,
|
||||||
|
.load_attr = type_load_attr,
|
||||||
|
.store_attr = type_store_attr,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mp_obj_t mp_obj_new_type(qstr name, mp_obj_t local_dict) {
|
||||||
|
mp_obj_type_t *o = m_new0(mp_obj_type_t, 1);
|
||||||
|
o->base.type = &mp_const_type;
|
||||||
|
o->name = qstr_str(name);
|
||||||
|
o->print = class_print;
|
||||||
|
o->make_new = class_make_new;
|
||||||
|
o->load_attr = class_load_attr;
|
||||||
|
o->store_attr = class_store_attr;
|
||||||
|
o->locals = local_dict;
|
||||||
|
assert(MP_OBJ_IS_TYPE(o->locals, &dict_type)); // Micro Python restriction, for now
|
||||||
|
return o;
|
||||||
|
}
|
||||||
|
2
py/py.mk
2
py/py.mk
@ -74,7 +74,6 @@ PY_O_BASENAME = \
|
|||||||
objbool.o \
|
objbool.o \
|
||||||
objboundmeth.o \
|
objboundmeth.o \
|
||||||
objcell.o \
|
objcell.o \
|
||||||
objclass.o \
|
|
||||||
objclosure.o \
|
objclosure.o \
|
||||||
objcomplex.o \
|
objcomplex.o \
|
||||||
objdict.o \
|
objdict.o \
|
||||||
@ -82,7 +81,6 @@ PY_O_BASENAME = \
|
|||||||
objfloat.o \
|
objfloat.o \
|
||||||
objfun.o \
|
objfun.o \
|
||||||
objgenerator.o \
|
objgenerator.o \
|
||||||
objinstance.o \
|
|
||||||
objint.o \
|
objint.o \
|
||||||
objlist.o \
|
objlist.o \
|
||||||
objmodule.o \
|
objmodule.o \
|
||||||
|
105
py/runtime.c
105
py/runtime.c
@ -188,8 +188,10 @@ void rt_assign_byte_code(int unique_code_id, byte *code, uint len, int n_args, i
|
|||||||
DEBUG_printf(" %02x", code[i]);
|
DEBUG_printf(" %02x", code[i]);
|
||||||
}
|
}
|
||||||
DEBUG_printf("\n");
|
DEBUG_printf("\n");
|
||||||
|
#if MICROPY_SHOW_BC
|
||||||
extern void mp_show_byte_code(const byte *code, int len);
|
extern void mp_show_byte_code(const byte *code, int len);
|
||||||
mp_show_byte_code(code, len);
|
mp_show_byte_code(code, len);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef WRITE_CODE
|
#ifdef WRITE_CODE
|
||||||
if (fp_write_code != NULL) {
|
if (fp_write_code != NULL) {
|
||||||
@ -775,86 +777,75 @@ mp_obj_t rt_store_map(mp_obj_t map, mp_obj_t key, mp_obj_t value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mp_obj_t rt_load_attr(mp_obj_t base, qstr attr) {
|
mp_obj_t rt_load_attr(mp_obj_t base, qstr attr) {
|
||||||
DEBUG_OP_printf("load attr %s\n", qstr_str(attr));
|
DEBUG_OP_printf("load attr %p.%s\n", base, qstr_str(attr));
|
||||||
if (MP_OBJ_IS_TYPE(base, &class_type)) {
|
// use load_method
|
||||||
mp_map_elem_t *elem = mp_map_lookup(mp_obj_class_get_locals(base), MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP);
|
mp_obj_t dest[2];
|
||||||
if (elem == NULL) {
|
rt_load_method(base, attr, dest);
|
||||||
// TODO what about generic method lookup?
|
if (dest[0] == NULL) {
|
||||||
goto no_attr;
|
// load_method returned just a normal attribute
|
||||||
|
return dest[1];
|
||||||
|
} else {
|
||||||
|
// load_method returned a method, so build a bound method object
|
||||||
|
return mp_obj_new_bound_meth(dest[0], dest[1]);
|
||||||
}
|
}
|
||||||
return elem->value;
|
|
||||||
} else if (MP_OBJ_IS_TYPE(base, &instance_type)) {
|
|
||||||
return mp_obj_instance_load_attr(base, attr);
|
|
||||||
} else if (MP_OBJ_IS_TYPE(base, &module_type)) {
|
|
||||||
DEBUG_OP_printf("lookup module map %p\n", mp_obj_module_get_globals(base));
|
|
||||||
mp_map_elem_t *elem = mp_map_lookup(mp_obj_module_get_globals(base), MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP);
|
|
||||||
if (elem == NULL) {
|
|
||||||
// TODO what about generic method lookup?
|
|
||||||
goto no_attr;
|
|
||||||
}
|
|
||||||
return elem->value;
|
|
||||||
} else if (MP_OBJ_IS_OBJ(base)) {
|
|
||||||
// generic method lookup
|
|
||||||
mp_obj_base_t *o = base;
|
|
||||||
const mp_method_t *meth = o->type->methods;
|
|
||||||
if (meth != NULL) {
|
|
||||||
for (; meth->name != NULL; meth++) {
|
|
||||||
if (strcmp(meth->name, qstr_str(attr)) == 0) {
|
|
||||||
return mp_obj_new_bound_meth(base, (mp_obj_t)meth->fun);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
no_attr:
|
|
||||||
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_AttributeError, "'%s' object has no attribute '%s'", mp_obj_get_type_str(base), qstr_str(attr)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void rt_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest) {
|
void rt_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest) {
|
||||||
DEBUG_OP_printf("load method %s\n", qstr_str(attr));
|
DEBUG_OP_printf("load method %p.%s\n", base, qstr_str(attr));
|
||||||
if (MP_OBJ_IS_TYPE(base, &gen_instance_type) && attr == MP_QSTR___next__) {
|
|
||||||
|
// clear output to indicate no attribute/method found yet
|
||||||
|
dest[0] = MP_OBJ_NULL;
|
||||||
|
dest[1] = MP_OBJ_NULL;
|
||||||
|
|
||||||
|
// get the type
|
||||||
|
mp_obj_type_t *type = mp_obj_get_type(base);
|
||||||
|
|
||||||
|
// if this type can do its own load, then call it
|
||||||
|
if (type->load_attr != NULL) {
|
||||||
|
type->load_attr(base, attr, dest);
|
||||||
|
}
|
||||||
|
|
||||||
|
// if nothing found yet, look for built-in and generic names
|
||||||
|
if (dest[1] == NULL) {
|
||||||
|
if (attr == MP_QSTR___next__ && type->iternext != NULL) {
|
||||||
dest[1] = (mp_obj_t)&mp_builtin_next_obj;
|
dest[1] = (mp_obj_t)&mp_builtin_next_obj;
|
||||||
dest[0] = base;
|
dest[0] = base;
|
||||||
return;
|
} else {
|
||||||
} else if (MP_OBJ_IS_TYPE(base, &instance_type)) {
|
|
||||||
mp_obj_instance_load_method(base, attr, dest);
|
|
||||||
return;
|
|
||||||
} else if (MP_OBJ_IS_OBJ(base)) {
|
|
||||||
// generic method lookup
|
// generic method lookup
|
||||||
mp_obj_base_t *o = base;
|
const mp_method_t *meth = type->methods;
|
||||||
const mp_method_t *meth = o->type->methods;
|
|
||||||
if (meth != NULL) {
|
if (meth != NULL) {
|
||||||
for (; meth->name != NULL; meth++) {
|
for (; meth->name != NULL; meth++) {
|
||||||
if (strcmp(meth->name, qstr_str(attr)) == 0) {
|
if (strcmp(meth->name, qstr_str(attr)) == 0) {
|
||||||
dest[1] = (mp_obj_t)meth->fun;
|
dest[1] = (mp_obj_t)meth->fun;
|
||||||
dest[0] = base;
|
dest[0] = base;
|
||||||
return;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// no method; fallback to load_attr
|
if (dest[1] == NULL) {
|
||||||
dest[1] = rt_load_attr(base, attr);
|
// no attribute/method called attr
|
||||||
dest[0] = NULL;
|
// following CPython, we give a more detailed error message for type objects
|
||||||
|
if (MP_OBJ_IS_TYPE(base, &mp_const_type)) {
|
||||||
|
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_AttributeError, "type object '%s' has no attribute '%s'", ((mp_obj_type_t*)base)->name, qstr_str(attr)));
|
||||||
|
} else {
|
||||||
|
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_AttributeError, "'%s' object has no attribute '%s'", mp_obj_get_type_str(base), qstr_str(attr)));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void rt_store_attr(mp_obj_t base, qstr attr, mp_obj_t value) {
|
void rt_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);
|
DEBUG_OP_printf("store attr %p.%s <- %p\n", base, qstr_str(attr), value);
|
||||||
if (MP_OBJ_IS_TYPE(base, &class_type)) {
|
mp_obj_type_t *type = mp_obj_get_type(base);
|
||||||
// TODO CPython allows STORE_ATTR to a class, but is this the correct implementation?
|
if (type->store_attr != NULL) {
|
||||||
mp_map_t *locals = mp_obj_class_get_locals(base);
|
if (type->store_attr(base, attr, value)) {
|
||||||
mp_map_lookup(locals, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;
|
return;
|
||||||
} else if (MP_OBJ_IS_TYPE(base, &instance_type)) {
|
|
||||||
mp_obj_instance_store_attr(base, attr, value);
|
|
||||||
} else if (MP_OBJ_IS_TYPE(base, &module_type)) {
|
|
||||||
// TODO CPython allows STORE_ATTR to a module, but is this the correct implementation?
|
|
||||||
mp_map_t *globals = mp_obj_module_get_globals(base);
|
|
||||||
mp_map_lookup(globals, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;
|
|
||||||
} else {
|
|
||||||
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_AttributeError, "'%s' object has no attribute '%s'", mp_obj_get_type_str(base), qstr_str(attr)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
nlr_jump(mp_obj_new_exception_msg_varg(MP_QSTR_AttributeError, "'%s' object has no attribute '%s'", mp_obj_get_type_str(base), qstr_str(attr)));
|
||||||
|
}
|
||||||
|
|
||||||
void rt_store_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t value) {
|
void rt_store_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t value) {
|
||||||
DEBUG_OP_printf("store subscr %p[%p] <- %p\n", base, index, value);
|
DEBUG_OP_printf("store subscr %p[%p] <- %p\n", base, index, value);
|
||||||
|
@ -65,6 +65,8 @@ void decode_addr_and_store(mp_obj_t object, qstr q_attr, unsigned char *ip, int
|
|||||||
rt_store_attr(object, q_attr, decode_addr(ip, n_bytes));
|
rt_store_attr(object, q_attr, decode_addr(ip, n_bytes));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static mp_obj_t net_address_type = MP_OBJ_NULL;
|
||||||
|
|
||||||
mp_obj_t pyb_wlan_get_ip(void) {
|
mp_obj_t pyb_wlan_get_ip(void) {
|
||||||
tNetappIpconfigRetArgs ipconfig;
|
tNetappIpconfigRetArgs ipconfig;
|
||||||
netapp_ipconfig(&ipconfig);
|
netapp_ipconfig(&ipconfig);
|
||||||
@ -74,16 +76,24 @@ mp_obj_t pyb_wlan_get_ip(void) {
|
|||||||
return mp_const_none;
|
return mp_const_none;
|
||||||
}
|
}
|
||||||
|
|
||||||
mp_obj_t data = mp_obj_new_class(mp_map_new(0)); // TODO should this be an instance of a class?
|
// if it doesn't already exist, make a new empty class for NetAddress objects
|
||||||
decode_addr_and_store(data, qstr_from_str_static("ip"), &ipconfig.aucIP[0], 4);
|
if (net_address_type == MP_OBJ_NULL) {
|
||||||
decode_addr_and_store(data, qstr_from_str_static("subnet"), &ipconfig.aucSubnetMask[0], 4);
|
net_address_type = mp_obj_new_type(qstr_from_str_static("NetAddress"), mp_obj_new_dict(0));
|
||||||
decode_addr_and_store(data, qstr_from_str_static("gateway"), &ipconfig.aucDefaultGateway[0], 4);
|
}
|
||||||
decode_addr_and_store(data, qstr_from_str_static("dhcp"), &ipconfig.aucDHCPServer[0], 4);
|
|
||||||
decode_addr_and_store(data, qstr_from_str_static("dns"), &ipconfig.aucDNSServer[0], 4);
|
|
||||||
decode_addr_and_store(data, qstr_from_str_static("mac"), &ipconfig.uaMacAddr[0], 6);
|
|
||||||
decode_addr_and_store(data, qstr_from_str_static("ssid"), &ipconfig.uaSSID[0], 32);
|
|
||||||
|
|
||||||
return data;
|
// make a new NetAddress object
|
||||||
|
mp_obj_t net_addr = rt_call_function_0(net_address_type);
|
||||||
|
|
||||||
|
// fill the NetAddress object with data
|
||||||
|
decode_addr_and_store(net_addr, qstr_from_str_static("ip"), &ipconfig.aucIP[0], 4);
|
||||||
|
decode_addr_and_store(net_addr, qstr_from_str_static("subnet"), &ipconfig.aucSubnetMask[0], 4);
|
||||||
|
decode_addr_and_store(net_addr, qstr_from_str_static("gateway"), &ipconfig.aucDefaultGateway[0], 4);
|
||||||
|
decode_addr_and_store(net_addr, qstr_from_str_static("dhcp"), &ipconfig.aucDHCPServer[0], 4);
|
||||||
|
decode_addr_and_store(net_addr, qstr_from_str_static("dns"), &ipconfig.aucDNSServer[0], 4);
|
||||||
|
decode_addr_and_store(net_addr, qstr_from_str_static("mac"), &ipconfig.uaMacAddr[0], 6);
|
||||||
|
decode_addr_and_store(net_addr, qstr_from_str_static("ssid"), &ipconfig.uaSSID[0], 32);
|
||||||
|
|
||||||
|
return net_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t last_ip = 0; // XXX such a hack!
|
uint32_t last_ip = 0; // XXX such a hack!
|
||||||
|
@ -5,6 +5,7 @@ class C1:
|
|||||||
self.x = 1
|
self.x = 1
|
||||||
|
|
||||||
c1 = C1()
|
c1 = C1()
|
||||||
|
print(type(c1) == C1)
|
||||||
print(c1.x)
|
print(c1.x)
|
||||||
|
|
||||||
class C2:
|
class C2:
|
||||||
@ -12,4 +13,5 @@ class C2:
|
|||||||
self.x = x
|
self.x = x
|
||||||
|
|
||||||
c2 = C2(4)
|
c2 = C2(4)
|
||||||
|
print(type(c2) == C2)
|
||||||
print(c2.x)
|
print(c2.x)
|
||||||
|
12
unix/main.c
12
unix/main.c
@ -210,6 +210,18 @@ int main(int argc, char **argv) {
|
|||||||
rt_store_name(qstr_from_str_static("test"), test_obj_new(42));
|
rt_store_name(qstr_from_str_static("test"), test_obj_new(42));
|
||||||
rt_store_name(qstr_from_str_static("open"), (mp_obj_t)&mp_builtin_open_obj);
|
rt_store_name(qstr_from_str_static("open"), (mp_obj_t)&mp_builtin_open_obj);
|
||||||
|
|
||||||
|
// Here is some example code to create a class and instance of that class.
|
||||||
|
// First is the Python, then the C code.
|
||||||
|
//
|
||||||
|
// class TestClass:
|
||||||
|
// pass
|
||||||
|
// test_obj = TestClass()
|
||||||
|
// test_obj.attr = 42
|
||||||
|
mp_obj_t test_class_type, test_class_instance;
|
||||||
|
test_class_type = mp_obj_new_type(qstr_from_str_static("TestClass"), mp_obj_new_dict(0));
|
||||||
|
rt_store_name(qstr_from_str_static("test_obj"), test_class_instance = rt_call_function_0(test_class_type));
|
||||||
|
rt_store_attr(test_class_instance, qstr_from_str_static("attr"), mp_obj_new_int(42));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
printf("bytes:\n");
|
printf("bytes:\n");
|
||||||
printf(" total %d\n", m_get_total_bytes_allocated());
|
printf(" total %d\n", m_get_total_bytes_allocated());
|
||||||
|
Loading…
Reference in New Issue
Block a user