ExpressionValue SemanticEval::evaluateExpr(ExpressionValue& ev, RefPortugolAST unary_op) {
  ExpressionValue nulo;

  //não permitir TIPO_ALL em expressões binarias
  if(ev.primitiveType() == TIPO_ALL) {
    stringstream msg;
    msg << "Função interna não pode participar de expressão";
    ErrorHandler::self()->add(msg.str(), unary_op->getLine());
    return nulo;
  }

  switch(unary_op->getType()) {

    //operadores unarios para expressões numéricas (retorna o tipo da expressão 'expr')
    case SemanticWalkerTokenTypes::TI_UN_POS://+
    case SemanticWalkerTokenTypes::TI_UN_NEG://-    
      if(!ev.isNumeric()) {
        stringstream msg;
        msg <<  "Operador unário \"" << unary_op->getText()
            << "\" deve ser usado em termos numéricos";
        ErrorHandler::self()->add(msg.str(), unary_op->getLine());
        return nulo;
      } else {      
        return ev;
      }  
      break;
    case SemanticWalkerTokenTypes::TI_UN_BNOT://~
      if(!ev.isNumeric(true)) {
        stringstream msg;
        msg <<  "Operador unário \"" << unary_op->getText()
            << "\" deve ser usado em termos numéricos inteiros e compatíveis";
        ErrorHandler::self()->add(msg.str(), unary_op->getLine());
        return nulo;
      } else {      
        return ev;
      }  
      break;
      
    //operador "not", para todos os tipos. Retorna TIPO_LOGICO
    case SemanticWalkerTokenTypes::TI_UN_NOT:
      ev.setPrimitiveType(TIPO_LOGICO);
      return ev;
      break;
  }

  stringstream msg;
  msg << "Erro interno: operador não suportado: " << unary_op->getText() << "";
  ErrorHandler::self()->add(msg.str(), unary_op->getLine());
  return nulo;
}
ExpressionValue SemanticEval::evaluateNumTypes(ExpressionValue& left, ExpressionValue& right) {
  ExpressionValue ret;

  if(!left.isNumeric() || !right.isNumeric()) return ret;

  //a ordem eh importante. Primeiro o tipo mais forte.

  if((left.primitiveType() == TIPO_REAL) || (right.primitiveType() == TIPO_REAL)) {
    ret.setPrimitiveType(TIPO_REAL); //promoted to real

  } else if((left.primitiveType() == TIPO_INTEIRO) || (right.primitiveType() == TIPO_INTEIRO)) {
    ret.setPrimitiveType(TIPO_INTEIRO); //promoted to int

  } else  if((left.primitiveType() == TIPO_CARACTERE) || (right.primitiveType() == TIPO_CARACTERE)) {
    ret.setPrimitiveType(TIPO_CARACTERE); //promoted to char

  } else if((left.primitiveType() == TIPO_LOGICO) || (right.primitiveType() == TIPO_LOGICO)) {
    ret.setPrimitiveType(TIPO_LOGICO); //promoted to bool
  }    

  return ret; //no number here...
}
void SemanticEval::evaluateAttribution(ExpressionValue&  lv, ExpressionValue& rv, int line) {
//lvalue e rvalue devem ter tipos compativeis
//  -numericos (inteiro, logico, real, caractere) sao compativeis entre si.

  stringstream msg;

  if(!lv.isPrimitive()) {
    msg << "Apenas variáveis de tipos primitivos podem receber valores";
    ErrorHandler::self()->add(msg.str(), line);
    return;
  }

  if(rv.primitiveType() == TIPO_NULO) {
    msg << "Expressão não retorna resultado para variável";  
    ErrorHandler::self()->add(msg.str(), line);
  } else  if(!lv.isCompatibleWidth(rv)) {
    msg << "Variável não pode receber valores do tipo '"
        << rv.toString() << "'";      
    ErrorHandler::self()->add(msg.str(), line);
  }
}
ExpressionValue SemanticEval::evaluateExpr(ExpressionValue& left, ExpressionValue& right, RefPortugolAST op) {
  //analisa expressoes binarias

  ExpressionValue ret, nulo;

  //operadores suportam apenas primitivos
//   if(!left.isPrimitive() || !right.isPrimitive()) {
//     return ret;
//   }

  //não permitir TIPO_ALL em expressões binarias
  if((left.primitiveType() == TIPO_ALL) || (right.primitiveType() == TIPO_ALL)) {
    stringstream msg;
    msg << "Função interna não pode participar de expressão";
    ErrorHandler::self()->add(msg.str(), op->getLine());
    return nulo;
  }

  switch(op->getType()) {
    //qualquer tipo, contanto que left e right sejam compativeis
    case SemanticWalkerTokenTypes::T_IGUAL:
    case SemanticWalkerTokenTypes::T_DIFERENTE:

    //nota sobre literais:
    // operacoes aplicadas sobre o length() do literal
    case SemanticWalkerTokenTypes::T_MAIOR:
    case SemanticWalkerTokenTypes::T_MENOR:
    case SemanticWalkerTokenTypes::T_MAIOR_EQ:
    case SemanticWalkerTokenTypes::T_MENOR_EQ:

    case SemanticWalkerTokenTypes::T_KW_OU:
    case SemanticWalkerTokenTypes::T_KW_E:
      if(left.isCompatibleWidth(right)) {
        ret.setPrimitiveType(TIPO_LOGICO);
        return ret;
      } else {
        stringstream msg;
        msg << "Operador \"" << op->getText() << "\" não pode ser usado em expressões no formato " 
            << "'" << left.toString() 
            << " " << op->getText() 
            << " " << right.toString() << "'";
            ErrorHandler::self()->add(msg.str(), op->getLine());
            return nulo;
      }   
      break;

    //qualquer numerico não-real (inteiro, caractere, lógico)
    case SemanticWalkerTokenTypes::T_BIT_OU:
    case SemanticWalkerTokenTypes::T_BIT_XOU:
    case SemanticWalkerTokenTypes::T_BIT_E:
      ret = evaluateNumTypes(left, right);
      if((ret.primitiveType() == TIPO_REAL) || (ret.primitiveType() == TIPO_NULO)) {
        stringstream msg;
        msg << "Operador \"" << op->getText() << "\" só pode ser usado com termos númericos não-reais";
            ErrorHandler::self()->add(msg.str(), op->getLine());
         return nulo;
      } else {
        return ret;
      }
      break;

    //qualquer numérico
    case SemanticWalkerTokenTypes::T_MAIS:
    case SemanticWalkerTokenTypes::T_MENOS:
    case SemanticWalkerTokenTypes::T_DIV:
    case SemanticWalkerTokenTypes::T_MULTIP:    
      ret = evaluateNumTypes(left, right);
      if(!ret.isNumeric()) {
        stringstream msg;
        msg << "Operador \"" << op->getText() << "\" só pode ser usado com termos numéricos";
            ErrorHandler::self()->add(msg.str(), op->getLine());          
            return nulo;
      } else {
        return ret;
      }      
      break;
    case SemanticWalkerTokenTypes::T_MOD:
      ret = evaluateNumTypes(left, right);
      if(!ret.isNumeric(true)) {
        stringstream msg;
        msg << "Operador \"" << op->getText() << "\" não pode ser usado com termos "
            << "numéricos inteiros e compatíveis";
            ErrorHandler::self()->add(msg.str(), op->getLine());          
            return nulo;
      } else {
        return ret;
      }      
      break;
  }

  stringstream msg;
  msg << "Erro interno: operador não suportado: " << op->getText();
  ErrorHandler::self()->add(msg.str(), op->getLine());
  return nulo;
}