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
21 private import more_collections
23 # The container class of a Nit object-oriented model.
25 # A model knows modules, classes and properties and can retrieve them.
27 # However, a model is not a program or a library as it can contains modules
28 # found by the system (including broken ones) but not used.
31 var mmodules
= new Array[MModule]
33 # Full module importation hierarchy including private or nested links.
34 var mmodule_importation_hierarchy
= new POSet[MModule]
36 # Collections of modules grouped by their short names
37 private var mmodules_by_name
= new MultiHashMap[String, MModule]
39 # Return all module named `name`
40 # If such a module does not exist, null is returned (instead of an empty array)
42 # Visibility or modules are not considered
43 fun get_mmodules_by_name
(name
: String): nullable Array[MModule]
45 if mmodules_by_name
.has_key
(name
) then
46 return mmodules_by_name
[name
]
54 # The loaded modules of this group
55 var mmodules
= new Array[MModule]
57 # The default module of a group (if any, and if loaded)
59 # The default module of a group is the one that has the same name.
60 # Return `null` if the group has no default module or if the default
61 # module is not loaded.
62 var default_mmodule
: nullable MModule = null
64 redef fun mdoc_or_fallback
66 if mdoc
!= null then return mdoc
67 var default_mmodule
= self.default_mmodule
68 if default_mmodule
== null then return null
69 return default_mmodule
.mdoc_or_fallback
73 # A Nit module is usually associated with a Nit source file.
77 # The model considered
80 # The group of module in the package if any
81 var mgroup
: nullable MGroup
83 # The path of the module source, if any
85 # safe alias to `location.file.filepath`
86 fun filepath
: nullable String do
87 var res
= self.location
.file
88 if res
== null then return null
92 # The package of the module if any
93 # Safe alias for `mgroup.mpackage`
94 fun mpackage
: nullable MPackage
97 if g
== null then return null else return g
.mpackage
100 # The short name of the module
103 redef var location
is writable
106 redef fun to_s
do return self.name
108 # The view of the module in the `model.mmodule_importation_hierarchy`
109 var in_importation
: POSetElement[MModule] is noinit
111 # The canonical name of the module.
113 # It is usually the `name` prefixed by the package's name.
114 # Example: `"package::name"`
116 # Default modules use a doubled name to distinguish them from the package name.
117 # E.g.: `"core::core"`
119 # If the module is package-less, then the short-name is used alone.
120 redef var full_name
is lazy
do
121 var mgroup
= self.mgroup
122 if mgroup
== null then
125 return "{mgroup.mpackage.name}::{self.name}"
129 # The namespace used for entities according to their visibility `v`.
131 # Public entities use only the package as a namespace.
132 # Private entities use the `full_name` (i.e. "package::module")
134 # This method is used by entities to implement their `full_name`.
135 fun namespace_for
(v
: MVisibility): String do
136 if v
<= private_visibility
then return full_name
137 var mgroup
= self.mgroup
138 if mgroup
== null then
141 return mgroup
.mpackage
.full_name
145 # Return the name of the global C identifier associated to `self`.
146 # This name is used to prefix files and other C identifiers associated with `self`.
147 redef var c_name
is lazy
do
150 if g
!= null and g
.mpackage
.name
!= name
then
151 res
= g
.mpackage
.name
.to_cmangle
+ "__" + name
.to_cmangle
153 res
= name
.to_cmangle
158 # C identifier version of `namespace_for`.
161 # This method is used by entities to implement their `c_name`.
162 fun c_namespace_for
(v
: MVisibility): String do
163 if v
<= private_visibility
then return c_name
164 var mgroup
= self.mgroup
165 if mgroup
== null then
168 return mgroup
.mpackage
.c_name
172 # Create a new empty module and register it to a model
175 model
.mmodules_by_name
.add_one
(name
, self)
176 model
.mmodules
.add
(self)
177 var mgroup
= self.mgroup
178 if mgroup
!= null then
179 mgroup
.mmodules
.add
(self)
180 if mgroup
.name
== name
then
181 assert mgroup
.default_mmodule
== null
182 mgroup
.default_mmodule
= self
185 self.in_importation
= model
.mmodule_importation_hierarchy
.add_node
(self)
188 # Register the imported modules (ie "import some_module")
189 # The visibility must be set with `set_visibility_for`.
190 fun set_imported_mmodules
(imported_mmodules
: Array[MModule])
192 for m
in imported_mmodules
do
193 self.model
.mmodule_importation_hierarchy
.add_edge
(self, m
)
197 private var intrude_mmodules
= new HashSet[MModule]
198 private var public_mmodules
= new HashSet[MModule]
199 private var private_mmodules
= new HashSet[MModule]
201 # Return the visibility level of an imported module `m`
202 fun visibility_for
(m
: MModule): MVisibility
204 if m
== self then return intrude_visibility
205 if self.intrude_mmodules
.has
(m
) then return intrude_visibility
206 if self.public_mmodules
.has
(m
) then return public_visibility
207 if self.private_mmodules
.has
(m
) then return private_visibility
208 return none_visibility
211 # Set the visibility of an imported module
212 # REQUIRE: the visibility of the modules imported by `m` are already set for `m`
213 fun set_visibility_for
(m
: MModule, v
: MVisibility)
215 if v
== intrude_visibility
then
216 self.intrude_mmodules
.add
(m
)
217 self.intrude_mmodules
.add_all
(m
.intrude_mmodules
)
218 self.public_mmodules
.add_all
(m
.public_mmodules
)
219 self.private_mmodules
.add_all
(m
.private_mmodules
)
220 else if v
== public_visibility
then
221 self.public_mmodules
.add
(m
)
222 self.public_mmodules
.add_all
(m
.intrude_mmodules
)
223 self.public_mmodules
.add_all
(m
.public_mmodules
)
224 else if v
== private_visibility
then
225 self.private_mmodules
.add
(m
)
226 self.private_mmodules
.add_all
(m
.intrude_mmodules
)
227 self.private_mmodules
.add_all
(m
.public_mmodules
)
229 print
"{self} visibility for {m} = {v}"
230 abort # invalid visibility
234 # Return true if a class or a property introduced in `intro_mmodule` with a visibility of `visibility` is visible in self.
235 fun is_visible
(intro_mmodule
: MModule, visibility
: MVisibility): Bool
237 var v
= visibility_for
(intro_mmodule
)
238 if v
== intrude_visibility
then
239 return visibility
>= private_visibility
240 else if v
== public_visibility
then
241 return visibility
> private_visibility
242 else if v
== private_visibility
then
243 return visibility
> private_visibility
244 else if v
== none_visibility
then
251 # Is `self` a unit test module used by `nitunit`?
252 var is_test_suite
: Bool = false is writable
254 # Is `self` a module generated by a tool?
256 # This flag has no effect on the semantic.
257 # It is only intended on software engineering software to discriminate computer-generated modules from human-written ones.
258 var is_generated
: Bool = false is writable
260 # Get the non-`is_fictive` module on which `self` is based on.
262 # On non-fictive module, this returns `self`.
263 # On fictive modules, this is used to refer the module which `self` is based on.
265 # This attribute should be set when a fictive module is created. See `is_fictive`.
266 var first_real_mmodule
: MModule = self is writable
268 redef fun parent_concern
do return mgroup