1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Copyright 2012 Jean Privat <jean@pryen.org>
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
17 # modules and module hierarchies in the metamodel
23 private import more_collections
25 # The container class of a Nit object-oriented model.
26 # A model knows modules, classes and properties and can retrieve them.
29 var mmodules
: Array[MModule] = new Array[MModule]
31 # placebo for old module nesting hierarchy.
32 # where mainmodule < mainmodule::nestedmodule
34 # TODO REMOVE, rely on mgroup instead
35 var mmodule_nesting_hierarchy
: POSet[MModule] = new POSet[MModule]
37 # Full module importation hierarchy including private or nested links.
38 var mmodule_importation_hierarchy
: POSet[MModule] = new POSet[MModule]
40 # Collections of modules grouped by their short names
41 private var mmodules_by_name
: MultiHashMap[String, MModule] = new MultiHashMap[String, MModule]
43 # Return all module named `name`
44 # If such a module does not exist, null is returned (instead of an empty array)
46 # Visibility or modules are not considered
47 fun get_mmodules_by_name
(name
: String): nullable Array[MModule]
49 if mmodules_by_name
.has_key
(name
) then
50 return mmodules_by_name
[name
]
58 # The loaded modules of this group
59 var mmodules
= new Array[MModule]
61 # Placebo stuff to find the owner (module with same name)
62 # null is returned if there is no owner, or if it is not loaded yet
63 fun fuzzy_owner
: nullable MModule
65 for m
in mmodules
do if m
.name
== name
then return m
70 # A Nit module is usually associated with a Nit source file.
74 # The model considered
77 # placebo for old module nesting hierarchy
78 # return null if self is not nested (ie. is a top-level module)
80 # TODO REMOVE, rely on mgroup instead
81 var direct_owner
: nullable MModule
83 # The group of module in the project if any
84 var mgroup
: nullable MGroup
86 # The short name of the module
87 redef var name
: String
89 # The origin of the definition
90 var location
: Location
93 redef fun to_s
do return self.name
95 # placebo for old module nesting hierarchy
96 # The view of the module in the `model.mmodule_nesting_hierarchy`
98 # TODO REMOVE, rely on mgroup instead
99 var in_nesting
: POSetElement[MModule]
101 # The view of the module in the `model.mmodule_importation_hierarchy`
102 var in_importation
: POSetElement[MModule]
104 # The canonical name of the module
105 # Example: `"project::name"`
106 fun full_name
: String
108 var mgroup
= self.mgroup
109 if mgroup
== null or mgroup
.mproject
.name
== self.name
then
112 return "{mgroup.mproject.name}::{self.name}"
116 # Create a new empty module and register it to a model
117 init(model
: Model, mgroup
: nullable MGroup, name
: String, location
: Location)
121 self.location
= location
122 model
.mmodules_by_name
.add_one
(name
, self)
123 model
.mmodules
.add
(self)
124 self.in_nesting
= model
.mmodule_nesting_hierarchy
.add_node
(self)
126 if mgroup
!= null then
127 mgroup
.mmodules
.add
(self)
128 # placebo for old module nesting hierarchy
129 var direct_owner
= mgroup
.fuzzy_owner
130 if direct_owner
== self then
131 # The module is the new owner of its own group, thus adopt the other modules
132 for m
in mgroup
.mmodules
do
133 if m
== self then continue
134 m
.direct_owner
= self
135 model
.mmodule_nesting_hierarchy
.add_edge
(self, m
)
137 # The potential owner is the the fuzzy_owner of the parent group
138 if mgroup
.parent
!= null then direct_owner
= mgroup
.parent
.fuzzy_owner
140 if direct_owner
!= self and direct_owner
!= null then
141 self.direct_owner
= direct_owner
142 model
.mmodule_nesting_hierarchy
.add_edge
(direct_owner
, self)
145 self.in_importation
= model
.mmodule_importation_hierarchy
.add_node
(self)
148 # Register the imported modules (ie "import some_module")
149 # This function can only invoked once by mmodule.
150 # The visibility must be set with `set_visibility_for`.
151 fun set_imported_mmodules
(imported_mmodules
: Array[MModule])
153 assert unique_invocation
: self.in_importation
.direct_greaters
.is_empty
154 for m
in imported_mmodules
do
155 self.model
.mmodule_importation_hierarchy
.add_edge
(self, m
)
159 private var intrude_mmodules
: HashSet[MModule] = new HashSet[MModule]
160 private var public_mmodules
: HashSet[MModule] = new HashSet[MModule]
161 private var private_mmodules
: HashSet[MModule] = new HashSet[MModule]
163 # Return the visibility level of an imported module `m`
164 fun visibility_for
(m
: MModule): MVisibility
166 if m
== self then return intrude_visibility
167 if self.intrude_mmodules
.has
(m
) then return intrude_visibility
168 if self.public_mmodules
.has
(m
) then return public_visibility
169 if self.private_mmodules
.has
(m
) then return private_visibility
170 return none_visibility
173 # Set the visibility of an imported module
174 # REQUIRE: the visibility of the modules imported by `m` are already set for `m`
175 fun set_visibility_for
(m
: MModule, v
: MVisibility)
177 if v
== intrude_visibility
then
178 self.intrude_mmodules
.add
(m
)
179 self.intrude_mmodules
.add_all
(m
.intrude_mmodules
)
180 self.public_mmodules
.add_all
(m
.public_mmodules
)
181 self.private_mmodules
.add_all
(m
.private_mmodules
)
182 else if v
== public_visibility
then
183 self.public_mmodules
.add
(m
)
184 self.public_mmodules
.add_all
(m
.intrude_mmodules
)
185 self.public_mmodules
.add_all
(m
.public_mmodules
)
186 else if v
== private_visibility
then
187 self.private_mmodules
.add
(m
)
188 self.private_mmodules
.add_all
(m
.intrude_mmodules
)
189 self.private_mmodules
.add_all
(m
.public_mmodules
)
191 print
"{self} visibility for {m} = {v}"
192 abort # invalid visibility
196 # placebo for old module nesting hierarchy
197 fun public_owner
: nullable MModule
199 var mgroup
= self.mgroup
200 if mgroup
== null then return null
201 mgroup
= mgroup
.mproject
.root
202 if mgroup
.mmodules
.is_empty
then return null
203 var res
= mgroup
.fuzzy_owner
204 if res
== self then return null
208 # Return true if a class or a property introduced in `intro_mmodule` with a visibility of `visibility` is visible in self.
209 fun is_visible
(intro_mmodule
: MModule, visibility
: MVisibility): Bool
211 var v
= visibility_for
(intro_mmodule
)
212 if v
== intrude_visibility
then
213 return visibility
>= private_visibility
214 else if v
== public_visibility
then
215 return visibility
> private_visibility
216 else if v
== private_visibility
then
217 return visibility
> private_visibility
218 else if v
== none_visibility
then
225 redef fun parent_concern
do return mgroup