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
#include "mpconfig.h"
35
#include "misc.h"
36
#include "qstr.h"
Damien's avatar
Damien committed
37
38
#include "lexer.h"
#include "parse.h"
39
#include "runtime0.h"
40
#include "obj.h"
41
42
43
#include "emitglue.h"
#include "scope.h"
#include "emit.h"
44
45
#include "compile.h"
#include "runtime.h"
46
#include "builtin.h"
47
#include "smallint.h"
Damien's avatar
Damien committed
48
49
50
51

// TODO need to mangle __attr names

typedef enum {
52
#define DEF_RULE(rule, comp, kind, ...) PN_##rule,
Damien's avatar
Damien committed
53
54
55
#include "grammar.h"
#undef DEF_RULE
    PN_maximum_number_of,
56
    PN_string, // special node for non-interned string
Damien's avatar
Damien committed
57
58
} pn_kind_t;

59
60
61
62
#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
63

64
// elements in this struct are ordered to make it compact
Damien's avatar
Damien committed
65
typedef struct _compiler_t {
66
    qstr source_file;
67

68
69
70
    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
71
72
73
74
75
    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
76

77
    uint next_label;
78

79
80
81
    uint16_t num_dict_params;
    uint16_t num_default_params;

82
83
    uint16_t break_label; // highest bit set indicates we are breaking out of a for loop
    uint16_t continue_label;
84
    uint16_t cur_except_level; // increased for SETUP_EXCEPT, SETUP_FINALLY; decreased for POP_BLOCK, POP_EXCEPT
85
    uint16_t break_continue_except_level;
Damien's avatar
Damien committed
86
87
88
89

    scope_t *scope_head;
    scope_t *scope_cur;

90
91
    emit_t *emit;                                   // current emitter
    const emit_method_table_t *emit_method_table;   // current emit method table
92
93
94

    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
95
96
} compiler_t;

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

109
STATIC const mp_map_elem_t mp_constants_table[] = {
110
111
112
    #if MICROPY_PY_UCTYPES
    { MP_OBJ_NEW_QSTR(MP_QSTR_uctypes), (mp_obj_t)&mp_module_uctypes },
    #endif
113
    // Extra constants as defined by a port
114
    MICROPY_PORT_CONSTANTS
115
116
117
118
119
};

STATIC const mp_map_t mp_constants_map = {
    .all_keys_are_qstrs = 1,
    .table_is_fixed_array = 1,
120
121
    .used = MP_ARRAY_SIZE(mp_constants_table),
    .alloc = MP_ARRAY_SIZE(mp_constants_table),
122
123
124
    .table = (mp_map_elem_t*)mp_constants_table,
};

125
126
127
128
// 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
129
#if MICROPY_COMP_CONST
130
131
132
133
134
135
136
137
138
    } 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)) {
139
        mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
Damien's avatar
Damien committed
140

141
142
        // fold some parse nodes before folding their arguments
        switch (MP_PARSE_NODE_STRUCT_KIND(pns)) {
143
#if MICROPY_COMP_CONST
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
            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;
                            }
167
                            mp_int_t value = MP_PARSE_NODE_LEAF_SMALL_INT(pn_value);
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186

                            // 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
187
188
            case PN_string:
                return pn;
189
190
191
192
        }

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

197
        // try to fold this parse node
198
        switch (MP_PARSE_NODE_STRUCT_KIND(pns)) {
199
200
201
202
203
204
205
206
207
208
            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
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
215
216
217
                    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
218
219
                    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]);
220
221
222
223
                    pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 & arg1);
                }
                break;

Damien's avatar
Damien committed
224
            case PN_shift_expr:
225
                if (n == 3 && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[0]) && MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[2])) {
226
227
                    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]);
228
                    if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_DBL_LESS)) {
229
230
231
232
                        // 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);
                        }
233
                    } else if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[1], MP_TOKEN_OP_DBL_MORE)) {
234
                        // int >> int
235
236
237
238
239
                        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;
                        }
240
                        pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, arg0 >> arg1);
Damien's avatar
Damien committed
241
242
243
244
245
246
247
248
                    } else {
                        // shouldn't happen
                        assert(0);
                    }
                }
                break;

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

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

            case PN_factor_2:
301
                if (MP_PARSE_NODE_IS_SMALL_INT(pns->nodes[1])) {
302
                    mp_int_t arg = MP_PARSE_NODE_LEAF_SMALL_INT(pns->nodes[1]);
303
                    if (MP_PARSE_NODE_IS_TOKEN_KIND(pns->nodes[0], MP_TOKEN_OP_PLUS)) {
304
                        // +int
305
306
                        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)) {
307
                        // -int
308
309
                        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)) {
310
                        // ~int
311
                        pn = mp_parse_node_new_leaf(MP_PARSE_NODE_SMALL_INT, ~arg);
Damien's avatar
Damien committed
312
313
314
315
316
317
318
319
                    } else {
                        // shouldn't happen
                        assert(0);
                    }
                }
                break;

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

    return pn;
}

364
STATIC void compile_trailer_paren_helper(compiler_t *comp, mp_parse_node_t pn_arglist, bool is_method_call, int n_positional_extra);
365
STATIC void compile_comprehension(compiler_t *comp, mp_parse_node_struct_t *pns, scope_kind_t kind);
366
STATIC void compile_node(compiler_t *comp, mp_parse_node_t pn);
Damien's avatar
Damien committed
367

368
STATIC uint comp_next_label(compiler_t *comp) {
369
370
371
    return comp->next_label++;
}

372
373
374
375
376
377
378
379
380
381
382
383
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;
}

384
STATIC scope_t *scope_new_and_link(compiler_t *comp, scope_kind_t kind, mp_parse_node_t pn, uint emit_options) {
385
    scope_t *scope = scope_new(kind, pn, comp->source_file, emit_options);
Damien's avatar
Damien committed
386
387
388
389
390
391
392
393
394
395
396
397
398
399
    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;
}

400
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)) {
401
402
403
    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
404
405
406
        for (int i = 0; i < num_nodes; i++) {
            f(comp, pns->nodes[i]);
        }
407
    } else if (!MP_PARSE_NODE_IS_NULL(pn)) {
Damien's avatar
Damien committed
408
409
410
411
        f(comp, pn);
    }
}

412
STATIC int list_get(mp_parse_node_t *pn, int pn_kind, mp_parse_node_t **nodes) {
413
    if (MP_PARSE_NODE_IS_NULL(*pn)) {
Damien's avatar
Damien committed
414
415
        *nodes = NULL;
        return 0;
416
    } else if (MP_PARSE_NODE_IS_LEAF(*pn)) {
Damien's avatar
Damien committed
417
418
419
        *nodes = pn;
        return 1;
    } else {
420
421
        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
422
423
424
425
            *nodes = pn;
            return 1;
        } else {
            *nodes = pns->nodes;
426
            return MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
Damien's avatar
Damien committed
427
428
429
430
        }
    }
}

431
STATIC void compile_generic_all_nodes(compiler_t *comp, mp_parse_node_struct_t *pns) {
432
    int num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
Damien's avatar
Damien committed
433
434
435
436
437
    for (int i = 0; i < num_nodes; i++) {
        compile_node(comp, pns->nodes[i]);
    }
}

438
#if MICROPY_EMIT_CPYTHON
439
STATIC bool cpython_c_tuple_is_const(mp_parse_node_t pn) {
440
441
442
    if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_string)) {
        return true;
    }
443
    if (!MP_PARSE_NODE_IS_LEAF(pn)) {
Damien's avatar
Damien committed
444
445
        return false;
    }
446
    if (MP_PARSE_NODE_IS_ID(pn)) {
Damien's avatar
Damien committed
447
448
449
450
451
        return false;
    }
    return true;
}

452
STATIC void cpython_c_print_quoted_str(vstr_t *vstr, const char *str, uint len, bool bytes) {
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
487
488
489
    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, "'");
    }
}

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

497
    assert(MP_PARSE_NODE_IS_LEAF(pn));
498
499
500
501
502
    if (MP_PARSE_NODE_IS_SMALL_INT(pn)) {
        vstr_printf(vstr, INT_FMT, MP_PARSE_NODE_LEAF_SMALL_INT(pn));
        return;
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    return;

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

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

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

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

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

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

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

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

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

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

Damien's avatar
Damien committed
977
    // make closed over variables, if any
978
    // ensure they are closed over in the order defined in the outer scope (mainly to agree with CPython)
Damien's avatar
Damien committed
979
980
    int nfree = 0;
    if (comp->scope_cur->kind != SCOPE_MODULE) {
981
982
983
984
985
        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];
986
                    if (id2->kind == ID_INFO_KIND_FREE && id->qst == id2->qst) {
Damien George's avatar
Damien George committed
987
#if MICROPY_EMIT_CPYTHON
988
                        EMIT_ARG(load_closure, id->qst, id->local_num);
Damien George's avatar
Damien George committed
989
990
#else
                        // in Micro Python we load closures using LOAD_FAST
991
                        EMIT_ARG(load_fast, id->qst, id->flags, id->local_num);
Damien George's avatar
Damien George committed
992
#endif
993
994
995
                        nfree += 1;
                    }
                }
Damien's avatar
Damien committed
996
997
998
999
1000
            }
        }
    }

    // make the function/closure