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