compile.c 138 KB
Newer Older
1
/*
2
 * This file is part of the MicroPython project, http://micropython.org/
3 4 5
 *
 * The MIT License (MIT)
 *
6
 * Copyright (c) 2013-2015 Damien P. George
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
 *
 * 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 32
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <assert.h>

33 34 35 36
#include "py/scope.h"
#include "py/emit.h"
#include "py/compile.h"
#include "py/runtime.h"
37
#include "py/asmbase.h"
Damien's avatar
Damien committed
38

39 40
#if MICROPY_ENABLE_COMPILER

Damien's avatar
Damien committed
41 42
// TODO need to mangle __attr names

43 44
#define INVALID_LABEL (0xffff)

Damien's avatar
Damien committed
45
typedef enum {
46
// define rules with a compile function
47
#define DEF_RULE(rule, comp, kind, ...) PN_##rule,
48
#define DEF_RULE_NC(rule, kind, ...)
49
#include "py/grammar.h"
Damien's avatar
Damien committed
50
#undef DEF_RULE
51
#undef DEF_RULE_NC
52
    PN_const_object, // special node for a constant, generic Python object
53 54 55 56 57 58
// define rules without a compile function
#define DEF_RULE(rule, comp, kind, ...)
#define DEF_RULE_NC(rule, kind, ...) PN_##rule,
#include "py/grammar.h"
#undef DEF_RULE
#undef DEF_RULE_NC
Damien's avatar
Damien committed
59 60
} pn_kind_t;

61
#define NEED_METHOD_TABLE MICROPY_EMIT_NATIVE
62 63 64 65

#if NEED_METHOD_TABLE

// we need a method table to do the lookup for the emitter functions
66 67
#define EMIT(fun) (comp->emit_method_table->fun(comp->emit))
#define EMIT_ARG(fun, ...) (comp->emit_method_table->fun(comp->emit, __VA_ARGS__))
68 69
#define EMIT_LOAD_FAST(qst, local_num) (comp->emit_method_table->load_id.fast(comp->emit, qst, local_num))
#define EMIT_LOAD_GLOBAL(qst) (comp->emit_method_table->load_id.global(comp->emit, qst))
Damien's avatar
Damien committed
70

71 72 73 74 75 76 77 78 79 80
#else

// if we only have the bytecode emitter enabled then we can do a direct call to the functions
#define EMIT(fun) (mp_emit_bc_##fun(comp->emit))
#define EMIT_ARG(fun, ...) (mp_emit_bc_##fun(comp->emit, __VA_ARGS__))
#define EMIT_LOAD_FAST(qst, local_num) (mp_emit_bc_load_fast(comp->emit, qst, local_num))
#define EMIT_LOAD_GLOBAL(qst) (mp_emit_bc_load_global(comp->emit, qst))

#endif

81 82 83 84 85 86 87 88 89 90
#if MICROPY_EMIT_NATIVE
// define a macro to access external native emitter
#if MICROPY_EMIT_X64
#define NATIVE_EMITTER(f) emit_native_x64_##f
#elif MICROPY_EMIT_X86
#define NATIVE_EMITTER(f) emit_native_x86_##f
#elif MICROPY_EMIT_THUMB
#define NATIVE_EMITTER(f) emit_native_thumb_##f
#elif MICROPY_EMIT_ARM
#define NATIVE_EMITTER(f) emit_native_arm_##f
91 92
#elif MICROPY_EMIT_XTENSA
#define NATIVE_EMITTER(f) emit_native_xtensa_##f
93 94 95 96 97
#else
#error "unknown native emitter"
#endif
#endif

98 99 100 101 102
#if MICROPY_EMIT_INLINE_ASM
// define macros for inline assembler
#if MICROPY_EMIT_INLINE_THUMB
#define ASM_DECORATOR_QSTR MP_QSTR_asm_thumb
#define ASM_EMITTER(f) emit_inline_thumb_##f
103 104 105
#elif MICROPY_EMIT_INLINE_XTENSA
#define ASM_DECORATOR_QSTR MP_QSTR_asm_xtensa
#define ASM_EMITTER(f) emit_inline_xtensa_##f
106 107 108 109 110
#else
#error "unknown asm emitter"
#endif
#endif

111 112 113
#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__))

114
// elements in this struct are ordered to make it compact
Damien's avatar
Damien committed
115
typedef struct _compiler_t {
116
    qstr source_file;
117

118 119
    uint8_t is_repl;
    uint8_t pass; // holds enum type pass_kind_t
120 121 122
    uint8_t have_star;

    // try to keep compiler clean from nlr
123
    mp_obj_t compile_error; // set to an exception object if there's an error
124
    size_t compile_error_line; // set to best guess of line of error
Damien's avatar
Damien committed
125

126
    uint next_label;
127

128 129 130
    uint16_t num_dict_params;
    uint16_t num_default_params;

131 132
    uint16_t break_label; // highest bit set indicates we are breaking out of a for loop
    uint16_t continue_label;
133
    uint16_t cur_except_level; // increased for SETUP_EXCEPT, SETUP_FINALLY; decreased for POP_BLOCK, POP_EXCEPT
134
    uint16_t break_continue_except_level;
Damien's avatar
Damien committed
135 136 137 138

    scope_t *scope_head;
    scope_t *scope_cur;

139
    emit_t *emit;                                   // current emitter
140
    #if NEED_METHOD_TABLE
141
    const emit_method_table_t *emit_method_table;   // current emit method table
142
    #endif
143

144
    #if MICROPY_EMIT_INLINE_ASM
145 146
    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
147
    #endif
Damien's avatar
Damien committed
148 149
} compiler_t;

150 151 152
STATIC void compile_error_set_line(compiler_t *comp, mp_parse_node_t pn) {
    // if the line of the error is unknown then try to update it from the pn
    if (comp->compile_error_line == 0 && MP_PARSE_NODE_IS_STRUCT(pn)) {
153
        comp->compile_error_line = ((mp_parse_node_struct_t*)pn)->source_line;
154
    }
155 156 157
}

STATIC void compile_syntax_error(compiler_t *comp, mp_parse_node_t pn, const char *msg) {
158 159 160 161 162
    // only register the error if there has been no other error
    if (comp->compile_error == MP_OBJ_NULL) {
        comp->compile_error = mp_obj_new_exception_msg(&mp_type_SyntaxError, msg);
        compile_error_set_line(comp, pn);
    }
163 164
}

165
STATIC void compile_trailer_paren_helper(compiler_t *comp, mp_parse_node_t pn_arglist, bool is_method_call, int n_positional_extra);
166
STATIC void compile_comprehension(compiler_t *comp, mp_parse_node_struct_t *pns, scope_kind_t kind);
167
STATIC void compile_node(compiler_t *comp, mp_parse_node_t pn);
Damien's avatar
Damien committed
168

169
STATIC uint comp_next_label(compiler_t *comp) {
170 171 172
    return comp->next_label++;
}

173 174 175 176 177 178 179 180 181 182 183 184
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;
}

185
STATIC scope_t *scope_new_and_link(compiler_t *comp, scope_kind_t kind, mp_parse_node_t pn, uint emit_options) {
186
    scope_t *scope = scope_new(kind, pn, comp->source_file, emit_options);
Damien's avatar
Damien committed
187 188 189 190 191 192 193 194 195 196 197 198 199 200
    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;
}

201 202 203
typedef void (*apply_list_fun_t)(compiler_t *comp, mp_parse_node_t pn);

STATIC void apply_to_single_or_list(compiler_t *comp, mp_parse_node_t pn, pn_kind_t pn_list_kind, apply_list_fun_t f) {
204
    if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, pn_list_kind)) {
205 206
        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
207 208 209
        for (int i = 0; i < num_nodes; i++) {
            f(comp, pns->nodes[i]);
        }
210
    } else if (!MP_PARSE_NODE_IS_NULL(pn)) {
Damien's avatar
Damien committed
211 212 213 214
        f(comp, pn);
    }
}

215
STATIC void compile_generic_all_nodes(compiler_t *comp, mp_parse_node_struct_t *pns) {
216
    int num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
Damien's avatar
Damien committed
217 218
    for (int i = 0; i < num_nodes; i++) {
        compile_node(comp, pns->nodes[i]);
219 220 221 222 223
        if (comp->compile_error != MP_OBJ_NULL) {
            // add line info for the error in case it didn't have a line number
            compile_error_set_line(comp, pns->nodes[i]);
            return;
        }
Damien's avatar
Damien committed
224 225 226
    }
}

227 228 229 230
STATIC void compile_load_id(compiler_t *comp, qstr qst) {
    if (comp->pass == MP_PASS_SCOPE) {
        mp_emit_common_get_id_for_load(comp->scope_cur, qst);
    } else {
231
        #if NEED_METHOD_TABLE
232
        mp_emit_common_id_op(comp->emit, &comp->emit_method_table->load_id, comp->scope_cur, qst);
233 234 235
        #else
        mp_emit_common_id_op(comp->emit, &mp_emit_bc_method_table_load_id_ops, comp->scope_cur, qst);
        #endif
236 237 238 239 240 241 242
    }
}

STATIC void compile_store_id(compiler_t *comp, qstr qst) {
    if (comp->pass == MP_PASS_SCOPE) {
        mp_emit_common_get_id_for_modification(comp->scope_cur, qst);
    } else {
243
        #if NEED_METHOD_TABLE
244
        mp_emit_common_id_op(comp->emit, &comp->emit_method_table->store_id, comp->scope_cur, qst);
245 246 247
        #else
        mp_emit_common_id_op(comp->emit, &mp_emit_bc_method_table_store_id_ops, comp->scope_cur, qst);
        #endif
248 249 250 251 252 253 254
    }
}

STATIC void compile_delete_id(compiler_t *comp, qstr qst) {
    if (comp->pass == MP_PASS_SCOPE) {
        mp_emit_common_get_id_for_modification(comp->scope_cur, qst);
    } else {
255
        #if NEED_METHOD_TABLE
256
        mp_emit_common_id_op(comp->emit, &comp->emit_method_table->delete_id, comp->scope_cur, qst);
257 258 259
        #else
        mp_emit_common_id_op(comp->emit, &mp_emit_bc_method_table_delete_id_ops, comp->scope_cur, qst);
        #endif
260 261 262
    }
}

263
STATIC void c_tuple(compiler_t *comp, mp_parse_node_t pn, mp_parse_node_struct_t *pns_list) {
264
    int total = 0;
265
    if (!MP_PARSE_NODE_IS_NULL(pn)) {
266 267 268 269
        compile_node(comp, pn);
        total += 1;
    }
    if (pns_list != NULL) {
270
        int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns_list);
271 272 273 274 275
        for (int i = 0; i < n; i++) {
            compile_node(comp, pns_list->nodes[i]);
        }
        total += n;
    }
276
    EMIT_ARG(build_tuple, total);
277
}
Damien's avatar
Damien committed
278

279
STATIC void compile_generic_tuple(compiler_t *comp, mp_parse_node_struct_t *pns) {
Damien's avatar
Damien committed
280
    // a simple tuple expression
281
    c_tuple(comp, MP_PARSE_NODE_NULL, pns);
Damien's avatar
Damien committed
282 283
}

284
STATIC void c_if_cond(compiler_t *comp, mp_parse_node_t pn, bool jump_if, int label) {
285
    if (mp_parse_node_is_const_false(pn)) {
286
        if (jump_if == false) {
287
            EMIT_ARG(jump, label);
288 289
        }
        return;
290
    } else if (mp_parse_node_is_const_true(pn)) {
291
        if (jump_if == true) {
292
            EMIT_ARG(jump, label);
293 294
        }
        return;
295 296 297 298
    } 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) {
299
            if (jump_if == false) {
300
            and_or_logic1:;
301
                uint label2 = comp_next_label(comp);
302
                for (int i = 0; i < n - 1; i++) {
303
                    c_if_cond(comp, pns->nodes[i], !jump_if, label2);
304
                }
305
                c_if_cond(comp, pns->nodes[n - 1], jump_if, label);
306
                EMIT_ARG(label_assign, label2);
307
            } else {
308
            and_or_logic2:
309
                for (int i = 0; i < n; i++) {
310
                    c_if_cond(comp, pns->nodes[i], jump_if, label);
311 312 313
                }
            }
            return;
314
        } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_and_test) {
315
            if (jump_if == false) {
316
                goto and_or_logic2;
317
            } else {
318
                goto and_or_logic1;
319
            }
320
        } else if (MP_PARSE_NODE_STRUCT_KIND(pns) == PN_not_test_2) {
321 322
            c_if_cond(comp, pns->nodes[0], !jump_if, label);
            return;
323 324 325 326 327 328 329
        } 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);
                }
330 331
            } else {
                assert(MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp));
332 333 334 335 336 337
                // non-empty tuple, acts as true for the condition
                if (jump_if == true) {
                    EMIT_ARG(jump, label);
                }
            }
            return;
338 339 340 341 342
        }
    }

    // nothing special, fall back to default compiling for node and jump
    compile_node(comp, pn);
343
    EMIT_ARG(pop_jump_if, jump_if, label);
Damien's avatar
Damien committed
344 345 346
}

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

349
STATIC void c_assign_atom_expr(compiler_t *comp, mp_parse_node_struct_t *pns, assign_kind_t assign_kind) {
Damien's avatar
Damien committed
350 351 352 353
    if (assign_kind != ASSIGN_AUG_STORE) {
        compile_node(comp, pns->nodes[0]);
    }

354 355
    if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) {
        mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t*)pns->nodes[1];
356
        if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_atom_expr_trailers) {
357
            int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns1);
Damien's avatar
Damien committed
358 359 360 361 362
            if (assign_kind != ASSIGN_AUG_STORE) {
                for (int i = 0; i < n - 1; i++) {
                    compile_node(comp, pns1->nodes[i]);
                }
            }
363 364
            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
365
        }
366
        if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_trailer_bracket) {
Damien's avatar
Damien committed
367 368 369 370 371 372 373
            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);
374
                    EMIT(load_subscr);
Damien's avatar
Damien committed
375 376 377 378
                } else {
                    EMIT(store_subscr);
                }
            }
379 380
        } 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
381 382
            if (assign_kind == ASSIGN_AUG_LOAD) {
                EMIT(dup_top);
383
                EMIT_ARG(load_attr, MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0]));
Damien's avatar
Damien committed
384 385 386 387
            } else {
                if (assign_kind == ASSIGN_AUG_STORE) {
                    EMIT(rot_two);
                }
388
                EMIT_ARG(store_attr, MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0]));
Damien's avatar
Damien committed
389 390
            }
        } else {
391
            goto cannot_assign;
Damien's avatar
Damien committed
392 393
        }
    } else {
394
        goto cannot_assign;
Damien's avatar
Damien committed
395 396
    }

397 398 399 400
    return;

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

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

    // look for star expression
408
    uint have_star_index = -1;
409 410 411 412
    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;
    }
413
    for (uint i = 0; i < num_tail; i++) {
414
        if (MP_PARSE_NODE_IS_STRUCT_KIND(nodes_tail[i], PN_star_expr)) {
415
            if (have_star_index == (uint)-1) {
416 417
                EMIT_ARG(unpack_ex, num_head + i, num_tail - i - 1);
                have_star_index = num_head + i;
Damien's avatar
Damien committed
418
            } else {
419
                compile_syntax_error(comp, nodes_tail[i], "multiple *x in assignment");
Damien's avatar
Damien committed
420 421 422 423
                return;
            }
        }
    }
424
    if (have_star_index == (uint)-1) {
425
        EMIT_ARG(unpack_sequence, num_head + num_tail);
Damien's avatar
Damien committed
426
    }
427 428 429
    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
430
        } else {
431 432 433
            c_assign(comp, node_head, ASSIGN_STORE);
        }
    }
434
    for (uint i = 0; i < num_tail; i++) {
435 436 437 438
        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
439 440 441 442 443
        }
    }
}

// assigns top of stack to pn
444
STATIC void c_assign(compiler_t *comp, mp_parse_node_t pn, assign_kind_t assign_kind) {
445 446
    assert(!MP_PARSE_NODE_IS_NULL(pn));
    if (MP_PARSE_NODE_IS_LEAF(pn)) {
447
        if (MP_PARSE_NODE_IS_ID(pn)) {
448
            qstr arg = MP_PARSE_NODE_LEAF_ARG(pn);
Damien's avatar
Damien committed
449 450 451
            switch (assign_kind) {
                case ASSIGN_STORE:
                case ASSIGN_AUG_STORE:
452
                    compile_store_id(comp, arg);
Damien's avatar
Damien committed
453 454
                    break;
                case ASSIGN_AUG_LOAD:
455
                default:
456
                    compile_load_id(comp, arg);
Damien's avatar
Damien committed
457 458 459
                    break;
            }
        } else {
460
            goto cannot_assign;
Damien's avatar
Damien committed
461 462
        }
    } else {
463
        // pn must be a struct
464 465
        mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
        switch (MP_PARSE_NODE_STRUCT_KIND(pns)) {
466
            case PN_atom_expr_normal:
Damien's avatar
Damien committed
467
                // lhs is an index or attribute
468
                c_assign_atom_expr(comp, pns, assign_kind);
Damien's avatar
Damien committed
469 470 471 472 473 474
                break;

            case PN_testlist_star_expr:
            case PN_exprlist:
                // lhs is a tuple
                if (assign_kind != ASSIGN_STORE) {
475
                    goto cannot_assign;
Damien's avatar
Damien committed
476
                }
477
                c_assign_tuple(comp, MP_PARSE_NODE_NULL, MP_PARSE_NODE_STRUCT_NUM_NODES(pns), pns->nodes);
Damien's avatar
Damien committed
478 479 480 481
                break;

            case PN_atom_paren:
                // lhs is something in parenthesis
482
                if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {
Damien's avatar
Damien committed
483
                    // empty tuple
484
                    goto cannot_assign;
485 486
                } else {
                    assert(MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_testlist_comp));
487
                    if (assign_kind != ASSIGN_STORE) {
488
                        goto cannot_assign;
489
                    }
490
                    pns = (mp_parse_node_struct_t*)pns->nodes[0];
Damien's avatar
Damien committed
491 492 493 494 495 496 497
                    goto testlist_comp;
                }
                break;

            case PN_atom_bracket:
                // lhs is something in brackets
                if (assign_kind != ASSIGN_STORE) {
498
                    goto cannot_assign;
Damien's avatar
Damien committed
499
                }
500
                if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {
Damien's avatar
Damien committed
501
                    // empty list, assignment allowed
502
                    c_assign_tuple(comp, MP_PARSE_NODE_NULL, 0, NULL);
503 504
                } 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
505 506 507
                    goto testlist_comp;
                } else {
                    // brackets around 1 item
508
                    c_assign_tuple(comp, pns->nodes[0], 0, NULL);
Damien's avatar
Damien committed
509 510 511 512
                }
                break;

            default:
513
                goto cannot_assign;
Damien's avatar
Damien committed
514 515 516 517 518
        }
        return;

        testlist_comp:
        // lhs is a sequence
519 520 521
        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
522
                // sequence of one item, with trailing comma
523
                assert(MP_PARSE_NODE_IS_NULL(pns2->nodes[0]));
524
                c_assign_tuple(comp, pns->nodes[0], 0, NULL);
525
            } else if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_testlist_comp_3c) {
Damien's avatar
Damien committed
526
                // sequence of many items
527 528
                uint n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns2);
                c_assign_tuple(comp, pns->nodes[0], n, pns2->nodes);
529
            } else if (MP_PARSE_NODE_STRUCT_KIND(pns2) == PN_comp_for) {
530
                goto cannot_assign;
Damien's avatar
Damien committed
531 532 533 534 535 536 537
            } else {
                // sequence with 2 items
                goto sequence_with_2_items;
            }
        } else {
            // sequence with 2 items
            sequence_with_2_items:
538
            c_assign_tuple(comp, MP_PARSE_NODE_NULL, 2, pns->nodes);
Damien's avatar
Damien committed
539 540 541 542 543
        }
        return;
    }
    return;

544 545
    cannot_assign:
    compile_syntax_error(comp, pn, "can't assign to expression");
Damien's avatar
Damien committed
546 547
}

548
// stuff for lambda and comprehensions and generators:
549 550 551
//  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)
552
STATIC void close_over_variables_etc(compiler_t *comp, scope_t *this_scope, int n_pos_defaults, int n_kw_defaults) {
553 554 555
    assert(n_pos_defaults >= 0);
    assert(n_kw_defaults >= 0);

556 557 558 559 560 561
    // set flags
    if (n_kw_defaults > 0) {
        this_scope->scope_flags |= MP_SCOPE_FLAG_DEFKWARGS;
    }
    this_scope->num_def_pos_args = n_pos_defaults;

Damien's avatar
Damien committed
562
    // make closed over variables, if any
563
    // ensure they are closed over in the order defined in the outer scope (mainly to agree with CPython)
Damien's avatar
Damien committed
564 565
    int nfree = 0;
    if (comp->scope_cur->kind != SCOPE_MODULE) {
566 567 568 569 570
        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];
571
                    if (id2->kind == ID_INFO_KIND_FREE && id->qst == id2->qst) {
572
                        // in MicroPython we load closures using LOAD_FAST
573
                        EMIT_LOAD_FAST(id->qst, id->local_num);
574 575 576
                        nfree += 1;
                    }
                }
Damien's avatar
Damien committed
577 578 579 580 581 582
            }
        }
    }

    // make the function/closure
    if (nfree == 0) {
583
        EMIT_ARG(make_function, this_scope, n_pos_defaults, n_kw_defaults);
Damien's avatar
Damien committed
584
    } else {
585
        EMIT_ARG(make_closure, this_scope, nfree, n_pos_defaults, n_kw_defaults);
Damien's avatar
Damien committed
586 587 588
    }
}

589
STATIC void compile_funcdef_lambdef_param(compiler_t *comp, mp_parse_node_t pn) {
590 591 592 593 594 595 596 597 598 599
    // For efficiency of the code below we extract the parse-node kind here
    int pn_kind;
    if (MP_PARSE_NODE_IS_ID(pn)) {
        pn_kind = -1;
    } else {
        assert(MP_PARSE_NODE_IS_STRUCT(pn));
        pn_kind = MP_PARSE_NODE_STRUCT_KIND((mp_parse_node_struct_t*)pn);
    }

    if (pn_kind == PN_typedargslist_star || pn_kind == PN_varargslist_star) {
600 601
        comp->have_star = true;
        /* don't need to distinguish bare from named star
602
        mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
603 604
        if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {
            // bare star
605 606
        } else {
            // named star
607
        }
608
        */
609

610
    } else if (pn_kind == PN_typedargslist_dbl_star || pn_kind == PN_varargslist_dbl_star) {
611
        // named double star
612 613 614 615 616
        // TODO do we need to do anything with this?

    } else {
        mp_parse_node_t pn_id;
        mp_parse_node_t pn_equal;
617
        if (pn_kind == -1) {
618 619 620 621 622
            // this parameter is just an id

            pn_id = pn;
            pn_equal = MP_PARSE_NODE_NULL;

623
        } else if (pn_kind == PN_typedargslist_name) {
624 625 626 627
            // this parameter has a colon and/or equal specifier

            mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
            pn_id = pns->nodes[0];
628
            //pn_colon = pns->nodes[1]; // unused
629
            pn_equal = pns->nodes[2];
630 631

        } else {
632
            assert(pn_kind == PN_varargslist_name); // should be
633 634 635 636 637
            // this parameter has an equal specifier

            mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
            pn_id = pns->nodes[0];
            pn_equal = pns->nodes[1];
638 639 640 641 642 643
        }

        if (MP_PARSE_NODE_IS_NULL(pn_equal)) {
            // this parameter does not have a default value

            // check for non-default parameters given after default parameters (allowed by parser, but not syntactically valid)
644
            if (!comp->have_star && comp->num_default_params != 0) {
645
                compile_syntax_error(comp, pn, "non-default argument follows default argument");
646 647 648 649
                return;
            }

        } else {
Damien's avatar
Damien committed
650 651
            // this parameter has a default value
            // in CPython, None (and True, False?) as default parameters are loaded with LOAD_NAME; don't understandy why
652

653
            if (comp->have_star) {
654
                comp->num_dict_params += 1;
655
                // in MicroPython we put the default dict parameters into a dictionary using the bytecode
656
                if (comp->num_dict_params == 1) {
657
                    // in MicroPython we put the default positional parameters into a tuple using the bytecode
658 659 660
                    // we need to do this here before we start building the map for the default keywords
                    if (comp->num_default_params > 0) {
                        EMIT_ARG(build_tuple, comp->num_default_params);
661 662
                    } else {
                        EMIT(load_null); // sentinel indicating empty default positional args
663
                    }
664 665 666
                    // first default dict param, so make the map
                    EMIT_ARG(build_map, 0);
                }
667 668

                // compile value then key, then store it to the dict
669
                compile_node(comp, pn_equal);
670
                EMIT_ARG(load_const_str, MP_PARSE_NODE_LEAF_ARG(pn_id));
671
                EMIT(store_map);
Damien's avatar
Damien committed
672
            } else {
673 674
                comp->num_default_params += 1;
                compile_node(comp, pn_equal);
Damien's avatar
Damien committed
675 676 677 678 679
            }
        }
    }
}

680
STATIC void compile_funcdef_lambdef(compiler_t *comp, scope_t *scope, mp_parse_node_t pn_params, pn_kind_t pn_list_kind) {
681 682 683 684 685 686 687
    // When we call compile_funcdef_lambdef_param below it can compile an arbitrary
    // expression for default arguments, which may contain a lambda.  The lambda will
    // call here in a nested way, so we must save and restore the relevant state.
    bool orig_have_star = comp->have_star;
    uint16_t orig_num_dict_params = comp->num_dict_params;
    uint16_t orig_num_default_params = comp->num_default_params;

Damien's avatar
Damien committed
688
    // compile default parameters
689
    comp->have_star = false;
690 691
    comp->num_dict_params = 0;
    comp->num_default_params = 0;
692
    apply_to_single_or_list(comp, pn_params, pn_list_kind, compile_funcdef_lambdef_param);
693

694
    if (comp->compile_error != MP_OBJ_NULL) {
695
        return;
696 697
    }

698
    // in MicroPython we put the default positional parameters into a tuple using the bytecode
699 700
    // the default keywords args may have already made the tuple; if not, do it now
    if (comp->num_default_params > 0 && comp->num_dict_params == 0) {
701
        EMIT_ARG(build_tuple, comp->num_default_params);
702
        EMIT(load_null); // sentinel indicating empty default keyword args
703 704
    }

705 706
    // make the function
    close_over_variables_etc(comp, scope, comp->num_default_params, comp->num_dict_params);
707 708 709 710 711

    // restore state
    comp->have_star = orig_have_star;
    comp->num_dict_params = orig_num_dict_params;
    comp->num_default_params = orig_num_default_params;
712 713 714 715 716 717 718 719 720 721 722 723
}

// leaves function object on stack
// returns function name
STATIC qstr compile_funcdef_helper(compiler_t *comp, mp_parse_node_struct_t *pns, uint emit_options) {
    if (comp->pass == MP_PASS_SCOPE) {
        // create a new scope for this function
        scope_t *s = scope_new_and_link(comp, SCOPE_FUNCTION, (mp_parse_node_t)pns, emit_options);
        // store the function scope so the compiling function can use it at each pass
        pns->nodes[4] = (mp_parse_node_t)s;
    }

Damien's avatar
Damien committed
724 725 726
    // get the scope for this function
    scope_t *fscope = (scope_t*)pns->nodes[4];

727 728
    // compile the function definition
    compile_funcdef_lambdef(comp, fscope, pns->nodes[1], PN_typedargslist);
Damien's avatar
Damien committed
729 730 731 732 733 734 735

    // return its name (the 'f' in "def f(...):")
    return fscope->simple_name;
}

// leaves class object on stack
// returns class name
736
STATIC qstr compile_classdef_helper(compiler_t *comp, mp_parse_node_struct_t *pns, uint emit_options) {
737
    if (comp->pass == MP_PASS_SCOPE) {
Damien's avatar
Damien committed
738
        // create a new scope for this class
739
        scope_t *s = scope_new_and_link(comp, SCOPE_CLASS, (mp_parse_node_t)pns, emit_options);
Damien's avatar
Damien committed
740
        // store the class scope so the compiling function can use it at each pass
741
        pns->nodes[3] = (mp_parse_node_t)s;
Damien's avatar
Damien committed
742 743 744 745 746 747 748 749 750 751 752
    }

    EMIT(load_build_class);

    // scope for this class
    scope_t *cscope = (scope_t*)pns->nodes[3];

    // compile the class
    close_over_variables_etc(comp, cscope, 0, 0);

    // get its name
753
    EMIT_ARG(load_const_str, cscope->simple_name);
Damien's avatar
Damien committed
754 755

    // nodes[1] has parent classes, if any
756 757 758 759 760 761
    // empty parenthesis (eg class C():) gets here as an empty PN_classdef_2 and needs special handling
    mp_parse_node_t parents = pns->nodes[1];
    if (MP_PARSE_NODE_IS_STRUCT_KIND(parents, PN_classdef_2)) {
        parents = MP_PARSE_NODE_NULL;
    }
    compile_trailer_paren_helper(comp, parents, false, 2);
Damien's avatar
Damien committed
762 763 764 765 766

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

767
// returns true if it was a built-in decorator (even if the built-in had an error)
768
STATIC bool compile_built_in_decorator(compiler_t *comp, int name_len, mp_parse_node_t *name_nodes, uint *emit_options) {
769
    if (MP_PARSE_NODE_LEAF_ARG(name_nodes[0]) != MP_QSTR_micropython) {
770 771 772 773
        return false;
    }

    if (name_len != 2) {
774
        compile_syntax_error(comp, name_nodes[0], "invalid micropython decorator");
775 776 777
        return true;
    }

778
    qstr attr = MP_PARSE_NODE_LEAF_ARG(name_nodes[1]);
779
    if (attr == MP_QSTR_bytecode) {
780
        *emit_options = MP_EMIT_OPT_BYTECODE;
781
#if MICROPY_EMIT_NATIVE
782
    } else if (attr == MP_QSTR_native) {
783
        *emit_options = MP_EMIT_OPT_NATIVE_PYTHON;
784
    } else if (attr == MP_QSTR_viper) {
785
        *emit_options = MP_EMIT_OPT_VIPER;
786
#endif
787 788 789 790
    #if MICROPY_EMIT_INLINE_ASM
    } else if (attr == ASM_DECORATOR_QSTR) {
        *emit_options = MP_EMIT_OPT_ASM;
    #endif
791
    } else {
792
        compile_syntax_error(comp, name_nodes[1], "invalid micropython decorator");
793 794 795 796 797
    }

    return true;
}

798
STATIC void compile_decorated(compiler_t *comp, mp_parse_node_struct_t *pns) {
Damien's avatar
Damien committed
799
    // get the list of decorators
800
    mp_parse_node_t *nodes;
801
    int n = mp_parse_node_extract_list(&pns->nodes[0], PN_decorators, &nodes);
Damien's avatar
Damien committed
802

803 804 805 806 807
    // inherit emit options for this function/class definition
    uint emit_options = comp->scope_cur->emit_options;

    // compile each decorator
    int num_built_in_decorators = 0;
Damien's avatar
Damien committed
808
    for (int i = 0; i < n; i++) {
809 810
        assert(MP_PARSE_NODE_IS_STRUCT_KIND(nodes[i], PN_decorator)); // should be
        mp_parse_node_struct_t *pns_decorator = (mp_parse_node_struct_t*)nodes[i];
811 812

        // nodes[0] contains the decorator function, which is a dotted name
813
        mp_parse_node_t *name_nodes;
814
        int name_len = mp_parse_node_extract_list(&pns_decorator->nodes[0], PN_dotted_name, &name_nodes);
815 816 817 818 819 820 821 822 823 824 825

        // check for built-in decorators
        if (compile_built_in_decorator(comp, name_len, name_nodes, &emit_options)) {
            // this was a built-in
            num_built_in_decorators += 1;

        } else {
            // not a built-in, compile normally

            // compile the decorator function
            compile_node(comp, name_nodes[0]);
826 827 828
            for (int j = 1; j < name_len; j++) {
                assert(MP_PARSE_NODE_IS_ID(name_nodes[j])); // should be
                EMIT_ARG(load_attr, MP_PARSE_NODE_LEAF_ARG(name_nodes[j]));
829 830 831
            }

            // nodes[1] contains arguments to the decorator function, if any
832
            if (!MP_PARSE_NODE_IS_NULL(pns_decorator->nodes[1])) {
833 834 835
                // call the decorator function with the arguments in nodes[1]
                compile_node(comp, pns_decorator->nodes[1]);
            }
Damien's avatar
Damien committed
836 837 838
        }
    }

839
    // compile the body (funcdef, async funcdef or classdef) and get its name
840
    mp_parse_node_struct_t *pns_body = (mp_parse_node_struct_t*)pns->nodes[1];
Damien's avatar
Damien committed
841
    qstr body_name = 0;
842
    if (MP_PARSE_NODE_STRUCT_KIND(pns_body) == PN_funcdef) {
843
        body_name = compile_funcdef_helper(comp, pns_body, emit_options);
844 845 846 847 848 849 850 851
    #if MICROPY_PY_ASYNC_AWAIT
    } else if (MP_PARSE_NODE_STRUCT_KIND(pns_body) == PN_async_funcdef) {
        assert(MP_PARSE_NODE_IS_STRUCT(pns_body->nodes[0]));
        mp_parse_node_struct_t *pns0 = (mp_parse_node_struct_t*)pns_body->nodes[0];
        body_name = compile_funcdef_helper(comp, pns0, emit_options);
        scope_t *fscope = (scope_t*)pns0->nodes[4];
        fscope->scope_flags |= MP_SCOPE_FLAG_GENERATOR;
    #endif
Damien's avatar
Damien committed
852
    } else {
853 854
        assert(MP_PARSE_NODE_STRUCT_KIND(pns_body) == PN_classdef); // should be
        body_name = compile_classdef_helper(comp, pns_body, emit_options);
Damien's avatar
Damien committed
855 856 857
    }

    // call each decorator
858
    for (int i = 0; i < n - num_built_in_decorators; i++) {
859
        EMIT_ARG(call_function, 1, 0, 0);
Damien's avatar
Damien committed
860 861 862
    }

    // store func/class object into name
863
    compile_store_id(comp, body_name);
Damien's avatar
Damien committed
864 865
}

866
STATIC void compile_funcdef(compiler_t *comp, mp_parse_node_struct_t *pns) {
867
    qstr fname = compile_funcdef_helper(comp, pns, comp->scope_cur->emit_options);
Damien's avatar
Damien committed
868
    // store function object into function name
869
    compile_store_id(comp, fname);
Damien's avatar
Damien committed
870 871
}

872
STATIC void c_del_stmt(compiler_t *comp, mp_parse_node_t pn) {
873
    if (MP_PARSE_NODE_IS_ID(pn)) {
874
        compile_delete_id(comp, MP_PARSE_NODE_LEAF_ARG(pn));
875
    } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_atom_expr_normal)) {
876
        mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
Damien's avatar
Damien committed
877

878
        compile_node(comp, pns->nodes[0]); // base of the atom_expr_normal node
Damien's avatar
Damien committed
879

880 881
        if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) {
            mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t*)pns->nodes[1];
882
            if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_atom_expr_trailers) {
883
                int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns1);
Damien's avatar
Damien committed
884 885 886
                for (int i = 0; i < n - 1; i++) {
                    compile_node(comp, pns1->nodes[i]);
                }
887 888
                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
889
            }
890
            if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_trailer_bracket) {
Damien's avatar
Damien committed
891 892
                compile_node(comp, pns1->nodes[0]);
                EMIT(delete_subscr);
893 894
            } else if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_trailer_period) {
                assert(MP_PARSE_NODE_IS_ID(pns1->nodes[0]));
895
                EMIT_ARG(delete_attr, MP_PARSE_NODE_LEAF_ARG(pns1->nodes[0]));
Damien's avatar
Damien committed
896
            } else {
897
                goto cannot_delete;
Damien's avatar
Damien committed
898 899
            }
        } else {
900
            goto cannot_delete;
Damien's avatar
Damien committed
901 902
        }

903 904
    } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_atom_paren)) {
        pn = ((mp_parse_node_struct_t*)pn)->nodes[0];
905 906 907 908
        if (MP_PARSE_NODE_IS_NULL(pn)) {
            goto cannot_delete;
        } else {
            assert(MP_PARSE_NODE_IS_STRUCT_KIND(pn, PN_testlist_comp));
909
            mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)pn;
Damien's avatar
Damien committed
910 911
            // TODO perhaps factorise testlist_comp code with other uses of PN_testlist_comp

912 913 914
            if (MP_PARSE_NODE_IS_STRUCT(pns->nodes[1])) {
                mp_parse_node_struct_t *pns1 = (mp_parse_node_struct_t*)pns->nodes[1];
                if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_testlist_comp_3b) {
Damien's avatar
Damien committed
915
                    // sequence of one item, with trailing comma
916
                    assert(MP_PARSE_NODE_IS_NULL(pns1->nodes[0]));
Damien's avatar
Damien committed
917
                    c_del_stmt(comp, pns->nodes[0]);
918
                } else if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_testlist_comp_3c) {
Damien's avatar
Damien committed
919
                    // sequence of many items
920
                    int n = MP_PARSE_NODE_STRUCT_NUM_NODES(pns1);
Damien's avatar
Damien committed
921 922 923 924
                    c_del_stmt(comp, pns->nodes[0]);
                    for (int i = 0; i < n; i++) {
                        c_del_stmt(comp, pns1->nodes[i]);
                    }
925
                } else if (MP_PARSE_NODE_STRUCT_KIND(pns1) == PN_comp_for) {
926
                    goto cannot_delete;
Damien's avatar
Damien committed
927 928 929 930 931 932 933 934 935 936 937 938
                } else {
                    // sequence with 2 items
                    goto sequence_with_2_items;
                }
            } else {
                // sequence with 2 items
                sequence_with_2_items:
                c_del_stmt(comp, pns->nodes[0]);
                c_del_stmt(comp, pns->nodes[1]);
            }
        }
    } else {
Ville Skyttä's avatar
Ville Skyttä committed
939
        // some arbitrary statement that we can't delete (eg del 1)
940
        goto cannot_delete;
Damien's avatar
Damien committed
941
    }
942 943 944 945 946

    return;

cannot_delete:
    compile_syntax_error(comp, (mp_parse_node_t)pn, "can't delete expression");
Damien's avatar
Damien committed
947 948
}

949
STATIC void compile_del_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
Damien's avatar
Damien committed
950 951 952
    apply_to_single_or_list(comp, pns->nodes[0], PN_exprlist, c_del_stmt);
}

953
STATIC void compile_break_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
954
    if (comp->break_label == INVALID_LABEL) {
955
        compile_syntax_error(comp, (mp_parse_node_t)pns, "'break' outside loop");
Damien's avatar
Damien committed
956
    }
957
    assert(comp->cur_except_level >= comp->break_continue_except_level);
958
    EMIT_ARG(break_loop, comp->break_label, comp->cur_except_level - comp->break_continue_except_level);
Damien's avatar
Damien committed
959 960
}

961
STATIC void compile_continue_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
962
    if (comp->continue_label == INVALID_LABEL) {
963
        compile_syntax_error(comp, (mp_parse_node_t)pns, "'continue' outside loop");
Damien's avatar
Damien committed
964
    }
965
    assert(comp->cur_except_level >= comp->break_continue_except_level);
966
    EMIT_ARG(continue_loop, comp->continue_label, comp->cur_except_level - comp->break_continue_except_level);
Damien's avatar
Damien committed
967 968
}

969
STATIC void compile_return_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
Damien's avatar
Damien committed
970
    if (comp->scope_cur->kind != SCOPE_FUNCTION) {
971
        compile_syntax_error(comp, (mp_parse_node_t)pns, "'return' outside function");
Damien's avatar
Damien committed
972 973
        return;
    }
974
    if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {
Damien's avatar
Damien committed
975
        // no argument to 'return', so return None
976
        EMIT_ARG(load_const_tok, MP_TOKEN_KW_NONE);
977 978
    } else if (MICROPY_COMP_RETURN_IF_EXPR
        && MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_test_if_expr)) {
Damien's avatar
Damien committed
979
        // special case when returning an if-expression; to match CPython optimisation
980 981
        mp_parse_node_struct_t *pns_test_if_expr = (mp_parse_node_struct_t*)pns->nodes[0];
        mp_parse_node_struct_t *pns_test_if_else = (mp_parse_node_struct_t*)pns_test_if_expr->nodes[1];
Damien's avatar
Damien committed
982

983
        uint l_fail = comp_next_label(comp);
Damien's avatar
Damien committed
984 985 986
        c_if_cond(comp, pns_test_if_else->nodes[0], false, l_fail); // condition
        compile_node(comp, pns_test_if_expr->nodes[0]); // success value
        EMIT(return_value);
987
        EMIT_ARG(label_assign, l_fail);
Damien's avatar
Damien committed
988 989 990 991 992 993 994
        compile_node(comp, pns_test_if_else->nodes[1]); // failure value
    } else {
        compile_node(comp, pns->nodes[0]);
    }
    EMIT(return_value);
}

995
STATIC void compile_yield_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
Damien's avatar
Damien committed
996 997 998 999
    compile_node(comp, pns->nodes[0]);
    EMIT(pop_top);
}

1000
STATIC void compile_raise_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
1001
    if (MP_PARSE_NODE_IS_NULL(pns->nodes[0])) {
Damien's avatar
Damien committed
1002
        // raise
1003
        EMIT_ARG(raise_varargs, 0);
1004
    } else if (MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[0], PN_raise_stmt_arg)) {
Damien's avatar
Damien committed
1005
        // raise x from y
1006
        pns = (mp_parse_node_struct_t*)pns->nodes[0];
Damien's avatar
Damien committed
1007 1008
        compile_node(comp, pns->nodes[0]);
        compile_node(comp, pns->nodes[1]);
1009
        EMIT_ARG(raise_varargs, 2);