mago_ast/ast/function_like/
parameter.rs

1use serde::Deserialize;
2use serde::Serialize;
3
4use mago_span::HasSpan;
5use mago_span::Span;
6
7use crate::ast::attribute::AttributeList;
8use crate::ast::class_like::property::PropertyHookList;
9use crate::ast::expression::Expression;
10use crate::ast::modifier::Modifier;
11use crate::ast::type_hint::Hint;
12use crate::ast::variable::DirectVariable;
13use crate::sequence::Sequence;
14use crate::sequence::TokenSeparatedSequence;
15
16/// Represents a parameter list in PHP.
17#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
18#[repr(C)]
19pub struct FunctionLikeParameterList {
20    pub left_parenthesis: Span,
21    pub parameters: TokenSeparatedSequence<FunctionLikeParameter>,
22    pub right_parenthesis: Span,
23}
24
25/// Represents a function-like parameter in PHP.
26///
27/// Example: `int $foo`, `string &$bar`, `bool ...$baz`, `mixed $qux = null`
28#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
29#[repr(C)]
30pub struct FunctionLikeParameter {
31    pub attribute_lists: Sequence<AttributeList>,
32    pub modifiers: Sequence<Modifier>,
33    pub hint: Option<Hint>,
34    pub ampersand: Option<Span>,
35    pub ellipsis: Option<Span>,
36    pub variable: DirectVariable,
37    pub default_value: Option<FunctionLikeParameterDefaultValue>,
38    pub hooks: Option<PropertyHookList>,
39}
40
41/// Represents the default value of a function-like parameter.
42#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize, PartialOrd, Ord)]
43#[repr(C)]
44pub struct FunctionLikeParameterDefaultValue {
45    pub equals: Span,
46    pub value: Expression,
47}
48
49impl FunctionLikeParameter {
50    /// Returns whether the parameter is a promoted property.
51    ///
52    /// A promoted property is a property that is declared in a constructor parameter list.
53    ///
54    /// A parameter is considered a promoted property if it has at least one modifier or a hook.
55    ///
56    /// [RFC: Constructor Property Promotion](https://wiki.php.net/rfc/constructor_promotion)
57    /// [RFC: Property Hooks](https://wiki.php.net/rfc/property-hooks)
58    pub fn is_promoted_property(&self) -> bool {
59        !self.modifiers.is_empty() || self.hooks.is_some()
60    }
61}
62
63impl HasSpan for FunctionLikeParameterList {
64    fn span(&self) -> Span {
65        Span::between(self.left_parenthesis, self.right_parenthesis)
66    }
67}
68
69impl HasSpan for FunctionLikeParameter {
70    fn span(&self) -> Span {
71        let right = self.hooks.as_ref().map(|hooks| hooks.span()).unwrap_or_else(|| {
72            self.default_value.as_ref().map_or_else(|| self.variable.span(), |default_value| default_value.span())
73        });
74
75        if let Some(attribute) = self.attribute_lists.first() {
76            return Span::between(attribute.span(), right);
77        }
78
79        if let Some(modifier) = self.modifiers.first() {
80            return Span::between(modifier.span(), right);
81        }
82
83        if let Some(type_hint) = &self.hint {
84            return Span::between(type_hint.span(), right);
85        }
86
87        if let Some(ellipsis) = self.ellipsis {
88            return Span::between(ellipsis, right);
89        }
90
91        if let Some(ampersand) = self.ampersand {
92            return Span::between(ampersand, right);
93        }
94
95        Span::between(self.variable.span(), right)
96    }
97}
98
99impl HasSpan for FunctionLikeParameterDefaultValue {
100    fn span(&self) -> Span {
101        Span::between(self.equals, self.value.span())
102    }
103}