compile.c 126 KB
Newer Older
xbe's avatar
xbe committed
1
#include <stdbool.h>
Damien's avatar
Damien committed
2
3
4
5
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
6
#include <math.h>
Damien's avatar
Damien committed
7
8

#include "misc.h"
9
#include "mpconfig.h"
10
#include "qstr.h"
Damien's avatar
Damien committed
11
12
13
#include "lexer.h"
#include "parse.h"
#include "scope.h"
14
#include "runtime0.h"
Damien's avatar
Damien committed
15
#include "emit.h"
16
17
18
#include "obj.h"
#include "compile.h"
#include "runtime.h"
19
#include "intdivmod.h"
Damien's avatar
Damien committed
20
21
22

// TODO need to mangle __attr names

23
24
#define MICROPY_EMIT_NATIVE (MICROPY_EMIT_X64 || MICROPY_EMIT_THUMB)

Damien's avatar
Damien committed
25
26
typedef enum {
    PN_none = 0,
27
#define DEF_RULE(rule, comp, kind, ...) PN_##rule,
Damien's avatar
Damien committed
28
29
30
31
32
#include "grammar.h"
#undef DEF_RULE
    PN_maximum_number_of,
} pn_kind_t;

33
34
35
36
#define EMIT(fun) (comp->emit_method_table->fun(comp->emit))
#define EMIT_ARG(fun, ...) (comp->emit_method_table->fun(comp->emit, __VA_ARGS__))
#define EMIT_INLINE_ASM(fun) (comp->emit_inline_asm_method_table->fun(comp->emit_inline_asm))
#define EMIT_INLINE_ASM_ARG(fun, ...) (comp->emit_inline_asm_method_table->fun(comp->emit_inline_asm, __VA_ARGS__))
Damien's avatar
Damien committed
37

38
39
40
#define EMIT_OPT_NONE           (0)
#define EMIT_OPT_BYTE_CODE      (1)
#define EMIT_OPT_NATIVE_PYTHON  (2)
Damien's avatar
Damien committed
41
42
#define EMIT_OPT_VIPER          (3)
#define EMIT_OPT_ASM_THUMB      (4)
43

Damien's avatar
Damien committed
44
typedef struct _compiler_t {
45
    qstr source_file;
Damien's avatar
Damien committed
46
    bool is_repl;
Damien's avatar
Damien committed
47
    pass_kind_t pass;
Damien's avatar
Damien committed
48
    bool had_error; // try to keep compiler clean from nlr
Damien's avatar
Damien committed
49

50
51
    int next_label;

Damien's avatar
Damien committed
52
53
    int break_label;
    int continue_label;
54
55
    int break_continue_except_level;
    int cur_except_level; // increased for SETUP_EXCEPT, SETUP_FINALLY; decreased for POP_BLOCK, POP_EXCEPT
Damien's avatar
Damien committed
56
57
58
59
60
61
62
63
64

    int n_arg_keyword;
    bool have_star_arg;
    bool have_dbl_star_arg;
    bool have_bare_star;
    int param_pass;
    int param_pass_num_dict_params;
    int param_pass_num_default_params;

Damien George's avatar
Damien George committed
65
66
    bool func_arg_is_super; // used to compile special case of super() function call

Damien's avatar
Damien committed
67
68
69
    scope_t *scope_head;
    scope_t *scope_cur;

70
71
    emit_t *emit;                                   // current emitter
    const emit_method_table_t *emit_method_table;   // current emit method table
72
73
74

    emit_inline_asm_t *emit_inline_asm;                                   // current emitter for inline asm
    const emit_inline_asm_method_table_t *emit_inline_asm_method_table;   // current emit method table for inline asm
Damien's avatar
Damien committed
75
76
} compiler_t;

77
78
79
80
81
82
STATIC void compile_syntax_error(compiler_t *comp, const char *msg) {
    // TODO store the error message to a variable in compiler_t instead of printing it
    printf("SyntaxError: %s\n", msg);
    comp->had_error = true;
}

83
84
85
86
mp_parse_node_t fold_constants(mp_parse_node_t pn) {
    if (MP_PARSE_NODE_IS_STRUCT(pn)) {
        mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
        int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
Damien's avatar
Damien committed
87
88
89
90
91
92

        // fold arguments first
        for (int i = 0; i < n; i++) {
            pns->nodes[i] = fold_constants(pns->nodes[i]);
        }

93
        switch (MP_PARSE_NODE_STRUCT_KIND(pns)) {
Damien's avatar
Damien committed
94
            case PN_shift_expr:
95
                if (n == 3 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[2])) {
96
97
                    int arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
                    int arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
98
                    if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_DBL_LESS)) {
99
#if MICROPY_EMIT_CPYTHON
100
                        // can overflow; enabled only to compare with CPython
101
                        pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 << arg1);
102
#endif
103
104
                    } else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_DBL_MORE)) {
                        pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 >> arg1);
Damien's avatar
Damien committed
105
106
107
108
109
110
111
112
                    } else {
                        // shouldn't happen
                        assert(0);
                    }
                }
                break;

            case PN_arith_expr:
113
                // overflow checking here relies on SMALL_INT being strictly smaller than machine_int_t
114
                if (n == 3 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[2])) {
115
116
                    machine_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
                    machine_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
117
                    machine_int_t res;
118
                    if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_PLUS)) {
119
                        res = arg0 + arg1;
120
                    } else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_MINUS)) {
121
                        res = arg0 - arg1;
Damien's avatar
Damien committed
122
123
124
                    } else {
                        // shouldn't happen
                        assert(0);
125
126
                        res = 0;
                    }
127
                    if (MP_PARSE_FITS_SMALL_INT(res)) {
128
                        pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, res);
Damien's avatar
Damien committed
129
130
131
132
133
                    }
                }
                break;

            case PN_term:
134
                if (n == 3 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[2])) {
135
136
                    int arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
                    int arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
137
                    if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_STAR)) {
138
#if MICROPY_EMIT_CPYTHON
139
                        // can overflow; enabled only to compare with CPython
140
                        pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 * arg1);
141
#endif
142
                    } else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_SLASH)) {
Damien's avatar
Damien committed
143
                        ; // pass
144
                    } else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_PERCENT)) {
145
                        pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, python_modulo(arg0, arg1));
146
                    } else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_DBL_SLASH)) {
147
148
149
150
151
                        //pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, 
                          //                          floor((mp_float_t)arg0 / arg1));
                        pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, 
                                                    python_floor_divide(arg0, arg1));
			
Damien's avatar
Damien committed
152
153
154
155
156
157
158
159
                    } else {
                        // shouldn't happen
                        assert(0);
                    }
                }
                break;

            case PN_factor_2:
160
                if (MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[1])) {
161
                    machine_int_t arg = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[1]);
162
163
164
165
166
167
                    if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[0], MP_TOKEN_OP_PLUS)) {
                        pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg);
                    } else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[0], MP_TOKEN_OP_MINUS)) {
                        pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, -arg);
                    } else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[0], MP_TOKEN_OP_TILDE)) {
                        pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, ~arg);
Damien's avatar
Damien committed
168
169
170
171
172
173
174
                    } else {
                        // shouldn't happen
                        assert(0);
                    }
                }
                break;

175
#if MICROPY_EMIT_CPYTHON
Damien's avatar
Damien committed
176
            case PN_power:
177
                // can overflow; enabled only to compare with CPython
178
179
180
                if (MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_NULL(pns->nodes[1]) && !MP_PARSE_NODE_IS_NULL(pns->nodes[2])) {
                    mp_parse_node_struct_t* pns2 = (mp_parse_node_struct_t*)pns->nodes[2];
                    if (MP_PARSE_NODE_IS_SMALL_INT(pns2->nodes[0])) {
181
                        int power = MP_PARSE_NODE_LEAF_SMALL_INT(pns2->nodes[0]);
Damien's avatar
Damien committed
182
183
                        if (power >= 0) {
                            int ans = 1;
184
                            int base = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
Damien's avatar
Damien committed
185
186
187
                            for (; power > 0; power--) {
                                ans *= base;
                            }
188
                            pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, ans);
Damien's avatar
Damien committed
189
190
191
192
                        }
                    }
                }
                break;
193
#endif
Damien's avatar
Damien committed
194
195
196
197
198
199
        }
    }

    return pn;
}

200
STATIC void compile_trailer_paren_helper(compiler_t *comp, mp_parse_node_t pn_arglist, bool is_method_call, int n_positional_extra);
201
void compile_node(compiler_t *comp, mp_parse_node_t pn);
Damien's avatar
Damien committed
202

203
STATIC int comp_next_label(compiler_t *comp) {
204
205
206
    return comp->next_label++;
}

207
STATIC scope_t *scope_new_and_link(compiler_t *comp, scope_kind_t kind, mp_parse_node_t pn, uint emit_options) {
208
    scope_t *scope = scope_new(kind, pn, comp->source_file, rt_get_unique_code_id(), emit_options);
Damien's avatar
Damien committed
209
210
211
212
213
214
215
216
217
218
219
220
221
222
    scope->parent = comp->scope_cur;
    scope->next = NULL;
    if (comp->scope_head == NULL) {
        comp->scope_head = scope;
    } else {
        scope_t *s = comp->scope_head;
        while (s->next != NULL) {
            s = s->next;
        }
        s->next = scope;
    }
    return scope;
}

223
STATIC int list_len(mp_parse_node_t pn, int pn_kind) {
224
    if (MP_PARSE_NODE_IS_NULL(pn)) {
Damien's avatar
Damien committed
225
        return 0;
226
    } else if (MP_PARSE_NODE_IS_LEAF(pn)) {
Damien's avatar
Damien committed
227
228
        return 1;
    } else {
229
230
        mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
        if (MP_PARSE_NODE_STRUCT_KIND(pns) != pn_kind) {
Damien's avatar
Damien committed
231
232
            return 1;
        } else {
233
            return MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
Damien's avatar
Damien committed
234
235
236
237
        }
    }
}

238
STATIC void apply_to_single_or_list(compiler_t *comp, mp_parse_node_t pn, int pn_list_kind, void (*f)(compiler_t*, mp_parse_node_t)) {
239
240
241
    if (MP_PARSE_NODE_IS_STRUCT(pn) && MP_PARSE_NODE_STRUCT_KIND((mp_parse_node_struct_t*)pn) == pn_list_kind) {
        mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
        int num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
Damien's avatar
Damien committed
242
243
244
        for (int i = 0; i < num_nodes; i++) {
            f(comp, pns->nodes[i]);
        }
245
    } else if (!MP_PARSE_NODE_IS_NULL(pn)) {
Damien's avatar
Damien committed
246
247
248
249
        f(comp, pn);
    }
}

250
STATIC int list_get(mp_parse_node_t *pn, int pn_kind, mp_parse_node_t **nodes) {
251
    if (MP_PARSE_NODE_IS_NULL(*pn)) {
Damien's avatar
Damien committed
252
253
        *nodes = NULL;
        return 0;
254
    } else if (MP_PARSE_NODE_IS_LEAF(*pn)) {
Damien's avatar
Damien committed
255
256
257
        *nodes = pn;
        return 1;
    } else {
258
259
        mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)(*pn);
        if (MP_PARSE_NODE_STRUCT_KIND(pns) != pn_kind) {
Damien's avatar
Damien committed
260
261
262
263
            *nodes = pn;
            return 1;
        } else {
            *nodes = pns->nodes;
264
            return MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
Damien's avatar
Damien committed
265
266
267
268
        }
    }
}

269
void compile_do_nothing(compiler_t *comp, mp_parse_node_struct_t *pns) {
Damien's avatar
Damien committed
270
271
}

272
273
void compile_generic_all_nodes(compiler_t *comp, mp_parse_node_struct_t *pns) {
    int num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
Damien's avatar
Damien committed
274
275
276
277
278
    for (int i = 0; i < num_nodes; i++) {
        compile_node(comp, pns->nodes[i]);
    }
}

279
#if MICROPY_EMIT_CPYTHON
280
STATIC bool cpython_c_tuple_is_const(mp_parse_node_t pn) {
281
    if (!MP_PARSE_NODE_IS_LEAF(pn)) {
Damien's avatar
Damien committed
282
283
        return false;
    }
284
    if (MP_PARSE_NODE_IS_ID(pn)) {
Damien's avatar
Damien committed
285
286
287
288
289
        return false;
    }
    return true;
}

290
STATIC void cpython_c_print_quoted_str(vstr_t *vstr, qstr qstr, bool bytes) {
291
292
    uint len;
    const byte *str = qstr_data(qstr, &len);
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
    bool has_single_quote = false;
    bool has_double_quote = false;
    for (int i = 0; i < len; i++) {
        if (str[i] == '\'') {
            has_single_quote = true;
        } else if (str[i] == '"') {
            has_double_quote = true;
        }
    }
    if (bytes) {
        vstr_printf(vstr, "b");
    }
    bool quote_single = false;
    if (has_single_quote && !has_double_quote) {
        vstr_printf(vstr, "\"");
    } else {
        quote_single = true;
        vstr_printf(vstr, "'");
    }
    for (int i = 0; i < len; i++) {
        if (str[i] == '\n') {
            vstr_printf(vstr, "\\n");
        } else if (str[i] == '\\') {
            vstr_printf(vstr, "\\\\");
        } else if (str[i] == '\'' && quote_single) {
            vstr_printf(vstr, "\\'");
        } else {
            vstr_printf(vstr, "%c", str[i]);
        }
    }
    if (has_single_quote && !has_double_quote) {
        vstr_printf(vstr, "\"");
    } else {
        vstr_printf(vstr, "'");
    }
}

330
STATIC void cpython_c_tuple_emit_const(compiler_t *comp, mp_parse_node_t pn, vstr_t *vstr) {
331
    assert(MP_PARSE_NODE_IS_LEAF(pn));
332
333
334
335
336
    if (MP_PARSE_NODE_IS_SMALL_INT(pn)) {
        vstr_printf(vstr, INT_FMT, MP_PARSE_NODE_LEAF_SMALL_INT(pn));
        return;
    }

337
338
339
340
341
342
343
344
    int arg = MP_PARSE_NODE_LEAF_ARG(pn);
    switch (MP_PARSE_NODE_LEAF_KIND(pn)) {
        case MP_PARSE_NODE_ID: assert(0);
        case MP_PARSE_NODE_INTEGER: vstr_printf(vstr, "%s", qstr_str(arg)); break;
        case MP_PARSE_NODE_DECIMAL: vstr_printf(vstr, "%s", qstr_str(arg)); break;
        case MP_PARSE_NODE_STRING: cpython_c_print_quoted_str(vstr, arg, false); break;
        case MP_PARSE_NODE_BYTES: cpython_c_print_quoted_str(vstr, arg, true); break;
        case MP_PARSE_NODE_TOKEN:
Damien's avatar
Damien committed
345
            switch (arg) {
346
347
348
                case MP_TOKEN_KW_FALSE: vstr_printf(vstr, "False"); break;
                case MP_TOKEN_KW_NONE: vstr_printf(vstr, "None"); break;
                case MP_TOKEN_KW_TRUE: vstr_printf(vstr, "True"); break;
Damien's avatar
Damien committed
349
350
351
352
353
354
355
                default: assert(0);
            }
            break;
        default: assert(0);
    }
}

356
STATIC void cpython_c_tuple(compiler_t *comp, mp_parse_node_t pn, mp_parse_node_struct_t *pns_list) {
Damien's avatar
Damien committed
357
358
    int n = 0;
    if (pns_list != NULL) {
359
        n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns_list);
Damien's avatar
Damien committed
360
361
362
    }
    int total = n;
    bool is_const = true;
363
    if (!MP_PARSE_NODE_IS_NULL(pn)) {
Damien's avatar
Damien committed
364
        total += 1;
365
        if (!cpython_c_tuple_is_const(pn)) {
Damien's avatar
Damien committed
366
367
368
369
            is_const = false;
        }
    }
    for (int i = 0; i < n; i++) {
370
        if (!cpython_c_tuple_is_const(pns_list->nodes[i])) {
Damien's avatar
Damien committed
371
372
373
374
375
376
            is_const = false;
            break;
        }
    }
    if (total > 0 && is_const) {
        bool need_comma = false;
377
378
        vstr_t *vstr = vstr_new();
        vstr_printf(vstr, "(");
379
        if (!MP_PARSE_NODE_IS_NULL(pn)) {
380
            cpython_c_tuple_emit_const(comp, pn, vstr);
Damien's avatar
Damien committed
381
382
383
384
            need_comma = true;
        }
        for (int i = 0; i < n; i++) {
            if (need_comma) {
385
                vstr_printf(vstr, ", ");
Damien's avatar
Damien committed
386
            }
387
            cpython_c_tuple_emit_const(comp, pns_list->nodes[i], vstr);
Damien's avatar
Damien committed
388
389
390
            need_comma = true;
        }
        if (total == 1) {
391
            vstr_printf(vstr, ",)");
Damien's avatar
Damien committed
392
        } else {
393
            vstr_printf(vstr, ")");
Damien's avatar
Damien committed
394
        }
395
        EMIT_ARG(load_const_verbatim_str, vstr_str(vstr));
396
        vstr_free(vstr);
Damien's avatar
Damien committed
397
    } else {
398
        if (!MP_PARSE_NODE_IS_NULL(pn)) {
Damien's avatar
Damien committed
399
400
401
402
403
            compile_node(comp, pn);
        }
        for (int i = 0; i < n; i++) {
            compile_node(comp, pns_list->nodes[i]);
        }
404
        EMIT_ARG(build_tuple, total);
Damien's avatar
Damien committed
405
406
    }
}
407
408
409
#endif

// funnelling all tuple creations through this function is purely so we can optionally agree with CPython
410
void c_tuple(compiler_t *comp, mp_parse_node_t pn, mp_parse_node_struct_t *pns_list) {
411
#if MICROPY_EMIT_CPYTHON
412
413
414
    cpython_c_tuple(comp, pn, pns_list);
#else
    int total = 0;
415
    if (!MP_PARSE_NODE_IS_NULL(pn)) {
416
417
418
419
        compile_node(comp, pn);
        total += 1;
    }
    if (pns_list != NULL) {
420
        int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns_list);
421
422
423
424
425
        for (int i = 0; i < n; i++) {
            compile_node(comp, pns_list->nodes[i]);
        }
        total += n;
    }
426
    EMIT_ARG(build_tuple, total);
427
428
#endif
}
Damien's avatar
Damien committed
429

430
void compile_generic_tuple(compiler_t *comp, mp_parse_node_struct_t *pns) {
Damien's avatar
Damien committed
431
    // a simple tuple expression
432
    c_tuple(comp, MP_PARSE_NODE_NULL, pns);
Damien's avatar
Damien committed
433
434
}

435
STATIC bool node_is_const_false(mp_parse_node_t pn) {
436
    return MP_PARSE_NODE_IS_TOKEN_KIND(pn, MP_TOKEN_KW_FALSE);
437
    // untested: || (MP_PARSE_NODE_IS_SMALL_INT(pn) && MP_PARSE_NODE_LEAF_SMALL_INT(pn) == 0);
Damien's avatar
Damien committed
438
439
}

440
STATIC bool node_is_const_true(mp_parse_node_t pn) {
441
    return MP_PARSE_NODE_IS_TOKEN_KIND(pn, MP_TOKEN_KW_TRUE) || (MP_PARSE_NODE_IS_SMALL_INT(pn) && MP_PARSE_NODE_LEAF_SMALL_INT(pn) == 1);
Damien's avatar
Damien committed
442
443
}

444
#if MICROPY_EMIT_CPYTHON
445
// the is_nested variable is purely to match with CPython, which doesn't fully optimise not's
446
STATIC void cpython_c_if_cond(compiler_t *comp, mp_parse_node_t pn, bool jump_if, int label, bool is_nested) {
Damien's avatar
Damien committed
447
448
    if (node_is_const_false(pn)) {
        if (jump_if == false) {
449
            EMIT_ARG(jump, label);
Damien's avatar
Damien committed
450
451
452
453
        }
        return;
    } else if (node_is_const_true(pn)) {
        if (jump_if == true) {
454
            EMIT_ARG(jump, label);
Damien's avatar
Damien committed
455
456
        }
        return;
457
458
459
460
    } else if (MP_PARSE_NODE_IS_STRUCT(pn)) {
        mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
        int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
        if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_or_test) {
Damien's avatar
Damien committed
461
            if (jump_if == false) {
462
                int label2 = comp_next_label(comp);
Damien's avatar
Damien committed
463
                for (int i = 0; i < n - 1; i++) {
464
                    cpython_c_if_cond(comp, pns->nodes[i], true, label2, true);
Damien's avatar
Damien committed
465
                }
466
                cpython_c_if_cond(comp, pns->nodes[n - 1], false, label, true);
467
                EMIT_ARG(label_assign, label2);
Damien's avatar
Damien committed
468
469
            } else {
                for (int i = 0; i < n; i++) {
470
                    cpython_c_if_cond(comp, pns->nodes[i], true, label, true);
Damien's avatar
Damien committed
471
472
473
                }
            }
            return;
474
        } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_and_test) {
Damien's avatar
Damien committed
475
476
            if (jump_if == false) {
                for (int i = 0; i < n; i++) {
477
                    cpython_c_if_cond(comp, pns->nodes[i], false, label, true);
Damien's avatar
Damien committed
478
479
                }
            } else {
480
                int label2 = comp_next_label(comp);
Damien's avatar
Damien committed
481
                for (int i = 0; i < n - 1; i++) {
482
                    cpython_c_if_cond(comp, pns->nodes[i], false, label2, true);
Damien's avatar
Damien committed
483
                }
484
                cpython_c_if_cond(comp, pns->nodes[n - 1], true, label, true);
485
                EMIT_ARG(label_assign, label2);
Damien's avatar
Damien committed
486
487
            }
            return;
488
        } else if (!is_nested && MP_PARSE_NODE_STRUCT_KIND(pns) == PN_not_test_2) {
489
            cpython_c_if_cond(comp, pns->nodes[0], !jump_if, label, true);
Damien's avatar
Damien committed
490
491
492
493
494
495
496
            return;
        }
    }

    // nothing special, fall back to default compiling for node and jump
    compile_node(comp, pn);
    if (jump_if == false) {
497
        EMIT_ARG(pop_jump_if_false, label);
Damien's avatar
Damien committed
498
    } else {
499
        EMIT_ARG(pop_jump_if_true, label);
Damien's avatar
Damien committed
500
501
    }
}
502
#endif
Damien's avatar
Damien committed
503

504
STATIC void c_if_cond(compiler_t *comp, mp_parse_node_t pn, bool jump_if, int label) {
505
#if MICROPY_EMIT_CPYTHON
506
507
508
509
    cpython_c_if_cond(comp, pn, jump_if, label, false);
#else
    if (node_is_const_false(pn)) {
        if (jump_if == false) {
510
            EMIT_ARG(jump, label);
511
512
513
514
        }
        return;
    } else if (node_is_const_true(pn)) {
        if (jump_if == true) {
515
            EMIT_ARG(jump, label);
516
517
        }
        return;
518
519
520
521
    } else if (MP_PARSE_NODE_IS_STRUCT(pn)) {
        mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
        int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
        if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_or_test) {
522
523
524
525
526
527
            if (jump_if == false) {
                int label2 = comp_next_label(comp);
                for (int i = 0; i < n - 1; i++) {
                    c_if_cond(comp, pns->nodes[i], true, label2);
                }
                c_if_cond(comp, pns->nodes[n - 1], false, label);
528
                EMIT_ARG(label_assign, label2);
529
530
531
532
533
534
            } else {
                for (int i = 0; i < n; i++) {
                    c_if_cond(comp, pns->nodes[i], true, label);
                }
            }
            return;
535
        } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_and_test) {
536
537
538
539
540
541
542
543
544
545
            if (jump_if == false) {
                for (int i = 0; i < n; i++) {
                    c_if_cond(comp, pns->nodes[i], false, label);
                }
            } else {
                int label2 = comp_next_label(comp);
                for (int i = 0; i < n - 1; i++) {
                    c_if_cond(comp, pns->nodes[i], false, label2);
                }
                c_if_cond(comp, pns->nodes[n - 1], true, label);
546
                EMIT_ARG(label_assign, label2);
547
548
            }
            return;
549
        } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_not_test_2) {
550
551
552
553
554
555
556
557
            c_if_cond(comp, pns->nodes[0], !jump_if, label);
            return;
        }
    }

    // nothing special, fall back to default compiling for node and jump
    compile_node(comp, pn);
    if (jump_if == false) {
558
        EMIT_ARG(pop_jump_if_false, label);
559
    } else {
560
        EMIT_ARG(pop_jump_if_true, label);
561
562
    }
#endif
Damien's avatar
Damien committed
563
564
565
}

typedef enum { ASSIGN_STORE, ASSIGN_AUG_LOAD, ASSIGN_AUG_STORE } assign_kind_t;
566
void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t kind);
Damien's avatar
Damien committed
567

568
void c_assign_power(compiler_t *comp, mp_parse_node_struct_t *pns, assign_kind_t assign_kind) {
Damien's avatar
Damien committed
569
570
571
572
    if (assign_kind != ASSIGN_AUG_STORE) {
        compile_node(comp, pns->nodes[0]);
    }

573
574
575
576
    if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) {
        mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t*)pns->nodes[1];
        if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_power_trailers) {
            int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns1);
Damien's avatar
Damien committed
577
578
579
580
581
            if (assign_kind != ASSIGN_AUG_STORE) {
                for (int i = 0; i < n - 1; i++) {
                    compile_node(comp, pns1->nodes[i]);
                }
            }
582
583
            assert(MP_PARSE_NODE_IS_STRUCT(pns1->nodes[n - 1]));
            pns1 = (mp_parse_node_struct_t*)pns1->nodes[n - 1];
Damien's avatar
Damien committed
584
        }
585
        if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_trailer_paren) {
586
            compile_syntax_error(comp, "can't assign to function call");
Damien's avatar
Damien committed
587
            return;
588
        } else if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_trailer_bracket) {
Damien's avatar
Damien committed
589
590
591
592
593
594
595
            if (assign_kind == ASSIGN_AUG_STORE) {
                EMIT(rot_three);
                EMIT(store_subscr);
            } else {
                compile_node(comp, pns1->nodes[0]);
                if (assign_kind == ASSIGN_AUG_LOAD) {
                    EMIT(dup_top_two);
596
                    EMIT_ARG(binary_op, RT_BINARY_OP_SUBSCR);
Damien's avatar
Damien committed
597
598
599
600
                } else {
                    EMIT(store_subscr);
                }
            }
601
602
        } else if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_trailer_period) {
            assert(MP_PARSE_NODE_IS_ID(pns1->nodes[0]));
Damien's avatar
Damien committed
603
604
            if (assign_kind == ASSIGN_AUG_LOAD) {
                EMIT(dup_top);
605
                EMIT_ARG(load_attr, MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0]));
Damien's avatar
Damien committed
606
607
608
609
            } else {
                if (assign_kind == ASSIGN_AUG_STORE) {
                    EMIT(rot_two);
                }
610
                EMIT_ARG(store_attr, MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0]));
Damien's avatar
Damien committed
611
612
613
614
615
616
617
618
619
620
            }
        } else {
            // shouldn't happen
            assert(0);
        }
    } else {
        // shouldn't happen
        assert(0);
    }

621
    if (!MP_PARSE_NODE_IS_NULL(pns->nodes[2])) {
Damien's avatar
Damien committed
622
623
624
625
626
        // SyntaxError, cannot assign
        assert(0);
    }
}

627
void c_assign_tuple(compiler_t *comp, int n, mp_parse_node_t *nodes) {
Damien's avatar
Damien committed
628
629
630
    assert(n >= 0);
    int have_star_index = -1;
    for (int i = 0; i < n; i++) {
631
        if (MP_PARSE_NODE_IS_STRUCT_KIND(nodes[i], PN_star_expr)) {
Damien's avatar
Damien committed
632
            if (have_star_index < 0) {
633
                EMIT_ARG(unpack_ex, i, n - i - 1);
Damien's avatar
Damien committed
634
635
                have_star_index = i;
            } else {
636
                compile_syntax_error(comp, "two starred expressions in assignment");
Damien's avatar
Damien committed
637
638
639
640
641
                return;
            }
        }
    }
    if (have_star_index < 0) {
642
        EMIT_ARG(unpack_sequence, n);
Damien's avatar
Damien committed
643
644
645
    }
    for (int i = 0; i < n; i++) {
        if (i == have_star_index) {
646
            c_assign(comp, ((mp_parse_node_struct_t*)nodes[i])->nodes[0], ASSIGN_STORE);
Damien's avatar
Damien committed
647
648
649
650
651
652
653
        } else {
            c_assign(comp, nodes[i], ASSIGN_STORE);
        }
    }
}

// assigns top of stack to pn
654
void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_kind) {
Damien's avatar
Damien committed
655
    tail_recursion:
656
    if (MP_PARSE_NODE_IS_NULL(pn)) {
Damien's avatar
Damien committed
657
        assert(0);
658
659
660
    } else if (MP_PARSE_NODE_IS_LEAF(pn)) {
        if (MP_PARSE_NODE_IS_ID(pn)) {
            int arg = MP_PARSE_NODE_LEAF_ARG(pn);
Damien's avatar
Damien committed
661
662
663
            switch (assign_kind) {
                case ASSIGN_STORE:
                case ASSIGN_AUG_STORE:
664
                    EMIT_ARG(store_id, arg);
Damien's avatar
Damien committed
665
666
                    break;
                case ASSIGN_AUG_LOAD:
667
                    EMIT_ARG(load_id, arg);
Damien's avatar
Damien committed
668
669
670
                    break;
            }
        } else {
671
            compile_syntax_error(comp, "can't assign to literal");
Damien's avatar
Damien committed
672
673
674
            return;
        }
    } else {
675
676
        mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
        switch (MP_PARSE_NODE_STRUCT_KIND(pns)) {
Damien's avatar
Damien committed
677
678
679
680
681
682
683
684
685
686
687
            case PN_power:
                // lhs is an index or attribute
                c_assign_power(comp, pns, assign_kind);
                break;

            case PN_testlist_star_expr:
            case PN_exprlist:
                // lhs is a tuple
                if (assign_kind != ASSIGN_STORE) {
                    goto bad_aug;
                }
688
                c_assign_tuple(comp, MP_PARSE_NODE_STRUCT_NUM_NODES(pns), pns->nodes);
Damien's avatar
Damien committed
689
690
691
692
                break;

            case PN_atom_paren:
                // lhs is something in parenthesis
693
                if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {
Damien's avatar
Damien committed
694
                    // empty tuple
695
                    compile_syntax_error(comp, "can't assign to ()");
Damien's avatar
Damien committed
696
                    return;
697
698
                } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp)) {
                    pns = (mp_parse_node_struct_t*)pns->nodes[0];
Damien's avatar
Damien committed
699
700
701
702
703
704
705
706
707
708
709
710
711
                    goto testlist_comp;
                } else {
                    // parenthesis around 1 item, is just that item
                    pn = pns->nodes[0];
                    goto tail_recursion;
                }
                break;

            case PN_atom_bracket:
                // lhs is something in brackets
                if (assign_kind != ASSIGN_STORE) {
                    goto bad_aug;
                }
712
                if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {
Damien's avatar
Damien committed
713
714
                    // empty list, assignment allowed
                    c_assign_tuple(comp, 0, NULL);
715
716
                } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp)) {
                    pns = (mp_parse_node_struct_t*)pns->nodes[0];
Damien's avatar
Damien committed
717
718
719
720
721
722
723
724
                    goto testlist_comp;
                } else {
                    // brackets around 1 item
                    c_assign_tuple(comp, 1, &pns->nodes[0]);
                }
                break;

            default:
725
                printf("unknown assign, %u\n", (uint)MP_PARSE_NODE_STRUCT_KIND(pns));
Damien's avatar
Damien committed
726
727
728
729
730
731
                assert(0);
        }
        return;

        testlist_comp:
        // lhs is a sequence
732
733
734
        if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) {
            mp_parse_node_struct_t *pns2 = (mp_parse_node_struct_t*)pns->nodes[1];
            if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_testlist_comp_3b) {
Damien's avatar
Damien committed
735
                // sequence of one item, with trailing comma
736
                assert(MP_PARSE_NODE_IS_NULL(pns2->nodes[0]));
Damien's avatar
Damien committed
737
                c_assign_tuple(comp, 1, &pns->nodes[0]);
738
            } else if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_testlist_comp_3c) {
Damien's avatar
Damien committed
739
740
                // sequence of many items
                // TODO call c_assign_tuple instead
741
                int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns2);
742
                EMIT_ARG(unpack_sequence, 1 + n);
Damien's avatar
Damien committed
743
744
745
746
                c_assign(comp, pns->nodes[0], ASSIGN_STORE);
                for (int i = 0; i < n; i++) {
                    c_assign(comp, pns2->nodes[i], ASSIGN_STORE);
                }
747
            } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_comp_for) {
Damien's avatar
Damien committed
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
                // TODO not implemented
                assert(0);
            } else {
                // sequence with 2 items
                goto sequence_with_2_items;
            }
        } else {
            // sequence with 2 items
            sequence_with_2_items:
            c_assign_tuple(comp, 2, pns->nodes);
        }
        return;
    }
    return;

    bad_aug:
764
    compile_syntax_error(comp, "illegal expression for augmented assignment");
Damien's avatar
Damien committed
765
766
767
768
}

// stuff for lambda and comprehensions and generators
void close_over_variables_etc(compiler_t *comp, scope_t *this_scope, int n_dict_params, int n_default_params) {
769
770
#if !MICROPY_EMIT_CPYTHON
    // in Micro Python we put the default params into a tuple using the bytecode
771
772
773
    if (n_default_params) {
        EMIT_ARG(build_tuple, n_default_params);
    }
774
775
#endif

Damien's avatar
Damien committed
776
    // make closed over variables, if any
777
    // ensure they are closed over in the order defined in the outer scope (mainly to agree with CPython)
Damien's avatar
Damien committed
778
779
    int nfree = 0;
    if (comp->scope_cur->kind != SCOPE_MODULE) {
780
781
782
783
784
785
        for (int i = 0; i < comp->scope_cur->id_info_len; i++) {
            id_info_t *id = &comp->scope_cur->id_info[i];
            if (id->kind == ID_INFO_KIND_CELL || id->kind == ID_INFO_KIND_FREE) {
                for (int j = 0; j < this_scope->id_info_len; j++) {
                    id_info_t *id2 = &this_scope->id_info[j];
                    if (id2->kind == ID_INFO_KIND_FREE && id->qstr == id2->qstr) {
Damien George's avatar
Damien George committed
786
#if MICROPY_EMIT_CPYTHON
787
                        EMIT_ARG(load_closure, id->qstr, id->local_num);
Damien George's avatar
Damien George committed
788
789
#else
                        // in Micro Python we load closures using LOAD_FAST
790
                        EMIT_ARG(load_fast, id->qstr, id->local_num);
Damien George's avatar
Damien George committed
791
#endif
792
793
794
                        nfree += 1;
                    }
                }
Damien's avatar
Damien committed
795
796
797
798
799
800
            }
        }
    }

    // make the function/closure
    if (nfree == 0) {
801
        EMIT_ARG(make_function, this_scope, n_dict_params, n_default_params);
Damien's avatar
Damien committed
802
    } else {
803
        EMIT_ARG(build_tuple, nfree);
804
        EMIT_ARG(make_closure, this_scope, n_dict_params, n_default_params);
Damien's avatar
Damien committed
805
806
807
    }
}

808
void compile_funcdef_param(compiler_t *comp, mp_parse_node_t pn) {
809
    if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_typedargslist_star)) {
810
        mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
        if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {
            // bare star
            comp->have_bare_star = true;
        }

    } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_typedargslist_dbl_star)) {
        // TODO do we need to do anything with this?

    } else {
        mp_parse_node_t pn_id;
        mp_parse_node_t pn_colon;
        mp_parse_node_t pn_equal;
        if (MP_PARSE_NODE_IS_ID(pn)) {
            // this parameter is just an id

            pn_id = pn;
            pn_colon = MP_PARSE_NODE_NULL;
            pn_equal = MP_PARSE_NODE_NULL;

        } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_typedargslist_name)) {
            // this parameter has a colon and/or equal specifier

            mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
            pn_id = pns->nodes[0];
            pn_colon = pns->nodes[1];
            pn_equal = pns->nodes[2];

        } else {
            assert(0);
            return;
        }

        if (MP_PARSE_NODE_IS_NULL(pn_equal)) {
            // this parameter does not have a default value

            // check for non-default parameters given after default parameters (allowed by parser, but not syntactically valid)
            if (!comp->have_bare_star && comp->param_pass_num_default_params != 0) {
                compile_syntax_error(comp, "non-default argument follows default argument");
                return;
            }

        } else {
Damien's avatar
Damien committed
853
854
            // this parameter has a default value
            // in CPython, None (and True, False?) as default parameters are loaded with LOAD_NAME; don't understandy why
855

Damien's avatar
Damien committed
856
857
858
            if (comp->have_bare_star) {
                comp->param_pass_num_dict_params += 1;
                if (comp->param_pass == 1) {
859
860
                    EMIT_ARG(load_const_id, MP_PARSE_NODE_LEAF_ARG(pn_id));
                    compile_node(comp, pn_equal);
Damien's avatar
Damien committed
861
862
863
864
                }
            } else {
                comp->param_pass_num_default_params += 1;
                if (comp->param_pass == 2) {
865
                    compile_node(comp, pn_equal);
Damien's avatar
Damien committed
866
867
868
                }
            }
        }
869
870
871

        // TODO pn_colon not implemented
        (void)pn_colon;
Damien's avatar
Damien committed
872
873
874
875
876
    }
}

// leaves function object on stack
// returns function name
877
qstr compile_funcdef_helper(compiler_t *comp, mp_parse_node_struct_t *pns, uint emit_options) {
Damien's avatar
Damien committed
878
879
    if (comp->pass == PASS_1) {
        // create a new scope for this function
880
        scope_t *s = scope_new_and_link(comp, SCOPE_FUNCTION, (mp_parse_node_t)pns, emit_options);
Damien's avatar
Damien committed
881
        // store the function scope so the compiling function can use it at each pass
882
        pns->nodes[4] = (mp_parse_node_t)s;
Damien's avatar
Damien committed
883
884
885
886
887
888
889
890
891
    }

    // save variables (probably don't need to do this, since we can't have nested definitions..?)
    bool old_have_bare_star = comp->have_bare_star;
    int old_param_pass = comp->param_pass;
    int old_param_pass_num_dict_params = comp->param_pass_num_dict_params;
    int old_param_pass_num_default_params = comp->param_pass_num_default_params;

    // compile default parameters
892
893

    // pass 1 does any default parameters after bare star
Damien's avatar
Damien committed
894
    comp->have_bare_star = false;
895
    comp->param_pass = 1;
Damien's avatar
Damien committed
896
897
898
    comp->param_pass_num_dict_params = 0;
    comp->param_pass_num_default_params = 0;
    apply_to_single_or_list(comp, pns->nodes[1], PN_typedargslist, compile_funcdef_param);
899
900
901
902
903
904

    if (comp->had_error) {
        return MP_QSTR_NULL;
    }

    // pass 2 does any default parameters before bare star
Damien's avatar
Damien committed
905
    comp->have_bare_star = false;
906
    comp->param_pass = 2;
Damien's avatar
Damien committed
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
    comp->param_pass_num_dict_params = 0;
    comp->param_pass_num_default_params = 0;
    apply_to_single_or_list(comp, pns->nodes[1], PN_typedargslist, compile_funcdef_param);

    // get the scope for this function
    scope_t *fscope = (scope_t*)pns->nodes[4];

    // make the function
    close_over_variables_etc(comp, fscope, comp->param_pass_num_dict_params, comp->param_pass_num_default_params);

    // restore variables
    comp->have_bare_star = old_have_bare_star;
    comp->param_pass = old_param_pass;
    comp->param_pass_num_dict_params = old_param_pass_num_dict_params;
    comp->param_pass_num_default_params = old_param_pass_num_default_params;

    // return its name (the 'f' in "def f(...):")
    return fscope->simple_name;
}

// leaves class object on stack
// returns class name
929
qstr compile_classdef_helper(compiler_t *comp, mp_parse_node_struct_t *pns, uint emit_options) {
Damien's avatar
Damien committed
930
931
    if (comp->pass == PASS_1) {
        // create a new scope for this class
932
        scope_t *s = scope_new_and_link(comp, SCOPE_CLASS, (mp_parse_node_t)pns, emit_options);
Damien's avatar
Damien committed
933
        // store the class scope so the compiling function can use it at each pass
934
        pns->nodes[3] = (mp_parse_node_t)s;
Damien's avatar
Damien committed
935
936
937
938
939
940
941
942
943
944
945
    }

    EMIT(load_build_class);

    // scope for this class
    scope_t *cscope = (scope_t*)pns->nodes[3];

    // compile the class
    close_over_variables_etc(comp, cscope, 0, 0);

    // get its name
946
    EMIT_ARG(load_const_id, cscope->simple_name);
Damien's avatar
Damien committed
947
948

    // nodes[1] has parent classes, if any
949
950
    comp->func_arg_is_super = false;
    compile_trailer_paren_helper(comp, pns->nodes[1], false, 2);
Damien's avatar
Damien committed
951
952
953
954
955

    // return its name (the 'C' in class C(...):")
    return cscope->simple_name;
}

956
// returns true if it was a built-in decorator (even if the built-in had an error)
957
STATIC bool compile_built_in_decorator(compiler_t *comp, int name_len, mp_parse_node_t *name_nodes, uint *emit_options) {
958
    if (MP_PARSE_NODE_LEAF_ARG(name_nodes[0]) != MP_QSTR_micropython) {
959
960
961
962
        return false;
    }

    if (name_len != 2) {
963
        compile_syntax_error(comp, "invalid micropython decorator");
964
965
966
        return true;
    }

967
    qstr attr = MP_PARSE_NODE_LEAF_ARG(name_nodes[1]);
968
    if (attr == MP_QSTR_byte_code) {
Damien's avatar
Damien committed
969
        *emit_options = EMIT_OPT_BYTE_CODE;
970
#if MICROPY_EMIT_NATIVE
971
    } else if (attr == MP_QSTR_native) {
972
        *emit_options = EMIT_OPT_NATIVE_PYTHON;
973
    } else if (attr == MP_QSTR_viper) {
Damien's avatar
Damien committed
974
        *emit_options = EMIT_OPT_VIPER;
975
#endif
976
#if MICROPY_EMIT_INLINE_THUMB
977
    } else if (attr == MP_QSTR_asm_thumb) {
978
        *emit_options = EMIT_OPT_ASM_THUMB;
979
#endif
980
    } else {
981
        compile_syntax_error(comp, "invalid micropython decorator");
982
983
984
985
986
    }

    return true;
}

987
void compile_decorated(compiler_t *comp, mp_parse_node_struct_t *pns) {
Damien's avatar
Damien committed
988
    // get the list of decorators
989
    mp_parse_node_t *nodes;
Damien's avatar
Damien committed
990
991
    int n = list_get(&pns->nodes[0], PN_decorators, &nodes);

992
993
994
995
996
    // inherit emit options for this function/class definition
    uint emit_options = comp->scope_cur->emit_options;

    // compile each decorator
    int num_built_in_decorators = 0;
Damien's avatar
Damien committed
997
    for (int i = 0; i < n; i++) {
998
999
        assert(MP_PARSE_NODE_IS_STRUCT_KIND(nodes[i], PN_decorator)); // should be
        mp_parse_node_struct_t *pns_decorator = (mp_parse_node_struct_t*)nodes[i];
1000
1001

        // nodes[0] contains the decorator function, which is a dotted name
1002
        mp_parse_node_t *name_nodes;
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
        int name_len = list_get(&pns_decorator->nodes[0], PN_dotted_name, &name_nodes);

        // check for built-in decorators
        if (compile_built_in_decorator(comp, name_len, name_nodes, &emit_options)) {
            // this was a built-in
            num_built_in_decorators += 1;

        } else {
            // not a built-in, compile normally

            // compile the decorator function
            compile_node(comp, name_nodes[0]);
            for (int i = 1; i < name_len; i++) {
1016
                assert(MP_PARSE_NODE_IS_ID(name_nodes[i])); // should be
1017
                EMIT_ARG(load_attr, MP_PARSE_NODE_LEAF_ARG(name_nodes[i]));
1018
1019
1020
            }

            // nodes[1] contains arguments to the decorator function, if any
1021
            if (!MP_PARSE_NODE_IS_NULL(pns_decorator->nodes[1])) {
1022
                // call the decorator function with the arguments in nodes[1]
Damien George's avatar
Damien George committed
1023
                comp->func_arg_is_super = false;
1024
1025
                compile_node(comp, pns_decorator->nodes[1]);
            }
Damien's avatar
Damien committed
1026
1027
1028
1029
        }
    }

    // compile the body (funcdef or classdef) and get its name
1030
    mp_parse_node_struct_t *pns_body = (mp_parse_node_struct_t*)pns->nodes[1];
Damien's avatar
Damien committed
1031
    qstr body_name = 0;
1032
    if (MP_PARSE_NODE_STRUCT_KIND(pns_body) == PN_funcdef) {
1033
        body_name = compile_funcdef_helper(comp, pns_body, emit_options);
1034
    } else if (MP_PARSE_NODE_STRUCT_KIND(pns_body) == PN_classdef) {
1035
        body_name = compile_classdef_helper(comp, pns_body, emit_options);
Damien's avatar
Damien committed
1036
1037
1038
1039
1040
1041
    } else {
        // shouldn't happen
        assert(0);
    }

    // call each decorator
1042
    for (int i = 0; i < n - num_built_in_decorators; i++) {
1043
        EMIT_ARG(call_function, 1, 0, false, false);
Damien's avatar
Damien committed
1044
1045
1046
    }

    // store func/class object into name
1047
    EMIT_ARG(store_id, body_name);
Damien's avatar
Damien committed
1048
1049
}

1050
void compile_funcdef(compiler_t *comp, mp_parse_node_struct_t *pns) {
1051
    qstr fname = compile_funcdef_helper(comp, pns, comp->scope_cur->emit_options);
Damien's avatar
Damien committed
1052
    // store function object into function name
1053
    EMIT_ARG(store_id, fname);
Damien's avatar
Damien committed
1054
1055
}

1056
1057
void c_del_stmt(compiler_t *comp, mp_parse_node_t pn) {
    if (MP_PARSE_NODE_IS_ID(pn)) {
Damien George's avatar