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

#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"
Damien's avatar
Damien committed
19
20
21

// TODO need to mangle __attr names

22
23
#define MICROPY_EMIT_NATIVE (MICROPY_EMIT_X64 || MICROPY_EMIT_THUMB)

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

32
33
34
35
#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
36

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

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

49
50
    int next_label;

Damien's avatar
Damien committed
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
    int break_label;
    int continue_label;
    int except_nest_level;

    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;

    scope_t *scope_head;
    scope_t *scope_cur;

66
67
    emit_t *emit;                                   // current emitter
    const emit_method_table_t *emit_method_table;   // current emit method table
68
69
70

    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
71
72
} compiler_t;

73
74
75
76
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
77
78
79
80
81
82

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

83
        switch (MP_PARSE_NODE_STRUCT_KIND(pns)) {
Damien's avatar
Damien committed
84
            case PN_shift_expr:
85
86
87
88
                if (n == 3 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[2])) {
                    int arg0 = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);
                    int arg1 = MP_PARSE_NODE_LEAF_ARG(pns->nodes[2]);
                    if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_DBL_LESS)) {
89
#if MICROPY_EMIT_CPYTHON
90
                        // can overflow; enabled only to compare with CPython
91
                        pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 << arg1);
92
#endif
93
94
                    } 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
95
96
97
98
99
100
101
102
                    } else {
                        // shouldn't happen
                        assert(0);
                    }
                }
                break;

            case PN_arith_expr:
103
                // overflow checking here relies on SMALL_INT being strictly smaller than machine_int_t
104
105
106
                if (n == 3 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[2])) {
                    machine_int_t arg0 = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);
                    machine_int_t arg1 = MP_PARSE_NODE_LEAF_ARG(pns->nodes[2]);
107
                    machine_int_t res;
108
                    if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_PLUS)) {
109
                        res = arg0 + arg1;
110
                    } else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_MINUS)) {
111
                        res = arg0 - arg1;
Damien's avatar
Damien committed
112
113
114
                    } else {
                        // shouldn't happen
                        assert(0);
115
116
                        res = 0;
                    }
117
118
                    if (MP_FIT_SMALL_INT(res)) {
                        pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, res);
Damien's avatar
Damien committed
119
120
121
122
123
                    }
                }
                break;

            case PN_term:
124
125
126
127
                if (n == 3 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[2])) {
                    int arg0 = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);
                    int arg1 = MP_PARSE_NODE_LEAF_ARG(pns->nodes[2]);
                    if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_STAR)) {
128
#if MICROPY_EMIT_CPYTHON
129
                        // can overflow; enabled only to compare with CPython
130
                        pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 * arg1);
131
#endif
132
                    } else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_SLASH)) {
Damien's avatar
Damien committed
133
                        ; // pass
134
                    } else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_PERCENT)) {
135
                        // XXX implement this properly as Python's % operator acts differently to C's
136
137
                        pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 % arg1);
                    } else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_DBL_SLASH)) {
138
                        // XXX implement this properly as Python's // operator acts differently to C's
139
                        pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 / arg1);
Damien's avatar
Damien committed
140
141
142
143
144
145
146
147
                    } else {
                        // shouldn't happen
                        assert(0);
                    }
                }
                break;

            case PN_factor_2:
148
149
150
151
152
153
154
155
                if (MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[1])) {
                    machine_int_t arg = MP_PARSE_NODE_LEAF_ARG(pns->nodes[1]);
                    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
156
157
158
159
160
161
162
                    } else {
                        // shouldn't happen
                        assert(0);
                    }
                }
                break;

163
#if MICROPY_EMIT_CPYTHON
Damien's avatar
Damien committed
164
            case PN_power:
165
                // can overflow; enabled only to compare with CPython
166
167
168
169
                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])) {
                        int power = MP_PARSE_NODE_LEAF_ARG(pns2->nodes[0]);
Damien's avatar
Damien committed
170
171
                        if (power >= 0) {
                            int ans = 1;
172
                            int base = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);
Damien's avatar
Damien committed
173
174
175
                            for (; power > 0; power--) {
                                ans *= base;
                            }
176
                            pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, ans);
Damien's avatar
Damien committed
177
178
179
180
                        }
                    }
                }
                break;
181
#endif
Damien's avatar
Damien committed
182
183
184
185
186
187
        }
    }

    return pn;
}

188
void compile_node(compiler_t *comp, mp_parse_node_t pn);
Damien's avatar
Damien committed
189

190
191
192
193
static int comp_next_label(compiler_t *comp) {
    return comp->next_label++;
}

194
static scope_t *scope_new_and_link(compiler_t *comp, scope_kind_t kind, mp_parse_node_t pn, uint emit_options) {
195
    scope_t *scope = scope_new(kind, pn, comp->source_file, rt_get_unique_code_id(), emit_options);
Damien's avatar
Damien committed
196
197
198
199
200
201
202
203
204
205
206
207
208
209
    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;
}

210
211
static int list_len(mp_parse_node_t pn, int pn_kind) {
    if (MP_PARSE_NODE_IS_NULL(pn)) {
Damien's avatar
Damien committed
212
        return 0;
213
    } else if (MP_PARSE_NODE_IS_LEAF(pn)) {
Damien's avatar
Damien committed
214
215
        return 1;
    } else {
216
217
        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
218
219
            return 1;
        } else {
220
            return MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
Damien's avatar
Damien committed
221
222
223
224
        }
    }
}

225
226
227
228
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)) {
    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
229
230
231
        for (int i = 0; i < num_nodes; i++) {
            f(comp, pns->nodes[i]);
        }
232
    } else if (!MP_PARSE_NODE_IS_NULL(pn)) {
Damien's avatar
Damien committed
233
234
235
236
        f(comp, pn);
    }
}

237
238
static int list_get(mp_parse_node_t *pn, int pn_kind, mp_parse_node_t **nodes) {
    if (MP_PARSE_NODE_IS_NULL(*pn)) {
Damien's avatar
Damien committed
239
240
        *nodes = NULL;
        return 0;
241
    } else if (MP_PARSE_NODE_IS_LEAF(*pn)) {
Damien's avatar
Damien committed
242
243
244
        *nodes = pn;
        return 1;
    } else {
245
246
        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
247
248
249
250
            *nodes = pn;
            return 1;
        } else {
            *nodes = pns->nodes;
251
            return MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
Damien's avatar
Damien committed
252
253
254
255
        }
    }
}

256
void compile_do_nothing(compiler_t *comp, mp_parse_node_struct_t *pns) {
Damien's avatar
Damien committed
257
258
}

259
260
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
261
262
263
264
265
    for (int i = 0; i < num_nodes; i++) {
        compile_node(comp, pns->nodes[i]);
    }
}

266
#if MICROPY_EMIT_CPYTHON
267
268
static bool cpython_c_tuple_is_const(mp_parse_node_t pn) {
    if (!MP_PARSE_NODE_IS_LEAF(pn)) {
Damien's avatar
Damien committed
269
270
        return false;
    }
271
    if (MP_PARSE_NODE_IS_ID(pn)) {
Damien's avatar
Damien committed
272
273
274
275
276
        return false;
    }
    return true;
}

277
static void cpython_c_print_quoted_str(vstr_t *vstr, qstr qstr, bool bytes) {
278
279
    uint len;
    const byte *str = qstr_data(qstr, &len);
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
    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, "'");
    }
}

317
318
319
320
321
322
323
324
325
326
327
static void cpython_c_tuple_emit_const(compiler_t *comp, mp_parse_node_t pn, vstr_t *vstr) {
    assert(MP_PARSE_NODE_IS_LEAF(pn));
    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_SMALL_INT: vstr_printf(vstr, "%d", arg); break;
        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
328
            switch (arg) {
329
330
331
                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
332
333
334
335
336
337
338
                default: assert(0);
            }
            break;
        default: assert(0);
    }
}

339
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
340
341
    int n = 0;
    if (pns_list != NULL) {
342
        n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns_list);
Damien's avatar
Damien committed
343
344
345
    }
    int total = n;
    bool is_const = true;
346
    if (!MP_PARSE_NODE_IS_NULL(pn)) {
Damien's avatar
Damien committed
347
        total += 1;
348
        if (!cpython_c_tuple_is_const(pn)) {
Damien's avatar
Damien committed
349
350
351
352
            is_const = false;
        }
    }
    for (int i = 0; i < n; i++) {
353
        if (!cpython_c_tuple_is_const(pns_list->nodes[i])) {
Damien's avatar
Damien committed
354
355
356
357
358
359
            is_const = false;
            break;
        }
    }
    if (total > 0 && is_const) {
        bool need_comma = false;
360
361
        vstr_t *vstr = vstr_new();
        vstr_printf(vstr, "(");
362
        if (!MP_PARSE_NODE_IS_NULL(pn)) {
363
            cpython_c_tuple_emit_const(comp, pn, vstr);
Damien's avatar
Damien committed
364
365
366
367
            need_comma = true;
        }
        for (int i = 0; i < n; i++) {
            if (need_comma) {
368
                vstr_printf(vstr, ", ");
Damien's avatar
Damien committed
369
            }
370
            cpython_c_tuple_emit_const(comp, pns_list->nodes[i], vstr);
Damien's avatar
Damien committed
371
372
373
            need_comma = true;
        }
        if (total == 1) {
374
            vstr_printf(vstr, ",)");
Damien's avatar
Damien committed
375
        } else {
376
            vstr_printf(vstr, ")");
Damien's avatar
Damien committed
377
        }
378
        EMIT_ARG(load_const_verbatim_str, vstr_str(vstr));
379
        vstr_free(vstr);
Damien's avatar
Damien committed
380
    } else {
381
        if (!MP_PARSE_NODE_IS_NULL(pn)) {
Damien's avatar
Damien committed
382
383
384
385
386
            compile_node(comp, pn);
        }
        for (int i = 0; i < n; i++) {
            compile_node(comp, pns_list->nodes[i]);
        }
387
        EMIT_ARG(build_tuple, total);
Damien's avatar
Damien committed
388
389
    }
}
390
391
392
#endif

// funnelling all tuple creations through this function is purely so we can optionally agree with CPython
393
void c_tuple(compiler_t *comp, mp_parse_node_t pn, mp_parse_node_struct_t *pns_list) {
394
#if MICROPY_EMIT_CPYTHON
395
396
397
    cpython_c_tuple(comp, pn, pns_list);
#else
    int total = 0;
398
    if (!MP_PARSE_NODE_IS_NULL(pn)) {
399
400
401
402
        compile_node(comp, pn);
        total += 1;
    }
    if (pns_list != NULL) {
403
        int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns_list);
404
405
406
407
408
        for (int i = 0; i < n; i++) {
            compile_node(comp, pns_list->nodes[i]);
        }
        total += n;
    }
409
    EMIT_ARG(build_tuple, total);
410
411
#endif
}
Damien's avatar
Damien committed
412

413
void compile_generic_tuple(compiler_t *comp, mp_parse_node_struct_t *pns) {
Damien's avatar
Damien committed
414
    // a simple tuple expression
415
    c_tuple(comp, MP_PARSE_NODE_NULL, pns);
Damien's avatar
Damien committed
416
417
}

418
419
420
static bool node_is_const_false(mp_parse_node_t pn) {
    return MP_PARSE_NODE_IS_TOKEN_KIND(pn, MP_TOKEN_KW_FALSE);
    // untested: || (MP_PARSE_NODE_IS_SMALL_INT(pn) && MP_PARSE_NODE_LEAF_ARG(pn) == 1);
Damien's avatar
Damien committed
421
422
}

423
424
static bool node_is_const_true(mp_parse_node_t pn) {
    return MP_PARSE_NODE_IS_TOKEN_KIND(pn, MP_TOKEN_KW_TRUE) || (MP_PARSE_NODE_IS_SMALL_INT(pn) && MP_PARSE_NODE_LEAF_ARG(pn) == 1);
Damien's avatar
Damien committed
425
426
}

427
#if MICROPY_EMIT_CPYTHON
428
// the is_nested variable is purely to match with CPython, which doesn't fully optimise not's
429
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
430
431
    if (node_is_const_false(pn)) {
        if (jump_if == false) {
432
            EMIT_ARG(jump, label);
Damien's avatar
Damien committed
433
434
435
436
        }
        return;
    } else if (node_is_const_true(pn)) {
        if (jump_if == true) {
437
            EMIT_ARG(jump, label);
Damien's avatar
Damien committed
438
439
        }
        return;
440
441
442
443
    } 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
444
            if (jump_if == false) {
445
                int label2 = comp_next_label(comp);
Damien's avatar
Damien committed
446
                for (int i = 0; i < n - 1; i++) {
447
                    cpython_c_if_cond(comp, pns->nodes[i], true, label2, true);
Damien's avatar
Damien committed
448
                }
449
                cpython_c_if_cond(comp, pns->nodes[n - 1], false, label, true);
450
                EMIT_ARG(label_assign, label2);
Damien's avatar
Damien committed
451
452
            } else {
                for (int i = 0; i < n; i++) {
453
                    cpython_c_if_cond(comp, pns->nodes[i], true, label, true);
Damien's avatar
Damien committed
454
455
456
                }
            }
            return;
457
        } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_and_test) {
Damien's avatar
Damien committed
458
459
            if (jump_if == false) {
                for (int i = 0; i < n; i++) {
460
                    cpython_c_if_cond(comp, pns->nodes[i], false, label, true);
Damien's avatar
Damien committed
461
462
                }
            } else {
463
                int label2 = comp_next_label(comp);
Damien's avatar
Damien committed
464
                for (int i = 0; i < n - 1; i++) {
465
                    cpython_c_if_cond(comp, pns->nodes[i], false, label2, true);
Damien's avatar
Damien committed
466
                }
467
                cpython_c_if_cond(comp, pns->nodes[n - 1], true, label, true);
468
                EMIT_ARG(label_assign, label2);
Damien's avatar
Damien committed
469
470
            }
            return;
471
        } else if (!is_nested && MP_PARSE_NODE_STRUCT_KIND(pns) == PN_not_test_2) {
472
            cpython_c_if_cond(comp, pns->nodes[0], !jump_if, label, true);
Damien's avatar
Damien committed
473
474
475
476
477
478
479
            return;
        }
    }

    // nothing special, fall back to default compiling for node and jump
    compile_node(comp, pn);
    if (jump_if == false) {
480
        EMIT_ARG(pop_jump_if_false, label);
Damien's avatar
Damien committed
481
    } else {
482
        EMIT_ARG(pop_jump_if_true, label);
Damien's avatar
Damien committed
483
484
    }
}
485
#endif
Damien's avatar
Damien committed
486

487
static void c_if_cond(compiler_t *comp, mp_parse_node_t pn, bool jump_if, int label) {
488
#if MICROPY_EMIT_CPYTHON
489
490
491
492
    cpython_c_if_cond(comp, pn, jump_if, label, false);
#else
    if (node_is_const_false(pn)) {
        if (jump_if == false) {
493
            EMIT_ARG(jump, label);
494
495
496
497
        }
        return;
    } else if (node_is_const_true(pn)) {
        if (jump_if == true) {
498
            EMIT_ARG(jump, label);
499
500
        }
        return;
501
502
503
504
    } 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) {
505
506
507
508
509
510
            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);
511
                EMIT_ARG(label_assign, label2);
512
513
514
515
516
517
            } else {
                for (int i = 0; i < n; i++) {
                    c_if_cond(comp, pns->nodes[i], true, label);
                }
            }
            return;
518
        } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_and_test) {
519
520
521
522
523
524
525
526
527
528
            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);
529
                EMIT_ARG(label_assign, label2);
530
531
            }
            return;
532
        } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_not_test_2) {
533
534
535
536
537
538
539
540
            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) {
541
        EMIT_ARG(pop_jump_if_false, label);
542
    } else {
543
        EMIT_ARG(pop_jump_if_true, label);
544
545
    }
#endif
Damien's avatar
Damien committed
546
547
548
}

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

551
void c_assign_power(compiler_t *comp, mp_parse_node_struct_t *pns, assign_kind_t assign_kind) {
Damien's avatar
Damien committed
552
553
554
555
    if (assign_kind != ASSIGN_AUG_STORE) {
        compile_node(comp, pns->nodes[0]);
    }

556
557
558
559
    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
560
561
562
563
564
            if (assign_kind != ASSIGN_AUG_STORE) {
                for (int i = 0; i < n - 1; i++) {
                    compile_node(comp, pns1->nodes[i]);
                }
            }
565
566
            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
567
        }
568
        if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_trailer_paren) {
Damien's avatar
Damien committed
569
570
            printf("SyntaxError: can't assign to function call\n");
            return;
571
        } else if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_trailer_bracket) {
Damien's avatar
Damien committed
572
573
574
575
576
577
578
            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);
579
                    EMIT_ARG(binary_op, RT_BINARY_OP_SUBSCR);
Damien's avatar
Damien committed
580
581
582
583
                } else {
                    EMIT(store_subscr);
                }
            }
584
585
        } 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
586
587
            if (assign_kind == ASSIGN_AUG_LOAD) {
                EMIT(dup_top);
588
                EMIT_ARG(load_attr, MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0]));
Damien's avatar
Damien committed
589
590
591
592
            } else {
                if (assign_kind == ASSIGN_AUG_STORE) {
                    EMIT(rot_two);
                }
593
                EMIT_ARG(store_attr, MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0]));
Damien's avatar
Damien committed
594
595
596
597
598
599
600
601
602
603
            }
        } else {
            // shouldn't happen
            assert(0);
        }
    } else {
        // shouldn't happen
        assert(0);
    }

604
    if (!MP_PARSE_NODE_IS_NULL(pns->nodes[2])) {
Damien's avatar
Damien committed
605
606
607
608
609
        // SyntaxError, cannot assign
        assert(0);
    }
}

610
void c_assign_tuple(compiler_t *comp, int n, mp_parse_node_t *nodes) {
Damien's avatar
Damien committed
611
612
613
    assert(n >= 0);
    int have_star_index = -1;
    for (int i = 0; i < n; i++) {
614
        if (MP_PARSE_NODE_IS_STRUCT_KIND(nodes[i], PN_star_expr)) {
Damien's avatar
Damien committed
615
            if (have_star_index < 0) {
616
                EMIT_ARG(unpack_ex, i, n - i - 1);
Damien's avatar
Damien committed
617
618
619
620
621
622
623
624
                have_star_index = i;
            } else {
                printf("SyntaxError: two starred expressions in assignment\n");
                return;
            }
        }
    }
    if (have_star_index < 0) {
625
        EMIT_ARG(unpack_sequence, n);
Damien's avatar
Damien committed
626
627
628
    }
    for (int i = 0; i < n; i++) {
        if (i == have_star_index) {
629
            c_assign(comp, ((mp_parse_node_struct_t*)nodes[i])->nodes[0], ASSIGN_STORE);
Damien's avatar
Damien committed
630
631
632
633
634
635
636
        } else {
            c_assign(comp, nodes[i], ASSIGN_STORE);
        }
    }
}

// assigns top of stack to pn
637
void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_kind) {
Damien's avatar
Damien committed
638
    tail_recursion:
639
    if (MP_PARSE_NODE_IS_NULL(pn)) {
Damien's avatar
Damien committed
640
        assert(0);
641
642
643
    } 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
644
645
646
            switch (assign_kind) {
                case ASSIGN_STORE:
                case ASSIGN_AUG_STORE:
647
                    EMIT_ARG(store_id, arg);
Damien's avatar
Damien committed
648
649
                    break;
                case ASSIGN_AUG_LOAD:
650
                    EMIT_ARG(load_id, arg);
Damien's avatar
Damien committed
651
652
653
654
655
656
657
                    break;
            }
        } else {
            printf("SyntaxError: can't assign to literal\n");
            return;
        }
    } else {
658
659
        mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
        switch (MP_PARSE_NODE_STRUCT_KIND(pns)) {
Damien's avatar
Damien committed
660
661
662
663
664
665
666
667
668
669
670
            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;
                }
671
                c_assign_tuple(comp, MP_PARSE_NODE_STRUCT_NUM_NODES(pns), pns->nodes);
Damien's avatar
Damien committed
672
673
674
675
                break;

            case PN_atom_paren:
                // lhs is something in parenthesis
676
                if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {
Damien's avatar
Damien committed
677
678
679
                    // empty tuple
                    printf("SyntaxError: can't assign to ()\n");
                    return;
680
681
                } 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
682
683
684
685
686
687
688
689
690
691
692
693
694
                    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;
                }
695
                if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {
Damien's avatar
Damien committed
696
697
                    // empty list, assignment allowed
                    c_assign_tuple(comp, 0, NULL);
698
699
                } 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
700
701
702
703
704
705
706
707
                    goto testlist_comp;
                } else {
                    // brackets around 1 item
                    c_assign_tuple(comp, 1, &pns->nodes[0]);
                }
                break;

            default:
708
                printf("unknown assign, %u\n", (uint)MP_PARSE_NODE_STRUCT_KIND(pns));
Damien's avatar
Damien committed
709
710
711
712
713
714
                assert(0);
        }
        return;

        testlist_comp:
        // lhs is a sequence
715
716
717
        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
718
                // sequence of one item, with trailing comma
719
                assert(MP_PARSE_NODE_IS_NULL(pns2->nodes[0]));
Damien's avatar
Damien committed
720
                c_assign_tuple(comp, 1, &pns->nodes[0]);
721
            } else if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_testlist_comp_3c) {
Damien's avatar
Damien committed
722
723
                // sequence of many items
                // TODO call c_assign_tuple instead
724
                int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns2);
725
                EMIT_ARG(unpack_sequence, 1 + n);
Damien's avatar
Damien committed
726
727
728
729
                c_assign(comp, pns->nodes[0], ASSIGN_STORE);
                for (int i = 0; i < n; i++) {
                    c_assign(comp, pns2->nodes[i], ASSIGN_STORE);
                }
730
            } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_comp_for) {
Damien's avatar
Damien committed
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
                // 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:
    printf("SyntaxError: illegal expression for augmented assignment\n");
}

// 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
753
    // ensure they are closed over in the order defined in the outer scope (mainly to agree with CPython)
Damien's avatar
Damien committed
754
755
    int nfree = 0;
    if (comp->scope_cur->kind != SCOPE_MODULE) {
756
757
758
759
760
761
        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
762
#if MICROPY_EMIT_CPYTHON
763
                        EMIT_ARG(load_closure, id->qstr, id->local_num);
Damien George's avatar
Damien George committed
764
765
#else
                        // in Micro Python we load closures using LOAD_FAST
766
                        EMIT_ARG(load_fast, id->qstr, id->local_num);
Damien George's avatar
Damien George committed
767
#endif
768
769
770
                        nfree += 1;
                    }
                }
Damien's avatar
Damien committed
771
772
773
774
            }
        }
    }
    if (nfree > 0) {
775
        EMIT_ARG(build_tuple, nfree);
Damien's avatar
Damien committed
776
777
778
779
    }

    // make the function/closure
    if (nfree == 0) {
780
        EMIT_ARG(make_function, this_scope, n_dict_params, n_default_params);
Damien's avatar
Damien committed
781
    } else {
782
        EMIT_ARG(make_closure, this_scope, n_dict_params, n_default_params);
Damien's avatar
Damien committed
783
784
785
    }
}

786
787
788
789
void compile_funcdef_param(compiler_t *comp, mp_parse_node_t pn) {
    if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_typedargslist_name)) {
        mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
        if (!MP_PARSE_NODE_IS_NULL(pns->nodes[2])) {
Damien's avatar
Damien committed
790
791
792
793
794
            // this parameter has a default value
            // in CPython, None (and True, False?) as default parameters are loaded with LOAD_NAME; don't understandy why
            if (comp->have_bare_star) {
                comp->param_pass_num_dict_params += 1;
                if (comp->param_pass == 1) {
795
                    EMIT_ARG(load_const_id, MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]));
Damien's avatar
Damien committed
796
797
798
799
800
801
802
803
804
                    compile_node(comp, pns->nodes[2]);
                }
            } else {
                comp->param_pass_num_default_params += 1;
                if (comp->param_pass == 2) {
                    compile_node(comp, pns->nodes[2]);
                }
            }
        }
805
806
807
    } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_typedargslist_star)) {
        mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
        if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {
Damien's avatar
Damien committed
808
809
810
811
812
813
814
815
            // bare star
            comp->have_bare_star = true;
        }
    }
}

// leaves function object on stack
// returns function name
816
qstr compile_funcdef_helper(compiler_t *comp, mp_parse_node_struct_t *pns, uint emit_options) {
Damien's avatar
Damien committed
817
818
    if (comp->pass == PASS_1) {
        // create a new scope for this function
819
        scope_t *s = scope_new_and_link(comp, SCOPE_FUNCTION, (mp_parse_node_t)pns, emit_options);
Damien's avatar
Damien committed
820
        // store the function scope so the compiling function can use it at each pass
821
        pns->nodes[4] = (mp_parse_node_t)s;
Damien's avatar
Damien committed
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
853
854
855
856
857
858
859
    }

    // 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
    comp->have_bare_star = false;
    comp->param_pass = 1; // pass 1 does any default parameters after bare star
    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);
    comp->have_bare_star = false;
    comp->param_pass = 2; // pass 2 does any default parameters before bare star
    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
860
qstr compile_classdef_helper(compiler_t *comp, mp_parse_node_struct_t *pns, uint emit_options) {
Damien's avatar
Damien committed
861
862
    if (comp->pass == PASS_1) {
        // create a new scope for this class
863
        scope_t *s = scope_new_and_link(comp, SCOPE_CLASS, (mp_parse_node_t)pns, emit_options);
Damien's avatar
Damien committed
864
        // store the class scope so the compiling function can use it at each pass
865
        pns->nodes[3] = (mp_parse_node_t)s;
Damien's avatar
Damien committed
866
867
868
869
870
871
872
873
874
875
876
    }

    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
877
    EMIT_ARG(load_const_id, cscope->simple_name);
Damien's avatar
Damien committed
878
879

    // nodes[1] has parent classes, if any
880
    if (MP_PARSE_NODE_IS_NULL(pns->nodes[1])) {
Damien's avatar
Damien committed
881
        // no parent classes
882
        EMIT_ARG(call_function, 2, 0, false, false);
Damien's avatar
Damien committed
883
884
885
886
    } else {
        // have a parent class or classes
        // TODO what if we have, eg, *a or **a in the parent list?
        compile_node(comp, pns->nodes[1]);
887
        EMIT_ARG(call_function, 2 + list_len(pns->nodes[1], PN_arglist), 0, false, false);
Damien's avatar
Damien committed
888
889
890
891
892
893
    }

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

894
// returns true if it was a built-in decorator (even if the built-in had an error)
895
static bool compile_built_in_decorator(compiler_t *comp, int name_len, mp_parse_node_t *name_nodes, uint *emit_options) {
896
    if (MP_PARSE_NODE_LEAF_ARG(name_nodes[0]) != MP_QSTR_micropython) {
897
898
899
900
901
902
903
904
        return false;
    }

    if (name_len != 2) {
        printf("SyntaxError: invalid micropython decorator\n");
        return true;
    }

905
    qstr attr = MP_PARSE_NODE_LEAF_ARG(name_nodes[1]);
906
    if (attr == MP_QSTR_byte_code) {
Damien's avatar
Damien committed
907
        *emit_options = EMIT_OPT_BYTE_CODE;
908
#if MICROPY_EMIT_NATIVE
909
    } else if (attr == MP_QSTR_native) {
910
        *emit_options = EMIT_OPT_NATIVE_PYTHON;
911
    } else if (attr == MP_QSTR_viper) {
Damien's avatar
Damien committed
912
        *emit_options = EMIT_OPT_VIPER;
913
#endif
914
#if MICROPY_EMIT_INLINE_THUMB
915
    } else if (attr == MP_QSTR_asm_thumb) {
916
        *emit_options = EMIT_OPT_ASM_THUMB;
917
#endif
918
    } else {
919
        printf("SyntaxError: invalid micropython decorator '%s'\n", qstr_str(attr));
920
921
922
923
924
    }

    return true;
}

925
void compile_decorated(compiler_t *comp, mp_parse_node_struct_t *pns) {
Damien's avatar
Damien committed
926
    // get the list of decorators
927
    mp_parse_node_t *nodes;
Damien's avatar
Damien committed
928
929
    int n = list_get(&pns->nodes[0], PN_decorators, &nodes);

930
931
932
933
934
    // 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
935
    for (int i = 0; i < n; i++) {
936
937
        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];
938
939

        // nodes[0] contains the decorator function, which is a dotted name
940
        mp_parse_node_t *name_nodes;
941
942
943
944
945
946
947
948
949
950
951
952
953
        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++) {
954
                assert(MP_PARSE_NODE_IS_ID(name_nodes[i])); // should be
955
                EMIT_ARG(load_attr, MP_PARSE_NODE_LEAF_ARG(name_nodes[i]));
956
957
958
            }

            // nodes[1] contains arguments to the decorator function, if any
959
            if (!MP_PARSE_NODE_IS_NULL(pns_decorator->nodes[1])) {
960
961
962
                // call the decorator function with the arguments in nodes[1]
                compile_node(comp, pns_decorator->nodes[1]);
            }
Damien's avatar
Damien committed
963
964
965
966
        }
    }

    // compile the body (funcdef or classdef) and get its name
967
    mp_parse_node_struct_t *pns_body = (mp_parse_node_struct_t*)pns->nodes[1];
Damien's avatar
Damien committed
968
    qstr body_name = 0;
969
    if (MP_PARSE_NODE_STRUCT_KIND(pns_body) == PN_funcdef) {
970
        body_name = compile_funcdef_helper(comp, pns_body, emit_options);
971
    } else if (MP_PARSE_NODE_STRUCT_KIND(pns_body) == PN_classdef) {
972
        body_name = compile_classdef_helper(comp, pns_body, emit_options);
Damien's avatar
Damien committed
973
974
975
976
977
978
    } else {
        // shouldn't happen
        assert(0);
    }

    // call each decorator
979
    for (int i = 0; i < n - num_built_in_decorators; i++) {
980
        EMIT_ARG(call_function, 1, 0, false, false);
Damien's avatar
Damien committed
981
982
983
    }

    // store func/class object into name
984
    EMIT_ARG(store_id, body_name);
Damien's avatar
Damien committed
985
986
}

987
void compile_funcdef(compiler_t *comp, mp_parse_node_struct_t *pns) {
988
    qstr fname = compile_funcdef_helper(comp, pns, comp->scope_cur->emit_options);
Damien's avatar
Damien committed
989
    // store function object into function name
990
    EMIT_ARG(store_id, fname);
Damien's avatar
Damien committed
991
992
}

993
994
void c_del_stmt(compiler_t *comp, mp_parse_node_t pn) {
    if (MP_PARSE_NODE_IS_ID(pn)) {
995
        EMIT_ARG(delete_id, MP_PARSE_NODE_LEAF_ARG(pn));
996
997
    } 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
998
999
1000

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

1001
1002
1003
1004
        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
1005
1006
1007
                for (int i = 0; i < n - 1; i++) {
                    compile_node(comp, pns1->nodes[i]);
                }
1008
1009
                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
1010
            }
1011
            if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_trailer_paren) {
Damien's avatar
Damien committed
1012
1013
                // SyntaxError: can't delete a function call
                assert(0);
1014
            } else if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_trailer_bracket) {
Damien's avatar
Damien committed
1015
1016
                compile_node(comp, pns1->nodes[0]);
                EMIT(delete_subscr);
1017
1018
            } else if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_trailer_period) {
                assert(MP_PARSE_NODE_IS_ID(pns1->nodes[0]));
1019
                EMIT_ARG(delete_attr, MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0]));
Damien's avatar
Damien committed
1020
1021
1022
1023
1024
1025
1026
1027
1028
            } else {
                // shouldn't happen
                assert(0);
            }
        } else {
            // shouldn't happen
            assert(0);
        }

1029
        if (!MP_PARSE_NODE_IS_NULL(pns->nodes[2])) {
Damien's avatar
Damien committed
1030
1031
1032
            // SyntaxError, cannot delete
            assert(0);
        }
1033
1034
1035
1036
    } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_atom_paren)) {
        pn = ((mp_parse_node_struct_t*)pn)->nodes[0];
        if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_testlist_comp)) {
            mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
Damien's avatar
Damien committed
1037
1038
            // TODO perhaps factorise testlist_comp code with other uses of PN_testlist_comp

1039
1040
1041
            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_testlist_comp_3b) {
Damien's avatar
Damien committed
1042
                    // sequence of one item, with trailing comma
1043
                    assert(MP_PARSE_NODE_IS_NULL(pns1->nodes[0]));
Damien's avatar
Damien committed
1044
                    c_del_stmt(comp, pns->nodes[0]);
1045
                } else if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_testlist_comp_3c) {
Damien's avatar
Damien committed
1046
                    // sequence of many items
1047
                    int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns1);
Damien's avatar
Damien committed
1048
1049
1050
1051
                    c_del_stmt(comp, pns->nodes[0]);
                    for (int i = 0; i < n; i++) {
                        c_del_stmt(comp, pns1->nodes[i]);
                    }
1052
                } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_comp_for) {
Damien's avatar
Damien committed
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
                    // TODO not implemented; can't del comprehension?
                    assert(0);
                } else {
                    // sequence with 2 items
                    goto sequence_with_2_items;
                }
            } else {
                // sequence with 2 items
                sequence_with_2_items:
                c_del_stmt(comp, pns->nodes[0]);
                c_del_stmt(comp, pns->nodes[1]);
            }
        } else {
            // tuple with 1 element
            c_del_stmt(comp, pn);
        }
    } else {
        // not implemented
        assert(0);
    }
}

1075
void compile_del_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
Damien's avatar
Damien committed
1076
1077
1078
    apply_to_single_or_list(comp, pns->nodes[0], PN_exprlist, c_del_stmt);
}

1079
void compile_break_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
Damien's avatar
Damien committed
1080
1081
1082
    if (comp->break_label == 0) {
        printf("ERROR: cannot break from here\n");
    }
1083
    EMIT_ARG(break_loop, comp->break_label);
Damien's avatar
Damien committed
1084
1085
}

1086
void compile_continue_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
Damien's avatar
Damien committed
1087
1088
1089
1090
    if (comp->continue_label == 0) {
        printf("ERROR: cannot continue from here\n");
    }
    if (comp->except_nest_level > 0) {
1091
        EMIT_ARG(continue_loop, comp->continue_label);
Damien's avatar
Damien committed
1092
    } else {
1093
        EMIT_ARG(jump, comp->continue_label);
Damien's avatar
Damien committed
1094
1095
1096
    }
}

1097
void compile_return_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
Damien's avatar
Damien committed
1098
1099
1100
1101
1102
    if (comp->scope_cur->kind != SCOPE_FUNCTION) {
        printf("SyntaxError: 'return' outside function\n");
        comp->had_error = true;
        return;
    }
1103
    if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {
Damien's avatar
Damien committed
1104
        // no argument to 'return', so return None