compile.c 151 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/*
 * This file is part of the Micro Python project, http://micropython.org/
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2013, 2014 Damien P. George
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

xbe's avatar
xbe committed
27
#include <stdbool.h>
Damien's avatar
Damien committed
28
29
30
31
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>
32
#include <math.h>
Damien's avatar
Damien committed
33

34
35
36
37
38
39
#include "py/scope.h"
#include "py/emit.h"
#include "py/compile.h"
#include "py/smallint.h"
#include "py/runtime.h"
#include "py/builtin.h"
Damien's avatar
Damien committed
40
41
42
43

// TODO need to mangle __attr names

typedef enum {
44
#define DEF_RULE(rule, comp, kind, ...) PN_##rule,
45
#include "py/grammar.h"
Damien's avatar
Damien committed
46
47
#undef DEF_RULE
    PN_maximum_number_of,
48
    PN_string, // special node for non-interned string
Damien's avatar
Damien committed
49
50
} pn_kind_t;

51
52
53
54
#define EMIT(fun) (comp->emit_method_table->fun(comp->emit))
#define EMIT_ARG(fun, ...) (comp->emit_method_table->fun(comp->emit, __VA_ARGS__))
#define EMIT_INLINE_ASM(fun) (comp->emit_inline_asm_method_table->fun(comp->emit_inline_asm))
#define EMIT_INLINE_ASM_ARG(fun, ...) (comp->emit_inline_asm_method_table->fun(comp->emit_inline_asm, __VA_ARGS__))
Damien's avatar
Damien committed
55

56
// elements in this struct are ordered to make it compact
Damien's avatar
Damien committed
57
typedef struct _compiler_t {
58
    qstr source_file;
59

60
61
62
    uint8_t is_repl;
    uint8_t pass; // holds enum type pass_kind_t
    uint8_t func_arg_is_super; // used to compile special case of super() function call
63
64
65
66
67
    uint8_t have_star;

    // try to keep compiler clean from nlr
    // this is set to an exception object if we have a compile error
    mp_obj_t compile_error;
Damien's avatar
Damien committed
68

69
    uint next_label;
70

71
72
73
    uint16_t num_dict_params;
    uint16_t num_default_params;

74
75
    uint16_t break_label; // highest bit set indicates we are breaking out of a for loop
    uint16_t continue_label;
76
    uint16_t cur_except_level; // increased for SETUP_EXCEPT, SETUP_FINALLY; decreased for POP_BLOCK, POP_EXCEPT
77
    uint16_t break_continue_except_level;
Damien's avatar
Damien committed
78
79
80
81

    scope_t *scope_head;
    scope_t *scope_cur;

82
83
    emit_t *emit;                                   // current emitter
    const emit_method_table_t *emit_method_table;   // current emit method table
84
85
86

    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
87
88
} compiler_t;

89
STATIC void compile_syntax_error(compiler_t *comp, mp_parse_node_t pn, const char *msg) {
90
91
    mp_obj_t exc = mp_obj_new_exception_msg(&mp_type_SyntaxError, msg);
    // we don't have a 'block' name, so just pass the NULL qstr to indicate this
92
    if (MP_PARSE_NODE_IS_STRUCT(pn)) {
93
        mp_obj_exception_add_traceback(exc, comp->source_file, (mp_uint_t)((mp_parse_node_struct_t*)pn)->source_line, MP_QSTR_NULL);
94
    } else {
95
96
        // we don't have a line number, so just pass 0
        mp_obj_exception_add_traceback(exc, comp->source_file, 0, MP_QSTR_NULL);
97
    }
98
    comp->compile_error = exc;
99
100
}

101
#if MICROPY_COMP_MODULE_CONST
102
STATIC const mp_map_elem_t mp_constants_table[] = {
103
104
105
    #if MICROPY_PY_UCTYPES
    { MP_OBJ_NEW_QSTR(MP_QSTR_uctypes), (mp_obj_t)&mp_module_uctypes },
    #endif
106
    // Extra constants as defined by a port
107
    MICROPY_PORT_CONSTANTS
108
};
109
110
STATIC MP_DEFINE_CONST_MAP(mp_constants_map, mp_constants_table);
#endif
111

112
113
114
115
// this function is essentially a simple preprocessor
STATIC mp_parse_node_t fold_constants(compiler_t *comp, mp_parse_node_t pn, mp_map_t *consts) {
    if (0) {
        // dummy
116
#if MICROPY_COMP_CONST
117
118
119
120
121
122
123
124
125
    } else if (MP_PARSE_NODE_IS_ID(pn)) {
        // lookup identifier in table of dynamic constants
        qstr qst = MP_PARSE_NODE_LEAF_ARG(pn);
        mp_map_elem_t *elem = mp_map_lookup(consts, MP_OBJ_NEW_QSTR(qst), MP_MAP_LOOKUP);
        if (elem != NULL) {
            pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, MP_OBJ_SMALL_INT_VALUE(elem->value));
        }
#endif
    } else if (MP_PARSE_NODE_IS_STRUCT(pn)) {
126
        mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
Damien's avatar
Damien committed
127

128
129
        // fold some parse nodes before folding their arguments
        switch (MP_PARSE_NODE_STRUCT_KIND(pns)) {
130
#if MICROPY_COMP_CONST
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
            case PN_expr_stmt:
                if (!MP_PARSE_NODE_IS_NULL(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_expr_stmt_assign) {
                        if (MP_PARSE_NODE_IS_ID(pns->nodes[0])
                            && MP_PARSE_NODE_IS_STRUCT_KIND(pns1->nodes[0], PN_power)
                            && MP_PARSE_NODE_IS_ID(((mp_parse_node_struct_t*)pns1->nodes[0])->nodes[0])
                            && MP_PARSE_NODE_LEAF_ARG(((mp_parse_node_struct_t*)pns1->nodes[0])->nodes[0]) == MP_QSTR_const
                            && MP_PARSE_NODE_IS_STRUCT_KIND(((mp_parse_node_struct_t*)pns1->nodes[0])->nodes[1], PN_trailer_paren)
                            && MP_PARSE_NODE_IS_NULL(((mp_parse_node_struct_t*)pns1->nodes[0])->nodes[2])
                            ) {
                            // code to assign dynamic constants: id = const(value)

                            // get the id
                            qstr id_qstr = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);

                            // get the value
                            mp_parse_node_t pn_value = ((mp_parse_node_struct_t*)((mp_parse_node_struct_t*)pns1->nodes[0])->nodes[1])->nodes[0];
                            pn_value = fold_constants(comp, pn_value, consts);
                            if (!MP_PARSE_NODE_IS_SMALL_INT(pn_value)) {
                                compile_syntax_error(comp, (mp_parse_node_t)pns, "constant must be an integer");
                                break;
                            }
154
                            mp_int_t value = MP_PARSE_NODE_LEAF_SMALL_INT(pn_value);
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173

                            // store the value in the table of dynamic constants
                            mp_map_elem_t *elem = mp_map_lookup(consts, MP_OBJ_NEW_QSTR(id_qstr), MP_MAP_LOOKUP_ADD_IF_NOT_FOUND);
                            if (elem->value != MP_OBJ_NULL) {
                                compile_syntax_error(comp, (mp_parse_node_t)pns, "constant redefined");
                                break;
                            }
                            elem->value = MP_OBJ_NEW_SMALL_INT(value);

                            // replace const(value) with value
                            pns1->nodes[0] = pn_value;

                            // finished folding this assignment
                            return pn;
                        }
                    }
                }
                break;
#endif
174
175
            case PN_string:
                return pn;
176
177
178
179
        }

        // fold arguments
        int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
Damien's avatar
Damien committed
180
        for (int i = 0; i < n; i++) {
181
            pns->nodes[i] = fold_constants(comp, pns->nodes[i], consts);
Damien's avatar
Damien committed
182
183
        }

184
        // try to fold this parse node
185
        switch (MP_PARSE_NODE_STRUCT_KIND(pns)) {
186
187
188
189
190
191
192
193
194
195
            case PN_atom_paren:
                if (n == 1 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0])) {
                    // (int)
                    pn = pns->nodes[0];
                }
                break;

            case PN_expr:
                if (n == 2 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[1])) {
                    // int | int
196
197
                    mp_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
                    mp_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[1]);
198
199
200
201
202
203
204
                    pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 | arg1);
                }
                break;

            case PN_and_expr:
                if (n == 2 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[1])) {
                    // int & int
205
206
                    mp_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
                    mp_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[1]);
207
208
209
210
                    pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 & arg1);
                }
                break;

Damien's avatar
Damien committed
211
            case PN_shift_expr:
212
                if (n == 3 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[2])) {
213
214
                    mp_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
                    mp_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
215
                    if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_DBL_LESS)) {
216
217
218
219
                        // int << int
                        if (!(arg1 >= BITS_PER_WORD || arg0 > (MP_SMALL_INT_MAX >> arg1) || arg0 < (MP_SMALL_INT_MIN >> arg1))) {
                            pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 << arg1);
                        }
220
                    } else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_DBL_MORE)) {
221
                        // int >> int
222
223
224
225
226
                        if (arg1 >= BITS_PER_WORD) {
                            // Shifting to big amounts is underfined behavior
                            // in C and is CPU-dependent; propagate sign bit.
                            arg1 = BITS_PER_WORD - 1;
                        }
227
                        pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 >> arg1);
Damien's avatar
Damien committed
228
229
230
231
232
233
234
235
                    } else {
                        // shouldn't happen
                        assert(0);
                    }
                }
                break;

            case PN_arith_expr:
236
                // overflow checking here relies on SMALL_INT being strictly smaller than mp_int_t
237
                if (n == 3 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[2])) {
238
239
                    mp_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
                    mp_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
240
                    if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_PLUS)) {
241
                        // int + int
242
                        arg0 += arg1;
243
                    } else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_MINUS)) {
244
                        // int - int
245
                        arg0 -= arg1;
Damien's avatar
Damien committed
246
247
248
                    } else {
                        // shouldn't happen
                        assert(0);
249
                    }
250
                    if (MP_SMALL_INT_FITS(arg0)) {
251
                        //printf("%ld + %ld\n", arg0, arg1);
252
                        pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0);
Damien's avatar
Damien committed
253
254
255
256
257
                    }
                }
                break;

            case PN_term:
258
                if (n == 3 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[2])) {
259
260
                    mp_int_t arg0 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
                    mp_int_t arg1 = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[2]);
261
                    if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_STAR)) {
262
                        // int * int
263
264
                        if (!mp_small_int_mul_overflow(arg0, arg1)) {
                            arg0 *= arg1;
265
                            if (MP_SMALL_INT_FITS(arg0)) {
266
267
268
                                pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0);
                            }
                        }
269
                    } else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_SLASH)) {
270
271
                        // int / int
                        // pass
272
                    } else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_PERCENT)) {
273
                        // int%int
274
                        pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, mp_small_int_modulo(arg0, arg1));
275
                    } else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_DBL_SLASH)) {
276
                        if (arg1 != 0) {
277
                            // int // int
278
                            pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, mp_small_int_floor_divide(arg0, arg1));
279
                        }
Damien's avatar
Damien committed
280
281
282
283
284
285
286
287
                    } else {
                        // shouldn't happen
                        assert(0);
                    }
                }
                break;

            case PN_factor_2:
288
                if (MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[1])) {
289
                    mp_int_t arg = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[1]);
290
                    if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[0], MP_TOKEN_OP_PLUS)) {
291
                        // +int
292
293
                        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)) {
294
                        // -int
295
296
                        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)) {
297
                        // ~int
298
                        pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, ~arg);
Damien's avatar
Damien committed
299
300
301
302
303
304
305
306
                    } else {
                        // shouldn't happen
                        assert(0);
                    }
                }
                break;

            case PN_power:
307
308
309
                if (0) {
#if MICROPY_EMIT_CPYTHON
                } else 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])) {
310
                    // int ** x
311
                    // can overflow; enabled only to compare with CPython
312
313
                    mp_parse_node_struct_t* pns2 = (mp_parse_node_struct_t*)pns->nodes[2];
                    if (MP_PARSE_NODE_IS_SMALL_INT(pns2->nodes[0])) {
314
                        int power = MP_PARSE_NODE_LEAF_SMALL_INT(pns2->nodes[0]);
Damien's avatar
Damien committed
315
316
                        if (power >= 0) {
                            int ans = 1;
317
                            int base = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
Damien's avatar
Damien committed
318
319
320
                            for (; power > 0; power--) {
                                ans *= base;
                            }
321
                            pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, ans);
Damien's avatar
Damien committed
322
323
                        }
                    }
324
#endif
325
#if MICROPY_COMP_MODULE_CONST
326
327
328
329
330
331
332
333
334
335
336
337
                } else if (MP_PARSE_NODE_IS_ID(pns->nodes[0]) && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_trailer_period) && MP_PARSE_NODE_IS_NULL(pns->nodes[2])) {
                    // id.id
                    // look it up in constant table, see if it can be replaced with an integer
                    mp_parse_node_struct_t* pns1 = (mp_parse_node_struct_t*)pns->nodes[1];
                    assert(MP_PARSE_NODE_IS_ID(pns1->nodes[0]));
                    qstr q_base = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);
                    qstr q_attr = MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0]);
                    mp_map_elem_t *elem = mp_map_lookup((mp_map_t*)&mp_constants_map, MP_OBJ_NEW_QSTR(q_base), MP_MAP_LOOKUP);
                    if (elem != NULL) {
                        mp_obj_t dest[2];
                        mp_load_method_maybe(elem->value, q_attr, dest);
                        if (MP_OBJ_IS_SMALL_INT(dest[0]) && dest[1] == NULL) {
338
                            mp_int_t val = MP_OBJ_SMALL_INT_VALUE(dest[0]);
339
                            pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, val);
340
341
                        }
                    }
342
#endif
Damien's avatar
Damien committed
343
344
345
346
347
348
349
350
                }
                break;
        }
    }

    return pn;
}

351
STATIC void compile_trailer_paren_helper(compiler_t *comp, mp_parse_node_t pn_arglist, bool is_method_call, int n_positional_extra);
352
STATIC void compile_comprehension(compiler_t *comp, mp_parse_node_struct_t *pns, scope_kind_t kind);
353
STATIC void compile_node(compiler_t *comp, mp_parse_node_t pn);
Damien's avatar
Damien committed
354

355
STATIC uint comp_next_label(compiler_t *comp) {
356
357
358
    return comp->next_label++;
}

359
360
361
362
363
364
365
366
367
368
369
370
STATIC void compile_increase_except_level(compiler_t *comp) {
    comp->cur_except_level += 1;
    if (comp->cur_except_level > comp->scope_cur->exc_stack_size) {
        comp->scope_cur->exc_stack_size = comp->cur_except_level;
    }
}

STATIC void compile_decrease_except_level(compiler_t *comp) {
    assert(comp->cur_except_level > 0);
    comp->cur_except_level -= 1;
}

371
STATIC scope_t *scope_new_and_link(compiler_t *comp, scope_kind_t kind, mp_parse_node_t pn, uint emit_options) {
372
    scope_t *scope = scope_new(kind, pn, comp->source_file, emit_options);
Damien's avatar
Damien committed
373
374
375
376
377
378
379
380
381
382
383
384
385
386
    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;
}

387
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)) {
388
389
390
    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
391
392
393
        for (int i = 0; i < num_nodes; i++) {
            f(comp, pns->nodes[i]);
        }
394
    } else if (!MP_PARSE_NODE_IS_NULL(pn)) {
Damien's avatar
Damien committed
395
396
397
398
        f(comp, pn);
    }
}

399
STATIC int list_get(mp_parse_node_t *pn, int pn_kind, mp_parse_node_t **nodes) {
400
    if (MP_PARSE_NODE_IS_NULL(*pn)) {
Damien's avatar
Damien committed
401
402
        *nodes = NULL;
        return 0;
403
    } else if (MP_PARSE_NODE_IS_LEAF(*pn)) {
Damien's avatar
Damien committed
404
405
406
        *nodes = pn;
        return 1;
    } else {
407
408
        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
409
410
411
412
            *nodes = pn;
            return 1;
        } else {
            *nodes = pns->nodes;
413
            return MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
Damien's avatar
Damien committed
414
415
416
417
        }
    }
}

418
STATIC void compile_generic_all_nodes(compiler_t *comp, mp_parse_node_struct_t *pns) {
419
    int num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
Damien's avatar
Damien committed
420
421
422
423
424
    for (int i = 0; i < num_nodes; i++) {
        compile_node(comp, pns->nodes[i]);
    }
}

425
#if MICROPY_EMIT_CPYTHON
426
STATIC bool cpython_c_tuple_is_const(mp_parse_node_t pn) {
427
428
429
    if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_string)) {
        return true;
    }
430
    if (!MP_PARSE_NODE_IS_LEAF(pn)) {
Damien's avatar
Damien committed
431
432
        return false;
    }
433
    if (MP_PARSE_NODE_IS_ID(pn)) {
Damien's avatar
Damien committed
434
435
436
437
438
        return false;
    }
    return true;
}

439
STATIC void cpython_c_print_quoted_str(vstr_t *vstr, const char *str, uint len, bool bytes) {
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
    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, "'");
    }
}

477
STATIC void cpython_c_tuple_emit_const(compiler_t *comp, mp_parse_node_t pn, vstr_t *vstr) {
478
479
    if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_string)) {
        mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
480
        cpython_c_print_quoted_str(vstr, (const char*)pns->nodes[0], (mp_uint_t)pns->nodes[1], false);
481
482
483
        return;
    }

484
    assert(MP_PARSE_NODE_IS_LEAF(pn));
485
486
487
488
489
    if (MP_PARSE_NODE_IS_SMALL_INT(pn)) {
        vstr_printf(vstr, INT_FMT, MP_PARSE_NODE_LEAF_SMALL_INT(pn));
        return;
    }

490
    mp_uint_t arg = MP_PARSE_NODE_LEAF_ARG(pn);
491
492
493
494
    switch (MP_PARSE_NODE_LEAF_KIND(pn)) {
        case MP_PARSE_NODE_ID: assert(0);
        case MP_PARSE_NODE_INTEGER: vstr_printf(vstr, "%s", qstr_str(arg)); break;
        case MP_PARSE_NODE_DECIMAL: vstr_printf(vstr, "%s", qstr_str(arg)); break;
495
496
        case MP_PARSE_NODE_STRING:
        case MP_PARSE_NODE_BYTES: {
497
            mp_uint_t len;
498
499
500
501
            const byte *str = qstr_data(arg, &len);
            cpython_c_print_quoted_str(vstr, (const char*)str, len, MP_PARSE_NODE_LEAF_KIND(pn) == MP_PARSE_NODE_BYTES);
            break;
        }
502
        case MP_PARSE_NODE_TOKEN:
Damien's avatar
Damien committed
503
            switch (arg) {
504
505
506
                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;
507
                default: assert(0); // shouldn't happen
Damien's avatar
Damien committed
508
509
510
511
512
513
            }
            break;
        default: assert(0);
    }
}

514
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
515
516
    int n = 0;
    if (pns_list != NULL) {
517
        n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns_list);
Damien's avatar
Damien committed
518
519
520
    }
    int total = n;
    bool is_const = true;
521
    if (!MP_PARSE_NODE_IS_NULL(pn)) {
Damien's avatar
Damien committed
522
        total += 1;
523
        if (!cpython_c_tuple_is_const(pn)) {
Damien's avatar
Damien committed
524
525
526
527
            is_const = false;
        }
    }
    for (int i = 0; i < n; i++) {
528
        if (!cpython_c_tuple_is_const(pns_list->nodes[i])) {
Damien's avatar
Damien committed
529
530
531
532
533
534
            is_const = false;
            break;
        }
    }
    if (total > 0 && is_const) {
        bool need_comma = false;
535
536
        vstr_t *vstr = vstr_new();
        vstr_printf(vstr, "(");
537
        if (!MP_PARSE_NODE_IS_NULL(pn)) {
538
            cpython_c_tuple_emit_const(comp, pn, vstr);
Damien's avatar
Damien committed
539
540
541
542
            need_comma = true;
        }
        for (int i = 0; i < n; i++) {
            if (need_comma) {
543
                vstr_printf(vstr, ", ");
Damien's avatar
Damien committed
544
            }
545
            cpython_c_tuple_emit_const(comp, pns_list->nodes[i], vstr);
Damien's avatar
Damien committed
546
547
548
            need_comma = true;
        }
        if (total == 1) {
549
            vstr_printf(vstr, ",)");
Damien's avatar
Damien committed
550
        } else {
551
            vstr_printf(vstr, ")");
Damien's avatar
Damien committed
552
        }
553
        EMIT_ARG(load_const_verbatim_str, vstr_str(vstr));
554
        vstr_free(vstr);
Damien's avatar
Damien committed
555
    } else {
556
        if (!MP_PARSE_NODE_IS_NULL(pn)) {
Damien's avatar
Damien committed
557
558
559
560
561
            compile_node(comp, pn);
        }
        for (int i = 0; i < n; i++) {
            compile_node(comp, pns_list->nodes[i]);
        }
562
        EMIT_ARG(build_tuple, total);
Damien's avatar
Damien committed
563
564
    }
}
565
566
567
#endif

// funnelling all tuple creations through this function is purely so we can optionally agree with CPython
568
STATIC void c_tuple(compiler_t *comp, mp_parse_node_t pn, mp_parse_node_struct_t *pns_list) {
569
#if MICROPY_EMIT_CPYTHON
570
571
572
    cpython_c_tuple(comp, pn, pns_list);
#else
    int total = 0;
573
    if (!MP_PARSE_NODE_IS_NULL(pn)) {
574
575
576
577
        compile_node(comp, pn);
        total += 1;
    }
    if (pns_list != NULL) {
578
        int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns_list);
579
580
581
582
583
        for (int i = 0; i < n; i++) {
            compile_node(comp, pns_list->nodes[i]);
        }
        total += n;
    }
584
    EMIT_ARG(build_tuple, total);
585
586
#endif
}
Damien's avatar
Damien committed
587

588
STATIC void compile_generic_tuple(compiler_t *comp, mp_parse_node_struct_t *pns) {
Damien's avatar
Damien committed
589
    // a simple tuple expression
590
    c_tuple(comp, MP_PARSE_NODE_NULL, pns);
Damien's avatar
Damien committed
591
592
}

593
STATIC bool node_is_const_false(mp_parse_node_t pn) {
594
595
    return MP_PARSE_NODE_IS_TOKEN_KIND(pn, MP_TOKEN_KW_FALSE)
        || (MP_PARSE_NODE_IS_SMALL_INT(pn) && MP_PARSE_NODE_LEAF_SMALL_INT(pn) == 0);
Damien's avatar
Damien committed
596
597
}

598
STATIC bool node_is_const_true(mp_parse_node_t pn) {
599
600
    return MP_PARSE_NODE_IS_TOKEN_KIND(pn, MP_TOKEN_KW_TRUE)
        || (MP_PARSE_NODE_IS_SMALL_INT(pn) && MP_PARSE_NODE_LEAF_SMALL_INT(pn) != 0);
Damien's avatar
Damien committed
601
602
}

603
#if MICROPY_EMIT_CPYTHON
604
// the is_nested variable is purely to match with CPython, which doesn't fully optimise not's
605
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
606
607
    if (node_is_const_false(pn)) {
        if (jump_if == false) {
608
            EMIT_ARG(jump, label);
Damien's avatar
Damien committed
609
610
611
612
        }
        return;
    } else if (node_is_const_true(pn)) {
        if (jump_if == true) {
613
            EMIT_ARG(jump, label);
Damien's avatar
Damien committed
614
615
        }
        return;
616
617
618
619
    } 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
620
            if (jump_if == false) {
621
                uint label2 = comp_next_label(comp);
Damien's avatar
Damien committed
622
                for (int i = 0; i < n - 1; i++) {
623
                    cpython_c_if_cond(comp, pns->nodes[i], true, label2, true);
Damien's avatar
Damien committed
624
                }
625
                cpython_c_if_cond(comp, pns->nodes[n - 1], false, label, true);
626
                EMIT_ARG(label_assign, label2);
Damien's avatar
Damien committed
627
628
            } else {
                for (int i = 0; i < n; i++) {
629
                    cpython_c_if_cond(comp, pns->nodes[i], true, label, true);
Damien's avatar
Damien committed
630
631
632
                }
            }
            return;
633
        } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_and_test) {
Damien's avatar
Damien committed
634
635
            if (jump_if == false) {
                for (int i = 0; i < n; i++) {
636
                    cpython_c_if_cond(comp, pns->nodes[i], false, label, true);
Damien's avatar
Damien committed
637
638
                }
            } else {
639
                uint label2 = comp_next_label(comp);
Damien's avatar
Damien committed
640
                for (int i = 0; i < n - 1; i++) {
641
                    cpython_c_if_cond(comp, pns->nodes[i], false, label2, true);
Damien's avatar
Damien committed
642
                }
643
                cpython_c_if_cond(comp, pns->nodes[n - 1], true, label, true);
644
                EMIT_ARG(label_assign, label2);
Damien's avatar
Damien committed
645
646
            }
            return;
647
        } else if (!is_nested && MP_PARSE_NODE_STRUCT_KIND(pns) == PN_not_test_2) {
648
            cpython_c_if_cond(comp, pns->nodes[0], !jump_if, label, true);
Damien's avatar
Damien committed
649
650
651
652
653
654
655
            return;
        }
    }

    // nothing special, fall back to default compiling for node and jump
    compile_node(comp, pn);
    if (jump_if == false) {
656
        EMIT_ARG(pop_jump_if_false, label);
Damien's avatar
Damien committed
657
    } else {
658
        EMIT_ARG(pop_jump_if_true, label);
Damien's avatar
Damien committed
659
660
    }
}
661
#endif
Damien's avatar
Damien committed
662

663
STATIC void c_if_cond(compiler_t *comp, mp_parse_node_t pn, bool jump_if, int label) {
664
#if MICROPY_EMIT_CPYTHON
665
666
667
668
    cpython_c_if_cond(comp, pn, jump_if, label, false);
#else
    if (node_is_const_false(pn)) {
        if (jump_if == false) {
669
            EMIT_ARG(jump, label);
670
671
672
673
        }
        return;
    } else if (node_is_const_true(pn)) {
        if (jump_if == true) {
674
            EMIT_ARG(jump, label);
675
676
        }
        return;
677
678
679
680
    } 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) {
681
            if (jump_if == false) {
682
                uint label2 = comp_next_label(comp);
683
684
685
686
                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);
687
                EMIT_ARG(label_assign, label2);
688
689
690
691
692
693
            } else {
                for (int i = 0; i < n; i++) {
                    c_if_cond(comp, pns->nodes[i], true, label);
                }
            }
            return;
694
        } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_and_test) {
695
696
697
698
699
            if (jump_if == false) {
                for (int i = 0; i < n; i++) {
                    c_if_cond(comp, pns->nodes[i], false, label);
                }
            } else {
700
                uint label2 = comp_next_label(comp);
701
702
703
704
                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);
705
                EMIT_ARG(label_assign, label2);
706
707
            }
            return;
708
        } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_not_test_2) {
709
710
            c_if_cond(comp, pns->nodes[0], !jump_if, label);
            return;
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
        } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_atom_paren) {
            // cond is something in parenthesis
            if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {
                // empty tuple, acts as false for the condition
                if (jump_if == false) {
                    EMIT_ARG(jump, label);
                }
            } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp)) {
                // non-empty tuple, acts as true for the condition
                if (jump_if == true) {
                    EMIT_ARG(jump, label);
                }
            } else {
                // parenthesis around 1 item, is just that item
                c_if_cond(comp, pns->nodes[0], jump_if, label);
            }
            return;
728
729
730
731
732
733
        }
    }

    // nothing special, fall back to default compiling for node and jump
    compile_node(comp, pn);
    if (jump_if == false) {
734
        EMIT_ARG(pop_jump_if_false, label);
735
    } else {
736
        EMIT_ARG(pop_jump_if_true, label);
737
738
    }
#endif
Damien's avatar
Damien committed
739
740
741
}

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

744
STATIC void c_assign_power(compiler_t *comp, mp_parse_node_struct_t *pns, assign_kind_t assign_kind) {
Damien's avatar
Damien committed
745
746
747
748
    if (assign_kind != ASSIGN_AUG_STORE) {
        compile_node(comp, pns->nodes[0]);
    }

749
750
751
752
    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
753
754
755
756
757
            if (assign_kind != ASSIGN_AUG_STORE) {
                for (int i = 0; i < n - 1; i++) {
                    compile_node(comp, pns1->nodes[i]);
                }
            }
758
759
            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
760
        }
761
        if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_trailer_paren) {
762
            goto cannot_assign;
763
        } else if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_trailer_bracket) {
Damien's avatar
Damien committed
764
765
766
767
768
769
770
            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);
771
                    EMIT(load_subscr);
Damien's avatar
Damien committed
772
773
774
775
                } else {
                    EMIT(store_subscr);
                }
            }
776
777
        } 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
778
779
            if (assign_kind == ASSIGN_AUG_LOAD) {
                EMIT(dup_top);
780
                EMIT_ARG(load_attr, MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0]));
Damien's avatar
Damien committed
781
782
783
784
            } else {
                if (assign_kind == ASSIGN_AUG_STORE) {
                    EMIT(rot_two);
                }
785
                EMIT_ARG(store_attr, MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0]));
Damien's avatar
Damien committed
786
787
            }
        } else {
788
            goto cannot_assign;
Damien's avatar
Damien committed
789
790
        }
    } else {
791
        goto cannot_assign;
Damien's avatar
Damien committed
792
793
    }

794
    if (!MP_PARSE_NODE_IS_NULL(pns->nodes[2])) {
795
        goto cannot_assign;
Damien's avatar
Damien committed
796
    }
797
798
799
800
801

    return;

cannot_assign:
    compile_syntax_error(comp, (mp_parse_node_t)pns, "can't assign to expression");
Damien's avatar
Damien committed
802
803
}

804
// we need to allow for a caller passing in 1 initial node (node_head) followed by an array of nodes (nodes_tail)
805
STATIC void c_assign_tuple(compiler_t *comp, mp_parse_node_t node_head, uint num_tail, mp_parse_node_t *nodes_tail) {
806
807
808
    uint num_head = (node_head == MP_PARSE_NODE_NULL) ? 0 : 1;

    // look for star expression
Damien's avatar
Damien committed
809
    int have_star_index = -1;
810
811
812
813
814
815
    if (num_head != 0 && MP_PARSE_NODE_IS_STRUCT_KIND(node_head, PN_star_expr)) {
        EMIT_ARG(unpack_ex, 0, num_tail);
        have_star_index = 0;
    }
    for (int i = 0; i < num_tail; i++) {
        if (MP_PARSE_NODE_IS_STRUCT_KIND(nodes_tail[i], PN_star_expr)) {
Damien's avatar
Damien committed
816
            if (have_star_index < 0) {
817
818
                EMIT_ARG(unpack_ex, num_head + i, num_tail - i - 1);
                have_star_index = num_head + i;
Damien's avatar
Damien committed
819
            } else {
820
                compile_syntax_error(comp, nodes_tail[i], "multiple *x in assignment");
Damien's avatar
Damien committed
821
822
823
824
825
                return;
            }
        }
    }
    if (have_star_index < 0) {
826
        EMIT_ARG(unpack_sequence, num_head + num_tail);
Damien's avatar
Damien committed
827
    }
828
829
830
    if (num_head != 0) {
        if (0 == have_star_index) {
            c_assign(comp, ((mp_parse_node_struct_t*)node_head)->nodes[0], ASSIGN_STORE);
Damien's avatar
Damien committed
831
        } else {
832
833
834
835
836
837
838
839
            c_assign(comp, node_head, ASSIGN_STORE);
        }
    }
    for (int i = 0; i < num_tail; i++) {
        if (num_head + i == have_star_index) {
            c_assign(comp, ((mp_parse_node_struct_t*)nodes_tail[i])->nodes[0], ASSIGN_STORE);
        } else {
            c_assign(comp, nodes_tail[i], ASSIGN_STORE);
Damien's avatar
Damien committed
840
841
842
843
844
        }
    }
}

// assigns top of stack to pn
845
STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_kind) {
Damien's avatar
Damien committed
846
    tail_recursion:
847
    if (MP_PARSE_NODE_IS_NULL(pn)) {
Damien's avatar
Damien committed
848
        assert(0);
849
850
    } else if (MP_PARSE_NODE_IS_LEAF(pn)) {
        if (MP_PARSE_NODE_IS_ID(pn)) {
851
            qstr arg = MP_PARSE_NODE_LEAF_ARG(pn);
Damien's avatar
Damien committed
852
853
854
            switch (assign_kind) {
                case ASSIGN_STORE:
                case ASSIGN_AUG_STORE:
855
                    EMIT_ARG(store_id, arg);
Damien's avatar
Damien committed
856
857
                    break;
                case ASSIGN_AUG_LOAD:
858
                    EMIT_ARG(load_id, arg);
Damien's avatar
Damien committed
859
860
861
                    break;
            }
        } else {
862
            compile_syntax_error(comp, pn, "can't assign to literal");
Damien's avatar
Damien committed
863
864
865
            return;
        }
    } else {
866
867
        mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
        switch (MP_PARSE_NODE_STRUCT_KIND(pns)) {
Damien's avatar
Damien committed
868
869
870
871
872
873
874
875
876
877
878
            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;
                }
879
                c_assign_tuple(comp, MP_PARSE_NODE_NULL, MP_PARSE_NODE_STRUCT_NUM_NODES(pns), pns->nodes);
Damien's avatar
Damien committed
880
881
882
883
                break;

            case PN_atom_paren:
                // lhs is something in parenthesis
884
                if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {
Damien's avatar
Damien committed
885
                    // empty tuple
886
                    goto cannot_assign;
887
888
                } 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
889
890
891
892
893
894
895
896
897
898
899
900
901
                    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;
                }
902
                if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {
Damien's avatar
Damien committed
903
                    // empty list, assignment allowed
904
                    c_assign_tuple(comp, MP_PARSE_NODE_NULL, 0, NULL);
905
906
                } 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
907
908
909
                    goto testlist_comp;
                } else {
                    // brackets around 1 item
910
                    c_assign_tuple(comp, pns->nodes[0], 0, NULL);
Damien's avatar
Damien committed
911
912
913
914
                }
                break;

            default:
915
                goto cannot_assign;
Damien's avatar
Damien committed
916
917
918
919
920
        }
        return;

        testlist_comp:
        // lhs is a sequence
921
922
923
        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
924
                // sequence of one item, with trailing comma
925
                assert(MP_PARSE_NODE_IS_NULL(pns2->nodes[0]));
926
                c_assign_tuple(comp, pns->nodes[0], 0, NULL);
927
            } else if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_testlist_comp_3c) {
Damien's avatar
Damien committed
928
                // sequence of many items
929
930
                uint n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns2);
                c_assign_tuple(comp, pns->nodes[0], n, pns2->nodes);
931
            } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_comp_for) {
932
                // TODO can we ever get here? can it be compiled?
933
                goto cannot_assign;
Damien's avatar
Damien committed
934
935
936
937
938
939
940
            } else {
                // sequence with 2 items
                goto sequence_with_2_items;
            }
        } else {
            // sequence with 2 items
            sequence_with_2_items:
941
            c_assign_tuple(comp, MP_PARSE_NODE_NULL, 2, pns->nodes);
Damien's avatar
Damien committed
942
943
944
945
946
        }
        return;
    }
    return;

947
948
949
950
    cannot_assign:
    compile_syntax_error(comp, pn, "can't assign to expression");
    return;

Damien's avatar
Damien committed
951
    bad_aug:
952
    compile_syntax_error(comp, pn, "illegal expression for augmented assignment");
Damien's avatar
Damien committed
953
954
955
}

// stuff for lambda and comprehensions and generators
956
957
958
959
// if we are not in CPython compatibility mode then:
//  if n_pos_defaults > 0 then there is a tuple on the stack with the positional defaults
//  if n_kw_defaults > 0 then there is a dictionary on the stack with the keyword defaults
//  if both exist, the tuple is above the dictionary (ie the first pop gets the tuple)
960
STATIC void close_over_variables_etc(compiler_t *comp, scope_t *this_scope, int n_pos_defaults, int n_kw_defaults) {
961
962
963
    assert(n_pos_defaults >= 0);
    assert(n_kw_defaults >= 0);

Damien's avatar
Damien committed
964
    // make closed over variables, if any
965
    // ensure they are closed over in the order defined in the outer scope (mainly to agree with CPython)
Damien's avatar
Damien committed
966
967
    int nfree = 0;
    if (comp->scope_cur->kind != SCOPE_MODULE) {
968
969
970
971
972
        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];
973
                    if (id2->kind == ID_INFO_KIND_FREE && id->qst == id2->qst) {
Damien George's avatar
Damien George committed
974
#if MICROPY_EMIT_CPYTHON
975
                        EMIT_ARG(load_closure, id->qst, id->local_num);
Damien George's avatar
Damien George committed
976
977
#else
                        // in Micro Python we load closures using LOAD_FAST
978
                        EMIT_ARG(load_fast, id->qst, id->flags, id->local_num);
Damien George's avatar
Damien George committed
979
#endif
980
981
982
                        nfree += 1;
                    }
                }
Damien's avatar
Damien committed
983
984
985
986
987
988
            }
        }
    }

    // make the function/closure
    if (nfree == 0) {
989
        EMIT_ARG(make_function, this_scope, n_pos_defaults, n_kw_defaults);
Damien's avatar
Damien committed
990
    } else {
991
        EMIT_ARG(make_closure, this_scope, nfree, n_pos_defaults, n_kw_defaults);
Damien's avatar
Damien committed
992
993
994
    }
}

995
STATIC void compile_funcdef_param(compiler_t *comp, mp_parse_node_t pn) {
996
    if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_typedargslist_star)) {