#ifndef CODEGEN_AUX_H
#define CODEGEN_AUX_H

#include "lexer.h"
#include "parser.h"
#include "semantico.h"
#include <sstream>
#include <string_view>

int tam_memoria(tipo_evaluado t) {
   if (t.modificador == APUNTADOR) {
      return 4;
   } else {
      int tam_base = (t.base == CHAR ? 1 : 4);
      return tam_base * (t.modificador == ESCALAR ? 1 : t.tamanyo);
   }
}

std::string_view ancho_acceso(tipo_evaluado t) {
   return (tam_memoria(t) == 1 ? "BYTE" : "WORD");
}

std::string eti(const expresion* ex) {
   std::ostringstream oss;
   oss << "eti_" << typeid(*ex).name( ) << "_" << (const void*)ex;
   return oss.str( );
}

std::string eti(const sentencia* ex) {
   std::ostringstream oss;
   oss << "eti_" << typeid(*ex).name( ) << "_" << (const void*)ex;
   return oss.str( );
}

std::string eti(std::string_view s) {
   std::ostringstream oss;
   oss << "eti_" << s;
   return oss.str( );
}

tipo_evaluado traduce(expresion* ex, auto&... params) {
   if (auto p = dynamic_cast<expresion_termino*>(ex); p != nullptr) {
      return traduce(p, params...);
   } else if (auto p = dynamic_cast<expresion_binaria*>(ex); p != nullptr) {
      return traduce(p, params...);
   } else if (auto p = dynamic_cast<expresion_prefija*>(ex); p != nullptr) {
      return traduce(p, params...);
   } else if (auto p = dynamic_cast<expresion_posfija*>(ex); p != nullptr) {
      return traduce(p, params...);
   } else if (auto p = dynamic_cast<expresion_llamada*>(ex); p != nullptr) {
      return traduce(p, params...);
   } else if (auto p = dynamic_cast<expresion_indexacion*>(ex); p != nullptr) {
      return traduce(p, params...);
   } else if (auto p = dynamic_cast<expresion_secuencia*>(ex); p != nullptr) {
      return traduce(p, params...);
   } else {
      return { };    // no debería ocurrir
   }
}

void traduce(sentencia* s, auto&&... params) {
   if (auto p = dynamic_cast<sentencia_expresion*>(s); p != nullptr) {
      return traduce(p, params...);
   } else if (auto p = dynamic_cast<sentencia_declaracion*>(s); p != nullptr) {
      return traduce(p, params...);
   } else if (auto p = dynamic_cast<sentencia_if*>(s); p != nullptr) {
      return traduce(p, params...);
   } else if (auto p = dynamic_cast<sentencia_while*>(s); p != nullptr) {
      return traduce(p, params...);
   } else if (auto p = dynamic_cast<sentencia_do*>(s); p != nullptr) {
      return traduce(p, params...);
   } else if (auto p = dynamic_cast<sentencia_for*>(s); p != nullptr) {
      return traduce(p, params...);
   } else if (auto p = dynamic_cast<sentencia_return*>(s); p != nullptr) {
      return traduce(p, params...);
   } else if (auto p = dynamic_cast<sentencia_break*>(s); p != nullptr) {
      return traduce(p, params...);
   } else if (auto p = dynamic_cast<sentencia_continue*>(s); p != nullptr) {
      return traduce(p, params...);
   } else if (auto p = dynamic_cast<sentencia_exit*>(s); p != nullptr) {
      return traduce(p, params...);
   }
}

#endif
