Merge remote-tracking branch 'origin/master' into init_auto
[nit.git] / src / interpreter / naive_interpreter.nit
index d417d9e..7389e2e 100644 (file)
@@ -113,17 +113,20 @@ class NaiveInterpreter
                return self.modelbuilder.force_get_primitive_method(current_node, name, recv.mclass, self.mainmodule)
        end
 
-       # Is a return executed?
-       # Set this mark to skip the evaluation until the end of the specified method frame
-       var returnmark: nullable FRAME = null
-
-       # Is a break or a continue executed?
+       # Is a return, a break or a continue executed?
        # Set this mark to skip the evaluation until a labeled statement catch it with `is_escape`
        var escapemark: nullable EscapeMark = null
 
+       # Is an abort being executed ?
+       # Set this mark to return to the last `catch` bloc or effectively aborting if there isn't any
+       var catch_mark = new EscapeMark
+
+       # The count of `catch` blocs that have been encountered and can catch an abort
+       var catch_count = 0
+
        # 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 returnmark != null or escapemark != null
+       fun is_escaping: Bool do return escapemark != null
 
        # The value associated with the current return/break/continue, if any.
        # Set the value when you set a escapemark.
@@ -447,7 +450,7 @@ class NaiveInterpreter
        # Return `null` if one of the evaluation of the arguments return null.
        fun varargize(mpropdef: MMethodDef, map: nullable SignatureMap, recv: Instance, args: SequenceRead[AExpr]): nullable Array[Instance]
        do
-               var msignature = mpropdef.new_msignature or else mpropdef.msignature.as(not null)
+               var msignature = mpropdef.msignature.as(not null)
                var res = new Array[Instance]
                res.add(recv)
 
@@ -579,28 +582,6 @@ class NaiveInterpreter
        fun callsite(callsite: nullable CallSite, arguments: Array[Instance]): nullable Instance
        do
                if callsite == null then return null
-               var initializers = callsite.mpropdef.initializers
-               if not initializers.is_empty then
-                       var recv = arguments.first
-                       var i = 1
-                       for p in initializers do
-                               if p isa MMethod then
-                                       var args = [recv]
-                                       for x in p.intro.msignature.mparameters do
-                                               args.add arguments[i]
-                                               i += 1
-                                       end
-                                       self.send(p, args)
-                               else if p isa MAttribute then
-                                       assert recv isa MutableInstance
-                                       write_attribute(p, recv, arguments[i])
-                                       i += 1
-                               else abort
-                       end
-                       assert i == arguments.length
-
-                       return send(callsite.mproperty, [recv])
-               end
                return send(callsite.mproperty, arguments)
        end
 
@@ -848,10 +829,8 @@ redef class AMethPropdef
                var f = v.new_frame(self, mpropdef, args)
                var res = call_commons(v, mpropdef, args, f)
                v.frames.shift
-               if v.returnmark == f then
-                       v.returnmark = null
+               if v.is_escape(self.return_mark) then
                        res = v.escapevalue
-                       v.escapevalue = null
                        return res
                end
                return res
@@ -1012,9 +991,6 @@ redef class AMethPropdef
                                return v.int32_instance(recvval.to_i32)
                        else if pname == "to_u32" then
                                return v.uint32_instance(recvval.to_u32)
-                       else if pname == "rand" then
-                               var res = recvval.rand
-                               return v.int_instance(res)
                        end
                else if cname == "Byte" then
                        var recvval = args[0].to_b
@@ -1140,8 +1116,6 @@ redef class AMethPropdef
                                return v.float_instance(args[0].to_f.log)
                        else if pname == "pow" then
                                return v.float_instance(args[0].to_f.pow(args[1].to_f))
-                       else if pname == "rand" then
-                               return v.float_instance(args[0].to_f.rand)
                        else if pname == "abs" then
                                return v.float_instance(args[0].to_f.abs)
                        else if pname == "hypot_with" then
@@ -1550,10 +1524,9 @@ redef class AAttrPropdef
                        val = v.expr(nexpr)
                else if nblock != null then
                        v.stmt(nblock)
-                       assert v.returnmark == f
+                       assert v.escapemark == return_mark
                        val = v.escapevalue
-                       v.returnmark = null
-                       v.escapevalue = null
+                       v.escapemark = null
                else
                        abort
                end
@@ -1578,6 +1551,31 @@ redef class AClassdef
                                v.call(superpd, arguments)
                        end
                        return null
+               else if mclassdef.auto_init == mpropdef then
+                       var recv = arguments.first
+                       var initializers = mpropdef.initializers
+                       var no_init = false
+                       if not initializers.is_empty then
+                               var i = 1
+                               for p in initializers do
+                                       if p isa MMethod then
+                                               var args = [recv]
+                                               for x in p.intro.msignature.mparameters do
+                                                       args.add arguments[i]
+                                                       i += 1
+                                               end
+                                               v.send(p, args)
+                                               if p.intro.is_calling_init then no_init = true
+                                       else if p isa MAttribute then
+                                               assert recv isa MutableInstance
+                                               v.write_attribute(p, recv, arguments[i])
+                                               i += 1
+                                       else abort
+                               end
+                               assert i == arguments.length
+                       end
+                       if not no_init then v.send(mclass.the_root_init_mmethod.as(not null), [recv])
+                       return null
                else
                        abort
                end
@@ -1698,24 +1696,17 @@ redef class AEscapeExpr
        end
 end
 
-redef class AReturnExpr
-       redef fun stmt(v)
-       do
-               var ne = self.n_expr
-               if ne != null then
-                       var i = v.expr(ne)
-                       if i == null then return
-                       v.escapevalue = i
-               end
-               v.returnmark = v.frame
-       end
-end
-
 redef class AAbortExpr
        redef fun stmt(v)
        do
-               fatal(v, "Aborted")
-               exit(1)
+               # Abort as asked if there is no `catch` bloc
+               if v.catch_count <= 0 then
+                       fatal(v, "Aborted")
+                       exit(1)
+               else
+                       # Abort mode, skipping everything until a `catch` bloc is reached
+                       v.escapemark = v.catch_mark
+               end
        end
 end
 
@@ -1759,8 +1750,15 @@ end
 redef class ADoExpr
        redef fun stmt(v)
        do
+               # If this bloc has a catch, register it in the counter
+               if self.n_catch != null then v.catch_count += 1
                v.stmt(self.n_block)
                v.is_escape(self.break_mark) # Clear the break (if any)
+               if self.n_catch != null then
+                       v.catch_count -= 1
+                       # Are we in abort mode? then this catch is executing
+                       if v.is_escape(v.catch_mark) then v.stmt(self.n_catch)
+               end
        end
 end
 
@@ -1848,7 +1846,13 @@ redef class AWithExpr
                v.callsite(method_start, [expr])
                v.stmt(self.n_block)
                v.is_escape(self.break_mark) # Clear the break
+
+               # Execute the finally without an escape
+               var old_mark = v.escapemark
+               v.escapemark = null
                v.callsite(method_finish, [expr])
+               # Restore the escape unless another escape was provided
+               if v.escapemark == null then v.escapemark = old_mark
        end
 end