teo_parser/search/
search_unit_for_definition.rs

1use crate::ast::argument_list::ArgumentList;
2use crate::availability::Availability;
3use crate::ast::expression::ExpressionKind;
4use crate::ast::node::Node;
5use crate::ast::reference_space::ReferenceSpace;
6use crate::ast::schema::Schema;
7use crate::ast::source::Source;
8use crate::ast::span::Span;
9use crate::ast::subscript::Subscript;
10use crate::ast::unit::Unit;
11use crate::r#type::r#type::Type;
12use crate::search::search_identifier_path::{search_identifier_path_names_with_filter_to_path};
13use crate::traits::identifiable::Identifiable;
14use crate::traits::named_identifiable::NamedIdentifiable;
15use crate::traits::node_trait::NodeTrait;
16use crate::traits::resolved::Resolve;
17use crate::utils::top_filter::top_filter_for_reference_type;
18
19#[derive(Debug)]
20pub enum UnitSearchResult {
21    Type(Type),
22    Reference(Vec<usize>),
23}
24
25impl UnitSearchResult {
26
27    pub(super) fn is_reference(&self) -> bool {
28        self.as_reference().is_some()
29    }
30
31    pub(super) fn as_reference(&self) -> Option<&Vec<usize>> {
32        match self {
33            Self::Reference(r) => Some(r),
34            _ => None,
35        }
36    }
37
38    pub(super) fn is_type(&self) -> bool {
39        self.as_type().is_some()
40    }
41
42    pub(super) fn as_type(&self) -> Option<&Type> {
43        match self {
44            Self::Type(t) => Some(t),
45            _ => None,
46        }
47    }
48}
49
50pub fn search_unit_for_definition<HAL, HS, HI, OUTPUT>(
51    schema: &Schema,
52    source: &Source,
53    unit: &Unit,
54    namespace_path: &Vec<&str>,
55    line_col: (usize, usize),
56    handle_argument_list: HAL,
57    handle_subscript: HS,
58    handle_identifier: HI,
59    default: OUTPUT,
60    availability: Availability,
61) -> OUTPUT where
62    HAL: Fn(&ArgumentList, &Vec<usize>, Option<&str>) -> OUTPUT,
63    HS: Fn(&Subscript) -> OUTPUT,
64    HI: Fn(Span, &Vec<usize>, Option<&str>) -> OUTPUT,
65{
66    let mut current: Option<UnitSearchResult> = None;
67    for (index, expression) in unit.expressions().enumerate() {
68        if index == 0 {
69            let mut identifier_span = None;
70            current = Some(if let Some(identifier) = expression.kind.as_identifier() {
71                if let Some(path) = search_identifier_path_names_with_filter_to_path(
72                    &vec![identifier.name()],
73                    schema,
74                    source,
75                    namespace_path,
76                    &top_filter_for_reference_type(ReferenceSpace::Default),
77                    availability,
78                ) {
79                    identifier_span = Some(identifier.span);
80                    UnitSearchResult::Reference(path)
81                } else {
82                    UnitSearchResult::Type(Type::Undetermined)
83                }
84            } else {
85                UnitSearchResult::Type(expression.resolved().r#type().clone())
86            });
87            if expression.span().contains_line_col(line_col) {
88                if let Some(current) = current {
89                    return match current {
90                        UnitSearchResult::Type(_) => default,
91                        UnitSearchResult::Reference(path) => handle_identifier(identifier_span.unwrap(), &path, None),
92                    }
93                }
94                break
95            }
96            if current.is_some() && current.as_ref().unwrap().is_reference() {
97                let top = schema.find_top_by_path(current.as_ref().unwrap().as_reference().unwrap()).unwrap();
98                if top.is_constant_declaration() {
99                    current = Some(UnitSearchResult::Type(top.as_constant_declaration().unwrap().resolved().r#type.clone()));
100                }
101            }
102        } else {
103            if current.as_ref().is_some() {
104                match current.as_ref().unwrap() {
105                    UnitSearchResult::Type(current_type) => {
106                        if let Some((reference, _)) = current_type.as_struct_object() {
107                            match &expression.kind {
108                                ExpressionKind::Identifier(_) => {
109                                    return default
110                                }
111                                ExpressionKind::Subscript(subscript) => {
112                                    let struct_declaration = schema.find_top_by_path(reference.path()).unwrap().as_struct_declaration().unwrap();
113                                    if subscript.span.contains_line_col(line_col) {
114                                        if subscript.expression().span().contains_line_col(line_col) {
115                                            return handle_subscript(&subscript);
116                                        } else {
117                                            return default;
118                                        }
119                                    } else {
120                                        if let Some(subscript_function) = struct_declaration.function_declarations().find(|f| {
121                                            f.r#static == false && f.identifier().name() == "subscript"
122                                        }) {
123                                            current = Some(UnitSearchResult::Type(subscript_function.return_type().resolved().clone()));
124                                        } else {
125                                            return default;
126                                        }
127                                    }
128                                }
129                                _ => unreachable!(),
130                            }
131                        } else {
132                            return default;
133                        }
134                    }
135                    UnitSearchResult::Reference(current_reference) => {
136                        match schema.find_top_by_path(&current_reference).unwrap() {
137                            Node::StructDeclaration(struct_declaration) => {
138                                match &expression.kind {
139                                    ExpressionKind::ArgumentList(argument_list) => {
140                                        if let Some(new) = struct_declaration.function_declarations().find(|f| f.r#static && f.identifier().name() == "new") {
141                                            if argument_list.span.contains_line_col(line_col) {
142                                                return handle_argument_list(argument_list, &struct_declaration.path, Some(new.identifier().name()));
143                                            } else {
144                                                current = Some(UnitSearchResult::Type(new.return_type().resolved().clone()));
145                                            }
146                                        } else {
147                                            return default;
148                                        }
149                                    }
150                                    ExpressionKind::Subscript(_s) => {
151                                        return default;
152                                    }
153                                    ExpressionKind::Identifier(_i) => {
154                                        return default;
155                                    }
156                                    _ => unreachable!()
157                                }
158                            },
159                            Node::Config(config) => {
160                                match &expression.kind {
161                                    ExpressionKind::Identifier(identifier) => {
162                                        if let Some(item) = config.items().iter().find(|(k, v)| k.named_key_without_resolving().is_some() && k.named_key_without_resolving().unwrap() == identifier.name()) {
163                                            if identifier.span.contains_line_col(line_col) {
164                                                return handle_identifier(identifier.span, config.path.as_ref(), item.0.named_key_without_resolving());
165                                            } else {
166                                                current = Some(UnitSearchResult::Type(item.1.resolved().r#type.clone()));
167                                            }
168                                        } else {
169                                            return default;
170                                        }
171                                    },
172                                    ExpressionKind::ArgumentList(_a) => {
173                                        return default;
174                                    }
175                                    ExpressionKind::Subscript(_s) => {
176                                        return default;
177                                    }
178                                    _ => unreachable!()
179                                }
180                            }
181                            Node::Enum(r#enum) => {
182                                match &expression.kind {
183                                    ExpressionKind::Identifier(i) => {
184                                        if let Some(member) = r#enum.members().find(|m| m.identifier().name() == i.name()) {
185                                            if i.span.contains_line_col(line_col) {
186                                                return handle_identifier(i.span, r#enum.path.as_ref(), Some(member.identifier().name()));
187                                            } else {
188                                                return default;
189                                            }
190                                        } else {
191                                            return default;
192                                        }
193                                    }
194                                    ExpressionKind::ArgumentList(_a) => {
195                                        return default;
196                                    }
197                                    ExpressionKind::Subscript(_s) => {
198                                        return default;
199                                    }
200                                    _ => unreachable!()
201                                }
202                            }
203                            Node::Model(model) => {
204                                match &expression.kind {
205                                    ExpressionKind::Identifier(identifier) => {
206                                        if let Some(field) = model.fields().find(|f| f.name() == identifier.name()) {
207                                            if identifier.span.contains_line_col(line_col) {
208                                                return handle_identifier(identifier.span, model.path.as_ref(), Some(field.name()));
209                                            } else {
210                                                return default;
211                                            }
212                                        } else {
213                                            return default;
214                                        }
215                                    },
216                                    ExpressionKind::ArgumentList(_a) => {
217                                        return default;
218                                    }
219                                    ExpressionKind::Subscript(_s) => {
220                                        return default;
221                                    }
222                                    _ => unreachable!()
223                                }
224                            }
225                            Node::InterfaceDeclaration(interface) => {
226                                match &expression.kind {
227                                    ExpressionKind::Identifier(identifier) => {
228                                        if let Some(field) = interface.fields().find(|f| f.name() == identifier.name()) {
229                                            if identifier.span.contains_line_col(line_col) {
230                                                return handle_identifier(identifier.span, interface.path.as_ref(), Some(field.name()));
231                                            } else {
232                                                return default;
233                                            }
234                                        } else {
235                                            return default;
236                                        }
237                                    },
238                                    ExpressionKind::ArgumentList(_a) => {
239                                        return default;
240                                    }
241                                    ExpressionKind::Subscript(_s) => {
242                                        return default;
243                                    }
244                                    _ => unreachable!()
245                                }
246                            }
247                            Node::Namespace(namespace) => {
248                                match &expression.kind {
249                                    ExpressionKind::Identifier(identifier) => {
250                                        if let Some(top) = namespace.find_top_by_name(identifier.name(), &top_filter_for_reference_type(ReferenceSpace::Default), availability) {
251                                            if identifier.span.contains_line_col(line_col) {
252                                                return handle_identifier(identifier.span, top.path(), None);
253                                            } else {
254                                                return default;
255                                            }
256                                        } else {
257                                            return default;
258                                        }
259                                    },
260                                    ExpressionKind::ArgumentList(_a) => {
261                                        return default;
262                                    }
263                                    ExpressionKind::Subscript(_s) => {
264                                        return default;
265                                    }
266                                    _ => unreachable!()
267                                }
268                            }
269                            _ => unreachable!()
270                        }
271                    }
272                }
273            } else {
274                return default
275            }
276        }
277    }
278    default
279}