/ compiler / ast / src / common / path.rs
path.rs
  1  // Copyright (C) 2019-2025 ADnet Contributors
  2  // This file is part of the ADL library.
  3  
  4  // The ADL 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 ADL 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 ADL library. If not, see <https://www.gnu.org/licenses/>.
 16  
 17  use crate::{Expression, Identifier, Node, NodeID, simple_node_impl};
 18  
 19  use adl_span::{Span, Symbol};
 20  
 21  use itertools::Itertools;
 22  use serde::{Deserialize, Serialize};
 23  use std::{fmt, hash::Hash};
 24  
 25  /// A Path in a program.
 26  #[derive(Clone, Default, Hash, Eq, PartialEq, Serialize, Deserialize)]
 27  pub 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      /// Is this path an absolute path? e.g. `::foo::bar::baz`.
 36      is_absolute: bool,
 37  
 38      /// The fully resolved path. We may not know this until the pass PathResolution pass runs.
 39      /// For path that refer to global items (composites, consts, functions), `absolute_path` is
 40      /// guaranteed to be set after the pass `PathResolution`.
 41      absolute_path: Option<Vec<Symbol>>,
 42  
 43      /// A span locating where the path occurred in the source.
 44      pub span: Span,
 45  
 46      /// The ID of the node.
 47      pub id: NodeID,
 48  }
 49  
 50  simple_node_impl!(Path);
 51  
 52  impl Path {
 53      /// Creates a new `Path` from the given components.
 54      ///
 55      /// - `qualifier`: The namespace segments (e.g., `foo::bar` in `foo::bar::baz`).
 56      /// - `identifier`: The final item in the path (e.g., `baz`).
 57      /// - `is_absolute`: Whether the path is absolute (starts with `::`).
 58      /// - `absolute_path`: Optionally, the fully resolved symbolic path.
 59      /// - `span`: The source code span for this path.
 60      /// - `id`: The node ID.
 61      pub fn new(
 62          qualifier: Vec<Identifier>,
 63          identifier: Identifier,
 64          is_absolute: bool,
 65          absolute_path: Option<Vec<Symbol>>,
 66          span: Span,
 67          id: NodeID,
 68      ) -> Self {
 69          Self { qualifier, identifier, is_absolute, absolute_path, span, id }
 70      }
 71  
 72      /// Returns the final identifier of the path (e.g., `baz` in `foo::bar::baz`).
 73      pub fn identifier(&self) -> Identifier {
 74          self.identifier
 75      }
 76  
 77      /// Returns a slice of the qualifier segments (e.g., `[foo, bar]` in `foo::bar::baz`).
 78      pub fn qualifier(&self) -> &[Identifier] {
 79          self.qualifier.as_slice()
 80      }
 81  
 82      /// Returns `true` if the path is absolute (i.e., starts with `::`).
 83      pub fn is_absolute(&self) -> bool {
 84          self.is_absolute
 85      }
 86  
 87      /// Returns a `Vec<Symbol>` representing the full symbolic path:
 88      /// the qualifier segments followed by the final identifier.
 89      ///
 90      /// Note: this refers to the user path which is not necessarily the absolute path.
 91      pub fn as_symbols(&self) -> Vec<Symbol> {
 92          self.qualifier.iter().map(|segment| segment.name).chain(std::iter::once(self.identifier.name)).collect()
 93      }
 94  
 95      /// Returns an optional vector of `Symbol`s representing the resolved absolute path,
 96      /// or `None` if resolution has not yet occurred.
 97      pub fn try_absolute_path(&self) -> Option<Vec<Symbol>> {
 98          if self.is_absolute { Some(self.as_symbols()) } else { self.absolute_path.clone() }
 99      }
100  
101      /// Returns a vector of `Symbol`s representing the resolved absolute path.
102      ///
103      /// If the path is not an absolute path, this method panics if the absolute path has not been resolved yet.
104      /// For relative paths, this is expected to be called only after path resolution has occurred.
105      pub fn absolute_path(&self) -> Vec<Symbol> {
106          if self.is_absolute {
107              self.as_symbols()
108          } else {
109              self.absolute_path.as_ref().expect("absolute path must be known at this stage").to_vec()
110          }
111      }
112  
113      /// Converts this `Path` into an absolute path by setting its `is_absolute` flag to `true`.
114      ///
115      /// This does not alter the qualifier or identifier, nor does it compute or modify
116      /// the resolved `absolute_path`.
117      pub fn into_absolute(mut self) -> Self {
118          self.is_absolute = true;
119          self
120      }
121  
122      /// Returns a new `Path` instance with the last segment's `Symbol` and the last symbol
123      /// in the `absolute_path` (if present) replaced with `new_symbol`.
124      ///
125      /// Other fields remain unchanged.
126      pub fn with_updated_last_symbol(mut self, new_symbol: Symbol) -> Self {
127          // Update identifier
128          self.identifier.name = new_symbol;
129  
130          // Update absolute_path's last symbol if present
131          if let Some(ref mut abs_path) = self.absolute_path
132              && let Some(last) = abs_path.last_mut()
133          {
134              *last = new_symbol;
135          }
136  
137          self
138      }
139  
140      /// Sets `self.absolute_path` to `absolute_path`
141      pub fn with_absolute_path(mut self, absolute_path: Option<Vec<Symbol>>) -> Self {
142          self.absolute_path = absolute_path;
143          self
144      }
145  
146      /// Sets the `absolute_path` by prepending the given `module_prefix` to the path's
147      /// own qualifier and identifier. Returns the updated `Path`.
148      pub fn with_module_prefix(mut self, module_prefix: &[Symbol]) -> Self {
149          let full_path = module_prefix
150              .iter()
151              .cloned()
152              .chain(self.qualifier.iter().map(|id| id.name))
153              .chain(std::iter::once(self.identifier.name))
154              .collect();
155  
156          self.absolute_path = Some(full_path);
157          self
158      }
159  }
160  
161  impl fmt::Display for Path {
162      fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
163          if self.is_absolute {
164              write!(f, "::")?;
165          }
166          if self.qualifier.is_empty() {
167              write!(f, "{}", self.identifier)
168          } else {
169              write!(f, "{}::{}", self.qualifier.iter().format("::"), self.identifier)
170          }
171      }
172  }
173  
174  impl fmt::Debug for Path {
175      fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
176          // Print user path (Display impl)
177          write!(f, "{self}")?;
178  
179          // Print resolved absolute path if available
180          if let Some(abs_path) = &self.absolute_path {
181              write!(f, "(::{})", abs_path.iter().format("::"))
182          } else {
183              write!(f, "()")
184          }
185      }
186  }
187  
188  impl From<Path> for Expression {
189      fn from(value: Path) -> Self {
190          Expression::Path(value)
191      }
192  }