auto_super_init: clean signature check
[nit.git] / src / abstract_compiler.nit
index 6a4923b..c8454e5 100644 (file)
@@ -107,8 +107,14 @@ redef class ModelBuilder
                        cc_paths.append(path_env.split_with(':'))
                end
 
+               var compile_dir = toolcontext.opt_compile_dir.value
+               if compile_dir == null then compile_dir = ".nit_compile"
+               self.compile_dir = compile_dir
        end
 
+       # The compilation directory
+       var compile_dir: String
+
        protected fun write_and_make(compiler: AbstractCompiler)
        do
                var mainmodule = compiler.mainmodule
@@ -119,20 +125,55 @@ redef class ModelBuilder
                var time0 = get_time
                self.toolcontext.info("*** WRITING C ***", 1)
 
-               var compile_dir = toolcontext.opt_compile_dir.value
-               if compile_dir == null then compile_dir = ".nit_compile"
-
                compile_dir.mkdir
 
+               var cfiles = new Array[String]
+               write_files(compiler, compile_dir, cfiles)
+
+               # Generate the Makefile
+
+               write_makefile(compiler, compile_dir, cfiles)
+
+               var time1 = get_time
+               self.toolcontext.info("*** END WRITING C: {time1-time0} ***", 2)
+
+               # Execute the Makefile
+
+               if self.toolcontext.opt_no_cc.value then return
+
+               time0 = time1
+               self.toolcontext.info("*** COMPILING C ***", 1)
+
+               compile_c_code(compiler, compile_dir)
+
+               time1 = get_time
+               self.toolcontext.info("*** END COMPILING C: {time1-time0} ***", 2)
+       end
+
+       fun write_files(compiler: AbstractCompiler, compile_dir: String, cfiles: Array[String])
+       do
                if self.toolcontext.opt_stacktrace.value then compiler.build_c_to_nit_bindings
 
-               var orig_dir=".." # FIXME only works if `compile_dir` is a subdirectory of cwd
+               # Add gc_choser.h to aditionnal bodies
+               var gc_chooser = new ExternCFile("gc_chooser.c", "-DWITH_LIBGC")
+               compiler.extern_bodies.add(gc_chooser)
+               compiler.files_to_copy.add "{cc_paths.first}/gc_chooser.c"
+               compiler.files_to_copy.add "{cc_paths.first}/gc_chooser.h"
 
-               var outname = self.toolcontext.opt_output.value
-               if outname == null then
-                       outname = "{mainmodule.name}"
+               # FFI
+               for m in compiler.mainmodule.in_importation.greaters do if mmodule2nmodule.keys.has(m) then
+                       var amodule = mmodule2nmodule[m]
+                       if m.uses_ffi or amodule.uses_legacy_ni then
+                               compiler.finalize_ffi_for_module(amodule)
+                       end
+               end
+
+               # Copy original .[ch] files to compile_dir
+               for src in compiler.files_to_copy do
+                       var basename = src.basename("")
+                       var dst = "{compile_dir}/{basename}"
+                       src.file_copy_to dst
                end
-               var outpath = orig_dir.join_path(outname).simplify_path
 
                var hfilename = compiler.header.file.name + ".h"
                var hfilepath = "{compile_dir}/{hfilename}"
@@ -147,8 +188,6 @@ redef class ModelBuilder
                end
                h.close
 
-               var cfiles = new Array[String]
-
                for f in compiler.files do
                        var i = 0
                        var hfile: nullable OFStream = null
@@ -196,24 +235,25 @@ redef class ModelBuilder
                end
 
                self.toolcontext.info("Total C source files to compile: {cfiles.length}", 2)
+       end
 
-               # FFI
-               for m in mainmodule.in_importation.greaters do if mmodule2nmodule.keys.has(m) then
-                       var amodule = mmodule2nmodule[m]
-                       if m.uses_ffi or amodule.uses_legacy_ni then
-                               compiler.finalize_ffi_for_module(amodule)
-                       end
-               end
+       fun write_makefile(compiler: AbstractCompiler, compile_dir: String, cfiles: Array[String])
+       do
+               var mainmodule = compiler.mainmodule
 
-               # Generate the Makefile
+               var outname = self.toolcontext.opt_output.value
+               if outname == null then
+                       outname = "{mainmodule.name}"
+               end
 
+               var orig_dir=".." # FIXME only works if `compile_dir` is a subdirectory of cwd
+               var outpath = orig_dir.join_path(outname).simplify_path
                var makename = "{mainmodule.name}.mk"
                var makepath = "{compile_dir}/{makename}"
                var makefile = new OFStream.open(makepath)
 
                var cc_includes = ""
                for p in cc_paths do
-                       p = orig_dir.join_path(p).simplify_path
                        cc_includes += " -I \"" + p + "\""
                end
 
@@ -223,33 +263,38 @@ redef class ModelBuilder
                        linker_options.add(amod.c_linker_options)
                end
 
-               if not toolcontext.opt_no_stacktrace.value then
-                       linker_options.add("-lunwind")
-    end
+               if not toolcontext.opt_no_stacktrace.value then linker_options.add("-lunwind")
 
                makefile.write("CC = ccache cc\nCFLAGS = -g -O2\nCINCL = {cc_includes}\nLDFLAGS ?= \nLDLIBS  ?= -lm -lgc {linker_options.join(" ")}\n\n")
                makefile.write("all: {outpath}\n\n")
 
                var ofiles = new Array[String]
+               var dep_rules = new Array[String]
                # Compile each generated file
                for f in cfiles do
                        var o = f.strip_extension(".c") + ".o"
                        makefile.write("{o}: {f}\n\t$(CC) $(CFLAGS) $(CINCL) -D NONITCNI -c -o {o} {f}\n\n")
                        ofiles.add(o)
+                       dep_rules.add(o)
                end
 
-               # Add gc_choser.h to aditionnal bodies
-               var gc_chooser = new ExternCFile("{cc_paths.first}/gc_chooser.c", "-DWITH_LIBGC")
-               compiler.extern_bodies.add(gc_chooser)
-
                # Compile each required extern body into a specific .o
                for f in compiler.extern_bodies do
                        if f isa ExternCFile then
                                var basename = f.filename.basename(".c")
                                var o = "{basename}.extern.o"
-                               var ff = orig_dir.join_path(f.filename).simplify_path
+                               var ff = f.filename.basename("")
                                makefile.write("{o}: {ff}\n\t$(CC) $(CFLAGS) -D NONITCNI {f.cflags} -c -o {o} {ff}\n\n")
                                ofiles.add(o)
+                               dep_rules.add(o)
+                       else
+                               var o = f.makefile_rule_name
+                               var ff = f.filename.basename("")
+                               makefile.write("{o}: {ff}\n")
+                               makefile.write("\t{f.makefile_rule_content}\n")
+                               dep_rules.add(f.makefile_rule_name)
+
+                               if f isa ExternCppFile then ofiles.add(o)
                        end
                end
 
@@ -259,16 +304,12 @@ redef class ModelBuilder
                makefile.write("clean:\n\trm {ofiles.join(" ")} 2>/dev/null\n\n")
                makefile.close
                self.toolcontext.info("Generated makefile: {makepath}", 2)
+       end
 
-               var time1 = get_time
-               self.toolcontext.info("*** END WRITING C: {time1-time0} ***", 2)
-
-               # Execute the Makefile
-
-               if self.toolcontext.opt_no_cc.value then return
+       fun compile_c_code(compiler: AbstractCompiler, compile_dir: String)
+       do
+               var makename = "{compiler.mainmodule.name}.mk" # FIXME duplicated from write_makefile
 
-               time0 = time1
-               self.toolcontext.info("*** COMPILING C ***", 1)
                var makeflags = self.toolcontext.opt_make_flags.value
                if makeflags == null then makeflags = ""
                self.toolcontext.info("make -B -C {compile_dir} -f {makename} -j 4 {makeflags}", 2)
@@ -282,9 +323,6 @@ redef class ModelBuilder
                if res != 0 then
                        toolcontext.error(null, "make failed! Error code: {res}.")
                end
-
-               time1 = get_time
-               self.toolcontext.info("*** END COMPILING C: {time1-time0} ***", 2)
        end
 end
 
@@ -349,8 +387,7 @@ abstract class AbstractCompiler
        # Binds the generated C function names to Nit function names
        fun build_c_to_nit_bindings
        do
-               var compile_dir = modelbuilder.toolcontext.opt_compile_dir.value
-               if compile_dir == null then compile_dir = ".nit_compile"
+               var compile_dir = modelbuilder.compile_dir
 
                var stream = new OFStream.open("{compile_dir}/C_fun_names")
                stream.write("%\{\n#include \"c_functions_hash.h\"\n%\}\n")
@@ -387,7 +424,7 @@ abstract class AbstractCompiler
                self.header.add_decl("#include <stdlib.h>")
                self.header.add_decl("#include <stdio.h>")
                self.header.add_decl("#include <string.h>")
-               self.header.add_decl("#include <gc_chooser.h>")
+               self.header.add_decl("#include \"gc_chooser.h\"")
 
                compile_header_structs
                compile_nitni_structs
@@ -438,6 +475,11 @@ abstract class AbstractCompiler
                        end
                end
 
+               v.add_decl("void sig_handler(int signo)\{")
+               v.add_decl("printf(\"Caught signal : %s\\n\", strsignal(signo));")
+               v.add_decl("show_backtrace(signo);")
+               v.add_decl("\}")
+
                v.add_decl("void show_backtrace (int signo) \{")
                if not modelbuilder.toolcontext.opt_no_stacktrace.value then
                        v.add_decl("char* opt = getenv(\"NIT_NO_STACK\");")
@@ -473,12 +515,12 @@ abstract class AbstractCompiler
 
                v.add_decl("int main(int argc, char** argv) \{")
 
-               v.add("signal(SIGABRT, show_backtrace);")
-               v.add("signal(SIGFPE, show_backtrace);")
-               v.add("signal(SIGILL, show_backtrace);")
-               v.add("signal(SIGINT, show_backtrace);")
-               v.add("signal(SIGTERM, show_backtrace);")
-               v.add("signal(SIGSEGV, show_backtrace);")
+               v.add("signal(SIGABRT, sig_handler);")
+               v.add("signal(SIGFPE, sig_handler);")
+               v.add("signal(SIGILL, sig_handler);")
+               v.add("signal(SIGINT, sig_handler);")
+               v.add("signal(SIGTERM, sig_handler);")
+               v.add("signal(SIGSEGV, sig_handler);")
 
                v.add("glob_argc = argc; glob_argv = argv;")
                v.add("initialize_gc_option();")
@@ -530,6 +572,9 @@ abstract class AbstractCompiler
        # List of additional files required to compile (FFI)
        var extern_bodies = new Array[ExternFile]
 
+       # List of source files to copy over to the compile dir
+       var files_to_copy = new Array[String]
+
        # This is used to avoid adding an extern file more than once
        private var seen_extern = new ArraySet[String]
 
@@ -845,7 +890,7 @@ abstract class AbstractCompilerVisitor
                var maybenull = recv.mcasttype isa MNullableType or recv.mcasttype isa MNullType
                if maybenull then
                        self.add("if ({recv} == NULL) \{")
-                       self.add_abort("Reciever is null")
+                       self.add_abort("Receiver is null")
                        self.add("\}")
                end
        end
@@ -1008,11 +1053,13 @@ abstract class AbstractCompilerVisitor
                file = file.strip_extension(".nit")
                var tryfile = file + ".nit.h"
                if tryfile.file_exists then
-                       self.declare_once("#include \"{"..".join_path(tryfile)}\"")
+                       self.declare_once("#include \"{tryfile.basename("")}\"")
+                       self.compiler.files_to_copy.add(tryfile)
                end
                tryfile = file + "_nit.h"
                if tryfile.file_exists then
-                       self.declare_once("#include \"{"..".join_path(tryfile)}\"")
+                       self.declare_once("#include \"{tryfile.basename("")}\"")
+                       self.compiler.files_to_copy.add(tryfile)
                end
 
                if self.compiler.seen_extern.has(file) then return
@@ -1022,8 +1069,9 @@ abstract class AbstractCompilerVisitor
                        tryfile = file + "_nit.c"
                        if not tryfile.file_exists then return
                end
-               var f = new ExternCFile(tryfile, "")
+               var f = new ExternCFile(tryfile.basename(""), "")
                self.compiler.extern_bodies.add(f)
+               self.compiler.files_to_copy.add(tryfile)
        end
 
        # Return a new local runtime_variable initialized with the C expression `cexpr`.
@@ -1461,13 +1509,13 @@ redef class AConcreteMethPropdef
                # Call the implicit super-init
                var auto_super_inits = self.auto_super_inits
                if auto_super_inits != null then
-                       var selfarg = [arguments.first]
+                       var args = [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)
+                               args.clear
+                               for i in [0..auto_super_init.intro.msignature.arity+1[ do
+                                       args.add(arguments[i])
                                end
+                               v.send(auto_super_init, args)
                        end
                end
                v.stmt(self.n_block)
@@ -2396,20 +2444,24 @@ redef class ASuperExpr
                for a in self.n_args.n_exprs do
                        args.add(v.expr(a, null))
                end
-               if args.length == 1 then
-                       args = v.frame.arguments
-               end
 
-               var mproperty = self.mproperty
-               if mproperty != null then
-                       if mproperty.intro.msignature.arity == 0 then
-                               args = [recv]
+               var callsite = self.callsite
+               if callsite != null then
+                       # Add additionnals arguments for the super init call
+                       if args.length == 1 then
+                               for i in [0..callsite.mproperty.intro.msignature.arity[ do
+                                       args.add(v.frame.arguments[i+1])
+                               end
                        end
                        # Super init call
-                       var res = v.send(mproperty, args)
+                       var res = v.compile_callsite(callsite, args)
                        return res
                end
 
+               if args.length == 1 then
+                       args = v.frame.arguments
+               end
+
                # stantard call-next-method
                return v.supercall(v.frame.mpropdef.as(MMethodDef), recv.mtype.as(MClassType), args)
        end