X-Git-Url: http://nitlanguage.org diff --git a/src/compiler/abstract_compiler.nit b/src/compiler/abstract_compiler.nit index 58cb346..c785dd6 100644 --- a/src/compiler/abstract_compiler.nit +++ b/src/compiler/abstract_compiler.nit @@ -22,47 +22,46 @@ import semantize import platform import c_tools private import annotation +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") # --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 @@ -71,7 +70,7 @@ 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) @@ -181,7 +180,6 @@ class MakefileToolchain do gather_cc_paths - var mainmodule = compiler.mainmodule var compile_dir = compile_dir # Generate the .h and .c files @@ -229,7 +227,6 @@ class MakefileToolchain compiler.files_to_copy.add "{cc_paths.first}/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 @@ -310,7 +307,16 @@ class MakefileToolchain fun makefile_name(mainmodule: MModule): String do return "{mainmodule.name}.mk" - fun default_outname(mainmodule: MModule): String do return mainmodule.name + fun default_outname(mainmodule: MModule): String + do + # Search a non fictive module + var res = mainmodule.name + while mainmodule.is_fictive do + mainmodule = mainmodule.in_importation.direct_greaters.first + res = mainmodule.name + end + return res + end # Combine options and platform informations to get the final path of the outfile fun outfile(mainmodule: MModule): String @@ -342,7 +348,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) @@ -450,7 +455,7 @@ abstract class AbstractCompiler # The real main module of the program var realmainmodule: MModule - # 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) @@ -474,7 +479,7 @@ 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 @@ -541,8 +546,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 ") self.header.add_decl("#include ") self.header.add_decl("#include ") @@ -891,6 +894,7 @@ 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 @@ -906,6 +910,7 @@ 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 @@ -1044,7 +1049,7 @@ abstract class AbstractCompilerVisitor fun get_property(name: String, recv: MType): MMethod do assert recv isa MClassType - return self.compiler.modelbuilder.force_get_primitive_method(self.current_node.as(not null), name, recv.mclass, self.compiler.mainmodule) + return self.compiler.modelbuilder.force_get_primitive_method(self.current_node, name, recv.mclass, self.compiler.mainmodule) end fun compile_callsite(callsite: CallSite, arguments: Array[RuntimeVariable]): nullable RuntimeVariable @@ -1081,39 +1086,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 + var msignature = mpropdef.new_msignature or else mpropdef.msignature.as(not null) + var res = new Array[RuntimeVariable] + res.add(recv) - for i in [0..vararg_rank[ do - args.add(rawargs[i+1]) - end - - 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 @@ -1217,7 +1228,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 @@ -1232,7 +1243,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 @@ -1282,7 +1293,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 @@ -1361,6 +1372,18 @@ abstract class AbstractCompilerVisitor return res end + # Generate an integer value + fun bool_instance(value: Bool): RuntimeVariable + do + var res = self.new_var(self.get_class("Bool").mclass_type) + if value then + self.add("{res} = 1;") + else + self.add("{res} = 0;") + end + return res + end + # Generate a string value fun string_instance(string: String): RuntimeVariable do @@ -1381,6 +1404,19 @@ abstract class AbstractCompilerVisitor return res end + fun value_instance(object: Object): RuntimeVariable + do + if object isa Int then + return int_instance(object) + else if object isa Bool then + return bool_instance(object) + else if object isa String then + return string_instance(object) + else + abort + end + end + # Generate an array value fun array_instance(array: Array[RuntimeVariable], elttype: MType): RuntimeVariable is abstract @@ -1809,7 +1845,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 @@ -1821,6 +1857,7 @@ redef class MMethodDef fun compile_inside_to_c(v: VISITOR, arguments: Array[RuntimeVariable]): nullable RuntimeVariable do var modelbuilder = v.compiler.modelbuilder + var val = constant_value if modelbuilder.mpropdef2npropdef.has_key(self) then var npropdef = modelbuilder.mpropdef2npropdef[self] var oldnode = v.current_node @@ -1828,13 +1865,15 @@ 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 self.compile_parameter_check(v, arguments) nclassdef.compile_to_c(v, self, arguments) v.current_node = oldnode + else if val != null then + v.ret(v.value_instance(val)) else abort end @@ -1950,8 +1989,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) @@ -2132,7 +2169,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 @@ -2364,8 +2401,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 @@ -2407,12 +2443,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) @@ -2532,38 +2562,6 @@ 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_escape_label(continue_mark) - var succ = v.send(v.get_property("successor", variable.mtype), [variable, one]) - assert succ != null - v.assign(variable, succ) - v.add("\}") - v.add_escape_label(break_mark) - return - end - var cl = v.expr(self.n_expr, null) var it_meth = self.method_iterator assert it_meth != null @@ -2748,7 +2746,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 @@ -2760,7 +2758,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 @@ -2840,11 +2838,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 @@ -2852,13 +2848,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]) @@ -2873,14 +2868,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]) @@ -2891,19 +2884,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 @@ -2919,11 +2915,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 @@ -2942,12 +2937,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 @@ -3026,9 +3022,6 @@ end # Create a tool context to handle options and paths var toolcontext = new ToolContext -var opt_mixins = new OptionArray("Additionals module to min-in", "-m") -toolcontext.option_context.add_option(opt_mixins) - toolcontext.tooldescription = "Usage: nitg [OPTION]... file.nit...\nCompiles Nit programs." # We do not add other options, so process them now! @@ -3047,7 +3040,6 @@ end # Here we load an process all modules passed on the command line var mmodules = modelbuilder.parse(arguments) -var mixins = modelbuilder.parse(opt_mixins.value) if mmodules.is_empty then return modelbuilder.run_phases @@ -3055,8 +3047,5 @@ modelbuilder.run_phases for mmodule in mmodules do toolcontext.info("*** PROCESS {mmodule} ***", 1) var ms = [mmodule] - if not mixins.is_empty then - ms.add_all mixins - end toolcontext.run_global_phases(ms) end