- if t.is_subtype(self.compiler.mainmodule, null, mtype) then
- self.add("case {self.compiler.classid(t)}: /* {t} */")
- end
- end
- self.add("{res} = 1;")
- self.add("break;")
- self.add("default:")
- self.add("{res} = 0;")
- self.add("\}")
-
- return res
- end
-
- # Generate a Nit "is" for two runtime_variables
- fun equal_test(value1, value2: RuntimeVariable): RuntimeVariable
- do
- var res = self.new_var(bool_type)
- 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} = {value1} == {value2};")
- else if value2.mtype.ctype != "val*" then
- self.add("{res} = 0; /* incompatible types {value1.mtype} vs. {value2.mtype}*/")
- else
- var mtype1 = value1.mtype.as(MClassType)
- self.add("{res} = ({value2} != NULL) && ({value2}->classid == {self.compiler.classid(mtype1)});")
- self.add("if ({res}) \{")
- self.add("{res} = ({self.autobox(value2, value1.mtype)} == {value1});")
- self.add("\}")
- end
- else
- var s = new Array[String]
- 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}->classid == {self.compiler.classid(t)} && ((struct {t.c_name}*){value1})->value == ((struct {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}->classid == {value2}->classid && ({s.join(" || ")}));")
- end
- end
- return res
- end
-
- # Generate a check-init-instance
- # TODO: is an empty stub currently
- fun check_init_instance(recv: RuntimeVariable)
- do
- end
-
- # Generate an integer value
- fun int_instance(value: Int): RuntimeVariable
- do
- var res = self.new_var(self.get_class("Int").mclass_type)
- self.add("{res} = {value};")
- return res
- end
-
- # Generate an array value
- fun array_instance(array: Array[RuntimeVariable], elttype: MType): RuntimeVariable
- do
- elttype = self.anchor(elttype)
- var res = self.init_instance(self.get_class("Array").get_mtype([elttype]))
- self.add("\{ /* {res} = array_instance Array[{elttype}] */")
- var nat = self.new_var(self.get_class("NativeArray").get_mtype([elttype]))
- nat.is_exact = true
- self.add("{nat} = GC_MALLOC({array.length} * sizeof({elttype.ctype}));")
- for i in [0..array.length[ do
- var r = self.autobox(array[i], elttype)
- self.add("{nat}[{i}] = {r};")
- end
- var length = self.int_instance(array.length)
- self.send(self.get_property("with_native", res.mtype), [res, nat, length])
- self.check_init_instance(res)
- self.add("\}")
- return res
- end
-
- # Generate a string value
- fun string_instance(string: String): RuntimeVariable
- do
- var mtype = self.get_class("String").mclass_type
- var name = self.get_name("varonce")
- self.add_decl("static {mtype.ctype} {name};")
- var res = self.new_var(mtype)
- self.add("if ({name}) \{")
- self.add("{res} = {name};")
- self.add("\} else \{")
- var nat = self.new_var(self.get_class("NativeString").mclass_type)
- self.add("{nat} = \"{string.escape_to_c}\";")
- var res2 = self.init_instance(mtype)
- self.add("{res} = {res2};")
- var length = self.int_instance(string.length)
- self.send(self.get_property("with_native", res.mtype), [res, nat, length])
- self.check_init_instance(res)
- self.add("{name} = {res};")
- self.add("\}")
- return res
- end
-
- # Generate generic abort
- # used by aborts, asserts, casts, etc.
- fun add_abort(message: String)
- do
- if self.current_node != null and self.current_node.location.file != null then
- self.add("fprintf(stderr, \"Runtime error: %s (%s:%d)\\n\", \"{message.escape_to_c}\", \"{self.current_node.location.file.filename.escape_to_c}\", {current_node.location.line_start});")
- else
- self.add("fprintf(stderr, \"Runtime error: %s\\n\", \"{message.escape_to_c}\");")
- end
- self.add("exit(1);")
- end
-end
-
-# A frame correspond to a visited property in a GlobalCompilerVisitor
-private class Frame
- # The associated visitor
-
- var visitor: GlobalCompilerVisitor
-
- # The executed property.
- # A Method in case of a call, an attribute in case of a default initialization.
- var mpropdef: MPropDef
-
- # The static type of the receiver
- var receiver: MClassType
-
- # Arguments of the method (the first is the receiver)
- var arguments: Array[RuntimeVariable]
-
- # The runtime_variable associated to the return (in a function)
- var returnvar: nullable RuntimeVariable = null
-
- # The label at the end of the property
- var returnlabel: nullable String = null
-end
-
-redef class MPropDef
- private var c_name_cache: nullable String
-
- # The mangled name associated to the property
- fun c_name: String
- do
- var res = self.c_name_cache
- if res != null then return res
- res = "{self.mclassdef.mmodule.name.to_cmangle}__{self.mclassdef.mclass.name.to_cmangle}__{self.mproperty.name.to_cmangle}"
- self.c_name_cache = res
- return res
- end
-end
-
-redef class MMethodDef
- # Can the body be inlined?
- private fun can_inline(v: GlobalCompilerVisitor): Bool
- do
- var modelbuilder = v.compiler.modelbuilder
- if modelbuilder.mpropdef2npropdef.has_key(self) then
- var npropdef = modelbuilder.mpropdef2npropdef[self]
- return npropdef.can_inline
- else if self.mproperty.name == "init" then
- # Automatic free init is always inlined since it is empty or contains only attribtes assigments
- return true
- else
- abort
- end
- end
-
- # Inline the body in another visitor
- private fun compile_inside_to_c(v: GlobalCompilerVisitor, arguments: Array[RuntimeVariable]): nullable RuntimeVariable
- do
- var modelbuilder = v.compiler.modelbuilder
- if modelbuilder.mpropdef2npropdef.has_key(self) then
- var npropdef = modelbuilder.mpropdef2npropdef[self]
- npropdef.compile_to_c(v, self, arguments)
- else if self.mproperty.name == "init" then
- var nclassdef = modelbuilder.mclassdef2nclassdef[self.mclassdef]
- nclassdef.compile_to_c(v, self, arguments)
- else
- abort
- end
- return null
- end
-end
-
-redef class APropdef
- private fun compile_to_c(v: GlobalCompilerVisitor, mpropdef: MMethodDef, arguments: Array[RuntimeVariable])
- do
- v.add("printf(\"NOT YET IMPLEMENTED {class_name} {mpropdef} at {location.to_s}\\n\");")
- debug("Not yet implemented")
- end
-
- private fun can_inline: Bool do return true
-end
-
-redef class AConcreteMethPropdef
- redef fun compile_to_c(v, mpropdef, arguments)
- do
- for i in [0..mpropdef.msignature.arity[ do
- var variable = self.n_signature.n_params[i].variable.as(not null)
- v.assign(v.variable(variable), arguments[i+1])
- end
- # Call the implicit super-init
- var auto_super_inits = self.auto_super_inits
- if auto_super_inits != null then
- var selfarg = [arguments.first]
- for auto_super_init in auto_super_inits do
- if auto_super_init.intro.msignature.arity == 0 then
- v.send(auto_super_init, selfarg)
- else
- v.send(auto_super_init, arguments)
- end
- end
- end
-
- v.stmt(self.n_block)
- end
-
- redef fun can_inline
- do
- if self.auto_super_inits != null then return false
- var nblock = self.n_block
- if nblock == null then return true
- if (mpropdef.mproperty.name == "==" or mpropdef.mproperty.name == "!=") and mpropdef.mclassdef.mclass.name == "Object" then return true
- if nblock isa ABlockExpr and nblock.n_expr.length == 0 then return true
- return false
- end
-end
-
-redef class AInternMethPropdef
- redef fun compile_to_c(v, mpropdef, arguments)
- do
- var pname = mpropdef.mproperty.name
- var cname = mpropdef.mclassdef.mclass.name
- var ret = mpropdef.msignature.return_mtype
- if ret != null then
- ret = v.resolve_for(ret, arguments.first)
- end
- if pname != "==" and pname != "!=" then
- v.adapt_signature(mpropdef, arguments)
- end
- if cname == "Int" then
- if pname == "output" then
- v.add("printf(\"%ld\\n\", {arguments.first});")
- return
- else if pname == "object_id" then
- v.ret(arguments.first)
- return
- else if pname == "+" then
- v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
- return
- else if pname == "-" then
- v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
- return
- else if pname == "unary -" then
- v.ret(v.new_expr("-{arguments[0]}", ret.as(not null)))
- return
- else if pname == "succ" then
- v.ret(v.new_expr("{arguments[0]}+1", ret.as(not null)))
- return
- else if pname == "prec" then
- v.ret(v.new_expr("{arguments[0]}-1", ret.as(not null)))
- return
- else if pname == "*" then
- v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null)))
- return
- else if pname == "/" then
- v.ret(v.new_expr("{arguments[0]} / {arguments[1]}", ret.as(not null)))
- return
- else if pname == "%" then
- v.ret(v.new_expr("{arguments[0]} % {arguments[1]}", ret.as(not null)))
- return
- else if pname == "lshift" then
- v.ret(v.new_expr("{arguments[0]} << {arguments[1]}", ret.as(not null)))
- return
- else if pname == "rshift" then
- v.ret(v.new_expr("{arguments[0]} >> {arguments[1]}", ret.as(not null)))
- return
- else if pname == "==" then
- v.ret(v.equal_test(arguments[0], arguments[1]))
- return
- else if pname == "!=" then
- var res = v.equal_test(arguments[0], arguments[1])
- v.ret(v.new_expr("!{res}", ret.as(not null)))
- return
- else if pname == "<" then
- v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
- return
- else if pname == ">" then
- v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
- return
- else if pname == "<=" then
- v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
- return
- else if pname == ">=" then
- v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
- return
- else if pname == "to_f" then
- v.ret(v.new_expr("(double){arguments[0]}", ret.as(not null)))
- return
- else if pname == "ascii" then
- v.ret(v.new_expr("{arguments[0]}", ret.as(not null)))
- return
- end
- else if cname == "Char" then
- if pname == "output" then
- v.add("printf(\"%c\", {arguments.first});")
- return
- else if pname == "object_id" then
- v.ret(arguments.first)
- return
- else if pname == "==" then
- v.ret(v.equal_test(arguments[0], arguments[1]))
- return
- else if pname == "!=" then
- var res = v.equal_test(arguments[0], arguments[1])
- v.ret(v.new_expr("!{res}", ret.as(not null)))
- return
- else if pname == "succ" then
- v.ret(v.new_expr("{arguments[0]}+1", ret.as(not null)))
- return
- else if pname == "prec" then
- v.ret(v.new_expr("{arguments[0]}-1", ret.as(not null)))
- return
- else if pname == "<" then
- v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
- return
- else if pname == ">" then
- v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
- return
- else if pname == "<=" then
- v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
- return
- else if pname == ">=" then
- v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
- return
- else if pname == "to_i" then
- v.ret(v.new_expr("{arguments[0]}-'0'", ret.as(not null)))
- return
- else if pname == "ascii" then
- v.ret(v.new_expr("(unsigned char){arguments[0]}", ret.as(not null)))
- return
- end
- else if cname == "Bool" then
- if pname == "output" then
- v.add("printf({arguments.first}?\"true\\n\":\"false\\n\");")
- return
- else if pname == "object_id" then
- v.ret(arguments.first)
- return
- else if pname == "==" then
- v.ret(v.equal_test(arguments[0], arguments[1]))
- return
- else if pname == "!=" then
- var res = v.equal_test(arguments[0], arguments[1])
- v.ret(v.new_expr("!{res}", ret.as(not null)))
- return
- end
- else if cname == "Float" then
- if pname == "output" then
- v.add("printf(\"%f\\n\", {arguments.first});")
- return
- else if pname == "object_id" then
- v.ret(v.new_expr("(double){arguments.first}", ret.as(not null)))
- return
- else if pname == "+" then
- v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null)))
- return
- else if pname == "-" then
- v.ret(v.new_expr("{arguments[0]} - {arguments[1]}", ret.as(not null)))
- return
- else if pname == "unary -" then
- v.ret(v.new_expr("-{arguments[0]}", ret.as(not null)))
- return
- else if pname == "succ" then
- v.ret(v.new_expr("{arguments[0]}+1", ret.as(not null)))
- return
- else if pname == "prec" then
- v.ret(v.new_expr("{arguments[0]}-1", ret.as(not null)))
- return
- else if pname == "*" then
- v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null)))
- return
- else if pname == "/" then
- v.ret(v.new_expr("{arguments[0]} / {arguments[1]}", ret.as(not null)))
- return
- else if pname == "==" then
- v.ret(v.equal_test(arguments[0], arguments[1]))
- return
- else if pname == "!=" then
- var res = v.equal_test(arguments[0], arguments[1])
- v.ret(v.new_expr("!{res}", ret.as(not null)))
- return
- else if pname == "<" then
- v.ret(v.new_expr("{arguments[0]} < {arguments[1]}", ret.as(not null)))
- return
- else if pname == ">" then
- v.ret(v.new_expr("{arguments[0]} > {arguments[1]}", ret.as(not null)))
- return
- else if pname == "<=" then
- v.ret(v.new_expr("{arguments[0]} <= {arguments[1]}", ret.as(not null)))
- return
- else if pname == ">=" then
- v.ret(v.new_expr("{arguments[0]} >= {arguments[1]}", ret.as(not null)))
- return
- else if pname == "to_i" then
- v.ret(v.new_expr("(long){arguments[0]}", ret.as(not null)))
- return
- end
- else if cname == "Char" then
- if pname == "output" then
- v.add("printf(\"%c\", {arguments.first});")
- return
- else if pname == "object_id" then
- v.ret(arguments.first)
- return
- else if pname == "==" then
- v.ret(v.equal_test(arguments[0], arguments[1]))
- return
- else if pname == "!=" then
- var res = v.equal_test(arguments[0], arguments[1])
- v.ret(v.new_expr("!{res}", ret.as(not null)))
- return
- else if pname == "ascii" then
- v.ret(v.new_expr("{arguments[0]}", ret.as(not null)))
- return
- end
- else if cname == "NativeString" then
- if pname == "[]" then
- v.ret(v.new_expr("{arguments[0]}[{arguments[1]}]", ret.as(not null)))
- return
- else if pname == "[]=" then
- v.add("{arguments[0]}[{arguments[1]}]={arguments[2]};")
- return
- else if pname == "copy_to" then
- v.add("memcpy({arguments[1]}+{arguments[4]},{arguments[0]}+{arguments[3]},{arguments[2]});")
- return
- else if pname == "atoi" then
- v.ret(v.new_expr("atoi({arguments[0]});", ret.as(not null)))
- return
- end
- else if cname == "NativeArray" then
- var elttype = arguments.first.mtype
- if pname == "[]" then
- v.ret(v.new_expr("{arguments[0]}[{arguments[1]}]", ret.as(not null)))
- return
- else if pname == "[]=" then
- v.add("{arguments[0]}[{arguments[1]}]={arguments[2]};")
- return
- else if pname == "copy_to" then
- v.add("memcpy({arguments[1]},{arguments[0]},{arguments[2]}*sizeof({elttype.ctype}));")
- return
- end
- end
- if pname == "exit" then
- v.add("exit({arguments[1]});")
- return
- else if pname == "sys" then
- v.ret(v.new_expr("glob_sys", ret.as(not null)))
- return
- else if pname == "calloc_string" then
- v.ret(v.new_expr("(char*)GC_MALLOC({arguments[1]})", ret.as(not null)))
- return
- else if pname == "calloc_array" then
- var elttype = arguments.first.mtype.supertype_to(v.compiler.mainmodule,arguments.first.mtype.as(MClassType),v.get_class("ArrayCapable")).as(MGenericType).arguments.first
- v.ret(v.new_expr("({elttype.ctype}*)GC_MALLOC({arguments[1]} * sizeof({elttype.ctype}))", ret.as(not null)))
- return
- else if pname == "object_id" then
- v.ret(v.new_expr("(long){arguments.first}", ret.as(not null)))
- return
- else if pname == "is_same_type" then
- if arguments[0].mtype.ctype == "val*" then
- v.ret(v.new_expr("{arguments[0]}->classid == {arguments[1]}->classid", ret.as(not null)))
- else
- v.ret(v.new_expr("{v.compiler.classid(arguments[0].mtype.as(MClassType))} == {arguments[1]}->classid", ret.as(not null)))
- end
- return
- else if pname == "output_class_name" then
- if arguments[0].mtype.ctype == "val*" then
- v.add("printf(\"%s\\n\", class_names[{arguments.first}->classid]);")
- else
- v.add("printf(\"%s\\n\", class_names[{v.compiler.classid(arguments.first.mtype.as(MClassType))}]);")