X-Git-Url: http://nitlanguage.org diff --git a/src/model/model.nit b/src/model/model.nit index 4d8ddc4..b9b484a 100644 --- a/src/model/model.nit +++ b/src/model/model.nit @@ -74,11 +74,7 @@ redef class Model # Visibility or modules are not considered fun get_mclasses_by_name(name: String): nullable Array[MClass] do - if mclasses_by_name.has_key(name) then - return mclasses_by_name[name] - else - return null - end + return mclasses_by_name.get_or_null(name) end # Collections of properties grouped by their short name @@ -92,11 +88,7 @@ redef class Model # Visibility or modules are not considered fun get_mproperties_by_name(name: String): nullable Array[MProperty] do - if not mproperties_by_name.has_key(name) then - return null - else - return mproperties_by_name[name] - end + return mproperties_by_name.get_or_null(name) end # The only null type @@ -361,9 +353,13 @@ class MClass # # It is the name of the class prefixed by the full_name of the `intro_mmodule` # Example: `"owner::module::MyClass"` - redef var full_name is lazy do return "{self.intro_mmodule.full_name}::{name}" + redef var full_name is lazy do + return "{self.intro_mmodule.namespace_for(visibility)}::{name}" + end - redef var c_name is lazy do return "{intro_mmodule.c_name}__{name.to_cmangle}" + redef var c_name is lazy do + return "{intro_mmodule.c_namespace_for(visibility)}__{name.to_cmangle}" + end # The number of generic formal parameters # 0 if the class is not generic @@ -472,6 +468,9 @@ class MClass end private var get_mtype_cache = new HashMap[Array[MType], MGenericType] + + # Is there a `new` factory to allow the pseudo instantiation? + var has_new_factory = false is writable end @@ -539,17 +538,29 @@ class MClassDef # Example: "my_module#intro_module::MyClass" redef var full_name is lazy do if is_intro then + # public gives 'p#A' + # private gives 'p::m#A' + return "{mmodule.namespace_for(mclass.visibility)}#{mclass.name}" + else if mclass.intro_mmodule.mproject != mmodule.mproject then + # public gives 'q::n#p::A' + # private gives 'q::n#p::m::A' + return "{mmodule.full_name}#{mclass.full_name}" + else if mclass.visibility > private_visibility then + # public gives 'p::n#A' return "{mmodule.full_name}#{mclass.name}" else - return "{mmodule.full_name}#{mclass.full_name}" + # private gives 'p::n#::m::A' (redundant p is omitted) + return "{mmodule.full_name}#::{mclass.intro_mmodule.name}::{mclass.name}" end end redef var c_name is lazy do if is_intro then - return mclass.c_name + return "{mmodule.c_namespace_for(mclass.visibility)}___{mclass.c_name}" + else if mclass.intro_mmodule.mproject == mmodule.mproject and mclass.visibility > private_visibility then + return "{mmodule.c_name}___{mclass.name.to_cmangle}" else - return "{mmodule.c_name}__{mclass.c_name.to_cmangle}" + return "{mmodule.c_name}___{mclass.c_name}" end end @@ -1183,7 +1194,7 @@ class MGenericType for t in arguments do args.add t.full_name end - return "{mclass.full_name}[{args.join(", ")}]}" + return "{mclass.full_name}[{args.join(", ")}]" end redef var c_name is lazy do @@ -1738,16 +1749,20 @@ abstract class MProperty # It is the short-`name` prefixed by the short-name of the class and the full-name of the module. # Example: "my_project::my_module::MyClass::my_method" redef var full_name is lazy do - return "{intro_mclassdef.mmodule.full_name}::{intro_mclassdef.mclass.name}::{name}" + return "{intro_mclassdef.mmodule.namespace_for(visibility)}::{intro_mclassdef.mclass.name}::{name}" end redef var c_name is lazy do - return "{intro_mclassdef.mmodule.c_name}__{intro_mclassdef.mclass.c_name}__{name.to_cmangle}" + # FIXME use `namespace_for` + return "{intro_mclassdef.mmodule.c_name}__{intro_mclassdef.mclass.name.to_cmangle}__{name.to_cmangle}" end # The visibility of the property var visibility: MVisibility + # Is the property usable as an initializer? + var is_autoinit = false is writable + init do intro_mclassdef.intro_mproperties.add(self) @@ -1778,6 +1793,9 @@ abstract class MProperty # If mtype does not know mproperty then an empty array is returned. # # If you want the really most specific property, then look at `lookup_first_definition` + # + # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter) + # ENSURE: `not mtype.has_mproperty(mmodule, self) == result.is_empty` fun lookup_definitions(mmodule: MModule, mtype: MType): Array[MPROPDEF] do assert not mtype.need_anchor @@ -1816,7 +1834,8 @@ abstract class MProperty # # If you want the really most specific property, then look at `lookup_next_definition` # - # FIXME: Move to `MPropDef`? + # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter) + # ENSURE: `not mtype.has_mproperty(mmodule, self) implies result.is_empty` fun lookup_super_definitions(mmodule: MModule, mtype: MType): Array[MPROPDEF] do assert not mtype.need_anchor @@ -1884,24 +1903,28 @@ abstract class MProperty # # FIXME: the linearization is still unspecified # - # REQUIRE: `not mtype.need_anchor` + # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter) # REQUIRE: `mtype.has_mproperty(mmodule, self)` fun lookup_first_definition(mmodule: MModule, mtype: MType): MPROPDEF do - assert mtype.has_mproperty(mmodule, self) return lookup_all_definitions(mmodule, mtype).first end # Return all definitions in a linearization order # Most specific first, most general last + # + # REQUIRE: `not mtype.need_anchor` to simplify the API (no `anchor` parameter) + # REQUIRE: `mtype.has_mproperty(mmodule, self)` fun lookup_all_definitions(mmodule: MModule, mtype: MType): Array[MPROPDEF] do - assert not mtype.need_anchor mtype = mtype.as_notnullable var cache = self.lookup_all_definitions_cache[mmodule, mtype] if cache != null then return cache + assert not mtype.need_anchor + assert mtype.has_mproperty(mmodule, self) + #print "select prop {mproperty} for {mtype} in {self}" # First, select all candidates var candidates = new Array[MPROPDEF] @@ -2018,42 +2041,66 @@ abstract class MPropDef # Therefore the combination of identifiers is awful, # the worst case being # - # ~~~nitish - # "{mclassdef.mmodule.full_name}#{mclassdef.mclass.intro_mmodule.full_name}::{mclassdef.name}#{mproperty.intro_mclassdef.mmodule.full_name}::{mproperty.intro_mclassdef.name}::{name}" - # ~~~ + # * a property "p::m::A::x" + # * redefined in a refinement of a class "q::n::B" + # * in a module "r::o" + # * so "r::o#q::n::B#p::m::A::x" # # Fortunately, the full-name is simplified when entities are repeated. - # The simplest form is "my_module#MyClass#my_property". + # For the previous case, the simplest form is "p#A#x". redef var full_name is lazy do var res = new FlatBuffer - res.append mclassdef.mmodule.full_name - res.append "#" - if not mclassdef.is_intro then - res.append mclassdef.mclass.intro_mmodule.full_name - res.append "::" - end - res.append mclassdef.name + + # The first part is the mclassdef. Worst case is "r::o#q::n::B" + res.append mclassdef.full_name + res.append "#" - if mproperty.intro_mclassdef.mmodule != mclassdef.mmodule then - res.append mproperty.intro_mclassdef.mmodule.full_name - res.append "::" - end - if mclassdef.mclass != mproperty.intro_mclassdef.mclass then - res.append mproperty.intro_mclassdef.mclass.name - res.append "::" + + if mclassdef.mclass == mproperty.intro_mclassdef.mclass then + # intro are unambiguous in a class + res.append name + else + # Just try to simplify each part + if mclassdef.mmodule.mproject != mproperty.intro_mclassdef.mmodule.mproject then + # precise "p::m" only if "p" != "r" + res.append mproperty.intro_mclassdef.mmodule.full_name + res.append "::" + else if mproperty.visibility <= private_visibility then + # Same project ("p"=="q"), but private visibility, + # does the module part ("::m") need to be displayed + if mclassdef.mmodule.namespace_for(mclassdef.mclass.visibility) != mproperty.intro_mclassdef.mmodule.mproject then + res.append "::" + res.append mproperty.intro_mclassdef.mmodule.name + res.append "::" + end + end + if mclassdef.mclass != mproperty.intro_mclassdef.mclass then + # precise "B" only if not the same class than "A" + res.append mproperty.intro_mclassdef.name + res.append "::" + end + # Always use the property name "x" + res.append mproperty.name end - res.append name return res.to_s end redef var c_name is lazy do var res = new FlatBuffer res.append mclassdef.c_name - res.append "__" - if is_intro then + res.append "___" + if mclassdef.mclass == mproperty.intro_mclassdef.mclass then res.append name.to_cmangle else - res.append mproperty.c_name.to_cmangle + if mclassdef.mmodule != mproperty.intro_mclassdef.mmodule then + res.append mproperty.intro_mclassdef.mmodule.c_name + res.append "__" + end + if mclassdef.mclass != mproperty.intro_mclassdef.mclass then + res.append mproperty.intro_mclassdef.name.to_cmangle + res.append "__" + end + res.append mproperty.name.to_cmangle end return res.to_s end