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 # Module nesting hierarchy.
32 # where mainmodule < mainmodule::nestedmodule
33 var mmodule_nesting_hierarchy
: POSet[MModule] = new POSet[MModule]
35 # Full module importation hierarchy including private or nested links.
36 var mmodule_importation_hierarchy
: POSet[MModule] = new POSet[MModule]
38 # Collections of modules grouped by their short names
39 private var mmodules_by_name
: MultiHashMap[String, MModule] = new MultiHashMap[String, MModule]
41 # Return all module named `name`
42 # If such a module does not exist, null is returned (instead of an empty array)
44 # Visibility or modules are not considered
45 fun get_mmodules_by_name
(name
: String): nullable Array[MModule]
47 if mmodules_by_name
.has_key
(name
) then
48 return mmodules_by_name
[name
]
55 # A Nit module is usually associated with a Nit source file.
56 # Modules can be nested (see `direct_owner`, `public_owner`, and `in_nesting`)
58 # The model considered
61 # The direct nesting module, return null if self is not nested (ie. is a top-level module)
62 var direct_owner
: nullable MModule
64 # The short name of the module
67 # The origin of the definition
68 var location
: Location
71 redef fun to_s
do return self.name
73 # The view of the module in the `model.mmodule_nesting_hierarchy`
74 var in_nesting
: POSetElement[MModule]
76 # The view of the module in the `model.mmodule_importation_hierarchy`
77 var in_importation
: POSetElement[MModule]
79 # The canonical name of the module
80 # Example: `"owner::name"`
83 var owner
= self.public_owner
87 return "{owner.full_name}::{self.name}"
91 # Create a new empty module and register it to a model
92 # `direct_owner` is the direct owner (null if top-level module)
93 init(model
: Model, direct_owner
: nullable MModule, name
: String, location
: Location)
97 self.location
= location
98 model
.mmodules_by_name
.add_one
(name
, self)
99 model
.mmodules
.add
(self)
100 self.in_nesting
= model
.mmodule_nesting_hierarchy
.add_node
(self)
101 self.direct_owner
= direct_owner
102 if direct_owner
!= null then
103 model
.mmodule_nesting_hierarchy
.add_edge
(direct_owner
, self)
105 self.in_importation
= model
.mmodule_importation_hierarchy
.add_node
(self)
108 # Register the imported modules (ie "import some_module")
109 # This function can only invoked once by mmodule.
110 # The visibility must be set with `set_visibility_for`.
111 fun set_imported_mmodules
(imported_mmodules
: Array[MModule])
113 assert unique_invocation
: self.in_importation
.direct_greaters
.is_empty
114 for m
in imported_mmodules
do
115 self.model
.mmodule_importation_hierarchy
.add_edge
(self, m
)
119 private var intrude_mmodules
: HashSet[MModule] = new HashSet[MModule]
120 private var public_mmodules
: HashSet[MModule] = new HashSet[MModule]
121 private var private_mmodules
: HashSet[MModule] = new HashSet[MModule]
123 # Return the visibility level of an imported module `m`
124 fun visibility_for
(m
: MModule): MVisibility
126 if m
== self then return intrude_visibility
127 if self.intrude_mmodules
.has
(m
) then return intrude_visibility
128 if self.public_mmodules
.has
(m
) then return public_visibility
129 if self.private_mmodules
.has
(m
) then return private_visibility
130 return none_visibility
133 # Set the visibility of an imported module
134 # REQUIRE: the visibility of the modules imported by `m` are already set for `m`
135 fun set_visibility_for
(m
: MModule, v
: MVisibility)
137 if v
== intrude_visibility
then
138 self.intrude_mmodules
.add
(m
)
139 self.intrude_mmodules
.add_all
(m
.intrude_mmodules
)
140 self.public_mmodules
.add_all
(m
.public_mmodules
)
141 self.private_mmodules
.add_all
(m
.private_mmodules
)
142 else if v
== public_visibility
then
143 self.public_mmodules
.add
(m
)
144 self.public_mmodules
.add_all
(m
.intrude_mmodules
)
145 self.public_mmodules
.add_all
(m
.public_mmodules
)
146 else if v
== private_visibility
then
147 self.private_mmodules
.add
(m
)
148 self.private_mmodules
.add_all
(m
.intrude_mmodules
)
149 self.private_mmodules
.add_all
(m
.public_mmodules
)
151 print
"{self} visibility for {m} = {v}"
152 abort # invalid visibility
156 # The first module in the nesting hierarchy to export self as public
157 # This function is used to determine the canonical name of modules, classes and properties.
158 # REQUIRE: the visibility of all nesting modules is already set.
159 fun public_owner
: nullable MModule
161 var res
= self.direct_owner
163 while last
!= null do
164 if last
.visibility_for
(self) >= public_visibility
then res
= last
165 last
= last
.direct_owner
170 # Return true if a class or a property introduced in `intro_mmodule` with a visibility of `visibility` is visible in self.
171 fun is_visible
(intro_mmodule
: MModule, visibility
: MVisibility): Bool
173 var v
= visibility_for
(intro_mmodule
)
174 if v
== intrude_visibility
then
175 return visibility
>= private_visibility
176 else if v
== public_visibility
then
177 return visibility
> private_visibility
178 else if v
== private_visibility
then
179 return visibility
> private_visibility
180 else if v
== none_visibility
then