niti: do not create `true` and `false` if Bool does not exists
[nit.git] / src / interpreter / naive_interpreter.nit
index f47d9d1..74a1929 100644 (file)
@@ -71,11 +71,13 @@ class NaiveInterpreter
 
        init
        do
-               self.true_instance = new PrimitiveInstance[Bool](mainmodule.bool_type, true)
-               init_instance_primitive(self.true_instance)
-               self.false_instance = new PrimitiveInstance[Bool](mainmodule.bool_type, false)
-               init_instance_primitive(self.false_instance)
-               self.null_instance = new MutableInstance(mainmodule.model.null_type)
+               if mainmodule.model.get_mclasses_by_name("Bool") != null then
+                       self.true_instance = new PrimitiveInstance[Bool](mainmodule.bool_type, true)
+                       init_instance_primitive(self.true_instance)
+                       self.false_instance = new PrimitiveInstance[Bool](mainmodule.bool_type, false)
+                       init_instance_primitive(self.false_instance)
+               end
+               self.null_instance = new PrimitiveInstance[nullable Object](mainmodule.model.null_type, null)
        end
 
        # Starts the interpreter on the main module of a program
@@ -100,13 +102,14 @@ class NaiveInterpreter
        # Subtype test in the context of the mainmodule
        fun is_subtype(sub, sup: MType): Bool
        do
-               return sub.is_subtype(self.mainmodule, self.frame.arguments.first.mtype.as(MClassType), sup)
+               return sub.is_subtype(self.mainmodule, current_receiver_class, sup)
        end
 
+       # Get a primitive method in the context of the main module
        fun force_get_primitive_method(name: String, recv: MType): MMethod
        do
                assert recv isa MClassType
-               return self.modelbuilder.force_get_primitive_method(self.frame.current_node, name, recv.mclass, self.mainmodule)
+               return self.modelbuilder.force_get_primitive_method(current_node, name, recv.mclass, self.mainmodule)
        end
 
        # Is a return executed?
@@ -238,6 +241,8 @@ class NaiveInterpreter
                return res
        end
 
+       # Return a instance associated to a primitive class
+       # Current primitive classes are `Int`, `Bool`, and `String`
        fun value_instance(object: Object): Instance
        do
                if object isa Int then
@@ -289,13 +294,27 @@ class NaiveInterpreter
                return b.to_s
        end
 
+       # The current node, used to print errors, debug and stack-traces
+       fun current_node: nullable ANode
+       do
+               if frames.is_empty then return null
+               return frames.first.current_node
+       end
+
+       # The dynamic type of the current `self`
+       fun current_receiver_class: MClassType
+       do
+               return frames.first.arguments.first.mtype.as(MClassType)
+       end
+
        # Exit the program with a message
        fun fatal(message: String)
        do
-               if frames.is_empty then
+               var node = current_node
+               if node == null then
                        print message
                else
-                       self.frame.current_node.fatal(self, message)
+                       node.fatal(self, message)
                end
                exit(1)
        end
@@ -303,10 +322,11 @@ class NaiveInterpreter
        # Debug on the current node
        fun debug(message: String)
        do
-               if frames.is_empty then
+               var node = current_node
+               if node == null then
                        print message
                else
-                       self.frame.current_node.debug(message)
+                       node.debug(message)
                end
        end
 
@@ -383,16 +403,18 @@ class NaiveInterpreter
                assert args.length == mpropdef.msignature.arity + 1 else debug("Invalid arity for {mpropdef}. {args.length} arguments given.")
 
                # Look for the AST node that implements the property
-               var mproperty = mpropdef.mproperty
                var val = mpropdef.constant_value
-               if self.modelbuilder.mpropdef2npropdef.has_key(mpropdef) then
-                       var npropdef = self.modelbuilder.mpropdef2npropdef[mpropdef]
-                       self.parameter_check(npropdef, mpropdef, args)
-                       return npropdef.call(self, mpropdef, args)
-               else if mproperty.is_root_init then
-                       var nclassdef = self.modelbuilder.mclassdef2nclassdef[mpropdef.mclassdef]
-                       self.parameter_check(nclassdef, mpropdef, args)
-                       return nclassdef.call(self, mpropdef, args)
+
+               var node = modelbuilder.mpropdef2node(mpropdef)
+               if node isa APropdef then
+                       self.parameter_check(node, mpropdef, args)
+                       return node.call(self, mpropdef, args)
+               else if node isa AClassdef then
+                       self.parameter_check(node, mpropdef, args)
+                       return node.call(self, mpropdef, args)
+               else if node != null then
+                       fatal("Fatal Error: method {mpropdef} associated to unexpected AST node {node.location}")
+                       abort
                else if val != null then
                        return value_instance(val)
                else
@@ -401,7 +423,7 @@ class NaiveInterpreter
                end
        end
 
-       # Generate type checks in the C code to check covariant parameters
+       # Execute type checks of covariant parameters
        fun parameter_check(node: ANode, mpropdef: MMethodDef, args: Array[Instance])
        do
                var msignature = mpropdef.msignature
@@ -413,6 +435,8 @@ class NaiveInterpreter
                        var origmtype =  mpropdef.mproperty.intro.msignature.mparameters[i].mtype
                        if not origmtype.need_anchor then continue
 
+                       #print "{mpropdef}: {mpropdef.mproperty.intro.msignature.mparameters[i]}"
+
                        # get the parameter type
                        var mtype = msignature.mparameters[i].mtype
                        var anchor = args.first.mtype.as(MClassType)
@@ -456,7 +480,7 @@ class NaiveInterpreter
                                        self.send(p, args)
                                else if p isa MAttribute then
                                        assert recv isa MutableInstance
-                                       recv.attributes[p] = arguments[i]
+                                       write_attribute(p, recv, arguments[i])
                                        i += 1
                                else abort
                        end
@@ -516,13 +540,7 @@ class NaiveInterpreter
                var cds = mtype.collect_mclassdefs(self.mainmodule).to_a
                self.mainmodule.linearize_mclassdefs(cds)
                for cd in cds do
-                       if not self.modelbuilder.mclassdef2nclassdef.has_key(cd) then continue
-                       var n = self.modelbuilder.mclassdef2nclassdef[cd]
-                       for npropdef in n.n_propdefs do
-                               if npropdef isa AAttrPropdef then
-                                       res.add(npropdef)
-                               end
-                       end
+                       res.add_all(modelbuilder.collect_attr_propdef(cd))
                end
 
                cache[mtype] = res
@@ -550,10 +568,10 @@ class NaiveInterpreter
                return mainmodule.get_primitive_class(name)
        end
 
-       # This function determine the correct type according the reciever of the current definition (self).
+       # This function determines the correct type according to the receiver of the current propdef (self).
        fun unanchor_type(mtype: MType): MType
        do
-               return mtype.anchor_to(self.mainmodule, self.frame.arguments.first.mtype.as(MClassType))
+               return mtype.anchor_to(self.mainmodule, current_receiver_class)
        end
 
        # Placebo instance used to mark internal error result when `null` already have a meaning.
@@ -588,7 +606,7 @@ abstract class Instance
 
        # The real value encapsulated if the instance is primitive.
        # Else aborts.
-       fun val: Object do abort
+       fun val: nullable Object do abort
 end
 
 # A instance with attribute (standards objects)
@@ -601,7 +619,7 @@ end
 
 # Special instance to handle primitives values (int, bool, etc.)
 # The trick it just to encapsulate the <<real>> value
-class PrimitiveInstance[E: Object]
+class PrimitiveInstance[E]
        super Instance
 
        # The real value encapsulated
@@ -616,17 +634,17 @@ class PrimitiveInstance[E: Object]
 
        redef fun ==(o)
        do
-               if not o isa PrimitiveInstance[Object] then return false
+               if not o isa PrimitiveInstance[nullable Object] then return false
                return self.val == o.val
        end
 
        redef fun eq_is(o)
        do
-               if not o isa PrimitiveInstance[Object] then return false
+               if not o isa PrimitiveInstance[nullable Object] then return false
                return self.val.is_same_instance(o.val)
        end
 
-       redef fun to_s do return "{mtype}#{val.object_id}({val})"
+       redef fun to_s do return "{mtype}#{val.object_id}({val or else "null"})"
 
        redef fun to_i do return val.as(Int)