teo_parser/search/
search_unit_for_definition.rs1use 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(¤t_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}