mago_codex/misc.rs
1use serde::Deserialize;
2use serde::Serialize;
3
4use mago_interner::StringIdentifier;
5use mago_interner::ThreadedInterner;
6use mago_span::Span;
7
8/// Represents a PHP variable identifier (e.g., `$foo`, `$this`).
9/// Wraps a `StringIdentifier` which holds the interned name (including '$').
10#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
11pub struct VariableIdentifier(
12 /// The interned identifier for the variable name (e.g., "$foo").
13 pub StringIdentifier,
14);
15
16/// Identifies the target of an expression, distinguishing simple variables from property accesses.
17#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
18pub enum ExpressionIdentifier {
19 /// A simple variable identifier.
20 ///
21 /// * `VariableIdentifier` - The identifier for the variable (e.g., `$foo`).
22 Variable(VariableIdentifier),
23 /// An instance property access (e.g., `$this->prop`, `$user->name`).
24 ///
25 /// * `VariableIdentifier` - The identifier for the object variable (e.g., `$this`, `$user`).
26 /// * `Span` - The source code location covering the property name part (e.g., `prop` or `name`).
27 /// * `StringIdentifier` - The name of the property being accessed (e.g., `prop`, `name`).
28 InstanceProperty(VariableIdentifier, Span, StringIdentifier),
29}
30
31/// Identifies the scope where a generic template parameter (`@template`) is defined.
32#[derive(PartialEq, Eq, Hash, Clone, Copy, Serialize, Deserialize, PartialOrd, Ord, Debug)]
33pub enum GenericParent {
34 /// The template is defined on a class, interface, trait, or enum.
35 /// * `StringIdentifier` - The fully qualified name (FQCN) of the class-like structure.
36 ClassLike(StringIdentifier),
37 /// The template is defined on a function or method.
38 /// * `(StringIdentifier, StringIdentifier)` - A tuple representing the function/method.
39 /// - `.0`: The FQCN of the class if it's a method, or the FQN of the function if global/namespaced.
40 /// - `.1`: The method name if it's a method, or `StringIdentifier::empty()` if it's a function.
41 FunctionLike((StringIdentifier, StringIdentifier)),
42}
43
44impl GenericParent {
45 /// Converts the `GenericParent` identifier to a stable string representation,
46 /// optionally using an interner for human-readable names.
47 ///
48 /// Used for creating unique keys or debugging information related to generic contexts.
49 /// The format distinguishes between class-like (`Namespace\ClassName`) and function-like
50 /// parents (`fn-Namespace\functionName` or `fn-Namespace\ClassName::methodName`).
51 ///
52 /// # Arguments
53 ///
54 /// * `interner` - An optional reference to the `ThreadedInterner` for resolving names.
55 #[inline]
56 pub fn to_string(&self, interner: Option<&ThreadedInterner>) -> String {
57 match self {
58 GenericParent::ClassLike(id) => {
59 if let Some(interner) = interner {
60 interner.lookup(id).to_string()
61 } else {
62 id.to_string()
63 }
64 }
65 GenericParent::FunctionLike(id) => {
66 let part1 = id.0;
67 let part2 = id.1;
68
69 if part1.is_empty() {
70 if let Some(interner) = interner {
71 format!("{}()", interner.lookup(&part2))
72 } else {
73 format!("{part2}()")
74 }
75 } else if let Some(interner) = interner {
76 format!("{}::{}()", interner.lookup(&part1), interner.lookup(&part2))
77 } else {
78 format!("{part1}::{part2}()")
79 }
80 }
81 }
82 }
83}