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
|