mago_codex/context/
mod.rs1use mago_interner::StringIdentifier;
2
3use crate::identifier::function_like::FunctionLikeIdentifier;
4use crate::metadata::class_like::ClassLikeMetadata;
5use crate::metadata::function_like::FunctionLikeMetadata;
6use crate::reference::ReferenceSource;
7
8#[derive(Clone, Copy, Debug, PartialEq, Eq)]
9pub struct ScopeContext<'a> {
10 pub(crate) function_like: Option<&'a FunctionLikeMetadata>,
11 pub(crate) class_like: Option<&'a ClassLikeMetadata>,
12 pub(crate) is_static: bool,
13}
14
15impl Default for ScopeContext<'_> {
16 fn default() -> Self {
17 Self::new()
18 }
19}
20
21impl<'a> ScopeContext<'a> {
22 #[inline]
24 pub fn new() -> Self {
25 Self { function_like: None, class_like: None, is_static: true }
26 }
27
28 #[inline]
30 pub const fn is_global(&self) -> bool {
31 self.function_like.is_none() && self.class_like.is_none()
32 }
33
34 #[inline]
36 pub const fn is_mutation_free(&self) -> bool {
37 if let Some(function_like) = self.function_like
38 && (function_like.flags.is_pure() || function_like.flags.is_mutation_free())
39 {
40 return true;
41 }
42
43 if let Some(class_like) = self.class_like
44 && class_like.flags.is_mutation_free()
45 {
46 return true;
47 }
48
49 false
50 }
51
52 #[inline]
54 pub const fn is_external_mutation_free(&self) -> bool {
55 if let Some(function_like) = self.function_like
56 && (function_like.flags.is_pure()
57 || function_like.flags.is_mutation_free()
58 || function_like.flags.is_external_mutation_free())
59 {
60 return true;
61 }
62
63 if let Some(class_like) = self.class_like
64 && (class_like.flags.is_mutation_free() || class_like.flags.is_external_mutation_free())
65 {
66 return true;
67 }
68
69 false
70 }
71
72 #[inline]
74 pub fn get_class_like(&self) -> Option<&'a ClassLikeMetadata> {
75 self.class_like
76 }
77
78 #[inline]
80 pub fn get_class_like_name(&self) -> Option<&'a StringIdentifier> {
81 self.class_like.map(|class| &class.original_name)
82 }
83
84 #[inline]
86 pub fn get_function_like(&self) -> Option<&'a FunctionLikeMetadata> {
87 self.function_like
88 }
89
90 #[inline]
92 pub fn get_function_like_identifier(&self) -> Option<FunctionLikeIdentifier> {
93 let function_like = self.function_like?;
94
95 let Some(function_name) = function_like.name else {
96 return Some(FunctionLikeIdentifier::Closure(function_like.span.file_id, function_like.span.start));
97 };
98
99 Some(if function_like.get_kind().is_method() {
100 let Some(class_like) = self.class_like else {
101 return Some(FunctionLikeIdentifier::Function(function_name));
102 };
103
104 FunctionLikeIdentifier::Method(class_like.name, function_name)
105 } else {
106 FunctionLikeIdentifier::Function(function_name)
107 })
108 }
109
110 #[inline]
112 pub const fn is_class_like_final(&self) -> bool {
113 match self.class_like {
114 Some(class) => class.flags.is_final(),
115 None => false,
116 }
117 }
118
119 #[inline]
121 pub const fn is_static(&self) -> bool {
122 self.is_static
123 }
124
125 #[inline]
127 pub fn set_function_like(&mut self, function_like: Option<&'a FunctionLikeMetadata>) {
128 self.function_like = function_like;
129 }
130
131 #[inline]
133 pub fn set_class_like(&mut self, class_like: Option<&'a ClassLikeMetadata>) {
134 self.class_like = class_like;
135 }
136
137 #[inline]
139 pub fn set_static(&mut self, is_static: bool) {
140 self.is_static = is_static;
141 }
142
143 #[inline]
146 pub fn get_reference_source(&self) -> Option<ReferenceSource> {
147 if let Some(calling_functionlike_id) = self.get_function_like_identifier() {
148 match calling_functionlike_id {
149 FunctionLikeIdentifier::Function(name) => Some(ReferenceSource::Symbol(false, name)),
150 FunctionLikeIdentifier::Method(class_name, method_name) => {
151 Some(ReferenceSource::ClassLikeMember(false, class_name, method_name))
152 }
153 _ => None,
154 }
155 } else {
156 None
157 }
158 }
159}