model: intro `MModule::first_real_mmodule` to get the first non-fictive module
[nit.git] / src / compiler / abstract_compiler.nit
index dfaa3a3..011b146 100644 (file)
@@ -23,6 +23,7 @@ import platform
 import c_tools
 private import annotation
 import mixin
+import counter
 
 # Add compiling options
 redef class ToolContext
@@ -121,20 +122,30 @@ redef class ModelBuilder
        protected fun write_and_make(compiler: AbstractCompiler)
        do
                var platform = compiler.target_platform
-               var toolchain = platform.toolchain(toolcontext)
+               var toolchain = platform.toolchain(toolcontext, compiler)
                compile_dir = toolchain.compile_dir
-               toolchain.write_and_make compiler
+               toolchain.write_and_make
        end
 end
 
 redef class Platform
        # The specific tool-chain associated to the platform
-       fun toolchain(toolcontext: ToolContext): Toolchain do return new MakefileToolchain(toolcontext)
+       fun toolchain(toolcontext: ToolContext, compiler: AbstractCompiler): Toolchain
+       do
+               return new MakefileToolchain(toolcontext, compiler)
+       end
 end
 
+# Build toolchain for a specific target program, varies per `Platform`
 class Toolchain
+
+       # Toolcontext
        var toolcontext: ToolContext
 
+       # Compiler of the target program
+       var compiler: AbstractCompiler
+
+       # Directory where to generate all C files
        fun compile_dir: String
        do
                var compile_dir = toolcontext.opt_compile_dir.value
@@ -142,13 +153,15 @@ class Toolchain
                return compile_dir
        end
 
-       fun write_and_make(compiler: AbstractCompiler) is abstract
+       # Write all C files and compile them
+       fun write_and_make is abstract
 end
 
+# Default toolchain using a Makefile
 class MakefileToolchain
        super Toolchain
 
-       redef fun write_and_make(compiler)
+       redef fun write_and_make
        do
                var compile_dir = compile_dir
 
@@ -161,11 +174,11 @@ class MakefileToolchain
                compile_dir.mkdir
 
                var cfiles = new Array[String]
-               write_files(compiler, compile_dir, cfiles)
+               write_files(compile_dir, cfiles)
 
                # Generate the Makefile
 
-               write_makefile(compiler, compile_dir, cfiles)
+               write_makefile(compile_dir, cfiles)
 
                var time1 = get_time
                self.toolcontext.info("*** END WRITING C: {time1-time0} ***", 2)
@@ -177,13 +190,14 @@ class MakefileToolchain
                time0 = time1
                self.toolcontext.info("*** COMPILING C ***", 1)
 
-               compile_c_code(compiler, compile_dir)
+               compile_c_code(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])
+       # Write all source files to the `compile_dir`
+       fun write_files(compile_dir: String, cfiles: Array[String])
        do
                var platform = compiler.target_platform
                if self.toolcontext.opt_stacktrace.value == "nitstack" and platform.supports_libunwind then compiler.build_c_to_nit_bindings
@@ -280,17 +294,14 @@ class MakefileToolchain
                self.toolcontext.info("Total C source files to compile: {cfiles.length}", 2)
        end
 
-       fun makefile_name(mainmodule: MModule): String do return "{mainmodule.c_name}.mk"
+       # Get the name of the Makefile to use
+       fun makefile_name: String do return "{compiler.mainmodule.c_name}.mk"
 
-       fun default_outname(mainmodule: MModule): String
+       # Get the default name of the executable to produce
+       fun default_outname: String
        do
-               # Search a non fictive module
-               var res = mainmodule.name
-               while mainmodule.is_fictive do
-                       mainmodule = mainmodule.in_importation.direct_greaters.first
-                       res = mainmodule.name
-               end
-               return res
+               var mainmodule = compiler.mainmodule.first_real_mmodule
+               return mainmodule.name
        end
 
        # Combine options and platform informations to get the final path of the outfile
@@ -298,13 +309,14 @@ class MakefileToolchain
        do
                var res = self.toolcontext.opt_output.value
                if res != null then return res
-               res = default_outname(mainmodule)
+               res = default_outname
                var dir = self.toolcontext.opt_dir.value
                if dir != null then return dir.join_path(res)
                return res
        end
 
-       fun write_makefile(compiler: AbstractCompiler, compile_dir: String, cfiles: Array[String])
+       # Write the Makefile
+       fun write_makefile(compile_dir: String, cfiles: Array[String])
        do
                var mainmodule = compiler.mainmodule
                var platform = compiler.target_platform
@@ -319,7 +331,7 @@ class MakefileToolchain
                        # 2. copy the binary at the right place in the `all` goal.
                        outpath = mainmodule.c_name
                end
-               var makename = makefile_name(mainmodule)
+               var makename = makefile_name
                var makepath = "{compile_dir}/{makename}"
                var makefile = new FileWriter.open(makepath)
 
@@ -444,9 +456,10 @@ endif
                makepath.file_copy_to "{compile_dir}/Makefile"
        end
 
-       fun compile_c_code(compiler: AbstractCompiler, compile_dir: String)
+       # The C code is generated, compile it to an executable
+       fun compile_c_code(compile_dir: String)
        do
-               var makename = makefile_name(compiler.mainmodule)
+               var makename = makefile_name
 
                var makeflags = self.toolcontext.opt_make_flags.value
                if makeflags == null then makeflags = ""
@@ -589,6 +602,8 @@ 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 <sys/types.h>\n")
+               self.header.add_decl("#include <unistd.h>\n")
                self.header.add_decl("#include \"gc_chooser.h\"")
                self.header.add_decl("#ifdef ANDROID")
                self.header.add_decl("  #include <android/log.h>")
@@ -1021,14 +1036,6 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref ) {
        end
 
        fun finalize_ffi_for_module(mmodule: MModule) do mmodule.finalize_ffi(self)
-
-       # Division facility
-       # Avoid division by zero by returning the string "n/a"
-       fun div(a,b:Int):String
-       do
-               if b == 0 then return "n/a"
-               return ((a*10000/b).to_f / 100.0).to_precision(2)
-       end
 end
 
 # A file unit (may be more than one file if
@@ -2796,6 +2803,16 @@ redef class ASuperstringExpr
                var a = v.native_array_instance(type_string, v.int_instance(array.length))
 
                v.add_decl("static {a.mtype.ctype} {varonce};")
+
+               # Pre-fill the array with the literal string parts.
+               # So they do not need to be filled again when reused
+               for i in [0..array.length[ do
+                       var ne = array[i]
+                       if not ne isa AStringFormExpr then continue
+                       var e = v.expr(ne, null)
+                       v.native_array_set(a, i, e)
+               end
+
                v.add("\} else \{")
                # Take the native-array from the store.
                # The point is to prevent that some recursive execution use (and corrupt) the same native array
@@ -2808,6 +2825,7 @@ redef class ASuperstringExpr
                var to_s_method = v.get_property("to_s", v.object_type)
                for i in [0..array.length[ do
                        var ne = array[i]
+                       if ne isa AStringFormExpr then continue
                        var e = v.expr(ne, null)
                        # Skip the `to_s` if the element is already a String
                        if not e.mcasttype.is_subtype(v.compiler.mainmodule, null, type_string) then