src: update most tools to new constructors
[nit.git] / src / model / mmodule.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2012 Jean Privat <jean@pryen.org>
4 #
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
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
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.
16
17 # modules and module hierarchies in the metamodel
18 module mmodule
19
20 import location
21 import mproject
22 private import more_collections
23
24 # The container class of a Nit object-oriented model.
25 # A model knows modules, classes and properties and can retrieve them.
26 redef class Model
27 # All known modules
28 var mmodules = new Array[MModule]
29
30 # placebo for old module nesting hierarchy.
31 # where mainmodule < mainmodule::nestedmodule
32 #
33 # TODO REMOVE, rely on mgroup instead
34 var mmodule_nesting_hierarchy = new POSet[MModule]
35
36 # Full module importation hierarchy including private or nested links.
37 var mmodule_importation_hierarchy = new POSet[MModule]
38
39 # Collections of modules grouped by their short names
40 private var mmodules_by_name = new MultiHashMap[String, MModule]
41
42 # Return all module named `name`
43 # If such a module does not exist, null is returned (instead of an empty array)
44 #
45 # Visibility or modules are not considered
46 fun get_mmodules_by_name(name: String): nullable Array[MModule]
47 do
48 if mmodules_by_name.has_key(name) then
49 return mmodules_by_name[name]
50 else
51 return null
52 end
53 end
54 end
55
56 redef class MGroup
57 # The loaded modules of this group
58 var mmodules = new Array[MModule]
59
60 # The default module of a group (if any, and if loaded)
61 #
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
66 end
67
68 # A Nit module is usually associated with a Nit source file.
69 class MModule
70 super MConcern
71
72 # The model considered
73 redef var model: Model
74
75 # The group of module in the project if any
76 var mgroup: nullable MGroup
77
78 # The short name of the module
79 redef var name: String
80
81 # The origin of the definition
82 var location: Location
83
84 # Alias for `name`
85 redef fun to_s do return self.name
86
87 # placebo for old module nesting hierarchy
88 # The view of the module in the `model.mmodule_nesting_hierarchy`
89 #
90 # TODO REMOVE, rely on mgroup instead
91 var in_nesting: POSetElement[MModule] is noinit
92
93 # The view of the module in the `model.mmodule_importation_hierarchy`
94 var in_importation: POSetElement[MModule] is noinit
95
96 # The canonical name of the module
97 # Example: `"project::name"`
98 fun full_name: String
99 do
100 var mgroup = self.mgroup
101 if mgroup == null or mgroup.mproject.name == self.name then
102 return self.name
103 else
104 return "{mgroup.mproject.name}::{self.name}"
105 end
106 end
107
108 # Create a new empty module and register it to a model
109 init
110 do
111 model.mmodules_by_name.add_one(name, self)
112 model.mmodules.add(self)
113 self.in_nesting = model.mmodule_nesting_hierarchy.add_node(self)
114 if mgroup != null then
115 mgroup.mmodules.add(self)
116 if mgroup.name == name then
117 assert mgroup.default_mmodule == null
118 mgroup.default_mmodule = self
119 end
120 # placebo for old module nesting hierarchy
121 var direct_owner = mgroup.default_mmodule
122 if direct_owner == self then
123 # The module is the new owner of its own group, thus adopt the other modules
124 for m in mgroup.mmodules do
125 if m == self then continue
126 model.mmodule_nesting_hierarchy.add_edge(self, m)
127 end
128 # The potential owner is the default_mmodule of the parent group
129 if mgroup.parent != null then direct_owner = mgroup.parent.default_mmodule
130 end
131 if direct_owner != self and direct_owner != null then
132 model.mmodule_nesting_hierarchy.add_edge(direct_owner, self)
133 end
134 end
135 self.in_importation = model.mmodule_importation_hierarchy.add_node(self)
136 end
137
138 # Register the imported modules (ie "import some_module")
139 # This function can only invoked once by mmodule.
140 # The visibility must be set with `set_visibility_for`.
141 fun set_imported_mmodules(imported_mmodules: Array[MModule])
142 do
143 assert unique_invocation: self.in_importation.direct_greaters.is_empty
144 for m in imported_mmodules do
145 self.model.mmodule_importation_hierarchy.add_edge(self, m)
146 end
147 end
148
149 private var intrude_mmodules = new HashSet[MModule]
150 private var public_mmodules = new HashSet[MModule]
151 private var private_mmodules = new HashSet[MModule]
152
153 # Return the visibility level of an imported module `m`
154 fun visibility_for(m: MModule): MVisibility
155 do
156 if m == self then return intrude_visibility
157 if self.intrude_mmodules.has(m) then return intrude_visibility
158 if self.public_mmodules.has(m) then return public_visibility
159 if self.private_mmodules.has(m) then return private_visibility
160 return none_visibility
161 end
162
163 # Set the visibility of an imported module
164 # REQUIRE: the visibility of the modules imported by `m` are already set for `m`
165 fun set_visibility_for(m: MModule, v: MVisibility)
166 do
167 if v == intrude_visibility then
168 self.intrude_mmodules.add(m)
169 self.intrude_mmodules.add_all(m.intrude_mmodules)
170 self.public_mmodules.add_all(m.public_mmodules)
171 self.private_mmodules.add_all(m.private_mmodules)
172 else if v == public_visibility then
173 self.public_mmodules.add(m)
174 self.public_mmodules.add_all(m.intrude_mmodules)
175 self.public_mmodules.add_all(m.public_mmodules)
176 else if v == private_visibility then
177 self.private_mmodules.add(m)
178 self.private_mmodules.add_all(m.intrude_mmodules)
179 self.private_mmodules.add_all(m.public_mmodules)
180 else
181 print "{self} visibility for {m} = {v}"
182 abort # invalid visibility
183 end
184 end
185
186 # Return true if a class or a property introduced in `intro_mmodule` with a visibility of `visibility` is visible in self.
187 fun is_visible(intro_mmodule: MModule, visibility: MVisibility): Bool
188 do
189 var v = visibility_for(intro_mmodule)
190 if v == intrude_visibility then
191 return visibility >= private_visibility
192 else if v == public_visibility then
193 return visibility > private_visibility
194 else if v == private_visibility then
195 return visibility > private_visibility
196 else if v == none_visibility then
197 return false
198 else
199 abort
200 end
201 end
202
203 # Is `self` created for internal purpose?
204 # Fictive modules are instantiated internally but they should not be
205 # exposed to the final user.
206 var is_fictive: Bool = false is writable
207
208 redef fun parent_concern do return mgroup
209 end