runtime.c 33 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 "objmodule.h"
11
#include "parsenum.h"
12
#include "runtime0.h"
Damien's avatar
Damien committed
13
#include "runtime.h"
14
#include "emitglue.h"
15
16
#include "map.h"
#include "builtin.h"
17
#include "builtintables.h"
18
#include "bc.h"
19
#include "intdivmod.h"
20

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

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

35
// a good optimising compiler will inline this if necessary
36
STATIC void mp_map_add_qstr(mp_map_t *map, qstr qstr, mp_obj_t value) {
37
38
39
    mp_map_lookup(map, MP_OBJ_NEW_QSTR(qstr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;
}

40
void rt_init(void) {
41
42
    mp_emit_glue_init();

43
    // locals = globals for outer module (see Objects/frameobject.c/PyFrame_New())
44
    map_locals = map_globals = mp_map_new(1);
45

46
    // init built-in hash table
47
    mp_map_init(&map_builtins, 3);
48

49
50
    // init global module stuff
    mp_module_init();
51

52
53
    // add some builtins that can't be done in ROM
    mp_map_add_qstr(map_globals, MP_QSTR___name__, MP_OBJ_NEW_QSTR(MP_QSTR___main__));
54
    mp_map_add_qstr(&map_builtins, MP_QSTR_Ellipsis, mp_const_ellipsis);
Damien George's avatar
Damien George committed
55

56
#if MICROPY_CPYTHON_COMPAT
57
    // Precreate sys module, so "import sys" didn't throw exceptions.
58
59
60
    mp_obj_t m_sys = mp_obj_new_module(MP_QSTR_sys);
    // Avoid warning of unused var
    (void)m_sys;
61
#endif
62
63
64
65
    // init sys.path
    // for efficiency, left to platform-specific startup code
    //sys_path = mp_obj_new_list(0, NULL);
    //rt_store_attr(m_sys, MP_QSTR_path, sys_path);
Damien's avatar
Damien committed
66
67
}

68
void rt_deinit(void) {
69
70
71
72
    mp_map_free(map_globals);
    mp_map_deinit(&map_builtins);
    mp_module_deinit();
    mp_emit_glue_deinit();
Damien's avatar
Damien committed
73
74
}

75
76
int rt_is_true(mp_obj_t arg) {
    DEBUG_OP_printf("is true %p\n", arg);
77
78
79
80
81
82
83
    if (arg == mp_const_false) {
        return 0;
    } else if (arg == mp_const_true) {
        return 1;
    } else if (arg == mp_const_none) {
        return 0;
    } else if (MP_OBJ_IS_SMALL_INT(arg)) {
84
85
86
87
88
89
        if (MP_OBJ_SMALL_INT_VALUE(arg) == 0) {
            return 0;
        } else {
            return 1;
        }
    } else {
90
91
92
        mp_obj_type_t *type = mp_obj_get_type(arg);
        if (type->unary_op != NULL) {
            mp_obj_t result = type->unary_op(RT_UNARY_OP_BOOL, arg);
93
            if (result != MP_OBJ_NULL) {
94
95
96
97
                return result == mp_const_true;
            }
        }

98
99
100
101
102
        mp_obj_t len = mp_obj_len_maybe(arg);
        if (len != MP_OBJ_NULL) {
            // obj has a length, truth determined if len != 0
            return len != MP_OBJ_NEW_SMALL_INT(0);
        } else {
103
            // any other obj is true per Python semantics
104
105
            return 1;
        }
106
107
108
109
110
111
112
113
    }
}

mp_obj_t rt_list_append(mp_obj_t self_in, mp_obj_t arg) {
    return mp_obj_list_append(self_in, arg);
}

mp_obj_t rt_load_const_dec(qstr qstr) {
Damien's avatar
Damien committed
114
    DEBUG_OP_printf("load '%s'\n", qstr_str(qstr));
115
116
    uint len;
    const byte* data = qstr_data(qstr, &len);
117
    return mp_parse_num_decimal((const char*)data, len, true, false);
Damien's avatar
Damien committed
118
119
}

120
mp_obj_t rt_load_const_str(qstr qstr) {
Damien's avatar
Damien committed
121
    DEBUG_OP_printf("load '%s'\n", qstr_str(qstr));
122
    return MP_OBJ_NEW_QSTR(qstr);
Damien's avatar
Damien committed
123
124
}

125
126
127
128
129
130
131
mp_obj_t rt_load_const_bytes(qstr qstr) {
    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);
}

132
mp_obj_t rt_load_name(qstr qstr) {
Damien's avatar
Damien committed
133
    // logic: search locals, globals, builtins
134
    DEBUG_OP_printf("load name %s\n", qstr_str(qstr));
135
    mp_map_elem_t *elem = mp_map_lookup(map_locals, MP_OBJ_NEW_QSTR(qstr), MP_MAP_LOOKUP);
136
137
138
139
    if (elem != NULL) {
        return elem->value;
    } else {
        return rt_load_global(qstr);
Damien's avatar
Damien committed
140
141
142
    }
}

143
mp_obj_t rt_load_global(qstr qstr) {
144
145
    // logic: search globals, builtins
    DEBUG_OP_printf("load global %s\n", qstr_str(qstr));
146
    mp_map_elem_t *elem = mp_map_lookup(map_globals, MP_OBJ_NEW_QSTR(qstr), MP_MAP_LOOKUP);
147
    if (elem == NULL) {
148
        elem = mp_map_lookup(&map_builtins, MP_OBJ_NEW_QSTR(qstr), MP_MAP_LOOKUP);
149
        if (elem == NULL) {
150
151
152
            mp_obj_t o = mp_builtin_tables_lookup_object(qstr);
            if (o != MP_OBJ_NULL) {
                return o;
153
            }
154
            nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_NameError, "name '%s' is not defined", qstr_str(qstr)));
155
156
157
        }
    }
    return elem->value;
Damien's avatar
Damien committed
158
159
}

160
mp_obj_t rt_load_build_class(void) {
Damien's avatar
Damien committed
161
    DEBUG_OP_printf("load_build_class\n");
162
    // lookup __build_class__ in dynamic table of builtins first
163
    mp_map_elem_t *elem = mp_map_lookup(&map_builtins, MP_OBJ_NEW_QSTR(MP_QSTR___build_class__), MP_MAP_LOOKUP);
164
    if (elem != NULL) {
165
        // found user-defined __build_class__, return it
166
167
        return elem->value;
    } else {
168
        // no user-defined __build_class__, return builtin one
169
        return (mp_obj_t)&mp_builtin___build_class___obj;
Damien's avatar
Damien committed
170
171
172
    }
}

173
174
mp_obj_t rt_get_cell(mp_obj_t cell) {
    return mp_obj_cell_get(cell);
175
176
}

177
178
void rt_set_cell(mp_obj_t cell, mp_obj_t val) {
    mp_obj_cell_set(cell, val);
179
180
}

181
void rt_store_name(qstr qstr, mp_obj_t obj) {
182
    DEBUG_OP_printf("store name %s <- %p\n", qstr_str(qstr), obj);
183
    mp_map_lookup(map_locals, MP_OBJ_NEW_QSTR(qstr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = obj;
184
185
}

186
187
188
189
190
void rt_delete_name(qstr qstr) {
    DEBUG_OP_printf("delete name %s\n", qstr_str(qstr));
    mp_map_lookup(map_locals, MP_OBJ_NEW_QSTR(qstr), MP_MAP_LOOKUP_REMOVE_IF_FOUND);
}

191
void rt_store_global(qstr qstr, mp_obj_t obj) {
192
    DEBUG_OP_printf("store global %s <- %p\n", qstr_str(qstr), obj);
193
    mp_map_lookup(map_globals, MP_OBJ_NEW_QSTR(qstr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = obj;
Damien's avatar
Damien committed
194
195
}

196
mp_obj_t rt_unary_op(int op, mp_obj_t arg) {
Damien's avatar
Damien committed
197
    DEBUG_OP_printf("unary %d %p\n", op, arg);
198

199
200
    if (MP_OBJ_IS_SMALL_INT(arg)) {
        mp_small_int_t val = MP_OBJ_SMALL_INT_VALUE(arg);
Damien's avatar
Damien committed
201
        switch (op) {
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
            case RT_UNARY_OP_BOOL:
                return MP_BOOL(val != 0);
            case RT_UNARY_OP_POSITIVE:
                return arg;
            case RT_UNARY_OP_NEGATIVE:
                // check for overflow
                if (val == MP_SMALL_INT_MIN) {
                    return mp_obj_new_int(-val);
                } else {
                    return MP_OBJ_NEW_SMALL_INT(-val);
                }
            case RT_UNARY_OP_INVERT:
                return MP_OBJ_NEW_SMALL_INT(~val);
            default:
                assert(0);
                return arg;
218
        }
219
220
221
222
    } 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);
223
224
225
            if (result != NULL) {
                return result;
            }
Damien's avatar
Damien committed
226
        }
227
        // TODO specify in error message what the operator is
Damien George's avatar
Damien George committed
228
        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
229
    }
Damien's avatar
Damien committed
230
231
}

232
mp_obj_t rt_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
Damien's avatar
Damien committed
233
    DEBUG_OP_printf("binary %d %p %p\n", op, lhs, rhs);
234
235
236
237
238
239
240
241
242
243

    // 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 +=

244
245
    // deal with is
    if (op == RT_BINARY_OP_IS) {
246
247
248
        return MP_BOOL(lhs == rhs);
    }

249
    // deal with == and != for all types
250
    if (op == RT_BINARY_OP_EQUAL || op == RT_BINARY_OP_NOT_EQUAL) {
251
        if (mp_obj_equal(lhs, rhs)) {
252
            if (op == RT_BINARY_OP_EQUAL) {
253
254
255
256
257
                return mp_const_true;
            } else {
                return mp_const_false;
            }
        } else {
258
            if (op == RT_BINARY_OP_EQUAL) {
259
260
261
262
263
264
265
266
                return mp_const_false;
            } else {
                return mp_const_true;
            }
        }
    }

    // deal with exception_match for all types
267
    if (op == RT_BINARY_OP_EXCEPTION_MATCH) {
268
269
270
271
272
273
        // 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);
            }
274
            if (mp_obj_is_subclass_fast(lhs, rhs)) {
275
276
277
278
279
                return mp_const_true;
            } else {
                return mp_const_false;
            }
        }
280
281
        assert(0);
        return mp_const_false;
282
283
    }

284
    if (MP_OBJ_IS_SMALL_INT(lhs)) {
285
        mp_small_int_t lhs_val = MP_OBJ_SMALL_INT_VALUE(lhs);
286
287
        if (MP_OBJ_IS_SMALL_INT(rhs)) {
            mp_small_int_t rhs_val = MP_OBJ_SMALL_INT_VALUE(rhs);
288
289
290
291
292
293
294
295
296
            // 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
297
298
299
300
301
302
303
304
            switch (op) {
                case RT_BINARY_OP_OR:
                case RT_BINARY_OP_INPLACE_OR: lhs_val |= rhs_val; break;
                case RT_BINARY_OP_XOR:
                case RT_BINARY_OP_INPLACE_XOR: lhs_val ^= rhs_val; break;
                case RT_BINARY_OP_AND:
                case RT_BINARY_OP_INPLACE_AND: lhs_val &= rhs_val; break;
                case RT_BINARY_OP_LSHIFT:
305
306
307
308
309
310
311
312
313
314
315
316
317
318
                case RT_BINARY_OP_INPLACE_LSHIFT: {
                    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;
                }
319
                case RT_BINARY_OP_RSHIFT:
320
321
322
323
324
325
326
327
328
                case RT_BINARY_OP_INPLACE_RSHIFT:
                    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;
329
330
331
332
333
                case RT_BINARY_OP_ADD:
                case RT_BINARY_OP_INPLACE_ADD: lhs_val += rhs_val; break;
                case RT_BINARY_OP_SUBTRACT:
                case RT_BINARY_OP_INPLACE_SUBTRACT: lhs_val -= rhs_val; break;
                case RT_BINARY_OP_MULTIPLY:
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
                case RT_BINARY_OP_INPLACE_MULTIPLY: {

                    // If long long type exists and is larger than machine_int_t, then
                    // we can use the following code to perform overflow-checked multiplication.
                    // Otherwise (eg in x64 case) we must use the branching code below.
                    #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

                    if (lhs_val > 0) { // lhs_val is positive
                        if (rhs_val > 0) { // lhs_val and rhs_val are positive
                            if (lhs_val > (MP_SMALL_INT_MAX / rhs_val)) {
                                goto mul_overflow;
                            }
                        } else { // lhs_val positive, rhs_val nonpositive
                            if (rhs_val < (MP_SMALL_INT_MIN / lhs_val)) {
                                goto mul_overflow;
                            }
                        } // lhs_val positive, rhs_val nonpositive
                    } else { // lhs_val is nonpositive
                        if (rhs_val > 0) { // lhs_val is nonpositive, rhs_val is positive
                            if (lhs_val < (MP_SMALL_INT_MIN / rhs_val)) {
                                goto mul_overflow;
                            }
                        } else { // lhs_val and rhs_val are nonpositive
                            if (lhs_val != 0 && rhs_val < (MP_SMALL_INT_MAX / lhs_val)) {
                                goto mul_overflow;
                            }
                        } // End if lhs_val and rhs_val are nonpositive
                    } // End if lhs_val is nonpositive

                    // use standard precision
                    return MP_OBJ_NEW_SMALL_INT(lhs_val * rhs_val);

                mul_overflow:
                    // use higher precision
                    lhs = mp_obj_new_int_from_ll(lhs_val);
                    goto generic_binary_op;

                    break;
                }
383
                case RT_BINARY_OP_FLOOR_DIVIDE:
384
385
386
387
388
                case RT_BINARY_OP_INPLACE_FLOOR_DIVIDE:
                {
                    lhs_val = python_floor_divide(lhs_val, rhs_val);
                    break;
                }
389
                #if MICROPY_ENABLE_FLOAT
390
391
                case RT_BINARY_OP_TRUE_DIVIDE:
                case RT_BINARY_OP_INPLACE_TRUE_DIVIDE: return mp_obj_new_float((mp_float_t)lhs_val / (mp_float_t)rhs_val);
392
                #endif
393
394

                case RT_BINARY_OP_MODULO:
395
396
397
398
399
                case RT_BINARY_OP_INPLACE_MODULO:
                {
                    lhs_val = python_modulo(lhs_val, rhs_val);
                    break;
                }
400
401
                case RT_BINARY_OP_POWER:
                case RT_BINARY_OP_INPLACE_POWER:
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
                    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 {
                        // TODO check for overflow
                        machine_int_t ans = 1;
                        while (rhs_val > 0) {
                            if (rhs_val & 1) {
                                ans *= lhs_val;
                            }
                            lhs_val *= lhs_val;
                            rhs_val /= 2;
418
                        }
419
                        lhs_val = ans;
420
                    }
421
                    break;
422
423
424
425
                case RT_BINARY_OP_LESS: return MP_BOOL(lhs_val < rhs_val); break;
                case RT_BINARY_OP_MORE: return MP_BOOL(lhs_val > rhs_val); break;
                case RT_BINARY_OP_LESS_EQUAL: return MP_BOOL(lhs_val <= rhs_val); break;
                case RT_BINARY_OP_MORE_EQUAL: return MP_BOOL(lhs_val >= rhs_val); break;
426

427
428
                default: assert(0);
            }
429
430
            // TODO: We just should make mp_obj_new_int() inline and use that
            if (MP_OBJ_FITS_SMALL_INT(lhs_val)) {
431
                return MP_OBJ_NEW_SMALL_INT(lhs_val);
432
433
            } else {
                return mp_obj_new_int(lhs_val);
434
            }
435
#if MICROPY_ENABLE_FLOAT
436
        } else if (MP_OBJ_IS_TYPE(rhs, &mp_type_float)) {
437
            return mp_obj_float_binary_op(op, lhs_val, rhs);
438
        } else if (MP_OBJ_IS_TYPE(rhs, &mp_type_complex)) {
439
            return mp_obj_complex_binary_op(op, lhs_val, 0, rhs);
440
#endif
441
        }
442
    }
443

444
    /* deal with `in`
445
446
     *
     * NOTE `a in b` is `b.__contains__(a)`, hence why the generic dispatch
Damien George's avatar
Damien George committed
447
     * needs to go below with swapped arguments
448
     */
449
    if (op == RT_BINARY_OP_IN) {
450
451
452
        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
453
            if (res != MP_OBJ_NULL) {
454
                return res;
John R. Lenton's avatar
John R. Lenton committed
455
            }
456
457
458
459
460
        }
        if (type->getiter != NULL) {
            /* second attempt, walk the iterator */
            mp_obj_t next = NULL;
            mp_obj_t iter = rt_getiter(rhs);
461
            while ((next = rt_iternext(iter)) != MP_OBJ_NULL) {
462
                if (mp_obj_equal(next, lhs)) {
463
                    return mp_const_true;
John R. Lenton's avatar
John R. Lenton committed
464
                }
465
            }
466
            return mp_const_false;
467
468
469
        }

        nlr_jump(mp_obj_new_exception_msg_varg(
470
                     &mp_type_TypeError, "'%s' object is not iterable",
471
472
473
474
                     mp_obj_get_type_str(rhs)));
        return mp_const_none;
    }

475
    // generic binary_op supplied by type
476
477
478
    mp_obj_type_t *type;
generic_binary_op:
    type = mp_obj_get_type(lhs);
479
480
481
482
    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
483
484
        }
    }
485

486
487
    // TODO implement dispatch for reverse binary ops

John R. Lenton's avatar
John R. Lenton committed
488
    // TODO specify in error message what the operator is
489
    nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
John R. Lenton's avatar
John R. Lenton committed
490
491
        "unsupported operand types for binary operator: '%s', '%s'",
        mp_obj_get_type_str(lhs), mp_obj_get_type_str(rhs)));
492
    return mp_const_none;
Damien's avatar
Damien committed
493
494
}

495
mp_obj_t rt_call_function_0(mp_obj_t fun) {
496
    return rt_call_function_n_kw(fun, 0, 0, NULL);
497
498
}

499
mp_obj_t rt_call_function_1(mp_obj_t fun, mp_obj_t arg) {
500
    return rt_call_function_n_kw(fun, 1, 0, &arg);
501
502
}

503
504
mp_obj_t rt_call_function_2(mp_obj_t fun, mp_obj_t arg1, mp_obj_t arg2) {
    mp_obj_t args[2];
505
506
507
    args[0] = arg1;
    args[1] = arg2;
    return rt_call_function_n_kw(fun, 2, 0, args);
508
509
}

510
511
512
513
514
515
// wrapper that accepts n_args and n_kw in one argument
// native emitter can only pass at most 3 arguments to a function
mp_obj_t rt_call_function_n_kw_for_native(mp_obj_t fun_in, uint n_args_kw, const mp_obj_t *args) {
    return rt_call_function_n_kw(fun_in, n_args_kw & 0xff, (n_args_kw >> 8) & 0xff, args);
}

516
517
// args contains, eg: arg0  arg1  key0  value0  key1  value1
mp_obj_t rt_call_function_n_kw(mp_obj_t fun_in, uint n_args, uint n_kw, const mp_obj_t *args) {
518
519
    // 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
520

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

523
524
525
526
527
528
    // 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);
529
    } else {
Damien George's avatar
Damien George committed
530
        nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not callable", mp_obj_get_type_str(fun_in)));
531
    }
532
533
}

534
535
// 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
536
mp_obj_t rt_call_method_n_kw(uint n_args, uint n_kw, const mp_obj_t *args) {
537
538
539
    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;
    return rt_call_function_n_kw(args[0], n_args + adjust, n_kw, args + 2 - adjust);
540
541
}

542
mp_obj_t rt_build_tuple(int n_args, mp_obj_t *items) {
543
    return mp_obj_new_tuple(n_args, items);
544
545
}

546
mp_obj_t rt_build_list(int n_args, mp_obj_t *items) {
547
    return mp_obj_new_list(n_args, items);
Damien's avatar
Damien committed
548
549
}

550
551
mp_obj_t rt_build_set(int n_args, mp_obj_t *items) {
    return mp_obj_new_set(n_args, items);
Damien's avatar
Damien committed
552
553
}

554
mp_obj_t rt_store_set(mp_obj_t set, mp_obj_t item) {
555
    mp_obj_set_store(set, item);
Damien's avatar
Damien committed
556
557
558
    return set;
}

559
// unpacked items are stored in reverse order into the array pointed to by items
560
void rt_unpack_sequence(mp_obj_t seq_in, uint num, mp_obj_t *items) {
561
    uint seq_len;
562
563
564
565
566
567
    if (MP_OBJ_IS_TYPE(seq_in, &tuple_type) || MP_OBJ_IS_TYPE(seq_in, &list_type)) {
        mp_obj_t *seq_items;
        if (MP_OBJ_IS_TYPE(seq_in, &tuple_type)) {
            mp_obj_tuple_get(seq_in, &seq_len, &seq_items);
        } else {
            mp_obj_list_get(seq_in, &seq_len, &seq_items);
568
        }
569
        if (seq_len < num) {
570
            goto too_short;
571
        } else if (seq_len > num) {
572
            goto too_long;
573
        }
574
575
576
        for (uint i = 0; i < num; i++) {
            items[i] = seq_items[num - 1 - i];
        }
577
    } else {
578
579
580
581
        mp_obj_t iterable = rt_getiter(seq_in);

        for (seq_len = 0; seq_len < num; seq_len++) {
            mp_obj_t el = rt_iternext(iterable);
582
            if (el == MP_OBJ_NULL) {
583
584
585
586
                goto too_short;
            }
            items[num - 1 - seq_len] = el;
        }
587
        if (rt_iternext(iterable) != MP_OBJ_NULL) {
588
589
            goto too_long;
        }
590
    }
591
592
593
    return;

too_short:
594
    nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "need more than %d values to unpack", seq_len));
595
too_long:
596
    nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "too many values to unpack (expected %d)", num));
597
598
}

599
600
mp_obj_t rt_build_map(int n_args) {
    return mp_obj_new_dict(n_args);
Damien's avatar
Damien committed
601
602
}

603
604
605
mp_obj_t rt_store_map(mp_obj_t map, mp_obj_t key, mp_obj_t value) {
    // map should always be a dict
    return mp_obj_dict_store(map, key, value);
Damien's avatar
Damien committed
606
607
}

608
mp_obj_t rt_load_attr(mp_obj_t base, qstr attr) {
609
610
611
612
    DEBUG_OP_printf("load attr %p.%s\n", base, qstr_str(attr));
    // use load_method
    mp_obj_t dest[2];
    rt_load_method(base, attr, dest);
613
    if (dest[1] == MP_OBJ_NULL) {
614
        // load_method returned just a normal attribute
615
        return dest[0];
616
617
618
    } 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
619
620
621
    }
}

622
623
624
// 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>
625
STATIC void rt_load_method_maybe(mp_obj_t base, qstr attr, mp_obj_t *dest) {
626
627
628
629
630
631
632
633
634
635
636
637
638
    // 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);

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

    // if nothing found yet, look for built-in and generic names
639
    if (dest[0] == MP_OBJ_NULL) {
Damien George's avatar
Damien George committed
640
641
642
643
        if (attr == MP_QSTR___class__) {
            // a.__class__ is equivalent to type(a)
            dest[0] = type;
        } else if (attr == MP_QSTR___next__ && type->iternext != NULL) {
644
645
            dest[0] = (mp_obj_t)&mp_builtin_next_obj;
            dest[1] = base;
646
647
        } else if (type->load_attr == NULL) {
            // generic method lookup if type didn't provide a specific one
648
            // this is a lookup in the object (ie not class or type)
649
650
651
652
653
654
655
656
657
658
659
660
661
662
            if (type->locals_dict != NULL) {
                assert(MP_OBJ_IS_TYPE(type->locals_dict, &dict_type)); // 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);
663
                    } else if (mp_obj_is_callable(elem->value)) {
664
                        // return a bound method, with self being this object
665
                        dest[0] = elem->value;
666
                        dest[1] = base;
667
668
669
                    } else {
                        // class member is a value, so just return that value
                        dest[0] = elem->value;
670
                    }
671
                }
Damien's avatar
Damien committed
672
673
            }
        }
674
    }
675
676
677
678
679
680
}

void rt_load_method(mp_obj_t base, qstr attr, mp_obj_t *dest) {
    DEBUG_OP_printf("load method %p.%s\n", base, qstr_str(attr));

    rt_load_method_maybe(base, attr, dest);
681

682
    if (dest[0] == MP_OBJ_NULL) {
683
684
        // no attribute/method called attr
        // following CPython, we give a more detailed error message for type objects
685
        if (MP_OBJ_IS_TYPE(base, &mp_type_type)) {
686
687
            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)));
688
        } else {
689
            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)));
690
691
        }
    }
692
693
}

694
void rt_store_attr(mp_obj_t base, qstr attr, mp_obj_t value) {
Damien's avatar
Damien committed
695
    DEBUG_OP_printf("store attr %p.%s <- %p\n", base, qstr_str(attr), value);
696
697
698
699
700
    mp_obj_type_t *type = mp_obj_get_type(base);
    if (type->store_attr != NULL) {
        if (type->store_attr(base, attr, value)) {
            return;
        }
701
    }
702
    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)));
703
704
}

705
void rt_store_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t value) {
Damien's avatar
Damien committed
706
    DEBUG_OP_printf("store subscr %p[%p] <- %p\n", base, index, value);
707
    if (MP_OBJ_IS_TYPE(base, &list_type)) {
708
        // list store
709
710
711
712
        mp_obj_list_store(base, index, value);
    } else if (MP_OBJ_IS_TYPE(base, &dict_type)) {
        // dict store
        mp_obj_dict_store(base, index, value);
Damien's avatar
Damien committed
713
    } else {
714
715
716
717
718
719
720
721
        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?
        }
722
        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
723
724
725
    }
}

726
mp_obj_t rt_getiter(mp_obj_t o_in) {
727
728
729
    mp_obj_type_t *type = mp_obj_get_type(o_in);
    if (type->getiter != NULL) {
        return type->getiter(o_in);
730
    } else {
731
        // check for __iter__ method
732
        mp_obj_t dest[2];
733
        rt_load_method_maybe(o_in, MP_QSTR___iter__, dest);
734
        if (dest[0] != MP_OBJ_NULL) {
735
736
            // __iter__ exists, call it and return its result
            return rt_call_method_n_kw(0, 0, dest);
737
        } else {
738
739
740
741
742
743
744
745
            rt_load_method_maybe(o_in, MP_QSTR___getitem__, dest);
            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)));
            }
746
        }
747
748
    }
}
749

750
751
752
// may return MP_OBJ_NULL as an optimisation instead of raise StopIteration()
// may also raise StopIteration()
mp_obj_t rt_iternext_allow_raise(mp_obj_t o_in) {
753
754
755
    mp_obj_type_t *type = mp_obj_get_type(o_in);
    if (type->iternext != NULL) {
        return type->iternext(o_in);
756
    } else {
757
758
759
760
761
762
763
764
765
        // check for __next__ method
        mp_obj_t dest[2];
        rt_load_method_maybe(o_in, MP_QSTR___next__, dest);
        if (dest[0] != MP_OBJ_NULL) {
            // __next__ exists, call it and return its result
            return rt_call_method_n_kw(0, 0, dest);
        } 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)));
        }
766
767
768
    }
}

769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
// will always return MP_OBJ_NULL instead of raising StopIteration() (or any subclass thereof)
// may raise other exceptions
mp_obj_t rt_iternext(mp_obj_t o_in) {
    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];
        rt_load_method_maybe(o_in, MP_QSTR___next__, dest);
        if (dest[0] != MP_OBJ_NULL) {
            // __next__ exists, call it and return its result
            nlr_buf_t nlr;
            if (nlr_push(&nlr) == 0) {
                mp_obj_t ret = rt_call_method_n_kw(0, 0, dest);
                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)));
        }
    }
}

799
800
801
802
803
mp_obj_t rt_make_raise_obj(mp_obj_t o) {
    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
804
805
        // TODO could have an option to disable traceback, then builtin exceptions (eg TypeError)
        // could have const instances in ROM which we return here instead
806
807
808
809
810
811
812
        return rt_call_function_n_kw(o, 0, 0, NULL);
    } 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");
813
814
815
    }
}

816
mp_obj_t rt_import_name(qstr name, mp_obj_t fromlist, mp_obj_t level) {
817
818
    DEBUG_printf("import name %s\n", qstr_str(name));

819
    // build args array
820
    mp_obj_t args[5];
821
    args[0] = MP_OBJ_NEW_QSTR(name);
822
823
    args[1] = mp_const_none; // TODO should be globals
    args[2] = mp_const_none; // TODO should be locals
824
825
826
827
    args[3] = fromlist;
    args[4] = level; // must be 0; we don't yet support other values

    // TODO lookup __import__ and call that instead of going straight to builtin implementation
828
    return mp_builtin___import__(5, args);
829
830
}

831
mp_obj_t rt_import_from(mp_obj_t module, qstr name) {
832
833
    DEBUG_printf("import from %p %s\n", module, qstr_str(name));

834
    mp_obj_t x = rt_load_attr(module, name);
835
836
837
838
839
840
841
842
    /* TODO convert AttributeError to ImportError
    if (fail) {
        (ImportError, "cannot import name %s", qstr_str(name), NULL)
    }
    */
    return x;
}

843
844
845
846
847
848
849
850
851
852
853
void rt_import_all(mp_obj_t module) {
    DEBUG_printf("import all %p\n", module);

    mp_map_t *map = mp_obj_module_get_globals(module);
    for (uint i = 0; i < map->alloc; i++) {
        if (map->table[i].key != MP_OBJ_NULL) {
            rt_store_name(MP_OBJ_QSTR_VALUE(map->table[i].key), map->table[i].value);
        }
    }
}

854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
mp_map_t *rt_locals_get(void) {
    return map_locals;
}

void rt_locals_set(mp_map_t *m) {
    DEBUG_OP_printf("rt_locals_set(%p)\n", m);
    map_locals = m;
}

mp_map_t *rt_globals_get(void) {
    return map_globals;
}

void rt_globals_set(mp_map_t *m) {
    DEBUG_OP_printf("rt_globals_set(%p)\n", m);
    map_globals = m;
}

872
// these must correspond to the respective enum
873
void *const rt_fun_table[RT_F_NUMBER_OF] = {
874
    rt_load_const_dec,
Damien's avatar
Damien committed
875
876
877
    rt_load_const_str,
    rt_load_name,
    rt_load_global,
878
    rt_load_build_class,
Damien's avatar
Damien committed
879
880
881
    rt_load_attr,
    rt_load_method,
    rt_store_name,
882
    rt_store_attr,
Damien's avatar
Damien committed
883
884
885
    rt_store_subscr,
    rt_is_true,
    rt_unary_op,
886
    rt_binary_op,
887
    rt_build_tuple,
Damien's avatar
Damien committed
888
    rt_build_list,
889
    rt_list_append,
Damien's avatar
Damien committed
890
891
892
    rt_build_map,
    rt_store_map,
    rt_build_set,
893
    rt_store_set,
Damien's avatar
Damien committed
894
    rt_make_function_from_id,
895
    rt_call_function_n_kw_for_native,
896
    rt_call_method_n_kw,
897
898
    rt_getiter,
    rt_iternext,
Damien's avatar
Damien committed
899
900
901
902
903
904
905
};

/*
void rt_f_vector(rt_fun_kind_t fun_kind) {
    (rt_f_table[fun_kind])();
}
*/