1use crate::{language::Visibility, Engines, Ident};
2
3use super::{module::Module, root::Root, ModulePath, ModulePathBuf};
4
5use sway_error::handler::{ErrorEmitted, Handler};
6use sway_types::{
7 constants::{CONTRACT_ID, CORE, PRELUDE, STD},
8 span::Span,
9};
10
11#[derive(Clone, Debug)]
13pub struct Namespace {
14 pub(crate) root: Root,
20 pub(crate) current_mod_path: ModulePathBuf,
26}
27
28impl Namespace {
29 pub fn new(
35 handler: &Handler,
36 engines: &Engines,
37 package_root: Root,
38 import_preludes_into_root: bool,
39 ) -> Result<Self, ErrorEmitted> {
40 let package_name = package_root.current_package_name().clone();
41 let mut res = Self {
42 root: package_root,
43 current_mod_path: vec![package_name],
44 };
45
46 if import_preludes_into_root {
47 res.import_implicits(handler, engines)?;
48 }
49 Ok(res)
50 }
51
52 pub fn root(self) -> Root {
53 self.root
54 }
55
56 pub fn root_ref(&self) -> &Root {
57 &self.root
58 }
59
60 pub fn current_module(&self) -> &Module {
61 self.root
62 .module_in_current_package(&self.current_mod_path)
63 .unwrap_or_else(|| panic!("Could not retrieve submodule for mod_path."))
64 }
65
66 pub fn current_module_mut(&mut self) -> &mut Module {
67 self.root
68 .module_mut_in_current_package(&self.current_mod_path)
69 .unwrap_or_else(|| panic!("Could not retrieve submodule for mod_path."))
70 }
71
72 pub(crate) fn current_module_has_submodule(&self, submod_name: &Ident) -> bool {
73 self.current_module()
74 .submodule(&[submod_name.clone()])
75 .is_some()
76 }
77
78 pub fn current_package_name(&self) -> &Ident {
79 self.root.current_package_name()
80 }
81
82 pub fn current_mod_path(&self) -> &ModulePathBuf {
84 &self.current_mod_path
85 }
86
87 pub fn prepend_module_path<'a>(
89 &'a self,
90 prefixes: impl IntoIterator<Item = &'a Ident>,
91 ) -> ModulePathBuf {
92 self.current_mod_path
93 .iter()
94 .chain(prefixes)
95 .cloned()
96 .collect()
97 }
98
99 pub fn parsed_path_to_full_path(
101 &self,
102 _engines: &Engines,
103 parsed_path: &ModulePathBuf,
104 is_relative_to_package_root: bool,
105 ) -> ModulePathBuf {
106 if is_relative_to_package_root {
107 let mut path = vec![self.current_package_name().clone()];
109 for ident in parsed_path.iter() {
110 path.push(ident.clone())
111 }
112 path
113 } else if self.current_module_has_submodule(&parsed_path[0]) {
114 self.prepend_module_path(parsed_path)
117 } else if self.module_is_external(parsed_path) {
118 parsed_path.to_vec()
120 } else {
121 self.prepend_module_path(parsed_path)
124 }
125 }
126
127 pub fn current_package_root_module(&self) -> &Module {
128 self.root.current_package_root_module()
129 }
130
131 pub fn module_from_absolute_path(&self, path: &ModulePathBuf) -> Option<&Module> {
132 self.root.module_from_absolute_path(path)
133 }
134
135 pub fn require_module_from_absolute_path(
137 &self,
138 handler: &Handler,
139 path: &ModulePathBuf,
140 ) -> Result<&Module, ErrorEmitted> {
141 self.root.require_module(handler, path)
142 }
143
144 pub(crate) fn module_is_submodule_of(
156 &self,
157 absolute_module_path: &ModulePath,
158 true_if_same: bool,
159 ) -> bool {
160 if self.current_mod_path.len() < absolute_module_path.len() {
161 return false;
162 }
163
164 let is_submodule = absolute_module_path
165 .iter()
166 .zip(self.current_mod_path.iter())
167 .all(|(left, right)| left == right);
168
169 if is_submodule {
170 if self.current_mod_path.len() == absolute_module_path.len() {
171 true_if_same
172 } else {
173 true
174 }
175 } else {
176 false
177 }
178 }
179
180 pub(crate) fn module_is_external(&self, absolute_module_path: &ModulePath) -> bool {
183 assert!(!absolute_module_path.is_empty(), "Absolute module path must have at least one element, because it always contains the package name.");
184
185 self.root.current_package_name() != &absolute_module_path[0]
186 }
187
188 pub fn package_exists(&self, name: &Ident) -> bool {
189 self.module_from_absolute_path(&vec![name.clone()])
190 .is_some()
191 }
192
193 pub(crate) fn module_has_binding(
194 &self,
195 engines: &Engines,
196 mod_path: &ModulePathBuf,
197 symbol: &Ident,
198 ) -> bool {
199 let dummy_handler = Handler::default();
200 if let Some(module) = self.module_from_absolute_path(mod_path) {
201 module
202 .resolve_symbol(&dummy_handler, engines, symbol)
203 .is_ok()
204 } else {
205 false
206 }
207 }
208
209 fn import_implicits(
211 &mut self,
212 handler: &Handler,
213 engines: &Engines,
214 ) -> Result<(), ErrorEmitted> {
215 let package_name = self.current_package_name().to_string();
217 let core_string = CORE.to_string();
218 let core_ident = Ident::new_no_span(core_string.clone());
219 let prelude_ident = Ident::new_no_span(PRELUDE.to_string());
220 if package_name == CORE {
221 } else if package_name == STD {
223 assert!(self.root.exists_as_external(&core_string));
225 self.root.star_import(
226 handler,
227 engines,
228 &[core_ident, prelude_ident],
229 &self.current_mod_path,
230 Visibility::Private,
231 )?
232 } else {
233 if self.root.exists_as_external(&core_string) {
235 self.root.star_import(
236 handler,
237 engines,
238 &[core_ident, prelude_ident.clone()],
239 &self.current_mod_path,
240 Visibility::Private,
241 )?;
242 }
243
244 let std_string = STD.to_string();
245 if self.root.exists_as_external(&std_string) {
247 self.root.star_import(
248 handler,
249 engines,
250 &[Ident::new_no_span(std_string), prelude_ident],
251 &self.current_mod_path,
252 Visibility::Private,
253 )?
254 }
255 }
256
257 if self.root.is_contract_package() && self.current_mod_path.len() > 1 {
259 self.root.item_import(
261 handler,
262 engines,
263 &[Ident::new_no_span(package_name)],
264 &Ident::new_no_span(CONTRACT_ID.to_string()),
265 &self.current_mod_path,
266 None,
267 Visibility::Private,
268 )?
269 }
270
271 Ok(())
272 }
273
274 pub(crate) fn enter_submodule(
275 &mut self,
276 handler: &Handler,
277 engines: &Engines,
278 mod_name: Ident,
279 visibility: Visibility,
280 module_span: Span,
281 ) -> Result<(), ErrorEmitted> {
282 let mut import_implicits = false;
283
284 if !self
286 .current_module()
287 .submodules()
288 .contains_key(&mod_name.to_string())
289 {
290 self.current_module_mut()
292 .add_new_submodule(&mod_name, visibility, Some(module_span));
293 import_implicits = true;
294 }
295
296 self.current_mod_path.push(mod_name.clone());
298
299 if import_implicits {
301 self.import_implicits(handler, engines)?;
302 }
303
304 Ok(())
305 }
306
307 pub fn push_submodule(
309 &mut self,
310 handler: &Handler,
311 engines: &Engines,
312 mod_name: Ident,
313 visibility: Visibility,
314 module_span: Span,
315 ) -> Result<(), ErrorEmitted> {
316 match self.enter_submodule(handler, engines, mod_name, visibility, module_span) {
317 Ok(_) => Ok(()),
318 Err(e) => Err(e),
319 }
320 }
321
322 pub fn pop_submodule(&mut self) {
324 self.current_mod_path.pop();
325 }
326
327 pub(crate) fn star_import_to_current_module(
328 &mut self,
329 handler: &Handler,
330 engines: &Engines,
331 src: &ModulePath,
332 visibility: Visibility,
333 ) -> Result<(), ErrorEmitted> {
334 self.root
335 .star_import(handler, engines, src, &self.current_mod_path, visibility)
336 }
337
338 pub(crate) fn variant_star_import_to_current_module(
339 &mut self,
340 handler: &Handler,
341 engines: &Engines,
342 src: &ModulePath,
343 enum_name: &Ident,
344 visibility: Visibility,
345 ) -> Result<(), ErrorEmitted> {
346 self.root.variant_star_import(
347 handler,
348 engines,
349 src,
350 &self.current_mod_path,
351 enum_name,
352 visibility,
353 )
354 }
355
356 pub(crate) fn self_import_to_current_module(
357 &mut self,
358 handler: &Handler,
359 engines: &Engines,
360 src: &ModulePath,
361 alias: Option<Ident>,
362 visibility: Visibility,
363 ) -> Result<(), ErrorEmitted> {
364 self.root.self_import(
365 handler,
366 engines,
367 src,
368 &self.current_mod_path,
369 alias,
370 visibility,
371 )
372 }
373
374 pub(crate) fn item_import_to_current_module(
375 &mut self,
376 handler: &Handler,
377 engines: &Engines,
378 src: &ModulePath,
379 item: &Ident,
380 alias: Option<Ident>,
381 visibility: Visibility,
382 ) -> Result<(), ErrorEmitted> {
383 self.root.item_import(
384 handler,
385 engines,
386 src,
387 item,
388 &self.current_mod_path,
389 alias,
390 visibility,
391 )
392 }
393
394 #[allow(clippy::too_many_arguments)]
395 pub(crate) fn variant_import_to_current_module(
396 &mut self,
397 handler: &Handler,
398 engines: &Engines,
399 src: &ModulePath,
400 enum_name: &Ident,
401 variant_name: &Ident,
402 alias: Option<Ident>,
403 visibility: Visibility,
404 ) -> Result<(), ErrorEmitted> {
405 self.root.variant_import(
406 handler,
407 engines,
408 src,
409 enum_name,
410 variant_name,
411 &self.current_mod_path,
412 alias,
413 visibility,
414 )
415 }
416}