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 {
Damien's avatar
Damien committed
42
    bool is_repl;
Damien's avatar
Damien committed
43
    pass_kind_t pass;
Damien's avatar
Damien committed
44
    bool had_error; // try to keep compiler clean from nlr
Damien's avatar
Damien committed
45

46
47
    int next_label;

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

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

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

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

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

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

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

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

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

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

    return pn;
}

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

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

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

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

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

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

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

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

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

274
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
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, "'");
    }
}

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

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

// funnelling all tuple creations through this function is purely so we can optionally agree with CPython
390
void c_tuple(compiler_t *comp, mp_parse_node_t pn, mp_parse_node_struct_t *pns_list) {
391
#if MICROPY_EMIT_CPYTHON
392
393
394
    cpython_c_tuple(comp, pn, pns_list);
#else
    int total = 0;
395
    if (!MP_PARSE_NODE_IS_NULL(pn)) {
396
397
398
399
        compile_node(comp, pn);
        total += 1;
    }
    if (pns_list != NULL) {
400
        int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns_list);
401
402
403
404
405
406
407
408
        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
409

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

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

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

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

484
static void c_if_cond(compiler_t *comp, mp_parse_node_t pn, bool jump_if, int label) {
485
#if MICROPY_EMIT_CPYTHON
486
487
488
489
490
491
492
493
494
495
496
497
    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;
498
499
500
501
    } 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) {
502
503
504
505
506
507
508
509
510
511
512
513
514
            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;
515
        } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_and_test) {
516
517
518
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);
                EMIT(label_assign, label2);
            }
            return;
529
        } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_not_test_2) {
530
531
532
533
534
535
536
537
538
539
540
541
542
            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
543
544
545
}

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

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

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

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

607
void c_assign_tuple(compiler_t *comp, int n, mp_parse_node_t *nodes) {
Damien's avatar
Damien committed
608
609
610
    assert(n >= 0);
    int have_star_index = -1;
    for (int i = 0; i < n; i++) {
611
        if (MP_PARSE_NODE_IS_STRUCT_KIND(nodes[i], PN_star_expr)) {
Damien's avatar
Damien committed
612
613
614
615
616
617
618
619
620
621
622
623
624
625
            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) {
626
            c_assign(comp, ((mp_parse_node_struct_t*)nodes[i])->nodes[0], ASSIGN_STORE);
Damien's avatar
Damien committed
627
628
629
630
631
632
633
        } else {
            c_assign(comp, nodes[i], ASSIGN_STORE);
        }
    }
}

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

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

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

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

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

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

    // 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
857
qstr compile_classdef_helper(compiler_t *comp, mp_parse_node_struct_t *pns, uint emit_options) {
Damien's avatar
Damien committed
858
859
    if (comp->pass == PASS_1) {
        // create a new scope for this class
860
        scope_t *s = scope_new_and_link(comp, SCOPE_CLASS, (mp_parse_node_t)pns, emit_options);
Damien's avatar
Damien committed
861
        // store the class scope so the compiling function can use it at each pass
862
        pns->nodes[3] = (mp_parse_node_t)s;
Damien's avatar
Damien committed
863
864
865
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
    EMIT(load_const_id, cscope->simple_name);

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

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

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

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

    return true;
}

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

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

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

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

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

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

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

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

990
991
992
993
994
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
995
996
997

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

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

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

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

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

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

1083
void compile_continue_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
Damien's avatar
Damien committed
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
    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);
    }
}

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

1108
        int l_fail = comp_next_label(comp);
Damien's avatar
Damien committed
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
        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);
}

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

1125
1126
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
1127
1128
        // raise
        EMIT(raise_varargs, 0);
1129
    } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_raise_stmt_arg)) {
Damien's avatar
Damien committed
1130
        // raise x from y
1131
        pns = (mp_parse_node_struct_t*)pns->nodes[0];
Damien's avatar
Damien committed
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
        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
1145
void do_import_name(compiler_t *comp, mp_parse_node_t pn, qstr *q1, qstr *q2) {
Damien's avatar
Damien committed
1146
    bool is_as = false;
1147
1148
    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
1149
        // a name of the form x as y; unwrap it
1150
        *q1 = MP_PARSE_NODE_LEAF_ARG(pns->nodes[1]);
Damien's avatar
Damien committed
1151
1152
1153
        pn = pns->nodes[0];
        is_as = true;
    }
1154
    if (MP_PARSE_NODE_IS_ID(pn)) {
Damien's avatar
Damien committed
1155
        // just a simple name
1156
        *q2 = MP_PARSE_NODE_LEAF_ARG(pn);
Damien's avatar
Damien committed
1157
1158
1159
1160
        if (!is_as) {
            *q1 = *q2;
        }
        EMIT(import_name, *q2);
1161
1162
1163
    } 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
1164
1165
            // a name of the form a.b.c
            if (!is_as) {
1166
                *q1 = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);
Damien's avatar
Damien committed
1167
            }
1168
            int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
Damien's avatar
Damien committed
1169
1170
            int len = n - 1;
            for (int i = 0; i < n; i++) {
1171
                len += strlen(qstr_str(MP_PARSE_NODE_LEAF_ARG(pns->nodes[i])));
Damien's avatar
Damien committed
1172
1173
            }
            char *str = m_new(char, len + 1);
1174
            char *str_dest = str;
Damien's avatar
Damien committed
1175
1176
1177
            str[0] = 0;
            for (int i = 0; i < n; i++) {
                if (i > 0) {
1178
                    *str_dest++ = '.';
Damien's avatar
Damien committed
1179
                }
1180
1181
1182
1183
                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
1184
            }
1185
            *str_dest = '\0';
1186
            *q2 = qstr_from_str_take(str, len + 1);
Damien's avatar