compile.c 152 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
49
    PN_bytes, // special node for non-interned bytes
50
    PN_const_object, // special node for a constant, generic Python object
Damien's avatar
Damien committed
51
52
} pn_kind_t;

53
54
55
56
#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
57

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

62
63
64
    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
65
66
67
68
69
    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
70

71
    uint next_label;
72

73
74
75
    uint16_t num_dict_params;
    uint16_t num_default_params;

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

    scope_t *scope_head;
    scope_t *scope_cur;

84
85
    emit_t *emit;                                   // current emitter
    const emit_method_table_t *emit_method_table;   // current emit method table
86
87
88

    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
89
90
} compiler_t;

91
STATIC void compile_syntax_error(compiler_t *comp, mp_parse_node_t pn, const char *msg) {
92
93
    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
94
    if (MP_PARSE_NODE_IS_STRUCT(pn)) {
95
        mp_obj_exception_add_traceback(exc, comp->source_file, (mp_uint_t)((mp_parse_node_struct_t*)pn)->source_line, MP_QSTR_NULL);
96
    } else {
97
98
        // we don't have a line number, so just pass 0
        mp_obj_exception_add_traceback(exc, comp->source_file, 0, MP_QSTR_NULL);
99
    }
100
    comp->compile_error = exc;
101
102
}

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

114
115
116
117
// 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
118
#if MICROPY_COMP_CONST
119
120
121
122
123
124
125
126
127
    } 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)) {
128
        mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
Damien's avatar
Damien committed
129

130
131
        // fold some parse nodes before folding their arguments
        switch (MP_PARSE_NODE_STRUCT_KIND(pns)) {
132
#if MICROPY_COMP_CONST
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
            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;
                            }
156
                            mp_int_t value = MP_PARSE_NODE_LEAF_SMALL_INT(pn_value);
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175

                            // 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
176
            case PN_string:
177
            case PN_bytes:
178
            case PN_const_object:
179
                return pn;
180
181
182
183
        }

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

188
        // try to fold this parse node
189
        switch (MP_PARSE_NODE_STRUCT_KIND(pns)) {
190
191
192
193
194
195
196
197
198
199
            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
200
201
                    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]);
202
203
204
205
206
207
208
                    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
209
210
                    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]);
211
212
213
214
                    pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 & arg1);
                }
                break;

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

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

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

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

            case PN_power:
311
312
313
                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])) {
314
                    // int ** x
315
                    // can overflow; enabled only to compare with CPython
316
317
                    mp_parse_node_struct_t* pns2 = (mp_parse_node_struct_t*)pns->nodes[2];
                    if (MP_PARSE_NODE_IS_SMALL_INT(pns2->nodes[0])) {
318
                        int power = MP_PARSE_NODE_LEAF_SMALL_INT(pns2->nodes[0]);
Damien's avatar
Damien committed
319
320
                        if (power >= 0) {
                            int ans = 1;
321
                            int base = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[0]);
Damien's avatar
Damien committed
322
323
324
                            for (; power > 0; power--) {
                                ans *= base;
                            }
325
                            pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, ans);
Damien's avatar
Damien committed
326
327
                        }
                    }
328
#endif
329
#if MICROPY_COMP_MODULE_CONST
330
331
332
333
334
335
336
337
338
339
340
341
                } 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) {
342
                            mp_int_t val = MP_OBJ_SMALL_INT_VALUE(dest[0]);
343
                            pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, val);
344
345
                        }
                    }
346
#endif
Damien's avatar
Damien committed
347
348
349
350
351
352
353
354
                }
                break;
        }
    }

    return pn;
}

355
STATIC void compile_trailer_paren_helper(compiler_t *comp, mp_parse_node_t pn_arglist, bool is_method_call, int n_positional_extra);
356
STATIC void compile_comprehension(compiler_t *comp, mp_parse_node_struct_t *pns, scope_kind_t kind);
357
STATIC void compile_node(compiler_t *comp, mp_parse_node_t pn);
Damien's avatar
Damien committed
358

359
STATIC uint comp_next_label(compiler_t *comp) {
360
361
362
    return comp->next_label++;
}

363
364
365
366
367
368
369
370
371
372
373
374
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;
}

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

391
392
STATIC void apply_to_single_or_list(compiler_t *comp, mp_parse_node_t pn, pn_kind_t pn_list_kind, void (*f)(compiler_t*, mp_parse_node_t)) {
    if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, pn_list_kind)) {
393
394
        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
395
396
397
        for (int i = 0; i < num_nodes; i++) {
            f(comp, pns->nodes[i]);
        }
398
    } else if (!MP_PARSE_NODE_IS_NULL(pn)) {
Damien's avatar
Damien committed
399
400
401
402
        f(comp, pn);
    }
}

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

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

429
#if MICROPY_EMIT_CPYTHON
430
STATIC bool cpython_c_tuple_is_const(mp_parse_node_t pn) {
431
432
433
    if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_string)) {
        return true;
    }
434
435
436
    if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_bytes)) {
        return true;
    }
437
438
439
    if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_const_object)) {
        return true;
    }
440
    if (!MP_PARSE_NODE_IS_LEAF(pn)) {
Damien's avatar
Damien committed
441
442
        return false;
    }
443
    if (MP_PARSE_NODE_IS_ID(pn)) {
Damien's avatar
Damien committed
444
445
446
447
448
        return false;
    }
    return true;
}

449
STATIC void cpython_c_print_quoted_str(vstr_t *vstr, const char *str, uint len, bool bytes) {
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
477
478
479
480
481
482
483
484
485
486
    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, "'");
    }
}

487
STATIC void cpython_c_tuple_emit_const(compiler_t *comp, mp_parse_node_t pn, vstr_t *vstr) {
488
    if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_string) || MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_bytes)) {
489
        mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
490
        cpython_c_print_quoted_str(vstr, (const char*)pns->nodes[0], (mp_uint_t)pns->nodes[1], MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_bytes));
491
492
493
        return;
    }

494
495
496
497
498
499
    if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_const_object)) {
        mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
        mp_obj_print((mp_obj_t)pns->nodes[0], PRINT_REPR);
        return;
    }

500
    assert(MP_PARSE_NODE_IS_LEAF(pn));
501
502
503
504
505
    if (MP_PARSE_NODE_IS_SMALL_INT(pn)) {
        vstr_printf(vstr, INT_FMT, MP_PARSE_NODE_LEAF_SMALL_INT(pn));
        return;
    }

506
    mp_uint_t arg = MP_PARSE_NODE_LEAF_ARG(pn);
507
508
    switch (MP_PARSE_NODE_LEAF_KIND(pn)) {
        case MP_PARSE_NODE_ID: assert(0);
509
510
        case MP_PARSE_NODE_STRING:
        case MP_PARSE_NODE_BYTES: {
511
            mp_uint_t len;
512
513
514
515
            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;
        }
516
        case MP_PARSE_NODE_TOKEN:
Damien's avatar
Damien committed
517
            switch (arg) {
518
519
520
                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;
521
                default: assert(0); // shouldn't happen
Damien's avatar
Damien committed
522
523
524
525
526
527
            }
            break;
        default: assert(0);
    }
}

528
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
529
530
    int n = 0;
    if (pns_list != NULL) {
531
        n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns_list);
Damien's avatar
Damien committed
532
533
534
    }
    int total = n;
    bool is_const = true;
535
    if (!MP_PARSE_NODE_IS_NULL(pn)) {
Damien's avatar
Damien committed
536
        total += 1;
537
        if (!cpython_c_tuple_is_const(pn)) {
Damien's avatar
Damien committed
538
539
540
541
            is_const = false;
        }
    }
    for (int i = 0; i < n; i++) {
542
        if (!cpython_c_tuple_is_const(pns_list->nodes[i])) {
Damien's avatar
Damien committed
543
544
545
546
547
548
            is_const = false;
            break;
        }
    }
    if (total > 0 && is_const) {
        bool need_comma = false;
549
550
        vstr_t *vstr = vstr_new();
        vstr_printf(vstr, "(");
551
        if (!MP_PARSE_NODE_IS_NULL(pn)) {
552
            cpython_c_tuple_emit_const(comp, pn, vstr);
Damien's avatar
Damien committed
553
554
555
556
            need_comma = true;
        }
        for (int i = 0; i < n; i++) {
            if (need_comma) {
557
                vstr_printf(vstr, ", ");
Damien's avatar
Damien committed
558
            }
559
            cpython_c_tuple_emit_const(comp, pns_list->nodes[i], vstr);
Damien's avatar
Damien committed
560
561
562
            need_comma = true;
        }
        if (total == 1) {
563
            vstr_printf(vstr, ",)");
Damien's avatar
Damien committed
564
        } else {
565
            vstr_printf(vstr, ")");
Damien's avatar
Damien committed
566
        }
567
        EMIT_ARG(load_const_verbatim_strn, vstr_str(vstr), vstr_len(vstr));
568
        vstr_free(vstr);
Damien's avatar
Damien committed
569
    } else {
570
        if (!MP_PARSE_NODE_IS_NULL(pn)) {
Damien's avatar
Damien committed
571
572
573
574
575
            compile_node(comp, pn);
        }
        for (int i = 0; i < n; i++) {
            compile_node(comp, pns_list->nodes[i]);
        }
576
        EMIT_ARG(build_tuple, total);
Damien's avatar
Damien committed
577
578
    }
}
579
580
581
#endif

// funnelling all tuple creations through this function is purely so we can optionally agree with CPython
582
STATIC void c_tuple(compiler_t *comp, mp_parse_node_t pn, mp_parse_node_struct_t *pns_list) {
583
#if MICROPY_EMIT_CPYTHON
584
585
586
    cpython_c_tuple(comp, pn, pns_list);
#else
    int total = 0;
587
    if (!MP_PARSE_NODE_IS_NULL(pn)) {
588
589
590
591
        compile_node(comp, pn);
        total += 1;
    }
    if (pns_list != NULL) {
592
        int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns_list);
593
594
595
596
597
        for (int i = 0; i < n; i++) {
            compile_node(comp, pns_list->nodes[i]);
        }
        total += n;
    }
598
    EMIT_ARG(build_tuple, total);
599
600
#endif
}
Damien's avatar
Damien committed
601

602
STATIC void compile_generic_tuple(compiler_t *comp, mp_parse_node_struct_t *pns) {
Damien's avatar
Damien committed
603
    // a simple tuple expression
604
    c_tuple(comp, MP_PARSE_NODE_NULL, pns);
Damien's avatar
Damien committed
605
606
}

607
STATIC bool node_is_const_false(mp_parse_node_t pn) {
608
609
    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
610
611
}

612
STATIC bool node_is_const_true(mp_parse_node_t pn) {
613
614
    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
615
616
}

617
#if MICROPY_EMIT_CPYTHON
618
// the is_nested variable is purely to match with CPython, which doesn't fully optimise not's
619
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
620
621
    if (node_is_const_false(pn)) {
        if (jump_if == false) {
622
            EMIT_ARG(jump, label);
Damien's avatar
Damien committed
623
624
625
626
        }
        return;
    } else if (node_is_const_true(pn)) {
        if (jump_if == true) {
627
            EMIT_ARG(jump, label);
Damien's avatar
Damien committed
628
629
        }
        return;
630
631
632
633
    } 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
634
            if (jump_if == false) {
635
                uint label2 = comp_next_label(comp);
Damien's avatar
Damien committed
636
                for (int i = 0; i < n - 1; i++) {
637
                    cpython_c_if_cond(comp, pns->nodes[i], true, label2, true);
Damien's avatar
Damien committed
638
                }
639
                cpython_c_if_cond(comp, pns->nodes[n - 1], false, label, true);
640
                EMIT_ARG(label_assign, label2);
Damien's avatar
Damien committed
641
642
            } else {
                for (int i = 0; i < n; i++) {
643
                    cpython_c_if_cond(comp, pns->nodes[i], true, label, true);
Damien's avatar
Damien committed
644
645
646
                }
            }
            return;
647
        } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_and_test) {
Damien's avatar
Damien committed
648
649
            if (jump_if == false) {
                for (int i = 0; i < n; i++) {
650
                    cpython_c_if_cond(comp, pns->nodes[i], false, label, true);
Damien's avatar
Damien committed
651
652
                }
            } else {
653
                uint label2 = comp_next_label(comp);
Damien's avatar
Damien committed
654
                for (int i = 0; i < n - 1; i++) {
655
                    cpython_c_if_cond(comp, pns->nodes[i], false, label2, true);
Damien's avatar
Damien committed
656
                }
657
                cpython_c_if_cond(comp, pns->nodes[n - 1], true, label, true);
658
                EMIT_ARG(label_assign, label2);
Damien's avatar
Damien committed
659
660
            }
            return;
661
        } else if (!is_nested && MP_PARSE_NODE_STRUCT_KIND(pns) == PN_not_test_2) {
662
            cpython_c_if_cond(comp, pns->nodes[0], !jump_if, label, true);
Damien's avatar
Damien committed
663
664
665
666
667
668
669
            return;
        }
    }

    // nothing special, fall back to default compiling for node and jump
    compile_node(comp, pn);
    if (jump_if == false) {
670
        EMIT_ARG(pop_jump_if_false, label);
Damien's avatar
Damien committed
671
    } else {
672
        EMIT_ARG(pop_jump_if_true, label);
Damien's avatar
Damien committed
673
674
    }
}
675
#endif
Damien's avatar
Damien committed
676

677
STATIC void c_if_cond(compiler_t *comp, mp_parse_node_t pn, bool jump_if, int label) {
678
#if MICROPY_EMIT_CPYTHON
679
680
681
682
    cpython_c_if_cond(comp, pn, jump_if, label, false);
#else
    if (node_is_const_false(pn)) {
        if (jump_if == false) {
683
            EMIT_ARG(jump, label);
684
685
686
687
        }
        return;
    } else if (node_is_const_true(pn)) {
        if (jump_if == true) {
688
            EMIT_ARG(jump, label);
689
690
        }
        return;
691
692
693
694
    } 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) {
695
            if (jump_if == false) {
696
                uint label2 = comp_next_label(comp);
697
698
699
700
                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);
701
                EMIT_ARG(label_assign, label2);
702
703
704
705
706
707
            } else {
                for (int i = 0; i < n; i++) {
                    c_if_cond(comp, pns->nodes[i], true, label);
                }
            }
            return;
708
        } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_and_test) {
709
710
711
712
713
            if (jump_if == false) {
                for (int i = 0; i < n; i++) {
                    c_if_cond(comp, pns->nodes[i], false, label);
                }
            } else {
714
                uint label2 = comp_next_label(comp);
715
716
717
718
                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);
719
                EMIT_ARG(label_assign, label2);
720
721
            }
            return;
722
        } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_not_test_2) {
723
724
            c_if_cond(comp, pns->nodes[0], !jump_if, label);
            return;
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
        } 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;
742
743
744
745
746
747
        }
    }

    // nothing special, fall back to default compiling for node and jump
    compile_node(comp, pn);
    if (jump_if == false) {
748
        EMIT_ARG(pop_jump_if_false, label);
749
    } else {
750
        EMIT_ARG(pop_jump_if_true, label);
751
752
    }
#endif
Damien's avatar
Damien committed
753
754
755
}

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

758
STATIC void c_assign_power(compiler_t *comp, mp_parse_node_struct_t *pns, assign_kind_t assign_kind) {
Damien's avatar
Damien committed
759
760
761
762
    if (assign_kind != ASSIGN_AUG_STORE) {
        compile_node(comp, pns->nodes[0]);
    }

763
764
765
766
    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
767
768
769
770
771
            if (assign_kind != ASSIGN_AUG_STORE) {
                for (int i = 0; i < n - 1; i++) {
                    compile_node(comp, pns1->nodes[i]);
                }
            }
772
773
            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
774
        }
775
        if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_trailer_paren) {
776
            goto cannot_assign;
777
        } else if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_trailer_bracket) {
Damien's avatar
Damien committed
778
779
780
781
782
783
784
            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);
785
                    EMIT(load_subscr);
Damien's avatar
Damien committed
786
787
788
789
                } else {
                    EMIT(store_subscr);
                }
            }
790
791
        } 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
792
793
            if (assign_kind == ASSIGN_AUG_LOAD) {
                EMIT(dup_top);
794
                EMIT_ARG(load_attr, MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0]));
Damien's avatar
Damien committed
795
796
797
798
            } else {
                if (assign_kind == ASSIGN_AUG_STORE) {
                    EMIT(rot_two);
                }
799
                EMIT_ARG(store_attr, MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0]));
Damien's avatar
Damien committed
800
801
            }
        } else {
802
            goto cannot_assign;
Damien's avatar
Damien committed
803
804
        }
    } else {
805
        goto cannot_assign;
Damien's avatar
Damien committed
806
807
    }

808
    if (!MP_PARSE_NODE_IS_NULL(pns->nodes[2])) {
809
        goto cannot_assign;
Damien's avatar
Damien committed
810
    }
811
812
813
814
815

    return;

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

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

    // look for star expression
823
    uint have_star_index = -1;
824
825
826
827
    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;
    }
828
    for (uint i = 0; i < num_tail; i++) {
829
        if (MP_PARSE_NODE_IS_STRUCT_KIND(nodes_tail[i], PN_star_expr)) {
830
            if (have_star_index == (uint)-1) {
831
832
                EMIT_ARG(unpack_ex, num_head + i, num_tail - i - 1);
                have_star_index = num_head + i;
Damien's avatar
Damien committed
833
            } else {
834
                compile_syntax_error(comp, nodes_tail[i], "multiple *x in assignment");
Damien's avatar
Damien committed
835
836
837
838
                return;
            }
        }
    }
839
    if (have_star_index == (uint)-1) {
840
        EMIT_ARG(unpack_sequence, num_head + num_tail);
Damien's avatar
Damien committed
841
    }
842
843
844
    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
845
        } else {
846
847
848
            c_assign(comp, node_head, ASSIGN_STORE);
        }
    }
849
    for (uint i = 0; i < num_tail; i++) {
850
851
852
853
        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
854
855
856
857
858
        }
    }
}

// assigns top of stack to pn
859
STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_kind) {
Damien's avatar
Damien committed
860
    tail_recursion:
861
    if (MP_PARSE_NODE_IS_NULL(pn)) {
Damien's avatar
Damien committed
862
        assert(0);
863
864
    } else if (MP_PARSE_NODE_IS_LEAF(pn)) {
        if (MP_PARSE_NODE_IS_ID(pn)) {
865
            qstr arg = MP_PARSE_NODE_LEAF_ARG(pn);
Damien's avatar
Damien committed
866
867
868
            switch (assign_kind) {
                case ASSIGN_STORE:
                case ASSIGN_AUG_STORE:
869
                    EMIT_ARG(store_id, arg);
Damien's avatar
Damien committed
870
871
                    break;
                case ASSIGN_AUG_LOAD:
872
                default:
873
                    EMIT_ARG(load_id, arg);
Damien's avatar
Damien committed
874
875
876
                    break;
            }
        } else {
877
            compile_syntax_error(comp, pn, "can't assign to literal");
Damien's avatar
Damien committed
878
879
880
            return;
        }
    } else {
881
882
        mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
        switch (MP_PARSE_NODE_STRUCT_KIND(pns)) {
Damien's avatar
Damien committed
883
884
885
886
887
888
889
890
891
892
893
            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;
                }
894
                c_assign_tuple(comp, MP_PARSE_NODE_NULL, MP_PARSE_NODE_STRUCT_NUM_NODES(pns), pns->nodes);
Damien's avatar
Damien committed
895
896
897
898
                break;

            case PN_atom_paren:
                // lhs is something in parenthesis
899
                if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {
Damien's avatar
Damien committed
900
                    // empty tuple
901
                    goto cannot_assign;
902
903
                } 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
904
905
906
907
908
909
910
911
912
913
914
915
916
                    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;
                }
917
                if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {
Damien's avatar
Damien committed
918
                    // empty list, assignment allowed
919
                    c_assign_tuple(comp, MP_PARSE_NODE_NULL, 0, NULL);
920
921
                } 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
922
923
924
                    goto testlist_comp;
                } else {
                    // brackets around 1 item
925
                    c_assign_tuple(comp, pns->nodes[0], 0, NULL);
Damien's avatar
Damien committed
926
927
928
929
                }
                break;

            default:
930
                goto cannot_assign;
Damien's avatar
Damien committed
931
932
933
934
935
        }
        return;

        testlist_comp:
        // lhs is a sequence
936
937
938
        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
939
                // sequence of one item, with trailing comma
940
                assert(MP_PARSE_NODE_IS_NULL(pns2->nodes[0]));
941
                c_assign_tuple(comp, pns->nodes[0], 0, NULL);
942
            } else if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_testlist_comp_3c) {
Damien's avatar
Damien committed
943
                // sequence of many items
944
945
                uint n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns2);
                c_assign_tuple(comp, pns->nodes[0], n, pns2->nodes);
946
            } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_comp_for) {
947
                // TODO can we ever get here? can it be compiled?
948
                goto cannot_assign;
Damien's avatar
Damien committed
949
950
951
952
953
954
955
            } else {
                // sequence with 2 items
                goto sequence_with_2_items;
            }
        } else {
            // sequence with 2 items
            sequence_with_2_items:
956
            c_assign_tuple(comp, MP_PARSE_NODE_NULL, 2, pns->nodes);
Damien's avatar
Damien committed
957
958
959
960
961
        }
        return;
    }
    return;

962
963
964
965
    cannot_assign:
    compile_syntax_error(comp, pn, "can't assign to expression");
    return;

Damien's avatar
Damien committed
966
    bad_aug:
967
    compile_syntax_error(comp, pn, "illegal expression for augmented assignment");
Damien's avatar
Damien committed
968
969
970
}

// stuff for lambda and comprehensions and generators
971
972
973
974
// 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)
975
STATIC void close_over_variables_etc(compiler_t *comp, scope_t *this_scope, int n_pos_defaults, int n_kw_defaults) {
976
977
978
    assert(n_pos_defaults >= 0);
    assert(n_kw_defaults >= 0);

Damien's avatar
Damien committed
979
    // make closed over variables, if any
980
    // ensure they are closed over in the order defined in the outer scope (mainly to agree with CPython)
Damien's avatar
Damien committed
981
982
    int nfree = 0;
    if (comp->scope_cur->kind != SCOPE_MODULE) {