runtime.c 39.6 KB
Newer Older
Damien's avatar
Damien committed
1
2
3
4
#include <stdio.h>
#include <string.h>
#include <assert.h>

5
#include "nlr.h"
Damien's avatar
Damien committed
6
#include "misc.h"
7
#include "mpconfig.h"
8
#include "qstr.h"
9
#include "obj.h"
10
#include "objtuple.h"
11
#include "objmodule.h"
12
#include "parsenum.h"
13
#include "runtime0.h"
Damien's avatar
Damien committed
14
#include "runtime.h"
15
#include "emitglue.h"
16
#include "builtin.h"
17
#include "builtintables.h"
18
#include "bc.h"
19
#include "smallint.h"
20
#include "objgenerator.h"
21

22
#if 0 // print debugging info
23
#define DEBUG_PRINT (1)
24
#define DEBUG_printf DEBUG_printf
25
#define DEBUG_OP_printf(...) DEBUG_printf(__VA_ARGS__)
26
#else // don't print debugging info
27
28
#define DEBUG_printf(...) (void)0
#define DEBUG_OP_printf(...) (void)0
29
#endif
Damien's avatar
Damien committed
30

31
// locals and globals need to be pointers because they can be the same in outer module scope
32
33
34
STATIC mp_map_t *map_locals;
STATIC mp_map_t *map_globals;
STATIC mp_map_t map_builtins;
35

36
37
38
39
40
41
42
43
STATIC mp_map_t map_main;

const mp_obj_module_t mp_module___main__ = {
    .base = { &mp_type_module },
    .name = MP_QSTR___main__,
    .globals = (mp_map_t*)&map_main,
};

44
// a good optimising compiler will inline this if necessary
45
STATIC void mp_map_add_qstr(mp_map_t *map, qstr qstr, mp_obj_t value) {
46
47
48
    mp_map_lookup(map, MP_OBJ_NEW_QSTR(qstr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;
}

Damien George's avatar
Damien George committed
49
void mp_init(void) {
50
51
    mp_emit_glue_init();

52
53
    // init global module stuff
    mp_module_init();
54

55
    mp_map_init(&map_main, 1);
56
    // add some builtins that can't be done in ROM
57
58
59
60
61
62
63
    mp_map_add_qstr(&map_main, MP_QSTR___name__, MP_OBJ_NEW_QSTR(MP_QSTR___main__));

    // locals = globals for outer module (see Objects/frameobject.c/PyFrame_New())
    map_locals = map_globals = &map_main;

    // init built-in hash table
    mp_map_init(&map_builtins, 3);
Damien George's avatar
Damien George committed
64

65
#if MICROPY_CPYTHON_COMPAT
66
    // Precreate sys module, so "import sys" didn't throw exceptions.
67
68
69
    mp_obj_t m_sys = mp_obj_new_module(MP_QSTR_sys);
    // Avoid warning of unused var
    (void)m_sys;
70
#endif
71
72
    // init sys.path
    // for efficiency, left to platform-specific startup code
Damien George's avatar
Damien George committed
73
74
    //mp_sys_path = mp_obj_new_list(0, NULL);
    //mp_store_attr(m_sys, MP_QSTR_path, mp_sys_path);
Damien's avatar
Damien committed
75
76
}

Damien George's avatar
Damien George committed
77
void mp_deinit(void) {
78
79
80
81
    mp_map_free(map_globals);
    mp_map_deinit(&map_builtins);
    mp_module_deinit();
    mp_emit_glue_deinit();
Damien's avatar
Damien committed
82
83
}

Damien George's avatar
Damien George committed
84
mp_obj_t mp_load_const_dec(qstr qstr) {
Damien's avatar
Damien committed
85
    DEBUG_OP_printf("load '%s'\n", qstr_str(qstr));
86
87
    uint len;
    const byte* data = qstr_data(qstr, &len);
88
    return mp_parse_num_decimal((const char*)data, len, true, false);
Damien's avatar
Damien committed
89
90
}

Damien George's avatar
Damien George committed
91
mp_obj_t mp_load_const_str(qstr qstr) {
Damien's avatar
Damien committed
92
    DEBUG_OP_printf("load '%s'\n", qstr_str(qstr));
93
    return MP_OBJ_NEW_QSTR(qstr);
Damien's avatar
Damien committed
94
95
}

Damien George's avatar
Damien George committed
96
mp_obj_t mp_load_const_bytes(qstr qstr) {
97
98
99
100
101
102
    DEBUG_OP_printf("load b'%s'\n", qstr_str(qstr));
    uint len;
    const byte *data = qstr_data(qstr, &len);
    return mp_obj_new_bytes(data, len);
}

Damien George's avatar
Damien George committed
103
mp_obj_t mp_load_name(qstr qstr) {
Damien's avatar
Damien committed
104
    // logic: search locals, globals, builtins
105
106
107
108
109
110
111
    DEBUG_OP_printf("load name %s\n", map_locals, qstr_str(qstr));
    // If we're at the outer scope (locals == globals), dispatch to load_global right away
    if (map_locals != map_globals) {
        mp_map_elem_t *elem = mp_map_lookup(map_locals, MP_OBJ_NEW_QSTR(qstr), MP_MAP_LOOKUP);
        if (elem != NULL) {
            return elem->value;
        }
Damien's avatar
Damien committed
112
    }
113
    return mp_load_global(qstr);
Damien's avatar
Damien committed
114
115
}

Damien George's avatar
Damien George committed
116
mp_obj_t mp_load_global(qstr qstr) {
117
118
    // logic: search globals, builtins
    DEBUG_OP_printf("load global %s\n", qstr_str(qstr));
119
    mp_map_elem_t *elem = mp_map_lookup(map_globals, MP_OBJ_NEW_QSTR(qstr), MP_MAP_LOOKUP);
120
    if (elem == NULL) {
121
        elem = mp_map_lookup(&map_builtins, MP_OBJ_NEW_QSTR(qstr), MP_MAP_LOOKUP);
122
        if (elem == NULL) {
123
124
125
            mp_obj_t o = mp_builtin_tables_lookup_object(qstr);
            if (o != MP_OBJ_NULL) {
                return o;
126
            }
127
            nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_NameError, "name '%s' is not defined", qstr_str(qstr)));
128
129
130
        }
    }
    return elem->value;
Damien's avatar
Damien committed
131
132
}

Damien George's avatar
Damien George committed
133
mp_obj_t mp_load_build_class(void) {
Damien's avatar
Damien committed
134
    DEBUG_OP_printf("load_build_class\n");
135
    // lookup __build_class__ in dynamic table of builtins first
136
    mp_map_elem_t *elem = mp_map_lookup(&map_builtins, MP_OBJ_NEW_QSTR(MP_QSTR___build_class__), MP_MAP_LOOKUP);
137
    if (elem != NULL) {
138
        // found user-defined __build_class__, return it
139
140
        return elem->value;
    } else {
141
        // no user-defined __build_class__, return builtin one
142
        return (mp_obj_t)&mp_builtin___build_class___obj;
Damien's avatar
Damien committed
143
144
145
    }
}

Damien George's avatar
Damien George committed
146
void mp_store_name(qstr qstr, mp_obj_t obj) {
147
    DEBUG_OP_printf("store name %s <- %p\n", qstr_str(qstr), obj);
148
    mp_map_lookup(map_locals, MP_OBJ_NEW_QSTR(qstr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = obj;
149
150
}

Damien George's avatar
Damien George committed
151
void mp_delete_name(qstr qstr) {
152
    DEBUG_OP_printf("delete name %s\n", qstr_str(qstr));
153
    // TODO raise NameError if qstr not found
154
155
156
    mp_map_lookup(map_locals, MP_OBJ_NEW_QSTR(qstr), MP_MAP_LOOKUP_REMOVE_IF_FOUND);
}

Damien George's avatar
Damien George committed
157
void mp_store_global(qstr qstr, mp_obj_t obj) {
158
    DEBUG_OP_printf("store global %s <- %p\n", qstr_str(qstr), obj);
159
    mp_map_lookup(map_globals, MP_OBJ_NEW_QSTR(qstr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = obj;
Damien's avatar
Damien committed
160
161
}

Damien George's avatar
Damien George committed
162
mp_obj_t mp_unary_op(int op, mp_obj_t arg) {
Damien's avatar
Damien committed
163
    DEBUG_OP_printf("unary %d %p\n", op, arg);
164

165
166
    if (MP_OBJ_IS_SMALL_INT(arg)) {
        mp_small_int_t val = MP_OBJ_SMALL_INT_VALUE(arg);
Damien's avatar
Damien committed
167
        switch (op) {
Damien George's avatar
Damien George committed
168
            case MP_UNARY_OP_BOOL:
169
                return MP_BOOL(val != 0);
Damien George's avatar
Damien George committed
170
            case MP_UNARY_OP_POSITIVE:
171
                return arg;
Damien George's avatar
Damien George committed
172
            case MP_UNARY_OP_NEGATIVE:
173
174
175
176
177
178
                // check for overflow
                if (val == MP_SMALL_INT_MIN) {
                    return mp_obj_new_int(-val);
                } else {
                    return MP_OBJ_NEW_SMALL_INT(-val);
                }
Damien George's avatar
Damien George committed
179
            case MP_UNARY_OP_INVERT:
180
181
182
183
                return MP_OBJ_NEW_SMALL_INT(~val);
            default:
                assert(0);
                return arg;
184
        }
185
186
187
188
    } else {
        mp_obj_type_t *type = mp_obj_get_type(arg);
        if (type->unary_op != NULL) {
            mp_obj_t result = type->unary_op(op, arg);
189
190
191
            if (result != NULL) {
                return result;
            }
Damien's avatar
Damien committed
192
        }
193
        // TODO specify in error message what the operator is
Damien George's avatar
Damien George committed
194
        nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "bad operand type for unary operator: '%s'", mp_obj_get_type_str(arg)));
Damien's avatar
Damien committed
195
    }
Damien's avatar
Damien committed
196
197
}

Damien George's avatar
Damien George committed
198
mp_obj_t mp_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
Damien's avatar
Damien committed
199
    DEBUG_OP_printf("binary %d %p %p\n", op, lhs, rhs);
200
201
202
203
204
205
206
207
208
209

    // TODO correctly distinguish inplace operators for mutable objects
    // lookup logic that CPython uses for +=:
    //   check for implemented +=
    //   then check for implemented +
    //   then check for implemented seq.inplace_concat
    //   then check for implemented seq.concat
    //   then fail
    // note that list does not implement + or +=, so that inplace_concat is reached first for +=

210
    // deal with is
Damien George's avatar
Damien George committed
211
    if (op == MP_BINARY_OP_IS) {
212
213
214
        return MP_BOOL(lhs == rhs);
    }

215
    // deal with == and != for all types
Damien George's avatar
Damien George committed
216
    if (op == MP_BINARY_OP_EQUAL || op == MP_BINARY_OP_NOT_EQUAL) {
217
        if (mp_obj_equal(lhs, rhs)) {
Damien George's avatar
Damien George committed
218
            if (op == MP_BINARY_OP_EQUAL) {
219
220
221
222
223
                return mp_const_true;
            } else {
                return mp_const_false;
            }
        } else {
Damien George's avatar
Damien George committed
224
            if (op == MP_BINARY_OP_EQUAL) {
225
226
227
228
229
230
231
232
                return mp_const_false;
            } else {
                return mp_const_true;
            }
        }
    }

    // deal with exception_match for all types
Damien George's avatar
Damien George committed
233
    if (op == MP_BINARY_OP_EXCEPTION_MATCH) {
234
235
236
237
238
239
        // rhs must be issubclass(rhs, BaseException)
        if (mp_obj_is_exception_type(rhs)) {
            // if lhs is an instance of an exception, then extract and use its type
            if (mp_obj_is_exception_instance(lhs)) {
                lhs = mp_obj_get_type(lhs);
            }
240
            if (mp_obj_is_subclass_fast(lhs, rhs)) {
241
242
243
244
245
                return mp_const_true;
            } else {
                return mp_const_false;
            }
        }
246
247
        assert(0);
        return mp_const_false;
248
249
    }

250
    if (MP_OBJ_IS_SMALL_INT(lhs)) {
251
        mp_small_int_t lhs_val = MP_OBJ_SMALL_INT_VALUE(lhs);
252
253
        if (MP_OBJ_IS_SMALL_INT(rhs)) {
            mp_small_int_t rhs_val = MP_OBJ_SMALL_INT_VALUE(rhs);
254
255
256
257
258
259
260
261
262
            // This is a binary operation: lhs_val op rhs_val
            // We need to be careful to handle overflow; see CERT INT32-C
            // Operations that can overflow:
            //      +       result always fits in machine_int_t, then handled by SMALL_INT check
            //      -       result always fits in machine_int_t, then handled by SMALL_INT check
            //      *       checked explicitly
            //      /       if lhs=MIN and rhs=-1; result always fits in machine_int_t, then handled by SMALL_INT check
            //      %       if lhs=MIN and rhs=-1; result always fits in machine_int_t, then handled by SMALL_INT check
            //      <<      checked explicitly
263
            switch (op) {
Damien George's avatar
Damien George committed
264
265
266
267
268
269
270
271
                case MP_BINARY_OP_OR:
                case MP_BINARY_OP_INPLACE_OR: lhs_val |= rhs_val; break;
                case MP_BINARY_OP_XOR:
                case MP_BINARY_OP_INPLACE_XOR: lhs_val ^= rhs_val; break;
                case MP_BINARY_OP_AND:
                case MP_BINARY_OP_INPLACE_AND: lhs_val &= rhs_val; break;
                case MP_BINARY_OP_LSHIFT:
                case MP_BINARY_OP_INPLACE_LSHIFT: {
272
273
274
275
276
277
278
279
280
281
282
283
284
                    if (rhs_val < 0) {
                        // negative shift not allowed
                        nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "negative shift count"));
                    } else if (rhs_val >= BITS_PER_WORD || lhs_val > (MP_SMALL_INT_MAX >> rhs_val) || lhs_val < (MP_SMALL_INT_MIN >> rhs_val)) {
                        // left-shift will overflow, so use higher precision integer
                        lhs = mp_obj_new_int_from_ll(lhs_val);
                        goto generic_binary_op;
                    } else {
                        // use standard precision
                        lhs_val <<= rhs_val;
                    }
                    break;
                }
Damien George's avatar
Damien George committed
285
286
                case MP_BINARY_OP_RSHIFT:
                case MP_BINARY_OP_INPLACE_RSHIFT:
287
288
289
290
291
292
293
294
                    if (rhs_val < 0) {
                        // negative shift not allowed
                        nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "negative shift count"));
                    } else {
                        // standard precision is enough for right-shift
                        lhs_val >>= rhs_val;
                    }
                    break;
Damien George's avatar
Damien George committed
295
296
297
298
299
300
                case MP_BINARY_OP_ADD:
                case MP_BINARY_OP_INPLACE_ADD: lhs_val += rhs_val; break;
                case MP_BINARY_OP_SUBTRACT:
                case MP_BINARY_OP_INPLACE_SUBTRACT: lhs_val -= rhs_val; break;
                case MP_BINARY_OP_MULTIPLY:
                case MP_BINARY_OP_INPLACE_MULTIPLY: {
301
302
303

                    // If long long type exists and is larger than machine_int_t, then
                    // we can use the following code to perform overflow-checked multiplication.
304
                    // Otherwise (eg in x64 case) we must use mp_small_int_mul_overflow.
305
306
307
308
309
310
311
312
313
314
315
316
                    #if 0
                    // compute result using long long precision
                    long long res = (long long)lhs_val * (long long)rhs_val;
                    if (res > MP_SMALL_INT_MAX || res < MP_SMALL_INT_MIN) {
                        // result overflowed SMALL_INT, so return higher precision integer
                        return mp_obj_new_int_from_ll(res);
                    } else {
                        // use standard precision
                        lhs_val = (mp_small_int_t)res;
                    }
                    #endif

317
318
319
320
321
322
323
324
                    if (mp_small_int_mul_overflow(lhs_val, rhs_val)) {
                        // use higher precision
                        lhs = mp_obj_new_int_from_ll(lhs_val);
                        goto generic_binary_op;
                    } else {
                        // use standard precision
                        return MP_OBJ_NEW_SMALL_INT(lhs_val * rhs_val);
                    }
325
326
                    break;
                }
Damien George's avatar
Damien George committed
327
328
                case MP_BINARY_OP_FLOOR_DIVIDE:
                case MP_BINARY_OP_INPLACE_FLOOR_DIVIDE:
329
330
331
                    if (rhs_val == 0) {
                        goto zero_division;
                    }
332
                    lhs_val = mp_small_int_floor_divide(lhs_val, rhs_val);
333
                    break;
334

335
                #if MICROPY_ENABLE_FLOAT
Damien George's avatar
Damien George committed
336
                case MP_BINARY_OP_TRUE_DIVIDE:
337
338
                case MP_BINARY_OP_INPLACE_TRUE_DIVIDE:
                    if (rhs_val == 0) {
339
                        goto zero_division;
340
341
                    }
                    return mp_obj_new_float((mp_float_t)lhs_val / (mp_float_t)rhs_val);
342
                #endif
343

Damien George's avatar
Damien George committed
344
                case MP_BINARY_OP_MODULO:
345
346
                case MP_BINARY_OP_INPLACE_MODULO: {
                    lhs_val = mp_small_int_modulo(lhs_val, rhs_val);
347
348
                    break;
                }
349

Damien George's avatar
Damien George committed
350
351
                case MP_BINARY_OP_POWER:
                case MP_BINARY_OP_INPLACE_POWER:
352
353
354
355
356
357
358
359
360
361
362
                    if (rhs_val < 0) {
                        #if MICROPY_ENABLE_FLOAT
                        lhs = mp_obj_new_float(lhs_val);
                        goto generic_binary_op;
                        #else
                        nlr_jump(mp_obj_new_exception_msg(&mp_type_ValueError, "negative power with no float support"));
                        #endif
                    } else {
                        machine_int_t ans = 1;
                        while (rhs_val > 0) {
                            if (rhs_val & 1) {
363
                                if (mp_small_int_mul_overflow(ans, lhs_val)) {
364
365
                                    goto power_overflow;
                                }
366
                                ans *= lhs_val;
367
368
369
                            }
                            if (rhs_val == 1) {
                                break;
370
371
                            }
                            rhs_val /= 2;
372
                            if (mp_small_int_mul_overflow(lhs_val, lhs_val)) {
373
374
                                goto power_overflow;
                            }
375
                            lhs_val *= lhs_val;
376
                        }
377
                        lhs_val = ans;
378
                    }
379
                    break;
380
381
382
383
384
385

                power_overflow:
                    // use higher precision
                    lhs = mp_obj_new_int_from_ll(MP_OBJ_SMALL_INT_VALUE(lhs));
                    goto generic_binary_op;

Damien George's avatar
Damien George committed
386
387
388
389
                case MP_BINARY_OP_LESS: return MP_BOOL(lhs_val < rhs_val); break;
                case MP_BINARY_OP_MORE: return MP_BOOL(lhs_val > rhs_val); break;
                case MP_BINARY_OP_LESS_EQUAL: return MP_BOOL(lhs_val <= rhs_val); break;
                case MP_BINARY_OP_MORE_EQUAL: return MP_BOOL(lhs_val >= rhs_val); break;
390

391
392
                default: assert(0);
            }
393
394
            // TODO: We just should make mp_obj_new_int() inline and use that
            if (MP_OBJ_FITS_SMALL_INT(lhs_val)) {
395
                return MP_OBJ_NEW_SMALL_INT(lhs_val);
396
397
            } else {
                return mp_obj_new_int(lhs_val);
398
            }
399
#if MICROPY_ENABLE_FLOAT
400
        } else if (MP_OBJ_IS_TYPE(rhs, &mp_type_float)) {
401
            return mp_obj_float_binary_op(op, lhs_val, rhs);
402
        } else if (MP_OBJ_IS_TYPE(rhs, &mp_type_complex)) {
403
            return mp_obj_complex_binary_op(op, lhs_val, 0, rhs);
404
#endif
405
        }
406
    }
407

408
    /* deal with `in`
409
410
     *
     * NOTE `a in b` is `b.__contains__(a)`, hence why the generic dispatch
Damien George's avatar
Damien George committed
411
     * needs to go below with swapped arguments
412
     */
Damien George's avatar
Damien George committed
413
    if (op == MP_BINARY_OP_IN) {
414
415
416
        mp_obj_type_t *type = mp_obj_get_type(rhs);
        if (type->binary_op != NULL) {
            mp_obj_t res = type->binary_op(op, rhs, lhs);
Damien George's avatar
Damien George committed
417
            if (res != MP_OBJ_NULL) {
418
                return res;
John R. Lenton's avatar
John R. Lenton committed
419
            }
420
421
422
423
        }
        if (type->getiter != NULL) {
            /* second attempt, walk the iterator */
            mp_obj_t next = NULL;
Damien George's avatar
Damien George committed
424
425
            mp_obj_t iter = mp_getiter(rhs);
            while ((next = mp_iternext(iter)) != MP_OBJ_NULL) {
426
                if (mp_obj_equal(next, lhs)) {
427
                    return mp_const_true;
John R. Lenton's avatar
John R. Lenton committed
428
                }
429
            }
430
            return mp_const_false;
431
432
433
        }

        nlr_jump(mp_obj_new_exception_msg_varg(
434
                     &mp_type_TypeError, "'%s' object is not iterable",
435
436
437
438
                     mp_obj_get_type_str(rhs)));
        return mp_const_none;
    }

439
    // generic binary_op supplied by type
440
441
442
    mp_obj_type_t *type;
generic_binary_op:
    type = mp_obj_get_type(lhs);
443
444
445
446
    if (type->binary_op != NULL) {
        mp_obj_t result = type->binary_op(op, lhs, rhs);
        if (result != MP_OBJ_NULL) {
            return result;
Damien's avatar
Damien committed
447
448
        }
    }
449

450
451
    // TODO implement dispatch for reverse binary ops

John R. Lenton's avatar
John R. Lenton committed
452
    // TODO specify in error message what the operator is
453
    nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
John R. Lenton's avatar
John R. Lenton committed
454
455
        "unsupported operand types for binary operator: '%s', '%s'",
        mp_obj_get_type_str(lhs), mp_obj_get_type_str(rhs)));
456
    return mp_const_none;
457
458
459

zero_division:
    nlr_jump(mp_obj_new_exception_msg(&mp_type_ZeroDivisionError, "division by zero"));
Damien's avatar
Damien committed
460
461
}

Damien George's avatar
Damien George committed
462
463
mp_obj_t mp_call_function_0(mp_obj_t fun) {
    return mp_call_function_n_kw(fun, 0, 0, NULL);
464
465
}

Damien George's avatar
Damien George committed
466
467
mp_obj_t mp_call_function_1(mp_obj_t fun, mp_obj_t arg) {
    return mp_call_function_n_kw(fun, 1, 0, &arg);
468
469
}

Damien George's avatar
Damien George committed
470
mp_obj_t mp_call_function_2(mp_obj_t fun, mp_obj_t arg1, mp_obj_t arg2) {
471
    mp_obj_t args[2];
472
473
    args[0] = arg1;
    args[1] = arg2;
Damien George's avatar
Damien George committed
474
    return mp_call_function_n_kw(fun, 2, 0, args);
475
476
}

477
478
// wrapper that accepts n_args and n_kw in one argument
// native emitter can only pass at most 3 arguments to a function
Damien George's avatar
Damien George committed
479
480
mp_obj_t mp_call_function_n_kw_for_native(mp_obj_t fun_in, uint n_args_kw, const mp_obj_t *args) {
    return mp_call_function_n_kw(fun_in, n_args_kw & 0xff, (n_args_kw >> 8) & 0xff, args);
481
482
}

483
// args contains, eg: arg0  arg1  key0  value0  key1  value1
Damien George's avatar
Damien George committed
484
mp_obj_t mp_call_function_n_kw(mp_obj_t fun_in, uint n_args, uint n_kw, const mp_obj_t *args) {
485
486
    // TODO improve this: fun object can specify its type and we parse here the arguments,
    // passing to the function arrays of fixed and keyword arguments
487

488
489
    DEBUG_OP_printf("calling function %p(n_args=%d, n_kw=%d, args=%p)\n", fun_in, n_args, n_kw, args);

490
491
492
493
494
495
    // get the type
    mp_obj_type_t *type = mp_obj_get_type(fun_in);

    // do the call
    if (type->call != NULL) {
        return type->call(fun_in, n_args, n_kw, args);
496
    } else {
Damien George's avatar
Damien George committed
497
        nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not callable", mp_obj_get_type_str(fun_in)));
498
    }
499
500
}

501
502
// args contains: fun  self/NULL  arg(0)  ...  arg(n_args-2)  arg(n_args-1)  kw_key(0)  kw_val(0)  ... kw_key(n_kw-1)  kw_val(n_kw-1)
// if n_args==0 and n_kw==0 then there are only fun and self/NULL
Damien George's avatar
Damien George committed
503
mp_obj_t mp_call_method_n_kw(uint n_args, uint n_kw, const mp_obj_t *args) {
504
505
    DEBUG_OP_printf("call method (fun=%p, self=%p, n_args=%u, n_kw=%u, args=%p)\n", args[0], args[1], n_args, n_kw, args);
    int adjust = (args[1] == NULL) ? 0 : 1;
Damien George's avatar
Damien George committed
506
    return mp_call_function_n_kw(args[0], n_args + adjust, n_kw, args + 2 - adjust);
507
508
}

509
mp_obj_t mp_call_method_n_kw_var(bool have_self, uint n_args_n_kw, const mp_obj_t *args) {
510
511
512
513
514
515
516
    mp_obj_t fun = *args++;
    mp_obj_t self = MP_OBJ_NULL;
    if (have_self) {
        self = *args++; // may be MP_OBJ_NULL
    }
    uint n_args = n_args_n_kw & 0xff;
    uint n_kw = (n_args_n_kw >> 8) & 0xff;
517
518
    mp_obj_t pos_seq = args[n_args + 2 * n_kw]; // map be MP_OBJ_NULL
    mp_obj_t kw_dict = args[n_args + 2 * n_kw + 1]; // map be MP_OBJ_NULL
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652

    DEBUG_OP_printf("call method var (fun=%p, self=%p, n_args=%u, n_kw=%u, args=%p, seq=%p, dict=%p)\n", fun, self, n_args, n_kw, args, pos_seq, kw_dict);

    // We need to create the following array of objects:
    //     args[0 .. n_args]  unpacked(pos_seq)  args[n_args .. n_args + 2 * n_kw]  unpacked(kw_dict)
    // TODO: optimize one day to avoid constructing new arg array? Will be hard.

    // The new args array
    mp_obj_t *args2;
    uint args2_alloc;
    uint args2_len = 0;

    // Try to get a hint for the size of the kw_dict
    uint kw_dict_len = 0;
    if (kw_dict != MP_OBJ_NULL && MP_OBJ_IS_TYPE(kw_dict, &mp_type_dict)) {
        kw_dict_len = mp_obj_dict_len(kw_dict);
    }

    // Extract the pos_seq sequence to the new args array.
    // Note that it can be arbitrary iterator.
    if (pos_seq == MP_OBJ_NULL) {
        // no sequence

        // allocate memory for the new array of args
        args2_alloc = 1 + n_args + 2 * (n_kw + kw_dict_len);
        args2 = m_new(mp_obj_t, args2_alloc);

        // copy the self
        if (self != MP_OBJ_NULL) {
            args2[args2_len++] = self;
        }

        // copy the fixed pos args
        m_seq_copy(args2 + args2_len, args, n_args, mp_obj_t);
        args2_len += n_args;

    } else if (MP_OBJ_IS_TYPE(pos_seq, &mp_type_tuple) || MP_OBJ_IS_TYPE(pos_seq, &mp_type_list)) {
        // optimise the case of a tuple and list

        // get the items
        uint len;
        mp_obj_t *items;
        mp_obj_get_array(pos_seq, &len, &items);

        // allocate memory for the new array of args
        args2_alloc = 1 + n_args + len + 2 * (n_kw + kw_dict_len);
        args2 = m_new(mp_obj_t, args2_alloc);

        // copy the self
        if (self != MP_OBJ_NULL) {
            args2[args2_len++] = self;
        }

        // copy the fixed and variable position args
        m_seq_cat(args2 + args2_len, args, n_args, items, len, mp_obj_t);
        args2_len += n_args + len;

    } else {
        // generic iterator

        // allocate memory for the new array of args
        args2_alloc = 1 + n_args + 2 * (n_kw + kw_dict_len) + 3;
        args2 = m_new(mp_obj_t, args2_alloc);

        // copy the self
        if (self != MP_OBJ_NULL) {
            args2[args2_len++] = self;
        }

        // copy the fixed position args
        m_seq_copy(args2 + args2_len, args, n_args, mp_obj_t);

        // extract the variable position args from the iterator
        mp_obj_t iterable = mp_getiter(pos_seq);
        mp_obj_t item;
        while ((item = mp_iternext(iterable)) != MP_OBJ_NULL) {
            if (args2_len >= args2_alloc) {
                args2 = m_renew(mp_obj_t, args2, args2_alloc, args2_alloc * 2);
                args2_alloc *= 2;
            }
            args2[args2_len++] = item;
        }
    }

    // The size of the args2 array now is the number of positional args.
    uint pos_args_len = args2_len;

    // Copy the fixed kw args.
    m_seq_copy(args2 + args2_len, args + n_args, 2 * n_kw, mp_obj_t);
    args2_len += 2 * n_kw;

    // Extract (key,value) pairs from kw_dict dictionary and append to args2.
    // Note that it can be arbitrary iterator.
    if (kw_dict == MP_OBJ_NULL) {
        // pass
    } else if (MP_OBJ_IS_TYPE(kw_dict, &mp_type_dict)) {
        // dictionary
        mp_map_t *map = mp_obj_dict_get_map(kw_dict);
        assert(args2_len + 2 * map->used <= args2_alloc); // should have enough, since kw_dict_len is in this case hinted correctly above
        for (uint i = 0; i < map->alloc; i++) {
            if (map->table[i].key != MP_OBJ_NULL) {
                args2[args2_len++] = map->table[i].key;
                args2[args2_len++] = map->table[i].value;
            }
        }
    } else {
        // generic mapping
        // TODO is calling 'items' on the mapping the correct thing to do here?
        mp_obj_t dest[2];
        mp_load_method(kw_dict, MP_QSTR_items, dest);
        mp_obj_t iterable = mp_getiter(mp_call_method_n_kw(0, 0, dest));
        mp_obj_t item;
        while ((item = mp_iternext(iterable)) != MP_OBJ_NULL) {
            if (args2_len + 1 >= args2_alloc) {
                uint new_alloc = args2_alloc * 2;
                if (new_alloc < 4) {
                    new_alloc = 4;
                }
                args2 = m_renew(mp_obj_t, args2, args2_alloc, new_alloc);
                args2_alloc = new_alloc;
            }
            mp_obj_t *items;
            mp_obj_get_array_fixed_n(item, 2, &items);
            args2[args2_len++] = items[0];
            args2[args2_len++] = items[1];
        }
    }

    mp_obj_t res = mp_call_function_n_kw(fun, pos_args_len, (args2_len - pos_args_len) / 2, args2);
    m_del(mp_obj_t, args2, args2_alloc);

    return res;
}

653
// unpacked items are stored in reverse order into the array pointed to by items
Damien George's avatar
Damien George committed
654
void mp_unpack_sequence(mp_obj_t seq_in, uint num, mp_obj_t *items) {
655
    uint seq_len;
656
    if (MP_OBJ_IS_TYPE(seq_in, &mp_type_tuple) || MP_OBJ_IS_TYPE(seq_in, &mp_type_list)) {
657
        mp_obj_t *seq_items;
658
        if (MP_OBJ_IS_TYPE(seq_in, &mp_type_tuple)) {
659
660
661
            mp_obj_tuple_get(seq_in, &seq_len, &seq_items);
        } else {
            mp_obj_list_get(seq_in, &seq_len, &seq_items);
662
        }
663
        if (seq_len < num) {
664
            goto too_short;
665
        } else if (seq_len > num) {
666
            goto too_long;
667
        }
668
669
670
        for (uint i = 0; i < num; i++) {
            items[i] = seq_items[num - 1 - i];
        }
671
    } else {
Damien George's avatar
Damien George committed
672
        mp_obj_t iterable = mp_getiter(seq_in);
673
674

        for (seq_len = 0; seq_len < num; seq_len++) {
Damien George's avatar
Damien George committed
675
            mp_obj_t el = mp_iternext(iterable);
676
            if (el == MP_OBJ_NULL) {
677
678
679
680
                goto too_short;
            }
            items[num - 1 - seq_len] = el;
        }
Damien George's avatar
Damien George committed
681
        if (mp_iternext(iterable) != MP_OBJ_NULL) {
682
683
            goto too_long;
        }
684
    }
685
686
687
    return;

too_short:
688
    nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "need more than %d values to unpack", seq_len));
689
too_long:
690
    nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "too many values to unpack (expected %d)", num));
691
692
}

693
mp_obj_t mp_load_attr_default(mp_obj_t base, qstr attr, mp_obj_t defval) {
694
695
    DEBUG_OP_printf("load attr %p.%s\n", base, qstr_str(attr));
    mp_obj_t dest[2];
696
697
698
699
700
    // use load_method, raising or not raising exception
    ((defval == MP_OBJ_NULL) ? mp_load_method : mp_load_method_maybe)(base, attr, dest);
    if (dest[0] == MP_OBJ_NULL) {
        return defval;
    } else if (dest[1] == MP_OBJ_NULL) {
701
        // load_method returned just a normal attribute
702
        return dest[0];
703
704
705
    } else {
        // load_method returned a method, so build a bound method object
        return mp_obj_new_bound_meth(dest[0], dest[1]);
Damien's avatar
Damien committed
706
707
708
    }
}

709
710
711
712
mp_obj_t mp_load_attr(mp_obj_t base, qstr attr) {
    return mp_load_attr_default(base, attr, MP_OBJ_NULL);
}

713
714
715
// no attribute found, returns:     dest[0] == MP_OBJ_NULL, dest[1] == MP_OBJ_NULL
// normal attribute found, returns: dest[0] == <attribute>, dest[1] == MP_OBJ_NULL
// method attribute found, returns: dest[0] == <method>,    dest[1] == <self>
Damien George's avatar
Damien George committed
716
void mp_load_method_maybe(mp_obj_t base, qstr attr, mp_obj_t *dest) {
717
718
719
720
721
722
723
    // clear output to indicate no attribute/method found yet
    dest[0] = MP_OBJ_NULL;
    dest[1] = MP_OBJ_NULL;

    // get the type
    mp_obj_type_t *type = mp_obj_get_type(base);

Damien George's avatar
Damien George committed
724
725
    // look for built-in names
    if (0) {
726
#if MICROPY_CPYTHON_COMPAT
Damien George's avatar
Damien George committed
727
728
729
    } else if (attr == MP_QSTR___class__) {
        // a.__class__ is equivalent to type(a)
        dest[0] = type;
730
#endif
Damien George's avatar
Damien George committed
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762

    } else if (attr == MP_QSTR___next__ && type->iternext != NULL) {
        dest[0] = (mp_obj_t)&mp_builtin_next_obj;
        dest[1] = base;

    } else if (type->load_attr != NULL) {
        // this type can do its own load, so call it
        type->load_attr(base, attr, dest);

    } else if (type->locals_dict != NULL) {
        // generic method lookup
        // this is a lookup in the object (ie not class or type)
        assert(MP_OBJ_IS_TYPE(type->locals_dict, &mp_type_dict)); // Micro Python restriction, for now
        mp_map_t *locals_map = mp_obj_dict_get_map(type->locals_dict);
        mp_map_elem_t *elem = mp_map_lookup(locals_map, MP_OBJ_NEW_QSTR(attr), MP_MAP_LOOKUP);
        if (elem != NULL) {
            // check if the methods are functions, static or class methods
            // see http://docs.python.org/3.3/howto/descriptor.html
            if (MP_OBJ_IS_TYPE(elem->value, &mp_type_staticmethod)) {
                // return just the function
                dest[0] = ((mp_obj_static_class_method_t*)elem->value)->fun;
            } else if (MP_OBJ_IS_TYPE(elem->value, &mp_type_classmethod)) {
                // return a bound method, with self being the type of this object
                dest[0] = ((mp_obj_static_class_method_t*)elem->value)->fun;
                dest[1] = mp_obj_get_type(base);
            } else if (mp_obj_is_callable(elem->value)) {
                // return a bound method, with self being this object
                dest[0] = elem->value;
                dest[1] = base;
            } else {
                // class member is a value, so just return that value
                dest[0] = elem->value;
Damien's avatar
Damien committed
763
764
            }
        }
765
    }
766
767
}

Damien George's avatar
Damien George committed
768
void mp_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest) {
769
770
    DEBUG_OP_printf("load method %p.%s\n", base, qstr_str(attr));

Damien George's avatar
Damien George committed
771
    mp_load_method_maybe(base, attr, dest);
772

773
    if (dest[0] == MP_OBJ_NULL) {
774
775
        // no attribute/method called attr
        // following CPython, we give a more detailed error message for type objects
776
        if (MP_OBJ_IS_TYPE(base, &mp_type_type)) {
777
778
            nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_AttributeError,
                "type object '%s' has no attribute '%s'", qstr_str(((mp_obj_type_t*)base)->name), qstr_str(attr)));
779
        } else {
780
            nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_AttributeError, "'%s' object has no attribute '%s'", mp_obj_get_type_str(base), qstr_str(attr)));
781
782
        }
    }
783
784
}

Damien George's avatar
Damien George committed
785
void mp_store_attr(mp_obj_t base, qstr attr, mp_obj_t value) {
Damien's avatar
Damien committed
786
    DEBUG_OP_printf("store attr %p.%s <- %p\n", base, qstr_str(attr), value);
787
788
789
790
791
    mp_obj_type_t *type = mp_obj_get_type(base);
    if (type->store_attr != NULL) {
        if (type->store_attr(base, attr, value)) {
            return;
        }
792
    }
793
    nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_AttributeError, "'%s' object has no attribute '%s'", mp_obj_get_type_str(base), qstr_str(attr)));
794
795
}

Damien George's avatar
Damien George committed
796
void mp_store_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t value) {
Damien's avatar
Damien committed
797
    DEBUG_OP_printf("store subscr %p[%p] <- %p\n", base, index, value);
798
    if (MP_OBJ_IS_TYPE(base, &mp_type_list)) {
799
        // list store
800
        mp_obj_list_store(base, index, value);
801
    } else if (MP_OBJ_IS_TYPE(base, &mp_type_dict)) {
802
803
        // dict store
        mp_obj_dict_store(base, index, value);
Damien's avatar
Damien committed
804
    } else {
805
806
807
808
809
810
811
812
        mp_obj_type_t *type = mp_obj_get_type(base);
        if (type->store_item != NULL) {
            bool r = type->store_item(base, index, value);
            if (r) {
                return;
            }
            // TODO: call base classes here?
        }
813
        nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object does not support item assignment", mp_obj_get_type_str(base)));
Damien's avatar
Damien committed
814
815
816
    }
}

817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
void mp_delete_subscr(mp_obj_t base, mp_obj_t index) {
    DEBUG_OP_printf("delete subscr %p[%p]\n", base, index);
    /* list delete not implemented
    if (MP_OBJ_IS_TYPE(base, &mp_type_list)) {
        // list delete
        mp_obj_list_delete(base, index);
    } else */
    if (MP_OBJ_IS_TYPE(base, &mp_type_dict)) {
        // dict delete
        mp_obj_dict_delete(base, index);
    } else {
        nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object does not support item deletion", mp_obj_get_type_str(base)));
    }
}

Damien George's avatar
Damien George committed
832
mp_obj_t mp_getiter(mp_obj_t o_in) {
833
834
835
    mp_obj_type_t *type = mp_obj_get_type(o_in);
    if (type->getiter != NULL) {
        return type->getiter(o_in);
836
    } else {
837
        // check for __iter__ method
838
        mp_obj_t dest[2];
Damien George's avatar
Damien George committed
839
        mp_load_method_maybe(o_in, MP_QSTR___iter__, dest);
840
        if (dest[0] != MP_OBJ_NULL) {
841
            // __iter__ exists, call it and return its result
Damien George's avatar
Damien George committed
842
            return mp_call_method_n_kw(0, 0, dest);
843
        } else {
Damien George's avatar
Damien George committed
844
            mp_load_method_maybe(o_in, MP_QSTR___getitem__, dest);
845
846
847
848
849
850
851
            if (dest[0] != MP_OBJ_NULL) {
                // __getitem__ exists, create an iterator
                return mp_obj_new_getitem_iter(dest);
            } else {
                // object not iterable
                nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not iterable", mp_obj_get_type_str(o_in)));
            }
852
        }
853
854
    }
}
855

856
857
// may return MP_OBJ_NULL as an optimisation instead of raise StopIteration()
// may also raise StopIteration()
Damien George's avatar
Damien George committed
858
mp_obj_t mp_iternext_allow_raise(mp_obj_t o_in) {
859
860
861
    mp_obj_type_t *type = mp_obj_get_type(o_in);
    if (type->iternext != NULL) {
        return type->iternext(o_in);
862
    } else {
863
864
        // check for __next__ method
        mp_obj_t dest[2];
Damien George's avatar
Damien George committed
865
        mp_load_method_maybe(o_in, MP_QSTR___next__, dest);
866
867
        if (dest[0] != MP_OBJ_NULL) {
            // __next__ exists, call it and return its result
Damien George's avatar
Damien George committed
868
            return mp_call_method_n_kw(0, 0, dest);
869
870
871
        } else {
            nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not an iterator", mp_obj_get_type_str(o_in)));
        }
872
873
874
    }
}

875
876
// will always return MP_OBJ_NULL instead of raising StopIteration() (or any subclass thereof)
// may raise other exceptions
Damien George's avatar
Damien George committed
877
mp_obj_t mp_iternext(mp_obj_t o_in) {
878
879
880
881
882
883
    mp_obj_type_t *type = mp_obj_get_type(o_in);
    if (type->iternext != NULL) {
        return type->iternext(o_in);
    } else {
        // check for __next__ method
        mp_obj_t dest[2];
Damien George's avatar
Damien George committed
884
        mp_load_method_maybe(o_in, MP_QSTR___next__, dest);
885
886
887
888
        if (dest[0] != MP_OBJ_NULL) {
            // __next__ exists, call it and return its result
            nlr_buf_t nlr;
            if (nlr_push(&nlr) == 0) {
Damien George's avatar
Damien George committed
889
                mp_obj_t ret = mp_call_method_n_kw(0, 0, dest);
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
                nlr_pop();
                return ret;
            } else {
                if (mp_obj_is_subclass_fast(mp_obj_get_type(nlr.ret_val), &mp_type_StopIteration)) {
                    return MP_OBJ_NULL;
                } else {
                    nlr_jump(nlr.ret_val);
                }
            }
        } else {
            nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not an iterator", mp_obj_get_type_str(o_in)));
        }
    }
}

905
906
// TODO: Unclear what to do with StopIterarion exception here.
mp_vm_return_kind_t mp_resume(mp_obj_t self_in, mp_obj_t send_value, mp_obj_t throw_value, mp_obj_t *ret_val) {
907
    assert((send_value != MP_OBJ_NULL) ^ (throw_value != MP_OBJ_NULL));
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
    mp_obj_type_t *type = mp_obj_get_type(self_in);

    if (type == &mp_type_gen_instance) {
        return mp_obj_gen_resume(self_in, send_value, throw_value, ret_val);
    }

    if (type->iternext != NULL && send_value == mp_const_none) {
        mp_obj_t ret = type->iternext(self_in);
        if (ret != MP_OBJ_NULL) {
            *ret_val = ret;
            return MP_VM_RETURN_YIELD;
        } else {
            // Emulate raise StopIteration()
            // Special case, handled in vm.c
            *ret_val = MP_OBJ_NULL;
            return MP_VM_RETURN_NORMAL;
        }
    }

    mp_obj_t dest[3]; // Reserve slot for send() arg

    if (send_value == mp_const_none) {
        mp_load_method_maybe(self_in, MP_QSTR___next__, dest);
        if (dest[0] != MP_OBJ_NULL) {
            *ret_val = mp_call_method_n_kw(0, 0, dest);
            return MP_VM_RETURN_YIELD;
        }
    }

    if (send_value != MP_OBJ_NULL) {
        mp_load_method(self_in, MP_QSTR_send, dest);
        dest[2] = send_value;
        *ret_val = mp_call_method_n_kw(1, 0, dest);
        return MP_VM_RETURN_YIELD;
    }

    if (throw_value != MP_OBJ_NULL) {
        if (mp_obj_is_subclass_fast(mp_obj_get_type(throw_value), &mp_type_GeneratorExit)) {
            mp_load_method_maybe(self_in, MP_QSTR_close, dest);
            if (dest[0] != MP_OBJ_NULL) {
                *ret_val = mp_call_method_n_kw(0, 0, dest);
                // We assume one can't "yield" from close()
                return MP_VM_RETURN_NORMAL;
            }
        }
953
954
955
956
957
958
959
960
961
962
963
964
965
966
        mp_load_method_maybe(self_in, MP_QSTR_throw, dest);
        if (dest[0] != MP_OBJ_NULL) {
            *ret_val = mp_call_method_n_kw(1, 0, &throw_value);
            // If .throw() method returned, we assume it's value to yield
            // - any exception would be thrown with nlr_jump().
            return MP_VM_RETURN_YIELD;
        }
        // If there's nowhere to throw exception into, then we assume that object
        // is just incapable to handle it, so any exception thrown into it
        // will be propagated up. This behavior is approved by test_pep380.py
        // test_delegation_of_close_to_non_generator(),
        //  test_delegating_throw_to_non_generator()
        *ret_val = throw_value;
        return MP_VM_RETURN_EXCEPTION;
967
968
969
970
971
972
    }

    assert(0);
    return MP_VM_RETURN_NORMAL; // Should be unreachable
}

Damien George's avatar
Damien George committed
973
mp_obj_t mp_make_raise_obj(mp_obj_t o) {
974
975
976
977
    DEBUG_printf("raise %p\n", o);
    if (mp_obj_is_exception_type(o)) {
        // o is an exception type (it is derived from BaseException (or is BaseException))
        // create and return a new exception instance by calling o
978
979
        // TODO could have an option to disable traceback, then builtin exceptions (eg TypeError)
        // could have const instances in ROM which we return here instead
Damien George's avatar
Damien George committed
980
        return mp_call_function_n_kw(o, 0, 0, NULL);
981
982
983
984
985
986
    } else if (mp_obj_is_exception_instance(o)) {
        // o is an instance of an exception, so use it as the exception
        return o;
    } else {
        // o cannot be used as an exception, so return a type error (which will be raised by the caller)
        return mp_obj_new_exception_msg(&mp_type_TypeError, "exceptions must derive from BaseException");
987
988
989
    }
}

Damien George's avatar
Damien George committed
990
mp_obj_t mp_import_name(qstr name, mp_obj_t fromlist, mp_obj_t level) {
991
992
    DEBUG_printf("import name %s\n", qstr_str(name));

993
    // build args array
994
    mp_obj_t args[5];
995
    args[0] = MP_OBJ_NEW_QSTR(name);
996
997
    args[1] = mp_const_none; // TODO should be globals
    args[2] = mp_const_none; // TODO should be locals
998
999
1000
    args[3] = fromlist;
    args[4] = level; // must be 0; we don't yet support other values