gitignore nit* in bin/
[nit.git] / src / separate_compiler.nit
index 7b84bb2..c70be37 100644 (file)
@@ -93,19 +93,25 @@ redef class ModelBuilder
                end
                v.add("\}")
 
+               # compile class structures
                for m in mainmodule.in_importation.greaters do
-                       compiler.compile_module_to_c(m)
                        for mclass in m.intro_mclasses do
                                compiler.compile_class_to_c(mclass)
                        end
                end
 
+               # compile methods
+               for m in mainmodule.in_importation.greaters do
+                       compiler.compile_module_to_c(m)
+               end
+
                # compile live & cast type structures
                var mtypes = compiler.do_global_type_coloring
                for t in mtypes do
                        compiler.compile_type_to_c(t)
                end
 
+               # compile live generic types selection structures
                for mclass in model.mclasses do
                        compiler.compile_live_gentype_to_c(mclass)
                end
@@ -463,21 +469,40 @@ class SeparateCompiler
                        return
                end
 
+               var is_native_array = mclass.name == "NativeArray"
+
+               var sig
+               if is_native_array then
+                       sig = "int length, struct type* type"
+               else
+                       sig = "struct type* type"
+               end
+
                #Build instance struct
-               v.add_decl("struct instance_{c_name} \{")
-               v.add_decl("const struct type *type;")
-               v.add_decl("const struct class *class;")
-               v.add_decl("nitattribute_t attrs[{attrs.length}];")
-               v.add_decl("\};")
+               #extern const struct instance_array__NativeArray instance_array__NativeArray;
+               self.header.add_decl("struct instance_{c_name} \{")
+               self.header.add_decl("const struct type *type;")
+               self.header.add_decl("const struct class *class;")
+               self.header.add_decl("nitattribute_t attrs[{attrs.length}];")
+               if is_native_array then
+                       # NativeArrays are just a instance header followed by an array of values
+                       self.header.add_decl("val* values[0];")
+               end
+               self.header.add_decl("\};")
 
 
+               self.header.add_decl("{mtype.ctype} NEW_{c_name}({sig});")
+               v.add_decl("/* allocate {mtype} */")
+               v.add_decl("{mtype.ctype} NEW_{c_name}({sig}) \{")
                var res = v.new_named_var(mtype, "self")
                res.is_exact = true
-
-               self.header.add_decl("{mtype.ctype} NEW_{c_name}(struct type* type);")
-               v.add_decl("/* allocate {mtype} */")
-               v.add_decl("{mtype.ctype} NEW_{c_name}(struct type* type) \{")
-               v.add("{res} = calloc(sizeof(struct instance_{c_name}), 1);")
+               if is_native_array then
+                       var mtype_elt = mtype.arguments.first
+                       v.add("{res} = GC_MALLOC(sizeof(struct instance_{c_name}) + length*sizeof({mtype_elt.ctype}));")
+               else
+                       v.add("{res} = GC_MALLOC(sizeof(struct instance_{c_name}));")
+               end
+               #v.add("{res} = calloc(sizeof(struct instance_{c_name}), 1);")
                v.add("{res}->type = type;")
                v.add("{res}->class = (struct class*) &class_{c_name};")
 
@@ -868,19 +893,27 @@ class SeparateCompilerVisitor
                var res = self.new_var(bool_type)
                var buff = new Buffer
 
-               if mtype isa MNullableType then mtype = mtype.mtype
+               var s: String
+               if mtype isa MNullableType then
+                       mtype = mtype.mtype
+                       s = "{value} == NULL ||"
+               else
+                       s = "{value} != NULL &&"
+               end
                if mtype isa MGenericType and mtype.need_anchor then
                        for ft in mtype.mclass.mclass_type.arguments do
                                var ftcolor = compiler.ft_colors[ft.as(MParameterType)]
                                buff.append("[self->type->fts_table->fts[{ftcolor}]->id]")
                        end
-                       self.add("{res} = {value}->type->type_table[livetypes_{mtype.mclass.c_name}{buff.to_s}->color] == livetypes_{mtype.mclass.c_name}{buff.to_s}->id;")
+                       self.add("{res} = {s} {value}->type->type_table[livetypes_{mtype.mclass.c_name}{buff.to_s}->color] == livetypes_{mtype.mclass.c_name}{buff.to_s}->id;")
                else if mtype isa MClassType then
                        compiler.undead_types.add(mtype)
-                       self.add("{res} = {value}->type->type_table[type_{mtype.c_name}.color] == type_{mtype.c_name}.id;")
+                       self.add("{res} = {s} {value}->type->type_table[type_{mtype.c_name}.color] == type_{mtype.c_name}.id;")
                else if mtype isa MParameterType then
                        var ftcolor = compiler.ft_colors[mtype]
-                       self.add("{res} = {value}->type->type_table[self->type->fts_table->fts[{ftcolor}]->color] == self->type->fts_table->fts[{ftcolor}]->id;")
+                       self.add("{res} = {s} {value}->type->type_table[self->type->fts_table->fts[{ftcolor}]->color] == self->type->fts_table->fts[{ftcolor}]->id;")
+               else
+                       add("printf(\"NOT YET IMPLEMENTED: type_test(%s, {mtype}).\\n\", \"{value.inspect}\"); exit(1);")
                end
 
                return res
@@ -889,8 +922,24 @@ class SeparateCompilerVisitor
        redef fun is_same_type_test(value1, value2)
        do
                var res = self.new_var(bool_type)
-               # TODO
-               add("printf(\"NOT YET IMPLEMENTED: is_same_type(%s,%s).\\n\", \"{value1.inspect}\", \"{value2.inspect}\"); exit(1);")
+               # Swap values to be symetric
+               if value2.mtype.ctype != "val*" and value1.mtype.ctype == "val*" then
+                       var tmp = value1
+                       value1 = value2
+                       value2 = tmp
+               end
+               if value1.mtype.ctype != "val*" then
+                       if value2.mtype.ctype == value1.mtype.ctype then
+                               self.add("{res} = 1; /* is_same_type_test: compatible types {value1.mtype} vs. {value2.mtype} */")
+                       else if value2.mtype.ctype != "val*" then
+                               self.add("{res} = 0; /* is_same_type_test: incompatible types {value1.mtype} vs. {value2.mtype}*/")
+                       else
+                               var mtype1 = value1.mtype.as(MClassType)
+                               self.add("{res} = ({value2} != NULL) && ({value2}->class == (struct class*) &class_{mtype1.c_name}); /* is_same_type_test */")
+                       end
+               else
+                       self.add("{res} = ({value1} == {value2}) || ({value1} != NULL && {value2} != NULL && {value1}->class == {value2}->class); /* is_same_type_test */")
+               end
                return res
        end
 
@@ -924,10 +973,70 @@ class SeparateCompilerVisitor
                                self.add("\}")
                        end
                else
-                       self.add("{res} = {value1} == {value2};")
+                       var s = new Array[String]
+                       # This is just ugly on so many level. this works but must be rewriten
+                       for t in self.compiler.live_primitive_types do
+                               if not t.is_subtype(self.compiler.mainmodule, null, value1.mcasttype) then continue
+                               if not t.is_subtype(self.compiler.mainmodule, null, value2.mcasttype) then continue
+                               s.add "({value1}->class == (struct class*)&class_{t.c_name} && ((struct instance_{t.c_name}*){value1})->value == ((struct instance_{t.c_name}*){value2})->value)"
+                       end
+                       if s.is_empty then
+                               self.add("{res} = {value1} == {value2};")
+                       else
+                               self.add("{res} = {value1} == {value2} || ({value1} != NULL && {value2} != NULL && {value1}->class == {value2}->class && ({s.join(" || ")}));")
+                       end
                end
                return res
        end
+
+       redef fun array_instance(array, elttype)
+       do
+               var compiler = self.compiler.as(SeparateCompiler)
+               var nclass = self.get_class("NativeArray")
+               elttype = self.anchor(elttype)
+               var arraytype = self.get_class("Array").get_mtype([elttype])
+               var res = self.init_instance(arraytype)
+               self.add("\{ /* {res} = array_instance Array[{elttype}] */")
+               var nat = self.new_var(self.get_class("NativeArray").get_mtype([elttype]))
+               nat.is_exact = true
+               compiler.undead_types.add(nat.mtype.as(MClassType))
+               self.add("{nat} = NEW_{nclass.c_name}({array.length}, (struct type *) &type_{nat.mtype.c_name});")
+               for i in [0..array.length[ do
+                       var r = self.autobox(array[i], self.object_type)
+                       self.add("((struct instance_{nclass.c_name}*){nat})->values[{i}] = (val*) {r};")
+               end
+               var length = self.int_instance(array.length)
+               self.send(self.get_property("with_native", arraytype), [res, nat, length])
+               self.check_init_instance(res)
+               self.add("\}")
+               return res
+       end
+
+       redef fun native_array_def(pname, ret_type, arguments)
+       do
+               var elttype = arguments.first.mtype
+               var nclass = self.get_class("NativeArray")
+               var recv = "((struct instance_{nclass.c_name}*){arguments[0]})->values"
+               if pname == "[]" then
+                       self.ret(self.new_expr("{recv}[{arguments[1]}]", ret_type.as(not null)))
+                       return
+               else if pname == "[]=" then
+                       self.add("{recv}[{arguments[1]}]={arguments[2]};")
+                       return
+               else if pname == "copy_to" then
+                       var recv1 = "((struct instance_{nclass.c_name}*){arguments[1]})->values"
+                       self.add("memcpy({recv1}, {recv}, {arguments[2]}*sizeof({elttype.ctype}));")
+                       return
+               end
+       end
+
+       redef fun calloc_array(ret_type, arguments)
+       do
+               var ret = ret_type.as(MClassType)
+               var compiler = self.compiler.as(SeparateCompiler)
+               compiler.undead_types.add(ret)
+               self.ret(self.new_expr("NEW_{ret.mclass.c_name}({arguments[1]}, (struct type*) &type_{ret_type.c_name})", ret_type))
+       end
 end
 
 redef class MClass