modelize: add `AAttrPropdef::mtype` to factorize the type access
[nit.git] / src / interpreter / naive_interpreter.nit
index 311d917..91c4a87 100644 (file)
@@ -201,8 +201,17 @@ class NaiveInterpreter
        # Return the integer instance associated with `val`.
        fun int_instance(val: Int): Instance
        do
-               var ic = get_primitive_class("Int")
-               var instance = new PrimitiveInstance[Int](ic.mclass_type, val)
+               var t = mainmodule.int_type
+               var instance = new PrimitiveInstance[Int](t, val)
+               init_instance_primitive(instance)
+               return instance
+       end
+
+       # Return the byte instance associated with `val`.
+       fun byte_instance(val: Byte): Instance
+       do
+               var t = mainmodule.byte_type
+               var instance = new PrimitiveInstance[Byte](t, val)
                init_instance_primitive(instance)
                return instance
        end
@@ -210,8 +219,8 @@ class NaiveInterpreter
        # Return the char instance associated with `val`.
        fun char_instance(val: Char): Instance
        do
-               var ic = get_primitive_class("Char")
-               var instance = new PrimitiveInstance[Char](ic.mclass_type, val)
+               var t = mainmodule.char_type
+               var instance = new PrimitiveInstance[Char](t, val)
                init_instance_primitive(instance)
                return instance
        end
@@ -219,8 +228,8 @@ class NaiveInterpreter
        # Return the float instance associated with `val`.
        fun float_instance(val: Float): Instance
        do
-               var ic = get_primitive_class("Float")
-               var instance = new PrimitiveInstance[Float](ic.mclass_type, val)
+               var t = mainmodule.float_type
+               var instance = new PrimitiveInstance[Float](t, val)
                init_instance_primitive(instance)
                return instance
        end
@@ -239,9 +248,9 @@ class NaiveInterpreter
        fun array_instance(values: Array[Instance], elttype: MType): Instance
        do
                assert not elttype.need_anchor
-               var nat = new PrimitiveInstance[Array[Instance]](get_primitive_class("NativeArray").get_mtype([elttype]), values)
+               var nat = new PrimitiveInstance[Array[Instance]](mainmodule.native_array_type(elttype), values)
                init_instance_primitive(nat)
-               var mtype = get_primitive_class("Array").get_mtype([elttype])
+               var mtype = mainmodule.array_type(elttype)
                var res = new MutableInstance(mtype)
                self.init_instance(res)
                self.send(self.force_get_primitive_method("with_native", mtype), [res, nat, self.int_instance(values.length)])
@@ -268,8 +277,8 @@ class NaiveInterpreter
        do
                var val = new FlatBuffer.from(txt)
                val.add('\0')
-               var ic = get_primitive_class("NativeString")
-               var instance = new PrimitiveInstance[Buffer](ic.mclass_type, val)
+               var t = mainmodule.native_string_type
+               var instance = new PrimitiveInstance[Buffer](t, val)
                init_instance_primitive(instance)
                return instance
        end
@@ -370,42 +379,50 @@ class NaiveInterpreter
        # This method is used to manage varargs in signatures and returns the real array
        # of instances to use in the call.
        # Return `null` if one of the evaluation of the arguments return null.
-       fun varargize(mpropdef: MMethodDef, recv: Instance, args: SequenceRead[AExpr]): nullable Array[Instance]
+       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 res = new Array[Instance]
                res.add(recv)
 
-               if args.is_empty then return res
+               if msignature.arity == 0 then return res
+
+               if map == null then
+                       assert args.length == msignature.arity else debug("Expected {msignature.arity} args, got {args.length}")
+                       for ne in args do
+                               var e = self.expr(ne)
+                               if e == null then return null
+                               res.add e
+                       end
+                       return res
+               end
+
+               # Eval in order of arguments, not parameters
+               var exprs = new Array[Instance].with_capacity(args.length)
+               for ne in args do
+                       var e = self.expr(ne)
+                       if e == null then return null
+                       exprs.add e
+               end
 
-               var vararg_rank = msignature.vararg_rank
-               var vararg_len = args.length - msignature.arity
-               if vararg_len < 0 then vararg_len = 0
 
+               # Fill `res` with the result of the evaluation according to the mapping
                for i in [0..msignature.arity[ do
-                       if i == vararg_rank then
-                               var ne = args[i]
-                               if ne isa AVarargExpr then
-                                       var e = self.expr(ne.n_expr)
-                                       if e == null then return null
-                                       res.add(e)
-                                       continue
-                               end
-                               var vararg = new Array[Instance]
-                               for j in [vararg_rank..vararg_rank+vararg_len] do
-                                       var e = self.expr(args[j])
-                                       if e == null then return null
-                                       vararg.add(e)
-                               end
-                               var elttype = msignature.mparameters[vararg_rank].mtype.anchor_to(self.mainmodule, recv.mtype.as(MClassType))
-                               res.add(self.array_instance(vararg, elttype))
-                       else
-                               var j = i
-                               if i > vararg_rank then j += vararg_len
-                               var e = self.expr(args[j])
-                               if e == null then return null
-                               res.add(e)
+                       var param = msignature.mparameters[i]
+                       var j = map.map.get_or_null(i)
+                       if j == null then
+                               # default value
+                               res.add(null_instance)
+                               continue
+                       end
+                       if param.is_vararg and map.vararg_decl > 0 then
+                               var vararg = exprs.sub(j, map.vararg_decl)
+                               var elttype = param.mtype.anchor_to(self.mainmodule, recv.mtype.as(MClassType))
+                               var arg = self.array_instance(vararg, elttype)
+                               res.add(arg)
+                               continue
                        end
+                       res.add exprs[j]
                end
                return res
        end
@@ -588,13 +605,6 @@ class NaiveInterpreter
        # A hook to initialize a `PrimitiveInstance`
        fun init_instance_primitive(recv: Instance) do end
 
-       # Return the primitive `MClass` corresponding to the `name` given in parameter
-       # `name` : name of the primitive class
-       fun get_primitive_class(name: String): MClass
-       do
-               return mainmodule.get_primitive_class(name)
-       end
-
        # This function determines the correct type according to the receiver of the current propdef (self).
        fun unanchor_type(mtype: MType): MType
        do
@@ -631,6 +641,10 @@ abstract class Instance
        # else aborts
        fun to_f: Float do abort
 
+       # Return the integer value if the instance is a byte.
+       # else aborts
+       fun to_b: Byte do abort
+
        # The real value encapsulated if the instance is primitive.
        # Else aborts.
        fun val: nullable Object do abort
@@ -676,6 +690,8 @@ class PrimitiveInstance[E]
        redef fun to_i do return val.as(Int)
 
        redef fun to_f do return val.as(Float)
+
+       redef fun to_b do return val.as(Byte)
 end
 
 # Information about local variables in a running method
@@ -840,6 +856,8 @@ redef class AMethPropdef
                        var recvval = args[0].to_i
                        if pname == "unary -" then
                                return v.int_instance(-args[0].to_i)
+                       else if pname == "unary +" then
+                               return args[0]
                        else if pname == "+" then
                                return v.int_instance(args[0].to_i + args[1].to_i)
                        else if pname == "-" then
@@ -864,6 +882,8 @@ redef class AMethPropdef
                                return v.char_instance(args[0].to_i.ascii)
                        else if pname == "to_f" then
                                return v.float_instance(args[0].to_i.to_f)
+                       else if pname == "to_b" then
+                               return v.byte_instance(args[0].to_i.to_b)
                        else if pname == "lshift" then
                                return v.int_instance(args[0].to_i.lshift(args[1].to_i))
                        else if pname == "rshift" then
@@ -891,6 +911,50 @@ redef class AMethPropdef
                        else if pname == "strerror_ext" then
                                return v.native_string_instance(recvval.strerror)
                        end
+               else if cname == "Byte" then
+                       var recvval = args[0].to_b
+                       if pname == "unary -" then
+                               return v.byte_instance(-args[0].to_b)
+                       else if pname == "unary +" then
+                               return args[0]
+                       else if pname == "+" then
+                               return v.byte_instance(args[0].to_b + args[1].to_b)
+                       else if pname == "-" then
+                               return v.byte_instance(args[0].to_b - args[1].to_b)
+                       else if pname == "*" then
+                               return v.byte_instance(args[0].to_b * args[1].to_b)
+                       else if pname == "%" then
+                               return v.byte_instance(args[0].to_b % args[1].to_b)
+                       else if pname == "/" then
+                               return v.byte_instance(args[0].to_b / args[1].to_b)
+                       else if pname == "<" then
+                               return v.bool_instance(args[0].to_b < args[1].to_b)
+                       else if pname == ">" then
+                               return v.bool_instance(args[0].to_b > args[1].to_b)
+                       else if pname == "<=" then
+                               return v.bool_instance(args[0].to_b <= args[1].to_b)
+                       else if pname == ">=" then
+                               return v.bool_instance(args[0].to_b >= args[1].to_b)
+                       else if pname == "<=>" then
+                               return v.int_instance(args[0].to_b <=> args[1].to_b)
+                       else if pname == "to_f" then
+                               return v.float_instance(args[0].to_b.to_f)
+                       else if pname == "to_i" then
+                               return v.int_instance(args[0].to_b.to_i)
+                       else if pname == "lshift" then
+                               return v.byte_instance(args[0].to_b.lshift(args[1].to_i))
+                       else if pname == "rshift" then
+                               return v.byte_instance(args[0].to_b.rshift(args[1].to_i))
+                       else if pname == "byte_to_s_len" then
+                               return v.int_instance(recvval.to_s.length)
+                       else if pname == "native_byte_to_s" then
+                               var s = recvval.to_s
+                               var srecv = args[1].val.as(Buffer)
+                               srecv.clear
+                               srecv.append(s)
+                               srecv.add('\0')
+                               return null
+                       end
                else if cname == "Char" then
                        var recv = args[0].val.as(Char)
                        if pname == "ascii" then
@@ -914,6 +978,8 @@ redef class AMethPropdef
                        var recv = args[0].to_f
                        if pname == "unary -" then
                                return v.float_instance(-recv)
+                       else if pname == "unary +" then
+                               return args[0]
                        else if pname == "+" then
                                return v.float_instance(recv + args[1].to_f)
                        else if pname == "-" then
@@ -932,6 +998,8 @@ redef class AMethPropdef
                                return v.bool_instance(recv >= args[1].to_f)
                        else if pname == "to_i" then
                                return v.int_instance(recv.to_i)
+                       else if pname == "to_b" then
+                               return v.byte_instance(recv.to_b)
                        else if pname == "cos" then
                                return v.float_instance(args[0].to_f.cos)
                        else if pname == "sin" then
@@ -1008,11 +1076,11 @@ redef class AMethPropdef
                        else if pname == "file_exists" then
                                return v.bool_instance(recvval.to_s.file_exists)
                        else if pname == "file_mkdir" then
-                               recvval.to_s.mkdir
-                               return null
+                               var res = recvval.to_s.mkdir
+                               return v.bool_instance(res == null)
                        else if pname == "file_chdir" then
-                               recvval.to_s.chdir
-                               return null
+                               var res = recvval.to_s.chdir
+                               return v.bool_instance(res == null)
                        else if pname == "file_realpath" then
                                return v.native_string_instance(recvval.to_s.realpath)
                        else if pname == "get_environ" then
@@ -1023,6 +1091,9 @@ redef class AMethPropdef
                                return v.int_instance(res)
                        else if pname == "atof" then
                                return v.float_instance(recvval.to_f)
+                       else if pname == "fast_cstring" then
+                               var ns = recvval.to_cstring.to_s.substring_from(args[1].to_i)
+                               return v.native_string_instance(ns)
                        end
                else if cname == "String" then
                        var cs = v.send(v.force_get_primitive_method("to_cstring", args.first.mtype), [args.first])
@@ -1030,7 +1101,7 @@ redef class AMethPropdef
                        if pname == "files" then
                                var res = new Array[Instance]
                                for f in str.files do res.add v.string_instance(f)
-                               return v.array_instance(res, v.get_primitive_class("String").mclass_type)
+                               return v.array_instance(res, v.mainmodule.string_type)
                        end
                else if pname == "calloc_string" then
                        return v.native_string_instance("!" * args[1].to_i)
@@ -1104,15 +1175,6 @@ redef class AMethPropdef
                        else if pname == "set_buffering_type" then
                                return v.int_instance(recvval.as(PrimitiveNativeFile).set_buffering_type(args[1].to_i, args[2].to_i))
                        end
-               else if pname == "calloc_array" then
-                       var recvtype = args.first.mtype.as(MClassType)
-                       var mtype: MType
-                       mtype = recvtype.supertype_to(v.mainmodule, recvtype, v.get_primitive_class("ArrayCapable"))
-                       mtype = mtype.arguments.first
-                       var val = new Array[Instance].filled_with(v.null_instance, args[1].to_i)
-                       var instance = new PrimitiveInstance[Array[Instance]](v.get_primitive_class("NativeArray").get_mtype([mtype]), val)
-                       v.init_instance_primitive(instance)
-                       return instance
                else if pname == "native_argc" then
                        return v.int_instance(v.arguments.length)
                else if pname == "native_argv" then
@@ -1189,7 +1251,7 @@ redef class AAttrPropdef
                end
                var mpropdef = self.mpropdef
                if mpropdef == null then return
-               var mtype = mpropdef.static_mtype.as(not null)
+               var mtype = self.mtype.as(not null)
                mtype = mtype.anchor_to(v.mainmodule, recv.mtype.as(MClassType))
                if mtype isa MNullableType then
                        v.write_attribute(self.mpropdef.mproperty, recv, v.null_instance)
@@ -1286,14 +1348,16 @@ redef class ABlockExpr
 end
 
 redef class AVardeclExpr
-       redef fun stmt(v)
+       redef fun expr(v)
        do
                var ne = self.n_expr
                if ne != null then
                        var i = v.expr(ne)
-                       if i == null then return
+                       if i == null then return null
                        v.write_variable(self.variable.as(not null), i)
+                       return i
                end
+               return null
        end
 end
 
@@ -1334,6 +1398,14 @@ redef class ASelfExpr
        end
 end
 
+redef class AImplicitSelfExpr
+       redef fun expr(v)
+       do
+               if not is_sys then return super
+               return v.mainobj
+       end
+end
+
 redef class AEscapeExpr
        redef fun stmt(v)
        do
@@ -1478,6 +1550,19 @@ redef class AForExpr
        end
 end
 
+redef class AWithExpr
+       redef fun stmt(v)
+       do
+               var expr = v.expr(self.n_expr)
+               if expr == null then return
+
+               v.callsite(method_start, [expr])
+               v.stmt(self.n_block)
+               v.is_escape(self.break_mark) # Clear the break
+               v.callsite(method_finish, [expr])
+       end
+end
+
 redef class AAssertExpr
        redef fun stmt(v)
        do
@@ -1553,6 +1638,13 @@ redef class AIntExpr
        end
 end
 
+redef class AByteExpr
+       redef fun expr(v)
+       do
+               return v.byte_instance(self.value.as(not null))
+       end
+end
+
 redef class AFloatExpr
        redef fun expr(v)
        do
@@ -1606,8 +1698,8 @@ redef class ASuperstringExpr
                        if i == null then return null
                        array.add(i)
                end
-               var i = v.array_instance(array, v.get_primitive_class("Object").mclass_type)
-               var res = v.send(v.force_get_primitive_method("to_s", i.mtype), [i])
+               var i = v.array_instance(array, v.mainmodule.object_type)
+               var res = v.send(v.force_get_primitive_method("plain_to_s", i.mtype), [i])
                assert res != null
                return res
        end
@@ -1726,7 +1818,7 @@ redef class ASendExpr
        do
                var recv = v.expr(self.n_expr)
                if recv == null then return null
-               var args = v.varargize(callsite.mpropdef, recv, self.raw_arguments)
+               var args = v.varargize(callsite.mpropdef, callsite.signaturemap, recv, self.raw_arguments)
                if args == null then return null
 
                var res = v.callsite(callsite, args)
@@ -1739,7 +1831,7 @@ redef class ASendReassignFormExpr
        do
                var recv = v.expr(self.n_expr)
                if recv == null then return
-               var args = v.varargize(callsite.mpropdef, recv, self.raw_arguments)
+               var args = v.varargize(callsite.mpropdef, callsite.signaturemap, recv, self.raw_arguments)
                if args == null then return
                var value = v.expr(self.n_value)
                if value == null then return
@@ -1763,29 +1855,35 @@ redef class ASuperExpr
 
                var callsite = self.callsite
                if callsite != null then
-                       var args = v.varargize(callsite.mpropdef, recv, self.n_args.n_exprs)
-                       if args == null then return null
-                       # Add additional arguments for the super init call
-                       if args.length == 1 then
+                       var args
+                       if self.n_args.n_exprs.is_empty then
+                               # Add automatic arguments for the super init call
+                               args = [recv]
                                for i in [0..callsite.msignature.arity[ do
                                        args.add(v.frame.arguments[i+1])
                                end
+                       else
+                               args = v.varargize(callsite.mpropdef, callsite.signaturemap, recv, self.n_args.n_exprs)
+                               if args == null then return null
                        end
+
                        # Super init call
                        var res = v.callsite(callsite, args)
                        return res
                end
 
-               # standard call-next-method
+               # Standard call-next-method
                var mpropdef = self.mpropdef
                mpropdef = mpropdef.lookup_next_definition(v.mainmodule, recv.mtype)
 
-               var args = v.varargize(mpropdef, recv, self.n_args.n_exprs)
-               if args == null then return null
-
-               if args.length == 1 then
+               var args
+               if self.n_args.n_exprs.is_empty then
                        args = v.frame.arguments
+               else
+                       args = v.varargize(mpropdef, signaturemap, recv, self.n_args.n_exprs)
+                       if args == null then return null
                end
+
                var res = v.call(mpropdef, args)
                return res
        end
@@ -1797,7 +1895,10 @@ redef class ANewExpr
                var mtype = v.unanchor_type(self.recvtype.as(not null))
                var recv: Instance = new MutableInstance(mtype)
                v.init_instance(recv)
-               var args = v.varargize(callsite.mpropdef, recv, self.n_args.n_exprs)
+               var callsite = self.callsite
+               if callsite == null then return recv
+
+               var args = v.varargize(callsite.mpropdef, callsite.signaturemap, recv, self.n_args.n_exprs)
                if args == null then return null
                var res2 = v.callsite(callsite, args)
                if res2 != null then
@@ -1859,6 +1960,20 @@ redef class AIssetAttrExpr
        end
 end
 
+redef class AVarargExpr
+       redef fun expr(v)
+       do
+               return v.expr(self.n_expr)
+       end
+end
+
+redef class ANamedargExpr
+       redef fun expr(v)
+       do
+               return v.expr(self.n_expr)
+       end
+end
+
 redef class ADebugTypeExpr
        redef fun stmt(v)
        do