Line data Source code
1 : #include "../../../inc/parsingAnalysis/ast/userTypes/ast_attrAccess.h"
2 : #include "../../../inc/parsingAnalysis/ast/userTypes/ast_constructorCall.h"
3 : #include "../../../inc/parsingAnalysis/ast/userTypes/ast_methodCall.h"
4 : #include "../../../inc/parsingAnalysis/ast/userTypes/ast_struct.h"
5 : #include "../../../inc/parsingAnalysis/ast/userTypes/ast_this.h"
6 : #include "../../../inc/visitors/typeAnalysis/typeAnalysis.h"
7 : #include <cstddef>
8 : #include <memory>
9 : #include <vector>
10 :
11 : namespace nicole {
12 :
13 : /*
14 : - comprobar tipo atributos no sea void ni puntero a est, comprobar si es generic
15 : - comrpobar metodos
16 : - comproabr constructor
17 : - comprobar destructor
18 : - retorna NoPropagate
19 : */
20 : std::expected<std::shared_ptr<Type>, Error>
21 0 : TypeAnalysis::visit(const AST_STRUCT *node) const noexcept {
22 0 : if (!node) {
23 0 : return createError(ERROR_TYPE::NULL_NODE, "invalid AST_STRUCT");
24 0 : }
25 0 : if (!node->generics().empty()) {
26 0 : insideDeclWithGenerics = true;
27 0 : currentGenericList_ = node->generics();
28 0 : }
29 :
30 0 : firstBody = false;
31 0 : analyzingInsideClass = true;
32 :
33 0 : if (node->constructor()) {
34 0 : auto consRes = node->constructor()->accept(*this);
35 0 : if (!consRes)
36 0 : return createError(consRes.error());
37 0 : }
38 :
39 0 : if (node->destructor()) {
40 0 : auto destrRes = node->destructor()->accept(*this);
41 0 : if (!destrRes)
42 0 : return createError(destrRes.error());
43 0 : }
44 :
45 0 : for (const auto &method : node->methods()) {
46 0 : auto methodRes = method->accept(*this);
47 0 : if (!methodRes)
48 0 : return createError(methodRes.error());
49 0 : }
50 :
51 0 : insideDeclWithGenerics = false;
52 0 : currentGenericList_.clear();
53 0 : analyzingInsideClass = false;
54 0 : firstBody = true;
55 0 : node->setReturnedFromAnalysis(typeTable_->noPropagateType());
56 0 : return typeTable_->noPropagateType();
57 0 : }
58 :
59 : /*
60 : - comprobar que sea genric
61 : - se apoya en currentType para saber si el atributo existe y retorna el tipo
62 : */
63 : std::expected<std::shared_ptr<Type>, Error>
64 0 : TypeAnalysis::visit(const AST_ATTR_ACCESS *node) const noexcept {
65 0 : if (!node) {
66 0 : return createError(ERROR_TYPE::NULL_NODE, "invalid AST_ATTR_ACCESS");
67 0 : }
68 0 : if (!currentType_)
69 0 : return createError(ERROR_TYPE::TYPE,
70 0 : "current type not set for attribute access");
71 :
72 0 : auto baseType = currentType_;
73 :
74 0 : if (insideDeclWithGenerics &&
75 0 : typeTable_->isGenericType(baseType, currentGenericList_)) {
76 0 : node->setReturnedFromAnalysis(baseType);
77 0 : return baseType;
78 0 : }
79 :
80 0 : auto userType = std::dynamic_pointer_cast<UserType>(baseType);
81 0 : if (!userType)
82 0 : return createError(ERROR_TYPE::TYPE,
83 0 : "attribute access requires a user-defined type");
84 :
85 0 : auto attrRes = userType->getAttribute(node->id());
86 0 : if (!attrRes)
87 0 : return createError(attrRes.error());
88 0 : auto attrType = attrRes.value().type();
89 : /*
90 : if (insideDeclWithGenerics &&
91 : typeTable_->isGenericType(attrType, currentGenericList_))
92 : attrType = std::make_shared<PlaceHolder>(attrType);
93 : */
94 0 : currentType_ = attrType;
95 0 : node->setReturnedFromAnalysis(attrType);
96 0 : return attrType;
97 0 : }
98 :
99 : /*
100 : - tener en cuenta generics
101 : - se apoya en currentType para saber si el metodo existe y retorna el tipo
102 : - igual que funcion
103 : */
104 : std::expected<std::shared_ptr<Type>, Error>
105 0 : TypeAnalysis::visit(const AST_METHOD_CALL *node) const noexcept {
106 0 : if (!node) {
107 0 : return createError(ERROR_TYPE::NULL_NODE, "Invalid AST_METHOD_CALL");
108 0 : }
109 :
110 0 : std::vector<std::shared_ptr<Type>> argTypes;
111 0 : for (const auto &expr : node->parameters()) {
112 0 : auto res = expr->accept(*this);
113 0 : if (!res)
114 0 : return createError(res.error());
115 0 : argTypes.push_back(res.value());
116 0 : }
117 :
118 0 : if (!currentType_)
119 0 : return createError(ERROR_TYPE::TYPE,
120 0 : "current type not set for method call");
121 :
122 0 : auto userType = std::dynamic_pointer_cast<UserType>(currentType_);
123 0 : if (!userType)
124 0 : return createError(ERROR_TYPE::TYPE,
125 0 : "method call requires a user-defined type");
126 :
127 0 : auto methodsExp = userType->getMethods(node->id());
128 0 : if (!methodsExp)
129 0 : return createError(methodsExp.error());
130 0 : auto methods = methodsExp.value();
131 0 : if (methods.empty())
132 0 : return createError(ERROR_TYPE::METHOD,
133 0 : "no method with id: " + node->id() + " exists");
134 :
135 0 : std::vector<Method> viableMethods;
136 0 : const auto &explicitGenerics = node->replaceOfGenerics();
137 :
138 0 : for (const auto &method : methods) {
139 : // Check if method generics match the explicit generics, if provided.
140 0 : if (!explicitGenerics.empty() &&
141 0 : method.generics().size() != explicitGenerics.size())
142 0 : continue;
143 : // Check parameter count.
144 0 : if (method.params().size() != argTypes.size())
145 0 : continue;
146 0 : bool candidateMatches = true;
147 0 : const auto ¶ms = method.params().params();
148 0 : for (size_t i = 0; i < params.size(); ++i) {
149 0 : auto paramType = params[i].second;
150 0 : auto argType = argTypes[i];
151 : // For generics, if either the parameter or argument type is still
152 : // generic, we skip the strict check here.
153 0 : if (insideDeclWithGenerics &&
154 0 : (typeTable_->isGenericType(paramType, currentGenericList_) ||
155 0 : typeTable_->isGenericType(argType, currentGenericList_))) {
156 0 : continue;
157 0 : }
158 0 : if (!typeTable_->canAssign(paramType, argType)) {
159 0 : candidateMatches = false;
160 0 : break;
161 0 : }
162 0 : }
163 0 : if (candidateMatches)
164 0 : viableMethods.push_back(method);
165 0 : }
166 :
167 0 : if (viableMethods.empty())
168 0 : return createError(ERROR_TYPE::METHOD,
169 0 : "no matching method found for call: " + node->id());
170 0 : if (viableMethods.size() > 1)
171 0 : return createError(ERROR_TYPE::METHOD,
172 0 : "ambiguous method call for: " + node->id());
173 0 : const auto returnType{viableMethods.front().returnType()};
174 0 : currentType_ = returnType;
175 0 : node->setReturnedFromAnalysis(returnType);
176 0 : return returnType;
177 0 : }
178 :
179 : /*
180 : - igual que funcion
181 : */
182 : std::expected<std::shared_ptr<Type>, Error>
183 0 : TypeAnalysis::visit(const AST_METHOD_DECL *node) const noexcept {
184 0 : if (!node) {
185 0 : return createError(ERROR_TYPE::NULL_NODE, "Invalid AST_METHOD_DECL");
186 0 : }
187 0 : if (!node->generics().empty()) {
188 0 : insideDeclWithGenerics = true;
189 0 : currentGenericList_ =
190 0 : mergeGenericLists(currentStructGenericList_, node->generics());
191 0 : }
192 :
193 0 : auto bodyRes = node->body()->accept(*this);
194 0 : if (!bodyRes)
195 0 : return createError(bodyRes.error());
196 0 : auto bodyType = bodyRes.value();
197 :
198 0 : auto voidType = typeTable_->voidType();
199 0 : auto declaredReturnType = node->returnType();
200 :
201 0 : if (typeTable_->areSameType(bodyType, typeTable_->noPropagateType()) ||
202 0 : typeTable_->areSameType(bodyType, voidType)) {
203 0 : if (!typeTable_->areSameType(declaredReturnType, voidType)) {
204 0 : return createError(ERROR_TYPE::TYPE,
205 0 : "function body returns void/noPropagate, but function "
206 0 : "return type is: " +
207 0 : declaredReturnType->toString());
208 0 : }
209 0 : } else {
210 0 : if (!typeTable_->canAssign(declaredReturnType, bodyType)) {
211 0 : return createError(
212 0 : ERROR_TYPE::TYPE,
213 0 : "function body return type does not match declared return type -> " +
214 0 : declaredReturnType->toString() + " | " + bodyType->toString());
215 0 : }
216 0 : }
217 :
218 0 : insideDeclWithGenerics = false;
219 0 : currentGenericList_.clear();
220 0 : node->setReturnedFromAnalysis(typeTable_->noPropagateType());
221 0 : return typeTable_->noPropagateType();
222 0 : }
223 :
224 : /*
225 : - igual que funcion
226 : */
227 : std::expected<std::shared_ptr<Type>, Error>
228 0 : TypeAnalysis::visit(const AST_CONSTRUCTOR_DECL *node) const noexcept {
229 0 : if (!node) {
230 0 : return createError(ERROR_TYPE::NULL_NODE, "Invalid AST_CONSTRUCTOR_DECL");
231 0 : }
232 :
233 0 : if (!node->generics().empty()) {
234 0 : insideDeclWithGenerics = true;
235 0 : currentGenericList_ =
236 0 : mergeGenericLists(currentStructGenericList_, node->generics());
237 0 : }
238 :
239 0 : auto bodyRes = node->body()->accept(*this);
240 0 : if (!bodyRes)
241 0 : return createError(bodyRes.error());
242 0 : auto bodyType = bodyRes.value();
243 :
244 0 : if (!typeTable_->areSameType(bodyType, typeTable_->noPropagateType()) &&
245 0 : !typeTable_->areSameType(bodyType, typeTable_->breakType()))
246 0 : return createError(ERROR_TYPE::TYPE,
247 0 : "constructor body must not return a value");
248 :
249 0 : insideDeclWithGenerics = false;
250 0 : currentGenericList_.clear();
251 0 : node->setReturnedFromAnalysis(typeTable_->noPropagateType());
252 0 : return typeTable_->noPropagateType();
253 0 : }
254 :
255 : /*
256 : - retorna el tipo del padre
257 : - comprobar generics y argumentos
258 : */
259 : std::expected<std::shared_ptr<Type>, Error>
260 0 : TypeAnalysis::visit(const AST_SUPER *node) const noexcept {
261 0 : if (!node) {
262 0 : return createError(ERROR_TYPE::NULL_NODE, "invalid AST_SUPER");
263 0 : }
264 0 : for (const auto &arg : node->arguments()) {
265 0 : auto res = arg->accept(*this);
266 0 : if (!res)
267 0 : return createError(res.error());
268 0 : }
269 :
270 0 : std::vector<std::shared_ptr<Type>> processedReplacements;
271 0 : for (const auto &rep : node->replacements()) {
272 0 : std::shared_ptr<Type> proc = rep;
273 : /*
274 : if (insideDeclWithGenerics &&
275 : typeTable_->isGenericType(rep, currentGenericList_))
276 : proc = std::make_shared<PlaceHolder>(rep);
277 : */
278 0 : processedReplacements.push_back(proc);
279 0 : }
280 :
281 0 : auto fatherType = node->fatherType();
282 0 : if (!fatherType)
283 0 : return createError(ERROR_TYPE::TYPE,
284 0 : "father type not specified in super call");
285 :
286 0 : if (!processedReplacements.empty()) {
287 0 : auto userType = std::dynamic_pointer_cast<UserType>(fatherType);
288 0 : if (!userType)
289 0 : return createError(
290 0 : ERROR_TYPE::TYPE,
291 0 : "father type in super call must be a user-defined type");
292 0 : const auto instance{
293 0 : std::make_shared<GenericInstanceType>(userType, processedReplacements)};
294 0 : node->setReturnedFromAnalysis(instance);
295 0 : return instance;
296 0 : }
297 0 : const auto result{typeTable_->getType(fatherType->toString())};
298 0 : if (!result) {
299 0 : return createError(result.error());
300 0 : }
301 0 : node->setReturnedFromAnalysis(*result);
302 0 : return result;
303 0 : }
304 :
305 : /*
306 : - comprobar body
307 : - retorna NoPropagate
308 : */
309 : std::expected<std::shared_ptr<Type>, Error>
310 0 : TypeAnalysis::visit(const AST_DESTRUCTOR_DECL *node) const noexcept {
311 0 : if (!node) {
312 0 : return createError(ERROR_TYPE::NULL_NODE, "Invalid AST_DESTRUCTOR_DECL");
313 0 : }
314 0 : const auto body{node->body()->accept(*this)};
315 0 : if (!body) {
316 0 : return createError(body.error());
317 0 : }
318 0 : node->setReturnedFromAnalysis(typeTable_->noPropagateType());
319 0 : return typeTable_->noPropagateType();
320 0 : }
321 :
322 : /*
323 : - retorna el tipo de la clase envuelto en un puntero const?
324 : */
325 : std::expected<std::shared_ptr<Type>, Error>
326 0 : TypeAnalysis::visit(const AST_THIS *node) const noexcept {
327 0 : if (!node) {
328 0 : return createError(ERROR_TYPE::NULL_NODE, "invalid AST_THIS");
329 0 : }
330 0 : if (!node->userType())
331 0 : return createError(ERROR_TYPE::TYPE, "user type not set for 'this'");
332 :
333 0 : auto typeFromTable = typeTable_->getType(node->userType()->name());
334 0 : if (!typeFromTable)
335 0 : return createError(typeFromTable.error());
336 0 : auto userType = std::dynamic_pointer_cast<UserType>(*typeFromTable);
337 0 : if (!userType)
338 0 : return createError(ERROR_TYPE::TYPE,
339 0 : "'this' must refer to a user-defined type");
340 :
341 0 : auto constType =
342 0 : std::make_shared<ConstType>(std::make_shared<PointerType>(userType));
343 0 : node->setReturnedFromAnalysis(constType);
344 0 : return std::make_shared<ConstType>(constType);
345 0 : }
346 :
347 : /*
348 : - comprueba generics
349 : - comprueba argumentos
350 : - comprueba body
351 : */
352 : std::expected<std::shared_ptr<Type>, Error>
353 0 : TypeAnalysis::visit(const AST_CONSTRUCTOR_CALL *node) const noexcept {
354 0 : if (!node)
355 0 : return createError(ERROR_TYPE::NULL_NODE, "Invalid AST_CONSTRUCTOR_CALL");
356 :
357 0 : auto tempUserType = std::make_shared<UserType>(
358 0 : node->id(), nullptr, std::vector<GenericParameter>{});
359 0 : if (insideDeclWithGenerics &&
360 0 : typeTable_->isGenericType(tempUserType, currentGenericList_)) {
361 0 : if (!node->replaceOfGenerics().empty()) {
362 0 : std::vector<std::shared_ptr<Type>> genericArgs;
363 0 : for (const auto &gen : node->replaceOfGenerics()) {
364 0 : if (insideDeclWithGenerics &&
365 0 : typeTable_->isGenericType(gen, currentGenericList_)) {
366 0 : genericArgs.push_back(gen);
367 0 : } else
368 0 : genericArgs.push_back(gen);
369 0 : }
370 0 : const auto instance{
371 0 : std::make_shared<GenericInstanceType>(tempUserType, genericArgs)};
372 0 : currentType_ = instance;
373 0 : node->setReturnedFromAnalysis(instance);
374 0 : return instance;
375 0 : } else {
376 0 : currentType_ = tempUserType;
377 0 : node->setReturnedFromAnalysis(tempUserType);
378 0 : return tempUserType;
379 0 : }
380 0 : }
381 :
382 0 : std::vector<std::shared_ptr<Type>> argTypes;
383 0 : for (const auto &expr : node->parameters()) {
384 0 : auto res = expr->accept(*this);
385 0 : if (!res)
386 0 : return createError(res.error());
387 0 : argTypes.push_back(res.value());
388 0 : }
389 :
390 0 : auto baseTypeExp = typeTable_->getType(node->id());
391 0 : if (!baseTypeExp)
392 0 : return createError(baseTypeExp.error());
393 0 : auto baseType = baseTypeExp.value();
394 :
395 0 : if (const auto enumType{std::dynamic_pointer_cast<EnumType>(baseType)}) {
396 0 : if (argTypes.size() != 1) {
397 0 : return createError(
398 0 : ERROR_TYPE::TYPE,
399 0 : "constructor call of a enum must have one argument of the same type");
400 0 : }
401 0 : if (!typeTable_->canAssign(enumType, argTypes[0])) {
402 0 : return createError(
403 0 : ERROR_TYPE::TYPE,
404 0 : "constructor call of a enum must have one argument of the same type");
405 0 : }
406 0 : node->setReturnedFromAnalysis(enumType);
407 0 : return enumType;
408 0 : }
409 :
410 0 : auto userType = std::dynamic_pointer_cast<UserType>(baseType);
411 0 : if (!userType)
412 0 : return createError(ERROR_TYPE::TYPE,
413 0 : "constructor call id must refer to a user-defined type");
414 :
415 0 : auto cons = userType->constructor();
416 0 : if (!cons)
417 0 : return createError(ERROR_TYPE::FUNCTION,
418 0 : "no constructor defined for type: " + userType->name());
419 :
420 0 : if (cons->params().size() != argTypes.size())
421 0 : return createError(ERROR_TYPE::FUNCTION,
422 0 : "constructor parameter count mismatch for type: " +
423 0 : userType->name());
424 :
425 0 : const auto &consParams = cons->params().params();
426 0 : for (size_t i = 0; i < consParams.size(); ++i) {
427 0 : auto paramType = consParams[i].second;
428 0 : auto argType = argTypes[i];
429 0 : if (!typeTable_->canAssign(paramType, argType))
430 0 : return createError(ERROR_TYPE::TYPE,
431 0 : "argument " + std::to_string(i) +
432 0 : " type mismatch in constructor call for type: " +
433 0 : userType->name());
434 0 : }
435 :
436 0 : if (!node->replaceOfGenerics().empty()) {
437 0 : std::vector<std::shared_ptr<Type>> genericArgs;
438 0 : for (const auto &gen : node->replaceOfGenerics()) {
439 0 : if (insideDeclWithGenerics &&
440 0 : typeTable_->isGenericType(gen, currentGenericList_)) {
441 0 : genericArgs.push_back(gen);
442 0 : } else
443 0 : genericArgs.push_back(gen);
444 0 : }
445 0 : const auto instance{
446 0 : std::make_shared<GenericInstanceType>(userType, genericArgs)};
447 0 : currentType_ = instance;
448 0 : node->setReturnedFromAnalysis(instance);
449 0 : return instance;
450 0 : }
451 0 : currentType_ = userType;
452 0 : node->setReturnedFromAnalysis(userType);
453 0 : return userType;
454 0 : }
455 :
456 : } // namespace nicole
|