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

            Line data    Source code
       1              : #include "../../../inc/tables/typeTable/typeTable.h"
       2              : #include <memory>
       3              : #include <vector>
       4              : 
       5              : namespace nicole {
       6              : 
       7            0 : bool TypeTable::has(const std::string &id) const noexcept {
       8            0 :   return table_.count(id);
       9            0 : }
      10              : 
      11              : const std::expected<std::shared_ptr<Type>, Error>
      12            0 : TypeTable::getType(const std::string &id) const noexcept {
      13            0 :   if (has(id)) {
      14            0 :     return table_.at(id);
      15            0 :   }
      16            0 :   return createError(ERROR_TYPE::TYPE, "the type: " + id + " does not exists");
      17            0 : }
      18              : 
      19              : std::expected<std::monostate, Error>
      20            0 : TypeTable::insert(const std::shared_ptr<Type> &type) noexcept {
      21            0 :   if (has(type->toString())) {
      22            0 :     return createError(ERROR_TYPE::TYPE,
      23            0 :                        "the type: " + type->toString() + " already exists");
      24            0 :   }
      25            0 :   if (const auto &enumType = std::dynamic_pointer_cast<EnumType>(type)) {
      26            0 :     table_[enumType->name()] = type;
      27            0 :     return {};
      28            0 :   }
      29            0 :   const auto &userType = std::dynamic_pointer_cast<UserType>(type);
      30            0 :   table_[userType->name()] = type;
      31            0 :   return {};
      32            0 : }
      33              : 
      34              : bool TypeTable::isPossibleType(
      35            0 :     const std::shared_ptr<Type> &type) const noexcept {
      36            0 :   if (const auto &basicType = std::dynamic_pointer_cast<BasicType>(type)) {
      37            0 :     return true;
      38            0 :   } else if (const auto &voidType = std::dynamic_pointer_cast<VoidType>(type)) {
      39            0 :     return true;
      40            0 :   } else if (const auto &vectorType =
      41            0 :                  std::dynamic_pointer_cast<VectorType>(type)) {
      42            0 :     return isPossibleType(vectorType->elementType());
      43            0 :   } else if (const auto &pointerType =
      44            0 :                  std::dynamic_pointer_cast<PointerType>(type)) {
      45            0 :     return isPossibleType(pointerType->baseType());
      46            0 :   } else if (const auto &constType =
      47            0 :                  std::dynamic_pointer_cast<ConstType>(type)) {
      48            0 :     return isPossibleType(constType->baseType());
      49            0 :   } else if (const auto &nullType = std::dynamic_pointer_cast<NullType>(type)) {
      50            0 :     return true;
      51            0 :   } else if (const auto &enumType = std::dynamic_pointer_cast<EnumType>(type)) {
      52            0 :     if (!has(enumType->name())) {
      53            0 :       return false;
      54            0 :     }
      55            0 :     return true;
      56            0 :   } else if (const auto &genericInstanceType =
      57            0 :                  std::dynamic_pointer_cast<GenericInstanceType>(type)) {
      58            0 :     if (!has(genericInstanceType->name())) {
      59            0 :       return false;
      60            0 :     }
      61            0 :     for (const auto &arg : genericInstanceType->typeArgs()) {
      62            0 :       if (!isPossibleType(arg)) {
      63            0 :         return false;
      64            0 :       }
      65            0 :     }
      66            0 :     return true;
      67            0 :   } else if (const auto &userType = std::dynamic_pointer_cast<UserType>(type)) {
      68            0 :     if (!has(userType->name())) {
      69            0 :       return false;
      70            0 :     }
      71            0 :     return true;
      72            0 :   }
      73            0 :   return false;
      74            0 : }
      75              : 
      76              : bool TypeTable::isGenericType(
      77              :     const std::shared_ptr<Type> &type,
      78            0 :     const std::vector<GenericParameter> &generics) const noexcept {
      79            0 :   if (const auto &vectorType = std::dynamic_pointer_cast<VectorType>(type)) {
      80            0 :     return isGenericType(vectorType->elementType(), generics);
      81            0 :   } else if (const auto &pointerType =
      82            0 :                  std::dynamic_pointer_cast<PointerType>(type)) {
      83            0 :     return isGenericType(pointerType->baseType(), generics);
      84            0 :   } else if (const auto &constType =
      85            0 :                  std::dynamic_pointer_cast<ConstType>(type)) {
      86            0 :     return isGenericType(constType->baseType(), generics);
      87            0 :   } else if (const auto &enumType = std::dynamic_pointer_cast<EnumType>(type)) {
      88            0 :     for (const auto &generic : generics) {
      89            0 :       if (generic.name() == enumType->name()) {
      90            0 :         return true;
      91            0 :       }
      92            0 :     }
      93            0 :     return false;
      94            0 :   } else if (const auto &genericInstanceType =
      95            0 :                  std::dynamic_pointer_cast<GenericInstanceType>(type)) {
      96            0 :     if (!has(genericInstanceType->name())) {
      97            0 :       return false;
      98            0 :     }
      99            0 :     for (const auto &arg : genericInstanceType->typeArgs()) {
     100            0 :       if (!isGenericType(arg, generics)) {
     101            0 :         return false;
     102            0 :       }
     103            0 :     }
     104            0 :     return true;
     105            0 :   } else if (const auto &userType = std::dynamic_pointer_cast<UserType>(type)) {
     106            0 :     for (const auto &generic : generics) {
     107            0 :       if (generic.name() == userType->name()) {
     108            0 :         return true;
     109            0 :       }
     110            0 :     }
     111            0 :     return false;
     112            0 :   }
     113            0 :   return false;
     114            0 : }
     115              : 
     116              : std::expected<std::shared_ptr<Type>, Error>
     117            0 : TypeTable::isCompundEnumType(const std::shared_ptr<Type> &type) const noexcept {
     118            0 :   if (auto constType = std::dynamic_pointer_cast<ConstType>(type)) {
     119            0 :     auto baseRes = isCompundEnumType(constType->baseType());
     120            0 :     if (!baseRes)
     121            0 :       return createError(baseRes.error());
     122            0 :     return std::make_shared<ConstType>(baseRes.value());
     123            0 :   }
     124            0 :   if (auto pointerType = std::dynamic_pointer_cast<PointerType>(type)) {
     125            0 :     auto baseRes = isCompundEnumType(pointerType->baseType());
     126            0 :     if (!baseRes)
     127            0 :       return createError(baseRes.error());
     128            0 :     return std::make_shared<PointerType>(baseRes.value());
     129            0 :   }
     130            0 :   if (auto vectorType = std::dynamic_pointer_cast<VectorType>(type)) {
     131            0 :     auto baseRes = isCompundEnumType(vectorType->elementType());
     132            0 :     if (!baseRes)
     133            0 :       return createError(baseRes.error());
     134            0 :     return std::make_shared<VectorType>(baseRes.value());
     135            0 :   }
     136            0 :   if (auto genericInstanceType =
     137            0 :           std::dynamic_pointer_cast<GenericInstanceType>(type)) {
     138            0 :     auto exists = getType(genericInstanceType->name());
     139            0 :     if (!exists)
     140            0 :       return createError(exists.error());
     141            0 :     const auto generciList{genericInstanceType->typeArgs()};
     142            0 :     for (std::size_t i{0}; i < generciList.size(); ++i) {
     143            0 :       auto maskedEnum = isCompundEnumType(generciList[i]);
     144            0 :       if (maskedEnum) {
     145            0 :         std::cout << i << " " << maskedEnum.value()->toString();
     146            0 :         const auto replaced{
     147            0 :             genericInstanceType->setGenericReplacement(i, *maskedEnum)};
     148            0 :         if (!replaced) {
     149            0 :           return createError(replaced.error());
     150            0 :         }
     151            0 :       }
     152            0 :     }
     153            0 :     return genericInstanceType;
     154            0 :   }
     155            0 :   if (auto userType = std::dynamic_pointer_cast<UserType>(type)) {
     156            0 :     auto exists = getType(userType->name());
     157            0 :     if (!exists)
     158            0 :       return createError(exists.error());
     159            0 :     if (auto enumType = std::dynamic_pointer_cast<EnumType>(exists.value()))
     160            0 :       return enumType;
     161            0 :     else
     162            0 :       return createError(ERROR_TYPE::TYPE,
     163            0 :                          "El tipo encontrado no es un EnumType");
     164            0 :   }
     165            0 :   return createError(ERROR_TYPE::TYPE, "El tipo no es un Enum compuesto");
     166            0 : }
     167              : 
     168              : std::expected<std::shared_ptr<Type>, Error> TypeTable::isCompundGenericType(
     169              :     const std::shared_ptr<Type> &type,
     170            0 :     const std::vector<GenericParameter> &genericList) const noexcept {
     171            0 :   if (auto constType = std::dynamic_pointer_cast<ConstType>(type)) {
     172            0 :     auto baseRes = isCompundGenericType(constType->baseType(), genericList);
     173            0 :     if (!baseRes)
     174            0 :       return createError(baseRes.error());
     175            0 :     return std::make_shared<ConstType>(baseRes.value());
     176            0 :   }
     177              : 
     178            0 :   if (auto pointerType = std::dynamic_pointer_cast<PointerType>(type)) {
     179            0 :     auto baseRes = isCompundGenericType(pointerType->baseType(), genericList);
     180            0 :     if (!baseRes)
     181            0 :       return createError(baseRes.error());
     182            0 :     return std::make_shared<PointerType>(baseRes.value());
     183            0 :   }
     184              : 
     185            0 :   if (auto vectorType = std::dynamic_pointer_cast<VectorType>(type)) {
     186            0 :     auto baseRes = isCompundGenericType(vectorType->elementType(), genericList);
     187            0 :     if (!baseRes)
     188            0 :       return createError(baseRes.error());
     189            0 :     return std::make_shared<VectorType>(baseRes.value());
     190            0 :   }
     191              : 
     192            0 :   if (auto genericInstanceType =
     193            0 :           std::dynamic_pointer_cast<GenericInstanceType>(type)) {
     194            0 :     for (const auto &gp : genericList) {
     195            0 :       if (gp.name() == genericInstanceType->name()) {
     196            0 :         return std::make_shared<PlaceHolder>(gp);
     197            0 :       }
     198            0 :     }
     199            0 :     const auto typeArgs = genericInstanceType->typeArgs();
     200            0 :     for (std::size_t i = 0; i < typeArgs.size(); ++i) {
     201            0 :       auto masked = isCompundGenericType(typeArgs[i], genericList);
     202            0 :       if (!masked)
     203            0 :         return createError(masked.error());
     204            0 :       auto replaced = genericInstanceType->setGenericReplacement(i, *masked);
     205            0 :       if (!replaced)
     206            0 :         return createError(replaced.error());
     207            0 :     }
     208            0 :     return genericInstanceType;
     209            0 :   }
     210              : 
     211            0 :   if (auto userType = std::dynamic_pointer_cast<UserType>(type)) {
     212            0 :     for (const auto &gp : genericList) {
     213            0 :       if (gp.name() == userType->name()) {
     214            0 :         return std::make_shared<PlaceHolder>(gp);
     215            0 :       }
     216            0 :     }
     217            0 :     return type;
     218            0 :   }
     219            0 :   return createError(ERROR_TYPE::TYPE,
     220            0 :                      "El tipo no es un tipo compuesto genérico");
     221            0 : }
     222              : 
     223              : bool TypeTable::areSameType(const std::shared_ptr<Type> &type1,
     224            0 :                             const std::shared_ptr<Type> &type2) const noexcept {
     225              :   // Si ambos apuntan al mismo objeto, son iguales.
     226            0 :   if (type1 == type2) {
     227            0 :     return true;
     228            0 :   }
     229              :   // Si alguno es nulo, no son iguales.
     230            0 :   if (!type1 || !type2) {
     231            0 :     return false;
     232            0 :   }
     233              : 
     234              :   // Caso BasicType
     235            0 :   if (auto basic1 = std::dynamic_pointer_cast<BasicType>(type1)) {
     236            0 :     if (auto basic2 = std::dynamic_pointer_cast<BasicType>(type2)) {
     237            0 :       return basic1->baseKind() == basic2->baseKind();
     238            0 :     }
     239            0 :     return false;
     240            0 :   }
     241              : 
     242              :   // Caso VoidType
     243            0 :   if (std::dynamic_pointer_cast<VoidType>(type1)) {
     244            0 :     return std::dynamic_pointer_cast<VoidType>(type2) != nullptr;
     245            0 :   }
     246              : 
     247              :   // Caso NullType
     248            0 :   if (std::dynamic_pointer_cast<NullType>(type1)) {
     249            0 :     return std::dynamic_pointer_cast<NullType>(type2) != nullptr;
     250            0 :   }
     251              : 
     252              :   // Caso VectorType
     253            0 :   if (auto vec1 = std::dynamic_pointer_cast<VectorType>(type1)) {
     254            0 :     if (auto vec2 = std::dynamic_pointer_cast<VectorType>(type2)) {
     255            0 :       return areSameType(vec1->elementType(), vec2->elementType());
     256            0 :     }
     257            0 :     return false;
     258            0 :   }
     259              : 
     260              :   // Caso PointerType
     261            0 :   if (auto ptr1 = std::dynamic_pointer_cast<PointerType>(type1)) {
     262            0 :     if (auto ptr2 = std::dynamic_pointer_cast<PointerType>(type2)) {
     263            0 :       return areSameType(ptr1->baseType(), ptr2->baseType());
     264            0 :     }
     265            0 :     return false;
     266            0 :   }
     267              : 
     268              :   // Caso ConstType
     269            0 :   if (auto const1 = std::dynamic_pointer_cast<ConstType>(type1)) {
     270            0 :     if (auto const2 = std::dynamic_pointer_cast<ConstType>(type2)) {
     271            0 :       return areSameType(const1->baseType(), const2->baseType());
     272            0 :     }
     273            0 :     return false;
     274            0 :   }
     275              : 
     276              :   // Caso EnumType
     277            0 :   if (auto enum1 = std::dynamic_pointer_cast<EnumType>(type1)) {
     278            0 :     if (auto enum2 = std::dynamic_pointer_cast<EnumType>(type2)) {
     279            0 :       return enum1->name() == enum2->name();
     280            0 :     }
     281            0 :     return false;
     282            0 :   }
     283              : 
     284              :   // Caso GenericInstanceType
     285            0 :   if (auto genInst1 = std::dynamic_pointer_cast<GenericInstanceType>(type1)) {
     286            0 :     if (auto genInst2 = std::dynamic_pointer_cast<GenericInstanceType>(type2)) {
     287              :       // Se comparan primero los tipos genéricos base
     288            0 :       if (genInst1->name() != genInst2->name()) {
     289            0 :         return false;
     290            0 :       }
     291            0 :       const auto &args1 = genInst1->typeArgs();
     292            0 :       const auto &args2 = genInst2->typeArgs();
     293            0 :       if (args1.size() != args2.size()) {
     294            0 :         return false;
     295            0 :       }
     296            0 :       for (size_t i = 0; i < args1.size(); ++i) {
     297            0 :         if (!areSameType(args1[i], args2[i])) {
     298            0 :           return false;
     299            0 :         }
     300            0 :       }
     301            0 :       return true;
     302            0 :     }
     303            0 :     return false;
     304            0 :   }
     305              : 
     306              :   // Caso UserType
     307            0 :   if (auto user1 = std::dynamic_pointer_cast<UserType>(type1)) {
     308            0 :     if (auto user2 = std::dynamic_pointer_cast<UserType>(type2)) {
     309            0 :       return user1->name() == user2->name();
     310            0 :     }
     311            0 :     return false;
     312            0 :   }
     313              : 
     314              :   // Si no se reconoce el tipo, se compara mediante su representación canónica.
     315            0 :   return type1->toString() == type2->toString();
     316            0 : }
     317              : 
     318              : bool TypeTable::canAssign(const std::shared_ptr<Type> &target,
     319            0 :                           const std::shared_ptr<Type> &source) const noexcept {
     320            0 :   return canAssignImpl(target, source, false);
     321            0 : }
     322              : 
     323              : bool TypeTable::canAssignImpl(const std::shared_ptr<Type> &target,
     324              :                               const std::shared_ptr<Type> &source,
     325            0 :                               bool pointerContext) const noexcept {
     326            0 :   if (areSameType(target, source))
     327            0 :     return true;
     328              : 
     329            0 :   if (std::dynamic_pointer_cast<NullType>(source)) {
     330            0 :     if (std::dynamic_pointer_cast<PointerType>(target))
     331            0 :       return true;
     332            0 :   }
     333              : 
     334            0 :   std::shared_ptr<Type> tTarget = target;
     335            0 :   std::shared_ptr<Type> tSource = source;
     336            0 :   if (auto constTarget = std::dynamic_pointer_cast<ConstType>(target))
     337            0 :     tTarget = constTarget->baseType();
     338            0 :   if (auto constSource = std::dynamic_pointer_cast<ConstType>(source))
     339            0 :     tSource = constSource->baseType();
     340              : 
     341            0 :   if (auto targetPtr = std::dynamic_pointer_cast<PointerType>(tTarget)) {
     342            0 :     if (auto sourcePtr = std::dynamic_pointer_cast<PointerType>(tSource))
     343            0 :       return canAssignImpl(targetPtr->baseType(), sourcePtr->baseType(), true);
     344            0 :   }
     345              : 
     346            0 :   if (auto holderTarget = std::dynamic_pointer_cast<PlaceHolder>(target))
     347            0 :     return true;
     348            0 :   if (auto holderSource = std::dynamic_pointer_cast<PlaceHolder>(source))
     349            0 :     return true;
     350              : 
     351            0 :   auto targetGenInst = std::dynamic_pointer_cast<GenericInstanceType>(tTarget);
     352            0 :   auto sourceGenInst = std::dynamic_pointer_cast<GenericInstanceType>(tSource);
     353            0 :   if (targetGenInst && sourceGenInst) {
     354            0 :     if (targetGenInst->name() != sourceGenInst->name())
     355            0 :       return false;
     356            0 :     const auto &argsTarget = targetGenInst->typeArgs();
     357            0 :     const auto &argsSource = sourceGenInst->typeArgs();
     358            0 :     if (argsTarget.size() != argsSource.size())
     359            0 :       return false;
     360            0 :     for (size_t i = 0; i < argsTarget.size(); ++i) {
     361            0 :       if (!canAssignImpl(argsTarget[i], argsSource[i], pointerContext))
     362            0 :         return false;
     363            0 :     }
     364            0 :     return true;
     365            0 :   }
     366              : 
     367            0 :   if (auto targetUser = std::dynamic_pointer_cast<UserType>(tTarget)) {
     368            0 :     if (auto sourceUser = std::dynamic_pointer_cast<UserType>(tSource)) {
     369              :       // Se permite A = A sin importar el contexto.
     370            0 :       if (targetUser->name() == sourceUser->name())
     371            0 :         return true;
     372              :       // Fuera del contexto de punteros no se admite la asignación basada en
     373              :       // herencia.
     374            0 :       if (!pointerContext)
     375            0 :         return false;
     376              :       // En contexto de punteros se permite que B herede de A.
     377            0 :       for (auto current = sourceUser; current; current = current->baseType()) {
     378            0 :         if (current->name() == targetUser->name())
     379            0 :           return true;
     380            0 :       }
     381            0 :     }
     382            0 :   }
     383              : 
     384            0 :   if (auto targetBasic = std::dynamic_pointer_cast<BasicType>(tTarget)) {
     385            0 :     if (auto sourceBasic = std::dynamic_pointer_cast<BasicType>(tSource))
     386            0 :       return targetBasic->baseKind() == sourceBasic->baseKind();
     387            0 :   }
     388              : 
     389            0 :   if (auto targetEnum = std::dynamic_pointer_cast<EnumType>(tTarget)) {
     390            0 :     if (auto sourceEnum = std::dynamic_pointer_cast<EnumType>(tSource))
     391            0 :       return targetEnum->name() == sourceEnum->name();
     392            0 :   }
     393              : 
     394            0 :   if (auto targetVec = std::dynamic_pointer_cast<VectorType>(tTarget)) {
     395            0 :     if (auto sourceVec = std::dynamic_pointer_cast<VectorType>(tSource)) {
     396            0 :       if (areSameType(sourceVec->elementType(), null_)) {
     397            0 :         return true;
     398            0 :       }
     399            0 :       return canAssignImpl(targetVec->elementType(), sourceVec->elementType(),
     400            0 :                            pointerContext);
     401            0 :     }
     402            0 :   }
     403              : 
     404            0 :   return false;
     405            0 : }
     406              : 
     407              : bool TypeTable::haveCommonAncestor(
     408              :     const std::shared_ptr<Type> &type1,
     409            0 :     const std::shared_ptr<Type> &type2) const noexcept {
     410              :   // Solo tiene sentido para tipos de usuario (incluyendo GenericInstanceType,
     411              :   // que se tratan como UserType)
     412            0 :   auto user1 = std::dynamic_pointer_cast<UserType>(type1);
     413            0 :   auto user2 = std::dynamic_pointer_cast<UserType>(type2);
     414            0 :   if (user1 && user2) {
     415              :     // Comprobar si user1 es ancestro de user2
     416            0 :     for (auto current = user2; current; current = current->baseType()) {
     417            0 :       if (current->name() == user1->name()) {
     418            0 :         return true;
     419            0 :       }
     420            0 :     }
     421              :     // O si user2 es ancestro de user1
     422            0 :     for (auto current = user1; current; current = current->baseType()) {
     423            0 :       if (current->name() == user2->name()) {
     424            0 :         return true;
     425            0 :       }
     426            0 :     }
     427            0 :   }
     428            0 :   return false;
     429            0 : }
     430              : 
     431              : // these two methods are still unfinished
     432              : std::expected<std::shared_ptr<Type>, Error>
     433              : TypeTable::applyUnaryOperator(const std::shared_ptr<Type> &operand,
     434            0 :                               const TokenType op) const noexcept {
     435            0 :   if (!operand)
     436            0 :     return createError(ERROR_TYPE::TYPE, "operand is null");
     437              : 
     438            0 :   std::shared_ptr<Type> t = operand;
     439            0 :   if (auto constType = std::dynamic_pointer_cast<ConstType>(t))
     440            0 :     t = constType->baseType();
     441              : 
     442            0 :   if (std::dynamic_pointer_cast<PlaceHolder>(t))
     443            0 :     return boolType();
     444              : 
     445              :   // Si el operando es un tipo definido por el usuario, se busca el método
     446              :   // correspondiente sin parámetros.
     447            0 :   if (auto userType = std::dynamic_pointer_cast<UserType>(t)) {
     448            0 :     std::string methodName;
     449            0 :     switch (op) {
     450            0 :     case TokenType::OPERATOR_NOT:
     451            0 :       methodName = "notable";
     452            0 :       break;
     453            0 :     case TokenType::INCREMENT:
     454            0 :       methodName = "incrementable";
     455            0 :       break;
     456            0 :     case TokenType::DECREMENT:
     457            0 :       methodName = "decrementable";
     458            0 :       break;
     459            0 :     case TokenType::OPERATOR_SUB:
     460            0 :       methodName = "negable";
     461            0 :       break;
     462            0 :     default:
     463            0 :       return createError(ERROR_TYPE::TYPE,
     464            0 :                          "unsupported unary operator for user-defined type");
     465            0 :     }
     466            0 :     auto methodsExp = userType->getMethods(methodName);
     467            0 :     if (!methodsExp)
     468            0 :       return createError(methodsExp.error());
     469            0 :     auto methods = methodsExp.value();
     470            0 :     for (const auto &m : methods) {
     471            0 :       if (m.params().size() == 0) {
     472              :         // Para operator_not, el resultado debe ser bool.
     473            0 :         if (op == TokenType::OPERATOR_NOT) {
     474            0 :           auto boolTypeExp = boolType();
     475            0 :           if (!areSameType(m.returnType(), boolTypeExp))
     476            0 :             return createError(ERROR_TYPE::TYPE, "operator ! must return bool");
     477            0 :           return boolTypeExp;
     478            0 :         }
     479              :         // Para los otros operadores, se retorna el tipo que devuelve el método.
     480            0 :         return m.returnType();
     481            0 :       }
     482            0 :     }
     483            0 :     return createError(ERROR_TYPE::TYPE, "user type " + userType->name() +
     484            0 :                                              " does not support operator " +
     485            0 :                                              tokenTypeToString(op));
     486            0 :   }
     487              : 
     488              :   // Si es un PointerType.
     489            0 :   if (auto ptrType = std::dynamic_pointer_cast<PointerType>(t)) {
     490            0 :     switch (op) {
     491            0 :     case TokenType::INCREMENT:
     492            0 :     case TokenType::DECREMENT:
     493            0 :       return t; // Se retorna el mismo tipo puntero.
     494            0 :     case TokenType::OPERATOR_NOT: {
     495            0 :       return boolType();
     496            0 :     }
     497            0 :     default:
     498            0 :       return createError(ERROR_TYPE::TYPE,
     499            0 :                          "unsupported unary operator for pointer type");
     500            0 :     }
     501            0 :   }
     502              : 
     503              :   // Si es un BasicType.
     504            0 :   if (auto basic = std::dynamic_pointer_cast<BasicType>(t)) {
     505            0 :     switch (op) {
     506            0 :     case TokenType::OPERATOR_NOT: {
     507            0 :       switch (basic->baseKind()) {
     508            0 :       case BasicKind::Str:
     509            0 :         return createError(ERROR_TYPE::TYPE,
     510            0 :                            "operator " + tokenTypeToString(op) +
     511            0 :                                " cannot be applied to type " + t->toString());
     512            0 :       default:
     513            0 :         return boolType();
     514            0 :       }
     515            0 :     }
     516            0 :     case TokenType::INCREMENT:
     517            0 :     case TokenType::DECREMENT:
     518            0 :     case TokenType::OPERATOR_SUB:
     519              :       // Verificar que sea numérico (o char, asumido como numérico).
     520            0 :       switch (basic->baseKind()) {
     521            0 :       case BasicKind::Int:
     522            0 :       case BasicKind::Float:
     523            0 :       case BasicKind::Double:
     524            0 :       case BasicKind::Char:
     525            0 :         return t;
     526            0 :       default:
     527            0 :         return createError(ERROR_TYPE::TYPE,
     528            0 :                            "operator " + tokenTypeToString(op) +
     529            0 :                                " cannot be applied to type " + t->toString());
     530            0 :       }
     531            0 :     default:
     532            0 :       return createError(ERROR_TYPE::TYPE, "unsupported unary operator");
     533            0 :     }
     534            0 :   }
     535              : 
     536            0 :   return createError(ERROR_TYPE::TYPE,
     537            0 :                      "unary operator cannot be applied to type " +
     538            0 :                          t->toString());
     539            0 : }
     540              : 
     541              : std::expected<std::shared_ptr<Type>, Error>
     542              : TypeTable::applyBinaryOperator(const std::shared_ptr<Type> &leftOperand,
     543              :                                const std::shared_ptr<Type> &rightOperand,
     544            0 :                                TokenType operatorToken) const noexcept {
     545              :   // Desenrollar los tipos constantes para trabajar con la representación base.
     546            0 :   std::shared_ptr<Type> leftResolvedType = leftOperand;
     547            0 :   std::shared_ptr<Type> rightResolvedType = rightOperand;
     548            0 :   if (auto leftConst = std::dynamic_pointer_cast<ConstType>(leftResolvedType))
     549            0 :     leftResolvedType = leftConst->baseType();
     550            0 :   if (auto rightConst = std::dynamic_pointer_cast<ConstType>(rightResolvedType))
     551            0 :     rightResolvedType = rightConst->baseType();
     552              : 
     553              :   // Caso: operador +
     554            0 :   if (operatorToken == TokenType::OPERATOR_ADD) {
     555              :     // Caso 1: Operando izquierdo y derecho son BasicType.
     556            0 :     auto leftBasicType = std::dynamic_pointer_cast<BasicType>(leftResolvedType);
     557            0 :     auto rightBasicType =
     558            0 :         std::dynamic_pointer_cast<BasicType>(rightResolvedType);
     559            0 :     if (leftBasicType && rightBasicType) {
     560              :       // Si alguno es de tipo cadena (Str), se asume concatenación.
     561            0 :       if (leftBasicType->baseKind() == BasicKind::Str and
     562            0 :           rightBasicType->baseKind() == BasicKind::Str) {
     563            0 :         return strType();
     564            0 :       }
     565              :       // Si son numéricos y ambos son del mismo tipo.
     566            0 :       if (areSameType(leftResolvedType, rightResolvedType))
     567            0 :         return leftResolvedType;
     568            0 :       else
     569            0 :         return createError(ERROR_TYPE::TYPE,
     570            0 :                            "incompatible numeric types for operator +");
     571            0 :     }
     572              :     // Caso 2: Aritmética de punteros: si el operando izquierdo es un puntero
     573              :     // y el derecho es un entero (o un char).
     574            0 :     auto leftPointerType =
     575            0 :         std::dynamic_pointer_cast<PointerType>(leftResolvedType);
     576            0 :     auto rightNumericBasic =
     577            0 :         std::dynamic_pointer_cast<BasicType>(rightResolvedType);
     578            0 :     if (leftPointerType && rightNumericBasic &&
     579            0 :         (rightNumericBasic->baseKind() == BasicKind::Int ||
     580            0 :          rightNumericBasic->baseKind() == BasicKind::Char)) {
     581            0 :       return leftResolvedType;
     582            0 :     }
     583            0 :     return createError(ERROR_TYPE::TYPE,
     584            0 :                        "operator + not applicable for given types: " +
     585            0 :                            leftResolvedType->toString() + " and " +
     586            0 :                            rightResolvedType->toString());
     587            0 :   }
     588              : 
     589              :   // Caso: operador -
     590            0 :   if (operatorToken == TokenType::OPERATOR_SUB) {
     591              :     // Caso 1: Resta entre BasicType numéricos.
     592            0 :     auto leftNumericType =
     593            0 :         std::dynamic_pointer_cast<BasicType>(leftResolvedType);
     594            0 :     auto rightNumericType =
     595            0 :         std::dynamic_pointer_cast<BasicType>(rightResolvedType);
     596            0 :     if (leftNumericType && rightNumericType) {
     597            0 :       if (areSameType(leftResolvedType, rightResolvedType))
     598            0 :         return leftResolvedType;
     599            0 :       else
     600            0 :         return createError(ERROR_TYPE::TYPE,
     601            0 :                            "incompatible numeric types for operator -");
     602            0 :     }
     603              :     // Caso 2: Resta entre punteros.
     604            0 :     auto leftPtrType = std::dynamic_pointer_cast<PointerType>(leftResolvedType);
     605            0 :     if (leftPtrType) {
     606            0 :       auto rightNumericOperand =
     607            0 :           std::dynamic_pointer_cast<BasicType>(rightResolvedType);
     608            0 :       if (rightNumericOperand &&
     609            0 :           (rightNumericOperand->baseKind() == BasicKind::Int ||
     610            0 :            rightNumericOperand->baseKind() == BasicKind::Char)) {
     611            0 :         return leftResolvedType;
     612            0 :       }
     613              :       // Si se resta dos punteros, el resultado es un entero.
     614            0 :       auto rightPtrType =
     615            0 :           std::dynamic_pointer_cast<PointerType>(rightResolvedType);
     616            0 :       if (rightPtrType) {
     617            0 :         return intType();
     618            0 :       }
     619            0 :     }
     620            0 :     return createError(ERROR_TYPE::TYPE,
     621            0 :                        "operator - not applicable for given types: " +
     622            0 :                            leftResolvedType->toString() + " and " +
     623            0 :                            rightResolvedType->toString());
     624            0 :   }
     625              : 
     626              :   // Caso: operador *
     627            0 :   if (operatorToken == TokenType::OPERATOR_MULT) {
     628            0 :     auto leftNumeric = std::dynamic_pointer_cast<BasicType>(leftResolvedType);
     629            0 :     auto rightNumeric = std::dynamic_pointer_cast<BasicType>(rightResolvedType);
     630            0 :     if (leftNumeric && rightNumeric) {
     631            0 :       if (areSameType(leftResolvedType, rightResolvedType))
     632            0 :         return leftResolvedType;
     633            0 :       else
     634            0 :         return createError(ERROR_TYPE::TYPE,
     635            0 :                            "incompatible types for operator *");
     636            0 :     }
     637            0 :     return createError(ERROR_TYPE::TYPE,
     638            0 :                        "operator * not applicable for given types: " +
     639            0 :                            leftResolvedType->toString() + " and " +
     640            0 :                            rightResolvedType->toString());
     641            0 :   }
     642              : 
     643              :   // Caso: operador /
     644            0 :   if (operatorToken == TokenType::OPERATOR_DIV) {
     645            0 :     auto leftNumeric = std::dynamic_pointer_cast<BasicType>(leftResolvedType);
     646            0 :     auto rightNumeric = std::dynamic_pointer_cast<BasicType>(rightResolvedType);
     647            0 :     if (leftNumeric && rightNumeric) {
     648            0 :       if (areSameType(leftResolvedType, rightResolvedType))
     649            0 :         return leftResolvedType;
     650            0 :       else
     651            0 :         return createError(ERROR_TYPE::TYPE,
     652            0 :                            "incompatible types for operator /");
     653            0 :     }
     654            0 :     return createError(ERROR_TYPE::TYPE,
     655            0 :                        "operator / not applicable for given types: " +
     656            0 :                            leftResolvedType->toString() + " and " +
     657            0 :                            rightResolvedType->toString());
     658            0 :   }
     659              : 
     660              :   // Caso: operador % (módulo)
     661            0 :   if (operatorToken == TokenType::OPERATOR_MODULE) {
     662            0 :     auto leftNumeric = std::dynamic_pointer_cast<BasicType>(leftResolvedType);
     663            0 :     auto rightNumeric = std::dynamic_pointer_cast<BasicType>(rightResolvedType);
     664            0 :     if (leftNumeric && rightNumeric) {
     665            0 :       if ((leftNumeric->baseKind() == BasicKind::Int ||
     666            0 :            leftNumeric->baseKind() == BasicKind::Char) &&
     667            0 :           (rightNumeric->baseKind() == BasicKind::Int ||
     668            0 :            rightNumeric->baseKind() == BasicKind::Char)) {
     669            0 :         return leftResolvedType;
     670            0 :       } else {
     671            0 :         return createError(ERROR_TYPE::TYPE,
     672            0 :                            "operator % not applicable for non-integral types");
     673            0 :       }
     674            0 :     }
     675            0 :     return createError(ERROR_TYPE::TYPE,
     676            0 :                        "operator % not applicable for given types: " +
     677            0 :                            leftResolvedType->toString() + " and " +
     678            0 :                            rightResolvedType->toString());
     679            0 :   }
     680              : 
     681              :   // Caso: operadores lógicos && y ||
     682            0 :   if (operatorToken == TokenType::AND || operatorToken == TokenType::OR) {
     683            0 :     auto leftBool = std::dynamic_pointer_cast<BasicType>(leftResolvedType);
     684            0 :     auto rightBool = std::dynamic_pointer_cast<BasicType>(rightResolvedType);
     685            0 :     if (leftBool && rightBool && leftBool->baseKind() == BasicKind::Bool &&
     686            0 :         rightBool->baseKind() == BasicKind::Bool) {
     687            0 :       return boolType();
     688            0 :     }
     689            0 :     return createError(ERROR_TYPE::TYPE,
     690            0 :                        "logical operators require boolean operands: " +
     691            0 :                            leftResolvedType->toString() + " and " +
     692            0 :                            rightResolvedType->toString());
     693            0 :   }
     694              : 
     695              :   // Caso: operadores de igualdad (== y !=)
     696            0 :   if (operatorToken == TokenType::EQUAL ||
     697            0 :       operatorToken == TokenType::NOTEQUAL) {
     698            0 :     const bool leftIsNull =
     699            0 :         (std::dynamic_pointer_cast<NullType>(leftResolvedType) != nullptr);
     700            0 :     const bool rightIsNull =
     701            0 :         (std::dynamic_pointer_cast<NullType>(rightResolvedType) != nullptr);
     702              : 
     703            0 :     if (leftIsNull || rightIsNull) {
     704              :       // Verificar que el otro operando es efectivamente un puntero.
     705            0 :       if (leftIsNull &&
     706            0 :           !std::dynamic_pointer_cast<PointerType>(rightResolvedType))
     707            0 :         return createError(ERROR_TYPE::TYPE,
     708            0 :                            "cannot compare non-pointer type with null");
     709            0 :       if (rightIsNull &&
     710            0 :           !std::dynamic_pointer_cast<PointerType>(leftResolvedType))
     711            0 :         return createError(ERROR_TYPE::TYPE,
     712            0 :                            "cannot compare non-pointer type with null");
     713              : 
     714            0 :       return boolType();
     715            0 :     }
     716              : 
     717              :     // Si ninguno es NullType, procedemos con la comparación habitual:
     718            0 :     if (areSameType(leftResolvedType, rightResolvedType) ||
     719            0 :         haveCommonAncestor(leftResolvedType, rightResolvedType)) {
     720            0 :       return boolType();
     721            0 :     }
     722              : 
     723            0 :     return createError(ERROR_TYPE::TYPE,
     724            0 :                        "incompatible types for equality operator: " +
     725            0 :                            leftResolvedType->toString() + " vs " +
     726            0 :                            rightResolvedType->toString());
     727            0 :   }
     728              : 
     729              :   // Caso: operadores relacionales (<, >, <=, >=)
     730            0 :   if (operatorToken == TokenType::OPERATOR_SMALLER ||
     731            0 :       operatorToken == TokenType::OPERATOR_GREATER ||
     732            0 :       operatorToken == TokenType::SMALLEREQUAL ||
     733            0 :       operatorToken == TokenType::BIGGEREQUAL) {
     734            0 :     auto leftNumeric = std::dynamic_pointer_cast<BasicType>(leftResolvedType);
     735            0 :     auto rightNumeric = std::dynamic_pointer_cast<BasicType>(rightResolvedType);
     736            0 :     if (leftNumeric && rightNumeric) {
     737            0 :       if (areSameType(leftResolvedType, rightResolvedType) ||
     738            0 :           haveCommonAncestor(leftResolvedType, rightResolvedType)) {
     739            0 :         return boolType();
     740            0 :       } else {
     741            0 :         return createError(ERROR_TYPE::TYPE,
     742            0 :                            "incompatible types for relational operator: " +
     743            0 :                                leftResolvedType->toString() + " vs " +
     744            0 :                                rightResolvedType->toString());
     745            0 :       }
     746            0 :     }
     747            0 :     return createError(ERROR_TYPE::TYPE,
     748            0 :                        "relational operators not applicable for given types: " +
     749            0 :                            leftResolvedType->toString() + " and " +
     750            0 :                            rightResolvedType->toString());
     751            0 :   }
     752              : 
     753              :   // Aquí se podrían agregar casos para tipos definidos por el usuario y enums,
     754              :   // etc. Por ejemplo, si el operando izquierdo es de UserType, se intentaría
     755              :   // llamar a un método sobrecargado que implemente el operador.
     756            0 :   if (auto leftUserType =
     757            0 :           std::dynamic_pointer_cast<UserType>(leftResolvedType)) {
     758            0 :     std::string methodName;
     759            0 :     switch (operatorToken) {
     760            0 :     case TokenType::OPERATOR_ADD:
     761            0 :       methodName = "addable";
     762            0 :       break;
     763            0 :     case TokenType::OPERATOR_SUB:
     764            0 :       methodName = "substrable";
     765            0 :       break;
     766            0 :     case TokenType::OPERATOR_MULT:
     767            0 :       methodName = "multiplicable";
     768            0 :       break;
     769            0 :     case TokenType::OPERATOR_DIV:
     770            0 :       methodName = "divisble";
     771            0 :       break;
     772            0 :     case TokenType::AND:
     773            0 :       methodName = "andable";
     774            0 :       break;
     775            0 :     case TokenType::OR:
     776            0 :       methodName = "orable";
     777            0 :       break;
     778            0 :     case TokenType::EQUAL:
     779            0 :       methodName = "equal";
     780            0 :       break;
     781            0 :     case TokenType::NOTEQUAL:
     782            0 :       methodName = "notEqual";
     783            0 :       break;
     784            0 :     default:
     785            0 :       break;
     786            0 :     }
     787            0 :     if (!methodName.empty()) {
     788            0 :       std::expected<std::vector<Method>, Error> userMethodsExp =
     789            0 :           leftUserType->getMethods(methodName);
     790            0 :       if (!userMethodsExp)
     791            0 :         return createError(userMethodsExp.error());
     792            0 :       std::vector<Method> userMethods = userMethodsExp.value();
     793            0 :       for (const Method &userMethod : userMethods) {
     794            0 :         if (userMethod.params().size() == 1) {
     795              :           // Verificar compatibilidad del parámetro con rightResolvedType.
     796            0 :           if (canAssign(userMethod.params().params().front().second,
     797            0 :                         rightResolvedType))
     798            0 :             return userMethod.returnType();
     799            0 :         }
     800            0 :       }
     801            0 :       return createError(ERROR_TYPE::TYPE,
     802            0 :                          "user type " + leftUserType->name() +
     803            0 :                              " does not overload operator " +
     804            0 :                              tokenTypeToString(operatorToken));
     805            0 :     }
     806            0 :   }
     807              : 
     808              :   // Caso para EnumType: Se permiten operadores de igualdad y desigualdad.
     809            0 :   if (auto leftEnumType =
     810            0 :           std::dynamic_pointer_cast<EnumType>(leftResolvedType)) {
     811            0 :     if (auto rightEnumType =
     812            0 :             std::dynamic_pointer_cast<EnumType>(rightResolvedType)) {
     813            0 :       if (operatorToken == TokenType::EQUAL ||
     814            0 :           operatorToken == TokenType::NOTEQUAL) {
     815            0 :         return boolType();
     816            0 :       } else {
     817            0 :         return createError(ERROR_TYPE::TYPE,
     818            0 :                            "operator " + tokenTypeToString(operatorToken) +
     819            0 :                                " not allowed on enums");
     820            0 :       }
     821            0 :     }
     822            0 :     return createError(ERROR_TYPE::TYPE,
     823            0 :                        "incompatible types for binary operator: enum mismatch");
     824            0 :   }
     825              : 
     826              :   // Caso para PlaceHolder: no se permiten operaciones binarias sobre generics
     827              :   // sin resolver.
     828            0 :   if (std::dynamic_pointer_cast<PlaceHolder>(leftResolvedType) ||
     829            0 :       std::dynamic_pointer_cast<PlaceHolder>(rightResolvedType)) {
     830            0 :     return leftResolvedType;
     831            0 :   }
     832              : 
     833              :   // Si leftOperand es un PointerType y ningún otro caso aplicó:
     834            0 :   if (auto leftPointerType =
     835            0 :           std::dynamic_pointer_cast<PointerType>(leftResolvedType)) {
     836            0 :     if (operatorToken == TokenType::OPERATOR_SUB) {
     837              :       // Si ambos operandos son punteros, el resultado es un entero.
     838            0 :       if (std::dynamic_pointer_cast<PointerType>(rightResolvedType)) {
     839            0 :         return intType();
     840            0 :       }
     841            0 :     }
     842            0 :   }
     843              : 
     844            0 :   return createError(
     845            0 :       ERROR_TYPE::TYPE,
     846            0 :       "operator " + tokenTypeToString(operatorToken) +
     847            0 :           " not implemented for given types: " + leftResolvedType->toString() +
     848            0 :           " and " + rightResolvedType->toString());
     849            0 : }
     850              : 
     851              : std::expected<std::string, Error>
     852            0 : TypeTable::nameMangling(const std::shared_ptr<Type> &type) const noexcept {
     853            0 :   std::string result{"$"};
     854            0 :   return nameManglingImpl(type, result);
     855            0 : }
     856              : 
     857              : std::expected<std::string, Error>
     858              : TypeTable::nameManglingImpl(const std::shared_ptr<Type> &type,
     859            0 :                             std::string &result) const noexcept {
     860            0 :   if (type) {
     861            0 :   }
     862            0 :   return result;
     863            0 : }
     864              : 
     865              : } // namespace nicole
        

Generated by: LCOV version 2.0-1