runtime.c 32.9 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__));
Damien George's avatar
Damien George committed
54

55
#if MICROPY_CPYTHON_COMPAT
56
    // Precreate sys module, so "import sys" didn't throw exceptions.
57
58
59
    mp_obj_t m_sys = mp_obj_new_module(MP_QSTR_sys);
    // Avoid warning of unused var
    (void)m_sys;
60
#endif
61
62
63
64
    // 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
65
66
}

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

74
75
int rt_is_true(mp_obj_t arg) {
    DEBUG_OP_printf("is true %p\n", arg);
76
77
78
79
80
81
82
    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)) {
83
84
85
86
87
88
        if (MP_OBJ_SMALL_INT_VALUE(arg) == 0) {
            return 0;
        } else {
            return 1;
        }
    } else {
89
90
91
        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);
92
            if (result != MP_OBJ_NULL) {
93
94
95
96
                return result == mp_const_true;
            }
        }

97
98
99
100
101
        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 {
102
            // any other obj is true per Python semantics
103
104
            return 1;
        }
105
106
107
108
109
110
111
112
    }
}

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
113
    DEBUG_OP_printf("load '%s'\n", qstr_str(qstr));
114
115
    uint len;
    const byte* data = qstr_data(qstr, &len);
116
    return mp_parse_num_decimal((const char*)data, len, true, false);
Damien's avatar
Damien committed
117
118
}

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

124
125
126
127
128
129
130
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);
}

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

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

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

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

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

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

185
186
187
188
189
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);
}

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

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

198
199
    if (MP_OBJ_IS_SMALL_INT(arg)) {
        mp_small_int_t val = MP_OBJ_SMALL_INT_VALUE(arg);
Damien's avatar
Damien committed
200
        switch (op) {
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
            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;
217
        }
218
219
220
221
    } 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);
222
223
224
            if (result != NULL) {
                return result;
            }
Damien's avatar
Damien committed
225
        }
226
        // TODO specify in error message what the operator is
Damien George's avatar
Damien George committed
227
        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
228
    }
Damien's avatar
Damien committed
229
230
}

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

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

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

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

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

283
    if (MP_OBJ_IS_SMALL_INT(lhs)) {
284
        mp_small_int_t lhs_val = MP_OBJ_SMALL_INT_VALUE(lhs);
285
286
        if (MP_OBJ_IS_SMALL_INT(rhs)) {
            mp_small_int_t rhs_val = MP_OBJ_SMALL_INT_VALUE(rhs);
287
288
289
290
291
292
293
294
295
            // 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
296
297
298
299
300
301
302
303
            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:
304
305
306
307
308
309
310
311
312
313
314
315
316
317
                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;
                }
318
                case RT_BINARY_OP_RSHIFT:
319
320
321
322
323
324
325
326
327
                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;
328
329
330
331
332
                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:
333
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
                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;
                }
382
                case RT_BINARY_OP_FLOOR_DIVIDE:
383
384
385
386
387
                case RT_BINARY_OP_INPLACE_FLOOR_DIVIDE:
                {
                    lhs_val = python_floor_divide(lhs_val, rhs_val);
                    break;
                }
388
                #if MICROPY_ENABLE_FLOAT
389
390
                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);
391
                #endif
392
393

                case RT_BINARY_OP_MODULO:
394
395
396
397
398
                case RT_BINARY_OP_INPLACE_MODULO:
                {
                    lhs_val = python_modulo(lhs_val, rhs_val);
                    break;
                }
399
400
                case RT_BINARY_OP_POWER:
                case RT_BINARY_OP_INPLACE_POWER:
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
                    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;
417
                        }
418
                        lhs_val = ans;
419
                    }
420
                    break;
421
422
423
424
                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;
425

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

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

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

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

485
486
    // TODO implement dispatch for reverse binary ops

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

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

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

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

509
510
511
512
513
514
// 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);
}

515
516
// 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) {
517
518
    // 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
519

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

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

533
534
// 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
535
mp_obj_t rt_call_method_n_kw(uint n_args, uint n_kw, const mp_obj_t *args) {
536
537
538
    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);
539
540
}

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

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

549
550
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
551
552
}

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

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

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

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

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

602
603
604
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
605
606
}

607
mp_obj_t rt_load_attr(mp_obj_t base, qstr attr) {
608
609
610
611
    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);
612
    if (dest[1] == MP_OBJ_NULL) {
613
        // load_method returned just a normal attribute
614
        return dest[0];
615
616
617
    } 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
618
619
620
    }
}

621
622
623
// 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>
624
STATIC void rt_load_method_maybe(mp_obj_t base, qstr attr, mp_obj_t *dest) {
625
626
627
628
629
630
631
632
633
634
635
636
637
    // 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
638
    if (dest[0] == MP_OBJ_NULL) {
Damien George's avatar
Damien George committed
639
640
641
642
        if (attr == MP_QSTR___class__) {
            // a.__class__ is equivalent to type(a)
            dest[0] = type;
        } else if (attr == MP_QSTR___next__ && type->iternext != NULL) {
643
644
            dest[0] = (mp_obj_t)&mp_builtin_next_obj;
            dest[1] = base;
645
646
        } else if (type->load_attr == NULL) {
            // generic method lookup if type didn't provide a specific one
647
            // this is a lookup in the object (ie not class or type)
648
            if (type->locals_dict != NULL) {
649
                assert(MP_OBJ_IS_TYPE(type->locals_dict, &mp_type_dict)); // Micro Python restriction, for now
650
651
652
653
654
655
656
657
658
659
660
661
                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);
662
                    } else if (mp_obj_is_callable(elem->value)) {
663
                        // return a bound method, with self being this object
664
                        dest[0] = elem->value;
665
                        dest[1] = base;
666
667
668
                    } else {
                        // class member is a value, so just return that value
                        dest[0] = elem->value;
669
                    }
670
                }
Damien's avatar
Damien committed
671
672
            }
        }
673
    }
674
675
676
677
678
679
}

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);
680

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

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

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

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

749
750
751
// 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) {
752
753
754
    mp_obj_type_t *type = mp_obj_get_type(o_in);
    if (type->iternext != NULL) {
        return type->iternext(o_in);
755
    } else {
756
757
758
759
760
761
762
763
764
        // 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)));
        }
765
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
// 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)));
        }
    }
}

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

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

818
    // build args array
819
    mp_obj_t args[5];
820
    args[0] = MP_OBJ_NEW_QSTR(name);
821
822
    args[1] = mp_const_none; // TODO should be globals
    args[2] = mp_const_none; // TODO should be locals
823
824
825
826
    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
827
    return mp_builtin___import__(5, args);
828
829
}

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

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

842
843
844
845
846
847
848
849
850
851
852
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);
        }
    }
}

853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
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;
}

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

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