X-Git-Url: http://nitlanguage.org diff --git a/src/compiler/abstract_compiler.nit b/src/compiler/abstract_compiler.nit index 311d71b..02bdade 100644 --- a/src/compiler/abstract_compiler.nit +++ b/src/compiler/abstract_compiler.nit @@ -23,6 +23,7 @@ import platform import c_tools private import annotation import mixin +import counter # Add compiling options redef class ToolContext @@ -94,12 +95,12 @@ redef class ToolContext # Default is nitstack opt_stacktrace.value = "nitstack" else - print "Error: unknown value `{st}` for --stacktrace. Use `none`, `libunwind`, `nitstack` or `auto`." + print "Option Error: unknown value `{st}` for --stacktrace. Use `none`, `libunwind`, `nitstack` or `auto`." exit(1) end if opt_output.value != null and opt_dir.value != null then - print "Error: cannot use both --dir and --output" + print "Option Error: cannot use both --dir and --output" exit(1) end @@ -114,15 +115,12 @@ redef class ToolContext end redef class ModelBuilder - # The compilation directory - var compile_dir: String - # Simple indirection to `Toolchain::write_and_make` protected fun write_and_make(compiler: AbstractCompiler) do var platform = compiler.target_platform var toolchain = platform.toolchain(toolcontext, compiler) - compile_dir = toolchain.compile_dir + compiler.toolchain = toolchain toolchain.write_and_make end end @@ -144,14 +142,21 @@ class Toolchain # Compiler of the target program var compiler: AbstractCompiler - # Directory where to generate all C files - fun compile_dir: String + # Directory where to generate all files + # + # The option `--compile_dir` change this directory. + fun root_compile_dir: String do var compile_dir = toolcontext.opt_compile_dir.value - if compile_dir == null then compile_dir = ".nit_compile" + if compile_dir == null then compile_dir = "nit_compile" return compile_dir end + # Directory where to generate all C files + # + # By default it is `root_compile_dir` but some platform may require that it is a subdirectory. + fun compile_dir: String do return root_compile_dir + # Write all C files and compile them fun write_and_make is abstract end @@ -170,6 +175,7 @@ class MakefileToolchain var time0 = get_time self.toolcontext.info("*** WRITING C ***", 1) + root_compile_dir.mkdir compile_dir.mkdir var cfiles = new Array[String] @@ -299,15 +305,8 @@ class MakefileToolchain # Get the default name of the executable to produce fun default_outname: String do - var mainmodule = compiler.mainmodule - - # Search a non fictive module - var res = mainmodule.name - while mainmodule.is_fictive do - mainmodule = mainmodule.in_importation.direct_greaters.first - res = mainmodule.name - end - return res + var mainmodule = compiler.mainmodule.first_real_mmodule + return mainmodule.name end # Combine options and platform informations to get the final path of the outfile @@ -333,7 +332,7 @@ class MakefileToolchain 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 + # 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 @@ -469,16 +468,18 @@ endif var makeflags = self.toolcontext.opt_make_flags.value if makeflags == null then makeflags = "" - self.toolcontext.info("make -B -C {compile_dir} -f {makename} -j 4 {makeflags}", 2) + + var command = "make -B -C {compile_dir} -f {makename} -j 4 {makeflags}" + self.toolcontext.info(command, 2) var res if self.toolcontext.verbose_level >= 3 then - res = sys.system("make -B -C {compile_dir} -f {makename} -j 4 {makeflags} 2>&1") + res = sys.system("{command} 2>&1") else - res = sys.system("make -B -C {compile_dir} -f {makename} -j 4 {makeflags} 2>&1 >/dev/null") + res = sys.system("{command} 2>&1 >/dev/null") end if res != 0 then - toolcontext.error(null, "make failed! Error code: {res}.") + toolcontext.error(null, "Compilation Error: `make` failed with error code: {res}. The command was `{command}`.") end end end @@ -500,6 +501,11 @@ abstract class AbstractCompiler # The modelbuilder used to know the model and the AST var modelbuilder: ModelBuilder is protected writable + # The associated toolchain + # + # Set by `modelbuilder.write_and_make` and permit sub-routines to access the current toolchain if required. + var toolchain: Toolchain is noinit + # Is hardening asked? (see --hardening) fun hardening: Bool do return self.modelbuilder.toolcontext.opt_hardening.value @@ -563,7 +569,7 @@ abstract class AbstractCompiler # Binds the generated C function names to Nit function names fun build_c_to_nit_bindings do - var compile_dir = modelbuilder.compile_dir + var compile_dir = toolchain.compile_dir var stream = new FileWriter.open("{compile_dir}/c_functions_hash.c") stream.write("#include \n") @@ -695,7 +701,7 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref ); var finalize_meth = mainmodule.try_get_primitive_method("finalize", finalizable_type.mclass) if finalize_meth == null then - modelbuilder.toolcontext.error(null, "The `Finalizable` class doesn't declare the `finalize` method.") + modelbuilder.toolcontext.error(null, "Error: the `Finalizable` class does not declare the `finalize` method.") return end @@ -1042,14 +1048,6 @@ extern void nitni_global_ref_decr( struct nitni_ref *ref ) { end fun finalize_ffi_for_module(mmodule: MModule) do mmodule.finalize_ffi(self) - - # Division facility - # Avoid division by zero by returning the string "n/a" - fun div(a,b:Int):String - do - if b == 0 then return "n/a" - return ((a*10000/b).to_f / 100.0).to_precision(2) - end end # A file unit (may be more than one file if @@ -1158,40 +1156,45 @@ abstract class AbstractCompilerVisitor # 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] + fun varargize(mpropdef: MMethodDef, map: nullable SignatureMap, recv: RuntimeVariable, args: SequenceRead[AExpr]): Array[RuntimeVariable] do var msignature = mpropdef.new_msignature or else mpropdef.msignature.as(not null) var res = new Array[RuntimeVariable] res.add(recv) - if args.is_empty then return res + if msignature.arity == 0 then return res - var vararg_rank = msignature.vararg_rank - var vararg_len = args.length - msignature.arity - if vararg_len < 0 then vararg_len = 0 + if map == null then + assert args.length == msignature.arity + for ne in args do + res.add self.expr(ne, null) + end + return res + end + # Eval in order of arguments, not parameters + var exprs = new Array[RuntimeVariable].with_capacity(args.length) + for ne in args do + exprs.add self.expr(ne, null) + end + + # Fill `res` with the result of the evaluation according to the mapping 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 param = msignature.mparameters[i] + var j = map.map.get_or_null(i) + if j == null then + # default value + res.add(null_instance) + continue + end + if param.is_vararg and map.vararg_decl > 0 then + var vararg = exprs.sub(j, map.vararg_decl) + var elttype = param.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) + continue end + res.add exprs[j] end return res end @@ -1642,6 +1645,12 @@ abstract class AbstractCompilerVisitor fun stmt(nexpr: nullable AExpr) do if nexpr == null then return + if nexpr.mtype == null and not nexpr.is_typed then + # Untyped expression. + # Might mean dead code + # So just return + return + end var narray = nexpr.comprehension if narray != null then @@ -1661,6 +1670,13 @@ abstract class AbstractCompilerVisitor # `mtype` is the expected return type, pass null if no specific type is expected. fun expr(nexpr: AExpr, mtype: nullable MType): RuntimeVariable do + if nexpr.mtype == null then + # Untyped expression. + # Might mean dead code + # so return a placebo result + if mtype == null then mtype = compiler.mainmodule.object_type + return new_var(mtype) + end var old = self.current_node self.current_node = nexpr var res = nexpr.expr(self).as(not null) @@ -2052,6 +2068,9 @@ redef class AMethPropdef else if pname == "unary -" then v.ret(v.new_expr("-{arguments[0]}", ret.as(not null))) return true + else if pname == "unary +" then + v.ret(arguments[0]) + return true else if pname == "*" then v.ret(v.new_expr("{arguments[0]} * {arguments[1]}", ret.as(not null))) return true @@ -2163,6 +2182,9 @@ redef class AMethPropdef else if pname == "unary -" then v.ret(v.new_expr("-{arguments[0]}", ret.as(not null))) return true + else if pname == "unary +" then + v.ret(arguments[0]) + return true else if pname == "succ" then v.ret(v.new_expr("{arguments[0]}+1", ret.as(not null))) return true @@ -2211,6 +2233,9 @@ 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 == "fast_cstring" then + v.ret(v.new_expr("{arguments[0]} + {arguments[1]}", ret.as(not null))) + return true else if pname == "new" then v.ret(v.new_expr("(char*)nit_alloc({arguments[1]})", ret.as(not null))) return true @@ -2381,7 +2406,7 @@ redef class AAttrPropdef 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]) + var frame = new StaticFrame(v, self.mpropdef.as(not null), recv.mcasttype.undecorate.as(MClassType), [recv]) v.frame = frame var value @@ -2532,6 +2557,13 @@ redef class ASelfExpr redef fun expr(v) do return v.frame.arguments.first end +redef class AImplicitSelfExpr + redef fun expr(v) do + if not is_sys then return super + return v.new_expr("glob_sys", mtype.as(not null)) + end +end + redef class AEscapeExpr redef fun stmt(v) do v.add("goto BREAK_{v.escapemark_name(self.escapemark)};") end @@ -2958,7 +2990,7 @@ redef class ASendExpr do var recv = v.expr(self.n_expr, null) var callsite = self.callsite.as(not null) - var args = v.varargize(callsite.mpropdef, recv, self.raw_arguments) + var args = v.varargize(callsite.mpropdef, callsite.signaturemap, recv, self.raw_arguments) return v.compile_callsite(callsite, args) end end @@ -2968,7 +3000,7 @@ redef class ASendReassignFormExpr do var recv = v.expr(self.n_expr, null) var callsite = self.callsite.as(not null) - var args = v.varargize(callsite.mpropdef, recv, self.raw_arguments) + var args = v.varargize(callsite.mpropdef, callsite.signaturemap, recv, self.raw_arguments) var value = v.expr(self.n_value, null) @@ -2990,26 +3022,33 @@ redef class ASuperExpr var callsite = self.callsite if callsite != null then - var args = v.varargize(callsite.mpropdef, recv, self.n_args.n_exprs) + var args - # Add additional arguments for the super init call - if args.length == 1 then + if self.n_args.n_exprs.is_empty then + # Add automatic arguments for the super init call + args = [recv] for i in [0..callsite.msignature.arity[ do args.add(v.frame.arguments[i+1]) end + else + args = v.varargize(callsite.mpropdef, callsite.signaturemap, recv, self.n_args.n_exprs) end + # Super init call var res = v.compile_callsite(callsite, args) 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 + + var args + if self.n_args.n_exprs.is_empty then args = v.frame.arguments + else + args = v.varargize(mpropdef, signaturemap, recv, self.n_args.n_exprs) end - # stantard call-next-method + # Standard call-next-method return v.supercall(mpropdef, recv.mtype.as(MClassType), args) end end @@ -3030,8 +3069,10 @@ redef class ANewExpr var recv = v.init_instance_or_extern(mtype) - var callsite = self.callsite.as(not null) - var args = v.varargize(callsite.mpropdef, recv, self.n_args.n_exprs) + var callsite = self.callsite + if callsite == null then return recv + + var args = v.varargize(callsite.mpropdef, callsite.signaturemap, 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}") @@ -3083,6 +3124,20 @@ redef class AIssetAttrExpr end end +redef class AVarargExpr + redef fun expr(v) + do + return v.expr(self.n_expr, null) + end +end + +redef class ANamedargExpr + redef fun expr(v) + do + return v.expr(self.n_expr, null) + end +end + redef class ADebugTypeExpr redef fun stmt(v) do @@ -3148,7 +3203,7 @@ var modelbuilder = new ModelBuilder(model, toolcontext) var arguments = toolcontext.option_context.rest if arguments.length > 1 and toolcontext.opt_output.value != null then - print "Error: --output needs a single source file. Do you prefer --dir?" + print "Option Error: --output needs a single source file. Do you prefer --dir?" exit 1 end