py/compile: Give more precise line number for compile errors.

Previous to this patch there were some cases where line numbers for
errors were 0 (unknown).  Now the compiler attempts to give a better
line number where possible, in some cases giving the line number of the
closest statement, and other cases the line number of the inner-most
scope of the error (eg the line number of the start of the function).
This helps to give good (and sometimes exact) line numbers for
ViperTypeError exceptions.

This patch also makes sure that the first compile error (eg SyntaxError)
that is encountered is reported (previously it was the last one that was
reported).
diff --git a/py/compile.c b/py/compile.c
index 12134d4..a124203 100644
--- a/py/compile.c
+++ b/py/compile.c
@@ -81,8 +81,8 @@
     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;
+    mp_obj_t compile_error; // set to an exception object if there's an error
+    mp_uint_t compile_error_line; // set to best guess of line of error
 
     uint next_label;
 
@@ -108,20 +108,19 @@
     #endif
 } compiler_t;
 
-STATIC void compile_error_add_traceback(compiler_t *comp, mp_parse_node_t pn) {
-    mp_uint_t line;
-    if (MP_PARSE_NODE_IS_STRUCT(pn)) {
-        line = (mp_uint_t)((mp_parse_node_struct_t*)pn)->source_line;
-    } else {
-        // we don't have a line number, so just pass 0
-        line = 0;
+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)) {
+        comp->compile_error_line = (mp_uint_t)((mp_parse_node_struct_t*)pn)->source_line;
     }
-    mp_obj_exception_add_traceback(comp->compile_error, comp->source_file, line, comp->scope_cur->simple_name);
 }
 
 STATIC void compile_syntax_error(compiler_t *comp, mp_parse_node_t pn, const char *msg) {
-    comp->compile_error = mp_obj_new_exception_msg(&mp_type_SyntaxError, msg);
-    compile_error_add_traceback(comp, pn);
+    // 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);
+    }
 }
 
 #if MICROPY_COMP_MODULE_CONST
@@ -421,6 +420,11 @@
     int num_nodes = MP_PARSE_NODE_STRUCT_NUM_NODES(pns);
     for (int i = 0; i < num_nodes; i++) {
         compile_node(comp, pns->nodes[i]);
+        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;
+        }
     }
 }
 
@@ -3535,9 +3539,9 @@
     }
 
     if (comp->compile_error != MP_OBJ_NULL) {
-        // inline assembler had an error; add traceback to its exception
+        // inline assembler had an error; set line for its exception
     inline_asm_error:
-        mp_obj_exception_add_traceback(comp->compile_error, comp->source_file, (mp_uint_t)pns->source_line, comp->scope_cur->simple_name);
+        comp->compile_error_line = pns->source_line;
     }
 }
 #endif
@@ -3822,16 +3826,18 @@
             if (comp->compile_error == MP_OBJ_NULL) {
                 compile_scope(comp, s, MP_PASS_EMIT);
             }
-
-            #if MICROPY_EMIT_NATIVE
-            // if viper had an error then add traceback
-            if (comp->compile_error != MP_OBJ_NULL && s->emit_options == MP_EMIT_OPT_VIPER) {
-                compile_error_add_traceback(comp, s->pn);
-            }
-            #endif
         }
     }
 
+    if (comp->compile_error != MP_OBJ_NULL) {
+        // if there is no line number for the error then use the line
+        // number for the start of this scope
+        compile_error_set_line(comp, comp->scope_cur->pn);
+        // add a traceback to the exception using relevant source info
+        mp_obj_exception_add_traceback(comp->compile_error, comp->source_file,
+            comp->compile_error_line, comp->scope_cur->simple_name);
+    }
+
     // free the emitters
 
 #if MICROPY_EMIT_CPYTHON