src/model: remove extra } from `MGenericType::to_s`
[nit.git] / src / model / model.nit
index f84b38f..b483543 100644 (file)
@@ -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,7 +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_namespace_for(visibility)}__{name.to_cmangle}"
+       end
 
        # The number of generic formal parameters
        # 0 if the class is not generic
@@ -371,6 +369,7 @@ class MClass
        # is empty if the class is not generic
        var mparameters = new Array[MParameterType]
 
+       # Initialize `mparameters` from their names.
        protected fun setup_parameter_names(parameter_names: nullable Array[String]) is
                autoinit
        do
@@ -527,6 +526,41 @@ class MClassDef
        # Actually the name of the `mclass`
        redef fun name do return mclass.name
 
+       # The module and class name separated by a '#'.
+       #
+       # The short-name of the class is used for introduction.
+       # Example: "my_module#MyClass"
+       #
+       # The full-name of the class is used for refinement.
+       # 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
+                       # 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 "{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}"
+               end
+       end
+
        redef fun model do return mmodule.model
 
        # All declared super-types
@@ -1034,6 +1068,10 @@ class MClassType
 
        redef fun to_s do return mclass.to_s
 
+       redef fun full_name do return mclass.full_name
+
+       redef fun c_name do return mclass.c_name
+
        redef fun need_anchor do return false
 
        redef fun anchor_to(mmodule: MModule, anchor: MClassType): MClassType
@@ -1142,10 +1180,30 @@ class MGenericType
                self.to_s = "{mclass}[{arguments.join(", ")}]"
        end
 
-       # Recursively print the type of the arguments within brackets.
+       # The short-name of the class, then the full-name of each type arguments within brackets.
        # Example: `"Map[String, List[Int]]"`
        redef var to_s: String is noinit
 
+       # The full-name of the class, then the full-name of each type arguments within brackets.
+       # Example: `"standard::Map[standard::String, standard::List[standard::Int]]"`
+       redef var full_name is lazy do
+               var args = new Array[String]
+               for t in arguments do
+                       args.add t.full_name
+               end
+               return "{mclass.full_name}[{args.join(", ")}]"
+       end
+
+       redef var c_name is lazy do
+               var res = mclass.c_name
+               # Note: because the arity is known, a prefix notation is enough
+               for t in arguments do
+                       res += "__"
+                       res += t.c_name
+               end
+               return res.to_s
+       end
+
        redef var need_anchor: Bool is noinit
 
        redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual)
@@ -1286,6 +1344,10 @@ class MVirtualType
        end
 
        redef fun to_s do return self.mproperty.to_s
+
+       redef fun full_name do return self.mproperty.full_name
+
+       redef fun c_name do return self.mproperty.c_name
 end
 
 # The type associated to a formal parameter generic type of a class
@@ -1330,6 +1392,10 @@ class MParameterType
 
        redef fun to_s do return name
 
+       redef var full_name is lazy do return "{mclass.full_name}::{name}"
+
+       redef var c_name is lazy do return mclass.c_name + "__" + "#{name}".to_cmangle
+
        redef fun lookup_bound(mmodule: MModule, resolved_receiver: MType): MType
        do
                assert not resolved_receiver.need_anchor
@@ -1449,6 +1515,10 @@ class MNullableType
 
        redef var to_s: String is noinit
 
+       redef var full_name is lazy do return "nullable {mtype.full_name}"
+
+       redef var c_name is lazy do return "nullable__{mtype.c_name}"
+
        redef fun need_anchor do return mtype.need_anchor
        redef fun as_nullable do return self
        redef fun as_notnullable do return mtype
@@ -1501,6 +1571,8 @@ class MNullType
        super MType
        redef var model: Model
        redef fun to_s do return "null"
+       redef fun full_name do return "null"
+       redef fun c_name do return "null"
        redef fun as_nullable do return self
        redef fun need_anchor do return false
        redef fun resolve_for(mtype, anchor, mmodule, cleanup_virtual) do return self
@@ -1630,6 +1702,8 @@ class MParameter
                end
        end
 
+       # Returns a new parameter with the `mtype` resolved.
+       # See `MType::resolve_for` for details.
        fun resolve_for(mtype: MType, anchor: nullable MClassType, mmodule: MModule, cleanup_virtual: Bool): MParameter
        do
                if not self.mtype.need_anchor then return self
@@ -1672,12 +1746,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
+               # 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)
@@ -1708,6 +1790,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
@@ -1746,7 +1831,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
@@ -1814,24 +1900,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]
@@ -1943,6 +2033,75 @@ abstract class MPropDef
        # Actually the name of the `mproperty`
        redef fun name do return mproperty.name
 
+       # The full-name of mpropdefs combine the information about the `classdef` and the `mproperty`.
+       #
+       # Therefore the combination of identifiers is awful,
+       # the worst case being
+       #
+       #  * 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.
+       # For the previous case, the simplest form is "p#A#x".
+       redef var full_name is lazy do
+               var res = new FlatBuffer
+
+               # The first part is the mclassdef. Worst case is "r::o#q::n::B"
+               res.append mclassdef.full_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
+               return res.to_s
+       end
+
+       redef var c_name is lazy do
+               var res = new FlatBuffer
+               res.append mclassdef.c_name
+               res.append "___"
+               if mclassdef.mclass == mproperty.intro_mclassdef.mclass then
+                       res.append name.to_cmangle
+               else
+                       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
+
        redef fun model do return mclassdef.model
 
        # Internal name combining the module, the class and the property