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
769
}

// 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) {
    // make closed over variables, if any
770
    // ensure they are closed over in the order defined in the outer scope (mainly to agree with CPython)
Damien's avatar
Damien committed
771
772
    int nfree = 0;
    if (comp->scope_cur->kind != SCOPE_MODULE) {
773
774
775
776
777
778
        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
779
#if MICROPY_EMIT_CPYTHON
780
                        EMIT_ARG(load_closure, id->qstr, id->local_num);
Damien George's avatar
Damien George committed
781
782
#else
                        // in Micro Python we load closures using LOAD_FAST
783
                        EMIT_ARG(load_fast, id->qstr, id->local_num);
Damien George's avatar
Damien George committed
784
#endif
785
786
787
                        nfree += 1;
                    }
                }
Damien's avatar
Damien committed
788
789
790
791
            }
        }
    }
    if (nfree > 0) {
792
        EMIT_ARG(build_tuple, nfree);
Damien's avatar
Damien committed
793
794
795
796
    }

    // make the function/closure
    if (nfree == 0) {
797
        EMIT_ARG(make_function, this_scope, n_dict_params, n_default_params);
Damien's avatar
Damien committed
798
    } else {
799
        EMIT_ARG(make_closure, this_scope, n_dict_params, n_default_params);
Damien's avatar
Damien committed
800
801
802
    }
}

803
void compile_funcdef_param(compiler_t *comp, mp_parse_node_t pn) {
804
    if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_typedargslist_star)) {
805
        mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
806
807
808
809
810
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
        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
848
849
            // this parameter has a default value
            // in CPython, None (and True, False?) as default parameters are loaded with LOAD_NAME; don't understandy why
850

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

        // TODO pn_colon not implemented
        (void)pn_colon;
Damien's avatar
Damien committed
867
868
869
870
871
    }
}

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

    // 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
887
888

    // pass 1 does any default parameters after bare star
Damien's avatar
Damien committed
889
    comp->have_bare_star = false;
890
    comp->param_pass = 1;
Damien's avatar
Damien committed
891
892
893
    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);
894
895
896
897
898
899

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

    // pass 2 does any default parameters before bare star
Damien's avatar
Damien committed
900
    comp->have_bare_star = false;
901
    comp->param_pass = 2;
Damien's avatar
Damien committed
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
    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
924
qstr compile_classdef_helper(compiler_t *comp, mp_parse_node_struct_t *pns, uint emit_options) {
Damien's avatar
Damien committed
925
926
    if (comp->pass == PASS_1) {
        // create a new scope for this class
927
        scope_t *s = scope_new_and_link(comp, SCOPE_CLASS, (mp_parse_node_t)pns, emit_options);
Damien's avatar
Damien committed
928
        // store the class scope so the compiling function can use it at each pass
929
        pns->nodes[3] = (mp_parse_node_t)s;
Damien's avatar
Damien committed
930
931
932
933
934
935
936
937
938
939
940
    }

    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
941
    EMIT_ARG(load_const_id, cscope->simple_name);
Damien's avatar
Damien committed
942
943

    // nodes[1] has parent classes, if any
944
945
    comp->func_arg_is_super = false;
    compile_trailer_paren_helper(comp, pns->nodes[1], false, 2);
Damien's avatar
Damien committed
946
947
948
949
950

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

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

    if (name_len != 2) {
958
        compile_syntax_error(comp, "invalid micropython decorator");
959
960
961
        return true;
    }

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

    return true;
}

982
void compile_decorated(compiler_t *comp, mp_parse_node_struct_t *pns) {
Damien's avatar
Damien committed
983
    // get the list of decorators
984
    mp_parse_node_t *nodes;
Damien's avatar
Damien committed
985
986
    int n = list_get(&pns->nodes[0], PN_decorators, &nodes);

987
988
989
990
991
    // 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
992
    for (int i = 0; i < n; i++) {
993
994
        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];
995
996

        // nodes[0] contains the decorator function, which is a dotted name
997
        mp_parse_node_t *name_nodes;
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
        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++) {
1011
                assert(MP_PARSE_NODE_IS_ID(name_nodes[i])); // should be
1012
                EMIT_ARG(load_attr, MP_PARSE_NODE_LEAF_ARG(name_nodes[i]));
1013
1014
1015
            }

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

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

    // call each decorator
1037
    for (int i = 0; i < n - num_built_in_decorators; i++) {
1038
        EMIT_ARG(call_function, 1, 0, false, false);
Damien's avatar
Damien committed
1039
1040
1041
    }

    // store func/class object into name
1042
    EMIT_ARG(store_id, body_name);
Damien's avatar
Damien committed
1043
1044
}

1045
void compile_funcdef(compiler_t *comp, mp_parse_node_struct_t *pns) {
1046
    qstr fname = compile_funcdef_helper(comp, pns, comp->scope_cur->emit_options);
Damien's avatar
Damien committed
1047
    // store function object into function name
1048
    EMIT_ARG(store_id, fname);
Damien's avatar
Damien committed
1049
1050
}

1051
1052
void c_del_stmt(compiler_t *comp, mp_parse_node_t pn) {
    if (MP_PARSE_NODE_IS_ID(pn)) {
1053
        EMIT_ARG(delete_id, MP_PARSE_NODE_LEAF_ARG(pn));
1054
1055
    } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_power)) {
        mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
Damien's avatar
Damien committed
1056
1057
1058

        compile_node(comp, pns->nodes[0]); // base of the power node