# Instance abstract representation
v.add_decl("typedef struct \{ struct type *type; struct class *class; nitattribute_t attrs[1]; \} val; /* general C type representing a Nit instance. */")
- # Class names (for the class_name and output_class_name methods)
- v.add_decl("extern const char const * class_names[];")
- v.add("const char const * class_names[] = \{")
- for t in runtime_type_analysis.live_types do
- v.add("\"{t}\",")
- end
- v.add("\};")
# The main function of the C
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 live & cast type structures
- var mtypes = new HashSet[MClassType]
- mtypes.add_all(runtime_type_analysis.live_types)
- mtypes.add_all(runtime_type_analysis.live_cast_types)
+ # 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
+
+ # for the class_name and output_class_name methods
+ compiler.compile_class_names
+
write_and_make(compiler)
end
end
class SeparateCompiler
super GlobalCompiler # TODO better separation of concerns
+ private var undead_types: Set[MClassType] = new HashSet[MClassType]
protected var typeids: HashMap[MClassType, Int] = new HashMap[MClassType, Int]
- private var type_colors: Map[MClassType, Int]
- private var type_tables: Map[MClassType, Array[nullable MClassType]]
+ private var type_colors: Map[MClassType, Int] = typeids
+ private var type_tables: nullable Map[MClassType, Array[nullable MClassType]] = null
+ private var livetypes_tables: nullable Map[MClass, Array[nullable Object]]
+ private var livetypes_tables_sizes: nullable Map[MClass, Array[Int]]
private var class_colors: Map[MClass, Int]
private var ft_tables: Map[MClass, Array[nullable MParameterType]]
init(mainmodule: MModule, runtime_type_analysis: RapidTypeAnalysis, mmbuilder: ModelBuilder) do
-
- # types coloration
- var mtypes = new HashSet[MClassType]
- mtypes.add_all(runtime_type_analysis.live_types)
- mtypes.add_all(runtime_type_analysis.live_cast_types)
-
- for mtype in mtypes do
- self.typeids[mtype] = self.typeids.length
- end
-
- var type_coloring = new TypeColoring(mainmodule, runtime_type_analysis)
- self.type_colors = type_coloring.colorize(mtypes)
- self.type_tables = type_coloring.build_type_tables(mtypes, type_colors)
-
# classes coloration
var class_coloring = new ClassColoring(mainmodule)
self.class_colors = class_coloring.colorize(mmbuilder.model.mclasses)
self.ft_tables = ft_coloring.build_ft_tables
end
+ private fun compile_class_names do
+
+ # Build type names table
+ var type_array = new Array[nullable MClassType]
+ for t, i in typeids do
+ if i >= type_array.length then
+ type_array[i] = null
+ end
+ type_array[i] = t
+ end
+
+ var v = new SeparateCompilerVisitor(self)
+ self.header.add_decl("extern const char const * class_names[];")
+ v.add("const char const * class_names[] = \{")
+ for t in type_array do
+ if t == null then
+ v.add("NULL,")
+ else
+ v.add("\"{t}\",")
+ end
+ end
+ v.add("\};")
+ end
+
+ # colorize live types of the program
+ private fun do_global_type_coloring: Set[MClassType] do
+ var mtypes = new HashSet[MClassType]
+ #print "undead types:"
+ #for t in self.undead_types do
+ # print t
+ #end
+ #print "live types:"
+ #for t in runtime_type_analysis.live_types do
+ # print t
+ #end
+ #print "cast types:"
+ #for t in runtime_type_analysis.live_cast_types do
+ # print t
+ #end
+ #print "--"
+ mtypes.add_all(self.runtime_type_analysis.live_types)
+ mtypes.add_all(self.runtime_type_analysis.live_cast_types)
+ mtypes.add_all(self.undead_types)
+
+ # add formal types arguments to mtypes
+ for mtype in mtypes do
+ if mtype isa MGenericType then
+ #TODO do it recursive
+ for ft in mtype.arguments do
+ if ft isa MNullableType then ft = ft.mtype
+ mtypes.add(ft.as(MClassType))
+ end
+ end
+ end
+
+ # set type unique id
+ for mtype in mtypes do
+ self.typeids[mtype] = self.typeids.length
+ end
+
+ # build livetypes tables
+ self.livetypes_tables = new HashMap[MClass, Array[nullable Object]]
+ self.livetypes_tables_sizes = new HashMap[MClass, Array[Int]]
+ for mtype in mtypes do
+ if mtype isa MGenericType then
+ var table: Array[nullable Object]
+ var sizes: Array[Int]
+ if livetypes_tables.has_key(mtype.mclass) then
+ table = livetypes_tables[mtype.mclass]
+ else
+ table = new Array[nullable Object]
+ self.livetypes_tables[mtype.mclass] = table
+ end
+ if livetypes_tables_sizes.has_key(mtype.mclass) then
+ sizes = livetypes_tables_sizes[mtype.mclass]
+ else
+ sizes = new Array[Int]
+ self.livetypes_tables_sizes[mtype.mclass] = sizes
+ end
+ build_livetype_table(mtype, 0, table, sizes)
+ end
+ end
+
+ # colorize
+ var type_coloring = new TypeColoring(self.mainmodule, self.runtime_type_analysis)
+ self.type_colors = type_coloring.colorize(mtypes)
+ self.type_tables = type_coloring.build_type_tables(mtypes, type_colors)
+
+ return mtypes
+ end
+
+ # build live gentype table recursively
+ private fun build_livetype_table(mtype: MGenericType, current_rank: Int, table: Array[nullable Object], sizes: Array[Int]) do
+ var ft = mtype.arguments[current_rank]
+ if ft isa MNullableType then ft = ft.mtype
+ var id = self.typeids[ft.as(MClassType)]
+
+ if current_rank >= sizes.length then
+ sizes[current_rank] = id + 1
+ else if id >= sizes[current_rank] then
+ sizes[current_rank] = id + 1
+ end
+
+ if id > table.length then
+ for i in [table.length .. id[ do table[i] = null
+ end
+
+ if current_rank == mtype.arguments.length - 1 then
+ table[id] = mtype
+ else
+ var ft_table = new Array[nullable Object]
+ table[id] = ft_table
+ build_livetype_table(mtype, current_rank + 1, ft_table, sizes)
+ end
+ end
+
+ private fun add_to_livetypes_table(table: Array[nullable Object], ft: MClassType) do
+ var id = self.typeids[ft]
+ for i in [table.length .. id[ do
+ table[i] = null
+ end
+ table[id] = ft
+ end
+
+ private fun compile_livetype_table(table: Array[nullable Object], buffer: Buffer, depth: Int, max: Int) do
+ for obj in table do
+ if obj == null then
+ if depth == max then
+ buffer.append("NULL,\n")
+ else
+ buffer.append("\{\},\n")
+ end
+ else if obj isa MClassType then
+ buffer.append("(struct type*) &type_{obj.c_name}, /* {obj} */\n")
+ else if obj isa Array[nullable Object] then
+ buffer.append("\{\n")
+ compile_livetype_table(obj, buffer, depth + 1, max)
+ buffer.append("\},\n")
+ end
+ end
+ end
+
+ # declare live generic types tables selection
+ private fun compile_live_gentype_to_c(mclass: MClass) do
+ if mclass.arity > 0 then
+ if self.livetypes_tables.has_key(mclass) then
+ var table = self.livetypes_tables[mclass]
+ var sign = self.livetypes_tables_sizes[mclass]
+ var table_buffer = new Buffer.from("const struct type *livetypes_{mclass.c_name}[{sign.join("][")}] = \{\n")
+ compile_livetype_table(table, table_buffer, 1, mclass.arity)
+ table_buffer.append("\};")
+
+ var v = new SeparateCompilerVisitor(self)
+ self.header.add_decl("extern const struct type *livetypes_{mclass.c_name}[{sign.join("][")}];")
+ v.add_decl(table_buffer.to_s)
+ else
+ var sign = new Array[Int].filled_with(0, mclass.arity)
+ var v = new SeparateCompilerVisitor(self)
+ self.header.add_decl("extern const struct type *livetypes_{mclass.c_name}[{sign.join("][")}];")
+ v.add_decl("const struct type *livetypes_{mclass.c_name}[{sign.join("][")}];")
+ end
+ end
+ end
+
# Separately compile all the method definitions of the module
fun compile_module_to_c(mmodule: MModule)
do
#print "compile {pd} @ {cd} @ {mmodule}"
var r = new SeparateRuntimeFunction(pd)
r.compile_to_c(self)
- if cd.bound_mtype.ctype != "val*" then
+ if true or cd.bound_mtype.ctype != "val*" then
var r2 = new VirtualRuntimeFunction(pd)
r2.compile_to_c(self)
end
v.add_decl("const struct fts_table_{c_name} fts_table_{c_name} = \{")
v.add_decl("\{")
- if mtype isa MGenericType then
- for ft in self.ft_tables[mtype.mclass] do
- if ft == null then
- v.add_decl("NULL, /* empty */")
+ for ft in self.ft_tables[mtype.mclass] do
+ if ft == null then
+ v.add_decl("NULL, /* empty */")
+ else
+ var id = -1
+ var ntype: MType
+ if ft.mclass == mtype.mclass then
+ ntype = mtype.arguments[ft.rank]
else
- var id = -1
- var ftype: MClassType
- if ft.mclass == mtype.mclass then
- var ntype = mtype.arguments[ft.rank]
- if ntype isa MNullableType then ntype = ntype.mtype
- ftype = ntype.as(MClassType)
- else
- ftype = ft.anchor_to(self.mainmodule, mtype).as(MClassType)
- end
- if self.typeids.has_key(ftype) then
- v.add_decl("(struct type*)&type_{ftype.c_name}, /* {ft} ({ftype}) */")
- else
- v.add_decl("NULL, /* empty ({ft} not a live type) */")
- end
+ ntype = ft.anchor_to(self.mainmodule, mtype)
+ end
+ if ntype isa MNullableType then ntype = ntype.mtype
+ var ftype = ntype.as(MClassType)
+ if self.typeids.has_key(ftype) then
+ v.add_decl("(struct type*)&type_{ftype.c_name}, /* {ft} ({ftype}) */")
+ else
+ v.add_decl("NULL, /* empty ({ft} not a live type) */")
end
end
end
fun compile_class_to_c(mclass: MClass)
do
var mtype = mclass.intro.bound_mtype
- var c_name = mclass.mclass_type.c_name
+ var c_name = mclass.c_name
var vft = self.method_tables[mclass]
var attrs = self.attr_tables[mclass]
-
var v = new SeparateCompilerVisitor(self)
- v.add_decl("/* runtime class {mtype} */")
+ v.add_decl("/* runtime class {c_name} */")
var idnum = classids.length
var idname = "ID_" + c_name
self.classids[mtype] = idname
- self.header.add_decl("#define {idname} {idnum} /* {mtype} */")
+ #self.header.add_decl("#define {idname} {idnum} /* {c_name} */")
self.header.add_decl("struct class_{c_name} \{")
self.header.add_decl("nitmethod_t vft[{vft.length}];")
if mpropdef == null then
v.add_decl("NULL, /* empty */")
else
- if mpropdef.mclassdef.bound_mtype.ctype != "val*" then
+ if true or mpropdef.mclassdef.bound_mtype.ctype != "val*" then
v.add_decl("(nitmethod_t)VIRTUAL_{mpropdef.c_name}, /* pointer to {mclass.intro_mmodule}:{mclass}:{mpropdef} */")
else
v.add_decl("(nitmethod_t){mpropdef.c_name}, /* pointer to {mclass.intro_mmodule}:{mclass}:{mpropdef} */")
if mtype.ctype != "val*" then
#Build instance struct
self.header.add_decl("struct instance_{c_name} \{")
- self.header.add_decl("const struct type_{c_name} *type;")
- self.header.add_decl("const struct class_{c_name} *class;")
+ self.header.add_decl("const struct type *type;")
+ self.header.add_decl("const struct class *class;")
self.header.add_decl("{mtype.ctype} value;")
self.header.add_decl("\};")
- self.header.add_decl("val* BOX_{c_name}({mtype.ctype});")
+ self.header.add_decl("val* BOX_{c_name}({mtype.ctype}, struct type*);")
v.add_decl("/* allocate {mtype} */")
- v.add_decl("val* BOX_{mtype.c_name}({mtype.ctype} value) \{")
+ v.add_decl("val* BOX_{mtype.c_name}({mtype.ctype} value, struct type* type) \{")
v.add("struct instance_{c_name}*res = GC_MALLOC(sizeof(struct instance_{c_name}));")
- if self.typeids.has_key(mtype) then
- v.add("res->type = &type_{c_name};")
- else
- v.add("res->type = NULL;")
- end
- v.add("res->class = &class_{c_name};")
+ v.add("res->type = type;")
+ v.add("res->class = (struct class*) &class_{c_name};")
v.add("res->value = value;")
v.add("return (val*)res;")
v.add("\}")
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_{c_name} *type;")
- v.add_decl("const struct class_{c_name} *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}(struct type *type);")
+ self.header.add_decl("{mtype.ctype} NEW_{c_name}({sig});")
v.add_decl("/* allocate {mtype} */")
- v.add_decl("{mtype.ctype} NEW_{c_name}(struct type *type) \{")
- var res = v.new_var(mtype)
+ v.add_decl("{mtype.ctype} NEW_{c_name}({sig}) \{")
+ var res = v.new_named_var(mtype, "self")
res.is_exact = true
- 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};")
sig.append("void ")
end
sig.append(self.c_name)
- sig.append("({selfvar.mtype.ctype} self")
- comment.append("(self: {recv}")
+ sig.append("({selfvar.mtype.ctype} {selfvar}")
+ comment.append("(self: {selfvar}")
arguments.add(selfvar)
for i in [0..mmethoddef.msignature.arity[ do
var mtype = mmethoddef.msignature.mparameters[i].mtype
var sig = new Buffer
var comment = new Buffer
- var msignature = mmethoddef.mproperty.intro.msignature
+
+ # Because the function is virtual, the signature must match the one of the original class
+ var intromclassdef = self.mmethoddef.mproperty.intro.mclassdef
+ var msignature = mmethoddef.mproperty.intro.msignature.resolve_for(intromclassdef.bound_mtype, intromclassdef.bound_mtype, intromclassdef.mmodule, true)
var ret = msignature.return_mtype
if ret != null then
- ret = v.resolve_for(ret, selfvar)
sig.append("{ret.ctype} ")
else if mmethoddef.mproperty.is_new then
ret = recv
sig.append("void ")
end
sig.append(self.c_name)
- sig.append("({selfvar.mtype.ctype} self")
- comment.append("(self: {recv}")
+ sig.append("({selfvar.mtype.ctype} {selfvar}")
+ comment.append("(self: {selfvar}")
arguments.add(selfvar)
for i in [0..msignature.arity[ do
var mtype = msignature.mparameters[i].mtype
if i == msignature.vararg_rank then
mtype = v.get_class("Array").get_mtype([mtype])
end
- mtype = v.resolve_for(mtype, selfvar)
comment.append(", {mtype}")
sig.append(", {mtype.ctype} p{i}")
var argvar = new RuntimeVariable("p{i}", mtype, mtype)
self.add("printf(\"Dead code executed!\\n\"); exit(1);")
return res
end
- self.add("{res} = BOX_{valtype.c_name}({value}); /* autobox from {value.mtype} to {mtype} */")
+ var totype = value.mtype
+ if totype isa MNullableType then totype = totype.mtype
+ self.add("{res} = BOX_{valtype.c_name}({value}, (struct type*) &type_{totype.c_name}); /* autobox from {value.mtype} to {mtype} */")
return res
else
# Bad things will appen!
var color = self.compiler.as(SeparateCompiler).method_colors[mmethod]
var r
if ret == null then r = "void" else r = ret.ctype
- var call = "(({r} (*)({s}))({arguments.first}->class->vft[{color}]))({ss})"
+ var call = "(({r} (*)({s}))({arguments.first}->class->vft[{color}]))({ss}) /* {mmethod} on {arguments.first.inspect}*/"
if res != null then
self.add("{res} = {call};")
do
# FIXME: Here we inconditionally return boxed primitive attributes
var res = self.new_var(bool_type)
- self.add("{res} = {recv}->attrs[{self.compiler.as(SeparateCompiler).attr_colors[a]}] != NULL;")
+ self.add("{res} = {recv}->attrs[{self.compiler.as(SeparateCompiler).attr_colors[a]}] != NULL; /* {a} on {recv.inspect}*/")
return res
end
var cret = self.object_type.as_nullable
var res = self.new_var(cret)
res.mcasttype = ret
- self.add("{res} = (val*) {recv}->attrs[{self.compiler.as(SeparateCompiler).attr_colors[a]}];")
+ self.add("{res} = {recv}->attrs[{self.compiler.as(SeparateCompiler).attr_colors[a]}]; /* {a} on {recv.inspect} */")
if not ret isa MNullableType then
self.add("if ({res} == NULL) \{")
self.add_abort("Uninitialized attribute {a.name}")
do
# FIXME: Here we inconditionally box primitive attributes
value = self.autobox(value, self.object_type.as_nullable)
- self.add("{recv}->attrs[{self.compiler.as(SeparateCompiler).attr_colors[a]}] = {value};")
+ self.add("{recv}->attrs[{self.compiler.as(SeparateCompiler).attr_colors[a]}] = {value}; /* {a} on {recv.inspect} */")
end
redef fun init_instance(mtype)
do
- mtype = self.anchor(mtype).as(MClassType)
- var res = self.new_expr("NEW_{mtype.mclass.mclass_type.c_name}((struct type*) &type_{mtype.c_name})", mtype)
- return res
+ var compiler = self.compiler.as(SeparateCompiler)
+ if mtype isa MGenericType and mtype.need_anchor then
+ var buff = new Buffer
+ var rank = 0
+ for ft in mtype.arguments do
+ if ft isa MParameterType then
+ var ftcolor = compiler.ft_colors[ft]
+ buff.append("[self->type->fts_table->fts[{ftcolor}]->id]")
+ else if ft isa MGenericType and ft.need_anchor then
+ var ft_decl = mtype.mclass.mclass_type.arguments[rank]
+ var ftcolor = compiler.ft_colors[ft_decl.as(MParameterType)]
+ buff.append("[self->type->fts_table->fts[{ftcolor}]->id]")
+ else
+ var typecolor = compiler.type_colors[ft.as(MClassType)]
+ buff.append("[{typecolor}]")
+ end
+ rank += 1
+ end
+ mtype = self.anchor(mtype).as(MClassType)
+ return self.new_expr("NEW_{mtype.mclass.c_name}((struct type *) livetypes_{mtype.mclass.c_name}{buff.to_s})", mtype)
+ end
+ compiler.undead_types.add(mtype)
+ return self.new_expr("NEW_{mtype.mclass.c_name}((struct type *) &type_{mtype.c_name})", mtype)
end
redef fun type_test(value, mtype)
do
var compiler = self.compiler.as(SeparateCompiler)
var res = self.new_var(bool_type)
+ var buff = new Buffer
- if mtype isa MNullableType then mtype = mtype.mtype
- if mtype isa MClassType then
- self.add("{res} = {value}->type->type_table[type_{mtype.c_name}.color] == type_{mtype.c_name}.id;")
+ 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} = {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} = {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
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
redef fun class_name_string(value1)
do
var res = self.get_name("var_class_name")
- self.add_decl("const char* {res};")
- # TODO
- add("printf(\"NOT YET IMPLEMENTED: class_name_string(%s).\\n\", \"{value1.inspect}\"); exit(1);")
+ self.add_decl("const char* {res} = class_names[self->type->id];")
return res
end
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
+ # Return the name of the C structure associated to a Nit class
+ fun c_name: String do
+ var res = self.c_name_cache
+ if res != null then return res
+ res = "{intro_mmodule.name.to_cmangle}__{name.to_cmangle}"
+ self.c_name_cache = res
+ return res
+ end
+ private var c_name_cache: nullable String
+end