objtype.c 28.8 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
        mp_obj_print_helper(print, env, self->subobj[0], kind);
        return;
153
154
    }

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

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

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

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

173
    mp_obj_class_t *o = mp_obj_new_class(self_in, num_native_bases);
174

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

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

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

    return o;
}

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

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

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

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

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

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

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

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

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

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

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

416
STATIC mp_obj_t class_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
417
    mp_obj_class_t *self = self_in;
418
    mp_obj_t member[2] = {MP_OBJ_NULL};
419
    uint meth_args;
420
421
    if (value == MP_OBJ_NULL) {
        // delete item
422
        mp_obj_class_lookup(self, self->base.type, MP_QSTR___delitem__, offsetof(mp_obj_type_t, subscr), member);
423
        meth_args = 2;
424
425
    } else if (value == MP_OBJ_SENTINEL) {
        // load item
426
        mp_obj_class_lookup(self, self->base.type, MP_QSTR___getitem__, offsetof(mp_obj_type_t, subscr), member);
427
        meth_args = 2;
428
    } else {
429
        // store item
430
        mp_obj_class_lookup(self, self->base.type, MP_QSTR___setitem__, offsetof(mp_obj_type_t, subscr), member);
431
        meth_args = 3;
432
    }
433
    if (member[0] == MP_OBJ_SENTINEL) {
434
        return mp_obj_subscr(self->subobj[0], index, value);
435
    } else if (member[0] != MP_OBJ_NULL) {
436
        mp_obj_t args[3] = {self_in, index, value};
437
        // TODO probably need to call class_convert_return_attr, and use mp_call_method_n_kw
438
        mp_obj_t ret = mp_call_function_n_kw(member[0], meth_args, 0, args);
439
440
441
442
443
        if (value == MP_OBJ_SENTINEL) {
            return ret;
        } else {
            return mp_const_none;
        }
444
    } else {
445
        return MP_OBJ_NOT_SUPPORTED;
446
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) {
    mp_obj_class_t *self = self_in;
451
452
453
454
    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;
455
    }
456
    if (member[0] == MP_OBJ_SENTINEL) {
457
458
        return mp_call_function_n_kw(self->subobj[0], n_args, n_kw, args);
    }
459
    mp_obj_t meth = mp_obj_new_bound_meth(member[0], self);
460
461
462
    return mp_call_function_n_kw(meth, n_args, n_kw, args);
}

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

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

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

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

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

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

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

495
    mp_obj_type_t *self = self_in;
496
497

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

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

    // return new instance
    return o;
}

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

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

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

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

    return false;
564
565
}

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

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

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

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

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

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

624
625
    return o;
}
626
627

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

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

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

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

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

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

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

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

        // not equivalent classes, keep searching base classes

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

714
        const mp_obj_type_t *self = object;
715
716
717

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

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

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

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

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

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

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

769
770
MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_issubclass_obj, mp_builtin_issubclass);

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

MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_isinstance_obj, mp_builtin_isinstance);
776
777
778
779

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

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

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

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

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

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