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 # placebo for old module nesting hierarchy.
31 # where mainmodule < mainmodule::nestedmodule
33 # TODO REMOVE, rely on mgroup instead
34 var mmodule_nesting_hierarchy
= new POSet[MModule]
36 # Full module importation hierarchy including private or nested links.
37 var mmodule_importation_hierarchy
= new POSet[MModule]
39 # Collections of modules grouped by their short names
40 private var mmodules_by_name
= new MultiHashMap[String, MModule]
42 # Return all module named `name`
43 # If such a module does not exist, null is returned (instead of an empty array)
45 # Visibility or modules are not considered
46 fun get_mmodules_by_name
(name
: String): nullable Array[MModule]
48 if mmodules_by_name
.has_key
(name
) then
49 return mmodules_by_name
[name
]
57 # The loaded modules of this group
58 var mmodules
= new Array[MModule]
60 # The default module of a group (if any, and if loaded)
62 # The default module of a group is the one that has the same name.
63 # Return `null` if the group has no default module or if the default
64 # module is not loaded.
65 var default_mmodule
: nullable MModule = null
68 # A Nit module is usually associated with a Nit source file.
72 # The model considered
73 redef var model
: Model
75 # The group of module in the project if any
76 var mgroup
: nullable MGroup
78 # The short name of the module
79 redef var name
: String
81 # The origin of the definition
82 var location
: Location
85 redef fun to_s
do return self.name
87 # placebo for old module nesting hierarchy
88 # The view of the module in the `model.mmodule_nesting_hierarchy`
90 # TODO REMOVE, rely on mgroup instead
91 var in_nesting
: POSetElement[MModule]
93 # The view of the module in the `model.mmodule_importation_hierarchy`
94 var in_importation
: POSetElement[MModule]
96 # The canonical name of the module
97 # Example: `"project::name"`
100 var mgroup
= self.mgroup
101 if mgroup
== null or mgroup
.mproject
.name
== self.name
then
104 return "{mgroup.mproject.name}::{self.name}"
108 # Create a new empty module and register it to a model
109 init(model
: Model, mgroup
: nullable MGroup, name
: String, location
: Location)
113 self.location
= location
114 model
.mmodules_by_name
.add_one
(name
, self)
115 model
.mmodules
.add
(self)
116 self.in_nesting
= model
.mmodule_nesting_hierarchy
.add_node
(self)
118 if mgroup
!= null then
119 mgroup
.mmodules
.add
(self)
120 if mgroup
.name
== name
then
121 assert mgroup
.default_mmodule
== null
122 mgroup
.default_mmodule
= self
124 # placebo for old module nesting hierarchy
125 var direct_owner
= mgroup
.default_mmodule
126 if direct_owner
== self then
127 # The module is the new owner of its own group, thus adopt the other modules
128 for m
in mgroup
.mmodules
do
129 if m
== self then continue
130 model
.mmodule_nesting_hierarchy
.add_edge
(self, m
)
132 # The potential owner is the default_mmodule of the parent group
133 if mgroup
.parent
!= null then direct_owner
= mgroup
.parent
.default_mmodule
135 if direct_owner
!= self and direct_owner
!= null then
136 model
.mmodule_nesting_hierarchy
.add_edge
(direct_owner
, self)
139 self.in_importation
= model
.mmodule_importation_hierarchy
.add_node
(self)
142 # Register the imported modules (ie "import some_module")
143 # This function can only invoked once by mmodule.
144 # The visibility must be set with `set_visibility_for`.
145 fun set_imported_mmodules
(imported_mmodules
: Array[MModule])
147 assert unique_invocation
: self.in_importation
.direct_greaters
.is_empty
148 for m
in imported_mmodules
do
149 self.model
.mmodule_importation_hierarchy
.add_edge
(self, m
)
153 private var intrude_mmodules
= new HashSet[MModule]
154 private var public_mmodules
= new HashSet[MModule]
155 private var private_mmodules
= new HashSet[MModule]
157 # Return the visibility level of an imported module `m`
158 fun visibility_for
(m
: MModule): MVisibility
160 if m
== self then return intrude_visibility
161 if self.intrude_mmodules
.has
(m
) then return intrude_visibility
162 if self.public_mmodules
.has
(m
) then return public_visibility
163 if self.private_mmodules
.has
(m
) then return private_visibility
164 return none_visibility
167 # Set the visibility of an imported module
168 # REQUIRE: the visibility of the modules imported by `m` are already set for `m`
169 fun set_visibility_for
(m
: MModule, v
: MVisibility)
171 if v
== intrude_visibility
then
172 self.intrude_mmodules
.add
(m
)
173 self.intrude_mmodules
.add_all
(m
.intrude_mmodules
)
174 self.public_mmodules
.add_all
(m
.public_mmodules
)
175 self.private_mmodules
.add_all
(m
.private_mmodules
)
176 else if v
== public_visibility
then
177 self.public_mmodules
.add
(m
)
178 self.public_mmodules
.add_all
(m
.intrude_mmodules
)
179 self.public_mmodules
.add_all
(m
.public_mmodules
)
180 else if v
== private_visibility
then
181 self.private_mmodules
.add
(m
)
182 self.private_mmodules
.add_all
(m
.intrude_mmodules
)
183 self.private_mmodules
.add_all
(m
.public_mmodules
)
185 print
"{self} visibility for {m} = {v}"
186 abort # invalid visibility
190 # Return true if a class or a property introduced in `intro_mmodule` with a visibility of `visibility` is visible in self.
191 fun is_visible
(intro_mmodule
: MModule, visibility
: MVisibility): Bool
193 var v
= visibility_for
(intro_mmodule
)
194 if v
== intrude_visibility
then
195 return visibility
>= private_visibility
196 else if v
== public_visibility
then
197 return visibility
> private_visibility
198 else if v
== private_visibility
then
199 return visibility
> private_visibility
200 else if v
== none_visibility
then
207 # Is `self` created for internal purpose?
208 # Fictive modules are instantiated internally but they should not be
209 # exposed to the final user.
210 var is_fictive
: Bool = false is writable
212 redef fun parent_concern
do return mgroup