sway_core/semantic_analysis/namespace/
package.rs

1use super::{module::Module, Ident, ModuleName};
2use crate::{language::Visibility, namespace::ModulePathBuf};
3use rustc_hash::FxHasher;
4use std::hash::BuildHasherDefault;
5use sway_types::{span::Span, ProgramId};
6
7/// A representation of the bindings in a package. The package's module structure can be accessed
8/// via the root module.
9///
10/// This is equivalent to a Rust crate. The root module is equivalent to Rust's "crate root".
11#[derive(Clone, Debug)]
12pub struct Package {
13    // The contents of the package being compiled.
14    root_module: Module,
15    // Program id for the package.
16    program_id: ProgramId,
17    // True if the current package is a contract, false otherwise.
18    is_contract_package: bool,
19    // The external dependencies of the current package. Note that an external package is
20    // represented as a `Package` object. This is because external packages may have their own external
21    // dependencies which are needed for lookups, but which are not directly accessible to the
22    // current package.
23    pub external_packages: im::HashMap<ModuleName, Package, BuildHasherDefault<FxHasher>>,
24}
25
26impl Package {
27    // Create a new `Package` object with a root module.
28    //
29    // To ensure the correct initialization the factory function `package_with_contract_id` is
30    // supplied in `contract_helpers`.
31    //
32    // External packages must be added afterwards by calling `add_external`.
33    pub fn new(
34        package_name: Ident,
35        span: Option<Span>,
36        program_id: ProgramId,
37        is_contract_package: bool,
38    ) -> Self {
39        // The root module must be public
40        let module = Module::new(package_name, Visibility::Public, span, &vec![]);
41        Self {
42            root_module: module,
43            program_id,
44            is_contract_package,
45            external_packages: Default::default(),
46        }
47    }
48
49    // Add an external package to this package. The package name must be supplied, since the package
50    // may be referred to by a different name in the Forc.toml file than the actual name of the
51    // package.
52    pub fn add_external(&mut self, package_name: String, external_package: Package) {
53        // This should be ensured by the package manager
54        assert!(!self.external_packages.contains_key(&package_name));
55        self.external_packages
56            .insert(package_name, external_package);
57    }
58
59    pub fn root_module(&self) -> &Module {
60        &self.root_module
61    }
62
63    pub fn root_module_mut(&mut self) -> &mut Module {
64        &mut self.root_module
65    }
66
67    pub fn name(&self) -> &Ident {
68        self.root_module.name()
69    }
70
71    pub fn program_id(&self) -> ProgramId {
72        self.program_id
73    }
74
75    pub(crate) fn check_path_is_in_package(&self, mod_path: &ModulePathBuf) -> bool {
76        !mod_path.is_empty() && mod_path[0] == *self.root_module.name()
77    }
78
79    pub(crate) fn package_relative_path(mod_path: &ModulePathBuf) -> ModulePathBuf {
80        mod_path[1..].to_vec()
81    }
82
83    pub(super) fn is_contract_package(&self) -> bool {
84        self.is_contract_package
85    }
86
87    // Find module in the current environment. `mod_path` must be a fully qualified path
88    pub fn module_from_absolute_path(&self, mod_path: &ModulePathBuf) -> Option<&Module> {
89        assert!(!mod_path.is_empty());
90        let package_relative_path = Self::package_relative_path(mod_path);
91        if mod_path[0] == *self.root_module.name() {
92            self.root_module.submodule(&package_relative_path)
93        } else if let Some(external_package) = self.external_packages.get(&mod_path[0].to_string())
94        {
95            external_package
96                .root_module()
97                .submodule(&package_relative_path)
98        } else {
99            None
100        }
101    }
102}