Merge: introduce nit_env.sh to setup the shell environement
[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 mpackage
22 private import more_collections
23
24 # The container class of a Nit object-oriented model.
25 #
26 # A model knows modules, classes and properties and can retrieve them.
27 #
28 # However, a model is not a program or a library as it can contains modules
29 # found by the system (including broken ones) but not used.
30 redef class Model
31 # All known modules
32 var mmodules = new Array[MModule]
33
34 # Full module importation hierarchy including private or nested links.
35 var mmodule_importation_hierarchy = new POSet[MModule]
36
37 # Collections of modules grouped by their short names
38 private var mmodules_by_name = new MultiHashMap[String, MModule]
39
40 # Return all module named `name`
41 # If such a module does not exist, null is returned (instead of an empty array)
42 #
43 # Visibility or modules are not considered
44 fun get_mmodules_by_name(name: String): nullable Array[MModule]
45 do
46 if mmodules_by_name.has_key(name) then
47 return mmodules_by_name[name]
48 else
49 return null
50 end
51 end
52 end
53
54 redef class MGroup
55 # The loaded modules of this group
56 var mmodules = new Array[MModule]
57
58 # The default module of a group (if any, and if loaded)
59 #
60 # The default module of a group is the one that has the same name.
61 # Return `null` if the group has no default module or if the default
62 # module is not loaded.
63 var default_mmodule: nullable MModule = null
64
65 redef fun mdoc_or_fallback
66 do
67 if mdoc != null then return mdoc
68 var default_mmodule = self.default_mmodule
69 if default_mmodule == null then return null
70 return default_mmodule.mdoc_or_fallback
71 end
72 end
73
74 # A Nit module is usually associated with a Nit source file.
75 class MModule
76 super MConcern
77
78 # The model considered
79 redef var model: Model
80
81 # The group of module in the package if any
82 var mgroup: nullable MGroup
83
84 # The package of the module if any
85 # Safe alias for `mgroup.mpackage`
86 fun mpackage: nullable MPackage
87 do
88 var g = mgroup
89 if g == null then return null else return g.mpackage
90 end
91
92 # The short name of the module
93 redef var name: String
94
95 # The origin of the definition
96 var location: Location
97
98 # Alias for `name`
99 redef fun to_s do return self.name
100
101 # The view of the module in the `model.mmodule_importation_hierarchy`
102 var in_importation: POSetElement[MModule] is noinit
103
104 # The canonical name of the module.
105 #
106 # It is usually the `name` prefixed by the package's name.
107 # Example: `"package::name"`
108 #
109 # If both names are the same (of if the module is package-less), then
110 # the short-name is used alone.
111 redef var full_name is lazy do
112 var mgroup = self.mgroup
113 if mgroup == null or mgroup.mpackage.name == self.name then
114 return self.name
115 else
116 return "{mgroup.mpackage.name}::{self.name}"
117 end
118 end
119
120 # The namespace used for entities according to their visibility `v`.
121 #
122 # Public entities use only the package as a namespace.
123 # Private entities use the `full_name` (i.e. "package::module")
124 #
125 # This method is used by entities to implement their `full_name`.
126 fun namespace_for(v: MVisibility): String do
127 if v <= private_visibility then return full_name
128 var mgroup = self.mgroup
129 if mgroup == null then
130 return full_name
131 else
132 return mgroup.mpackage.full_name
133 end
134 end
135
136 # Return the name of the global C identifier associated to `self`.
137 # This name is used to prefix files and other C identifiers associated with `self`.
138 redef var c_name: String is lazy do
139 var g = mgroup
140 var res
141 if g != null and g.mpackage.name != name then
142 res = g.mpackage.name.to_cmangle + "__" + name.to_cmangle
143 else
144 res = name.to_cmangle
145 end
146 return res
147 end
148
149 # C identifier version of `namespace_for`.
150 # See `c_name`
151 #
152 # This method is used by entities to implement their `c_name`.
153 fun c_namespace_for(v: MVisibility): String do
154 if v <= private_visibility then return c_name
155 var mgroup = self.mgroup
156 if mgroup == null then
157 return c_name
158 else
159 return mgroup.mpackage.c_name
160 end
161 end
162
163 # Create a new empty module and register it to a model
164 init
165 do
166 model.mmodules_by_name.add_one(name, self)
167 model.mmodules.add(self)
168 var mgroup = self.mgroup
169 if mgroup != null then
170 mgroup.mmodules.add(self)
171 if mgroup.name == name then
172 assert mgroup.default_mmodule == null
173 mgroup.default_mmodule = self
174 end
175 end
176 self.in_importation = model.mmodule_importation_hierarchy.add_node(self)
177 end
178
179 # Register the imported modules (ie "import some_module")
180 # The visibility must be set with `set_visibility_for`.
181 fun set_imported_mmodules(imported_mmodules: Array[MModule])
182 do
183 for m in imported_mmodules do
184 self.model.mmodule_importation_hierarchy.add_edge(self, m)
185 end
186 end
187
188 private var intrude_mmodules = new HashSet[MModule]
189 private var public_mmodules = new HashSet[MModule]
190 private var private_mmodules = new HashSet[MModule]
191
192 # Return the visibility level of an imported module `m`
193 fun visibility_for(m: MModule): MVisibility
194 do
195 if m == self then return intrude_visibility
196 if self.intrude_mmodules.has(m) then return intrude_visibility
197 if self.public_mmodules.has(m) then return public_visibility
198 if self.private_mmodules.has(m) then return private_visibility
199 return none_visibility
200 end
201
202 # Set the visibility of an imported module
203 # REQUIRE: the visibility of the modules imported by `m` are already set for `m`
204 fun set_visibility_for(m: MModule, v: MVisibility)
205 do
206 if v == intrude_visibility then
207 self.intrude_mmodules.add(m)
208 self.intrude_mmodules.add_all(m.intrude_mmodules)
209 self.public_mmodules.add_all(m.public_mmodules)
210 self.private_mmodules.add_all(m.private_mmodules)
211 else if v == public_visibility then
212 self.public_mmodules.add(m)
213 self.public_mmodules.add_all(m.intrude_mmodules)
214 self.public_mmodules.add_all(m.public_mmodules)
215 else if v == private_visibility then
216 self.private_mmodules.add(m)
217 self.private_mmodules.add_all(m.intrude_mmodules)
218 self.private_mmodules.add_all(m.public_mmodules)
219 else
220 print "{self} visibility for {m} = {v}"
221 abort # invalid visibility
222 end
223 end
224
225 # Return true if a class or a property introduced in `intro_mmodule` with a visibility of `visibility` is visible in self.
226 fun is_visible(intro_mmodule: MModule, visibility: MVisibility): Bool
227 do
228 var v = visibility_for(intro_mmodule)
229 if v == intrude_visibility then
230 return visibility >= private_visibility
231 else if v == public_visibility then
232 return visibility > private_visibility
233 else if v == private_visibility then
234 return visibility > private_visibility
235 else if v == none_visibility then
236 return false
237 else
238 abort
239 end
240 end
241
242 # Is `self` a unit test module used by `nitunit`?
243 var is_test_suite: Bool = false is writable
244
245 # Get the first non `is_fictive` module greater than self
246 fun first_real_mmodule: MModule
247 do
248 var mmodule = self
249 while mmodule.is_fictive do
250 mmodule = mmodule.in_importation.direct_greaters.first
251 end
252 return mmodule
253 end
254
255 redef fun parent_concern do return mgroup
256 end