# Model exploration and traversing facilities
module model_utils
-import toolcontext
-import exprbuilder
+import model
+
+redef class MConcern
+
+ # Boost a MConcern rank
+ # see: `MConcernRankSorter`
+ # Use a positive booster to push down a result in the list
+ # A negative booster can be used to push up the result
+ var booster_rank: Int = 0 is writable
+
+ # Concern ranking used for ordering
+ # see: `MConcernRankSorter`
+ # Rank can be positive or negative
+ fun concern_rank: Int is abstract
+end
+
+redef class MProject
+ redef var concern_rank is lazy do
+ var max = 0
+ for mgroup in mgroups do
+ var mmax = mgroup.concern_rank
+ if mmax > max then max = mmax
+ end
+ return max + 1
+ end
+end
+
+redef class MGroup
+ fun in_nesting_intro_mclasses(min_visibility: MVisibility): Set[MClass] do
+ var res = new HashSet[MClass]
+ var lst = in_nesting.direct_smallers
+ for mmodule in mmodules do res.add_all mmodule.filter_intro_mclasses(min_visibility)
+ for mgrp in lst do res.add_all mgrp.in_nesting_intro_mclasses(min_visibility)
+ return res
+ end
+
+ fun in_nesting_redef_mclasses(min_visibility: MVisibility): Set[MClass] do
+ var res = new HashSet[MClass]
+ var lst = in_nesting.direct_smallers
+ for mmodule in mmodules do res.add_all mmodule.filter_redef_mclasses(min_visibility)
+ for mgrp in lst do res.add_all mgrp.in_nesting_redef_mclasses(min_visibility)
+ return res
+ end
+
+ fun in_nesting_intro_mclassdefs(min_visibility: MVisibility): Set[MClassDef] do
+ var res = new HashSet[MClassDef]
+ var lst = in_nesting.direct_smallers
+ for mmodule in mmodules do res.add_all mmodule.intro_mclassdefs(min_visibility)
+ for mgrp in lst do res.add_all mgrp.in_nesting_intro_mclassdefs(min_visibility)
+ return res
+ end
+
+ fun in_nesting_redef_mclassdefs(min_visibility: MVisibility): Set[MClassDef] do
+ var res = new HashSet[MClassDef]
+ var lst = in_nesting.direct_smallers
+ for mmodule in mmodules do res.add_all mmodule.redef_mclassdefs(min_visibility)
+ for mgrp in lst do res.add_all mgrp.in_nesting_redef_mclassdefs(min_visibility)
+ return res
+ end
+
+ # Collect nested modules
+ fun collect_mmodules: Set[MModule] do
+ var res = new HashSet[MModule]
+ res.add_all mmodules
+ for mgroup in in_nesting.direct_smallers do
+ res.add_all mgroup.collect_mmodules
+ end
+ return res
+ end
+
+ redef var concern_rank is lazy do
+ var max = 0
+ for mmodule in collect_mmodules do
+ var mmax = mmodule.concern_rank
+ if mmax > max then max = mmax
+ end
+ return max + 1
+ end
+end
redef class MModule
+
+ # The list of intro mclassdef in the module.
+ # with visibility >= to min_visibility
+ fun intro_mclassdefs(min_visibility: MVisibility): Set[MClassDef] do
+ var res = new HashSet[MClassDef]
+ for mclassdef in mclassdefs do
+ if not mclassdef.is_intro then continue
+ if mclassdef.mclass.visibility < min_visibility then continue
+ res.add mclassdef
+ end
+ return res
+ end
+
+ # The list of redef mclassdef in the module.
+ # with visibility >= to min_visibility
+ fun redef_mclassdefs(min_visibility: MVisibility): Set[MClassDef] do
+ var res = new HashSet[MClassDef]
+ for mclassdef in mclassdefs do
+ if mclassdef.is_intro then continue
+ if mclassdef.mclass.visibility < min_visibility then continue
+ res.add mclassdef
+ end
+ return res
+ end
+
+ # The list of intro mclass in the module.
+ # with visibility >= to min_visibility
+ fun filter_intro_mclasses(min_visibility: MVisibility): Set[MClass] do
+ var res = new HashSet[MClass]
+ for mclass in intro_mclasses do
+ if mclass.visibility < min_visibility then continue
+ res.add mclass
+ end
+ return res
+ end
+
# Get the list of mclasses refined in 'self'.
fun redef_mclasses: Set[MClass] do
var mclasses = new HashSet[MClass]
return mclasses
end
+ # Get the list of mclasses refined in 'self'.
+ fun filter_redef_mclasses(min_visibility: MVisibility): Set[MClass] do
+ var mclasses = new HashSet[MClass]
+ for c in mclassdefs do
+ if c.mclass.visibility < min_visibility then continue
+ if not c.is_intro then mclasses.add(c.mclass)
+ end
+ return mclasses
+ end
+
# Get the list of all mclasses imported by 'self'.
fun imported_mclasses: Set[MClass] do
var mclasses = new HashSet[MClass]
return mclasses
end
- # Get all mclasses in 'self' with their state
- fun mclasses: HashMap[MClass, Int] do
- var mclasses = new HashMap[MClass, Int]
- for c in intro_mclasses do mclasses[c] = c_is_intro
- for r in redef_mclasses do mclasses[r] = c_is_refined
- for i in imported_mclasses do mclasses[i] = c_is_imported
- return mclasses
+ redef var concern_rank is lazy do
+ var max = 0
+ for p in in_importation.direct_greaters do
+ var pmax = p.concern_rank
+ if pmax > max then max = pmax
+ end
+ return max + 1
+ end
+
+ # Find all mmodules nested in `self` if `self` is the default module of a `MGroup`.
+ fun nested_mmodules: Array[MModule] do
+ var res = new Array[MModule]
+ var mgroup = mgroup
+ if mgroup == null or self != mgroup.default_mmodule then return res
+ for mmodule in mgroup.mmodules do
+ if mmodule == self then continue
+ res.add mmodule
+ end
+ for nested in mgroup.in_nesting.direct_smallers do
+ var default = nested.default_mmodule
+ if default == null then continue
+ res.add default
+ end
+ return res
end
end
return res
end
- # Get the set of properties introduced in 'self'.
- fun intro_mproperties: Set[MProperty] do
- var res = new HashSet[MProperty]
+ # the set of properties introduced in 'self'.
+ fun intro_mproperties(min_visibility: MVisibility): Set[MProperty] do
+ var set = new HashSet[MProperty]
+ for mclassdef in mclassdefs do
+ for mprop in mclassdef.intro_mproperties do
+ if mprop.visibility < min_visibility then continue
+ set.add(mprop)
+ end
+ end
+ return set
+ end
+
+ fun intro_mpropdefs(min_visibility: MVisibility): Set[MPropDef] do
+ var set = new HashSet[MPropDef]
for mclassdef in mclassdefs do
for mpropdef in mclassdef.mpropdefs do
- if mpropdef.is_intro then res.add(mpropdef.mproperty)
+ if not mpropdef.is_intro then continue
+ if mpropdef.mproperty.visibility < min_visibility then continue
+ set.add(mpropdef)
end
end
- return res
+ return set
end
- # Get the list of locally refined methods in 'self'.
- fun redef_methods: Set[MMethod] do
- var res = new HashSet[MMethod]
+ # the set of locally refined properties in 'self'.
+ fun redef_mproperties(min_visibility: MVisibility): Set[MProperty] do
+ var set = new HashSet[MProperty]
for mclassdef in mclassdefs do
for mpropdef in mclassdef.mpropdefs do
- if mpropdef isa MMethodDef then
- if not mpropdef.is_intro and not mpropdef.mproperty.is_init then res.add(mpropdef.mproperty)
- end
+ if mpropdef.mproperty.visibility < min_visibility then continue
+ if mpropdef.mproperty.intro_mclassdef.mclass != self then set.add(mpropdef.mproperty)
end
end
- return res
+ return set
end
- # Get the set of locally refined properties in 'self'.
- fun redef_mproperties: Set[MProperty] do
- var res = new HashSet[MProperty]
+ fun redef_mpropdefs(min_visibility: MVisibility): Set[MPropDef] do
+ var set = new HashSet[MPropDef]
for mclassdef in mclassdefs do
for mpropdef in mclassdef.mpropdefs do
- if not mpropdef.is_intro then res.add(mpropdef.mproperty)
+ if mpropdef.is_intro then continue
+ if mpropdef.mproperty.visibility < min_visibility then continue
+ set.add(mpropdef)
end
end
- return res
+ return set
end
- # Get the list of methods inherited by 'self'.
- fun inherited_methods: Set[MMethod] do
+ # the set of methods inherited by 'self'.
+ fun inherited_mproperties(mainmodule: MModule, min_visibility: MVisibility): Set[MProperty] do
+ var set = new HashSet[MProperty]
+ for parent in in_hierarchy(mainmodule).direct_greaters do
+ set.add_all(parent.intro_mproperties(min_visibility))
+ set.add_all(parent.inherited_mproperties(mainmodule, min_visibility))
+ end
+ return set
+ end
+
+ # the set of introduced and redefined mproperties
+ fun local_mproperties(min_visibility: MVisibility): Set[MProperty] do
+ var set = new HashSet[MProperty]
+ set.add_all(intro_mproperties(min_visibility))
+ set.add_all(redef_mproperties(min_visibility))
+ return set
+ end
+
+ # the set of all accessible mproperties for this class
+ fun all_mproperties(mainmodule: MModule, min_visibility: MVisibility): Set[MProperty] do
+ var set = new HashSet[MProperty]
+ set.add_all(local_mproperties(min_visibility))
+ set.add_all(inherited_mproperties(mainmodule, min_visibility))
+ return set
+ end
+
+ # the set of all accessible mattributes for this class
+ fun all_mattributes(mainmodule: MModule, min_visibility: MVisibility): Set[MAttribute] do
+ var set = new HashSet[MAttribute]
+ for mprop in all_mproperties(mainmodule, min_visibility) do
+ if mprop isa MAttribute then set.add(mprop)
+ end
+ return set
+ end
+
+ # Get the list of locally refined methods in 'self'.
+ fun redef_methods: Set[MMethod] do
var res = new HashSet[MMethod]
- for s in ancestors do
- for m in s.intro_methods do
- if not self.intro_methods.has(m) and not self.redef_methods.has(m) then res.add(m)
+ for mclassdef in mclassdefs do
+ for mpropdef in mclassdef.mpropdefs do
+ if mpropdef isa MMethodDef then
+ if not mpropdef.is_intro and not mpropdef.mproperty.is_init then res.add(mpropdef.mproperty)
+ end
end
end
return res
end
- # Get the set of all properties inherited by self
- fun inherited_mproperties: Set[MProperty] do
- var res = new HashSet[MProperty]
+ fun inherited_methods: Set[MMethod] do
+ var res = new HashSet[MMethod]
for s in ancestors do
- for m in s.intro_mproperties do
- if not self.intro_mproperties.has(m) and not self.redef_mproperties.has(m) then res.add(m)
+ for m in s.intro_methods do
+ if not self.intro_methods.has(m) and not self.redef_methods.has(m) then res.add(m)
end
end
return res
# Get the list of all parameter types in 'self'.
fun parameter_types: Map[String, MType] do
var res = new HashMap[String, MType]
- for i in [0..intro.parameter_names.length[ do
- res[intro.parameter_names[i]] = intro.bound_mtype.arguments[i]
+ for p in mparameters do
+ res[p.name] = p
end
return res
end
- fun mmodules: Set[MModule] do
- var mdls = new HashSet[MModule]
- for mclassdef in mclassdefs do mdls.add(mclassdef.mmodule)
- return mdls
- end
-
- # Get the list of MModule concern in 'self'
- fun concerns: HashMap[MModule, nullable List[MModule]] do
- var hm = new HashMap[MModule, nullable List[MModule]]
- for mmodule in mmodules do
- var owner = mmodule.public_owner
- if owner == null then
- hm[mmodule] = null
- else
- if hm.has_key(owner) then
- hm[owner].add(mmodule)
- else
- hm[owner] = new List[MModule]
- hm[owner].add(mmodule)
- end
- end
- end
- return hm
- end
-
fun is_class: Bool do
return self.kind == concrete_kind or self.kind == abstract_kind
end
end
end
-# MClass State
-fun c_is_intro: Int do return 1
-fun c_is_refined: Int do return 2
-fun c_is_imported: Int do return 3
+redef class MAttribute
+ # Is this attribute nullable for sure?
+ #
+ # This mean that its introduction is declarred with a nullable static type
+ # since attributes are invariant this will work on most cases
+ # attributes with static type anchored with a virtual type are not "nullable for-sure"
+ # because this type can be redefined in subclasses
+ fun is_nullable: Bool do return intro.static_mtype isa MNullableType
+end
+
+redef class MClassDef
+ # modifiers are keywords like redef, private etc.
+ fun modifiers: Array[String] do
+ var res = new Array[String]
+ if not is_intro then
+ res.add "redef"
+ else
+ res.add mclass.visibility.to_s
+ end
+ res.add mclass.kind.to_s
+ return res
+ end
+
+ fun collect_mpropdefs(min_visibility: MVisibility): Set[MPropDef] do
+ var res = new HashSet[MPropDef]
+ for mpropdef in mpropdefs do
+ if mpropdef.mproperty.visibility < min_visibility then continue
+ res.add mpropdef
+ end
+ return res
+ end
+
+ fun collect_intro_mpropdefs(min_visibility: MVisibility): Set[MPropDef] do
+ var res = new HashSet[MPropDef]
+ for mpropdef in mpropdefs do
+ if not mpropdef.is_intro then continue
+ if mpropdef.mproperty.visibility < min_visibility then continue
+ res.add mpropdef
+ end
+ return res
+ end
+
+ fun collect_redef_mpropdefs(min_visibility: MVisibility): Set[MPropDef] do
+ var res = new HashSet[MPropDef]
+ for mpropdef in mpropdefs do
+ if mpropdef.is_intro then continue
+ if mpropdef.mproperty.visibility < min_visibility then continue
+ res.add mpropdef
+ end
+ return res
+ end
+end
+
+redef class MPropDef
+ # modifiers are keywords like redef, private etc.
+ fun modifiers: Array[String] do
+ var res = new Array[String]
+ if not is_intro then
+ res.add "redef"
+ else
+ res.add mproperty.visibility.to_s
+ end
+ var mprop = self
+ if mprop isa MVirtualTypeDef then
+ res.add "type"
+ else if mprop isa MMethodDef then
+ if mprop.is_abstract then
+ res.add "abstract"
+ else if mprop.is_intern then
+ res.add "intern"
+ end
+ if mprop.mproperty.is_init then
+ res.add "init"
+ else
+ res.add "fun"
+ end
+ end
+ return res
+ end
+end
+
+# Sorters
+
+# Sort mentities by their name
+class MEntityNameSorter
+ super Comparator
+ redef type COMPARED: MEntity
+ redef fun compare(a, b) do return a.name <=> b.name
+end
+
+# Sort MConcerns based on the module importation hierarchy ranking
+# see also: `MConcern::concern_rank` and `MConcern::booster_rank`
+#
+# Comparison is made with the formula:
+#
+# ~~~nitish
+# a.concern_rank + a.booster_rank <=> b.concern_rank + b.booster_ran
+# ~~~
+#
+# If both `a` and `b` have the same ranking,
+# ordering is based on lexicographic comparison of `a.name` and `b.name`
+class MConcernRankSorter
+ super Comparator
+ redef type COMPARED: MConcern
+
+ redef fun compare(a, b) do
+ if a.concern_rank == b.concern_rank then
+ return a.name <=> b.name
+ end
+ return a.concern_rank + a.booster_rank <=> b.concern_rank + b.booster_rank
+ end
+end