objtype.c 32.2 KB
Newer Older
1
2
3
4
5
6
/*
 * This file is part of the Micro Python project, http://micropython.org/
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2013, 2014 Damien P. George
7
 * Copyright (c) 2014 Paul Sokolovsky
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

28
29
#include <stdio.h>
#include <stddef.h>
30
31
#include <string.h>
#include <assert.h>
32

33
#include "mpconfig.h"
34
35
#include "nlr.h"
#include "misc.h"
36
#include "qstr.h"
37
#include "obj.h"
38
#include "runtime0.h"
39
#include "runtime.h"
40
#include "objtype.h"
41

42
43
44
45
46
47
48
#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

49
/******************************************************************************/
50
// instance object
51

52
#define is_instance_type(type) ((type)->make_new == instance_make_new)
53
#define is_native_type(type) ((type)->make_new != instance_make_new)
54
mp_obj_t instance_make_new(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args);
55
STATIC void instance_convert_return_attr(mp_obj_t self, const mp_obj_type_t *type, mp_obj_t member, mp_obj_t *dest);
56

57
STATIC mp_obj_t mp_obj_new_instance(mp_obj_t class, uint subobjs) {
58
    mp_obj_instance_t *o = m_new_obj_var(mp_obj_instance_t, mp_obj_t, subobjs);
59
60
    o->base.type = class;
    mp_map_init(&o->members, 0);
61
    mp_seq_clear(o->subobj, 0, subobjs, sizeof(*o->subobj));
62
63
64
    return o;
}

65
STATIC int instance_count_native_bases(const mp_obj_type_t *type, const mp_obj_type_t **last_native_base) {
66
67
68
69
70
71
72
    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));
73
74
75
76
77
78
        const mp_obj_type_t *bt = (const mp_obj_type_t *)items[i];
        if (bt == &mp_type_object) {
            // Not a "real" type
            continue;
        }
        if (is_native_type(bt)) {
79
80
81
            *last_native_base = items[i];
            count++;
        } else {
82
            count += instance_count_native_bases(items[i], last_native_base);
83
84
85
86
87
88
89
90
91
92
93
        }
    }

    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/
//
94
// will return MP_OBJ_NULL if not found
95
96
97
98
99
// 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
100
// instance->subobj[0]. This case is handled via instance_count_native_bases() though.
101
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) {
102
103
    assert(dest[0] == NULL);
    assert(dest[1] == NULL);
104
    for (;;) {
105
106
107
108
109
110
111
        // 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));
112
113
                dest[0] = MP_OBJ_SENTINEL;
                return;
114
115
116
            }
        }

117
        if (type->locals_dict != NULL) {
118
            // search locals_dict (the set of methods/attributes)
119
            assert(MP_OBJ_IS_TYPE(type->locals_dict, &mp_type_dict)); // Micro Python restriction, for now
120
            mp_map_t *locals_map = mp_obj_dict_get_map(type->locals_dict);
121
122
            mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP);
            if (elem != NULL) {
123
124
                dest[0] = elem->value;
                if (o != MP_OBJ_NULL && is_native_type(type)) {
125
126
127
                    instance_convert_return_attr(o->subobj[0], type, elem->value, dest);
                } else {
                    instance_convert_return_attr(o, type, elem->value, dest);
128
129
                }
                return;
130
            }
131
132
        }

133
        // Try this for completeness, but all native methods should be statically defined
134
        // in locals_dict, and would be handled by above.
135
136
137
        if (o != MP_OBJ_NULL && is_native_type(type)) {
            mp_load_method_maybe(o->subobj[0], attr, dest);
            if (dest[0] != MP_OBJ_NULL) {
138
                return;
139
140
141
            }
        }

142
143
144
        // attribute not found, keep searching base classes

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

        uint len;
        mp_obj_t *items;
151
        mp_obj_tuple_get(type->bases_tuple, &len, &items);
152
        if (len == 0) {
153
            return;
154
155
        }
        for (uint i = 0; i < len - 1; i++) {
156
            assert(MP_OBJ_IS_TYPE(items[i], &mp_type_type));
157
158
159
160
161
162
            mp_obj_type_t *bt = (mp_obj_type_t*)items[i];
            if (bt == &mp_type_object) {
                // Not a "real" type
                continue;
            }
            mp_obj_class_lookup(o, bt, attr, meth_offset, dest);
163
164
            if (dest[0] != MP_OBJ_NULL) {
                return;
165
166
167
168
            }
        }

        // search last base (simple tail recursion elimination)
169
        assert(MP_OBJ_IS_TYPE(items[len - 1], &mp_type_type));
170
        type = (mp_obj_type_t*)items[len - 1];
171
172
173
174
        if (type == &mp_type_object) {
            // Not a "real" type
            return;
        }
175
176
177
    }
}

178
STATIC void instance_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
179
    mp_obj_instance_t *self = self_in;
180
    qstr meth = (kind == PRINT_STR) ? MP_QSTR___str__ : MP_QSTR___repr__;
181
182
183
    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) {
184
        // If there's no __str__, fall back to __repr__
185
        mp_obj_class_lookup(self, self->base.type, MP_QSTR___repr__, 0, member);
186
187
    }

188
    if (member[0] == MP_OBJ_SENTINEL) {
189
190
191
192
193
194
195
196
197
        // 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);
        }
198
        return;
199
200
    }

201
202
    if (member[0] != MP_OBJ_NULL) {
        mp_obj_t r = mp_call_function_1(member[0], self_in);
203
204
205
206
207
        mp_obj_print_helper(print, env, r, PRINT_STR);
        return;
    }

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

211
mp_obj_t instance_make_new(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
212
    assert(MP_OBJ_IS_TYPE(self_in, &mp_type_type));
213
    mp_obj_type_t *self = self_in;
214

215
    const mp_obj_type_t *native_base;
216
    uint num_native_bases = instance_count_native_bases(self, &native_base);
217
    assert(num_native_bases < 2);
218

219
    mp_obj_instance_t *o = mp_obj_new_instance(self_in, num_native_bases);
220

221
222
223
224
225
226
227
228
    // This executes only "__new__" part of obejection creation.
    // TODO: This won't work will for classes with native bases.
    // TODO: This is hack, should be resolved along the lines of
    // https://github.com/micropython/micropython/issues/606#issuecomment-43685883
    if (n_args == 1 && *args == MP_OBJ_SENTINEL) {
        return o;
    }

229
    // look for __new__ function
230
    mp_obj_t init_fn[2] = {MP_OBJ_NULL};
231
    mp_obj_class_lookup(NULL, self, MP_QSTR___new__, offsetof(mp_obj_type_t, make_new), init_fn);
232

233
    mp_obj_t new_ret = o;
234
    if (init_fn[0] == MP_OBJ_SENTINEL) {
235
236
237
        // 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);
238
    } else if (init_fn[0] != MP_OBJ_NULL) {
239
        // now call Python class __new__ function with all args
240
        if (n_args == 0 && n_kw == 0) {
241
            new_ret = mp_call_function_n_kw(init_fn[0], 1, 0, (mp_obj_t*)(void*)&self_in);
242
        } else {
243
            mp_obj_t *args2 = m_new(mp_obj_t, 1 + n_args + 2 * n_kw);
244
            args2[0] = self_in;
245
            memcpy(args2 + 1, args, (n_args + 2 * n_kw) * sizeof(mp_obj_t));
246
            new_ret = mp_call_function_n_kw(init_fn[0], n_args + 1, n_kw, args2);
247
            m_del(mp_obj_t, args2, 1 + n_args + 2 * n_kw);
248
        }
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274

    }

    // https://docs.python.org/3.4/reference/datamodel.html#object.__new__
    // "If __new__() does not return an instance of cls, then the new instance’s __init__() method will not be invoked."
    if (mp_obj_get_type(new_ret) != self_in) {
        return new_ret;
    }

    o = new_ret;

    // now call Python class __init__ function with all args
    init_fn[0] = init_fn[1] = NULL;
    mp_obj_class_lookup(o, self, MP_QSTR___init__, 0, init_fn);
    if (init_fn[0] != MP_OBJ_NULL) {
        mp_obj_t init_ret;
        if (n_args == 0 && n_kw == 0) {
            init_ret = mp_call_method_n_kw(0, 0, init_fn);
        } else {
            mp_obj_t *args2 = m_new(mp_obj_t, 2 + n_args + 2 * n_kw);
            args2[0] = init_fn[0];
            args2[1] = init_fn[1];
            memcpy(args2 + 2, args, (n_args + 2 * n_kw) * sizeof(mp_obj_t));
            init_ret = mp_call_method_n_kw(n_args, n_kw, args2);
            m_del(mp_obj_t, args2, 2 + n_args + 2 * n_kw);
        }
275
        if (init_ret != mp_const_none) {
276
            nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "__init__() should return None, not '%s'", mp_obj_get_type_str(init_ret)));
277
278
279
280
281
282
283
        }

    }

    return o;
}

284
STATIC const qstr unary_op_method_name[] = {
Damien George's avatar
Damien George committed
285
286
287
288
289
290
    [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
291
292
};

293
STATIC mp_obj_t instance_unary_op(int op, mp_obj_t self_in) {
294
    mp_obj_instance_t *self = self_in;
295
    qstr op_name = unary_op_method_name[op];
296
    /* Still try to lookup native slot
297
    if (op_name == 0) {
298
        return MP_OBJ_NULL;
299
    }
300
    */
301
302
303
    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) {
304
        return mp_unary_op(op, self->subobj[0]);
305
306
    } else if (member[0] != MP_OBJ_NULL) {
        return mp_call_function_1(member[0], self_in);
307
    } else {
308
        return MP_OBJ_NULL; // op not supported
309
310
311
    }
}

312
STATIC const qstr binary_op_method_name[] = {
313
    /*
Damien George's avatar
Damien George committed
314
315
316
317
318
    MP_BINARY_OP_OR,
    MP_BINARY_OP_XOR,
    MP_BINARY_OP_AND,
    MP_BINARY_OP_LSHIFT,
    MP_BINARY_OP_RSHIFT,
319
    */
Damien George's avatar
Damien George committed
320
321
    [MP_BINARY_OP_ADD] = MP_QSTR___add__,
    [MP_BINARY_OP_SUBTRACT] = MP_QSTR___sub__,
322
    /*
Damien George's avatar
Damien George committed
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
    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,
348
    */
Damien George's avatar
Damien George committed
349
    [MP_BINARY_OP_EXCEPTION_MATCH] = MP_QSTR_, // not implemented, used to make sure array has full size
350
351
};

352
353
354
355
// 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
356
STATIC void instance_convert_return_attr(mp_obj_t self, const mp_obj_type_t *type, mp_obj_t member, mp_obj_t *dest) {
357
    assert(dest[1] == NULL);
358
359
360
361
362
363
    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;
364
        dest[1] = (mp_obj_t)type;
365
366
367
    } else if (MP_OBJ_IS_TYPE(member, &mp_type_type)) {
        // Don't try to bind types
        dest[0] = member;
368
369
370
371
372
373
374
375
376
377
    } 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;
    }
}

378
STATIC mp_obj_t instance_binary_op(int op, mp_obj_t lhs_in, mp_obj_t rhs_in) {
379
380
    // Note: For ducktyping, CPython does not look in the instance members or use
    // __getattr__ or __getattribute__.  It only looks in the class dictionary.
381
    mp_obj_instance_t *lhs = lhs_in;
382
    qstr op_name = binary_op_method_name[op];
383
    /* Still try to lookup native slot
384
    if (op_name == 0) {
385
        return MP_OBJ_NULL;
386
    }
387
    */
388
389
390
    mp_obj_t dest[3] = {MP_OBJ_NULL};
    mp_obj_class_lookup(lhs, lhs->base.type, op_name, offsetof(mp_obj_type_t, binary_op), dest);
    if (dest[0] == MP_OBJ_SENTINEL) {
391
        return mp_binary_op(op, lhs->subobj[0], rhs_in);
392
    } else if (dest[0] != MP_OBJ_NULL) {
393
394
        dest[2] = rhs_in;
        return mp_call_method_n_kw(1, 0, dest);
395
    } else {
396
        return MP_OBJ_NULL; // op not supported
397
398
399
    }
}

400
STATIC void instance_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
401
    // logic: look in obj members then class locals (TODO check this against CPython)
402
    assert(is_instance_type(mp_obj_get_type(self_in)));
403
    mp_obj_instance_t *self = self_in;
404

405
406
407
    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
408
        // TODO should we check for properties?
409
        dest[0] = elem->value;
410
411
        return;
    }
412

413
414
    mp_obj_class_lookup(self, self->base.type, attr, 0, dest);
    mp_obj_t member = dest[0];
415
    if (member != MP_OBJ_NULL) {
416
#if MICROPY_ENABLE_PROPERTY
417
        if (MP_OBJ_IS_TYPE(member, &mp_type_property)) {
418
419
            // object member is a property
            // delegate the store to the property
420
            // TODO should this be part of instance_convert_return_attr?
421
422
423
424
425
            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);
426
                // TODO should we convert the returned value using instance_convert_return_attr?
427
428
            }
        }
429
#endif
Damien George's avatar
Damien George committed
430
431
432
433
434
435
436
437
438
439
440
441
        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);
442
443
444
445
446
            return;
        }
    }
}

447
STATIC bool instance_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) {
448
    mp_obj_instance_t *self = self_in;
449
450
451
452

#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?
453
454
455
    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)) {
456
457
        // attribute already exists and is a property
        // delegate the store to the property
458
        const mp_obj_t *proxy = mp_obj_property_get(member[0]);
459
460
461
462
463
464
465
466
467
468
469
        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

470
471
    if (value == MP_OBJ_NULL) {
        // delete attribute
472
473
        mp_map_elem_t *elem = mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_REMOVE_IF_FOUND);
        return elem != NULL;
474
475
476
477
478
    } else {
        // store attribute
        mp_map_lookup(&self->members, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;
        return true;
    }
479
480
}

481
STATIC mp_obj_t instance_subscr(mp_obj_t self_in, mp_obj_t index, mp_obj_t value) {
482
    mp_obj_instance_t *self = self_in;
483
    mp_obj_t member[2] = {MP_OBJ_NULL};
484
    uint meth_args;
485
486
    if (value == MP_OBJ_NULL) {
        // delete item
487
        mp_obj_class_lookup(self, self->base.type, MP_QSTR___delitem__, offsetof(mp_obj_type_t, subscr), member);
488
        meth_args = 2;
489
490
    } else if (value == MP_OBJ_SENTINEL) {
        // load item
491
        mp_obj_class_lookup(self, self->base.type, MP_QSTR___getitem__, offsetof(mp_obj_type_t, subscr), member);
492
        meth_args = 2;
493
    } else {
494
        // store item
495
        mp_obj_class_lookup(self, self->base.type, MP_QSTR___setitem__, offsetof(mp_obj_type_t, subscr), member);
496
        meth_args = 3;
497
    }
498
    if (member[0] == MP_OBJ_SENTINEL) {
499
        return mp_obj_subscr(self->subobj[0], index, value);
500
    } else if (member[0] != MP_OBJ_NULL) {
501
        mp_obj_t args[3] = {self_in, index, value};
502
        // TODO probably need to call instance_convert_return_attr, and use mp_call_method_n_kw
503
        mp_obj_t ret = mp_call_function_n_kw(member[0], meth_args, 0, args);
504
505
506
507
508
        if (value == MP_OBJ_SENTINEL) {
            return ret;
        } else {
            return mp_const_none;
        }
509
    } else {
510
        return MP_OBJ_NULL; // op not supported
511
512
513
    }
}

514
STATIC mp_obj_t instance_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
515
    mp_obj_instance_t *self = self_in;
516
517
518
519
    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;
520
    }
521
    if (member[0] == MP_OBJ_SENTINEL) {
522
523
        return mp_call_function_n_kw(self->subobj[0], n_args, n_kw, args);
    }
524
    mp_obj_t meth = mp_obj_new_bound_meth(member[0], self);
525
526
527
    return mp_call_function_n_kw(meth, n_args, n_kw, args);
}

528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
STATIC mp_obj_t instance_getiter(mp_obj_t self_in) {
    mp_obj_instance_t *self = self_in;
    mp_obj_t member[2] = {MP_OBJ_NULL};
    mp_obj_class_lookup(self, self->base.type, MP_QSTR___iter__, offsetof(mp_obj_type_t, getiter), member);
    if (member[0] == MP_OBJ_NULL) {
        // This kinda duplicates code in mp_getiter()
        mp_obj_class_lookup(self, self->base.type, MP_QSTR___getitem__, 0, member);
        if (member[0] != MP_OBJ_NULL) {
            // __getitem__ exists, create an iterator
            return mp_obj_new_getitem_iter(member);
        }
        return MP_OBJ_NULL;
    }
    if (member[0] == MP_OBJ_SENTINEL) {
        mp_obj_type_t *type = mp_obj_get_type(self->subobj[0]);
        return type->getiter(self->subobj[0]);
    }
    mp_obj_t meth = mp_obj_new_bound_meth(member[0], self);
    return mp_call_function_n_kw(meth, 0, 0, NULL);
}

549
550
551
/******************************************************************************/
// type object
//  - the struct is mp_obj_type_t and is defined in obj.h so const types can be made
552
//  - there is a constant mp_obj_type_t (called mp_type_type) for the 'type' object
553
//  - creating a new class (a new type) creates a new mp_obj_type_t
554

555
STATIC void type_print(void (*print)(void *env, const char *fmt, ...), void *env, mp_obj_t self_in, mp_print_kind_t kind) {
556
    mp_obj_type_t *self = self_in;
557
    print(env, "<class '%s'>", qstr_str(self->name));
558
559
}

560
STATIC mp_obj_t type_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) {
561
    mp_arg_check_num(n_args, n_kw, 1, 3, false);
562

563
564
565
566
567
    switch (n_args) {
        case 1:
            return mp_obj_get_type(args[0]);

        case 3:
568
            // args[0] = name
569
            // args[1] = bases tuple
570
            // args[2] = locals dict
571
            return mp_obj_new_type(mp_obj_str_get_qstr(args[0]), args[1], args[2]);
572
573

        default:
574
            nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "type takes 1 or 3 arguments"));
575
576
577
    }
}

578
STATIC mp_obj_t type_call(mp_obj_t self_in, uint n_args, uint n_kw, const mp_obj_t *args) {
579
580
    // instantiate an instance of a class

581
    mp_obj_type_t *self = self_in;
582
583

    if (self->make_new == NULL) {
584
        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "cannot create '%s' instances", qstr_str(self->name)));
585
    }
586
587

    // make new instance
588
    mp_obj_t o = self->make_new(self, n_args, n_kw, args);
589
590
591
592
593

    // return new instance
    return o;
}

594
// for fail, do nothing; for attr, dest[0] = value; for method, dest[0] = method, dest[1] = self
595
STATIC void type_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
596
    assert(MP_OBJ_IS_TYPE(self_in, &mp_type_type));
597
    mp_obj_type_t *self = self_in;
598
#if MICROPY_CPYTHON_COMPAT
599
600
601
602
    if (attr == MP_QSTR___name__) {
        dest[0] = MP_OBJ_NEW_QSTR(self->name);
        return;
    }
603
#endif
604
    mp_obj_class_lookup(NULL, self, attr, 0, dest);
605
606
}

607
STATIC bool type_store_attr(mp_obj_t self_in, qstr attr, mp_obj_t value) {
608
    assert(MP_OBJ_IS_TYPE(self_in, &mp_type_type));
609
610
    mp_obj_type_t *self = self_in;

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

613
    if (self->locals_dict != NULL) {
614
        assert(MP_OBJ_IS_TYPE(self->locals_dict, &mp_type_dict)); // Micro Python restriction, for now
615
        mp_map_t *locals_map = mp_obj_dict_get_map(self->locals_dict);
616
617
618
619
620
621
622
623
624
625
626
627
628
        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;
            }
629
        }
630
    }
631
632

    return false;
633
634
}

635
636
637
638
639
640
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);
641
642

        default:
643
            return MP_OBJ_NULL; // op not supported
644
645
646
    }
}

647
648
const mp_obj_type_t mp_type_type = {
    { &mp_type_type },
649
    .name = MP_QSTR_type,
650
    .print = type_print,
651
    .make_new = type_make_new,
652
    .call = type_call,
653
654
    .load_attr = type_load_attr,
    .store_attr = type_store_attr,
655
    .binary_op = type_binary_op,
656
};
657

658
mp_obj_t mp_obj_new_type(qstr name, mp_obj_t bases_tuple, mp_obj_t locals_dict) {
659
    assert(MP_OBJ_IS_TYPE(bases_tuple, &mp_type_tuple)); // Micro Python restriction, for now
660
    assert(MP_OBJ_IS_TYPE(locals_dict, &mp_type_dict)); // Micro Python restriction, for now
661
662
663
664
665
666
667
668
669
670
671
672
673
674

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

675
    mp_obj_type_t *o = m_new0(mp_obj_type_t, 1);
676
    o->base.type = &mp_type_type;
677
    o->name = name;
678
679
680
681
682
683
684
685
    o->print = instance_print;
    o->make_new = instance_make_new;
    o->unary_op = instance_unary_op;
    o->binary_op = instance_binary_op;
    o->load_attr = instance_load_attr;
    o->store_attr = instance_store_attr;
    o->subscr = instance_subscr;
    o->call = instance_call;
686
    o->getiter = instance_getiter;
687
688
    o->bases_tuple = bases_tuple;
    o->locals_dict = locals_dict;
689
690

    const mp_obj_type_t *native_base;
691
    uint num_native_bases = instance_count_native_bases(o, &native_base);
692
693
694
695
    if (num_native_bases > 1) {
        nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "multiple bases have instance lay-out conflict"));
    }

696
697
    return o;
}
698
699

/******************************************************************************/
Damien George's avatar
Damien George committed
700
701
702
703
704
705
706
707
// 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;

708
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
709
710
711
712
713
714
715
716
    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, ">");
}

717
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
718
719
720
    if (n_args != 2 || n_kw != 0) {
        // 0 arguments are turned into 2 in the compiler
        // 1 argument is not yet implemented
721
        nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "super() requires 2 arguments"));
Damien George's avatar
Damien George committed
722
723
724
725
726
    }
    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
727
STATIC void super_load_attr(mp_obj_t self_in, qstr attr, mp_obj_t *dest) {
728
    assert(MP_OBJ_IS_TYPE(self_in, &mp_type_super));
Damien George's avatar
Damien George committed
729
730
    mp_obj_super_t *self = self_in;

731
    assert(MP_OBJ_IS_TYPE(self->type, &mp_type_type));
Damien George's avatar
Damien George committed
732
733
734
735
736
737
738
739
740
741
742
743

    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++) {
744
        assert(MP_OBJ_IS_TYPE(items[i], &mp_type_type));
745
        mp_obj_class_lookup(self->obj, (mp_obj_type_t*)items[i], attr, 0, dest);
746
747
748
        if (dest[0] != MP_OBJ_NULL) {
            return;
        }
Damien George's avatar
Damien George committed
749
    }
750
    mp_obj_class_lookup(self->obj, &mp_type_object, attr, 0, dest);
Damien George's avatar
Damien George committed
751
752
}

753
const mp_obj_type_t mp_type_super = {
754
    { &mp_type_type },
755
    .name = MP_QSTR_super,
Damien George's avatar
Damien George committed
756
757
758
759
760
761
762
    .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);
763
    *o = (mp_obj_super_t){{&mp_type_super}, type, obj};
Damien George's avatar
Damien George committed
764
765
766
767
    return o;
}

/******************************************************************************/
768
// subclassing and built-ins specific to types
769

770
771
// object and classinfo should be type objects
// (but the function will fail gracefully if they are not)
772
bool mp_obj_is_subclass_fast(mp_const_obj_t object, mp_const_obj_t classinfo) {
773
774
    for (;;) {
        if (object == classinfo) {
775
            return true;
776
777
778
779
        }

        // not equivalent classes, keep searching base classes

780
781
782
783
784
        // 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;
        }

785
        const mp_obj_type_t *self = object;
786
787
788

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

792
        // get the base objects (they should be type objects)
793
794
795
796
        uint len;
        mp_obj_t *items;
        mp_obj_tuple_get(self->bases_tuple, &len, &items);
        if (len == 0) {
797
            return false;
798
        }
799
800

        // iterate through the base objects
801
        for (uint i = 0; i < len - 1; i++) {
802
            if (mp_obj_is_subclass_fast(items[i], classinfo)) {
803
                return true;
804
805
806
807
808
809
810
811
            }
        }

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

812
813
814
815
816
817
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;
818
    } else if (MP_OBJ_IS_TYPE(classinfo, &mp_type_tuple)) {
819
820
        mp_obj_tuple_get(classinfo, &len, &items);
    } else {
821
        nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "issubclass() arg 2 must be a class or a tuple of classes"));
822
823
    }

824
    for (uint i = 0; i < len; i++) {
825
826
        // 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])) {
827
828
            return mp_const_true;
        }
829
    }
830
    return mp_const_false;
831
832
}

833
STATIC mp_obj_t mp_builtin_issubclass(mp_obj_t object, mp_obj_t classinfo) {
834
    if (!MP_OBJ_IS_TYPE(object, &mp_type_type)) {
835
        nlr_raise(mp_obj_new_exception_msg(&mp_type_TypeError, "issubclass() arg 1 must be a class"));
836
837
    }
    return mp_obj_is_subclass(object, classinfo);
838
839
}

840
841
MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_issubclass_obj, mp_builtin_issubclass);

842
STATIC mp_obj_t mp_builtin_isinstance(mp_obj_t object, mp_obj_t classinfo) {
843
    return mp_obj_is_subclass(mp_obj_get_type(object), classinfo);
844
845
846
}

MP_DEFINE_CONST_FUN_OBJ_2(mp_builtin_isinstance_obj, mp_builtin_isinstance);
847

848
849
850
851
852
853
854
855
856
mp_obj_t mp_instance_cast_to_native_base(mp_const_obj_t self_in, mp_const_obj_t native_type) {
    mp_obj_type_t *self_type = mp_obj_get_type(self_in);
    if (!mp_obj_is_subclass_fast(self_type, native_type)) {
        return MP_OBJ_NULL;
    }
    mp_obj_instance_t *self = (mp_obj_instance_t*)self_in;
    return self->subobj[0];
}

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

860
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) {
861
862
863
    assert(self_in == &mp_type_staticmethod || self_in == &mp_type_classmethod);

    if (n_args != 1 || n_kw != 0) {
864
        nlr_raise(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "function takes 1 positional argument but %d were given", n_args));
865
866
867
868
869
870
871
    }

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

872
const mp_obj_type_t mp_type_staticmethod = {
873
    { &mp_type_type },
874
    .name = MP_QSTR_staticmethod,
875
    .make_new = static_class_method_make_new
876
877
878
};

const mp_obj_type_t mp_type_classmethod = {
879
    { &mp_type_type },
880
    .name = MP_QSTR_classmethod,
881
    .make_new = static_class_method_make_new
882
};