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
22 private import more_collections
24 # The container class of a Nit object-oriented model.
25 # A model knows modules, classes and properties and can retrieve them.
28 var mmodules
= new Array[MModule]
30 # Full module importation hierarchy including private or nested links.
31 var mmodule_importation_hierarchy
= new POSet[MModule]
33 # Collections of modules grouped by their short names
34 private var mmodules_by_name
= new MultiHashMap[String, MModule]
36 # Return all module named `name`
37 # If such a module does not exist, null is returned (instead of an empty array)
39 # Visibility or modules are not considered
40 fun get_mmodules_by_name
(name
: String): nullable Array[MModule]
42 if mmodules_by_name
.has_key
(name
) then
43 return mmodules_by_name
[name
]
51 # The loaded modules of this group
52 var mmodules
= new Array[MModule]
54 # The default module of a group (if any, and if loaded)
56 # The default module of a group is the one that has the same name.
57 # Return `null` if the group has no default module or if the default
58 # module is not loaded.
59 var default_mmodule
: nullable MModule = null
61 redef fun mdoc_or_fallback
63 if mdoc
!= null then return mdoc
64 if default_mmodule
== null then return null
65 return default_mmodule
.mdoc_or_fallback
69 # A Nit module is usually associated with a Nit source file.
73 # The model considered
74 redef var model
: Model
76 # The group of module in the project if any
77 var mgroup
: nullable MGroup
79 # The project of the module if any
80 # Safe alias for `mgroup.mproject`
81 fun mproject
: nullable MProject
84 if g
== null then return null else return g
.mproject
87 # The short name of the module
88 redef var name
: String
90 # The origin of the definition
91 var location
: Location
94 redef fun to_s
do return self.name
96 # The view of the module in the `model.mmodule_importation_hierarchy`
97 var in_importation
: POSetElement[MModule] is noinit
99 # The canonical name of the module.
101 # It is usually the `name` prefixed by the project's name.
102 # Example: `"project::name"`
104 # If both names are the same (of if the module is project-less), then
105 # the short-name is used alone.
106 redef var full_name
is lazy
do
107 var mgroup
= self.mgroup
108 if mgroup
== null or mgroup
.mproject
.name
== self.name
then
111 return "{mgroup.mproject.name}::{self.name}"
115 # The namespace used for entities according to their visibility `v`.
117 # Public entities use only the project as a namespace.
118 # Private entities use the `full_name` (i.e. "project::module")
120 # This method is used by entities to implement their `full_name`.
121 fun namespace_for
(v
: MVisibility): String do
122 if v
<= private_visibility
then return full_name
123 var mgroup
= self.mgroup
124 if mgroup
== null then
127 return mgroup
.mproject
.full_name
131 # Return the name of the global C identifier associated to `self`.
132 # This name is used to prefix files and other C identifiers associated with `self`.
133 redef var c_name
: String is lazy
do
136 if g
!= null and g
.mproject
.name
!= name
then
137 res
= g
.mproject
.name
.to_cmangle
+ "__" + name
.to_cmangle
139 res
= name
.to_cmangle
144 # C identifier version of `namespace_for`.
147 # This method is used by entities to implement their `c_name`.
148 fun c_namespace_for
(v
: MVisibility): String do
149 if v
<= private_visibility
then return c_name
150 var mgroup
= self.mgroup
151 if mgroup
== null then
154 return mgroup
.mproject
.c_name
158 # Create a new empty module and register it to a model
161 model
.mmodules_by_name
.add_one
(name
, self)
162 model
.mmodules
.add
(self)
163 if mgroup
!= null then
164 mgroup
.mmodules
.add
(self)
165 if mgroup
.name
== name
then
166 assert mgroup
.default_mmodule
== null
167 mgroup
.default_mmodule
= self
170 self.in_importation
= model
.mmodule_importation_hierarchy
.add_node
(self)
173 # Register the imported modules (ie "import some_module")
174 # This function can only invoked once by mmodule.
175 # The visibility must be set with `set_visibility_for`.
176 fun set_imported_mmodules
(imported_mmodules
: Array[MModule])
178 assert unique_invocation
: self.in_importation
.direct_greaters
.is_empty
179 for m
in imported_mmodules
do
180 self.model
.mmodule_importation_hierarchy
.add_edge
(self, m
)
184 private var intrude_mmodules
= new HashSet[MModule]
185 private var public_mmodules
= new HashSet[MModule]
186 private var private_mmodules
= new HashSet[MModule]
188 # Return the visibility level of an imported module `m`
189 fun visibility_for
(m
: MModule): MVisibility
191 if m
== self then return intrude_visibility
192 if self.intrude_mmodules
.has
(m
) then return intrude_visibility
193 if self.public_mmodules
.has
(m
) then return public_visibility
194 if self.private_mmodules
.has
(m
) then return private_visibility
195 return none_visibility
198 # Set the visibility of an imported module
199 # REQUIRE: the visibility of the modules imported by `m` are already set for `m`
200 fun set_visibility_for
(m
: MModule, v
: MVisibility)
202 if v
== intrude_visibility
then
203 self.intrude_mmodules
.add
(m
)
204 self.intrude_mmodules
.add_all
(m
.intrude_mmodules
)
205 self.public_mmodules
.add_all
(m
.public_mmodules
)
206 self.private_mmodules
.add_all
(m
.private_mmodules
)
207 else if v
== public_visibility
then
208 self.public_mmodules
.add
(m
)
209 self.public_mmodules
.add_all
(m
.intrude_mmodules
)
210 self.public_mmodules
.add_all
(m
.public_mmodules
)
211 else if v
== private_visibility
then
212 self.private_mmodules
.add
(m
)
213 self.private_mmodules
.add_all
(m
.intrude_mmodules
)
214 self.private_mmodules
.add_all
(m
.public_mmodules
)
216 print
"{self} visibility for {m} = {v}"
217 abort # invalid visibility
221 # Return true if a class or a property introduced in `intro_mmodule` with a visibility of `visibility` is visible in self.
222 fun is_visible
(intro_mmodule
: MModule, visibility
: MVisibility): Bool
224 var v
= visibility_for
(intro_mmodule
)
225 if v
== intrude_visibility
then
226 return visibility
>= private_visibility
227 else if v
== public_visibility
then
228 return visibility
> private_visibility
229 else if v
== private_visibility
then
230 return visibility
> private_visibility
231 else if v
== none_visibility
then
238 # Is `self` created for internal purpose?
239 # Fictive modules are instantiated internally but they should not be
240 # exposed to the final user.
241 var is_fictive
: Bool = false is writable
243 # Is `self` a unit test module used by `nitunit`?
244 var is_test_suite
: Bool = false is writable
246 # Get the first non `is_fictive` module greater than self
247 fun first_real_mmodule
: MModule
250 while mmodule
.is_fictive
do
251 mmodule
= mmodule
.in_importation
.direct_greaters
.first
256 redef fun parent_concern
do return mgroup