compile.c 121 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 "mpqstr.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
26
27
28
29
30
31
typedef enum {
    PN_none = 0,
#define DEF_RULE(rule, comp, kind, arg...) PN_##rule,
#include "grammar.h"
#undef DEF_RULE
    PN_maximum_number_of,
} pn_kind_t;

32
#define EMIT(fun, arg...) (comp->emit_method_table->fun(comp->emit, ##arg))
33
#define EMIT_INLINE_ASM(fun, arg...) (comp->emit_inline_asm_method_table->fun(comp->emit_inline_asm, ##arg))
Damien's avatar
Damien committed
34

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

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

47
48
    int next_label;

Damien's avatar
Damien committed
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
    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;

64
65
    emit_t *emit;                                   // current emitter
    const emit_method_table_t *emit_method_table;   // current emit method table
66
67
68

    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
69
70
} compiler_t;

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

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

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

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

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

            case PN_factor_2:
146
147
148
149
150
151
152
153
                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
154
155
156
157
158
159
160
                    } else {
                        // shouldn't happen
                        assert(0);
                    }
                }
                break;

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

    return pn;
}

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

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

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

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

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

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

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

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

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

275
276
277
278
279
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
static void cpython_c_print_quoted_str(vstr_t *vstr, qstr qstr, bool bytes) {
    const char *str = qstr_str(qstr);
    int len = strlen(str);
    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, "'");
    }
}

315
316
317
318
319
320
321
322
323
324
325
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
326
            switch (arg) {
327
328
329
                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
330
331
332
333
334
335
336
                default: assert(0);
            }
            break;
        default: assert(0);
    }
}

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

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

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

416
417
418
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
419
420
}

421
422
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
423
424
}

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

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

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

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

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

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

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

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

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

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

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

        testlist_comp:
        // lhs is a sequence
713
714
715
        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
716
                // sequence of one item, with trailing comma
717
                assert(MP_PARSE_NODE_IS_NULL(pns2->nodes[0]));
Damien's avatar
Damien committed
718
                c_assign_tuple(comp, 1, &pns->nodes[0]);
719
            } else if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_testlist_comp_3c) {
Damien's avatar
Damien committed
720
721
                // sequence of many items
                // TODO call c_assign_tuple instead
722
                int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns2);
Damien's avatar
Damien committed
723
724
725
726
727
                EMIT(unpack_sequence, 1 + n);
                c_assign(comp, pns->nodes[0], ASSIGN_STORE);
                for (int i = 0; i < n; i++) {
                    c_assign(comp, pns2->nodes[i], ASSIGN_STORE);
                }
728
            } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_comp_for) {
Damien's avatar
Damien committed
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
                // 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
751
    // ensure they are closed over in the order defined in the outer scope (mainly to agree with CPython)
Damien's avatar
Damien committed
752
753
    int nfree = 0;
    if (comp->scope_cur->kind != SCOPE_MODULE) {
754
755
756
757
758
759
        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
760
#if MICROPY_EMIT_CPYTHON
761
                        EMIT(load_closure, id->qstr, id->local_num);
Damien George's avatar
Damien George committed
762
763
764
765
#else
                        // in Micro Python we load closures using LOAD_FAST
                        EMIT(load_fast, id->qstr, id->local_num);
#endif
766
767
768
                        nfree += 1;
                    }
                }
Damien's avatar
Damien committed
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
            }
        }
    }
    if (nfree > 0) {
        EMIT(build_tuple, nfree);
    }

    // make the function/closure
    if (nfree == 0) {
        EMIT(make_function, this_scope, n_dict_params, n_default_params);
    } else {
        EMIT(make_closure, this_scope, n_dict_params, n_default_params);
    }
}

784
785
786
787
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
788
789
790
791
792
            // 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) {
793
                    EMIT(load_const_id, MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]));
Damien's avatar
Damien committed
794
795
796
797
798
799
800
801
802
                    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]);
                }
            }
        }
803
804
805
    } 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
806
807
808
809
810
811
812
813
            // bare star
            comp->have_bare_star = true;
        }
    }
}

// leaves function object on stack
// returns function name
814
qstr compile_funcdef_helper(compiler_t *comp, mp_parse_node_struct_t *pns, uint emit_options) {
Damien's avatar
Damien committed
815
816
    if (comp->pass == PASS_1) {
        // create a new scope for this function
817
        scope_t *s = scope_new_and_link(comp, SCOPE_FUNCTION, (mp_parse_node_t)pns, emit_options);
Damien's avatar
Damien committed
818
        // store the function scope so the compiling function can use it at each pass
819
        pns->nodes[4] = (mp_parse_node_t)s;
Damien's avatar
Damien committed
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
    }

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

    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
    EMIT(load_const_id, cscope->simple_name);

    // nodes[1] has parent classes, if any
878
    if (MP_PARSE_NODE_IS_NULL(pns->nodes[1])) {
Damien's avatar
Damien committed
879
880
881
882
883
884
885
886
887
888
889
890
891
        // no parent classes
        EMIT(call_function, 2, 0, false, false);
    } 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]);
        EMIT(call_function, 2 + list_len(pns->nodes[1], PN_arglist), 0, false, false);
    }

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

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

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

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

    return true;
}

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

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

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

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

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

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

    // store func/class object into name
982
    EMIT(store_id, body_name);
Damien's avatar
Damien committed
983
984
}

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

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

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

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

1027
        if (!MP_PARSE_NODE_IS_NULL(pns->nodes[2])) {
Damien's avatar
Damien committed
1028
1029
1030
            // SyntaxError, cannot delete
            assert(0);
        }
1031
1032
1033
1034
    } 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
1035
1036
            // TODO perhaps factorise testlist_comp code with other uses of PN_testlist_comp

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

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

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

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

1095
void compile_return_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
Damien's avatar
Damien committed
1096
1097
1098
1099
1100
    if (comp->scope_cur->kind != SCOPE_FUNCTION) {
        printf("SyntaxError: 'return' outside function\n");
        comp->had_error = true;
        return;
    }
1101
    if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {
Damien's avatar
Damien committed
1102
        // no argument to 'return', so return None
1103
1104
        EMIT(load_const_tok, MP_TOKEN_KW_NONE);
    } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_test_if_expr)) {
Damien's avatar
Damien committed
1105
        // special case when returning an if-expression; to match CPython optimisation
1106
1107
        mp_parse_node_struct_t *pns_test_if_expr = (mp_parse_node_struct_t*)pns->nodes[0];
        mp_parse_node_struct_t *pns_test_if_else = (mp_parse_node_struct_t*)pns_test_if_expr->nodes[1];
Damien's avatar
Damien committed
1108

1109
        int l_fail = comp_next_label(comp);
Damien's avatar
Damien committed
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
        c_if_cond(comp, pns_test_if_else->nodes[0], false, l_fail); // condition
        compile_node(comp, pns_test_if_expr->nodes[0]); // success value
        EMIT(return_value);
        EMIT(label_assign, l_fail);
        compile_node(comp, pns_test_if_else->nodes[1]); // failure value
    } else {
        compile_node(comp, pns->nodes[0]);
    }
    EMIT(return_value);
}

1121
void compile_yield_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
Damien's avatar
Damien committed
1122
1123
1124
1125
    compile_node(comp, pns->nodes[0]);
    EMIT(pop_top);
}

1126
1127
void compile_raise_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
    if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {
Damien's avatar
Damien committed
1128
1129
        // raise
        EMIT(raise_varargs, 0);
1130
    } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_raise_stmt_arg)) {
Damien's avatar
Damien committed
1131
        // raise x from y
1132
        pns = (mp_parse_node_struct_t*)pns->nodes[0];
Damien's avatar
Damien committed
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
        compile_node(comp, pns->nodes[0]);
        compile_node(comp, pns->nodes[1]);
        EMIT(raise_varargs, 2);
    } else {
        // raise x
        compile_node(comp, pns->nodes[0]);
        EMIT(raise_varargs, 1);
    }
}

// q1 holds the base, q2 the full name
// eg   a -> q1=q2=a
//      a.b.c -> q1=a, q2=a.b.c
1146
void do_import_name(compiler_t *comp, mp_parse_node_t pn, qstr *q1, qstr *q2) {
Damien's avatar
Damien committed
1147
    bool is_as = false;
1148
1149
    if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_dotted_as_name)) {
        mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
Damien's avatar
Damien committed
1150
        // a name of the form x as y; unwrap it
1151
        *q1 = MP_PARSE_NODE_LEAF_ARG(pns->nodes[1]);
Damien's avatar
Damien committed
1152
1153
1154
        pn = pns->nodes[0];
        is_as = true;
    }
1155
    if (MP_PARSE_NODE_IS_ID(pn)) {
Damien's avatar
Damien committed
1156
        // just a simple name
1157
        *q2 = MP_PARSE_NODE_LEAF_ARG(pn);
Damien's avatar
Damien committed
1158
1159
1160
1161
        if (!is_as) {
            *q1 = *q2;
        }
        EMIT(import_name, *q2);
1162
1163
1164
    } else if (MP_PARSE_NODE_IS_STRUCT(pn)) {
        mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
        if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_dotted_name) {
Damien's avatar
Damien committed
1165
1166
            // a name of the form a.b.c
            if (!is_as) {
1167
                *q1 = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);
Damien's avatar
Damien committed
1168
            }
1169
            int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
Damien's avatar
Damien committed
1170
1171
            int len = n - 1;
            for (int i = 0; i < n; i++) {
1172
                len += strlen(qstr_str(MP_PARSE_NODE_LEAF_ARG(pns->nodes[i])));
Damien's avatar
Damien committed
1173
1174
            }
            char *str = m_new(char, len + 1);
1175
            char *str_dest = str;
Damien's avatar
Damien committed
1176
1177
1178
            str[0] = 0;
            for (int i = 0; i < n; i++) {
                if (i > 0) {
1179
                    *str_dest++ = '.';
Damien's avatar
Damien committed
1180
                }
1181
1182
1183
1184
                const char *str_src = qstr_str(MP_PARSE_NODE_LEAF_ARG(pns->nodes[i]));
                size_t str_src_len = strlen(str_src);
                memcpy(str_dest, str_src, str_src_len);
                str_dest += str_src_len;
Damien's avatar
Damien committed
1185
            }
1186
            *str_dest = '\0';
Damien's avatar