LCOV - code coverage report
Current view: top level - src/visitors/typeAnalysis - typeAnalysisUserTypes.cc (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 335 0
Test Date: 2025-04-18 15:53:49 Functions: 0.0 % 9 0

            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 &params = 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
        

Generated by: LCOV version 2.0-1