Skip to content
GitLab
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Sign in
Toggle navigation
Menu
Open sidebar
TASTE
uPython-mirror
Commits
37977b7b
Commit
37977b7b
authored
Apr 30, 2014
by
Damien George
Browse files
Merge pull request #528 from pfalcon/native-subclass1
Initial support for subclassing native types
parents
4ae52d45
c9633101
Changes
5
Hide whitespace changes
Inline
Side-by-side
py/objtype.c
View file @
37977b7b
#include
<stdio.h>
#include
<stddef.h>
#include
<string.h>
#include
<assert.h>
...
...
@@ -9,6 +11,13 @@
#include
"runtime0.h"
#include
"runtime.h"
#if 0 // print debugging info
#define DEBUG_PRINT (1)
#define DEBUG_printf DEBUG_printf
#else
// don't print debugging info
#define DEBUG_printf(...) (void)0
#endif
/******************************************************************************/
// class object
// creating an instance of a class makes one of these objects
...
...
@@ -16,26 +25,88 @@
typedef
struct
_mp_obj_class_t
{
mp_obj_base_t
base
;
mp_map_t
members
;
mp_obj_t
subobj
[];
// TODO maybe cache __getattr__ and __setattr__ for efficient lookup of them
}
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
);
#define is_native_type(type) ((type)->make_new != class_make_new)
STATIC
mp_obj_t
class_make_new
(
mp_obj_t
self_in
,
uint
n_args
,
uint
n_kw
,
const
mp_obj_t
*
args
);
STATIC
mp_obj_t
mp_obj_new_class
(
mp_obj_t
class
,
uint
subobjs
)
{
mp_obj_class_t
*
o
=
m_new_obj_var
(
mp_obj_class_t
,
mp_obj_t
,
subobjs
);
o
->
base
.
type
=
class
;
mp_map_init
(
&
o
->
members
,
0
);
mp_seq_clear
(
o
->
subobj
,
0
,
subobjs
,
sizeof
(
*
o
->
subobj
));
return
o
;
}
STATIC
int
class_count_native_bases
(
const
mp_obj_type_t
*
type
,
const
mp_obj_type_t
**
last_native_base
)
{
uint
len
;
mp_obj_t
*
items
;
mp_obj_tuple_get
(
type
->
bases_tuple
,
&
len
,
&
items
);
int
count
=
0
;
for
(
uint
i
=
0
;
i
<
len
;
i
++
)
{
assert
(
MP_OBJ_IS_TYPE
(
items
[
i
],
&
mp_type_type
));
if
(
is_native_type
((
const
mp_obj_type_t
*
)
items
[
i
]))
{
*
last_native_base
=
items
[
i
];
count
++
;
}
else
{
count
+=
class_count_native_bases
(
items
[
i
],
last_native_base
);
}
}
return
count
;
}
// TODO
// This implements depth-first left-to-right MRO, which is not compliant with Python3 MRO
// http://python-history.blogspot.com/2010/06/method-resolution-order.html
// https://www.python.org/download/releases/2.3/mro/
//
// will return MP_OBJ_NULL if not found
STATIC
mp_obj_t
mp_obj_class_lookup
(
const
mp_obj_type_t
*
type
,
qstr
attr
)
{
// will return MP_OBJ_SENTINEL if special method was found in a native type base
// via slot id (meth_offset). As there can be only one native base, it's known that it
// applies to instance->subobj[0]. In most cases, we also don't need to know which type
// it was - because instance->subobj[0] is of that type. The only exception is when
// object is not yet constructed, then we need to know base native type to construct
// instance->subobj[0]. This case is handled via class_count_native_bases() though.
STATIC
void
mp_obj_class_lookup
(
mp_obj_class_t
*
o
,
const
mp_obj_type_t
*
type
,
qstr
attr
,
machine_uint_t
meth_offset
,
mp_obj_t
*
dest
)
{
assert
(
dest
[
0
]
==
NULL
);
assert
(
dest
[
1
]
==
NULL
);
for
(;;)
{
// Optimize special method lookup for native types
// This avoids extra method_name => slot lookup. On the other hand,
// this should not be applied to class types, as will result in extra
// lookup either.
if
(
meth_offset
!=
0
&&
is_native_type
(
type
))
{
if
(
*
(
void
**
)((
char
*
)
type
+
meth_offset
)
!=
NULL
)
{
DEBUG_printf
(
"mp_obj_class_lookup: matched special meth slot for %s
\n
"
,
qstr_str
(
attr
));
dest
[
0
]
=
MP_OBJ_SENTINEL
;
return
;
}
}
if
(
type
->
locals_dict
!=
NULL
)
{
// search locals_dict (the set of methods/attributes)
assert
(
MP_OBJ_IS_TYPE
(
type
->
locals_dict
,
&
mp_type_dict
));
// Micro Python restriction, for now
mp_map_t
*
locals_map
=
mp_obj_dict_get_map
(
type
->
locals_dict
);
mp_map_elem_t
*
elem
=
mp_map_lookup
(
locals_map
,
MP_OBJ_NEW_QSTR
(
attr
),
MP_MAP_LOOKUP
);
if
(
elem
!=
NULL
)
{
return
elem
->
value
;
dest
[
0
]
=
elem
->
value
;
if
(
o
!=
MP_OBJ_NULL
&&
is_native_type
(
type
))
{
dest
[
1
]
=
o
->
subobj
[
0
];
}
return
;
}
}
// Try this for completeness, by all native methods should be statically defined
// in locals_dict, and would be handled by above.
if
(
o
!=
MP_OBJ_NULL
&&
is_native_type
(
type
))
{
mp_load_method_maybe
(
o
->
subobj
[
0
],
attr
,
dest
);
if
(
dest
[
0
]
!=
MP_OBJ_NULL
)
{
return
;
}
}
...
...
@@ -43,20 +114,20 @@ STATIC mp_obj_t mp_obj_class_lookup(const mp_obj_type_t *type, qstr attr) {
// for a const struct, this entry might be NULL
if
(
type
->
bases_tuple
==
MP_OBJ_NULL
)
{
return
MP_OBJ_NULL
;
return
;
}
uint
len
;
mp_obj_t
*
items
;
mp_obj_tuple_get
(
type
->
bases_tuple
,
&
len
,
&
items
);
if
(
len
==
0
)
{
return
MP_OBJ_NULL
;
return
;
}
for
(
uint
i
=
0
;
i
<
len
-
1
;
i
++
)
{
assert
(
MP_OBJ_IS_TYPE
(
items
[
i
],
&
mp_type_type
));
mp_obj_t
obj
=
mp_obj_class_lookup
((
mp_obj_type_t
*
)
items
[
i
],
attr
);
if
(
obj
!=
MP_OBJ_NULL
)
{
return
obj
;
mp_obj_class_lookup
(
o
,
(
mp_obj_type_t
*
)
items
[
i
],
attr
,
meth_offset
,
dest
);
if
(
dest
[
0
]
!=
MP_OBJ_NULL
)
{
return
;
}
}
...
...
@@ -69,14 +140,20 @@ STATIC mp_obj_t mp_obj_class_lookup(const mp_obj_type_t *type, qstr attr) {
STATIC
void
class_print
(
void
(
*
print
)(
void
*
env
,
const
char
*
fmt
,
...),
void
*
env
,
mp_obj_t
self_in
,
mp_print_kind_t
kind
)
{
mp_obj_class_t
*
self
=
self_in
;
qstr
meth
=
(
kind
==
PRINT_STR
)
?
MP_QSTR___str__
:
MP_QSTR___repr__
;
mp_obj_t
member
=
mp_obj_class_lookup
(
self
->
base
.
type
,
meth
);
if
(
member
==
MP_OBJ_NULL
&&
kind
==
PRINT_STR
)
{
mp_obj_t
member
[
2
]
=
{
MP_OBJ_NULL
};
mp_obj_class_lookup
(
self
,
self
->
base
.
type
,
meth
,
offsetof
(
mp_obj_type_t
,
print
),
member
);
if
(
member
[
0
]
==
MP_OBJ_NULL
&&
kind
==
PRINT_STR
)
{
// If there's no __str__, fall back to __repr__
member
=
mp_obj_class_lookup
(
self
->
base
.
type
,
MP_QSTR___repr__
);
mp_obj_class_lookup
(
self
,
self
->
base
.
type
,
MP_QSTR___repr__
,
0
,
member
);
}
if
(
member
!=
MP_OBJ_NULL
)
{
mp_obj_t
r
=
mp_call_function_1
(
member
,
self_in
);
if
(
member
[
0
]
==
MP_OBJ_SENTINEL
)
{
mp_obj_print_helper
(
print
,
env
,
self
->
subobj
[
0
],
kind
);
return
;
}
if
(
member
[
0
]
!=
MP_OBJ_NULL
)
{
mp_obj_t
r
=
mp_call_function_1
(
member
[
0
],
self_in
);
mp_obj_print_helper
(
print
,
env
,
r
,
PRINT_STR
);
return
;
}
...
...
@@ -89,21 +166,34 @@ STATIC mp_obj_t class_make_new(mp_obj_t self_in, uint n_args, uint n_kw, const m
assert
(
MP_OBJ_IS_TYPE
(
self_in
,
&
mp_type_type
));
mp_obj_type_t
*
self
=
self_in
;
mp_obj_t
o
=
mp_obj_new_class
(
self_in
);
const
mp_obj_type_t
*
native_base
;
uint
num_native_bases
=
class_count_native_bases
(
self
,
&
native_base
);
assert
(
num_native_bases
<
2
);
// look for __init__ function
mp_obj_t
init_fn
=
mp_obj_class_lookup
(
self
,
MP_QSTR___init__
);
mp_obj_class_t
*
o
=
mp_obj_new_class
(
self_in
,
num_native_bases
);
if
(
init_fn
!=
MP_OBJ_NULL
)
{
// call __init__ function
// look for __init__ function
mp_obj_t
init_fn
[
2
]
=
{
MP_OBJ_NULL
};
mp_obj_class_lookup
(
NULL
,
self
,
MP_QSTR___init__
,
offsetof
(
mp_obj_type_t
,
make_new
),
init_fn
);
if
(
init_fn
[
0
]
==
MP_OBJ_SENTINEL
)
{
// Native type's constructor is what wins - it gets all our arguments,
// and none Python classes are initialized at all.
o
->
subobj
[
0
]
=
native_base
->
make_new
((
mp_obj_type_t
*
)
native_base
,
n_args
,
n_kw
,
args
);
}
else
if
(
init_fn
[
0
]
!=
MP_OBJ_NULL
)
{
// We need to default-initialize any native subobjs first
if
(
num_native_bases
>
0
)
{
o
->
subobj
[
0
]
=
native_base
->
make_new
((
mp_obj_type_t
*
)
native_base
,
0
,
0
,
NULL
);
}
// now call Python class __init__ function with all args
mp_obj_t
init_ret
;
if
(
n_args
==
0
&&
n_kw
==
0
)
{
init_ret
=
mp_call_function_n_kw
(
init_fn
,
1
,
0
,
(
mp_obj_t
*
)
&
o
);
init_ret
=
mp_call_function_n_kw
(
init_fn
[
0
]
,
1
,
0
,
(
mp_obj_t
*
)
&
o
);
}
else
{
mp_obj_t
*
args2
=
m_new
(
mp_obj_t
,
1
+
n_args
+
2
*
n_kw
);
args2
[
0
]
=
o
;
memcpy
(
args2
+
1
,
args
,
(
n_args
+
2
*
n_kw
)
*
sizeof
(
mp_obj_t
));
init_ret
=
mp_call_function_n_kw
(
init_fn
,
n_args
+
1
,
n_kw
,
args2
);
init_ret
=
mp_call_function_n_kw
(
init_fn
[
0
]
,
n_args
+
1
,
n_kw
,
args2
);
m_del
(
mp_obj_t
,
args2
,
1
+
n_args
+
2
*
n_kw
);
}
if
(
init_ret
!=
mp_const_none
)
{
...
...
@@ -111,9 +201,8 @@ STATIC mp_obj_t class_make_new(mp_obj_t self_in, uint n_args, uint n_kw, const m
}
}
else
{
// TODO
if
(
n_args
!=
0
)
{
nlr_raise
(
mp_obj_new_exception_msg_varg
(
&
mp_type_TypeError
,
"
function takes 0 positional arguments but %d were given"
,
n_args
));
nlr_raise
(
mp_obj_new_exception_msg_varg
(
&
mp_type_TypeError
,
"
object() takes no parameters"
));
}
}
...
...
@@ -132,12 +221,17 @@ STATIC const qstr unary_op_method_name[] = {
STATIC
mp_obj_t
class_unary_op
(
int
op
,
mp_obj_t
self_in
)
{
mp_obj_class_t
*
self
=
self_in
;
qstr
op_name
=
unary_op_method_name
[
op
];
/* Still try to lookup native slot
if (op_name == 0) {
return MP_OBJ_NOT_SUPPORTED;
}
mp_obj_t
member
=
mp_obj_class_lookup
(
self
->
base
.
type
,
op_name
);
if
(
member
!=
MP_OBJ_NULL
)
{
return
mp_call_function_1
(
member
,
self_in
);
*/
mp_obj_t
member
[
2
]
=
{
MP_OBJ_NULL
};
mp_obj_class_lookup
(
self
,
self
->
base
.
type
,
op_name
,
offsetof
(
mp_obj_type_t
,
unary_op
),
member
);
if
(
member
[
0
]
==
MP_OBJ_SENTINEL
)
{
return
mp_unary_op
(
op
,
self
->
subobj
[
0
]);
}
else
if
(
member
[
0
]
!=
MP_OBJ_NULL
)
{
return
mp_call_function_1
(
member
[
0
],
self_in
);
}
else
{
return
MP_OBJ_NOT_SUPPORTED
;
}
...
...
@@ -188,6 +282,7 @@ STATIC const qstr binary_op_method_name[] = {
// Conversion means dealing with static/class methods, callables, and values.
// see http://docs.python.org/3.3/howto/descriptor.html
STATIC
void
class_convert_return_attr
(
mp_obj_t
self
,
mp_obj_t
member
,
mp_obj_t
*
dest
)
{
assert
(
dest
[
1
]
==
NULL
);
if
(
MP_OBJ_IS_TYPE
(
member
,
&
mp_type_staticmethod
))
{
// return just the function
dest
[
0
]
=
((
mp_obj_static_class_method_t
*
)
member
)
->
fun
;
...
...
@@ -210,14 +305,19 @@ STATIC mp_obj_t class_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
// __getattr__ or __getattribute__. It only looks in the class dictionary.
mp_obj_class_t
*
lhs
=
lhs_in
;
qstr
op_name
=
binary_op_method_name
[
op
];
/* Still try to lookup native slot
if (op_name == 0) {
return MP_OBJ_NOT_SUPPORTED;
}
mp_obj_t
member
=
mp_obj_class_lookup
(
lhs
->
base
.
type
,
op_name
);
if
(
member
!=
MP_OBJ_NULL
)
{
*/
mp_obj_t
member
[
2
]
=
{
MP_OBJ_NULL
};
mp_obj_class_lookup
(
lhs
,
lhs
->
base
.
type
,
op_name
,
offsetof
(
mp_obj_type_t
,
binary_op
),
member
);
if
(
member
[
0
]
==
MP_OBJ_SENTINEL
)
{
return
mp_binary_op
(
op
,
lhs
->
subobj
[
0
],
rhs_in
);
}
else
if
(
member
[
0
]
!=
MP_OBJ_NULL
)
{
mp_obj_t
dest
[
3
];
dest
[
1
]
=
MP_OBJ_NULL
;
class_convert_return_attr
(
lhs_in
,
member
,
dest
);
class_convert_return_attr
(
lhs_in
,
member
[
0
]
,
dest
);
dest
[
2
]
=
rhs_in
;
return
mp_call_method_n_kw
(
1
,
0
,
dest
);
}
else
{
...
...
@@ -237,7 +337,8 @@ STATIC void class_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
return
;
}
mp_obj_t
member
=
mp_obj_class_lookup
(
self
->
base
.
type
,
attr
);
mp_obj_class_lookup
(
self
,
self
->
base
.
type
,
attr
,
0
,
dest
);
mp_obj_t
member
=
dest
[
0
];
if
(
member
!=
MP_OBJ_NULL
)
{
if
(
0
)
{
#if MICROPY_ENABLE_PROPERTY
...
...
@@ -255,7 +356,11 @@ STATIC void class_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
#endif
}
else
{
// not a property
class_convert_return_attr
(
self_in
,
member
,
dest
);
// if we don't yet have bound method (supposedly from native base), go
// try to convert own attrs.
if
(
dest
[
1
]
==
MP_OBJ_NULL
)
{
class_convert_return_attr
(
self_in
,
member
,
dest
);
}
}
return
;
}
...
...
@@ -280,11 +385,12 @@ STATIC bool class_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) {
#if MICROPY_ENABLE_PROPERTY
// for property, we need to do a lookup first in the class dict
// this makes all stores slow... how to fix?
mp_obj_t
member
=
mp_obj_class_lookup
(
self
->
base
.
type
,
attr
);
if
(
member
!=
MP_OBJ_NULL
&&
MP_OBJ_IS_TYPE
(
member
,
&
mp_type_property
))
{
mp_obj_t
member
[
2
]
=
{
MP_OBJ_NULL
};
mp_obj_class_lookup
(
self
,
self
->
base
.
type
,
attr
,
0
,
member
);
if
(
member
[
0
]
!=
MP_OBJ_NULL
&&
MP_OBJ_IS_TYPE
(
member
[
0
],
&
mp_type_property
))
{
// attribute already exists and is a property
// delegate the store to the property
const
mp_obj_t
*
proxy
=
mp_obj_property_get
(
member
);
const
mp_obj_t
*
proxy
=
mp_obj_property_get
(
member
[
0
]
);
if
(
proxy
[
1
]
==
mp_const_none
)
{
// TODO better error message
return
false
;
...
...
@@ -309,25 +415,27 @@ STATIC bool class_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) {
STATIC
mp_obj_t
class_subscr
(
mp_obj_t
self_in
,
mp_obj_t
index
,
mp_obj_t
value
)
{
mp_obj_class_t
*
self
=
self_in
;
mp_obj_t
member
;
mp_obj_t
member
[
2
]
=
{
MP_OBJ_NULL
}
;
uint
meth_args
;
if
(
value
==
MP_OBJ_NULL
)
{
// delete item
member
=
mp_obj_class_lookup
(
self
->
base
.
type
,
MP_QSTR___delitem__
);
mp_obj_class_lookup
(
self
,
self
->
base
.
type
,
MP_QSTR___delitem__
,
offsetof
(
mp_obj_type_t
,
subscr
),
member
);
meth_args
=
2
;
}
else
if
(
value
==
MP_OBJ_SENTINEL
)
{
// load item
member
=
mp_obj_class_lookup
(
self
->
base
.
type
,
MP_QSTR___getitem__
);
mp_obj_class_lookup
(
self
,
self
->
base
.
type
,
MP_QSTR___getitem__
,
offsetof
(
mp_obj_type_t
,
subscr
),
member
);
meth_args
=
2
;
}
else
{
// store item
member
=
mp_obj_class_lookup
(
self
->
base
.
type
,
MP_QSTR___setitem__
);
mp_obj_class_lookup
(
self
,
self
->
base
.
type
,
MP_QSTR___setitem__
,
offsetof
(
mp_obj_type_t
,
subscr
),
member
);
meth_args
=
3
;
}
if
(
member
!=
MP_OBJ_NULL
)
{
if
(
member
[
0
]
==
MP_OBJ_SENTINEL
)
{
return
mp_obj_subscr
(
self
->
subobj
[
0
],
index
,
value
);
}
else
if
(
member
[
0
]
!=
MP_OBJ_NULL
)
{
mp_obj_t
args
[
3
]
=
{
self_in
,
index
,
value
};
// TODO probably need to call class_convert_return_attr, and use mp_call_method_n_kw
mp_obj_t
ret
=
mp_call_function_n_kw
(
member
,
meth_args
,
0
,
args
);
mp_obj_t
ret
=
mp_call_function_n_kw
(
member
[
0
]
,
meth_args
,
0
,
args
);
if
(
value
==
MP_OBJ_SENTINEL
)
{
return
ret
;
}
else
{
...
...
@@ -340,11 +448,15 @@ STATIC mp_obj_t class_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
STATIC
mp_obj_t
class_call
(
mp_obj_t
self_in
,
uint
n_args
,
uint
n_kw
,
const
mp_obj_t
*
args
)
{
mp_obj_class_t
*
self
=
self_in
;
mp_obj_t
member
=
mp_obj_class_lookup
(
self
->
base
.
type
,
MP_QSTR___call__
);
if
(
member
==
MP_OBJ_NULL
)
{
return
member
;
mp_obj_t
member
[
2
]
=
{
MP_OBJ_NULL
};
mp_obj_class_lookup
(
self
,
self
->
base
.
type
,
MP_QSTR___call__
,
offsetof
(
mp_obj_type_t
,
call
),
member
);
if
(
member
[
0
]
==
MP_OBJ_NULL
)
{
return
MP_OBJ_NULL
;
}
if
(
member
[
0
]
==
MP_OBJ_SENTINEL
)
{
return
mp_call_function_n_kw
(
self
->
subobj
[
0
],
n_args
,
n_kw
,
args
);
}
mp_obj_t
meth
=
mp_obj_new_bound_meth
(
member
,
self
);
mp_obj_t
meth
=
mp_obj_new_bound_meth
(
member
[
0
]
,
self
);
return
mp_call_function_n_kw
(
meth
,
n_args
,
n_kw
,
args
);
}
...
...
@@ -403,21 +515,22 @@ STATIC void type_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
return
;
}
#endif
mp_obj_t
member
=
mp_obj_class_lookup
(
self
,
attr
);
if
(
member
!=
MP_OBJ_NULL
)
{
mp_obj_t
member
[
2
]
=
{
MP_OBJ_NULL
};
mp_obj_class_lookup
(
NULL
,
self
,
attr
,
0
,
member
);
if
(
member
[
0
]
!=
MP_OBJ_NULL
)
{
// 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
(
member
,
&
mp_type_staticmethod
))
{
if
(
MP_OBJ_IS_TYPE
(
member
[
0
]
,
&
mp_type_staticmethod
))
{
// return just the function
dest
[
0
]
=
((
mp_obj_static_class_method_t
*
)
member
)
->
fun
;
}
else
if
(
MP_OBJ_IS_TYPE
(
member
,
&
mp_type_classmethod
))
{
dest
[
0
]
=
((
mp_obj_static_class_method_t
*
)
member
[
0
]
)
->
fun
;
}
else
if
(
MP_OBJ_IS_TYPE
(
member
[
0
]
,
&
mp_type_classmethod
))
{
// return a bound method, with self being this class
dest
[
0
]
=
((
mp_obj_static_class_method_t
*
)
member
)
->
fun
;
dest
[
0
]
=
((
mp_obj_static_class_method_t
*
)
member
[
0
]
)
->
fun
;
dest
[
1
]
=
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
[
0
]
=
(
mp_obj_t
)
member
;
dest
[
0
]
=
member
[
0
]
;
}
}
}
...
...
@@ -474,6 +587,20 @@ const mp_obj_type_t mp_type_type = {
mp_obj_t
mp_obj_new_type
(
qstr
name
,
mp_obj_t
bases_tuple
,
mp_obj_t
locals_dict
)
{
assert
(
MP_OBJ_IS_TYPE
(
bases_tuple
,
&
mp_type_tuple
));
// Micro Python restriction, for now
assert
(
MP_OBJ_IS_TYPE
(
locals_dict
,
&
mp_type_dict
));
// Micro Python restriction, for now
// Basic validation of base classes
uint
len
;
mp_obj_t
*
items
;
mp_obj_tuple_get
(
bases_tuple
,
&
len
,
&
items
);
for
(
uint
i
=
0
;
i
<
len
;
i
++
)
{
assert
(
MP_OBJ_IS_TYPE
(
items
[
i
],
&
mp_type_type
));
mp_obj_type_t
*
t
=
items
[
i
];
// TODO: Verify with CPy, tested on function type
if
(
t
->
make_new
==
NULL
)
{
nlr_raise
(
mp_obj_new_exception_msg_varg
(
&
mp_type_TypeError
,
"type '%s' is not an acceptable base type"
,
qstr_str
(
t
->
name
)));
}
}
mp_obj_type_t
*
o
=
m_new0
(
mp_obj_type_t
,
1
);
o
->
base
.
type
=
&
mp_type_type
;
o
->
name
=
name
;
...
...
@@ -487,6 +614,13 @@ mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict)
o
->
call
=
class_call
;
o
->
bases_tuple
=
bases_tuple
;
o
->
locals_dict
=
locals_dict
;
const
mp_obj_type_t
*
native_base
;
uint
num_native_bases
=
class_count_native_bases
(
o
,
&
native_base
);
if
(
num_native_bases
>
1
)
{
nlr_raise
(
mp_obj_new_exception_msg
(
&
mp_type_TypeError
,
"multiple bases have instance lay-out conflict"
));
}
return
o
;
}
...
...
@@ -536,9 +670,10 @@ STATIC void super_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
mp_obj_tuple_get
(
type
->
bases_tuple
,
&
len
,
&
items
);
for
(
uint
i
=
0
;
i
<
len
;
i
++
)
{
assert
(
MP_OBJ_IS_TYPE
(
items
[
i
],
&
mp_type_type
));
mp_obj_t
member
=
mp_obj_class_lookup
((
mp_obj_type_t
*
)
items
[
i
],
attr
);
if
(
member
!=
MP_OBJ_NULL
)
{
class_convert_return_attr
(
self
->
obj
,
member
,
dest
);
mp_obj_t
member
[
2
]
=
{
MP_OBJ_NULL
};
mp_obj_class_lookup
(
self
->
obj
,
(
mp_obj_type_t
*
)
items
[
i
],
attr
,
0
,
member
);
if
(
member
[
0
]
!=
MP_OBJ_NULL
)
{
class_convert_return_attr
(
self
->
obj
,
member
[
0
],
dest
);
return
;
}
}
...
...
tests/basics/subclass-native1.py
0 → 100644
View file @
37977b7b
class
mylist
(
list
):
pass
a
=
mylist
([
1
,
2
,
5
])
# Test setting instance attr
a
.
attr
=
"something"
# Test base type __str__
print
(
a
)
# Test getting instance attr
print
(
a
.
attr
)
# Test base type ->subscr
print
(
a
[
-
1
])
a
[
0
]
=
-
1
print
(
a
)
# Test another base type unary op
print
(
len
(
a
))
# Test binary op of base type, with 2nd arg being raw base type
print
(
a
+
[
20
,
30
,
40
])
# Test binary op of base type, with 2nd arg being same class as 1st arg
# TODO: Faults
#print(a + a)
def
foo
():
print
(
"hello from foo"
)
try
:
class
myfunc
(
type
(
foo
)):
pass
except
TypeError
:
print
(
"TypeError"
)
tests/basics/subclass-native2.py
0 → 100644
View file @
37977b7b
class
Base1
:
def
__init__
(
self
,
*
args
):
print
(
"Base1.__init__"
,
args
)
class
Clist1
(
Base1
,
list
):
pass
class
Ctuple1
(
Base1
,
tuple
):
pass
a
=
Clist1
()
print
(
len
(
a
))
a
=
Clist1
([
1
,
2
,
3
])
print
(
len
(
a
))
a
=
Ctuple1
()
print
(
len
(
a
))
a
=
Ctuple1
([
1
,
2
,
3
])
# TODO: Faults
#print(len(a))
print
(
"---"
)
class
Clist2
(
list
,
Base1
):
pass
class
Ctuple2
(
tuple
,
Base1
):
pass
a
=
Clist2
()
print
(
len
(
a
))
a
=
Clist2
([
1
,
2
,
3
])
print
(
len
(
a
))
#a = Ctuple2()
#print(len(a))
#a = Ctuple2([1, 2, 3])
#print(len(a))
tests/basics/subclass-native3.py
0 → 100644
View file @
37977b7b
class
MyExc
(
Exception
):
pass
e
=
MyExc
(
100
,
"Some error"
)
print
(
e
)
# TODO: Prints native base class name
#print(repr(e))
print
(
e
.
args
)
tests/basics/subclass-native4.py
0 → 100644
View file @
37977b7b
# Test calling non-special method inherited from native type
class
mylist
(
list
):
pass
l
=
mylist
([
1
,
2
,
3
])
print
(
l
)
l
.
append
(
10
)
print
(
l
)
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment