compiler: add and use `MModule::c_name`
[nit.git] / src / compiler / abstract_compiler.nit
index e83739d..16c0e4b 100644 (file)
@@ -34,16 +34,16 @@ redef class ToolContext
        var opt_no_cc = new OptionBool("Do not invoke C compiler", "--no-cc")
        # --no-main
        var opt_no_main = new OptionBool("Do not generate main entry point", "--no-main")
-       # --cc-paths
-       var opt_cc_path = new OptionArray("Set include path for C header files (may be used more than once)", "--cc-path")
        # --make-flags
        var opt_make_flags = new OptionString("Additional options to make", "--make-flags")
+       # --max-c-lines
+       var opt_max_c_lines = new OptionInt("Maximum number of lines in generated C files. Use 0 for unlimited", 10000, "--max-c-lines")
+       # --group-c-files
+       var opt_group_c_files = new OptionBool("Group all generated code in the same series of files", "--group-c-files")
        # --compile-dir
        var opt_compile_dir = new OptionString("Directory used to generate temporary files", "--compile-dir")
        # --hardening
        var opt_hardening = new OptionBool("Generate contracts in the C code against bugs in the compiler", "--hardening")
-       # --no-shortcut-range
-       var opt_no_shortcut_range = new OptionBool("Always insantiate a range and its iterator on 'for' loops", "--no-shortcut-range")
        # --no-check-covariance
        var opt_no_check_covariance = new OptionBool("Disable type tests of covariant parameters (dangerous)", "--no-check-covariance")
        # --no-check-attr-isset
@@ -72,12 +72,15 @@ redef class ToolContext
        redef init
        do
                super
-               self.option_context.add_option(self.opt_output, self.opt_dir, self.opt_no_cc, self.opt_no_main, self.opt_make_flags, self.opt_compile_dir, self.opt_hardening, self.opt_no_shortcut_range)
+               self.option_context.add_option(self.opt_output, self.opt_dir, self.opt_no_cc, self.opt_no_main, self.opt_make_flags, self.opt_compile_dir, self.opt_hardening)
                self.option_context.add_option(self.opt_no_check_covariance, self.opt_no_check_attr_isset, self.opt_no_check_assert, self.opt_no_check_autocast, self.opt_no_check_null, self.opt_no_check_all)
                self.option_context.add_option(self.opt_typing_test_metrics, self.opt_invocation_metrics, self.opt_isset_checks_metrics)
                self.option_context.add_option(self.opt_stacktrace)
                self.option_context.add_option(self.opt_no_gcc_directive)
                self.option_context.add_option(self.opt_release)
+               self.option_context.add_option(self.opt_max_c_lines, self.opt_group_c_files)
+
+               opt_no_main.hidden = true
        end
 
        redef fun process_options(args)
@@ -148,40 +151,9 @@ end
 
 class MakefileToolchain
        super Toolchain
-       # The list of directories to search for included C headers (-I for C compilers)
-       # The list is initially set with :
-       #   * the toolcontext --cc-path option
-       #   * the NIT_CC_PATH environment variable
-       #   * `toolcontext.nit_dir`
-       # Path can be added (or removed) by the client
-       var cc_paths = new Array[String]
-
-       protected fun gather_cc_paths
-       do
-               # Look for the the Nit clib path
-               var path_env = toolcontext.nit_dir
-               if path_env != null then
-                       var libname = "{path_env}/clib"
-                       if libname.file_exists then cc_paths.add(libname)
-               end
-
-               if cc_paths.is_empty then
-                       toolcontext.error(null, "Cannot determine the nit clib path. define envvar NIT_DIR.")
-               end
-
-               # Add user defined cc_paths
-               cc_paths.append(toolcontext.opt_cc_path.value)
-
-               path_env = "NIT_CC_PATH".environ
-               if not path_env.is_empty then
-                       cc_paths.append(path_env.split_with(':'))
-               end
-       end
 
        redef fun write_and_make(compiler)
        do
-               gather_cc_paths
-
                var compile_dir = compile_dir
 
                # Generate the .h and .c files
@@ -224,9 +196,11 @@ class MakefileToolchain
 
                # Add gc_choser.h to aditionnal bodies
                var gc_chooser = new ExternCFile("gc_chooser.c", cc_opt_with_libgc)
+               if cc_opt_with_libgc != "" then gc_chooser.pkgconfigs.add "bdw-gc"
                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 clib = toolcontext.nit_dir / "clib"
+               compiler.files_to_copy.add "{clib}/gc_chooser.c"
+               compiler.files_to_copy.add "{clib}/gc_chooser.h"
 
                # FFI
                for m in compiler.mainmodule.in_importation.greaters do
@@ -253,39 +227,21 @@ class MakefileToolchain
                end
                h.close
 
+               var max_c_lines = toolcontext.opt_max_c_lines.value
                for f in compiler.files do
                        var i = 0
-                       var hfile: nullable OFStream = null
                        var count = 0
-                       var cfilename = "{f.name}.0.h"
-                       var cfilepath = "{compile_dir}/{cfilename}"
-                       hfile = new OFStream.open(cfilepath)
-                       hfile.write "#include \"{hfilename}\"\n"
-                       for key in f.required_declarations do
-                               if not compiler.provided_declarations.has_key(key) then
-                                       var node = compiler.requirers_of_declarations.get_or_null(key)
-                                       if node != null then
-                                               node.debug "No provided declaration for {key}"
-                                       else
-                                               print "No provided declaration for {key}"
-                                       end
-                                       abort
-                               end
-                               hfile.write compiler.provided_declarations[key]
-                               hfile.write "\n"
-                       end
-                       hfile.close
                        var file: nullable OFStream = null
                        for vis in f.writers do
                                if vis == compiler.header then continue
                                var total_lines = vis.lines.length + vis.decl_lines.length
                                if total_lines == 0 then continue
                                count += total_lines
-                               if file == null or count > 10000  then
+                               if file == null or (count > max_c_lines and max_c_lines > 0) then
                                        i += 1
                                        if file != null then file.close
-                                       cfilename = "{f.name}.{i}.c"
-                                       cfilepath = "{compile_dir}/{cfilename}"
+                                       var cfilename = "{f.name}.{i}.c"
+                                       var cfilepath = "{compile_dir}/{cfilename}"
                                        self.toolcontext.info("new C source files to compile: {cfilepath}", 3)
                                        cfiles.add(cfilename)
                                        file = new OFStream.open(cfilepath)
@@ -301,13 +257,34 @@ class MakefileToolchain
                                        file.write "\n"
                                end
                        end
-                       if file != null then file.close
+                       if file == null then continue
+                       file.close
+
+                       var cfilename = "{f.name}.0.h"
+                       var cfilepath = "{compile_dir}/{cfilename}"
+                       var hfile: nullable OFStream = null
+                       hfile = new OFStream.open(cfilepath)
+                       hfile.write "#include \"{hfilename}\"\n"
+                       for key in f.required_declarations do
+                               if not compiler.provided_declarations.has_key(key) then
+                                       var node = compiler.requirers_of_declarations.get_or_null(key)
+                                       if node != null then
+                                               node.debug "No provided declaration for {key}"
+                                       else
+                                               print "No provided declaration for {key}"
+                                       end
+                                       abort
+                               end
+                               hfile.write compiler.provided_declarations[key]
+                               hfile.write "\n"
+                       end
+                       hfile.close
                end
 
                self.toolcontext.info("Total C source files to compile: {cfiles.length}", 2)
        end
 
-       fun makefile_name(mainmodule: MModule): String do return "{mainmodule.name}.mk"
+       fun makefile_name(mainmodule: MModule): String do return "{mainmodule.c_name}.mk"
 
        fun default_outname(mainmodule: MModule): String
        do
@@ -338,24 +315,18 @@ class MakefileToolchain
 
                var outname = outfile(mainmodule)
 
-               var orig_dir = compile_dir.relpath(".")
-               var outpath = orig_dir.join_path(outname).simplify_path
+               var outpath = compile_dir.relpath(outname)
                var makename = makefile_name(mainmodule)
                var makepath = "{compile_dir}/{makename}"
                var makefile = new OFStream.open(makepath)
 
-               var cc_includes = ""
-               for p in cc_paths do
-                       cc_includes += " -I \"" + p + "\""
-               end
-
                var linker_options = new HashSet[String]
                for m in mainmodule.in_importation.greaters do
                        var libs = m.collect_linker_libs
                        if libs != null then linker_options.add_all(libs)
                end
 
-               makefile.write("CC = ccache cc\nCXX = ccache c++\nCFLAGS = -g -O2 -Wno-unused-value -Wno-switch\nCINCL = {cc_includes}\nLDFLAGS ?= \nLDLIBS  ?= -lm -lgc {linker_options.join(" ")}\n\n")
+               makefile.write("CC = ccache cc\nCXX = ccache c++\nCFLAGS = -g -O2 -Wno-unused-value -Wno-switch\nCINCL =\nLDFLAGS ?= \nLDLIBS  ?= -lm {linker_options.join(" ")}\n\n")
 
                var ost = toolcontext.opt_stacktrace.value
                if (ost == "libunwind" or ost == "nitstack") and (platform == null or platform.supports_libunwind) then makefile.write("NEED_LIBUNWIND := YesPlease\n")
@@ -391,6 +362,28 @@ class MakefileToolchain
 
                var java_files = new Array[ExternFile]
 
+               var pkgconfigs = new Array[String]
+               for f in compiler.extern_bodies do
+                       pkgconfigs.add_all f.pkgconfigs
+               end
+               # Protect pkg-config
+               if not pkgconfigs.is_empty then
+                       makefile.write """
+# does pkg-config exists?
+ifneq ($(shell which pkg-config >/dev/null; echo $$?), 0)
+$(error "Command `pkg-config` not found. Please install it")
+endif
+"""
+                       for p in pkgconfigs do
+                               makefile.write """
+# Check for library {{{p}}}
+ifneq ($(shell pkg-config --exists '{{{p}}}'; echo $$?), 0)
+$(error "pkg-config: package {{{p}}} is not found.")
+endif
+"""
+                       end
+               end
+
                # Compile each required extern body into a specific .o
                for f in compiler.extern_bodies do
                        var o = f.makefile_rule_name
@@ -416,11 +409,17 @@ class MakefileToolchain
                end
 
                # Link edition
-               makefile.write("{outpath}: {dep_rules.join(" ")}\n\t$(CC) $(LDFLAGS) -o {outpath} {ofiles.join(" ")} $(LDLIBS)\n\n")
+               var pkg = ""
+               if not pkgconfigs.is_empty then
+                       pkg = "`pkg-config --libs {pkgconfigs.join(" ")}`"
+               end
+               makefile.write("{outpath}: {dep_rules.join(" ")}\n\t$(CC) $(LDFLAGS) -o {outpath} {ofiles.join(" ")} $(LDLIBS) {pkg}\n\n")
                # Clean
                makefile.write("clean:\n\trm {ofiles.join(" ")} 2>/dev/null\n\n")
                makefile.close
                self.toolcontext.info("Generated makefile: {makepath}", 2)
+
+               makepath.file_copy_to "{compile_dir}/Makefile"
        end
 
        fun compile_c_code(compiler: AbstractCompiler, compile_dir: String)
@@ -455,7 +454,7 @@ abstract class AbstractCompiler
        var mainmodule: MModule is writable
 
        # The real main module of the program
-       var realmainmodule: MModule
+       var realmainmodule: MModule is noinit
 
        # The modelbuilder used to know the model and the AST
        var modelbuilder: ModelBuilder is protected writable
@@ -463,17 +462,22 @@ abstract class AbstractCompiler
        # Is hardening asked? (see --hardening)
        fun hardening: Bool do return self.modelbuilder.toolcontext.opt_hardening.value
 
-       init(mainmodule: MModule, modelbuilder: ModelBuilder)
+       init
        do
-               self.mainmodule = mainmodule
                self.realmainmodule = mainmodule
-               self.modelbuilder = modelbuilder
        end
 
        # Force the creation of a new file
        # The point is to avoid contamination between must-be-compiled-separately files
        fun new_file(name: String): CodeFile
        do
+               if modelbuilder.toolcontext.opt_group_c_files.value then
+                       if self.files.is_empty then
+                               var f = new CodeFile(mainmodule.c_name)
+                               self.files.add(f)
+                       end
+                       return self.files.first
+               end
                var f = new CodeFile(name)
                self.files.add(f)
                return f
@@ -487,7 +491,7 @@ abstract class AbstractCompiler
        fun new_visitor: VISITOR is abstract
 
        # Where global declaration are stored (the main .h)
-       var header: CodeWriter is writable
+       var header: CodeWriter is writable, noinit
 
        # Provide a declaration that can be requested (before or latter) by a visitor
        fun provide_declaration(key: String, s: String)
@@ -1009,9 +1013,8 @@ class CodeWriter
        # (used for local or global declaration)
        fun add_decl(s: String) do self.decl_lines.add(s)
 
-       init(file: CodeFile)
+       init
        do
-               self.file = file
                file.writers.add(self)
        end
 end
@@ -1028,7 +1031,7 @@ abstract class AbstractCompilerVisitor
        var current_node: nullable ANode = null is writable
 
        # The current `Frame`
-       var frame: nullable Frame is writable
+       var frame: nullable Frame = null is writable
 
        # Alias for self.compiler.mainmodule.object_type
        fun object_type: MClassType do return self.compiler.mainmodule.object_type
@@ -1036,11 +1039,10 @@ abstract class AbstractCompilerVisitor
        # Alias for self.compiler.mainmodule.bool_type
        fun bool_type: MClassType do return self.compiler.mainmodule.bool_type
 
-       var writer: CodeWriter
+       var writer: CodeWriter is noinit
 
-       init(compiler: COMPILER)
+       init
        do
-               self.compiler = compiler
                self.writer = new CodeWriter(compiler.files.last)
        end
 
@@ -1105,6 +1107,12 @@ abstract class AbstractCompilerVisitor
 
                for i in [0..msignature.arity[ do
                        if i == vararg_rank then
+                               var ne = args[i]
+                               if ne isa AVarargExpr then
+                                       var e = self.expr(ne.n_expr, null)
+                                       res.add(e)
+                                       continue
+                               end
                                var vararg = new Array[RuntimeVariable]
                                for j in [vararg_rank..vararg_rank+vararg_len] do
                                        var e = self.expr(args[j], null)
@@ -1273,6 +1281,14 @@ abstract class AbstractCompilerVisitor
                return name
        end
 
+       # Insert a C label for associated with an escapemark
+       fun add_escape_label(e: nullable EscapeMark)
+       do
+               if e == null then return
+               if e.escapes.is_empty then return
+               add("BREAK_{escapemark_name(e)}: (void)0;")
+       end
+
        private var escapemark_names = new HashMap[EscapeMark, String]
 
        # Return a "const char*" variable associated to the classname of the dynamic type of an object
@@ -1610,11 +1626,8 @@ class RuntimeVariable
        # false (usual value) means that the variable is a mcasttype or a subtype.
        var is_exact: Bool = false is writable
 
-       init(name: String, mtype: MType, mcasttype: MType)
+       init
        do
-               self.name = name
-               self.mtype = mtype
-               self.mcasttype = mcasttype
                assert not mtype.need_anchor
                assert not mcasttype.need_anchor
        end
@@ -1684,7 +1697,7 @@ redef class MClassType
        do
                var res = self.c_name_cache
                if res != null then return res
-               res = "{mclass.intro_mmodule.name.to_cmangle}__{mclass.name.to_cmangle}"
+               res = "{mclass.intro_mmodule.c_name}__{mclass.name.to_cmangle}"
                self.c_name_cache = res
                return res
        end
@@ -1790,7 +1803,7 @@ redef class MClass
        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}"
+               res = "{intro_mmodule.c_name}__{name.to_cmangle}"
                self.c_name_cache = res
                return res
        end
@@ -1818,7 +1831,7 @@ redef class MPropDef
        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}"
+               res = "{self.mclassdef.mmodule.c_name}__{self.mclassdef.mclass.name.to_cmangle}__{self.mproperty.name.to_cmangle}"
                self.c_name_cache = res
                return res
        end
@@ -1833,7 +1846,7 @@ redef class MMethodDef
                if modelbuilder.mpropdef2npropdef.has_key(self) then
                        var npropdef = modelbuilder.mpropdef2npropdef[self]
                        return npropdef.can_inline
-               else if self.mproperty.name == "init" then
+               else if self.mproperty.is_root_init then
                        # Automatic free init is always inlined since it is empty or contains only attribtes assigments
                        return true
                else
@@ -1853,7 +1866,7 @@ redef class MMethodDef
                        self.compile_parameter_check(v, arguments)
                        npropdef.compile_to_c(v, self, arguments)
                        v.current_node = oldnode
-               else if self.mproperty.name == "init" then
+               else if self.mproperty.is_root_init then
                        var nclassdef = modelbuilder.mclassdef2nclassdef[self.mclassdef]
                        var oldnode = v.current_node
                        v.current_node = nclassdef
@@ -1977,8 +1990,6 @@ redef class AMethPropdef
                var ret = mpropdef.msignature.return_mtype
                if ret != null then
                        ret = v.resolve_for(ret, arguments.first)
-               else if mpropdef.mproperty.is_new then
-                       ret = arguments.first.mcasttype
                end
                if pname != "==" and pname != "!=" then
                        v.adapt_signature(mpropdef, arguments)
@@ -2159,7 +2170,7 @@ redef class AMethPropdef
                        else if pname == "atoi" then
                                v.ret(v.new_expr("atoi({arguments[0]});", ret.as(not null)))
                                return true
-                       else if pname == "init" then
+                       else if pname == "new" then
                                v.ret(v.new_expr("(char*)nit_alloc({arguments[1]})", ret.as(not null)))
                                return true
                        end
@@ -2279,24 +2290,24 @@ redef class AAttrPropdef
        do
                if mpropdef == mreadpropdef then
                        assert arguments.length == 1
+                       var recv = arguments.first
                        var res
                        if is_lazy then
-                               var nexpr = n_expr
-                               assert nexpr != null
                                var set
                                var ret = self.mpropdef.static_mtype
                                var useiset = ret.ctype == "val*" and not ret isa MNullableType
                                var guard = self.mlazypropdef.mproperty
                                if useiset then
-                                       set = v.isset_attribute(self.mpropdef.mproperty, arguments.first)
+                                       set = v.isset_attribute(self.mpropdef.mproperty, recv)
                                else
-                                       set = v.read_attribute(guard, arguments.first)
+                                       set = v.read_attribute(guard, recv)
                                end
                                v.add("if(likely({set})) \{")
-                               res = v.read_attribute(self.mpropdef.mproperty, arguments.first)
+                               res = v.read_attribute(self.mpropdef.mproperty, recv)
                                v.add("\} else \{")
-                               var value = v.expr(nexpr, self.mpropdef.static_mtype)
-                               v.write_attribute(self.mpropdef.mproperty, arguments.first, value)
+
+                               var value = evaluate_expr(v, recv)
+
                                v.assign(res, value)
                                if not useiset then
                                        var true_v = v.new_expr("1", v.bool_type)
@@ -2324,18 +2335,44 @@ redef class AAttrPropdef
 
        fun init_expr(v: AbstractCompilerVisitor, recv: RuntimeVariable)
        do
+               if has_value and not is_lazy then evaluate_expr(v, recv)
+       end
+
+       # Evaluate, store and return the default value of the attribute
+       private fun evaluate_expr(v: AbstractCompilerVisitor, recv: RuntimeVariable): RuntimeVariable
+       do
+               var oldnode = v.current_node
+               v.current_node = self
+               var old_frame = v.frame
+               var frame = new Frame(v, self.mpropdef.as(not null), recv.mcasttype.as(MClassType), [recv])
+               v.frame = frame
+
+               var value
+               var mtype = self.mpropdef.static_mtype
+               assert mtype != null
+
                var nexpr = self.n_expr
-               if nexpr != null and not is_lazy then
-                       var oldnode = v.current_node
-                       v.current_node = self
-                       var old_frame = v.frame
-                       var frame = new Frame(v, self.mpropdef.as(not null), recv.mtype.as(MClassType), [recv])
-                       v.frame = frame
-                       var value = v.expr(nexpr, self.mpropdef.static_mtype)
-                       v.write_attribute(self.mpropdef.mproperty, recv, value)
-                       v.frame = old_frame
-                       v.current_node = oldnode
+               var nblock = self.n_block
+               if nexpr != null then
+                       value = v.expr(nexpr, mtype)
+               else if nblock != null then
+                       value = v.new_var(mtype)
+                       frame.returnvar = value
+                       frame.returnlabel = v.get_name("RET_LABEL")
+                       v.add("\{")
+                       v.stmt(nblock)
+                       v.add("{frame.returnlabel.as(not null)}:(void)0;")
+                       v.add("\}")
+               else
+                       abort
                end
+
+               v.write_attribute(self.mpropdef.mproperty, recv, value)
+
+               v.frame = old_frame
+               v.current_node = oldnode
+
+               return value
        end
 
        fun check_expr(v: AbstractCompilerVisitor, recv: RuntimeVariable)
@@ -2391,8 +2428,7 @@ redef class AExpr
        # Do not call this method directly, use `v.stmt` instead
        private fun stmt(v: AbstractCompilerVisitor)
        do
-               var res = expr(v)
-               if res != null then v.add("{res};")
+               expr(v)
        end
 end
 
@@ -2434,12 +2470,6 @@ redef class AVarExpr
 end
 
 redef class AVarAssignExpr
-       redef fun stmt(v)
-       do
-               var variable = self.variable.as(not null)
-               var i = v.expr(self.n_value, variable.declared_type)
-               v.assign(v.variable(variable), i)
-       end
        redef fun expr(v)
        do
                var variable = self.variable.as(not null)
@@ -2465,11 +2495,7 @@ redef class ASelfExpr
        redef fun expr(v) do return v.frame.arguments.first
 end
 
-redef class AContinueExpr
-       redef fun stmt(v) do v.add("goto CONTINUE_{v.escapemark_name(self.escapemark)};")
-end
-
-redef class ABreakExpr
+redef class AEscapeExpr
        redef fun stmt(v) do v.add("goto BREAK_{v.escapemark_name(self.escapemark)};")
 end
 
@@ -2532,10 +2558,7 @@ redef class ADoExpr
        redef fun stmt(v)
        do
                v.stmt(self.n_block)
-               var escapemark = self.escapemark
-               if escapemark != null then
-                       v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
-               end
+               v.add_escape_label(break_mark)
        end
 end
 
@@ -2546,9 +2569,9 @@ redef class AWhileExpr
                var cond = v.expr_bool(self.n_expr)
                v.add("if (!{cond}) break;")
                v.stmt(self.n_block)
-               v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;")
+               v.add_escape_label(continue_mark)
                v.add("\}")
-               v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
+               v.add_escape_label(break_mark)
        end
 end
 
@@ -2557,47 +2580,15 @@ redef class ALoopExpr
        do
                v.add("for(;;) \{")
                v.stmt(self.n_block)
-               v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;")
+               v.add_escape_label(continue_mark)
                v.add("\}")
-               v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
+               v.add_escape_label(break_mark)
        end
 end
 
 redef class AForExpr
        redef fun stmt(v)
        do
-               # Shortcut on explicit range
-               # Avoid the instantiation of the range and the iterator
-               var nexpr = self.n_expr
-               if self.variables.length == 1 and nexpr isa ARangeExpr and not v.compiler.modelbuilder.toolcontext.opt_no_shortcut_range.value then
-                       var from = v.expr(nexpr.n_expr, null)
-                       var to = v.expr(nexpr.n_expr2, null)
-                       var variable = v.variable(variables.first)
-                       var one = v.new_expr("1", v.get_class("Int").mclass_type)
-
-                       v.assign(variable, from)
-                       v.add("for(;;) \{ /* shortcut range */")
-
-                       var ok
-                       if nexpr isa AOrangeExpr then
-                               ok = v.send(v.get_property("<", variable.mtype), [variable, to])
-                       else
-                               ok = v.send(v.get_property("<=", variable.mtype), [variable, to])
-                       end
-                       assert ok != null
-                       v.add("if(!{ok}) break;")
-
-                       v.stmt(self.n_block)
-
-                       v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;")
-                       var succ = v.send(v.get_property("successor", variable.mtype), [variable, one])
-                       assert succ != null
-                       v.assign(variable, succ)
-                       v.add("\}")
-                       v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
-                       return
-               end
-
                var cl = v.expr(self.n_expr, null)
                var it_meth = self.method_iterator
                assert it_meth != null
@@ -2630,12 +2621,12 @@ redef class AForExpr
                        abort
                end
                v.stmt(self.n_block)
-               v.add("CONTINUE_{v.escapemark_name(escapemark)}: (void)0;")
+               v.add_escape_label(continue_mark)
                var next_meth = self.method_next
                assert next_meth != null
                v.compile_callsite(next_meth, [it])
                v.add("\}")
-               v.add("BREAK_{v.escapemark_name(escapemark)}: (void)0;")
+               v.add_escape_label(break_mark)
 
                var method_finish = self.method_finish
                if method_finish != null then
@@ -2934,7 +2925,8 @@ end
 redef class ANewExpr
        redef fun expr(v)
        do
-               var mtype = self.mtype.as(MClassType)
+               var mtype = self.recvtype
+               assert mtype != null
                var recv
                var ctype = mtype.ctype
                if mtype.mclass.name == "NativeArray" then
@@ -2972,12 +2964,13 @@ redef class AAttrExpr
 end
 
 redef class AAttrAssignExpr
-       redef fun stmt(v)
+       redef fun expr(v)
        do
                var recv = v.expr(self.n_expr, null)
                var i = v.expr(self.n_value, null)
                var mproperty = self.mproperty.as(not null)
                v.write_attribute(mproperty, recv, i)
+               return i
        end
 end
 
@@ -3022,6 +3015,19 @@ redef class Array[E]
 end
 
 redef class MModule
+       # Return the name of the global C identifier associated to `self`.
+       # This name is used to prefix files and other C identifiers associated with `self`.
+       var c_name: String is lazy do
+               var g = mgroup
+               var res
+               if g != null and g.mproject.name != name then
+                       res = g.mproject.name.to_cmangle + "__" + name.to_cmangle
+               else
+                       res = name.to_cmangle
+               end
+               return res
+       end
+
        # All `MProperty` associated to all `MClassDef` of `mclass`
        fun properties(mclass: MClass): Set[MProperty] do
                if not self.properties_cache.has_key(mclass) then