nitc :: MClassDef :: defaultinit
# A definition (an introduction or a refinement) of a class in a module
#
# A `MClassDef` is associated with an explicit (or almost) definition of a
# class. Unlike `MClass`, a `MClassDef` is a local definition that belong to
# a specific class and a specific module, and contains declarations like super-classes
# or properties.
#
# It is the class definitions that are the backbone of most things in the model:
# ClassDefs are defined with regard with other classdefs.
# Refinement and specialization are combined to produce a big poset called the `Model::mclassdef_hierarchy`.
#
# Moreover, the extension and the intention of types is defined by looking at the MClassDefs.
class MClassDef
super MEntity
# The module where the definition is
var mmodule: MModule
# The associated `MClass`
var mclass: MClass is noinit
# The bounded type associated to the mclassdef
#
# For a non-generic class, `bound_mtype` and `mclass.mclass_type`
# are the same type.
#
# Example:
# For the classdef Array[E: Object], the bound_mtype is Array[Object].
# If you want Array[E], then see `mclass.mclass_type`
#
# ENSURE: `bound_mtype.mclass == self.mclass`
var bound_mtype: MClassType
redef var location
redef fun visibility do return mclass.visibility
# Internal name combining the module and the class
# Example: "mymodule$MyClass"
redef var to_s is noinit
init
do
self.mclass = bound_mtype.mclass
mmodule.add_mclassdef(self)
mclass.mclassdefs.add(self)
if mclass.intro_mmodule == mmodule then
assert not isset mclass._intro
mclass.intro = self
end
self.to_s = "{mmodule}${mclass}"
end
# 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.mpackage != mmodule.mpackage 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.mpackage == mmodule.mpackage 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
# FIXME: quite ugly but not better idea yet
var supertypes = new Array[MClassType]
# Register some super-types for the class (ie "super SomeType")
#
# The hierarchy must not already be set
# REQUIRE: `self.in_hierarchy == null`
fun set_supertypes(supertypes: Array[MClassType])
do
assert unique_invocation: self.in_hierarchy == null
var mmodule = self.mmodule
var model = mmodule.model
var mtype = self.bound_mtype
for supertype in supertypes do
self.supertypes.add(supertype)
# Register in full_type_specialization_hierarchy
model.full_mtype_specialization_hierarchy.add_edge(mtype, supertype)
# Register in intro_type_specialization_hierarchy
if mclass.intro_mmodule == mmodule and supertype.mclass.intro_mmodule == mmodule then
model.intro_mtype_specialization_hierarchy.add_edge(mtype, supertype)
end
end
end
# Collect the super-types (set by set_supertypes) to build the hierarchy
#
# This function can only invoked once by class
# REQUIRE: `self.in_hierarchy == null`
# ENSURE: `self.in_hierarchy != null`
fun add_in_hierarchy
do
assert unique_invocation: self.in_hierarchy == null
var model = mmodule.model
var res = model.mclassdef_hierarchy.add_node(self)
self.in_hierarchy = res
var mtype = self.bound_mtype
# Here we need to connect the mclassdef to its pairs in the mclassdef_hierarchy
# The simpliest way is to attach it to collect_mclassdefs
for mclassdef in mtype.collect_mclassdefs(mmodule) do
res.poset.add_edge(self, mclassdef)
end
end
# The view of the class definition in `mclassdef_hierarchy`
var in_hierarchy: nullable POSetElement[MClassDef] = null
# Is the definition the one that introduced `mclass`?
fun is_intro: Bool do return isset mclass._intro and mclass.intro == self
# All properties introduced by the classdef
var intro_mproperties = new Array[MProperty]
# All property introductions and redefinitions in `self` (not inheritance).
var mpropdefs = new Array[MPropDef]
# The special default_init constructor
var default_init: nullable MMethodDef = null is writable
# All property introductions and redefinitions (not inheritance) in `self` by its associated property.
var mpropdefs_by_property = new HashMap[MProperty, MPropDef]
# Return the direct parent mtype of `self`
# Exemple
# ~~~nitish
# module 1
#
# class A
# class B
# super A
#
# module 2
#
# redef class A
# class C
# super B
#
# mclassdef_C.get_direct_supermtype == [B]
# ~~~~
fun get_direct_supermtype: Collection[MClassType]
do
# Get the potentiel direct parents
var parents = in_hierarchy.direct_greaters
# Stock the potentiel direct parents
var res = supertypes
for parent in parents do
# remove all super parents of the potentiel direct parents
res.remove_all(parent.supertypes)
# if the length of the potentiel direct parent equal 1 break
if res.length == 1 then break
end
return res
end
redef fun mdoc_or_fallback do return mdoc or else mclass.mdoc_or_fallback
end
src/model/model.nit:628,1--820,3