#include <iostream>

#include "operator.h"
#include "errors.h"
#include "symbol.h"
#include "processor.h"


static bool isFloat(Value *v)
{
  if(v &&  (typeid(*v) == typeid(Float)))
    return true;
  return false;
}
static bool isInteger(Value *v)
{
  if(v &&  (typeid(*v) == typeid(Integer)))
    return true;
  return false;
}
static bool isBoolean(Value *v)
{
  if(v &&  (typeid(*v) == typeid(Boolean)))
    return true;
  return false;
}

BinaryOperator::BinaryOperator(string  opString, 
			       Expression* _leftExpr, 
			       Expression* _rightExpr) : Operator(opString)
{
  leftExpr = _leftExpr;
  rightExpr = _rightExpr;
  value = 0;
}


BinaryOperator::~BinaryOperator()
{
  delete leftExpr;
  delete rightExpr;
  delete value;
}


Value* BinaryOperator::shortCircuit(Value* leftValue)
{
  return 0;
}

string BinaryOperator::show()
{
  return toString();
}

string BinaryOperator::showType()
{
  return showOp();
}


string BinaryOperator::toString()
{
  return string("(" + leftExpr->toString() + showOp() + rightExpr->toString() + ")");
}

Value *BinaryOperator::evaluate()
{

  return applyOp(leftExpr->evaluate(), rightExpr->evaluate());
}
Expression *BinaryOperator::getLeft() {
  return leftExpr;
}

Expression *BinaryOperator::getRight() {
  return rightExpr;
}


/*****************************************************************
 * The basic unary operator class.
 */
UnaryOperator::UnaryOperator(string theOpString, Expression* expr_)
  : Operator(theOpString)
{
  expr = expr_;
  value = 0;
}

UnaryOperator::~UnaryOperator()
{
  delete expr;
}


string UnaryOperator::showType()
{
  return showOp();
}


string UnaryOperator::show()
{
  return toString();
}


string UnaryOperator::toString()
{
  return string(showOp() + "(" + expr->toString() + ")");
}



Value* UnaryOperator::evaluate()
{
  Value* tmp, *vReturn;

  // start evaluating our operand expression:
  tmp = expr->evaluate();

  // Apply the specific operator to the evaluated operand:
  vReturn = applyOp(tmp);

  // If the result is constant, save the result for future use:
  //if (tmp->isConstant()) {
  //  value = tmp;
  //}
  delete tmp;
  return vReturn;
}

/*****************************************************************
 * Comparison operators
 */
ComparisonOperator::ComparisonOperator(string opString, 
				       Expression* leftExpr,
				       Expression* rightExpr)
  : BinaryOperator(opString,leftExpr,rightExpr), 
    bLess(false), bEqual(false), bGreater(false)
{
}

ComparisonOperator:: ~ComparisonOperator()
{
}

Value* ComparisonOperator::applyOp(Value* leftValue, Value* rightValue)
{
  return new Boolean(leftValue->compare(this,rightValue));
}
int ComparisonOperator::set_break(ObjectBreakTypes bt, ObjectActionTypes at, Expression *pExpr)
{
  return get_bp().set_break(bt, at, (Register *)0, this);

}

/******************************************************************************
 Operator: AbstractRange 
 
 *****************************************************************************/
OpAbstractRange::OpAbstractRange(Expression *lVal, Expression *rVal)
  : BinaryOperator(":", lVal, rVal)
{
}


OpAbstractRange::~OpAbstractRange()
{
}


Value* OpAbstractRange::applyOp(Value* lVal, Value* rVal)
{
  Value* result=0;

  Integer* lInteger = Integer::typeCheck(lVal, showOp());
  Integer* rInteger = Integer::typeCheck(rVal, showOp());
  
  int left = (int)lInteger->getVal();
  int right = (int)rInteger->getVal();
  
  result = new AbstractRange(left, right);
  return(result);
}

//------------------------------------------------------------------------


OpAdd::OpAdd(Expression* leftExpr, Expression* rightExpr)
  : BinaryOperator("+",leftExpr,rightExpr)
{
}

OpAdd::~OpAdd()
{
}

Value *OpAdd::applyOp(Value *lval, Value *rval)
{
  if(isFloat(lval) || isFloat(rval)) {
    double d1,d2;

    lval->get(d1);
    rval->get(d2);

    return new Float(d1+d2);
  }

  // Try to add as integers. (An exception is thrown if the values
  // cannot be type casted.

  gint64 i1,i2;

  lval->get(i1);
  rval->get(i2);

  return new Integer(i1+i2);

  //throw new TypeMismatch(showOp(), lval->showType(), rval->showType());
}

//------------------------------------------------------------------------


OpAnd::OpAnd(Expression* leftExpr, Expression* rightExpr)
  : BinaryOperator("&",leftExpr,rightExpr)
{
}

OpAnd::~OpAnd()
{
}

Value *OpAnd::applyOp(Value *lval, Value *rval)
{

  if(isFloat(lval) || isFloat(rval))
    throw new TypeMismatch(showOp(), lval->showType(), rval->showType());

  gint64 i1,i2;

  lval->get(i1);
  rval->get(i2);

  return new Integer(i1 & i2);

}

//------------------------------------------------------------------------
OpEq::OpEq(Expression* leftExpr, Expression* rightExpr)
  : ComparisonOperator("==",leftExpr,rightExpr)
{
  bEqual = true;
}

OpEq::~OpEq()
{
}

//------------------------------------------------------------------------
OpGe::OpGe(Expression* leftExpr, Expression* rightExpr)
  : ComparisonOperator(">=",leftExpr,rightExpr)
{
  bEqual = true;
  bGreater = true;
}

OpGe::~OpGe()
{
}

//------------------------------------------------------------------------
OpGt::OpGt(Expression* leftExpr, Expression* rightExpr)
  : ComparisonOperator(">",leftExpr,rightExpr)
{
  bGreater = true;
}

OpGt::~OpGt()
{
}

//------------------------------------------------------------------------
OpLe::OpLe(Expression* leftExpr, Expression* rightExpr)
  : ComparisonOperator("<=",leftExpr,rightExpr)
{
  bLess = true;
  bEqual = true;
}

OpLe::~OpLe()
{
}
//------------------------------------------------------------------------
OpLt::OpLt(Expression* leftExpr, Expression* rightExpr)
  : ComparisonOperator("<",leftExpr,rightExpr)
{
  bLess = true;
}

OpLt::~OpLt()
{
}

//------------------------------------------------------------------------
OpLogicalAnd::OpLogicalAnd(Expression* leftExpr, Expression* rightExpr)
  : BinaryOperator("&&",leftExpr,rightExpr)
{
}

OpLogicalAnd::~OpLogicalAnd()
{
}

Value *OpLogicalAnd::applyOp(Value* lval, Value* rval)
{
  if(isBoolean(lval) && isBoolean(rval)) {
    bool b1 = (static_cast<Boolean *>(lval))->getVal();
    bool b2 = (static_cast<Boolean *>(rval))->getVal();

    return new Boolean(b1 & b2);
  }

  throw new TypeMismatch(showOp(), lval->showType(), rval->showType());

}

//------------------------------------------------------------------------
OpLogicalOr::OpLogicalOr(Expression* leftExpr, Expression* rightExpr)
  : BinaryOperator("||",leftExpr,rightExpr)
{
}

OpLogicalOr::~OpLogicalOr()
{
}

Value *OpLogicalOr::applyOp(Value* lval, Value* rval)
{
  if(isBoolean(lval) && isBoolean(rval)) {
    bool b1 = (static_cast<Boolean *>(lval))->getVal();
    bool b2 = (static_cast<Boolean *>(rval))->getVal();

    return new Boolean(b1 | b2);
  }

  throw new TypeMismatch(showOp(), lval->showType(), rval->showType());

}


//------------------------------------------------------------------------
OpNe::OpNe(Expression* leftExpr, Expression* rightExpr)
  : ComparisonOperator("!=",leftExpr,rightExpr)
{
  bLess = true;
  bGreater = true;
}

OpNe::~OpNe()
{
}


//------------------------------------------------------------------------


OpSub::OpSub(Expression* leftExpr, Expression* rightExpr)
  : BinaryOperator("-",leftExpr,rightExpr)
{
}

OpSub::~OpSub()
{
}

Value *OpSub::applyOp(Value *lval, Value *rval)
{
  if(isFloat(lval) || isFloat(rval)) {
    double d1,d2;

    lval->get(d1);
    rval->get(d2);

    return new Float(d1-d2);
  }

  gint64 i1,i2;

  lval->get(i1);
  rval->get(i2);

  return new Integer(i1-i2);

  //  throw new TypeMismatch(showOp(), lval->showType(), rval->showType());

}

//------------------------------------------------------------------------


OpMpy::OpMpy(Expression* leftExpr, Expression* rightExpr)
  : BinaryOperator("*",leftExpr,rightExpr)
{
}

OpMpy::~OpMpy()
{
}

Value *OpMpy::applyOp(Value *lval, Value *rval)
{
  if(isFloat(lval) || isFloat(rval)) {
    double d1,d2;

    lval->get(d1);
    rval->get(d2);

    return new Float(d1*d2);
  }

  gint64 i1,i2;

  lval->get(i1);
  rval->get(i2);

  return new Integer(i1*i2);

  throw new TypeMismatch(showOp(), lval->showType(), rval->showType());
}

//------------------------------------------------------------------------


OpOr::OpOr(Expression* leftExpr, Expression* rightExpr)
  : BinaryOperator("|",leftExpr,rightExpr)
{
}

OpOr::~OpOr()
{
}

Value *OpOr::applyOp(Value *lval, Value *rval)
{
  if(isFloat(lval) || isFloat(rval))
    throw new TypeMismatch(showOp(), lval->showType(), rval->showType());

  gint64 i1,i2;

  lval->get(i1);
  rval->get(i2);

  return new Integer(i1 | i2);
}

//------------------------------------------------------------------------


OpXor::OpXor(Expression* leftExpr, Expression* rightExpr)
  : BinaryOperator("^",leftExpr,rightExpr)
{
}

OpXor::~OpXor()
{
}

Value *OpXor::applyOp(Value *lval, Value *rval)
{

  if(isFloat(lval) || isFloat(rval))
    throw new TypeMismatch(showOp(), lval->showType(), rval->showType());

  gint64 i1,i2;

  lval->get(i1);
  rval->get(i2);

  return new Integer(i1 ^ i2);
}

//------------------------------------------------------------------------


OpDiv::OpDiv(Expression* leftExpr, Expression* rightExpr)
  : BinaryOperator("/",leftExpr,rightExpr)
{
}

OpDiv::~OpDiv()
{
}

Value *OpDiv::applyOp(Value *lval, Value *rval)
{

  if(isFloat(lval) || isFloat(rval)) {
    double d1,d2;

    lval->get(d1);
    rval->get(d2);

    if(d2 == 0.0)
      throw new Error("Divide by zero");

    return new Float(d1/d2);
  }

  gint64 i1,i2;

  lval->get(i1);
  rval->get(i2);

  if(i2 == 0)
    throw new Error("Divide by zero");

  return new Integer(i1/i2);

}

//------------------------------------------------------------------------


OpShl::OpShl(Expression* leftExpr, Expression* rightExpr)
  : BinaryOperator("<<",leftExpr,rightExpr)
{
}

OpShl::~OpShl()
{
}

Value *OpShl::applyOp(Value *lval, Value *rval)
{

  if(isFloat(lval) || isFloat(rval))
    throw new TypeMismatch(showOp(), lval->showType(), rval->showType());

  gint64 i1;
  gint64 i2;

  rval->get(i2);

  if(i2 < 0  || i2 > 63)
    throw new Error("Operator " + showOp() + " bad shift count");

  lval->get(i1);

  return new Integer(i1<<i2);
}

//------------------------------------------------------------------------


OpShr::OpShr(Expression* leftExpr, Expression* rightExpr)
  : BinaryOperator(">>",leftExpr,rightExpr)
{
}

OpShr::~OpShr()
{
}

Value *OpShr::applyOp(Value *lval, Value *rval)
{

  if(isFloat(lval) || isFloat(rval))
    throw new TypeMismatch(showOp(), lval->showType(), rval->showType());

  gint64 i1;
  gint64 i2;

  rval->get(i2);

  if(i2 < 0  || i2 > 63)
    throw new Error("Operator " + showOp() + " bad shift count");

  lval->get(i1);

  return new Integer(i1>>i2);
}


/******************************************************************************
 The logical NOT operator '!'.
******************************************************************************/
OpLogicalNot::OpLogicalNot(Expression* expr)
  : UnaryOperator("!", expr)
{
}

OpLogicalNot::~OpLogicalNot()
{
}

Value* OpLogicalNot::applyOp(Value* operand)
{
  Boolean* op;
  bool bVal;

  op = Boolean::typeCheck(operand, showOp());
  bVal = op->getVal();
  return new Boolean(!bVal);
}

/******************************************************************************
 The unary 'negate' operator.
******************************************************************************/
OpNegate::OpNegate(Expression* expr)
  : UnaryOperator("-", expr)
{
}

OpNegate::~OpNegate()
{
}


Value* OpNegate::applyOp(Value* operand)
{
  Value* rVal=0;

  if (isInteger(operand)) {
    Integer* iOp = (Integer*)(operand);
    rVal = new Integer(-(iOp->getVal()));
  }
  else if (isFloat(operand)) {
    Float* fOp = (Float*)(operand);
    rVal = new Float(-(fOp->getVal()));
  }
  else {
    throw new TypeMismatch(showOp(), operand->showType());
  }

  return rVal;
}

/******************************************************************************
 The unary ones complement operator '~'.
******************************************************************************/
OpOnescomp::OpOnescomp(Expression* expr)
  : UnaryOperator("~", expr)
{
}

OpOnescomp::~OpOnescomp()
{
}


Value* OpOnescomp::applyOp(Value* operand)
{
  Integer* op;
  
  op = Integer::typeCheck(operand, showOp());  
  return new Integer(~ op->getVal() );
}

/******************************************************************************
 The unary 'plus' operator.
******************************************************************************/
OpPlus::OpPlus(Expression* expr)
  : UnaryOperator("+", expr)
{
}

OpPlus::~OpPlus()
{
}


Value* OpPlus::applyOp(Value* operand)
{
  Value* rVal=0;

  if (isInteger(operand)) {
    Integer* iOp = (Integer*)(operand);
    rVal = new Integer(iOp->getVal());
  }
  else if (isFloat(operand) ) {
    Float* fOp = (Float*)(operand);
    rVal = new Float(fOp->getVal());
  }
  else {
    throw new TypeMismatch(showOp(), operand->showType());
  }

  return rVal;
}

/******************************************************************************
 The unary '*' operator - indirect access
******************************************************************************/
OpIndirect::OpIndirect(Expression* expr)
  : UnaryOperator("*", expr)
{
}

OpIndirect::~OpIndirect()
{
}


Value* OpIndirect::applyOp(Value* operand)
{
  Value* rVal=0;
  if (isInteger(operand)) {
    Integer* iOp = (Integer*)(operand);
    // hmm ... what about ema? Need a different indirection operator?
    Register *pReg = get_active_cpu()->rma.get_register(*iOp);
    if(pReg) {
      rVal = new Integer(pReg->get());
    }
    else {
      static char sFormat[] = "Value $%x is an invalid memory address";
      char sMsg[sizeof(sFormat) + 10];
      sprintf(sMsg, sFormat, (int)iOp->getVal());
      throw new Error(string(sMsg));
    }
  }
  else if (isFloat(operand) ) {
    Float* fOp = (Float*)(operand);
    rVal = new Float(fOp->getVal());
  }
  else {
    throw new TypeMismatch(showOp(), operand->showType());
  }

  return rVal;
}

/******************************************************************************
 The unary '*' operator - indirect access
******************************************************************************/
OpAddressOf::OpAddressOf(Expression* expr)
  : UnaryOperator("&", expr)
{
}

OpAddressOf::~OpAddressOf()
{
}

Value* OpAddressOf::evaluate()
{
  Value* tmp;

  // start evaluating our operand expression:
  LiteralSymbol *pSym = dynamic_cast<LiteralSymbol *>(expr);
  if (pSym) {
    tmp = applyOp(pSym->GetSymbol());
  }
  else {
    throw new TypeMismatch(showOp(), expr->showType());
  }
  return tmp;
}

Value* OpAddressOf::applyOp(Value* operand)
{
  Value* rVal=0;

  register_symbol *pReg =dynamic_cast<register_symbol*>(operand);
  if (pReg) {
    rVal = new Integer(pReg->getAddress());
  }
  else {
    AliasedSymbol *pSym = dynamic_cast<AliasedSymbol*>(operand);
    if (pSym) {
      pReg = dynamic_cast<register_symbol*>(pSym);
      if (pReg) {
        rVal = new Integer(pReg->getAddress());
      }
    }
  }
  if(rVal==0) {
    throw new TypeMismatch(showOp(), operand->showType());
  }
  return rVal;
}



syntax highlighted by Code2HTML, v. 0.9.1