X-Git-Url: http://nitlanguage.org diff --git a/src/compiler/abstract_compiler.nit b/src/compiler/abstract_compiler.nit index dbf3794..dfe463c 100644 --- a/src/compiler/abstract_compiler.nit +++ b/src/compiler/abstract_compiler.nit @@ -34,12 +34,12 @@ 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 @@ -78,7 +78,9 @@ redef class ToolContext 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.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) @@ -118,20 +120,16 @@ redef class ModelBuilder # Simple indirection to `Toolchain::write_and_make` protected fun write_and_make(compiler: AbstractCompiler) do - var platform = compiler.mainmodule.target_platform - var toolchain - if platform == null then - toolchain = new MakefileToolchain(toolcontext) - else - toolchain = platform.toolchain(toolcontext) - end + var platform = compiler.target_platform + var toolchain = platform.toolchain(toolcontext) compile_dir = toolchain.compile_dir toolchain.write_and_make compiler end end redef class Platform - fun toolchain(toolcontext: ToolContext): Toolchain is abstract + # The specific tool-chain associated to the platform + fun toolchain(toolcontext: ToolContext): Toolchain do return new MakefileToolchain(toolcontext) end class Toolchain @@ -149,40 +147,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 @@ -218,16 +185,18 @@ class MakefileToolchain fun write_files(compiler: AbstractCompiler, compile_dir: String, cfiles: Array[String]) do - var platform = compiler.mainmodule.target_platform - if self.toolcontext.opt_stacktrace.value == "nitstack" and (platform == null or platform.supports_libunwind) then compiler.build_c_to_nit_bindings + var platform = compiler.target_platform + if self.toolcontext.opt_stacktrace.value == "nitstack" and platform.supports_libunwind then compiler.build_c_to_nit_bindings var cc_opt_with_libgc = "-DWITH_LIBGC" - if platform != null and not platform.supports_libgc then cc_opt_with_libgc = "" + if not platform.supports_libgc then cc_opt_with_libgc = "" # 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 @@ -311,7 +280,7 @@ class MakefileToolchain 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,30 +307,32 @@ class MakefileToolchain fun write_makefile(compiler: AbstractCompiler, compile_dir: String, cfiles: Array[String]) do var mainmodule = compiler.mainmodule - var platform = compiler.mainmodule.target_platform + var platform = compiler.target_platform var outname = outfile(mainmodule) - var outpath = compile_dir.relpath(outname) + var real_outpath = compile_dir.relpath(outname) + var outpath = real_outpath.escape_to_mk + if outpath != real_outpath then + # If the name is crazy and need escaping, we will do an indirection + # 1. generate the binary in the .nit_compile dir under an escaped name + # 2. copy the binary at the right place in the `all` goal. + outpath = mainmodule.c_name + end 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 -Wno-attributes\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") + if (ost == "libunwind" or ost == "nitstack") and platform.supports_libunwind then makefile.write("NEED_LIBUNWIND := YesPlease\n") # Dynamic adaptations # While `platform` enable complex toolchains, they are statically applied @@ -380,7 +351,11 @@ class MakefileToolchain makefile.write("ifdef NEED_LIBUNWIND\n\tLDLIBS += -lunwind\nendif\n") - makefile.write("all: {outpath}\n\n") + makefile.write("all: {outpath}\n") + if outpath != real_outpath then + makefile.write("\tcp -- {outpath.escape_to_sh} {real_outpath.escape_to_sh.replace("$","$$")}") + end + makefile.write("\n") var ofiles = new Array[String] var dep_rules = new Array[String] @@ -392,8 +367,42 @@ class MakefileToolchain dep_rules.add(o) end + # Generate linker script, if any + if not compiler.linker_script.is_empty then + var linker_script_path = "{compile_dir}/linker_script" + ofiles.add "linker_script" + var f = new OFStream.open(linker_script_path) + for l in compiler.linker_script do + f.write l + f.write "\n" + end + f.close + end + 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 @@ -419,11 +428,20 @@ 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.escape_to_sh} {ofiles.join(" ")} $(LDLIBS) {pkg}\n\n") # Clean - makefile.write("clean:\n\trm {ofiles.join(" ")} 2>/dev/null\n\n") + makefile.write("clean:\n\trm {ofiles.join(" ")} 2>/dev/null\n") + if outpath != real_outpath then + makefile.write("\trm -- {outpath.escape_to_sh} 2>/dev/null\n") + end 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,7 +476,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 @@ -466,17 +484,30 @@ abstract class AbstractCompiler # Is hardening asked? (see --hardening) fun hardening: Bool do return self.modelbuilder.toolcontext.opt_hardening.value - init(mainmodule: MModule, modelbuilder: ModelBuilder) + # The targeted specific platform + var target_platform: Platform is noinit + + init do - self.mainmodule = mainmodule self.realmainmodule = mainmodule - self.modelbuilder = modelbuilder + target_platform = mainmodule.target_platform or else new Platform end + # Do the full code generation of the program `mainmodule` + # It is the main method usually called after the instantiation + fun do_compilation is abstract + # 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 @@ -490,7 +521,11 @@ 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 + + # Additionnal linker script for `ld`. + # Mainly used to do specific link-time symbol resolution + var linker_script = new Array[String] # Provide a declaration that can be requested (before or latter) by a visitor fun provide_declaration(key: String, s: String) @@ -523,9 +558,9 @@ abstract class AbstractCompiler stream.write("static const C_Nit_Names map[{names.length}] = \{\n") for i in names.keys do stream.write("\{\"") - stream.write(i) + stream.write(i.escape_to_c) stream.write("\",\"") - stream.write(names[i]) + stream.write(names[i].escape_to_c) stream.write("\"\},\n") end stream.write("\};\n") @@ -662,11 +697,11 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref ); var v = self.new_visitor v.add_decl("#include ") var ost = modelbuilder.toolcontext.opt_stacktrace.value - var platform = mainmodule.target_platform + var platform = target_platform - if platform != null and not platform.supports_libunwind then ost = "none" + if not platform.supports_libunwind then ost = "none" - var no_main = (platform != null and platform.no_main) or modelbuilder.toolcontext.opt_no_main.value + var no_main = platform.no_main or modelbuilder.toolcontext.opt_no_main.value if ost == "nitstack" or ost == "libunwind" then v.add_decl("#define UNW_LOCAL_ONLY") @@ -899,12 +934,8 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref ) { var cds = mtype.collect_mclassdefs(self.mainmodule).to_a self.mainmodule.linearize_mclassdefs(cds) for cd in cds do - if not self.modelbuilder.mclassdef2nclassdef.has_key(cd) then continue - var n = self.modelbuilder.mclassdef2nclassdef[cd] - for npropdef in n.n_propdefs do - if npropdef isa AAttrPropdef then - npropdef.init_expr(v, recv) - end + for npropdef in modelbuilder.collect_attr_propdef(cd) do + npropdef.init_expr(v, recv) end end end @@ -915,12 +946,8 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref ) { var cds = mtype.collect_mclassdefs(self.mainmodule).to_a self.mainmodule.linearize_mclassdefs(cds) for cd in cds do - if not self.modelbuilder.mclassdef2nclassdef.has_key(cd) then continue - var n = self.modelbuilder.mclassdef2nclassdef[cd] - for npropdef in n.n_propdefs do - if npropdef isa AAttrPropdef then - npropdef.check_expr(v, recv) - end + for npropdef in modelbuilder.collect_attr_propdef(cd) do + npropdef.check_expr(v, recv) end end end @@ -1012,9 +1039,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 @@ -1030,8 +1056,8 @@ abstract class AbstractCompilerVisitor # The current visited AST node var current_node: nullable ANode = null is writable - # The current `Frame` - var frame: nullable Frame is writable + # The current `StaticFrame` + var frame: nullable StaticFrame = null is writable # Alias for self.compiler.mainmodule.object_type fun object_type: MClassType do return self.compiler.mainmodule.object_type @@ -1039,11 +1065,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 @@ -1274,11 +1299,11 @@ abstract class AbstractCompilerVisitor fun escapemark_name(e: nullable EscapeMark): String do assert e != null - if escapemark_names.has_key(e) then return escapemark_names[e] + if frame.escapemark_names.has_key(e) then return frame.escapemark_names[e] var name = e.name if name == null then name = "label" name = get_name(name) - escapemark_names[e] = name + frame.escapemark_names[e] = name return name end @@ -1290,8 +1315,6 @@ abstract class AbstractCompilerVisitor 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 # NOTE: we do not return a `RuntimeVariable` "NativeString" as the class may not exist in the module/program fun class_name_string(value: RuntimeVariable): String is abstract @@ -1455,10 +1478,11 @@ abstract class AbstractCompilerVisitor self.require_declaration(s) end - # look for a needed .h and .c file for a given .nit source-file - # FIXME: bad API, parameter should be a `MModule`, not its source-file - fun add_extern(file: String) + # Look for a needed .h and .c file for a given module + # This is used for the legacy FFI + fun add_extern(mmodule: MModule) do + var file = mmodule.location.file.filename file = file.strip_extension(".nit") var tryfile = file + ".nit.h" if tryfile.file_exists then @@ -1531,6 +1555,15 @@ abstract class AbstractCompilerVisitor fun stmt(nexpr: nullable AExpr) do if nexpr == null then return + + var narray = nexpr.comprehension + if narray != null then + var recv = frame.comprehension.as(not null) + var val = expr(nexpr, narray.element_mtype) + compile_callsite(narray.push_callsite.as(not null), [recv, val]) + return + end + var old = self.current_node self.current_node = nexpr nexpr.stmt(self) @@ -1627,11 +1660,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 @@ -1656,8 +1686,8 @@ class RuntimeVariable end end -# A frame correspond to a visited property in a `GlobalCompilerVisitor` -class Frame +# The static context of a visited property in a `AbstractCompilerVisitor` +class StaticFrame type VISITOR: AbstractCompilerVisitor @@ -1679,6 +1709,13 @@ class Frame # The label at the end of the property var returnlabel: nullable String = null is writable + + # Labels associated to a each escapemarks. + # Because of inlinings, escape-marks must be associated to their context (the frame) + private var escapemark_names = new HashMap[EscapeMark, String] + + # The array comprehension currently filled, if any + private var comprehension: nullable RuntimeVariable = null end redef class MType @@ -1690,21 +1727,9 @@ redef class MType # Short name of the `ctype` to use in unions fun ctypename: String do return "val" - - # Return the name of the C structure associated to a Nit live type - fun c_name: String is abstract - protected var c_name_cache: nullable String is protected writable end redef class MClassType - redef fun c_name - do - var res = self.c_name_cache - if res != null then return res - res = "{mclass.intro_mmodule.name.to_cmangle}__{mclass.name.to_cmangle}" - self.c_name_cache = res - return res - end redef fun ctype: String do @@ -1755,90 +1780,8 @@ redef class MClassType end end -redef class MGenericType - redef fun c_name - do - var res = self.c_name_cache - if res != null then return res - res = super - for t in self.arguments do - res = res + t.c_name - end - self.c_name_cache = res - return res - end -end - -redef class MParameterType - redef fun c_name - do - var res = self.c_name_cache - if res != null then return res - res = "{self.mclass.c_name}_FT{self.rank}" - self.c_name_cache = res - return res - end -end - -redef class MVirtualType - redef fun c_name - do - var res = self.c_name_cache - if res != null then return res - res = "{self.mproperty.intro.mclassdef.mclass.c_name}_VT{self.mproperty.name}" - self.c_name_cache = res - return res - end -end - -redef class MNullableType - redef fun c_name - do - var res = self.c_name_cache - if res != null then return res - res = "nullable_{self.mtype.c_name}" - self.c_name_cache = res - return res - end -end - -redef class MClass - # Return the name of the C structure associated to a Nit class - 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}" - self.c_name_cache = res - return res - end - private var c_name_cache: nullable String -end - -redef class MProperty - fun c_name: String do - var res = self.c_name_cache - if res != null then return res - res = "{self.intro.c_name}" - self.c_name_cache = res - return res - end - private var c_name_cache: nullable String -end - redef class MPropDef type VISITOR: AbstractCompilerVisitor - - private var c_name_cache: nullable String - - # The mangled name associated to the property - fun c_name: String - 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}" - self.c_name_cache = res - return res - end end redef class MMethodDef @@ -1847,10 +1790,10 @@ redef class MMethodDef do if is_abstract then return true var modelbuilder = v.compiler.modelbuilder - if modelbuilder.mpropdef2npropdef.has_key(self) then - var npropdef = modelbuilder.mpropdef2npropdef[self] - return npropdef.can_inline - else if self.mproperty.is_root_init then + var node = modelbuilder.mpropdef2node(self) + if node isa APropdef then + return node.can_inline + else if node isa AClassdef then # Automatic free init is always inlined since it is empty or contains only attribtes assigments return true else @@ -1863,19 +1806,18 @@ redef class MMethodDef do var modelbuilder = v.compiler.modelbuilder var val = constant_value - if modelbuilder.mpropdef2npropdef.has_key(self) then - var npropdef = modelbuilder.mpropdef2npropdef[self] + var node = modelbuilder.mpropdef2node(self) + if node isa APropdef then var oldnode = v.current_node - v.current_node = npropdef + v.current_node = node self.compile_parameter_check(v, arguments) - npropdef.compile_to_c(v, self, arguments) + node.compile_to_c(v, self, arguments) v.current_node = oldnode - else if self.mproperty.is_root_init then - var nclassdef = modelbuilder.mclassdef2nclassdef[self.mclassdef] + else if node isa AClassdef then var oldnode = v.current_node - v.current_node = nclassdef + v.current_node = node self.compile_parameter_check(v, arguments) - nclassdef.compile_to_c(v, self, arguments) + node.compile_to_c(v, self, arguments) v.current_node = oldnode else if val != null then v.ret(v.value_instance(val)) @@ -2230,16 +2172,13 @@ redef class AMethPropdef do var externname var at = self.get_single_annotation("extern", v.compiler.modelbuilder) - if at != null then + if at != null and at.n_args.length == 1 then externname = at.arg_as_string(v.compiler.modelbuilder) if externname == null then return false else return false end - if location.file != null then - var file = location.file.filename - v.add_extern(file) - end + v.add_extern(mpropdef.mclassdef.mmodule) var res: nullable RuntimeVariable = null var ret = mpropdef.msignature.return_mtype if ret != null then @@ -2271,10 +2210,7 @@ redef class AMethPropdef else return false end - if location.file != null then - var file = location.file.filename - v.add_extern(file) - end + v.add_extern(mpropdef.mclassdef.mmodule) v.adapt_signature(mpropdef, arguments) v.unbox_signature_extern(mpropdef, arguments) var ret = arguments.first.mtype @@ -2290,28 +2226,30 @@ redef class AMethPropdef end redef class AAttrPropdef + redef fun can_inline: Bool do return not is_lazy + redef fun compile_to_c(v, mpropdef, arguments) 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) @@ -2339,18 +2277,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 StaticFrame(v, self.mpropdef.as(not null), recv.mcasttype.as_notnullable.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) @@ -2361,7 +2325,7 @@ redef class AAttrPropdef 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]) + var frame = new StaticFrame(v, self.mpropdef.as(not null), recv.mtype.as(MClassType), [recv]) v.frame = frame # Force read to check the initialization v.read_attribute(self.mpropdef.mproperty, recv) @@ -2715,13 +2679,18 @@ end redef class AArrayExpr redef fun expr(v) do - var mtype = self.mtype.as(MClassType).arguments.first + var mtype = self.element_mtype.as(not null) var array = new Array[RuntimeVariable] - for nexpr in self.n_exprs.n_exprs do - var i = v.expr(nexpr, mtype) - array.add(i) + var res = v.array_instance(array, mtype) + + var old_comprehension = v.frame.comprehension + v.frame.comprehension = res + for nexpr in self.n_exprs do + v.stmt(nexpr) end - return v.array_instance(array, mtype) + v.frame.comprehension = old_comprehension + + return res end end @@ -3027,7 +2996,7 @@ end # Create a tool context to handle options and paths var toolcontext = new ToolContext -toolcontext.tooldescription = "Usage: nitg [OPTION]... file.nit...\nCompiles Nit programs." +toolcontext.tooldescription = "Usage: nitc [OPTION]... file.nit...\nCompiles Nit programs." # We do not add other options, so process them now! toolcontext.process_options(args)