mago_syntax/utils/
assignment.rs

1use crate::ast::Access;
2use crate::ast::Argument;
3use crate::ast::ArrayElement;
4use crate::ast::Assignment;
5use crate::ast::Call;
6use crate::ast::ClassLikeConstantSelector;
7use crate::ast::ClassLikeMemberSelector;
8use crate::ast::Construct;
9use crate::ast::Expression;
10use crate::ast::MatchArm;
11use crate::ast::PartialApplication;
12use crate::ast::Yield;
13
14/// Get the assignment operation from an expression.
15///
16/// This function will recursively search through the expression and its children to find
17///  the first assignment operation.
18///
19/// If no assignment operation is found, it will return `None`.
20#[inline]
21#[must_use]
22pub fn get_assignment_from_expression<'a, 'arena>(
23    expression: &'a Expression<'arena>,
24) -> Option<&'a Assignment<'arena>> {
25    match &expression {
26        Expression::Assignment(assignment_operation) => Some(assignment_operation),
27        Expression::Parenthesized(parenthesized) => get_assignment_from_expression(parenthesized.expression),
28        Expression::Binary(operation) => {
29            get_assignment_from_expression(operation.lhs).or_else(|| get_assignment_from_expression(operation.rhs))
30        }
31        Expression::UnaryPrefix(operation) => get_assignment_from_expression(operation.operand),
32        Expression::UnaryPostfix(operation) => get_assignment_from_expression(operation.operand),
33        Expression::Conditional(conditional) => get_assignment_from_expression(conditional.condition)
34            .or_else(|| conditional.then.as_ref().and_then(|then| get_assignment_from_expression(then)))
35            .or_else(|| get_assignment_from_expression(conditional.r#else)),
36        Expression::Array(array) => array.elements.iter().find_map(|element| match &element {
37            ArrayElement::KeyValue(key_value_array_element) => {
38                get_assignment_from_expression(key_value_array_element.key)
39                    .or_else(|| get_assignment_from_expression(key_value_array_element.value))
40            }
41            ArrayElement::Value(value_array_element) => get_assignment_from_expression(value_array_element.value),
42            ArrayElement::Variadic(variadic_array_element) => {
43                get_assignment_from_expression(variadic_array_element.value)
44            }
45            ArrayElement::Missing(_) => None,
46        }),
47        Expression::LegacyArray(legacy_array) => legacy_array.elements.iter().find_map(|element| match &element {
48            ArrayElement::KeyValue(key_value_array_element) => {
49                get_assignment_from_expression(key_value_array_element.key)
50                    .or_else(|| get_assignment_from_expression(key_value_array_element.value))
51            }
52            ArrayElement::Value(value_array_element) => get_assignment_from_expression(value_array_element.value),
53            ArrayElement::Variadic(variadic_array_element) => {
54                get_assignment_from_expression(variadic_array_element.value)
55            }
56            ArrayElement::Missing(_) => None,
57        }),
58        Expression::List(list) => list.elements.iter().find_map(|element| match &element {
59            ArrayElement::KeyValue(key_value_array_element) => {
60                get_assignment_from_expression(key_value_array_element.key)
61                    .or_else(|| get_assignment_from_expression(key_value_array_element.value))
62            }
63            ArrayElement::Value(value_array_element) => get_assignment_from_expression(value_array_element.value),
64            ArrayElement::Variadic(variadic_array_element) => {
65                get_assignment_from_expression(variadic_array_element.value)
66            }
67            ArrayElement::Missing(_) => None,
68        }),
69        Expression::ArrayAccess(array_access) => get_assignment_from_expression(array_access.array)
70            .or_else(|| get_assignment_from_expression(array_access.index)),
71        Expression::ArrayAppend(array_append) => get_assignment_from_expression(array_append.array),
72        Expression::Match(r#match) => get_assignment_from_expression(r#match.expression).or_else(|| {
73            r#match.arms.iter().find_map(|arm| match arm {
74                MatchArm::Expression(match_expression_arm) => match_expression_arm
75                    .conditions
76                    .iter()
77                    .find_map(|condition| get_assignment_from_expression(condition))
78                    .or_else(|| get_assignment_from_expression(match_expression_arm.expression)),
79                MatchArm::Default(match_default_arm) => get_assignment_from_expression(match_default_arm.expression),
80            })
81        }),
82        Expression::Yield(r#yield) => match r#yield {
83            Yield::Value(yield_value) => {
84                yield_value.value.as_ref().and_then(|value| get_assignment_from_expression(value))
85            }
86            Yield::Pair(yield_pair) => get_assignment_from_expression(yield_pair.key)
87                .or_else(|| get_assignment_from_expression(yield_pair.value)),
88            Yield::From(yield_from) => get_assignment_from_expression(yield_from.iterator),
89        },
90        Expression::Construct(construct) => match construct {
91            Construct::Isset(isset_construct) => {
92                isset_construct.values.iter().find_map(|v| get_assignment_from_expression(v))
93            }
94            Construct::Empty(empty_construct) => get_assignment_from_expression(empty_construct.value),
95            Construct::Eval(eval_construct) => get_assignment_from_expression(eval_construct.value),
96            Construct::Include(include_construct) => get_assignment_from_expression(include_construct.value),
97            Construct::IncludeOnce(include_once_construct) => {
98                get_assignment_from_expression(include_once_construct.value)
99            }
100            Construct::Require(require_construct) => get_assignment_from_expression(require_construct.value),
101            Construct::RequireOnce(require_once_construct) => {
102                get_assignment_from_expression(require_once_construct.value)
103            }
104            Construct::Print(print_construct) => get_assignment_from_expression(print_construct.value),
105            Construct::Exit(exit_construct) => exit_construct.arguments.as_ref().and_then(|arguments| {
106                arguments.arguments.iter().find_map(|argument| {
107                    get_assignment_from_expression(match &argument {
108                        Argument::Positional(positional_argument) => &positional_argument.value,
109                        Argument::Named(named_argument) => &named_argument.value,
110                    })
111                })
112            }),
113            Construct::Die(die_construct) => die_construct.arguments.as_ref().and_then(|arguments| {
114                arguments.arguments.iter().find_map(|argument| {
115                    get_assignment_from_expression(match &argument {
116                        Argument::Positional(positional_argument) => &positional_argument.value,
117                        Argument::Named(named_argument) => &named_argument.value,
118                    })
119                })
120            }),
121        },
122        Expression::Throw(throw) => get_assignment_from_expression(throw.exception),
123        Expression::Clone(clone) => get_assignment_from_expression(clone.object),
124        Expression::Call(call) => match &call {
125            Call::Function(function_call) => get_assignment_from_expression(function_call.function).or_else(|| {
126                function_call.argument_list.arguments.iter().find_map(|argument| match &argument {
127                    Argument::Positional(positional_argument) => {
128                        get_assignment_from_expression(&positional_argument.value)
129                    }
130                    Argument::Named(named_argument) => get_assignment_from_expression(&named_argument.value),
131                })
132            }),
133            Call::Method(method_call) => get_assignment_from_expression(method_call.object)
134                .or_else(|| match &method_call.method {
135                    ClassLikeMemberSelector::Expression(class_like_member_expression_selector) => {
136                        get_assignment_from_expression(class_like_member_expression_selector.expression)
137                    }
138                    _ => None,
139                })
140                .or_else(|| {
141                    method_call.argument_list.arguments.iter().find_map(|argument| match &argument {
142                        Argument::Positional(positional_argument) => {
143                            get_assignment_from_expression(&positional_argument.value)
144                        }
145                        Argument::Named(named_argument) => get_assignment_from_expression(&named_argument.value),
146                    })
147                }),
148            Call::NullSafeMethod(null_safe_method_call) => get_assignment_from_expression(null_safe_method_call.object)
149                .or_else(|| match &null_safe_method_call.method {
150                    ClassLikeMemberSelector::Expression(class_like_member_expression_selector) => {
151                        get_assignment_from_expression(class_like_member_expression_selector.expression)
152                    }
153                    _ => None,
154                })
155                .or_else(|| {
156                    null_safe_method_call.argument_list.arguments.iter().find_map(|argument| match &argument {
157                        Argument::Positional(positional_argument) => {
158                            get_assignment_from_expression(&positional_argument.value)
159                        }
160                        Argument::Named(named_argument) => get_assignment_from_expression(&named_argument.value),
161                    })
162                }),
163            Call::StaticMethod(static_method_call) => get_assignment_from_expression(static_method_call.class)
164                .or_else(|| match &static_method_call.method {
165                    ClassLikeMemberSelector::Expression(class_like_member_expression_selector) => {
166                        get_assignment_from_expression(class_like_member_expression_selector.expression)
167                    }
168                    _ => None,
169                })
170                .or_else(|| {
171                    static_method_call.argument_list.arguments.iter().find_map(|argument| match &argument {
172                        Argument::Positional(positional_argument) => {
173                            get_assignment_from_expression(&positional_argument.value)
174                        }
175                        Argument::Named(named_argument) => get_assignment_from_expression(&named_argument.value),
176                    })
177                }),
178        },
179        Expression::Access(access) => match access {
180            Access::Property(property_access) => {
181                get_assignment_from_expression(property_access.object).or_else(|| match &property_access.property {
182                    ClassLikeMemberSelector::Expression(class_like_member_expression_selector) => {
183                        get_assignment_from_expression(class_like_member_expression_selector.expression)
184                    }
185                    _ => None,
186                })
187            }
188            Access::NullSafeProperty(null_safe_property_access) => {
189                get_assignment_from_expression(null_safe_property_access.object).or_else(|| {
190                    match &null_safe_property_access.property {
191                        ClassLikeMemberSelector::Expression(class_like_member_expression_selector) => {
192                            get_assignment_from_expression(class_like_member_expression_selector.expression)
193                        }
194                        _ => None,
195                    }
196                })
197            }
198            Access::StaticProperty(static_property_access) => {
199                get_assignment_from_expression(static_property_access.class)
200            }
201            Access::ClassConstant(class_constant_access) => get_assignment_from_expression(class_constant_access.class)
202                .or_else(|| match &class_constant_access.constant {
203                    ClassLikeConstantSelector::Expression(class_like_member_expression_selector) => {
204                        get_assignment_from_expression(class_like_member_expression_selector.expression)
205                    }
206                    _ => None,
207                }),
208        },
209        Expression::PartialApplication(partial_application) => match partial_application {
210            PartialApplication::Function(function_partial_application) => {
211                get_assignment_from_expression(function_partial_application.function)
212            }
213            PartialApplication::Method(method_partial_application) => {
214                get_assignment_from_expression(method_partial_application.object).or_else(|| {
215                    match &method_partial_application.method {
216                        ClassLikeMemberSelector::Expression(class_like_member_expression_selector) => {
217                            get_assignment_from_expression(class_like_member_expression_selector.expression)
218                        }
219                        _ => None,
220                    }
221                })
222            }
223            PartialApplication::StaticMethod(static_method_partial_application) => {
224                get_assignment_from_expression(static_method_partial_application.class).or_else(|| {
225                    match &static_method_partial_application.method {
226                        ClassLikeMemberSelector::Expression(class_like_member_expression_selector) => {
227                            get_assignment_from_expression(class_like_member_expression_selector.expression)
228                        }
229                        _ => None,
230                    }
231                })
232            }
233        },
234        Expression::Instantiation(instantiation) => get_assignment_from_expression(instantiation.class).or_else(|| {
235            instantiation.argument_list.as_ref().and_then(|arguments| {
236                arguments.arguments.iter().find_map(|argument| match &argument {
237                    Argument::Positional(positional_argument) => {
238                        get_assignment_from_expression(&positional_argument.value)
239                    }
240                    Argument::Named(named_argument) => get_assignment_from_expression(&named_argument.value),
241                })
242            })
243        }),
244        _ => None,
245    }
246}