src: update most tools to new constructors
[nit.git] / src / compiler / abstract_compiler.nit
index 04e0719..62c0987 100644 (file)
@@ -27,43 +27,45 @@ import mixin
 # Add compiling options
 redef class ToolContext
        # --output
-       var opt_output: OptionString = new OptionString("Output file", "-o", "--output")
+       var opt_output = new OptionString("Output file", "-o", "--output")
        # --dir
-       var opt_dir: OptionString = new OptionString("Output directory", "--dir")
+       var opt_dir = new OptionString("Output directory", "--dir")
        # --no-cc
-       var opt_no_cc: OptionBool = new OptionBool("Do not invoke C compiler", "--no-cc")
+       var opt_no_cc = new OptionBool("Do not invoke C compiler", "--no-cc")
        # --no-main
-       var opt_no_main: OptionBool = new OptionBool("Do not generate main entry point", "--no-main")
+       var opt_no_main = new OptionBool("Do not generate main entry point", "--no-main")
        # --cc-paths
-       var opt_cc_path: OptionArray = new OptionArray("Set include path for C header files (may be used more than once)", "--cc-path")
+       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: OptionString = new OptionString("Additional options to make", "--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: OptionString = new OptionString("Directory used to generate temporary files", "--compile-dir")
+       var opt_compile_dir = new OptionString("Directory used to generate temporary files", "--compile-dir")
        # --hardening
-       var opt_hardening: OptionBool = new OptionBool("Generate contracts in the C code against bugs in the compiler", "--hardening")
-       # --no-shortcut-range
-       var opt_no_shortcut_range: OptionBool = new OptionBool("Always insantiate a range and its iterator on 'for' loops", "--no-shortcut-range")
+       var opt_hardening = new OptionBool("Generate contracts in the C code against bugs in the compiler", "--hardening")
        # --no-check-covariance
-       var opt_no_check_covariance: OptionBool = new OptionBool("Disable type tests of covariant parameters (dangerous)", "--no-check-covariance")
+       var opt_no_check_covariance = new OptionBool("Disable type tests of covariant parameters (dangerous)", "--no-check-covariance")
        # --no-check-attr-isset
-       var opt_no_check_attr_isset: OptionBool = new OptionBool("Disable isset tests before each attribute access (dangerous)", "--no-check-attr-isset")
+       var opt_no_check_attr_isset = new OptionBool("Disable isset tests before each attribute access (dangerous)", "--no-check-attr-isset")
        # --no-check-assert
-       var opt_no_check_assert: OptionBool = new OptionBool("Disable the evaluation of explicit 'assert' and 'as' (dangerous)", "--no-check-assert")
+       var opt_no_check_assert = new OptionBool("Disable the evaluation of explicit 'assert' and 'as' (dangerous)", "--no-check-assert")
        # --no-check-autocast
-       var opt_no_check_autocast: OptionBool = new OptionBool("Disable implicit casts on unsafe expression usage (dangerous)", "--no-check-autocast")
+       var opt_no_check_autocast = new OptionBool("Disable implicit casts on unsafe expression usage (dangerous)", "--no-check-autocast")
        # --no-check-null
-       var opt_no_check_null: OptionBool = new OptionBool("Disable tests of null receiver (dangerous)", "--no-check-null")
+       var opt_no_check_null = new OptionBool("Disable tests of null receiver (dangerous)", "--no-check-null")
        # --no-check-all
-       var opt_no_check_all: OptionBool = new OptionBool("Disable all tests (dangerous)", "--no-check-all")
+       var opt_no_check_all = new OptionBool("Disable all tests (dangerous)", "--no-check-all")
        # --typing-test-metrics
-       var opt_typing_test_metrics: OptionBool = new OptionBool("Enable static and dynamic count of all type tests", "--typing-test-metrics")
+       var opt_typing_test_metrics = new OptionBool("Enable static and dynamic count of all type tests", "--typing-test-metrics")
        # --invocation-metrics
-       var opt_invocation_metrics: OptionBool = new OptionBool("Enable static and dynamic count of all method invocations", "--invocation-metrics")
+       var opt_invocation_metrics = new OptionBool("Enable static and dynamic count of all method invocations", "--invocation-metrics")
        # --isset-checks-metrics
-       var opt_isset_checks_metrics: OptionBool = new OptionBool("Enable static and dynamic count of isset checks before attributes access", "--isset-checks-metrics")
+       var opt_isset_checks_metrics = new OptionBool("Enable static and dynamic count of isset checks before attributes access", "--isset-checks-metrics")
        # --stacktrace
-       var opt_stacktrace: OptionString = new OptionString("Control the generation of stack traces", "--stacktrace")
+       var opt_stacktrace = new OptionString("Control the generation of stack traces", "--stacktrace")
        # --no-gcc-directives
        var opt_no_gcc_directive = new OptionArray("Disable a advanced gcc directives for optimization", "--no-gcc-directive")
        # --release
@@ -72,12 +74,13 @@ 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)
        end
 
        redef fun process_options(args)
@@ -156,17 +159,20 @@ class MakefileToolchain
        # Path can be added (or removed) by the client
        var cc_paths = new Array[String]
 
+       # The clib directory of Nit
+       # Used to found some common runtime
+       var clib: String is noinit
+
        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.")
+                       if not libname.file_exists then
+                               toolcontext.fatal_error(null, "Cannot determine the nit clib path. define envvar NIT_DIR.")
+                       end
+                       clib = libname
                end
 
                # Add user defined cc_paths
@@ -182,7 +188,6 @@ class MakefileToolchain
        do
                gather_cc_paths
 
-               var mainmodule = compiler.mainmodule
                var compile_dir = compile_dir
 
                # Generate the .h and .c files
@@ -226,11 +231,10 @@ class MakefileToolchain
                # Add gc_choser.h to aditionnal bodies
                var gc_chooser = new ExternCFile("gc_chooser.c", cc_opt_with_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"
+               compiler.files_to_copy.add "{clib}/gc_chooser.c"
+               compiler.files_to_copy.add "{clib}/gc_chooser.h"
 
                # FFI
-               var m2m = toolcontext.modelbuilder.mmodule2nmodule
                for m in compiler.mainmodule.in_importation.greaters do
                        compiler.finalize_ffi_for_module(m)
                end
@@ -255,39 +259,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)
@@ -303,7 +289,28 @@ 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)
@@ -340,8 +347,7 @@ 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)
@@ -352,7 +358,6 @@ class MakefileToolchain
                end
 
                var linker_options = new HashSet[String]
-               var m2m = toolcontext.modelbuilder.mmodule2nmodule
                for m in mainmodule.in_importation.greaters do
                        var libs = m.collect_linker_libs
                        if libs != null then linker_options.add_all(libs)
@@ -424,6 +429,8 @@ class MakefileToolchain
                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)
@@ -458,25 +465,30 @@ abstract class AbstractCompiler
        var mainmodule: MModule is writable
 
        # The real main module of the program
-       var realmainmodule: MModule
+       var realmainmodule: MModule is noinit
 
-       # The modeulbuilder used to know the model and the AST
+       # The modelbuilder used to know the model and the AST
        var modelbuilder: ModelBuilder is protected writable
 
        # 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.name)
+                               self.files.add(f)
+                       end
+                       return self.files.first
+               end
                var f = new CodeFile(name)
                self.files.add(f)
                return f
@@ -484,13 +496,13 @@ abstract class AbstractCompiler
 
        # The list of all associated files
        # Used to generate .c files
-       var files: List[CodeFile] = new List[CodeFile]
+       var files = new List[CodeFile]
 
        # Initialize a visitor specific for a compiler engine
        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)
@@ -551,8 +563,6 @@ abstract class AbstractCompiler
        # Compile C headers
        # This method call compile_header_strucs method that has to be refined
        fun compile_header do
-               var v = self.header
-               var toolctx = modelbuilder.toolcontext
                self.header.add_decl("#include <stdlib.h>")
                self.header.add_decl("#include <stdio.h>")
                self.header.add_decl("#include <string.h>")
@@ -1014,9 +1024,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
@@ -1033,7 +1042,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
@@ -1041,11 +1050,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
 
@@ -1093,39 +1101,45 @@ abstract class AbstractCompilerVisitor
 
        fun native_array_def(pname: String, ret_type: nullable MType, arguments: Array[RuntimeVariable]) is abstract
 
-       # Transform varargs, in raw arguments, into a single argument of type `Array`
-       # Note: this method modify the given `args`
-       # If there is no vararg, then `args` is not modified.
-       fun varargize(mpropdef: MPropDef, msignature: MSignature, args: Array[RuntimeVariable])
+       # Evaluate `args` as expressions in the call of `mpropdef` on `recv`.
+       # This method is used to manage varargs in signatures and returns the real array
+       # of runtime variables to use in the call.
+       fun varargize(mpropdef: MMethodDef, recv: RuntimeVariable, args: SequenceRead[AExpr]): Array[RuntimeVariable]
        do
-               var recv = args.first
-               var vararg_rank = msignature.vararg_rank
-               if vararg_rank >= 0 then
-                       assert args.length >= msignature.arity + 1 # because of self
-                       var rawargs = args
-                       args = new Array[RuntimeVariable]
-
-                       args.add(rawargs.first) # recv
-
-                       for i in [0..vararg_rank[ do
-                               args.add(rawargs[i+1])
-                       end
+               var msignature = mpropdef.new_msignature or else mpropdef.msignature.as(not null)
+               var res = new Array[RuntimeVariable]
+               res.add(recv)
 
-                       var vararg_lastrank = vararg_rank + rawargs.length-1-msignature.arity
-                       var vararg = new Array[RuntimeVariable]
-                       for i in [vararg_rank..vararg_lastrank] do
-                               vararg.add(rawargs[i+1])
-                       end
+               if args.is_empty then return res
 
-                       var elttype = msignature.mparameters[vararg_rank].mtype
-                       args.add(self.vararg_instance(mpropdef, recv, vararg, elttype))
+               var vararg_rank = msignature.vararg_rank
+               var vararg_len = args.length - msignature.arity
+               if vararg_len < 0 then vararg_len = 0
 
-                       for i in [vararg_lastrank+1..rawargs.length-1[ do
-                               args.add(rawargs[i+1])
+               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)
+                                       vararg.add(e)
+                               end
+                               var elttype = msignature.mparameters[vararg_rank].mtype
+                               var arg = self.vararg_instance(mpropdef, recv, vararg, elttype)
+                               res.add(arg)
+                       else
+                               var j = i
+                               if i > vararg_rank then j += vararg_len
+                               var e = self.expr(args[j], null)
+                               res.add(e)
                        end
-                       rawargs.clear
-                       rawargs.add_all(args)
                end
+               return res
        end
 
        # Type handling
@@ -1229,7 +1243,7 @@ abstract class AbstractCompilerVisitor
 
        # Checks
 
-       # Add a check and an abort for a null reciever if needed
+       # Add a check and an abort for a null receiver if needed
        fun check_recv_notnull(recv: RuntimeVariable)
        do
                if self.compiler.modelbuilder.toolcontext.opt_no_check_null.value then return
@@ -1244,7 +1258,7 @@ abstract class AbstractCompilerVisitor
 
        # Names handling
 
-       private var names: HashSet[String] = new HashSet[String]
+       private var names = new HashSet[String]
        private var last: Int = 0
 
        # Return a new name based on `s` and unique in the visitor
@@ -1278,6 +1292,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
@@ -1286,7 +1308,7 @@ abstract class AbstractCompilerVisitor
 
        # Variables handling
 
-       protected var variables: HashMap[Variable, RuntimeVariable] = new HashMap[Variable, RuntimeVariable]
+       protected var variables = new HashMap[Variable, RuntimeVariable]
 
        # Return the local runtime_variable associated to a Nit local variable
        fun variable(variable: Variable): RuntimeVariable
@@ -1615,11 +1637,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
@@ -1838,7 +1857,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
@@ -1858,7 +1877,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
@@ -1982,8 +2001,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)
@@ -2164,7 +2181,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
@@ -2284,24 +2301,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)
@@ -2329,18 +2346,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)
@@ -2396,8 +2439,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
 
@@ -2439,12 +2481,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)
@@ -2470,11 +2506,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
 
@@ -2537,10 +2569,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
 
@@ -2551,9 +2580,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
 
@@ -2562,47 +2591,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
@@ -2635,12 +2632,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
@@ -2787,7 +2784,7 @@ redef class ACrangeExpr
                var i2 = v.expr(self.n_expr2, null)
                var mtype = self.mtype.as(MClassType)
                var res = v.init_instance(mtype)
-               var it = v.compile_callsite(init_callsite.as(not null), [res, i1, i2])
+               v.compile_callsite(init_callsite.as(not null), [res, i1, i2])
                return res
        end
 end
@@ -2799,7 +2796,7 @@ redef class AOrangeExpr
                var i2 = v.expr(self.n_expr2, null)
                var mtype = self.mtype.as(MClassType)
                var res = v.init_instance(mtype)
-               var it = v.compile_callsite(init_callsite.as(not null), [res, i1, i2])
+               v.compile_callsite(init_callsite.as(not null), [res, i1, i2])
                return res
        end
 end
@@ -2879,11 +2876,9 @@ redef class ASendExpr
        redef fun expr(v)
        do
                var recv = v.expr(self.n_expr, null)
-               var args = [recv]
-               for a in self.raw_arguments do
-                       args.add(v.expr(a, null))
-               end
-               return v.compile_callsite(self.callsite.as(not null), args)
+               var callsite = self.callsite.as(not null)
+               var args = v.varargize(callsite.mpropdef, recv, self.raw_arguments)
+               return v.compile_callsite(callsite, args)
        end
 end
 
@@ -2891,13 +2886,12 @@ redef class ASendReassignFormExpr
        redef fun stmt(v)
        do
                var recv = v.expr(self.n_expr, null)
-               var args = [recv]
-               for a in self.raw_arguments do
-                       args.add(v.expr(a, null))
-               end
+               var callsite = self.callsite.as(not null)
+               var args = v.varargize(callsite.mpropdef, recv, self.raw_arguments)
+
                var value = v.expr(self.n_value, null)
 
-               var left = v.compile_callsite(self.callsite.as(not null), args)
+               var left = v.compile_callsite(callsite, args)
                assert left != null
 
                var res = v.compile_callsite(self.reassign_callsite.as(not null), [left, value])
@@ -2912,14 +2906,12 @@ redef class ASuperExpr
        redef fun expr(v)
        do
                var recv = v.frame.arguments.first
-               var args = [recv]
-               for a in self.n_args.n_exprs do
-                       args.add(v.expr(a, null))
-               end
 
                var callsite = self.callsite
                if callsite != null then
-                       # Add additionnals arguments for the super init call
+                       var args = v.varargize(callsite.mpropdef, recv, self.n_args.n_exprs)
+
+                       # Add additional arguments for the super init call
                        if args.length == 1 then
                                for i in [0..callsite.msignature.arity[ do
                                        args.add(v.frame.arguments[i+1])
@@ -2930,19 +2922,22 @@ redef class ASuperExpr
                        return res
                end
 
+               var mpropdef = self.mpropdef.as(not null)
+               var args = v.varargize(mpropdef, recv, self.n_args.n_exprs)
                if args.length == 1 then
                        args = v.frame.arguments
                end
 
                # stantard call-next-method
-               return v.supercall(mpropdef.as(not null), recv.mtype.as(MClassType), args)
+               return v.supercall(mpropdef, recv.mtype.as(MClassType), args)
        end
 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
@@ -2958,11 +2953,10 @@ redef class ANewExpr
                else
                        recv = v.new_expr("({ctype})0/*special!*/", mtype)
                end
-               var args = [recv]
-               for a in self.n_args.n_exprs do
-                       args.add(v.expr(a, null))
-               end
-               var res2 = v.compile_callsite(self.callsite.as(not null), args)
+
+               var callsite = self.callsite.as(not null)
+               var args = v.varargize(callsite.mpropdef, recv, self.n_args.n_exprs)
+               var res2 = v.compile_callsite(callsite, args)
                if res2 != null then
                        #self.debug("got {res2} from {mproperty}. drop {recv}")
                        return res2
@@ -2981,12 +2975,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