objtype.c 29.2 KB
Newer Older
1
2
#include <stdio.h>
#include <stddef.h>
3
4
#include <string.h>
#include <assert.h>
5
6
7
8

#include "nlr.h"
#include "misc.h"
#include "mpconfig.h"
9
#include "qstr.h"
10
#include "obj.h"
11
#include "runtime0.h"
12
13
#include "runtime.h"

14
15
16
17
18
19
20
#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

21
22
23
24
25
26
27
/******************************************************************************/
// 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;
28
    mp_obj_t subobj[];
Damien George's avatar
Damien George committed
29
    // TODO maybe cache __getattr__ and __setattr__ for efficient lookup of them
30
31
} mp_obj_class_t;

32
33
34
35
36
#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);
37
38
    o->base.type = class;
    mp_map_init(&o->members, 0);
39
    mp_seq_clear(o->subobj, 0, subobjs, sizeof(*o->subobj));
40
41
42
    return o;
}

43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
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/
//
67
// will return MP_OBJ_NULL if not found
68
69
70
71
72
73
// 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.
74
75
76
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);
77
    for (;;) {
78
79
80
81
82
83
84
        // 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));
85
86
                dest[0] = MP_OBJ_SENTINEL;
                return;
87
88
89
            }
        }

90
        if (type->locals_dict != NULL) {
91
            // search locals_dict (the set of methods/attributes)
92
            assert(MP_OBJ_IS_TYPE(type->locals_dict, &mp_type_dict)); // Micro Python restriction, for now
93
            mp_map_t *locals_map = mp_obj_dict_get_map(type->locals_dict);
94
95
            mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP);
            if (elem != NULL) {
96
97
98
99
100
                dest[0] = elem->value;
                if (o != MP_OBJ_NULL && is_native_type(type)) {
                    dest[1] = o->subobj[0];
                }
                return;
101
            }
102
103
        }

104
105
        // Try this for completeness, by all native methods should be statically defined
        // in locals_dict, and would be handled by above.
106
107
108
        if (o != MP_OBJ_NULL && is_native_type(type)) {
            mp_load_method_maybe(o->subobj[0], attr, dest);
            if (dest[0] != MP_OBJ_NULL) {
109
                return;
110
111
112
            }
        }

113
114
115
        // attribute not found, keep searching base classes

        // for a const struct, this entry might be NULL
116
        if (type->bases_tuple == MP_OBJ_NULL) {
117
            return;
118
119
120
121
        }

        uint len;
        mp_obj_t *items;
122
        mp_obj_tuple_get(type->bases_tuple, &len, &items);
123
        if (len == 0) {
124
            return;
125
126
        }
        for (uint i = 0; i < len - 1; i++) {
127
            assert(MP_OBJ_IS_TYPE(items[i], &mp_type_type));
128
129
130
            mp_obj_class_lookup(o, (mp_obj_type_t*)items[i], attr, meth_offset, dest);
            if (dest[0] != MP_OBJ_NULL) {
                return;
131
132
133
134
            }
        }

        // search last base (simple tail recursion elimination)
135
        assert(MP_OBJ_IS_TYPE(items[len - 1], &mp_type_type));
136
        type = (mp_obj_type_t*)items[len - 1];
137
138
139
    }
}

140
STATIC void class_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
141
142
    mp_obj_class_t *self = self_in;
    qstr meth = (kind == PRINT_STR) ? MP_QSTR___str__ : MP_QSTR___repr__;
143
144
145
    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) {
146
        // If there's no __str__, fall back to __repr__
147
        mp_obj_class_lookup(self, self->base.type, MP_QSTR___repr__, 0, member);
148
149
    }

150
    if (member[0] == MP_OBJ_SENTINEL) {
151
152
153
154
155
156
157
158
159
        // Handle Exception subclasses specially
        if (mp_obj_is_native_exception_instance(self->subobj[0])) {
            if (kind != PRINT_STR) {
                print(env, "%s", qstr_str(self->base.type->name));
            }
            mp_obj_print_helper(print, env, self->subobj[0], kind | PRINT_EXC_SUBCLASS);
        } else {
            mp_obj_print_helper(print, env, self->subobj[0], kind);
        }
160
        return;
161
162
    }

163
164
    if (member[0] != MP_OBJ_NULL) {
        mp_obj_t r = mp_call_function_1(member[0], self_in);
165
166
167
168
169
        mp_obj_print_helper(print, env, r, PRINT_STR);
        return;
    }

    // TODO: CPython prints fully-qualified type name
170
171
172
    print(env, "<%s object at %p>", mp_obj_get_type_str(self_in), self_in);
}

173
STATIC mp_obj_t class_make_new(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
174
    assert(MP_OBJ_IS_TYPE(self_in, &mp_type_type));
175
    mp_obj_type_t *self = self_in;
176

177
178
179
    const mp_obj_type_t *native_base;
    uint num_native_bases = class_count_native_bases(self, &native_base);
    assert(num_native_bases < 2);
180

181
    mp_obj_class_t *o = mp_obj_new_class(self_in, num_native_bases);
182

183
    // look for __init__ function
184
185
    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);
186

187
    if (init_fn[0] == MP_OBJ_SENTINEL) {
188
189
190
        // 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);
191
    } else if (init_fn[0] != MP_OBJ_NULL) {
192
193
194
195
196
        // 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
197
        mp_obj_t init_ret;
198
        if (n_args == 0 && n_kw == 0) {
199
            init_ret = mp_call_function_n_kw(init_fn[0], 1, 0, (mp_obj_t*)&o);
200
        } else {
201
202
203
            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));
204
            init_ret = mp_call_function_n_kw(init_fn[0], n_args + 1, n_kw, args2);
205
            m_del(mp_obj_t, args2, 1 + n_args + 2 * n_kw);
206
207
        }
        if (init_ret != mp_const_none) {
208
            nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "__init__() should return None, not '%s'", mp_obj_get_type_str(init_ret)));
209
210
211
212
        }

    } else {
        if (n_args != 0) {
213
            nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "object() takes no parameters"));
214
215
216
217
218
219
        }
    }

    return o;
}

220
STATIC const qstr unary_op_method_name[] = {
Damien George's avatar
Damien George committed
221
222
223
224
225
226
    [MP_UNARY_OP_BOOL] = MP_QSTR___bool__,
    [MP_UNARY_OP_LEN] = MP_QSTR___len__,
    //[MP_UNARY_OP_POSITIVE,
    //[MP_UNARY_OP_NEGATIVE,
    //[MP_UNARY_OP_INVERT,
    [MP_UNARY_OP_NOT] = MP_QSTR_, // don't need to implement this, used to make sure array has full size
227
228
};

229
STATIC mp_obj_t class_unary_op(int op, mp_obj_t self_in) {
230
231
    mp_obj_class_t *self = self_in;
    qstr op_name = unary_op_method_name[op];
232
    /* Still try to lookup native slot
233
    if (op_name == 0) {
234
        return MP_OBJ_NOT_SUPPORTED;
235
    }
236
    */
237
238
239
    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) {
240
        return mp_unary_op(op, self->subobj[0]);
241
242
    } else if (member[0] != MP_OBJ_NULL) {
        return mp_call_function_1(member[0], self_in);
243
    } else {
244
        return MP_OBJ_NOT_SUPPORTED;
245
246
247
    }
}

248
STATIC const qstr binary_op_method_name[] = {
249
    /*
Damien George's avatar
Damien George committed
250
251
252
253
254
    MP_BINARY_OP_OR,
    MP_BINARY_OP_XOR,
    MP_BINARY_OP_AND,
    MP_BINARY_OP_LSHIFT,
    MP_BINARY_OP_RSHIFT,
255
    */
Damien George's avatar
Damien George committed
256
257
    [MP_BINARY_OP_ADD] = MP_QSTR___add__,
    [MP_BINARY_OP_SUBTRACT] = MP_QSTR___sub__,
258
    /*
Damien George's avatar
Damien George committed
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
    MP_BINARY_OP_MULTIPLY,
    MP_BINARY_OP_FLOOR_DIVIDE,
    MP_BINARY_OP_TRUE_DIVIDE,
    MP_BINARY_OP_MODULO,
    MP_BINARY_OP_POWER,
    MP_BINARY_OP_INPLACE_OR,
    MP_BINARY_OP_INPLACE_XOR,
    MP_BINARY_OP_INPLACE_AND,
    MP_BINARY_OP_INPLACE_LSHIFT,
    MP_BINARY_OP_INPLACE_RSHIFT,
    MP_BINARY_OP_INPLACE_ADD,
    MP_BINARY_OP_INPLACE_SUBTRACT,
    MP_BINARY_OP_INPLACE_MULTIPLY,
    MP_BINARY_OP_INPLACE_FLOOR_DIVIDE,
    MP_BINARY_OP_INPLACE_TRUE_DIVIDE,
    MP_BINARY_OP_INPLACE_MODULO,
    MP_BINARY_OP_INPLACE_POWER,
    MP_BINARY_OP_LESS,
    MP_BINARY_OP_MORE,
    MP_BINARY_OP_EQUAL,
    MP_BINARY_OP_LESS_EQUAL,
    MP_BINARY_OP_MORE_EQUAL,
    MP_BINARY_OP_NOT_EQUAL,
    MP_BINARY_OP_IN,
    MP_BINARY_OP_IS,
284
    */
Damien George's avatar
Damien George committed
285
    [MP_BINARY_OP_EXCEPTION_MATCH] = MP_QSTR_, // not implemented, used to make sure array has full size
286
287
};

288
289
290
291
292
// Given a member that was extracted from an instance, convert it correctly
// and put the result in the dest[] array for a possible method call.
// 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) {
293
    assert(dest[1] == NULL);
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
    if (MP_OBJ_IS_TYPE(member, &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)) {
        // return a bound method, with self being the type of this object
        dest[0] = ((mp_obj_static_class_method_t*)member)->fun;
        dest[1] = mp_obj_get_type(self);
    } else if (mp_obj_is_callable(member)) {
        // return a bound method, with self being this object
        dest[0] = member;
        dest[1] = self;
    } else {
        // class member is a value, so just return that value
        dest[0] = member;
    }
}

311
STATIC mp_obj_t class_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
312
313
    // Note: For ducktyping, CPython does not look in the instance members or use
    // __getattr__ or __getattribute__.  It only looks in the class dictionary.
314
    mp_obj_class_t *lhs = lhs_in;
315
    qstr op_name = binary_op_method_name[op];
316
    /* Still try to lookup native slot
317
    if (op_name == 0) {
318
        return MP_OBJ_NOT_SUPPORTED;
319
    }
320
    */
321
322
323
    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) {
324
        return mp_binary_op(op, lhs->subobj[0], rhs_in);
325
    } else if (member[0] != MP_OBJ_NULL) {
326
327
        mp_obj_t dest[3];
        dest[1] = MP_OBJ_NULL;
328
        class_convert_return_attr(lhs_in, member[0], dest);
329
330
        dest[2] = rhs_in;
        return mp_call_method_n_kw(1, 0, dest);
331
    } else {
332
        return MP_OBJ_NOT_SUPPORTED;
333
334
335
    }
}

336
STATIC void class_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
337
338
    // logic: look in obj members then class locals (TODO check this against CPython)
    mp_obj_class_t *self = self_in;
339

340
341
342
    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
343
        // TODO should we check for properties?
344
        dest[0] = elem->value;
345
346
        return;
    }
347

348
349
    mp_obj_class_lookup(self, self->base.type, attr, 0, dest);
    mp_obj_t member = dest[0];
350
    if (member != MP_OBJ_NULL) {
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
        if (0) {
#if MICROPY_ENABLE_PROPERTY
        } else if (MP_OBJ_IS_TYPE(member, &mp_type_property)) {
            // object member is a property
            // delegate the store to the property
            // TODO should this be part of class_convert_return_attr?
            const mp_obj_t *proxy = mp_obj_property_get(member);
            if (proxy[0] == mp_const_none) {
                // TODO
            } else {
                dest[0] = mp_call_function_n_kw(proxy[0], 1, 0, &self_in);
                // TODO should we convert the returned value using class_convert_return_attr?
            }
#endif
        } else {
            // not a property
367
368
369
370
371
            // 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);
            }
372
        }
Damien George's avatar
Damien George committed
373
374
375
376
377
378
379
380
381
382
383
384
        return;
    }

    // try __getattr__
    if (attr != MP_QSTR___getattr__) {
        mp_obj_t dest2[3];
        mp_load_method_maybe(self_in, MP_QSTR___getattr__, dest2);
        if (dest2[0] != MP_OBJ_NULL) {
            // __getattr__ exists, call it and return its result
            // XXX if this fails to load the requested attr, should we catch the attribute error and return silently?
            dest2[2] = MP_OBJ_NEW_QSTR(attr);
            dest[0] = mp_call_method_n_kw(1, 0, dest2);
385
386
387
388
389
            return;
        }
    }
}

390
STATIC bool class_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) {
391
    mp_obj_class_t *self = self_in;
392
393
394
395

#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?
396
397
398
    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)) {
399
400
        // attribute already exists and is a property
        // delegate the store to the property
401
        const mp_obj_t *proxy = mp_obj_property_get(member[0]);
402
403
404
405
406
407
408
409
410
411
412
        if (proxy[1] == mp_const_none) {
            // TODO better error message
            return false;
        } else {
            mp_obj_t dest[2] = {self_in, value};
            mp_call_function_n_kw(proxy[1], 2, 0, dest);
            return true;
        }
    }
#endif

413
414
    if (value == MP_OBJ_NULL) {
        // delete attribute
415
416
        mp_map_elem_t *elem = mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_REMOVE_IF_FOUND);
        return elem != NULL;
417
418
419
420
421
    } else {
        // store attribute
        mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;
        return true;
    }
422
423
}

424
STATIC mp_obj_t class_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
425
    mp_obj_class_t *self = self_in;
426
    mp_obj_t member[2] = {MP_OBJ_NULL};
427
    uint meth_args;
428
429
    if (value == MP_OBJ_NULL) {
        // delete item
430
        mp_obj_class_lookup(self, self->base.type, MP_QSTR___delitem__, offsetof(mp_obj_type_t, subscr), member);
431
        meth_args = 2;
432
433
    } else if (value == MP_OBJ_SENTINEL) {
        // load item
434
        mp_obj_class_lookup(self, self->base.type, MP_QSTR___getitem__, offsetof(mp_obj_type_t, subscr), member);
435
        meth_args = 2;
436
    } else {
437
        // store item
438
        mp_obj_class_lookup(self, self->base.type, MP_QSTR___setitem__, offsetof(mp_obj_type_t, subscr), member);
439
        meth_args = 3;
440
    }
441
    if (member[0] == MP_OBJ_SENTINEL) {
442
        return mp_obj_subscr(self->subobj[0], index, value);
443
    } else if (member[0] != MP_OBJ_NULL) {
444
        mp_obj_t args[3] = {self_in, index, value};
445
        // TODO probably need to call class_convert_return_attr, and use mp_call_method_n_kw
446
        mp_obj_t ret = mp_call_function_n_kw(member[0], meth_args, 0, args);
447
448
449
450
451
        if (value == MP_OBJ_SENTINEL) {
            return ret;
        } else {
            return mp_const_none;
        }
452
    } else {
453
        return MP_OBJ_NOT_SUPPORTED;
454
455
456
    }
}

457
458
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;
459
460
461
462
    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;
463
    }
464
    if (member[0] == MP_OBJ_SENTINEL) {
465
466
        return mp_call_function_n_kw(self->subobj[0], n_args, n_kw, args);
    }
467
    mp_obj_t meth = mp_obj_new_bound_meth(member[0], self);
468
469
470
    return mp_call_function_n_kw(meth, n_args, n_kw, args);
}

471
472
473
/******************************************************************************/
// type object
//  - the struct is mp_obj_type_t and is defined in obj.h so const types can be made
474
//  - there is a constant mp_obj_type_t (called mp_type_type) for the 'type' object
475
//  - creating a new class (a new type) creates a new mp_obj_type_t
476

477
STATIC void type_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
478
    mp_obj_type_t *self = self_in;
479
    print(env, "<class '%s'>", qstr_str(self->name));
480
481
}

482
STATIC mp_obj_t type_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
483
484
    // TODO check n_kw == 0

485
486
487
488
489
    switch (n_args) {
        case 1:
            return mp_obj_get_type(args[0]);

        case 3:
490
            // args[0] = name
491
            // args[1] = bases tuple
492
            // args[2] = locals dict
493
            return mp_obj_new_type(mp_obj_str_get_qstr(args[0]), args[1], args[2]);
494
495

        default:
496
            nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "type takes 1 or 3 arguments"));
497
498
499
    }
}

500
STATIC mp_obj_t type_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
501
502
    // instantiate an instance of a class

503
    mp_obj_type_t *self = self_in;
504
505

    if (self->make_new == NULL) {
506
        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "cannot create '%s' instances", qstr_str(self->name)));
507
    }
508
509

    // make new instance
510
    mp_obj_t o = self->make_new(self, n_args, n_kw, args);
511
512
513
514
515

    // return new instance
    return o;
}

516
// for fail, do nothing; for attr, dest[0] = value; for method, dest[0] = method, dest[1] = self
517
STATIC void type_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
518
    assert(MP_OBJ_IS_TYPE(self_in, &mp_type_type));
519
    mp_obj_type_t *self = self_in;
520
#if MICROPY_CPYTHON_COMPAT
521
522
523
524
    if (attr == MP_QSTR___name__) {
        dest[0] = MP_OBJ_NEW_QSTR(self->name);
        return;
    }
525
#endif
526
527
528
    mp_obj_t member[2] = {MP_OBJ_NULL};
    mp_obj_class_lookup(NULL, self, attr, 0, member);
    if (member[0] != MP_OBJ_NULL) {
529
530
        // check if the methods are functions, static or class methods
        // see http://docs.python.org/3.3/howto/descriptor.html
531
        if (MP_OBJ_IS_TYPE(member[0], &mp_type_staticmethod)) {
532
            // return just the function
533
534
            dest[0] = ((mp_obj_static_class_method_t*)member[0])->fun;
        } else if (MP_OBJ_IS_TYPE(member[0], &mp_type_classmethod)) {
535
            // return a bound method, with self being this class
536
            dest[0] = ((mp_obj_static_class_method_t*)member[0])->fun;
537
538
539
540
            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
541
            dest[0] = member[0];
542
543
        }
    }
544
545
}

546
STATIC bool type_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) {
547
    assert(MP_OBJ_IS_TYPE(self_in, &mp_type_type));
548
549
    mp_obj_type_t *self = self_in;

550
551
    // TODO CPython allows STORE_ATTR to a class, but is this the correct implementation?

552
    if (self->locals_dict != NULL) {
553
        assert(MP_OBJ_IS_TYPE(self->locals_dict, &mp_type_dict)); // Micro Python restriction, for now
554
        mp_map_t *locals_map = mp_obj_dict_get_map(self->locals_dict);
555
556
557
558
559
560
561
562
563
564
565
566
567
        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;
            }
568
        }
569
    }
570
571

    return false;
572
573
}

574
575
576
577
578
579
580
581
582
583
STATIC mp_obj_t type_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
    switch (op) {
        case MP_BINARY_OP_EQUAL:
            // Types can be equal only if it's the same type structure,
            // we don't even need to check for 2nd arg type.
            return MP_BOOL(lhs_in == rhs_in);
    }
    return NULL;
}

584
585
const mp_obj_type_t mp_type_type = {
    { &mp_type_type },
586
    .name = MP_QSTR_type,
587
    .print = type_print,
588
    .make_new = type_make_new,
589
    .call = type_call,
590
591
    .load_attr = type_load_attr,
    .store_attr = type_store_attr,
592
    .binary_op = type_binary_op,
593
};
594

595
mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) {
596
    assert(MP_OBJ_IS_TYPE(bases_tuple, &mp_type_tuple)); // Micro Python restriction, for now
597
    assert(MP_OBJ_IS_TYPE(locals_dict, &mp_type_dict)); // Micro Python restriction, for now
598
599
600
601
602
603
604
605
606
607
608
609
610
611

    // 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)));
        }
    }

612
    mp_obj_type_t *o = m_new0(mp_obj_type_t, 1);
613
    o->base.type = &mp_type_type;
614
    o->name = name;
615
616
    o->print = class_print;
    o->make_new = class_make_new;
617
    o->unary_op = class_unary_op;
618
    o->binary_op = class_binary_op;
619
620
    o->load_attr = class_load_attr;
    o->store_attr = class_store_attr;
621
    o->subscr = class_subscr;
622
    o->call = class_call;
623
624
    o->bases_tuple = bases_tuple;
    o->locals_dict = locals_dict;
625
626
627
628
629
630
631

    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"));
    }

632
633
    return o;
}
634
635

/******************************************************************************/
Damien George's avatar
Damien George committed
636
637
638
639
640
641
642
643
// super object

typedef struct _mp_obj_super_t {
    mp_obj_base_t base;
    mp_obj_t type;
    mp_obj_t obj;
} mp_obj_super_t;

644
STATIC void super_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
Damien George's avatar
Damien George committed
645
646
647
648
649
650
651
652
    mp_obj_super_t *self = self_in;
    print(env, "<super: ");
    mp_obj_print_helper(print, env, self->type, PRINT_STR);
    print(env, ", ");
    mp_obj_print_helper(print, env, self->obj, PRINT_STR);
    print(env, ">");
}

653
STATIC mp_obj_t super_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
Damien George's avatar
Damien George committed
654
655
656
    if (n_args != 2 || n_kw != 0) {
        // 0 arguments are turned into 2 in the compiler
        // 1 argument is not yet implemented
657
        nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "super() requires 2 arguments"));
Damien George's avatar
Damien George committed
658
659
660
661
662
    }
    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
663
STATIC void super_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
664
    assert(MP_OBJ_IS_TYPE(self_in, &mp_type_super));
Damien George's avatar
Damien George committed
665
666
    mp_obj_super_t *self = self_in;

667
    assert(MP_OBJ_IS_TYPE(self->type, &mp_type_type));
Damien George's avatar
Damien George committed
668
669
670
671
672
673
674
675
676
677
678
679

    mp_obj_type_t *type = self->type;

    // for a const struct, this entry might be NULL
    if (type->bases_tuple == MP_OBJ_NULL) {
        return;
    }

    uint len;
    mp_obj_t *items;
    mp_obj_tuple_get(type->bases_tuple, &len, &items);
    for (uint i = 0; i < len; i++) {
680
        assert(MP_OBJ_IS_TYPE(items[i], &mp_type_type));
681
682
683
684
        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);
685
            return;
Damien George's avatar
Damien George committed
686
687
688
689
        }
    }
}

690
const mp_obj_type_t mp_type_super = {
691
    { &mp_type_type },
692
    .name = MP_QSTR_super,
Damien George's avatar
Damien George committed
693
694
695
696
697
698
699
    .print = super_print,
    .make_new = super_make_new,
    .load_attr = super_load_attr,
};

mp_obj_t mp_obj_new_super(mp_obj_t type, mp_obj_t obj) {
    mp_obj_super_t *o = m_new_obj(mp_obj_super_t);
700
    *o = (mp_obj_super_t){{&mp_type_super}, type, obj};
Damien George's avatar
Damien George committed
701
702
703
704
    return o;
}

/******************************************************************************/
705
// subclassing and built-ins specific to types
706

707
708
// object and classinfo should be type objects
// (but the function will fail gracefully if they are not)
709
bool mp_obj_is_subclass_fast(mp_const_obj_t object, mp_const_obj_t classinfo) {
710
711
    for (;;) {
        if (object == classinfo) {
712
            return true;
713
714
715
716
        }

        // not equivalent classes, keep searching base classes

717
718
719
720
721
        // object should always be a type object, but just return false if it's not
        if (!MP_OBJ_IS_TYPE(object, &mp_type_type)) {
            return false;
        }

722
        const mp_obj_type_t *self = object;
723
724
725

        // for a const struct, this entry might be NULL
        if (self->bases_tuple == MP_OBJ_NULL) {
726
            return false;
727
728
        }

729
        // get the base objects (they should be type objects)
730
731
732
733
        uint len;
        mp_obj_t *items;
        mp_obj_tuple_get(self->bases_tuple, &len, &items);
        if (len == 0) {
734
            return false;
735
        }
736
737

        // iterate through the base objects
738
        for (uint i = 0; i < len - 1; i++) {
739
            if (mp_obj_is_subclass_fast(items[i], classinfo)) {
740
                return true;
741
742
743
744
745
746
747
748
            }
        }

        // search last base (simple tail recursion elimination)
        object = items[len - 1];
    }
}

749
750
751
752
753
754
STATIC mp_obj_t mp_obj_is_subclass(mp_obj_t object, mp_obj_t classinfo) {
    uint len;
    mp_obj_t *items;
    if (MP_OBJ_IS_TYPE(classinfo, &mp_type_type)) {
        len = 1;
        items = &classinfo;
755
    } else if (MP_OBJ_IS_TYPE(classinfo, &mp_type_tuple)) {
756
757
        mp_obj_tuple_get(classinfo, &len, &items);
    } else {
758
        nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "issubclass() arg 2 must be a class or a tuple of classes"));
759
760
    }

761
    for (uint i = 0; i < len; i++) {
762
763
        // We explicitly check for 'object' here since no-one explicitly derives from it
        if (items[i] == &mp_type_object || mp_obj_is_subclass_fast(object, items[i])) {
764
765
            return mp_const_true;
        }
766
    }
767
    return mp_const_false;
768
769
}

770
STATIC mp_obj_t mp_builtin_issubclass(mp_obj_t object, mp_obj_t classinfo) {
771
    if (!MP_OBJ_IS_TYPE(object, &mp_type_type)) {
772
        nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "issubclass() arg 1 must be a class"));
773
774
    }
    return mp_obj_is_subclass(object, classinfo);
775
776
}

777
778
MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_issubclass_obj, mp_builtin_issubclass);

779
STATIC mp_obj_t mp_builtin_isinstance(mp_obj_t object, mp_obj_t classinfo) {
780
    return mp_obj_is_subclass(mp_obj_get_type(object), classinfo);
781
782
783
}

MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_isinstance_obj, mp_builtin_isinstance);
784
785
786
787

/******************************************************************************/
// staticmethod and classmethod types (probably should go in a different file)

788
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) {
789
790
791
    assert(self_in == &mp_type_staticmethod || self_in == &mp_type_classmethod);

    if (n_args != 1 || n_kw != 0) {
792
        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function takes 1 positional argument but %d were given", n_args));
793
794
795
796
797
798
799
    }

    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;
}

800
const mp_obj_type_t mp_type_staticmethod = {
801
    { &mp_type_type },
802
    .name = MP_QSTR_staticmethod,
803
    .make_new = static_class_method_make_new
804
805
806
};

const mp_obj_type_t mp_type_classmethod = {
807
    { &mp_type_type },
808
    .name = MP_QSTR_classmethod,
809
    .make_new = static_class_method_make_new
810
};