py, compiler: Improve passes; add an extra pass for native emitter.
diff --git a/py/compile.c b/py/compile.c
index 9a660e2..bc9d7ae 100644
--- a/py/compile.c
+++ b/py/compile.c
@@ -994,7 +994,7 @@
 // leaves function object on stack
 // returns function name
 qstr compile_funcdef_helper(compiler_t *comp, mp_parse_node_struct_t *pns, uint emit_options) {
-    if (comp->pass == PASS_1) {
+    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
@@ -1043,7 +1043,7 @@
 // leaves class object on stack
 // returns class name
 qstr compile_classdef_helper(compiler_t *comp, mp_parse_node_struct_t *pns, uint emit_options) {
-    if (comp->pass == PASS_1) {
+    if (comp->pass == MP_PASS_SCOPE) {
         // create a new scope for this class
         scope_t *s = scope_new_and_link(comp, SCOPE_CLASS, (mp_parse_node_t)pns, emit_options);
         // store the class scope so the compiling function can use it at each pass
@@ -1510,7 +1510,7 @@
 }
 
 void compile_global_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
-    if (comp->pass == PASS_1) {
+    if (comp->pass == MP_PASS_SCOPE) {
         if (MP_PARSE_NODE_IS_LEAF(pns->nodes[0])) {
             scope_declare_global(comp->scope_cur, MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]));
         } else {
@@ -1524,7 +1524,7 @@
 }
 
 void compile_nonlocal_stmt(compiler_t *comp, mp_parse_node_struct_t *pns) {
-    if (comp->pass == PASS_1) {
+    if (comp->pass == MP_PASS_SCOPE) {
         if (MP_PARSE_NODE_IS_LEAF(pns->nodes[0])) {
             scope_declare_nonlocal(comp->scope_cur, MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]));
         } else {
@@ -2056,7 +2056,7 @@
                 && 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])
                 ) {
-                if (comp->pass == PASS_1) {
+                if (comp->pass == MP_PASS_SCOPE) {
                     qstr const_id = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]);
 
                     if (!MP_PARSE_NODE_IS_SMALL_INT(((mp_parse_node_struct_t*)((mp_parse_node_struct_t*)pns1->nodes[0])->nodes[1])->nodes[0])) {
@@ -2153,7 +2153,7 @@
     //mp_parse_node_t pn_params = pns->nodes[0];
     //mp_parse_node_t pn_body = pns->nodes[1];
 
-    if (comp->pass == PASS_1) {
+    if (comp->pass == MP_PASS_SCOPE) {
         // create a new scope for this lambda
         scope_t *s = scope_new_and_link(comp, SCOPE_LAMBDA, (mp_parse_node_t)pns, comp->scope_cur->emit_options);
         // store the lambda scope so the compiling function (this one) can use it at each pass
@@ -2499,7 +2499,7 @@
     assert(MP_PARSE_NODE_IS_STRUCT_KIND(pns->nodes[1], PN_comp_for));
     mp_parse_node_struct_t *pns_comp_for = (mp_parse_node_struct_t*)pns->nodes[1];
 
-    if (comp->pass == PASS_1) {
+    if (comp->pass == MP_PASS_SCOPE) {
         // create a new scope for this comprehension
         scope_t *s = scope_new_and_link(comp, kind, (mp_parse_node_t)pns, comp->scope_cur->emit_options);
         // store the comprehension scope so the compiling function (this one) can use it at each pass
@@ -3020,7 +3020,7 @@
     comp->next_label = 1;
     EMIT_ARG(start_pass, pass, scope);
 
-    if (comp->pass == PASS_1) {
+    if (comp->pass == MP_PASS_SCOPE) {
         // reset maximum stack sizes in scope
         // they will be computed in this first pass
         scope->stack_size = 0;
@@ -3028,7 +3028,7 @@
     }
 
 #if MICROPY_EMIT_CPYTHON
-    if (comp->pass == PASS_3) {
+    if (comp->pass == MP_PASS_EMIT) {
         scope_print_info(scope);
     }
 #endif
@@ -3053,7 +3053,7 @@
 
         // work out number of parameters, keywords and default parameters, and add them to the id_info array
         // must be done before compiling the body so that arguments are numbered first (for LOAD_FAST etc)
-        if (comp->pass == PASS_1) {
+        if (comp->pass == MP_PASS_SCOPE) {
             comp->have_star = false;
             apply_to_single_or_list(comp, pns->nodes[1], PN_typedargslist, compile_scope_func_param);
         }
@@ -3073,7 +3073,7 @@
 
         // work out number of parameters, keywords and default parameters, and add them to the id_info array
         // must be done before compiling the body so that arguments are numbered first (for LOAD_FAST etc)
-        if (comp->pass == PASS_1) {
+        if (comp->pass == MP_PASS_SCOPE) {
             comp->have_star = false;
             apply_to_single_or_list(comp, pns->nodes[0], PN_varargslist, compile_scope_lambda_param);
         }
@@ -3104,7 +3104,7 @@
 #else
         qstr qstr_arg = MP_QSTR_;
 #endif
-        if (comp->pass == PASS_1) {
+        if (comp->pass == MP_PASS_SCOPE) {
             bool added;
             id_info_t *id_info = scope_find_or_add_id(comp->scope_cur, qstr_arg, &added);
             assert(added);
@@ -3141,7 +3141,7 @@
         mp_parse_node_struct_t *pns = (mp_parse_node_struct_t*)scope->pn;
         assert(MP_PARSE_NODE_STRUCT_KIND(pns) == PN_classdef);
 
-        if (comp->pass == PASS_1) {
+        if (comp->pass == MP_PASS_SCOPE) {
             bool added;
             id_info_t *id_info = scope_find_or_add_id(scope, MP_QSTR___class__, &added);
             assert(added);
@@ -3177,6 +3177,7 @@
 }
 
 #if MICROPY_EMIT_INLINE_THUMB
+// requires 3 passes: SCOPE, CODE_SIZE, EMIT
 STATIC void compile_scope_inline_asm(compiler_t *comp, scope_t *scope, pass_kind_t pass) {
     comp->pass = pass;
     comp->scope_cur = scope;
@@ -3187,7 +3188,7 @@
         return;
     }
 
-    if (comp->pass > PASS_1) {
+    if (comp->pass > MP_PASS_SCOPE) {
         EMIT_INLINE_ASM_ARG(start_pass, comp->pass, comp->scope_cur);
     }
 
@@ -3199,7 +3200,7 @@
     //qstr f_id = MP_PARSE_NODE_LEAF_ARG(pns->nodes[0]); // function name
 
     // parameters are in pns->nodes[1]
-    if (comp->pass == PASS_2) {
+    if (comp->pass == MP_PASS_CODE_SIZE) {
         mp_parse_node_t *pn_params;
         int n_params = list_get(&pns->nodes[1], PN_typedargslist, &pn_params);
         scope->num_pos_args = EMIT_INLINE_ASM_ARG(count_params, n_params, pn_params);
@@ -3212,7 +3213,7 @@
     int num = list_get(&pn_body, PN_suite_block_stmts, &nodes);
 
     /*
-    if (comp->pass == PASS_3) {
+    if (comp->pass == MP_PASS_EMIT) {
         //printf("----\n");
         scope_print_info(scope);
     }
@@ -3250,7 +3251,7 @@
                 return;
             }
             uint lab = comp_next_label(comp);
-            if (pass > PASS_1) {
+            if (pass > MP_PASS_SCOPE) {
                 EMIT_INLINE_ASM_ARG(label, lab, MP_PARSE_NODE_LEAF_ARG(pn_arg[0]));
             }
         } else if (op == MP_QSTR_align) {
@@ -3258,7 +3259,7 @@
                 compile_syntax_error(comp, nodes[i], "inline assembler 'align' requires 1 argument");
                 return;
             }
-            if (pass > PASS_1) {
+            if (pass > MP_PASS_SCOPE) {
                 EMIT_INLINE_ASM_ARG(align, MP_PARSE_NODE_LEAF_SMALL_INT(pn_arg[0]));
             }
         } else if (op == MP_QSTR_data) {
@@ -3266,7 +3267,7 @@
                 compile_syntax_error(comp, nodes[i], "inline assembler 'data' requires at least 2 arguments");
                 return;
             }
-            if (pass > PASS_1) {
+            if (pass > MP_PASS_SCOPE) {
                 machine_int_t bytesize = MP_PARSE_NODE_LEAF_SMALL_INT(pn_arg[0]);
                 for (uint i = 1; i < n_args; i++) {
                     if (!MP_PARSE_NODE_IS_SMALL_INT(pn_arg[i])) {
@@ -3277,13 +3278,13 @@
                 }
             }
         } else {
-            if (pass > PASS_1) {
+            if (pass > MP_PASS_SCOPE) {
                 EMIT_INLINE_ASM_ARG(op, op, n_args, pn_arg);
             }
         }
     }
 
-    if (comp->pass > PASS_1) {
+    if (comp->pass > MP_PASS_SCOPE) {
         bool success = EMIT_INLINE_ASM(end_pass);
         if (!success) {
             comp->had_error = true;
@@ -3438,10 +3439,10 @@
         if (false) {
 #if MICROPY_EMIT_INLINE_THUMB
         } else if (s->emit_options == MP_EMIT_OPT_ASM_THUMB) {
-            compile_scope_inline_asm(comp, s, PASS_1);
+            compile_scope_inline_asm(comp, s, MP_PASS_SCOPE);
 #endif
         } else {
-            compile_scope(comp, s, PASS_1);
+            compile_scope(comp, s, MP_PASS_SCOPE);
         }
 
         // update maximim number of labels needed
@@ -3482,9 +3483,9 @@
             comp->emit_method_table = NULL;
             comp->emit_inline_asm = emit_inline_thumb;
             comp->emit_inline_asm_method_table = &emit_inline_thumb_method_table;
-            compile_scope_inline_asm(comp, s, PASS_2);
+            compile_scope_inline_asm(comp, s, MP_PASS_CODE_SIZE);
             if (!comp->had_error) {
-                compile_scope_inline_asm(comp, s, PASS_3);
+                compile_scope_inline_asm(comp, s, MP_PASS_EMIT);
             }
 #endif
 
@@ -3514,6 +3515,10 @@
 #endif
                     comp->emit = emit_native;
                     comp->emit_method_table->set_native_types(comp->emit, s->emit_options == MP_EMIT_OPT_VIPER);
+
+                    // native emitters need an extra pass to compute stack size
+                    compile_scope(comp, s, MP_PASS_STACK_SIZE);
+
                     break;
 #endif // MICROPY_EMIT_NATIVE
 
@@ -3527,10 +3532,14 @@
             }
 #endif // !MICROPY_EMIT_CPYTHON
 
-            // compile pass 2 and pass 3
-            compile_scope(comp, s, PASS_2);
+            // second last pass: compute code size
             if (!comp->had_error) {
-                compile_scope(comp, s, PASS_3);
+                compile_scope(comp, s, MP_PASS_CODE_SIZE);
+            }
+
+            // final pass: emit code
+            if (!comp->had_error) {
+                compile_scope(comp, s, MP_PASS_EMIT);
             }
         }
     }