niti: keep the fatal_error information
[nit.git] / src / interpreter / naive_interpreter.nit
index 34530b7..7b22a58 100644 (file)
@@ -121,6 +121,9 @@ class NaiveInterpreter
        # The count of `catch` blocs that have been encountered and can catch an abort
        var catch_count = 0
 
+       # The last error thrown on abort/runtime error where catch_count > 0
+       var last_error: nullable FatalError = null
+
        # Is a return or a break or a continue executed?
        # Use this function to know if you must skip the evaluation of statements
        fun is_escaping: Bool do return escapemark != null
@@ -685,15 +688,25 @@ class NaiveInterpreter
        var error_instance = new MutableInstance(modelbuilder.model.null_type) is lazy
 end
 
+# A runtime error
+class FatalError
+       # The error message
+       var message: String
+
+       # The problematic node, if any
+       var node: nullable ANode
+end
+
 # An instance represents a value of the executed program.
 abstract class Instance
        # The dynamic type of the instance
        # ASSERT: not self.mtype.is_anchored
        var mtype: MType
 
-       # return true if the instance is the true value.
-       # return false if the instance is the true value.
-       # else aborts
+       # Return `true` if the instance is the `true` value.
+       #
+       # Return `false` if the instance is the `false` value.
+       # Abort if the instance is not a boolean value.
        fun is_true: Bool do abort
 
        # Return true if `self` IS `o` (using the Nit semantic of is)
@@ -748,7 +761,7 @@ class MutableInstance
 end
 
 # Special instance to handle primitives values (int, bool, etc.)
-# The trick it just to encapsulate the <<real>> value
+# The trick is just to encapsulate the “real” value.
 class PrimitiveInstance[E]
        super Instance
 
@@ -820,6 +833,12 @@ redef class ANode
        # `v` is used to know if a colored message is displayed or not
        fun fatal(v: NaiveInterpreter, message: String)
        do
+               # Abort if there is a `catch` block
+               if v.catch_count > 0 then
+                       v.last_error = new FatalError(message, self)
+                       abort
+               end
+
                if v.modelbuilder.toolcontext.opt_no_color.value == true then
                        sys.stderr.write("Runtime error: {message} ({location.file.filename}:{location.line_start})\n")
                else
@@ -1174,9 +1193,9 @@ redef class AMethPropdef
                                var ns = recvval.fast_cstring(args[1].to_i)
                                return v.c_string_instance(ns.to_s)
                        else if pname == "fetch_4_chars" then
-                               return v.int_instance(args[0].val.as(CString).fetch_4_chars(args[1].to_i))
+                               return v.uint32_instance(args[0].val.as(CString).fetch_4_chars(args[1].to_i))
                        else if pname == "fetch_4_hchars" then
-                               return v.int_instance(args[0].val.as(CString).fetch_4_hchars(args[1].to_i))
+                               return v.uint32_instance(args[0].val.as(CString).fetch_4_hchars(args[1].to_i))
                        else if pname == "utf8_length" then
                                return v.int_instance(args[0].val.as(CString).utf8_length(args[1].to_i, args[2].to_i))
                        end
@@ -1688,13 +1707,8 @@ end
 redef class AAbortExpr
        redef fun stmt(v)
        do
-               # Abort as asked if there is no `catch` bloc
-               if v.catch_count <= 0 then
-                       fatal(v, "Aborted")
-                       exit(1)
-               else
-                       abort
-               end
+               fatal(v, "Aborted")
+               exit(1)
        end
 end