use mago_atom::Atom;
use crate::identifier::function_like::FunctionLikeIdentifier;
use crate::metadata::class_like::ClassLikeMetadata;
use crate::metadata::function_like::FunctionLikeMetadata;
use crate::metadata::property_hook::PropertyHookMetadata;
use crate::reference::ReferenceSource;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct ScopeContext<'ctx> {
pub(crate) function_like: Option<&'ctx FunctionLikeMetadata>,
pub(crate) class_like: Option<&'ctx ClassLikeMetadata>,
pub(crate) property_hook: Option<(Atom, &'ctx PropertyHookMetadata)>,
pub(crate) is_static: bool,
}
impl Default for ScopeContext<'_> {
fn default() -> Self {
Self::new()
}
}
impl<'ctx> ScopeContext<'ctx> {
#[inline]
#[must_use]
pub fn new() -> Self {
Self { function_like: None, class_like: None, property_hook: None, is_static: true }
}
#[inline]
#[must_use]
pub const fn is_global(&self) -> bool {
self.function_like.is_none() && self.class_like.is_none()
}
#[inline]
#[must_use]
pub const fn is_pure(&self) -> bool {
if let Some(function_like) = self.function_like
&& function_like.flags.is_pure()
{
return true;
}
false
}
#[inline]
#[must_use]
pub fn get_class_like(&self) -> Option<&'ctx ClassLikeMetadata> {
self.class_like
}
#[inline]
#[must_use]
pub fn get_class_like_name(&self) -> Option<Atom> {
self.class_like.map(|class| class.name)
}
#[inline]
#[must_use]
pub fn get_function_like(&self) -> Option<&'ctx FunctionLikeMetadata> {
self.function_like
}
#[inline]
#[must_use]
pub fn get_function_like_identifier(&self) -> Option<FunctionLikeIdentifier> {
let function_like = self.function_like?;
let Some(function_name) = function_like.name else {
return Some(FunctionLikeIdentifier::Closure(function_like.span.file_id, function_like.span.start));
};
Some(if function_like.get_kind().is_method() {
let Some(class_like) = self.class_like else {
return Some(FunctionLikeIdentifier::Function(function_name));
};
FunctionLikeIdentifier::Method(class_like.name, function_name)
} else {
FunctionLikeIdentifier::Function(function_name)
})
}
#[inline]
#[must_use]
pub const fn is_class_like_final(&self) -> bool {
match self.class_like {
Some(class) => class.flags.is_final(),
None => false,
}
}
#[inline]
#[must_use]
pub const fn is_static(&self) -> bool {
self.is_static
}
#[inline]
pub fn set_function_like(&mut self, function_like: Option<&'ctx FunctionLikeMetadata>) {
self.function_like = function_like;
}
#[inline]
pub fn set_class_like(&mut self, class_like: Option<&'ctx ClassLikeMetadata>) {
self.class_like = class_like;
}
#[inline]
pub fn set_static(&mut self, is_static: bool) {
self.is_static = is_static;
}
#[inline]
#[must_use]
pub fn get_property_hook(&self) -> Option<(Atom, &'ctx PropertyHookMetadata)> {
self.property_hook
}
#[inline]
pub fn set_property_hook(&mut self, property_hook: Option<(Atom, &'ctx PropertyHookMetadata)>) {
self.property_hook = property_hook;
}
#[inline]
#[must_use]
pub fn get_reference_source(&self) -> Option<ReferenceSource> {
if let Some(calling_functionlike_id) = self.get_function_like_identifier() {
match calling_functionlike_id {
FunctionLikeIdentifier::Function(name) => Some(ReferenceSource::Symbol(false, name)),
FunctionLikeIdentifier::Method(class_name, method_name) => {
Some(ReferenceSource::ClassLikeMember(false, class_name, method_name))
}
_ => None,
}
} else {
None
}
}
}