Merge: compiler: introduce and use `MType::is_c_primitive`
[nit.git] / src / compiler / abstract_compiler.nit
index f286f02..c3952e3 100644 (file)
@@ -212,7 +212,7 @@ class MakefileToolchain
 
                var hfilename = compiler.header.file.name + ".h"
                var hfilepath = "{compile_dir}/{hfilename}"
-               var h = new OFStream.open(hfilepath)
+               var h = new FileWriter.open(hfilepath)
                for l in compiler.header.decl_lines do
                        h.write l
                        h.write "\n"
@@ -227,7 +227,7 @@ class MakefileToolchain
                for f in compiler.files do
                        var i = 0
                        var count = 0
-                       var file: nullable OFStream = null
+                       var file: nullable FileWriter = null
                        for vis in f.writers do
                                if vis == compiler.header then continue
                                var total_lines = vis.lines.length + vis.decl_lines.length
@@ -240,7 +240,7 @@ class MakefileToolchain
                                        var cfilepath = "{compile_dir}/{cfilename}"
                                        self.toolcontext.info("new C source files to compile: {cfilepath}", 3)
                                        cfiles.add(cfilename)
-                                       file = new OFStream.open(cfilepath)
+                                       file = new FileWriter.open(cfilepath)
                                        file.write "#include \"{f.name}.0.h\"\n"
                                        count = total_lines
                                end
@@ -258,8 +258,8 @@ class MakefileToolchain
 
                        var cfilename = "{f.name}.0.h"
                        var cfilepath = "{compile_dir}/{cfilename}"
-                       var hfile: nullable OFStream = null
-                       hfile = new OFStream.open(cfilepath)
+                       var hfile: nullable FileWriter = null
+                       hfile = new FileWriter.open(cfilepath)
                        hfile.write "#include \"{hfilename}\"\n"
                        for key in f.required_declarations do
                                if not compiler.provided_declarations.has_key(key) then
@@ -321,7 +321,7 @@ class MakefileToolchain
                end
                var makename = makefile_name(mainmodule)
                var makepath = "{compile_dir}/{makename}"
-               var makefile = new OFStream.open(makepath)
+               var makefile = new FileWriter.open(makepath)
 
                var linker_options = new HashSet[String]
                for m in mainmodule.in_importation.greaters do
@@ -371,7 +371,7 @@ class MakefileToolchain
                if not compiler.linker_script.is_empty then
                        var linker_script_path = "{compile_dir}/linker_script"
                        ofiles.add "linker_script"
-                       var f = new OFStream.open(linker_script_path)
+                       var f = new FileWriter.open(linker_script_path)
                        for l in compiler.linker_script do
                                f.write l
                                f.write "\n"
@@ -546,7 +546,7 @@ abstract class AbstractCompiler
        do
                var compile_dir = modelbuilder.compile_dir
 
-               var stream = new OFStream.open("{compile_dir}/c_functions_hash.c")
+               var stream = new FileWriter.open("{compile_dir}/c_functions_hash.c")
                stream.write("#include <string.h>\n")
                stream.write("#include <stdlib.h>\n")
                stream.write("#include \"c_functions_hash.h\"\n")
@@ -576,7 +576,7 @@ abstract class AbstractCompiler
                stream.write("\}\n")
                stream.close
 
-               stream = new OFStream.open("{compile_dir}/c_functions_hash.h")
+               stream = new FileWriter.open("{compile_dir}/c_functions_hash.h")
                stream.write("const char* get_nit_name(register const char* procname, register unsigned int len);\n")
                stream.close
 
@@ -603,9 +603,9 @@ abstract class AbstractCompiler
                var gccd_disable = modelbuilder.toolcontext.opt_no_gcc_directive.value
                if gccd_disable.has("noreturn") or gccd_disable.has("all") then
                        # Signal handler function prototype
-                       self.header.add_decl("void show_backtrace(int);")
+                       self.header.add_decl("void fatal_exit(int);")
                else
-                       self.header.add_decl("void show_backtrace(int) __attribute__ ((noreturn));")
+                       self.header.add_decl("void fatal_exit(int) __attribute__ ((noreturn));")
                end
 
                if gccd_disable.has("likely") or gccd_disable.has("all") then
@@ -741,12 +741,7 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref );
                        v.compiler.header.add_decl("extern long count_isset_checks;")
                end
 
-               v.add_decl("void sig_handler(int signo)\{")
-               v.add_decl("PRINT_ERROR(\"Caught signal : %s\\n\", strsignal(signo));")
-               v.add_decl("show_backtrace(signo);")
-               v.add_decl("\}")
-
-               v.add_decl("void show_backtrace (int signo) \{")
+               v.add_decl("static void show_backtrace(void) \{")
                if ost == "nitstack" or ost == "libunwind" then
                        v.add_decl("char* opt = getenv(\"NIT_NO_STACK\");")
                        v.add_decl("unw_cursor_t cursor;")
@@ -776,7 +771,19 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref );
                        v.add_decl("free(procname);")
                        v.add_decl("\}")
                end
-               v.add_decl("exit(signo);")
+               v.add_decl("\}")
+
+               v.add_decl("void sig_handler(int signo)\{")
+               v.add_decl("PRINT_ERROR(\"Caught signal : %s\\n\", strsignal(signo));")
+               v.add_decl("show_backtrace();")
+               # rethrows
+               v.add_decl("signal(signo, SIG_DFL);")
+               v.add_decl("kill(getpid(), signo);")
+               v.add_decl("\}")
+
+               v.add_decl("void fatal_exit(int status) \{")
+               v.add_decl("show_backtrace();")
+               v.add_decl("exit(status);")
                v.add_decl("\}")
 
                if no_main then
@@ -1078,9 +1085,6 @@ abstract class AbstractCompilerVisitor
                self.writer = new CodeWriter(compiler.files.last)
        end
 
-       # Force to get the primitive class named `name` or abort
-       fun get_class(name: String): MClass do return self.compiler.mainmodule.get_primitive_class(name)
-
        # Force to get the primitive property named `name` in the instance `recv` or abort
        fun get_property(name: String, recv: MType): MMethod
        do
@@ -1395,7 +1399,7 @@ abstract class AbstractCompilerVisitor
                var recv
                var ctype = mtype.ctype
                assert mtype.mclass.name != "NativeArray"
-               if ctype == "val*" then
+               if not mtype.is_c_primitive then
                        recv = init_instance(mtype)
                else if ctype == "char*" then
                        recv = new_expr("NULL/*special!*/", mtype)
@@ -1416,37 +1420,64 @@ abstract class AbstractCompilerVisitor
                end
        end
 
+       # The currently processed module
+       #
+       # alias for `compiler.mainmodule`
+       fun mmodule: MModule do return compiler.mainmodule
+
        # 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};")
+               var t = mmodule.int_type
+               var res = new RuntimeVariable("{value.to_s}l", t, t)
+               return res
+       end
+
+       # Generate a char value
+       fun char_instance(value: Char): RuntimeVariable
+       do
+               var t = mmodule.char_type
+               var res = new RuntimeVariable("'{value.to_s.escape_to_c}'", t, t)
+               return res
+       end
+
+       # Generate a float value
+       #
+       # FIXME pass a Float, not a string
+       fun float_instance(value: String): RuntimeVariable
+       do
+               var t = mmodule.float_type
+               var res = new RuntimeVariable("{value}", t, t)
                return res
        end
 
        # Generate an integer value
        fun bool_instance(value: Bool): RuntimeVariable
        do
-               var res = self.new_var(self.get_class("Bool").mclass_type)
-               if value then
-                       self.add("{res} = 1;")
-               else
-                       self.add("{res} = 0;")
-               end
+               var s = if value then "1" else "0"
+               var res = new RuntimeVariable(s, bool_type, bool_type)
+               return res
+       end
+
+       # Generate the `null` value
+       fun null_instance: RuntimeVariable
+       do
+               var t = compiler.mainmodule.model.null_type
+               var res = new RuntimeVariable("((val*)NULL)", t, t)
                return res
        end
 
        # Generate a string value
        fun string_instance(string: String): RuntimeVariable
        do
-               var mtype = self.get_class("String").mclass_type
+               var mtype = mmodule.string_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("if (likely({name}!=NULL)) \{")
                self.add("{res} = {name};")
                self.add("\} else \{")
-               var native_mtype = self.get_class("NativeString").mclass_type
+               var native_mtype = mmodule.native_string_type
                var nat = self.new_var(native_mtype)
                self.add("{nat} = \"{string.escape_to_c}\";")
                var length = self.int_instance(string.length)
@@ -1557,7 +1588,7 @@ abstract class AbstractCompilerVisitor
                else
                        self.add("PRINT_ERROR(\"\\n\");")
                end
-               self.add("show_backtrace(1);")
+               self.add("fatal_exit(1);")
        end
 
        # Add a dynamic cast
@@ -1754,12 +1785,16 @@ redef class MType
 
        # Short name of the `ctype` to use in unions
        fun ctypename: String do return "val"
+
+       # Is the associated C type a primitive one?
+       #
+       # ENSURE `result == (ctype != "val*")`
+       fun is_c_primitive: Bool do return false
 end
 
 redef class MClassType
 
-       redef fun ctype: String
-       do
+       redef var ctype is lazy do
                if mclass.name == "Int" then
                        return "long"
                else if mclass.name == "Bool" then
@@ -1777,6 +1812,8 @@ redef class MClassType
                end
        end
 
+       redef var is_c_primitive is lazy do return ctype != "val*"
+
        redef fun ctype_extern: String
        do
                if mclass.kind == extern_kind then
@@ -1834,6 +1871,15 @@ redef class MMethodDef
                var modelbuilder = v.compiler.modelbuilder
                var val = constant_value
                var node = modelbuilder.mpropdef2node(self)
+
+               if is_abstract then
+                       var cn = v.class_name_string(arguments.first)
+                       v.current_node = node
+                       v.add("PRINT_ERROR(\"Runtime error: Abstract method `%s` called on `%s`\", \"{mproperty.name.escape_to_c}\", {cn});")
+                       v.add_raw_abort
+                       return null
+               end
+
                if node isa APropdef then
                        var oldnode = v.current_node
                        v.current_node = node
@@ -1893,13 +1939,6 @@ end
 redef class AMethPropdef
        redef fun compile_to_c(v, mpropdef, arguments)
        do
-               if mpropdef.is_abstract then
-                       var cn = v.class_name_string(arguments.first)
-                       v.add("PRINT_ERROR(\"Runtime error: Abstract method `%s` called on `%s`\", \"{mpropdef.mproperty.name.escape_to_c}\", {cn});")
-                       v.add_raw_abort
-                       return
-               end
-
                # Call the implicit super-init
                var auto_super_inits = self.auto_super_inits
                if auto_super_inits != null then
@@ -2264,7 +2303,7 @@ redef class AAttrPropdef
                        if is_lazy then
                                var set
                                var ret = self.mpropdef.static_mtype
-                               var useiset = ret.ctype == "val*" and not ret isa MNullableType
+                               var useiset = not ret.is_c_primitive and not ret isa MNullableType
                                var guard = self.mlazypropdef.mproperty
                                if useiset then
                                        set = v.isset_attribute(self.mpropdef.mproperty, recv)
@@ -2279,7 +2318,7 @@ redef class AAttrPropdef
 
                                v.assign(res, value)
                                if not useiset then
-                                       var true_v = v.new_expr("1", v.bool_type)
+                                       var true_v = v.bool_instance(true)
                                        v.write_attribute(guard, arguments.first, true_v)
                                end
                                v.add("\}")
@@ -2292,9 +2331,9 @@ redef class AAttrPropdef
                        v.write_attribute(self.mpropdef.mproperty, arguments.first, arguments[1])
                        if is_lazy then
                                var ret = self.mpropdef.static_mtype
-                               var useiset = ret.ctype == "val*" and not ret isa MNullableType
+                               var useiset = not ret.is_c_primitive and not ret isa MNullableType
                                if not useiset then
-                                       v.write_attribute(self.mlazypropdef.mproperty, arguments.first, v.new_expr("1", v.bool_type))
+                                       v.write_attribute(self.mlazypropdef.mproperty, arguments.first, v.bool_instance(true))
                                end
                        end
                else
@@ -2304,7 +2343,7 @@ redef class AAttrPropdef
 
        fun init_expr(v: AbstractCompilerVisitor, recv: RuntimeVariable)
        do
-               if has_value and not is_lazy then evaluate_expr(v, recv)
+               if has_value and not is_lazy and not n_expr isa ANullExpr then evaluate_expr(v, recv)
        end
 
        # Evaluate, store and return the default value of the attribute
@@ -2692,15 +2731,15 @@ redef class AOrElseExpr
 end
 
 redef class AIntExpr
-       redef fun expr(v) do return v.new_expr("{self.value.to_s}", self.mtype.as(not null))
+       redef fun expr(v) do return v.int_instance(self.value.as(not null))
 end
 
 redef class AFloatExpr
-       redef fun expr(v) do return v.new_expr("{self.n_float.text}", self.mtype.as(not null)) # FIXME use value, not n_float
+       redef fun expr(v) do return v.float_instance("{self.n_float.text}") # FIXME use value, not n_float
 end
 
 redef class ACharExpr
-       redef fun expr(v) do return v.new_expr("'{self.value.to_s.escape_to_c}'", self.mtype.as(not null))
+       redef fun expr(v) do return v.char_instance(self.value.as(not null))
 end
 
 redef class AArrayExpr
@@ -2765,15 +2804,15 @@ redef class AOrangeExpr
 end
 
 redef class ATrueExpr
-       redef fun expr(v) do return v.new_expr("1", self.mtype.as(not null))
+       redef fun expr(v) do return v.bool_instance(true)
 end
 
 redef class AFalseExpr
-       redef fun expr(v) do return v.new_expr("0", self.mtype.as(not null))
+       redef fun expr(v) do return v.bool_instance(false)
 end
 
 redef class ANullExpr
-       redef fun expr(v) do return v.new_expr("NULL", self.mtype.as(not null))
+       redef fun expr(v) do return v.null_instance
 end
 
 redef class AIsaExpr
@@ -2801,7 +2840,7 @@ redef class AAsNotnullExpr
                var i = v.expr(self.n_expr, null)
                if v.compiler.modelbuilder.toolcontext.opt_no_check_assert.value then return i
 
-               if i.mtype.ctype != "val*" then return i
+               if i.mtype.is_c_primitive then return i
 
                v.add("if (unlikely({i} == NULL)) \{")
                v.add_abort("Cast failed")
@@ -2823,7 +2862,7 @@ redef class AOnceExpr
                v.add_decl("static {mtype.ctype} {name};")
                v.add_decl("static int {guard};")
                var res = v.new_var(mtype)
-               v.add("if ({guard}) \{")
+               v.add("if (likely({guard})) \{")
                v.add("{res} = {name};")
                v.add("\} else \{")
                var i = v.expr(self.n_expr, mtype)