runtime.c 37.2 KB
Newer Older
1
// in principle, rt_xxx functions are called only by vm/native/viper and make assumptions about args
2
// mp_xxx functions are safer and can be called by anyone
3
// note that rt_assign_xxx are called only from emit*, and maybe we can rename them to reflect this
4

Damien's avatar
Damien committed
5
6
7
8
9
10
#include <stdint.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>

11
#include "nlr.h"
Damien's avatar
Damien committed
12
#include "misc.h"
13
#include "mpconfig.h"
14
#include "qstr.h"
15
#include "obj.h"
16
#include "parsenum.h"
17
#include "runtime0.h"
Damien's avatar
Damien committed
18
#include "runtime.h"
19
20
#include "map.h"
#include "builtin.h"
21
#include "objarray.h"
22
#include "bc.h"
23

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

34
// locals and globals need to be pointers because they can be the same in outer module scope
35
36
37
38
STATIC mp_map_t *map_locals;
STATIC mp_map_t *map_globals;
STATIC mp_map_t map_builtins;
STATIC mp_map_t map_loaded_modules; // TODO: expose as sys.modules
39

Damien's avatar
Damien committed
40
typedef enum {
41
42
43
44
45
46
47
    MP_CODE_NONE,
    MP_CODE_BYTE,
    MP_CODE_NATIVE,
    MP_CODE_INLINE_ASM,
} mp_code_kind_t;

typedef struct _mp_code_t {
48
49
50
51
    mp_code_kind_t kind : 8;
    uint scope_flags : 8;
    uint n_args : 16;
    uint n_state : 16;
Damien's avatar
Damien committed
52
53
54
55
56
    union {
        struct {
            byte *code;
            uint len;
        } u_byte;
57
        struct {
58
            mp_fun_t fun;
59
60
        } u_native;
        struct {
61
            void *fun;
62
        } u_inline_asm;
Damien's avatar
Damien committed
63
    };
64
    qstr *arg_names;
65
} mp_code_t;
Damien's avatar
Damien committed
66

67
68
69
STATIC uint next_unique_code_id;
STATIC machine_uint_t unique_codes_alloc = 0;
STATIC mp_code_t *unique_codes = NULL;
Damien's avatar
Damien committed
70

71
72
#ifdef WRITE_CODE
FILE *fp_write_code = NULL;
73
#endif
Damien's avatar
Damien committed
74

75
76
77
78
79
80
81
82
83
84
85
// builtins
// we put this table in ROM because it's always needed and takes up quite a bit of room in RAM
// in fact, it uses less ROM here in table form than the equivalent in code form initialising a dynamic mp_map_t object in RAM
// at the moment it's a linear table, but we could convert it to a const mp_map_t table with a simple preprocessing script
// if we wanted to allow dynamic modification of the builtins, we could provide an mp_map_t object which is searched before this one

typedef struct _mp_builtin_elem_t {
    qstr qstr;
    mp_obj_t fun;
} mp_builtin_elem_t;

86
STATIC const mp_builtin_elem_t builtin_table[] = {
87
88
89
90
91
92
93
94
    // built-in core functions
    { MP_QSTR___build_class__, (mp_obj_t)&mp_builtin___build_class___obj },
    { MP_QSTR___import__, (mp_obj_t)&mp_builtin___import___obj },
    { MP_QSTR___repl_print__, (mp_obj_t)&mp_builtin___repl_print___obj },

    // built-in types
    { MP_QSTR_bool, (mp_obj_t)&bool_type },
#if MICROPY_ENABLE_FLOAT
95
    { MP_QSTR_complex, (mp_obj_t)&mp_type_complex },
96
97
98
99
100
#endif
    { MP_QSTR_dict, (mp_obj_t)&dict_type },
    { MP_QSTR_enumerate, (mp_obj_t)&enumerate_type },
    { MP_QSTR_filter, (mp_obj_t)&filter_type },
#if MICROPY_ENABLE_FLOAT
101
    { MP_QSTR_float, (mp_obj_t)&mp_type_float },
102
103
104
105
106
107
108
#endif
    { MP_QSTR_int, (mp_obj_t)&int_type },
    { MP_QSTR_list, (mp_obj_t)&list_type },
    { MP_QSTR_map, (mp_obj_t)&map_type },
    { MP_QSTR_set, (mp_obj_t)&set_type },
    { MP_QSTR_super, (mp_obj_t)&super_type },
    { MP_QSTR_tuple, (mp_obj_t)&tuple_type },
109
    { MP_QSTR_type, (mp_obj_t)&mp_type_type },
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
    { MP_QSTR_zip, (mp_obj_t)&zip_type },

    { MP_QSTR_classmethod, (mp_obj_t)&mp_type_classmethod },
    { MP_QSTR_staticmethod, (mp_obj_t)&mp_type_staticmethod },

    // built-in user functions
    { MP_QSTR_abs, (mp_obj_t)&mp_builtin_abs_obj },
    { MP_QSTR_all, (mp_obj_t)&mp_builtin_all_obj },
    { MP_QSTR_any, (mp_obj_t)&mp_builtin_any_obj },
    { MP_QSTR_bytes, (mp_obj_t)&mp_builtin_bytes_obj },
    { MP_QSTR_callable, (mp_obj_t)&mp_builtin_callable_obj },
    { MP_QSTR_chr, (mp_obj_t)&mp_builtin_chr_obj },
    { MP_QSTR_dir, (mp_obj_t)&mp_builtin_dir_obj },
    { MP_QSTR_divmod, (mp_obj_t)&mp_builtin_divmod_obj },
    { MP_QSTR_eval, (mp_obj_t)&mp_builtin_eval_obj },
    { MP_QSTR_exec, (mp_obj_t)&mp_builtin_exec_obj },
    { MP_QSTR_hash, (mp_obj_t)&mp_builtin_hash_obj },
    { MP_QSTR_id, (mp_obj_t)&mp_builtin_id_obj },
    { MP_QSTR_isinstance, (mp_obj_t)&mp_builtin_isinstance_obj },
    { MP_QSTR_issubclass, (mp_obj_t)&mp_builtin_issubclass_obj },
    { MP_QSTR_iter, (mp_obj_t)&mp_builtin_iter_obj },
    { MP_QSTR_len, (mp_obj_t)&mp_builtin_len_obj },
    { MP_QSTR_max, (mp_obj_t)&mp_builtin_max_obj },
    { MP_QSTR_min, (mp_obj_t)&mp_builtin_min_obj },
    { MP_QSTR_next, (mp_obj_t)&mp_builtin_next_obj },
    { MP_QSTR_ord, (mp_obj_t)&mp_builtin_ord_obj },
    { MP_QSTR_pow, (mp_obj_t)&mp_builtin_pow_obj },
    { MP_QSTR_print, (mp_obj_t)&mp_builtin_print_obj },
    { MP_QSTR_range, (mp_obj_t)&mp_builtin_range_obj },
    { MP_QSTR_repr, (mp_obj_t)&mp_builtin_repr_obj },
    { MP_QSTR_sorted, (mp_obj_t)&mp_builtin_sorted_obj },
    { MP_QSTR_sum, (mp_obj_t)&mp_builtin_sum_obj },
    { MP_QSTR_str, (mp_obj_t)&mp_builtin_str_obj },
    { MP_QSTR_bytearray, (mp_obj_t)&mp_builtin_bytearray_obj },

145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
    // built-in exceptions
    { MP_QSTR_BaseException, (mp_obj_t)&mp_type_BaseException },
    { MP_QSTR_AssertionError, (mp_obj_t)&mp_type_AssertionError },
    { MP_QSTR_AttributeError, (mp_obj_t)&mp_type_AttributeError },
    { MP_QSTR_ImportError, (mp_obj_t)&mp_type_ImportError },
    { MP_QSTR_IndentationError, (mp_obj_t)&mp_type_IndentationError },
    { MP_QSTR_IndexError, (mp_obj_t)&mp_type_IndexError },
    { MP_QSTR_KeyError, (mp_obj_t)&mp_type_KeyError },
    { MP_QSTR_NameError, (mp_obj_t)&mp_type_NameError },
    { MP_QSTR_SyntaxError, (mp_obj_t)&mp_type_SyntaxError },
    { MP_QSTR_TypeError, (mp_obj_t)&mp_type_TypeError },
    { MP_QSTR_ValueError, (mp_obj_t)&mp_type_ValueError },
    // Somehow CPython managed to have OverflowError not inherit from ValueError ;-/
    // TODO: For MICROPY_CPYTHON_COMPAT==0 use ValueError to avoid exc proliferation
    { MP_QSTR_OverflowError, (mp_obj_t)&mp_type_OverflowError },
    { MP_QSTR_OSError, (mp_obj_t)&mp_type_OSError },
    { MP_QSTR_NotImplementedError, (mp_obj_t)&mp_type_NotImplementedError },
    { MP_QSTR_StopIteration, (mp_obj_t)&mp_type_StopIteration },

164
165
166
    // Extra builtins as defined by a port
    MICROPY_EXTRA_BUILTINS

167
168
169
    { MP_QSTR_, MP_OBJ_NULL }, // end of list sentinel
};

170
// a good optimising compiler will inline this if necessary
171
STATIC void mp_map_add_qstr(mp_map_t *map, qstr qstr, mp_obj_t value) {
172
173
174
    mp_map_lookup(map, MP_OBJ_NEW_QSTR(qstr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = value;
}

175
void rt_init(void) {
176
    // locals = globals for outer module (see Objects/frameobject.c/PyFrame_New())
177
    map_locals = map_globals = mp_map_new(1);
178
    mp_map_add_qstr(map_globals, MP_QSTR___name__, MP_OBJ_NEW_QSTR(MP_QSTR___main__));
179

180
    // init built-in hash table
181
    mp_map_init(&map_builtins, 3);
182

183
184
185
    // init loaded modules table
    mp_map_init(&map_loaded_modules, 3);

Damien George's avatar
Damien George committed
186
    // built-in objects
187
    mp_map_add_qstr(&map_builtins, MP_QSTR_Ellipsis, mp_const_ellipsis);
Damien George's avatar
Damien George committed
188

189
190
191
    mp_obj_t m_array = mp_obj_new_module(MP_QSTR_array);
    rt_store_attr(m_array, MP_QSTR_array, (mp_obj_t)&array_type);

192
193
194
    mp_obj_t m_collections = mp_obj_new_module(MP_QSTR_collections);
    rt_store_attr(m_collections, MP_QSTR_namedtuple, (mp_obj_t)&mp_namedtuple_obj);

195
#if MICROPY_CPYTHON_COMPAT
196
    // Precreate sys module, so "import sys" didn't throw exceptions.
197
198
199
    mp_obj_t m_sys = mp_obj_new_module(MP_QSTR_sys);
    // Avoid warning of unused var
    (void)m_sys;
200
#endif
201
202
203
204
    // 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);
205

206
207
208
    // we pre-import the micropython module
    // probably shouldn't do this, so we are compatible with CPython
    rt_store_name(MP_QSTR_micropython, (mp_obj_t)&mp_module_micropython);
209

210
    // TODO: wastes one mp_code_t structure in mem
211
    next_unique_code_id = 1; // 0 indicates "no code"
212
    unique_codes_alloc = 0;
Damien's avatar
Damien committed
213
214
    unique_codes = NULL;

215
216
#ifdef WRITE_CODE
    fp_write_code = fopen("out-code", "wb");
217
#endif
Damien's avatar
Damien committed
218
219
}

220
void rt_deinit(void) {
221
    m_del(mp_code_t, unique_codes, unique_codes_alloc);
222
223
224
    mp_map_free(map_globals);
    mp_map_deinit(&map_loaded_modules);
    mp_map_deinit(&map_builtins);
225
226
227
#ifdef WRITE_CODE
    if (fp_write_code != NULL) {
        fclose(fp_write_code);
Damien's avatar
Damien committed
228
    }
229
#endif
Damien's avatar
Damien committed
230
231
}

232
uint rt_get_unique_code_id(void) {
233
    return next_unique_code_id++;
Damien's avatar
Damien committed
234
235
}

236
STATIC void alloc_unique_codes(void) {
237
    if (next_unique_code_id > unique_codes_alloc) {
238
        DEBUG_printf("allocate more unique codes: " UINT_FMT " -> %u\n", unique_codes_alloc, next_unique_code_id);
239
240
        // increase size of unique_codes table
        unique_codes = m_renew(mp_code_t, unique_codes, unique_codes_alloc, next_unique_code_id);
241
        for (uint i = unique_codes_alloc; i < next_unique_code_id; i++) {
242
            unique_codes[i].kind = MP_CODE_NONE;
243
        }
244
        unique_codes_alloc = next_unique_code_id;
Damien's avatar
Damien committed
245
    }
246
247
}

248
void rt_assign_byte_code(uint unique_code_id, byte *code, uint len, int n_args, int n_locals, int n_stack, uint scope_flags, qstr *arg_names) {
249
250
    alloc_unique_codes();

251
    assert(1 <= unique_code_id && unique_code_id < next_unique_code_id && unique_codes[unique_code_id].kind == MP_CODE_NONE);
252
    unique_codes[unique_code_id].kind = MP_CODE_BYTE;
253
    unique_codes[unique_code_id].scope_flags = scope_flags;
254
255
    unique_codes[unique_code_id].n_args = n_args;
    unique_codes[unique_code_id].n_state = n_locals + n_stack;
256
257
    unique_codes[unique_code_id].u_byte.code = code;
    unique_codes[unique_code_id].u_byte.len = len;
258
    unique_codes[unique_code_id].arg_names = arg_names;
259

Damien's avatar
Damien committed
260
    //printf("byte code: %d bytes\n", len);
261
262

#ifdef DEBUG_PRINT
263
    DEBUG_printf("assign byte code: id=%d code=%p len=%u n_args=%d n_locals=%d n_stack=%d\n", unique_code_id, code, len, n_args, n_locals, n_stack);
264
265
266
267
268
269
270
    for (int i = 0; i < 128 && i < len; i++) {
        if (i > 0 && i % 16 == 0) {
            DEBUG_printf("\n");
        }
        DEBUG_printf(" %02x", code[i]);
    }
    DEBUG_printf("\n");
271
272
#if MICROPY_DEBUG_PRINTERS
    mp_byte_code_print(code, len);
273
#endif
274
#endif
275
276
}

277
void rt_assign_native_code(uint unique_code_id, void *fun, uint len, int n_args) {
278
279
    alloc_unique_codes();

280
    assert(1 <= unique_code_id && unique_code_id < next_unique_code_id && unique_codes[unique_code_id].kind == MP_CODE_NONE);
281
    unique_codes[unique_code_id].kind = MP_CODE_NATIVE;
282
    unique_codes[unique_code_id].scope_flags = 0;
283
284
    unique_codes[unique_code_id].n_args = n_args;
    unique_codes[unique_code_id].n_state = 0;
Damien's avatar
Damien committed
285
286
    unique_codes[unique_code_id].u_native.fun = fun;

287
    //printf("native code: %d bytes\n", len);
288

289
#ifdef DEBUG_PRINT
Damien's avatar
Damien committed
290
291
292
293
294
295
296
297
298
299
    DEBUG_printf("assign native code: id=%d fun=%p len=%u n_args=%d\n", unique_code_id, fun, len, n_args);
    byte *fun_data = (byte*)(((machine_uint_t)fun) & (~1)); // need to clear lower bit in case it's thumb code
    for (int i = 0; i < 128 && i < len; i++) {
        if (i > 0 && i % 16 == 0) {
            DEBUG_printf("\n");
        }
        DEBUG_printf(" %02x", fun_data[i]);
    }
    DEBUG_printf("\n");

300
301
302
303
#ifdef WRITE_CODE
    if (fp_write_code != NULL) {
        fwrite(fun_data, len, 1, fp_write_code);
        fflush(fp_write_code);
Damien's avatar
Damien committed
304
    }
305
306
#endif
#endif
Damien's avatar
Damien committed
307
308
}

309
void rt_assign_inline_asm_code(uint unique_code_id, void *fun, uint len, int n_args) {
310
311
    alloc_unique_codes();

312
    assert(1 <= unique_code_id && unique_code_id < next_unique_code_id && unique_codes[unique_code_id].kind == MP_CODE_NONE);
313
    unique_codes[unique_code_id].kind = MP_CODE_INLINE_ASM;
314
    unique_codes[unique_code_id].scope_flags = 0;
315
316
    unique_codes[unique_code_id].n_args = n_args;
    unique_codes[unique_code_id].n_state = 0;
317
    unique_codes[unique_code_id].u_inline_asm.fun = fun;
Damien's avatar
Damien committed
318

319
#ifdef DEBUG_PRINT
320
321
322
323
324
325
326
327
328
329
    DEBUG_printf("assign inline asm code: id=%d fun=%p len=%u n_args=%d\n", unique_code_id, fun, len, n_args);
    byte *fun_data = (byte*)(((machine_uint_t)fun) & (~1)); // need to clear lower bit in case it's thumb code
    for (int i = 0; i < 128 && i < len; i++) {
        if (i > 0 && i % 16 == 0) {
            DEBUG_printf("\n");
        }
        DEBUG_printf(" %02x", fun_data[i]);
    }
    DEBUG_printf("\n");

330
331
332
#ifdef WRITE_CODE
    if (fp_write_code != NULL) {
        fwrite(fun_data, len, 1, fp_write_code);
333
    }
334
335
#endif
#endif
Damien's avatar
Damien committed
336
337
}

338
339
int rt_is_true(mp_obj_t arg) {
    DEBUG_OP_printf("is true %p\n", arg);
340
341
342
343
344
345
346
    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)) {
347
348
349
350
351
352
        if (MP_OBJ_SMALL_INT_VALUE(arg) == 0) {
            return 0;
        } else {
            return 1;
        }
    } else {
353
354
355
        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);
356
            if (result != MP_OBJ_NULL) {
357
358
359
360
                return result == mp_const_true;
            }
        }

361
362
363
364
365
        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 {
366
            // any other obj is true per Python semantics
367
368
            return 1;
        }
369
370
371
372
373
374
375
376
    }
}

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
377
    DEBUG_OP_printf("load '%s'\n", qstr_str(qstr));
378
379
380
    uint len;
    const byte* data = qstr_data(qstr, &len);
    return mp_parse_num_decimal((const char*)data, len);
Damien's avatar
Damien committed
381
382
}

383
mp_obj_t rt_load_const_str(qstr qstr) {
Damien's avatar
Damien committed
384
    DEBUG_OP_printf("load '%s'\n", qstr_str(qstr));
385
    return MP_OBJ_NEW_QSTR(qstr);
Damien's avatar
Damien committed
386
387
}

388
389
390
391
392
393
394
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);
}

395
mp_obj_t rt_load_name(qstr qstr) {
Damien's avatar
Damien committed
396
    // logic: search locals, globals, builtins
397
    DEBUG_OP_printf("load name %s\n", qstr_str(qstr));
398
    mp_map_elem_t *elem = mp_map_lookup(map_locals, MP_OBJ_NEW_QSTR(qstr), MP_MAP_LOOKUP);
399
400
401
402
    if (elem != NULL) {
        return elem->value;
    } else {
        return rt_load_global(qstr);
Damien's avatar
Damien committed
403
404
405
    }
}

406
mp_obj_t rt_load_global(qstr qstr) {
407
408
    // logic: search globals, builtins
    DEBUG_OP_printf("load global %s\n", qstr_str(qstr));
409
    mp_map_elem_t *elem = mp_map_lookup(map_globals, MP_OBJ_NEW_QSTR(qstr), MP_MAP_LOOKUP);
410
    if (elem == NULL) {
411
        elem = mp_map_lookup(&map_builtins, MP_OBJ_NEW_QSTR(qstr), MP_MAP_LOOKUP);
412
        if (elem == NULL) {
413
414
415
416
417
            for (const mp_builtin_elem_t *e = &builtin_table[0]; e->qstr != MP_QSTR_; e++) {
                if (e->qstr == qstr) {
                    return e->fun;
                }
            }
418
            nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_NameError, "name '%s' is not defined", qstr_str(qstr)));
419
420
421
        }
    }
    return elem->value;
Damien's avatar
Damien committed
422
423
}

424
mp_obj_t rt_load_build_class(void) {
Damien's avatar
Damien committed
425
    DEBUG_OP_printf("load_build_class\n");
426
    mp_map_elem_t *elem = mp_map_lookup(&map_builtins, MP_OBJ_NEW_QSTR(MP_QSTR___build_class__), MP_MAP_LOOKUP);
427
428
429
430
    if (elem != NULL) {
        return elem->value;
    } else {
        return (mp_obj_t)&mp_builtin___build_class___obj;
Damien's avatar
Damien committed
431
432
433
    }
}

434
435
mp_obj_t rt_get_cell(mp_obj_t cell) {
    return mp_obj_cell_get(cell);
436
437
}

438
439
void rt_set_cell(mp_obj_t cell, mp_obj_t val) {
    mp_obj_cell_set(cell, val);
440
441
}

442
void rt_store_name(qstr qstr, mp_obj_t obj) {
443
    DEBUG_OP_printf("store name %s <- %p\n", qstr_str(qstr), obj);
444
    mp_map_lookup(map_locals, MP_OBJ_NEW_QSTR(qstr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = obj;
445
446
}

447
void rt_store_global(qstr qstr, mp_obj_t obj) {
448
    DEBUG_OP_printf("store global %s <- %p\n", qstr_str(qstr), obj);
449
    mp_map_lookup(map_globals, MP_OBJ_NEW_QSTR(qstr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND)->value = obj;
Damien's avatar
Damien committed
450
451
}

452
mp_obj_t rt_unary_op(int op, mp_obj_t arg) {
Damien's avatar
Damien committed
453
    DEBUG_OP_printf("unary %d %p\n", op, arg);
454

455
456
    if (MP_OBJ_IS_SMALL_INT(arg)) {
        mp_small_int_t val = MP_OBJ_SMALL_INT_VALUE(arg);
Damien's avatar
Damien committed
457
        switch (op) {
458
            case RT_UNARY_OP_BOOL: return MP_BOOL(val != 0);
Damien's avatar
Damien committed
459
460
461
462
463
            case RT_UNARY_OP_POSITIVE: break;
            case RT_UNARY_OP_NEGATIVE: val = -val; break;
            case RT_UNARY_OP_INVERT: val = ~val; break;
            default: assert(0); val = 0;
        }
464
        if (MP_OBJ_FITS_SMALL_INT(val)) {
465
466
            return MP_OBJ_NEW_SMALL_INT(val);
        }
467
        return mp_obj_new_int(val);
468
469
470
471
    } 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);
472
473
474
            if (result != NULL) {
                return result;
            }
Damien's avatar
Damien committed
475
        }
476
        // TODO specify in error message what the operator is
477
        nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "bad operand type for unary operator: '%s'", type->name));
Damien's avatar
Damien committed
478
    }
Damien's avatar
Damien committed
479
480
}

481
mp_obj_t rt_binary_op(int op, mp_obj_t lhs, mp_obj_t rhs) {
Damien's avatar
Damien committed
482
    DEBUG_OP_printf("binary %d %p %p\n", op, lhs, rhs);
483
484
485
486
487
488
489
490
491
492

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

493
494
    // deal with is
    if (op == RT_BINARY_OP_IS) {
495
496
497
        return MP_BOOL(lhs == rhs);
    }

498
    // deal with == and != for all types
499
    if (op == RT_BINARY_OP_EQUAL || op == RT_BINARY_OP_NOT_EQUAL) {
500
        if (mp_obj_equal(lhs, rhs)) {
501
            if (op == RT_BINARY_OP_EQUAL) {
502
503
504
505
506
                return mp_const_true;
            } else {
                return mp_const_false;
            }
        } else {
507
            if (op == RT_BINARY_OP_EQUAL) {
508
509
510
511
512
513
514
515
                return mp_const_false;
            } else {
                return mp_const_true;
            }
        }
    }

    // deal with exception_match for all types
516
    if (op == RT_BINARY_OP_EXCEPTION_MATCH) {
517
518
519
520
521
522
        // 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);
            }
523
            if (mp_obj_is_subclass_fast(lhs, rhs)) {
524
525
526
527
528
529
530
                return mp_const_true;
            } else {
                return mp_const_false;
            }
        }
    }

531
    if (MP_OBJ_IS_SMALL_INT(lhs)) {
532
        mp_small_int_t lhs_val = MP_OBJ_SMALL_INT_VALUE(lhs);
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
        if (MP_OBJ_IS_SMALL_INT(rhs)) {
            mp_small_int_t rhs_val = MP_OBJ_SMALL_INT_VALUE(rhs);
            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:
                case RT_BINARY_OP_INPLACE_LSHIFT: lhs_val <<= rhs_val; break;
                case RT_BINARY_OP_RSHIFT:
                case RT_BINARY_OP_INPLACE_RSHIFT: lhs_val >>= rhs_val; break;
                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:
                case RT_BINARY_OP_INPLACE_MULTIPLY: lhs_val *= rhs_val; break;
                case RT_BINARY_OP_FLOOR_DIVIDE:
                case RT_BINARY_OP_INPLACE_FLOOR_DIVIDE: lhs_val /= rhs_val; break;
    #if MICROPY_ENABLE_FLOAT
                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);
    #endif

                // TODO implement modulo as specified by Python
                case RT_BINARY_OP_MODULO:
                case RT_BINARY_OP_INPLACE_MODULO: lhs_val %= rhs_val; break;

                // TODO check for negative power, and overflow
                case RT_BINARY_OP_POWER:
                case RT_BINARY_OP_INPLACE_POWER:
                {
                    int ans = 1;
                    while (rhs_val > 0) {
                        if (rhs_val & 1) {
                            ans *= lhs_val;
                        }
                        lhs_val *= lhs_val;
                        rhs_val /= 2;
574
                    }
575
576
                    lhs_val = ans;
                    break;
577
                }
578
579
580
581
                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;
582

583
584
                default: assert(0);
            }
585
586
            // TODO: We just should make mp_obj_new_int() inline and use that
            if (MP_OBJ_FITS_SMALL_INT(lhs_val)) {
587
588
                return MP_OBJ_NEW_SMALL_INT(lhs_val);
            }
589
            return mp_obj_new_int(lhs_val);
590
#if MICROPY_ENABLE_FLOAT
591
        } else if (MP_OBJ_IS_TYPE(rhs, &mp_type_float)) {
592
            return mp_obj_float_binary_op(op, lhs_val, rhs);
593
        } else if (MP_OBJ_IS_TYPE(rhs, &mp_type_complex)) {
594
            return mp_obj_complex_binary_op(op, lhs_val, 0, rhs);
595
#endif
596
        }
597
    }
598

599
    /* deal with `in`
600
601
     *
     * NOTE `a in b` is `b.__contains__(a)`, hence why the generic dispatch
Damien George's avatar
Damien George committed
602
     * needs to go below with swapped arguments
603
     */
604
    if (op == RT_BINARY_OP_IN) {
605
606
607
        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
608
            if (res != MP_OBJ_NULL) {
609
                return res;
John R. Lenton's avatar
John R. Lenton committed
610
            }
611
612
613
614
615
616
617
        }
        if (type->getiter != NULL) {
            /* second attempt, walk the iterator */
            mp_obj_t next = NULL;
            mp_obj_t iter = rt_getiter(rhs);
            while ((next = rt_iternext(iter)) != mp_const_stop_iteration) {
                if (mp_obj_equal(next, lhs)) {
618
                    return mp_const_true;
John R. Lenton's avatar
John R. Lenton committed
619
                }
620
            }
621
            return mp_const_false;
622
623
624
        }

        nlr_jump(mp_obj_new_exception_msg_varg(
625
                     &mp_type_TypeError, "'%s' object is not iterable",
626
627
628
629
                     mp_obj_get_type_str(rhs)));
        return mp_const_none;
    }

630
631
632
633
634
635
    // generic binary_op supplied by type
    mp_obj_type_t *type = mp_obj_get_type(lhs);
    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
636
637
        }
    }
638

639
640
    // TODO implement dispatch for reverse binary ops

John R. Lenton's avatar
John R. Lenton committed
641
    // TODO specify in error message what the operator is
642
    nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError,
John R. Lenton's avatar
John R. Lenton committed
643
644
        "unsupported operand types for binary operator: '%s', '%s'",
        mp_obj_get_type_str(lhs), mp_obj_get_type_str(rhs)));
645
    return mp_const_none;
Damien's avatar
Damien committed
646
647
}

648
mp_obj_t rt_make_function_from_id(int unique_code_id, mp_obj_t def_args) {
649
650
    DEBUG_OP_printf("make_function_from_id %d\n", unique_code_id);
    if (unique_code_id < 1 || unique_code_id >= next_unique_code_id) {
Damien's avatar
Damien committed
651
        // illegal code id
652
        return mp_const_none;
Damien's avatar
Damien committed
653
    }
654
655
656
657

    // make the function, depending on the code kind
    mp_code_t *c = &unique_codes[unique_code_id];
    mp_obj_t fun;
Damien's avatar
Damien committed
658
    switch (c->kind) {
659
        case MP_CODE_BYTE:
660
            fun = mp_obj_new_fun_bc(c->scope_flags, c->arg_names, c->n_args, def_args, c->n_state, c->u_byte.code);
661
            break;
662
        case MP_CODE_NATIVE:
663
            fun = rt_make_function_n(c->n_args, c->u_native.fun);
Damien's avatar
Damien committed
664
            break;
665
666
        case MP_CODE_INLINE_ASM:
            fun = mp_obj_new_fun_asm(c->n_args, c->u_inline_asm.fun);
Damien's avatar
Damien committed
667
668
669
            break;
        default:
            assert(0);
670
            fun = mp_const_none;
Damien's avatar
Damien committed
671
    }
672
673

    // check for generator functions and if so wrap in generator object
674
    if ((c->scope_flags & MP_SCOPE_FLAG_GENERATOR) != 0) {
675
        fun = mp_obj_new_gen_wrap(fun);
676
677
    }

678
    return fun;
Damien's avatar
Damien committed
679
680
}

681
mp_obj_t rt_make_closure_from_id(int unique_code_id, mp_obj_t closure_tuple) {
Damien George's avatar
Damien George committed
682
    DEBUG_OP_printf("make_closure_from_id %d\n", unique_code_id);
683
    // make function object
684
    mp_obj_t ffun = rt_make_function_from_id(unique_code_id, MP_OBJ_NULL);
Damien's avatar
Damien committed
685
    // wrap function in closure object
686
    return mp_obj_new_closure(ffun, closure_tuple);
Damien's avatar
Damien committed
687
688
}

689
mp_obj_t rt_call_function_0(mp_obj_t fun) {
690
    return rt_call_function_n_kw(fun, 0, 0, NULL);
691
692
}

693
mp_obj_t rt_call_function_1(mp_obj_t fun, mp_obj_t arg) {
694
    return rt_call_function_n_kw(fun, 1, 0, &arg);
695
696
}

697
698
mp_obj_t rt_call_function_2(mp_obj_t fun, mp_obj_t arg1, mp_obj_t arg2) {
    mp_obj_t args[2];
699
700
701
    args[0] = arg1;
    args[1] = arg2;
    return rt_call_function_n_kw(fun, 2, 0, args);
702
703
}

704
705
706
707
708
709
// 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);
}

710
711
// 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) {
712
713
    // 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
714

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

717
718
719
720
721
722
    // 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);
723
    } else {
724
        nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_TypeError, "'%s' object is not callable", type->name));
725
    }
726
727
}

728
729
// 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
730
mp_obj_t rt_call_method_n_kw(uint n_args, uint n_kw, const mp_obj_t *args) {
731
732
733
    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);
734
735
}

736
mp_obj_t rt_build_tuple(int n_args, mp_obj_t *items) {
737
    return mp_obj_new_tuple(n_args, items);
738
739
}

740
mp_obj_t rt_build_list(int n_args, mp_obj_t *items) {
741
    return mp_obj_new_list(n_args, items);
Damien's avatar
Damien committed
742
743
}

744
745
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
746
747
}

748
mp_obj_t rt_store_set(mp_obj_t set, mp_obj_t item) {
749
    mp_obj_set_store(set, item);
Damien's avatar
Damien committed
750
751
752
    return set;
}

753
// unpacked items are stored in reverse order into the array pointed to by items
754
void rt_unpack_sequence(mp_obj_t seq_in, uint num, mp_obj_t *items) {
755
    uint seq_len;
756
757
758
759
760
761
    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);
762
        }
763
        if (seq_len < num) {
764
            goto too_short;
765
        } else if (seq_len > num) {
766
            goto too_long;
767
        }
768
769
770
        for (uint i = 0; i < num; i++) {
            items[i] = seq_items[num - 1 - i];
        }
771
    } else {
772
773
774
775
776
777
778
779
780
781
782
783
        mp_obj_t iterable = rt_getiter(seq_in);

        for (seq_len = 0; seq_len < num; seq_len++) {
            mp_obj_t el = rt_iternext(iterable);
            if (el == mp_const_stop_iteration) {
                goto too_short;
            }
            items[num - 1 - seq_len] = el;
        }
        if (rt_iternext(iterable) != mp_const_stop_iteration) {
            goto too_long;
        }
784
    }
785
786
787
    return;

too_short:
788
    nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "need more than %d values to unpack", seq_len));
789
too_long:
790
    nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_ValueError, "too many values to unpack (expected %d)", num));
791
792
}

793
794
mp_obj_t rt_build_map(int n_args) {
    return mp_obj_new_dict(n_args);
Damien's avatar
Damien committed
795
796
}

797
798
799
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
800
801
}

802
mp_obj_t rt_load_attr(mp_obj_t base, qstr attr) {
803
804
805
806
    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);
807
    if (dest[1] == MP_OBJ_NULL) {
808
        // load_method returned just a normal attribute
809
        return dest[0];
810
811
812
    } 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
813
814
815
    }
}

816
817
818
// 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>
819
STATIC void rt_load_method_maybe(mp_obj_t base, qstr attr, mp_obj_t *dest) {
820
821
822
823
824
825
826
827
828
829
830
831
832
    // 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
833
    if (dest[0] == MP_OBJ_NULL) {
Damien George's avatar
Damien George committed
834
835
836
837
        if (attr == MP_QSTR___class__) {
            // a.__class__ is equivalent to type(a)
            dest[0] = type;
        } else if (attr == MP_QSTR___next__ && type->iternext != NULL) {
838
839
            dest[0] = (mp_obj_t)&mp_builtin_next_obj;
            dest[1] = base;
840
841
        } else if (type->load_attr == NULL) {
            // generic method lookup if type didn't provide a specific one
842
            // this is a lookup in the object (ie not class or type)
843
844
845
846
            const mp_method_t *meth = type->methods;
            if (meth != NULL) {
                for (; meth->name != NULL; meth++) {
                    if (strcmp(meth->name, qstr_str(attr)) == 0) {
847
848
849
850
                        // 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(meth->fun, &mp_type_staticmethod)) {
                            // return just the function
851
                            dest[0] = ((mp_obj_static_class_method_t*)meth->fun)->fun;
852
853
                        } else if (MP_OBJ_IS_TYPE(meth->fun, &mp_type_classmethod)) {
                            // return a bound method, with self being the type of this object
854
                            dest[0] = ((mp_obj_static_class_method_t*)meth->fun)->fun;
855
                            dest[1] = mp_obj_get_type(base);
856
857
                        } else {
                            // return a bound method, with self being this object
858
859
                            dest[0] = (mp_obj_t)meth->fun;
                            dest[1] = base;
860
                        }
861
862
                        break;
                    }
863
                }
Damien's avatar
Damien committed
864
865
            }
        }
866
    }
867
868
869
870
871
872
}

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

874
    if (dest[0] == MP_OBJ_NULL) {
875
876
        // no attribute/method called attr
        // following CPython, we give a more detailed error message for type objects
877
878
        if (MP_OBJ_IS_TYPE(base, &mp_type_type)) {
            nlr_jump(mp_obj_new_exception_msg_varg(&mp_type_AttributeError, "type object '%s' has no attribute '%s'", ((mp_obj_type_t*)base)->name, qstr_str(attr)));
879
        } else {
880
            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)));
881
882
        }
    }
883
884
}

885
void rt_store_attr(mp_obj_t base, qstr attr, mp_obj_t value) {
Damien's avatar
Damien committed
886
    DEBUG_OP_printf("store attr %p.%s <- %p\n", base, qstr_str(attr), value);
887
888
889
890
891
    mp_obj_type_t *type = mp_obj_get_type(base);
    if (type->store_attr != NULL) {
        if (type->store_attr(base, attr, value)) {
            return;
        }
892
    }
893
    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)));
894
895
}

896
void rt_store_subscr(mp_obj_t base, mp_obj_t index, mp_obj_t value) {
Damien's avatar
Damien committed
897
    DEBUG_OP_printf("store subscr %p[%p] <- %p\n", base, index, value);
898
    if (MP_OBJ_IS_TYPE(base, &list_type)) {
899
        // list store
900
901
902
903
        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
904
    } else {
905
906
907
908
909
910
911
912
        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?
        }
913
        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
914
915
916
    }
}

917
mp_obj_t rt_getiter(mp_obj_t o_in) {
918
919
920
    mp_obj_type_t *type = mp_obj_get_type(o_in);
    if (type->getiter != NULL) {
        return type->getiter(o_in);
921
    } else {
922
923
        // check for __getitem__ method
        mp_obj_t dest[2];
924
        rt_load_method_maybe(o_in, MP_QSTR___getitem__, dest);
925
926
927
928
929
        if (dest[0] != MP_OBJ_NULL) {
            // __getitem__ exists, create an iterator
            return mp_obj_new_getitem_iter(dest);
        } else {
            // object not iterable