X-Git-Url: http://nitlanguage.org diff --git a/src/abstract_compiler.nit b/src/abstract_compiler.nit index 951ba49..5a5597c 100644 --- a/src/abstract_compiler.nit +++ b/src/abstract_compiler.nit @@ -20,6 +20,7 @@ module abstract_compiler import literal import typing import auto_super_init +import frontend # Add compiling options redef class ToolContext @@ -27,6 +28,8 @@ redef class ToolContext var opt_output: OptionString = new OptionString("Output file", "-o", "--output") # --no-cc var opt_no_cc: OptionBool = new OptionBool("Do not invoke C compiler", "--no-cc") + # --cc-paths + var opt_cc_path: OptionArray = 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") # --hardening @@ -56,6 +59,42 @@ redef class ToolContext end redef class ModelBuilder + # 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 + # * some heuristics including the NIT_DIR environment variable and the progname of the process + # Path can be added (or removed) by the client + var cc_paths = new Array[String] + + redef init(model, toolcontext) + do + super + + # Look for the the Nit clib path + var path_env = "NIT_DIR".environ + if not path_env.is_empty then + var libname = "{path_env}/clib" + if libname.file_exists then cc_paths.add(libname) + end + + var libname = "{sys.program_name.dirname}/../clib" + if libname.file_exists then cc_paths.add(libname.simplify_path) + + 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 + protected fun write_and_make(compiler: AbstractCompiler) do var mainmodule = compiler.mainmodule @@ -64,12 +103,13 @@ redef class ModelBuilder # A single C file regroups many compiled rumtime functions # Note that we do not try to be clever an a small change in a Nit source file may change the content of all the generated .c files var time0 = get_time + self.toolcontext.info("*** WRITING C ***", 1) ".nit_compile".mkdir var outname = self.toolcontext.opt_output.value if outname == null then - outname = "{mainmodule.name}.bin" + outname = "{mainmodule.name}" end var hfilename = compiler.header.file.name + ".h" @@ -138,23 +178,34 @@ redef class ModelBuilder var makename = ".nit_compile/{mainmodule.name}.mk" var makefile = new OFStream.open(makename) - makefile.write("CC = ccache cc\nCFLAGS = -g -O2\nLDFLAGS ?= \nLDLIBS ?= -lm -lgc\n\n") + var cc_includes = "" + for p in cc_paths do + #p = "..".join_path(p) + cc_includes += " -I \"" + p + "\"" + end + makefile.write("CC = ccache cc\nCFLAGS = -g -O2\nCINCL = {cc_includes}\nLDFLAGS ?= \nLDLIBS ?= -lm -lgc\n\n") makefile.write("all: {outname}\n\n") var ofiles = new Array[String] # Compile each generated file for f in cfiles do var o = f.strip_extension(".c") + ".o" - makefile.write("{o}: {f}\n\t$(CC) $(CFLAGS) -D NONITCNI -c -o {o} {f}\n\n") + makefile.write("{o}: {f}\n\t$(CC) $(CFLAGS) $(CINCL) -D NONITCNI -c -o {o} {f}\n\n") ofiles.add(o) end + + # Add gc_choser.h to aditionnal bodies + var gc_chooser = new ExternCFile("{cc_paths.first}/gc_chooser.c", "-DWITH_LIBGC") + compiler.extern_bodies.add(gc_chooser) + # Compile each required extern body into a specific .o for f in compiler.extern_bodies do - var basename = f.basename(".c") + var basename = f.filename.basename(".c") var o = ".nit_compile/{basename}.extern.o" - makefile.write("{o}: {f}\n\t$(CC) $(CFLAGS) -D NONITCNI -c -o {o} {f}\n\n") + makefile.write("{o}: {f.filename}\n\t$(CC) $(CFLAGS) -D NONITCNI {f.cflags} -c -o {o} {f.filename}\n\n") ofiles.add(o) end + # Link edition makefile.write("{outname}: {ofiles.join(" ")}\n\t$(CC) $(LDFLAGS) -o {outname} {ofiles.join(" ")} $(LDLIBS)\n\n") # Clean @@ -163,7 +214,7 @@ redef class ModelBuilder self.toolcontext.info("Generated makefile: {makename}", 2) var time1 = get_time - self.toolcontext.info("*** END COMPILING TO C: {time1-time0} ***", 2) + self.toolcontext.info("*** END WRITING C: {time1-time0} ***", 2) # Execute the Makefile @@ -194,8 +245,12 @@ end abstract class AbstractCompiler type VISITOR: AbstractCompilerVisitor - # The main module of the program - var mainmodule: MModule protected writable + # The main module of the program currently compiled + # Is assigned during the separate compilation + var mainmodule: MModule writable + + # The real main module of the program + var realmainmodule: MModule # The modeulbuilder used to know the model and the AST var modelbuilder: ModelBuilder protected writable @@ -206,6 +261,7 @@ abstract class AbstractCompiler init(mainmodule: MModule, modelbuilder: ModelBuilder) do self.mainmodule = mainmodule + self.realmainmodule = mainmodule self.modelbuilder = modelbuilder end @@ -246,16 +302,7 @@ abstract class AbstractCompiler self.header.add_decl("#include ") self.header.add_decl("#include ") self.header.add_decl("#include ") - self.header.add_decl("#ifndef NOBOEHM") - self.header.add_decl("#include ") - self.header.add_decl("#ifdef NOBOEHM_ATOMIC") - self.header.add_decl("#undef GC_MALLOC_ATOMIC") - self.header.add_decl("#define GC_MALLOC_ATOMIC(x) GC_MALLOC(x)") - self.header.add_decl("#endif /*NOBOEHM_ATOMIC*/") - self.header.add_decl("#else /*NOBOEHM*/") - self.header.add_decl("#define GC_MALLOC(x) calloc(1, (x))") - self.header.add_decl("#define GC_MALLOC_ATOMIC(x) calloc(1, (x))") - self.header.add_decl("#endif /*NOBOEHM*/") + self.header.add_decl("#include ") compile_header_structs @@ -292,16 +339,17 @@ abstract class AbstractCompiler end v.add_decl("int main(int argc, char** argv) \{") v.add("glob_argc = argc; glob_argv = argv;") + v.add("initialize_gc_option();") var main_type = mainmodule.sys_type if main_type != null then var mainmodule = v.compiler.mainmodule var glob_sys = v.init_instance(main_type) v.add("glob_sys = {glob_sys};") - var main_init = mainmodule.try_get_primitive_method("init", main_type) + var main_init = mainmodule.try_get_primitive_method("init", main_type.mclass) if main_init != null then v.send(main_init, [glob_sys]) end - var main_method = mainmodule.try_get_primitive_method("main", main_type) + var main_method = mainmodule.try_get_primitive_method("main", main_type.mclass) if main_method != null then v.send(main_method, [glob_sys]) end @@ -337,7 +385,10 @@ abstract class AbstractCompiler end # List of additional .c files required to compile (native interface) - var extern_bodies = new ArraySet[String] + var extern_bodies = new Array[ExternCFile] + + # This is used to avoid adding an extern file more than once + private var seen_extern = new ArraySet[String] # Generate code that check if an instance is correctly initialized fun generate_check_init_instance(mtype: MClassType) is abstract @@ -390,8 +441,8 @@ abstract class AbstractCompiler # Display stats about compilation process # Metrics used: - # * type tests against resolved types (x isa Collection[Animal]) - # * type tests against unresolved types (x isa Collection[E]) + # * type tests against resolved types (`x isa Collection[Animal]`) + # * type tests against unresolved types (`x isa Collection[E]`) # * type tests skipped # * type tests total # * @@ -474,7 +525,7 @@ abstract class AbstractCompilerVisitor # The current visited AST node var current_node: nullable ANode writable = null - # The current Frame + # The current `Frame` var frame: nullable Frame writable # Alias for self.compiler.mainmodule.object_type @@ -491,13 +542,14 @@ abstract class AbstractCompilerVisitor self.writer = new CodeWriter(compiler.files.last) end - # Force to get the primitive class named `name' or abort + # Force to get the primitive class named `name` or abort fun get_class(name: String): MClass do return self.compiler.mainmodule.get_primitive_class(name) - # Force to get the primitive property named `name' in the instance `recv' or abort + # Force to get the primitive property named `name` in the instance `recv` or abort fun get_property(name: String, recv: MType): MMethod do - return self.compiler.modelbuilder.force_get_primitive_method(self.current_node.as(not null), name, recv, self.compiler.mainmodule) + assert recv isa MClassType + return self.compiler.modelbuilder.force_get_primitive_method(self.current_node.as(not null), name, recv.mclass, self.compiler.mainmodule) end fun compile_callsite(callsite: CallSite, args: Array[RuntimeVariable]): nullable RuntimeVariable @@ -509,7 +561,7 @@ 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 + # 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]) @@ -561,8 +613,8 @@ abstract class AbstractCompilerVisitor # Unsafely cast a value to a new type # ie the result share the same C variable but my have a different mcasttype - # NOTE: if the adaptation is useless then `value' is returned as it. - # ENSURE: return.name == value.name + # NOTE: if the adaptation is useless then `value` is returned as it. + # ENSURE: `(return).name == value.name` fun autoadapt(value: RuntimeVariable, mtype: MType): RuntimeVariable do mtype = self.anchor(mtype) @@ -603,10 +655,10 @@ abstract class AbstractCompilerVisitor # Generate a static call on a method definition fun call(m: MMethodDef, recvtype: MClassType, args: Array[RuntimeVariable]): nullable RuntimeVariable is abstract - # Generate a polymorphic send for the method `m' and the arguments `args' + # Generate a polymorphic send for the method `m` and the arguments `args` fun send(m: MMethod, args: Array[RuntimeVariable]): nullable RuntimeVariable is abstract - # Generate a monomorphic send for the method `m', the type `t' and the arguments `args' + # Generate a monomorphic send for the method `m`, the type `t` and the arguments `args` fun monomorphic_send(m: MMethod, t: MType, args: Array[RuntimeVariable]): nullable RuntimeVariable do assert t isa MClassType @@ -648,7 +700,7 @@ abstract class AbstractCompilerVisitor private var names: HashSet[String] = new HashSet[String] private var last: Int = 0 - # Return a new name based on `s' and unique in the visitor + # Return a new name based on `s` and unique in the visitor fun get_name(s: String): String do if not self.names.has(s) then @@ -682,7 +734,7 @@ abstract class AbstractCompilerVisitor 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 + # 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 # Variables handling @@ -755,13 +807,11 @@ abstract class AbstractCompilerVisitor self.add("if ({name}) \{") self.add("{res} = {name};") self.add("\} else \{") - var nat = self.new_var(self.get_class("NativeString").mclass_type) + var native_mtype = self.get_class("NativeString").mclass_type + var nat = self.new_var(native_mtype) self.add("{nat} = \"{string.escape_to_c}\";") - var res2 = self.init_instance(mtype) - self.add("{res} = {res2};") var length = self.int_instance(string.length) - self.send(self.get_property("with_native", mtype), [res, nat, length]) - self.check_init_instance(res, mtype) + self.add("{res} = {self.monomorphic_send(self.get_property("to_s_with_length", native_mtype), native_mtype, [nat, length]).as(not null)};") self.add("{name} = {res};") self.add("\}") return res @@ -797,7 +847,7 @@ abstract class AbstractCompilerVisitor 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 + # FIXME: bad API, parameter should be a `MModule`, not its source-file fun add_extern(file: String) do file = file.strip_extension(".nit") @@ -809,17 +859,19 @@ abstract class AbstractCompilerVisitor if tryfile.file_exists then self.declare_once("#include \"{"..".join_path(tryfile)}\"") end + + if self.compiler.seen_extern.has(file) then return + self.compiler.seen_extern.add(file) tryfile = file + ".nit.c" - if tryfile.file_exists then - self.compiler.extern_bodies.add(tryfile) - end - tryfile = file + "_nit.c" - if tryfile.file_exists then - self.compiler.extern_bodies.add(tryfile) + if not tryfile.file_exists then + tryfile = file + "_nit.c" + if not tryfile.file_exists then return end + var f = new ExternCFile(tryfile, "") + self.compiler.extern_bodies.add(f) end - # Return a new local runtime_variable initialized with the C expression `cexpr'. + # Return a new local runtime_variable initialized with the C expression `cexpr`. fun new_expr(cexpr: String, mtype: MType): RuntimeVariable do var res = new_var(mtype) @@ -839,7 +891,7 @@ abstract class AbstractCompilerVisitor self.add("exit(1);") end - # Generate a return with the value `s' + # Generate a return with the value `s` fun ret(s: RuntimeVariable) do self.assign(self.frame.returnvar.as(not null), s) @@ -880,7 +932,7 @@ abstract class AbstractCompilerVisitor return res end - # Alias for `self.expr(nexpr, self.bool_type)' + # Alias for `self.expr(nexpr, self.bool_type)` fun expr_bool(nexpr: AExpr): RuntimeVariable do return expr(nexpr, bool_type) # Safely show a debug message on the current node and repeat the message in the C code as a comment @@ -926,7 +978,7 @@ abstract class AbstractRuntimeFunction # May inline the body or generate a C function call fun call(v: VISITOR, arguments: Array[RuntimeVariable]): nullable RuntimeVariable is abstract - # Generate the code for the RuntimeFunction + # Generate the code for the `AbstractRuntimeFunction` # Warning: compile more than once compilation makes CC unhappy fun compile_to_c(compiler: COMPILER) is abstract end @@ -934,7 +986,7 @@ end # A runtime variable hold a runtime value in C. # Runtime variables are associated to Nit local variables and intermediate results in Nit expressions. # -# The tricky point is that a single C variable can be associated to more than one RuntimeVariable because the static knowledge of the type of an expression can vary in the C code. +# The tricky point is that a single C variable can be associated to more than one `RuntimeVariable` because the static knowledge of the type of an expression can vary in the C code. class RuntimeVariable # The name of the variable in the C code var name: String @@ -978,7 +1030,7 @@ class RuntimeVariable end end -# A frame correspond to a visited property in a GlobalCompilerVisitor +# A frame correspond to a visited property in a `GlobalCompilerVisitor` class Frame type VISITOR: AbstractCompilerVisitor @@ -1003,6 +1055,14 @@ class Frame var returnlabel: nullable String writable = null end +# An extern C file to compile +class ExternCFile + # The filename of the file + var filename: String + # Additionnal specific CC compiler -c flags + var cflags: String +end + redef class String # Mangle a string to be a unique valid C identifier fun to_cmangle: String @@ -1552,7 +1612,7 @@ redef class AInternMethPropdef v.ret(v.new_expr("glob_sys", ret.as(not null))) return else if pname == "calloc_string" then - v.ret(v.new_expr("(char*)GC_MALLOC_ATOMIC({arguments[1]})", ret.as(not null))) + v.ret(v.new_expr("(char*)nit_alloc({arguments[1]})", ret.as(not null))) return else if pname == "calloc_array" then v.calloc_array(ret.as(not null), arguments) @@ -1572,7 +1632,13 @@ redef class AInternMethPropdef v.ret(v.new_expr("(char*){nat}", ret.as(not null))) return else if pname == "force_garbage_collection" then - v.add("GC_gcollect();") + v.add("nit_gcollect();") + return + else if pname == "native_argc" then + v.ret(v.new_expr("glob_argc", ret.as(not null))) + return + else if pname == "native_argv" then + v.ret(v.new_expr("glob_argv[{arguments[1]}]", ret.as(not null))) return end v.add("printf(\"NOT YET IMPLEMENTED {class_name}:{mpropdef} at {location.to_s}\\n\");") @@ -1716,7 +1782,7 @@ end redef class AExpr # Try to compile self as an expression - # Do not call this method directly, use `v.expr' instead + # Do not call this method directly, use `v.expr` instead private fun expr(v: AbstractCompilerVisitor): nullable RuntimeVariable do v.add("printf(\"NOT YET IMPLEMENTED {class_name}:{location.to_s}\\n\");") @@ -1731,7 +1797,7 @@ redef class AExpr end # Try to compile self as a statement - # Do not call this method directly, use `v.stmt' instead + # Do not call this method directly, use `v.stmt` instead private fun stmt(v: AbstractCompilerVisitor) do var res = expr(v) @@ -1744,6 +1810,15 @@ redef class ABlockExpr do for e in self.n_expr do v.stmt(e) end + redef fun expr(v) + do + var last = self.n_expr.last + for e in self.n_expr do + if e == last then break + v.stmt(e) + end + return v.expr(last, null) + end end redef class AVardeclExpr @@ -1774,6 +1849,13 @@ redef class AVarAssignExpr 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) + var i = v.expr(self.n_value, variable.declared_type) + v.assign(v.variable(variable), i) + return i + end end redef class AVarReassignExpr @@ -1827,6 +1909,18 @@ redef class AIfExpr v.stmt(self.n_else) v.add("\}") end + + redef fun expr(v) + do + var res = v.new_var(self.mtype.as(not null)) + var cond = v.expr_bool(self.n_expr) + v.add("if ({cond})\{") + v.assign(res, v.expr(self.n_then.as(not null), null)) + v.add("\} else \{") + v.assign(res, v.expr(self.n_else.as(not null), null)) + v.add("\}") + return res + end end redef class AIfexprExpr @@ -2029,15 +2123,15 @@ redef class AEeExpr end redef class AIntExpr - redef fun expr(v) do return v.new_expr("{self.n_number.text}", self.mtype.as(not null)) + redef fun expr(v) do return v.new_expr("{self.value.to_s}", self.mtype.as(not null)) end redef class AFloatExpr - redef fun expr(v) do return v.new_expr("{self.n_float.text}", self.mtype.as(not null)) + redef fun expr(v) do return v.new_expr("{self.n_float.text}", self.mtype.as(not null)) # FIXME use value, not n_float end redef class ACharExpr - redef fun expr(v) do return v.new_expr("{self.n_char.text}", self.mtype.as(not null)) + redef fun expr(v) do return v.new_expr("'{self.value.to_s.escape_to_c}'", self.mtype.as(not null)) end redef class AArrayExpr @@ -2308,20 +2402,8 @@ end # Utils -redef class HashSet[E] - init from(elements: Collection[E]) do - init - self.add_all(elements) - end -end - redef class Array[E] - init from(elements: Collection[E]) do - init - self.add_all(elements) - end - - # Return a new Array with the elements only contened in 'self' and not in 'o' + # Return a new `Array` with the elements only contened in self and not in `o` fun -(o: Array[E]): Array[E] do var res = new Array[E] for e in self do if not o.has(e) then res.add(e) @@ -2330,208 +2412,25 @@ redef class Array[E] end redef class MModule - - # Return a linearization of a set of mtypes - fun linearize_mtypes(mtypes: Set[MType]): Array[MType] do - var lin = new Array[MType].from(mtypes) - var sorter = new TypeSorter(self) - sorter.sort(lin) - return lin - end - - # Return a reverse linearization of a set of mtypes - fun reverse_linearize_mtypes(mtypes: Set[MType]): Array[MType] do - var lin = new Array[MType].from(mtypes) - var sorter = new ReverseTypeSorter(self) - sorter.sort(lin) - return lin - end - - # Return super types of a `mtype` in `self` - fun super_mtypes(mtype: MType, mtypes: Set[MType]): Set[MType] do - if not self.super_mtypes_cache.has_key(mtype) then - var supers = new HashSet[MType] - for otype in mtypes do - if otype == mtype then continue - if mtype.is_subtype(self, null, otype) then - supers.add(otype) - end - end - self.super_mtypes_cache[mtype] = supers - end - return self.super_mtypes_cache[mtype] - end - - private var super_mtypes_cache: Map[MType, Set[MType]] = new HashMap[MType, Set[MType]] - - # Return all sub mtypes (directs and indirects) of a `mtype` in `self` - fun sub_mtypes(mtype: MType, mtypes: Set[MType]): Set[MType] do - if not self.sub_mtypes_cache.has_key(mtype) then - var subs = new HashSet[MType] - for otype in mtypes do - if otype == mtype then continue - if otype.is_subtype(self, null, mtype) then - subs.add(otype) - end - end - self.sub_mtypes_cache[mtype] = subs - end - return self.sub_mtypes_cache[mtype] - end - - private var sub_mtypes_cache: Map[MType, Set[MType]] = new HashMap[MType, Set[MType]] - - # Return a linearization of a set of mclasses - fun linearize_mclasses_2(mclasses: Set[MClass]): Array[MClass] do - var lin = new Array[MClass].from(mclasses) - var sorter = new ClassSorter(self) - sorter.sort(lin) - return lin - end - - # Return a reverse linearization of a set of mtypes - fun reverse_linearize_mclasses(mclasses: Set[MClass]): Array[MClass] do - var lin = new Array[MClass].from(mclasses) - var sorter = new ReverseClassSorter(self) - sorter.sort(lin) - return lin - end - - # Return all super mclasses (directs and indirects) of a `mclass` in `self` - fun super_mclasses(mclass: MClass): Set[MClass] do - if not self.super_mclasses_cache.has_key(mclass) then - var supers = new HashSet[MClass] - if self.flatten_mclass_hierarchy.has(mclass) then - for sup in self.flatten_mclass_hierarchy[mclass].greaters do - if sup == mclass then continue - supers.add(sup) - end - end - self.super_mclasses_cache[mclass] = supers - end - return self.super_mclasses_cache[mclass] - end - - private var super_mclasses_cache: Map[MClass, Set[MClass]] = new HashMap[MClass, Set[MClass]] - - # Return all parents of a `mclass` in `self` - fun parent_mclasses(mclass: MClass): Set[MClass] do - if not self.parent_mclasses_cache.has_key(mclass) then - var parents = new HashSet[MClass] - if self.flatten_mclass_hierarchy.has(mclass) then - for sup in self.flatten_mclass_hierarchy[mclass].direct_greaters do - if sup == mclass then continue - parents.add(sup) - end - end - self.parent_mclasses_cache[mclass] = parents - end - return self.parent_mclasses_cache[mclass] - end - - private var parent_mclasses_cache: Map[MClass, Set[MClass]] = new HashMap[MClass, Set[MClass]] - - # Return all sub mclasses (directs and indirects) of a `mclass` in `self` - fun sub_mclasses(mclass: MClass): Set[MClass] do - if not self.sub_mclasses_cache.has_key(mclass) then - var subs = new HashSet[MClass] - if self.flatten_mclass_hierarchy.has(mclass) then - for sub in self.flatten_mclass_hierarchy[mclass].smallers do - if sub == mclass then continue - subs.add(sub) - end - end - self.sub_mclasses_cache[mclass] = subs - end - return self.sub_mclasses_cache[mclass] - end - - private var sub_mclasses_cache: Map[MClass, Set[MClass]] = new HashMap[MClass, Set[MClass]] - - # All 'mproperties' associated to all 'mclassdefs' of `mclass` + # All `MProperty` associated to all `MClassDef` of `mclass` fun properties(mclass: MClass): Set[MProperty] do if not self.properties_cache.has_key(mclass) then var properties = new HashSet[MProperty] - var parents = self.super_mclasses(mclass) + var parents = new Array[MClass] + if self.flatten_mclass_hierarchy.has(mclass) then + parents.add_all(mclass.in_hierarchy(self).direct_greaters) + end for parent in parents do properties.add_all(self.properties(parent)) end - for mclassdef in mclass.mclassdefs do - for mpropdef in mclassdef.mpropdefs do - properties.add(mpropdef.mproperty) + for mprop in mclassdef.intro_mproperties do + properties.add(mprop) end end self.properties_cache[mclass] = properties end return properties_cache[mclass] end - private var properties_cache: Map[MClass, Set[MProperty]] = new HashMap[MClass, Set[MProperty]] end - -# A sorter for linearize list of types -private class TypeSorter - super AbstractSorter[MType] - - private var mmodule: MModule - - init(mmodule: MModule) do self.mmodule = mmodule - - redef fun compare(a, b) do - if a == b then - return 0 - else if a.is_subtype(self.mmodule, null, b) then - return -1 - end - return 1 - end -end - -# A sorter for reverse linearization -private class ReverseTypeSorter - super TypeSorter - - init(mmodule: MModule) do end - - redef fun compare(a, b) do - if a == b then - return 0 - else if a.is_subtype(self.mmodule, null, b) then - return 1 - end - return -1 - end -end - -# A sorter for linearize list of classes -private class ClassSorter - super AbstractSorter[MClass] - - var mmodule: MModule - - redef fun compare(a, b) do - if a == b then - return 0 - else if self.mmodule.flatten_mclass_hierarchy.has(a) and self.mmodule.flatten_mclass_hierarchy[a].greaters.has(b) then - return -1 - end - return 1 - end -end - -# A sorter for reverse linearization -private class ReverseClassSorter - super AbstractSorter[MClass] - - var mmodule: MModule - - redef fun compare(a, b) do - if a == b then - return 0 - else if self.mmodule.flatten_mclass_hierarchy.has(a) and self.mmodule.flatten_mclass_hierarchy[a].greaters.has(b) then - return 1 - end - return -1 - end -end