objtype.c 29 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
#include "runtime.h"
13
#include "objtype.h"
14

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

22
/******************************************************************************/
23
// instance object
24

25
26
27
28
#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) {
29
    mp_obj_instance_t *o = m_new_obj_var(mp_obj_instance_t, mp_obj_t, subobjs);
30
31
    o->base.type = class;
    mp_map_init(&o->members, 0);
32
    mp_seq_clear(o->subobj, 0, subobjs, sizeof(*o->subobj));
33
34
35
    return o;
}

36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
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/
//
60
// will return MP_OBJ_NULL if not found
61
62
63
64
65
66
// 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.
67
STATIC void mp_obj_class_lookup(mp_obj_instance_t *o, const mp_obj_type_t *type, qstr attr, machine_uint_t meth_offset, mp_obj_t *dest) {
68
69
    assert(dest[0] == NULL);
    assert(dest[1] == NULL);
70
    for (;;) {
71
72
73
74
75
76
77
        // 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));
78
79
                dest[0] = MP_OBJ_SENTINEL;
                return;
80
81
82
            }
        }

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

97
98
        // Try this for completeness, by all native methods should be statically defined
        // in locals_dict, and would be handled by above.
99
100
101
        if (o != MP_OBJ_NULL && is_native_type(type)) {
            mp_load_method_maybe(o->subobj[0], attr, dest);
            if (dest[0] != MP_OBJ_NULL) {
102
                return;
103
104
105
            }
        }

106
107
108
        // attribute not found, keep searching base classes

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

        uint len;
        mp_obj_t *items;
115
        mp_obj_tuple_get(type->bases_tuple, &len, &items);
116
        if (len == 0) {
117
            return;
118
119
        }
        for (uint i = 0; i < len - 1; i++) {
120
            assert(MP_OBJ_IS_TYPE(items[i], &mp_type_type));
121
122
123
            mp_obj_class_lookup(o, (mp_obj_type_t*)items[i], attr, meth_offset, dest);
            if (dest[0] != MP_OBJ_NULL) {
                return;
124
125
126
127
            }
        }

        // search last base (simple tail recursion elimination)
128
        assert(MP_OBJ_IS_TYPE(items[len - 1], &mp_type_type));
129
        type = (mp_obj_type_t*)items[len - 1];
130
131
132
    }
}

133
STATIC void class_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
134
    mp_obj_instance_t *self = self_in;
135
    qstr meth = (kind == PRINT_STR) ? MP_QSTR___str__ : MP_QSTR___repr__;
136
137
138
    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) {
139
        // If there's no __str__, fall back to __repr__
140
        mp_obj_class_lookup(self, self->base.type, MP_QSTR___repr__, 0, member);
141
142
    }

143
    if (member[0] == MP_OBJ_SENTINEL) {
144
145
146
147
148
149
150
151
152
        // 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);
        }
153
        return;
154
155
    }

156
157
    if (member[0] != MP_OBJ_NULL) {
        mp_obj_t r = mp_call_function_1(member[0], self_in);
158
159
160
161
162
        mp_obj_print_helper(print, env, r, PRINT_STR);
        return;
    }

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

166
STATIC mp_obj_t class_make_new(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
167
    assert(MP_OBJ_IS_TYPE(self_in, &mp_type_type));
168
    mp_obj_type_t *self = self_in;
169

170
171
172
    const mp_obj_type_t *native_base;
    uint num_native_bases = class_count_native_bases(self, &native_base);
    assert(num_native_bases < 2);
173

174
    mp_obj_instance_t *o = mp_obj_new_class(self_in, num_native_bases);
175

176
    // look for __init__ function
177
178
    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);
179

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

    } else {
        if (n_args != 0) {
206
            nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "object() takes no parameters"));
207
208
209
210
211
212
        }
    }

    return o;
}

213
STATIC const qstr unary_op_method_name[] = {
Damien George's avatar
Damien George committed
214
215
216
217
218
219
    [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
220
221
};

222
STATIC mp_obj_t class_unary_op(int op, mp_obj_t self_in) {
223
    mp_obj_instance_t *self = self_in;
224
    qstr op_name = unary_op_method_name[op];
225
    /* Still try to lookup native slot
226
    if (op_name == 0) {
227
        return MP_OBJ_NOT_SUPPORTED;
228
    }
229
    */
230
231
232
    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) {
233
        return mp_unary_op(op, self->subobj[0]);
234
235
    } else if (member[0] != MP_OBJ_NULL) {
        return mp_call_function_1(member[0], self_in);
236
    } else {
237
        return MP_OBJ_NOT_SUPPORTED;
238
239
240
    }
}

241
STATIC const qstr binary_op_method_name[] = {
242
    /*
Damien George's avatar
Damien George committed
243
244
245
246
247
    MP_BINARY_OP_OR,
    MP_BINARY_OP_XOR,
    MP_BINARY_OP_AND,
    MP_BINARY_OP_LSHIFT,
    MP_BINARY_OP_RSHIFT,
248
    */
Damien George's avatar
Damien George committed
249
250
    [MP_BINARY_OP_ADD] = MP_QSTR___add__,
    [MP_BINARY_OP_SUBTRACT] = MP_QSTR___sub__,
251
    /*
Damien George's avatar
Damien George committed
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
    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,
277
    */
Damien George's avatar
Damien George committed
278
    [MP_BINARY_OP_EXCEPTION_MATCH] = MP_QSTR_, // not implemented, used to make sure array has full size
279
280
};

281
282
283
284
285
// 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) {
286
    assert(dest[1] == NULL);
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
    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;
    }
}

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

329
STATIC void class_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
330
    // logic: look in obj members then class locals (TODO check this against CPython)
331
    mp_obj_instance_t *self = self_in;
332

333
334
335
    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
336
        // TODO should we check for properties?
337
        dest[0] = elem->value;
338
339
        return;
    }
340

341
342
    mp_obj_class_lookup(self, self->base.type, attr, 0, dest);
    mp_obj_t member = dest[0];
343
    if (member != MP_OBJ_NULL) {
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
        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
360
361
362
363
364
            // 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);
            }
365
        }
Damien George's avatar
Damien George committed
366
367
368
369
370
371
372
373
374
375
376
377
        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);
378
379
380
381
382
            return;
        }
    }
}

383
STATIC bool class_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) {
384
    mp_obj_instance_t *self = self_in;
385
386
387
388

#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?
389
390
391
    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)) {
392
393
        // attribute already exists and is a property
        // delegate the store to the property
394
        const mp_obj_t *proxy = mp_obj_property_get(member[0]);
395
396
397
398
399
400
401
402
403
404
405
        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

406
407
    if (value == MP_OBJ_NULL) {
        // delete attribute
408
409
        mp_map_elem_t *elem = mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_REMOVE_IF_FOUND);
        return elem != NULL;
410
411
412
413
414
    } else {
        // store attribute
        mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;
        return true;
    }
415
416
}

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

450
STATIC mp_obj_t class_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
451
    mp_obj_instance_t *self = self_in;
452
453
454
455
    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;
456
    }
457
    if (member[0] == MP_OBJ_SENTINEL) {
458
459
        return mp_call_function_n_kw(self->subobj[0], n_args, n_kw, args);
    }
460
    mp_obj_t meth = mp_obj_new_bound_meth(member[0], self);
461
462
463
    return mp_call_function_n_kw(meth, n_args, n_kw, args);
}

464
465
466
/******************************************************************************/
// type object
//  - the struct is mp_obj_type_t and is defined in obj.h so const types can be made
467
//  - there is a constant mp_obj_type_t (called mp_type_type) for the 'type' object
468
//  - creating a new class (a new type) creates a new mp_obj_type_t
469

470
STATIC void type_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
471
    mp_obj_type_t *self = self_in;
472
    print(env, "<class '%s'>", qstr_str(self->name));
473
474
}

475
STATIC mp_obj_t type_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
476
477
    // TODO check n_kw == 0

478
479
480
481
482
    switch (n_args) {
        case 1:
            return mp_obj_get_type(args[0]);

        case 3:
483
            // args[0] = name
484
            // args[1] = bases tuple
485
            // args[2] = locals dict
486
            return mp_obj_new_type(mp_obj_str_get_qstr(args[0]), args[1], args[2]);
487
488

        default:
489
            nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "type takes 1 or 3 arguments"));
490
491
492
    }
}

493
STATIC mp_obj_t type_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
494
495
    // instantiate an instance of a class

496
    mp_obj_type_t *self = self_in;
497
498

    if (self->make_new == NULL) {
499
        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "cannot create '%s' instances", qstr_str(self->name)));
500
    }
501
502

    // make new instance
503
    mp_obj_t o = self->make_new(self, n_args, n_kw, args);
504
505
506
507
508

    // return new instance
    return o;
}

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

539
STATIC bool type_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) {
540
    assert(MP_OBJ_IS_TYPE(self_in, &mp_type_type));
541
542
    mp_obj_type_t *self = self_in;

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

545
    if (self->locals_dict != NULL) {
546
        assert(MP_OBJ_IS_TYPE(self->locals_dict, &mp_type_dict)); // Micro Python restriction, for now
547
        mp_map_t *locals_map = mp_obj_dict_get_map(self->locals_dict);
548
549
550
551
552
553
554
555
556
557
558
559
560
        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;
            }
561
        }
562
    }
563
564

    return false;
565
566
}

567
568
569
570
571
572
573
574
575
576
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;
}

577
578
const mp_obj_type_t mp_type_type = {
    { &mp_type_type },
579
    .name = MP_QSTR_type,
580
    .print = type_print,
581
    .make_new = type_make_new,
582
    .call = type_call,
583
584
    .load_attr = type_load_attr,
    .store_attr = type_store_attr,
585
    .binary_op = type_binary_op,
586
};
587

588
mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) {
589
    assert(MP_OBJ_IS_TYPE(bases_tuple, &mp_type_tuple)); // Micro Python restriction, for now
590
    assert(MP_OBJ_IS_TYPE(locals_dict, &mp_type_dict)); // Micro Python restriction, for now
591
592
593
594
595
596
597
598
599
600
601
602
603
604

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

605
    mp_obj_type_t *o = m_new0(mp_obj_type_t, 1);
606
    o->base.type = &mp_type_type;
607
    o->name = name;
608
609
    o->print = class_print;
    o->make_new = class_make_new;
610
    o->unary_op = class_unary_op;
611
    o->binary_op = class_binary_op;
612
613
    o->load_attr = class_load_attr;
    o->store_attr = class_store_attr;
614
    o->subscr = class_subscr;
615
    o->call = class_call;
616
617
    o->bases_tuple = bases_tuple;
    o->locals_dict = locals_dict;
618
619
620
621
622
623
624

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

625
626
    return o;
}
627
628

/******************************************************************************/
Damien George's avatar
Damien George committed
629
630
631
632
633
634
635
636
// 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;

637
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
638
639
640
641
642
643
644
645
    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, ">");
}

646
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
647
648
649
    if (n_args != 2 || n_kw != 0) {
        // 0 arguments are turned into 2 in the compiler
        // 1 argument is not yet implemented
650
        nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "super() requires 2 arguments"));
Damien George's avatar
Damien George committed
651
652
653
654
655
    }
    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
656
STATIC void super_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
657
    assert(MP_OBJ_IS_TYPE(self_in, &mp_type_super));
Damien George's avatar
Damien George committed
658
659
    mp_obj_super_t *self = self_in;

660
    assert(MP_OBJ_IS_TYPE(self->type, &mp_type_type));
Damien George's avatar
Damien George committed
661
662
663
664
665
666
667
668
669
670
671
672

    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++) {
673
        assert(MP_OBJ_IS_TYPE(items[i], &mp_type_type));
674
675
676
677
        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);
678
            return;
Damien George's avatar
Damien George committed
679
680
681
682
        }
    }
}

683
const mp_obj_type_t mp_type_super = {
684
    { &mp_type_type },
685
    .name = MP_QSTR_super,
Damien George's avatar
Damien George committed
686
687
688
689
690
691
692
    .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);
693
    *o = (mp_obj_super_t){{&mp_type_super}, type, obj};
Damien George's avatar
Damien George committed
694
695
696
697
    return o;
}

/******************************************************************************/
698
// subclassing and built-ins specific to types
699

700
701
// object and classinfo should be type objects
// (but the function will fail gracefully if they are not)
702
bool mp_obj_is_subclass_fast(mp_const_obj_t object, mp_const_obj_t classinfo) {
703
704
    for (;;) {
        if (object == classinfo) {
705
            return true;
706
707
708
709
        }

        // not equivalent classes, keep searching base classes

710
711
712
713
714
        // 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;
        }

715
        const mp_obj_type_t *self = object;
716
717
718

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

722
        // get the base objects (they should be type objects)
723
724
725
726
        uint len;
        mp_obj_t *items;
        mp_obj_tuple_get(self->bases_tuple, &len, &items);
        if (len == 0) {
727
            return false;
728
        }
729
730

        // iterate through the base objects
731
        for (uint i = 0; i < len - 1; i++) {
732
            if (mp_obj_is_subclass_fast(items[i], classinfo)) {
733
                return true;
734
735
736
737
738
739
740
741
            }
        }

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

742
743
744
745
746
747
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;
748
    } else if (MP_OBJ_IS_TYPE(classinfo, &mp_type_tuple)) {
749
750
        mp_obj_tuple_get(classinfo, &len, &items);
    } else {
751
        nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "issubclass() arg 2 must be a class or a tuple of classes"));
752
753
    }

754
    for (uint i = 0; i < len; i++) {
755
756
        // 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])) {
757
758
            return mp_const_true;
        }
759
    }
760
    return mp_const_false;
761
762
}

763
STATIC mp_obj_t mp_builtin_issubclass(mp_obj_t object, mp_obj_t classinfo) {
764
    if (!MP_OBJ_IS_TYPE(object, &mp_type_type)) {
765
        nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "issubclass() arg 1 must be a class"));
766
767
    }
    return mp_obj_is_subclass(object, classinfo);
768
769
}

770
771
MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_issubclass_obj, mp_builtin_issubclass);

772
STATIC mp_obj_t mp_builtin_isinstance(mp_obj_t object, mp_obj_t classinfo) {
773
    return mp_obj_is_subclass(mp_obj_get_type(object), classinfo);
774
775
776
}

MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_isinstance_obj, mp_builtin_isinstance);
777
778
779
780

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

781
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) {
782
783
784
    assert(self_in == &mp_type_staticmethod || self_in == &mp_type_classmethod);

    if (n_args != 1 || n_kw != 0) {
785
        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function takes 1 positional argument but %d were given", n_args));
786
787
788
789
790
791
792
    }

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

793
const mp_obj_type_t mp_type_staticmethod = {
794
    { &mp_type_type },
795
    .name = MP_QSTR_staticmethod,
796
    .make_new = static_class_method_make_new
797
798
799
};

const mp_obj_type_t mp_type_classmethod = {
800
    { &mp_type_type },
801
    .name = MP_QSTR_classmethod,
802
    .make_new = static_class_method_make_new
803
};