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...
}
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::evaluateLValue(RefPortugolAST id, list<ExpressionValue>& dim) {
/*
  1: lvalue (id) deve ter sido declarado no escopo global ou local
  2: o tipo do lvalue (id) deve ser o mesmo da declaracao (primitivo/dimensoes)
  3: as expressoes das dimensoes devem ser numericas inteiras. [1.2] ou ["aa"] ->erro
*/

  bool islocal;
  Symbol lvalue;
  ExpressionValue ret;

  try {
    lvalue = stable.getSymbol(currentScope, id->getText(), true);
    if(lvalue.scope == SymbolTable::GlobalScope) {
      islocal = false;
    } else {
      islocal = true;
    }
  } catch(SymbolTableException& e) {
    stringstream msg;    
    msg << "Variável \"" << id->getText() << "\" não foi declarada";
    ErrorHandler::self()->add(msg.str(), id->getLine());
    return ret;
  }

  ret.setPrimitiveType(lvalue.type.primitiveType());

  if(lvalue.isFunction) {
    stringstream msg;
    msg << "Função \"" << id->getText() << "\" não pode ser usada como variável";
    ErrorHandler::self()->add(msg.str(), id->getLine());
    return ret;    
  }

  if(lvalue.type.isPrimitive()) {
    ret.set(lvalue.type);
    if(dim.size() > 0) {
      stringstream msg;
      msg << "Variável \"" << id->getText() << "\" não é uma matriz/conjunto";
      ErrorHandler::self()->add(msg.str(), id->getLine());
      return ret;
    } else {
      return ret;
    }
  } else {//matriz/conjunto    

//     ret.setPrimitive(true);
//     ret.setPrimitiveType(lvalue.type.primitiveType());

    //checar expressoes dos subscritos
    list<ExpressionValue>::iterator it;
    for(it = dim.begin(); it != dim.end();++it) {
      if(!(*it).isNumeric(true)) {
        ErrorHandler::self()->add("Subscritos de conjuntos/matrizes devem ser valores numéricos inteiros ou equivalente", id->getLine());
      }
    }

    /* Nota: checar pelas dimensoes impede que 
       se passe matriz como parametros. Checar subscritos apenas 
       em atribuicoes.
    */

    //checar numero de dimensoes usado
    // - So eh permitido matrizes como lvalue sem subscritos, ou com todos os seus subscritos

    if(dim.size() > 0) {
      //matriz com seus subscritos, retorna apenas o tipo primitivo
      ret.setPrimitive(true);

      if(lvalue.type.dimensions().size() != dim.size()) {
        stringstream msg;
        msg << "Matriz/conjunto \"" << id->getText() << "\" possui " << lvalue.type.dimensions().size();
  
        if(dim.size() == 1) {
          msg << " dimensão";
        } else {
          msg << " dimensões";
        }
        msg << " Use " << lvalue.type.dimensions().size() << " subscrito(s)";
        ErrorHandler::self()->add(msg.str(), id->getLine());
      } 
    } else {
      //variavel matriz sem subscritos, retorna tipo matriz
      ret.setPrimitive(true);
      ret.setDimensions(lvalue.type.dimensions());
    }
    return ret;
  }
}