mago_names/lib.rs
1use std::collections::HashSet;
2
3use ahash::HashMap;
4use serde::Serialize;
5
6use mago_span::HasPosition;
7use mago_span::Position;
8
9pub mod kind;
10pub mod resolver;
11pub mod scope;
12
13mod internal;
14
15/// Stores the results of a name resolution pass over a PHP program.
16///
17/// Maps source code positions (specifically, the starting byte offset of identifiers)
18/// to their resolved fully qualified name (`StringIdentifier`) and a flag indicating
19/// whether the resolution involved an explicit `use` alias or construct.
20#[derive(Debug, Clone, Eq, PartialEq, Serialize, Default)]
21pub struct ResolvedNames<'arena> {
22 /// Internal map storing: position (byte offset) -> (Resolved Name ID, Was Imported Flag)
23 names: HashMap<u32, (&'arena str, bool)>,
24}
25
26impl<'arena> ResolvedNames<'arena> {
27 /// Returns the total number of resolved names stored.
28 pub fn len(&self) -> usize {
29 self.names.len()
30 }
31
32 /// Returns `true` if no resolved names are stored.
33 pub fn is_empty(&self) -> bool {
34 self.names.is_empty()
35 }
36
37 /// Checks if a resolved name exists for the given source `Position`.
38 pub fn contains(&self, position: &Position) -> bool {
39 self.names.contains_key(&position.offset)
40 }
41
42 /// Gets the resolved name identifier for the given source position.
43 ///
44 /// # Panics
45 ///
46 /// Panics if no resolved name is found at the specified `position`.
47 /// Use `contains` first if unsure.
48 pub fn get<T: HasPosition>(&self, position: &T) -> &'arena str {
49 self.names.get(&position.offset()).map(|(name, _)| name).expect("resolved name not found at position")
50 }
51
52 /// Checks if the name resolved at the given position originated from an explicit `use` alias or construct.
53 ///
54 /// Returns `false` if the name was resolved relative to the namespace, is a definition,
55 /// or if no name is found at the position.
56 pub fn is_imported<T: HasPosition>(&self, position: &T) -> bool {
57 self.names
58 .get(&position.offset()) // Get Option<(StringIdentifier, bool)>
59 .map(|(_, imported)| *imported) // Extract the bool flag
60 .unwrap_or(false) // Default to false if position not found
61 }
62
63 /// Inserts a resolution result into the map (intended for internal use).
64 ///
65 /// Associates the resolved `name` identifier and its `imported` status with the
66 /// given `position` (byte offset).
67 pub(crate) fn insert_at<T: HasPosition>(&mut self, position: &T, name: &'arena str, imported: bool) {
68 self.names.insert(position.offset(), (name, imported));
69 }
70
71 /// Returns a `HashSet` containing references to all stored resolution results.
72 ///
73 /// Each element in the set is a reference to a tuple: `(&usize, &(StringIdentifier, bool))`,
74 /// representing `(&position, &(resolved_name_id, was_imported_flag))`.
75 pub fn all(&self) -> HashSet<(&u32, &(&'arena str, bool))> {
76 HashSet::from_iter(self.names.iter())
77 }
78}