leo_ast/common/
path.rs

1// Copyright (C) 2019-2025 Provable Inc.
2// This file is part of the Leo library.
3
4// The Leo library is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// The Leo library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with the Leo library. If not, see <https://www.gnu.org/licenses/>.
16
17use crate::{Expression, Identifier, Node, NodeID, simple_node_impl};
18
19use leo_span::{Span, Symbol};
20
21use itertools::Itertools;
22use serde::{Deserialize, Serialize};
23use std::{fmt, hash::Hash};
24
25/// A Path in a program.
26#[derive(Clone, Default, Hash, Eq, PartialEq, Serialize, Deserialize)]
27pub struct Path {
28    /// The qualifying namespace segments written by the user, excluding the item itself.
29    /// e.g., in `foo::bar::baz`, this would be `[foo, bar]`.
30    qualifier: Vec<Identifier>,
31
32    /// The final item in the path, e.g., `baz` in `foo::bar::baz`.
33    identifier: Identifier,
34
35    /// The fully resolved path. We may not know this until the pass PathResolution pass runs.
36    /// For path that refer to global items (structs, consts, functions), `absolute_path` is
37    /// guaranteed to be set after the pass `PathResolution`.
38    absolute_path: Option<Vec<Symbol>>,
39
40    /// A span locating where the path occurred in the source.
41    pub span: Span,
42
43    /// The ID of the node.
44    pub id: NodeID,
45}
46
47simple_node_impl!(Path);
48
49impl Path {
50    pub fn new(
51        qualifier: Vec<Identifier>,
52        identifier: Identifier,
53        absolute_path: Option<Vec<Symbol>>,
54        span: Span,
55        id: NodeID,
56    ) -> Self {
57        Self { qualifier, identifier, absolute_path, span, id }
58    }
59
60    pub fn identifier(&self) -> Identifier {
61        self.identifier
62    }
63
64    pub fn qualifier(&self) -> &[Identifier] {
65        self.qualifier.as_slice()
66    }
67
68    /// Returns a `Vec<Symbol>` representing the full symbolic path:
69    /// the qualifier segments followed by the final identifier.
70    ///
71    /// Note: this refers to the user path which is not necessarily the absolute path.
72    pub fn as_symbols(&self) -> Vec<Symbol> {
73        self.qualifier.iter().map(|segment| segment.name).chain(std::iter::once(self.identifier.name)).collect()
74    }
75
76    /// Returns an optional slice of `Symbol`s representing the resolved absolute path,
77    /// or `None` if resolution has not yet occurred.
78    pub fn try_absolute_path(&self) -> Option<&[Symbol]> {
79        self.absolute_path.as_deref()
80    }
81
82    /// Returns a slice of `Symbol`s representing the resolved absolute path.
83    ///
84    /// # Panics
85    ///
86    /// Panics if the absolute path has not been resolved yet. This is expected to be
87    /// called only after path resolution has occurred.
88    pub fn absolute_path(&self) -> &[Symbol] {
89        self.absolute_path.as_deref().expect("absolute path must be known at this stage")
90    }
91
92    /// Returns a new `Path` instance with the last segment's `Symbol` and the last symbol
93    /// in the `absolute_path` (if present) replaced with `new_symbol`.
94    ///
95    /// Other fields remain unchanged.
96    pub fn with_updated_last_symbol(mut self, new_symbol: Symbol) -> Self {
97        // Update identifier
98        self.identifier.name = new_symbol;
99
100        // Update absolute_path's last symbol if present
101        if let Some(ref mut abs_path) = self.absolute_path {
102            if let Some(last) = abs_path.last_mut() {
103                *last = new_symbol;
104            }
105        }
106
107        self
108    }
109
110    /// Sets `self.absolute_path` to `absolute_path`
111    pub fn with_absolute_path(mut self, absolute_path: Option<Vec<Symbol>>) -> Self {
112        self.absolute_path = absolute_path;
113        self
114    }
115
116    /// Sets the `absolute_path` by prepending the given `module_prefix` to the path's
117    /// own qualifier and identifier. Returns the updated `Path`.
118    pub fn with_module_prefix(mut self, module_prefix: &[Symbol]) -> Self {
119        let full_path = module_prefix
120            .iter()
121            .cloned()
122            .chain(self.qualifier.iter().map(|id| id.name))
123            .chain(std::iter::once(self.identifier.name))
124            .collect();
125
126        self.absolute_path = Some(full_path);
127        self
128    }
129}
130
131impl fmt::Display for Path {
132    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
133        if self.qualifier.is_empty() {
134            write!(f, "{}", self.identifier)
135        } else {
136            write!(f, "{}::{}", self.qualifier.iter().format("::"), self.identifier)
137        }
138    }
139}
140
141impl fmt::Debug for Path {
142    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
143        // Print user path (Display impl)
144        write!(f, "{self}")?;
145
146        // Print resolved absolute path if available
147        if let Some(abs_path) = &self.absolute_path {
148            write!(f, "(::{})", abs_path.iter().format("::"))
149        } else {
150            write!(f, "()")
151        }
152    }
153}
154
155impl From<Path> for Expression {
156    fn from(value: Path) -> Self {
157        Expression::Path(value)
158    }
159}