/*************************************************************************
*									 *
*	 YAP Prolog 							 *
*									 *
*	Yap Prolog was developed at NCCUP - Universidade do Porto	 *
*									 *
* Copyright L.Damas, V.S.Costa and Universidade do Porto 1985-1997	 *
*									 *
**************************************************************************
*									 *
* File:		evalis.c						 *
* Last rev:								 *
* mods:									 *
* comments:	is/3 predicate						 *
*									 *
*************************************************************************/
#ifdef SCCS
static char     SccsId[] = "%W% %G%";
#endif /* SCCS */

/*
 * This predicates had to be developed here because of a bug in the MPW
 * compiler, which was not able to compile the original eval.c 
 */

#include "Yap.h"
#include "Yatom.h"
#include "Heap.h"
#include "eval.h"


int 
UnEvalInt(BITS16 op, Int i1)
{
  switch(op) {
  case e_uminus:
    REvalInt(-i1);
  case e_abs:
#if SHORT_INTS
#if HAVE_LABS
    REvalInt((Int)labs((long int)i1));
#else
    REvalInt((i1 >= 0 ? i1 : -i1));
#endif
#else
    REvalInt(abs(i1));
#endif
  case e_msb:
    REvalInt(msb(i1));
  case e_uplus:
    REvalInt(i1);
  case e_not:
    REvalInt(~i1);
  case e_exp:
    REvalFl(exp(FL(i1)));
  case e_log:
    REvalFl(log(FL(i1)));
  case e_log10:
    REvalFl(log10(FL(i1)));
  case e_sqrt:
    REvalFl(sqrt(FL(i1)));
  case e_sin:
    REvalFl(sin(FL(i1)));
  case e_cos:
    REvalFl(cos(FL(i1)));
  case e_tan:
    REvalFl(tan(FL(i1)));
  case e_sinh:
    REvalFl(sinh(FL(i1)));
  case e_cosh:
    REvalFl(cosh(FL(i1)));
  case e_tanh:
    REvalFl(tanh(FL(i1)));
  case e_asin:
    REvalFl(asin(FL(i1)));
  case e_acos:
    REvalFl(acos(FL(i1)));
  case e_atan:
    REvalFl(atan(FL(i1)));
  case e_asinh:
    REvalFl(asinh(FL(i1)));
  case e_acosh:
    REvalFl(acosh(FL(i1)));
  case e_atanh:
    REvalFl(atanh(FL(i1)));
  case e_floor:
    if (yap_flags[LANGUAGE_MODE_FLAG] == 1) { /* iso */
      Error(TYPE_ERROR_FLOAT, MkIntegerTerm(i1), "floor/1");
      P = (yamop *)FAILCODE;
      REvalError();	    
    } else {
      REvalFl(FL(i1));
    }
  case e_round:
    if (yap_flags[LANGUAGE_MODE_FLAG] == 1) { /* iso */
      Error(TYPE_ERROR_FLOAT, MkIntegerTerm(i1), "round/1");
      P = (yamop *)FAILCODE;
      REvalError();	    
    } else {
      REvalFl(FL(i1));
    }
  case e_ceiling:
    if (yap_flags[LANGUAGE_MODE_FLAG] == 1) { /* iso */
      Error(TYPE_ERROR_FLOAT, MkIntegerTerm(i1), "floor/1");
      P = (yamop *)FAILCODE;
      REvalError();	    
    } else {
      REvalFl(FL(i1));
    }
  case e_truncate:
    if (yap_flags[LANGUAGE_MODE_FLAG] == 1) { /* iso */
      Error(TYPE_ERROR_FLOAT, MkIntegerTerm(i1), "truncate/1");
      P = (yamop *)FAILCODE;
      REvalError();	    
    } else {
      REvalFl(FL(i1));
    }
  case e_integer:
    REvalInt(i1);
  case e_float:
    REvalFl(FL(i1));
  case e_fmodf:
    if (yap_flags[LANGUAGE_MODE_FLAG] == 1) { /* iso */
      Error(TYPE_ERROR_FLOAT,MkIntegerTerm(i1),"mod/2");
      P = (yamop *)FAILCODE;
      REvalError();	  
    } else {
      REvalFl(FL(0.0));
    }
  case e_imodf:
    if (yap_flags[LANGUAGE_MODE_FLAG] == 1) { /* iso */
      /* iso does not allow integer arguments to this procedure */
      Error(TYPE_ERROR_FLOAT,MkIntegerTerm(i1),"mod/2");
      P = (yamop *)FAILCODE;
      REvalError();	  
    } else {
      REvalFl(FL(i1));
    }
  case e_sign:
    if (i1 < 0) {
      REvalInt(-1);
    } else if (i1 == 0) {
      REvalInt(0);
    } else {
      REvalInt(1);
    }
  default:
    {
      Term t, ti[2];

      ti[0] = MkAtomTerm(NameOfFunctor(FunctorOfTerm(current_eval_term)));
      ti[1] = MkIntegerTerm(1);
      t = MkApplTerm(MkFunctor(LookupAtom("/"),1), 1, ti);
      Error(TYPE_ERROR_EVALUABLE, t,
	    "arithmetic expression  %s/%d",
	    RepAtom(NameOfFunctor(FunctorOfTerm(current_eval_term)))->StrOfAE,
	    2
	    );
      P = (yamop *)FAILCODE;
      REvalError();
    }
  }
}

Int 
p_unary_is(void)
{
  register BITS16 OpNum;
  Term t2, t3;
  int flag;

  current_eval_term = MkIntTerm(1);
  t2 = Deref(ARG2);
  if (IsVarTerm(t2)) {
    Error(INSTANTIATION_ERROR, t2, "operation for is/3");
    P = (yamop *)FAILCODE;
    return(FALSE);
  }
  if (IsAtomTerm(t2)) {
    Atom            name;
    Prop            p;
    name = AtomOfTerm(t2);
    if ((p = GetExpProp(name, 1)) == NIL) {
      Term t, ti[2];

      ti[0] = MkAtomTerm(name);
      ti[1] = MkIntegerTerm(1);
      t = MkApplTerm(MkFunctor(LookupAtom("/"),2), 2, ti);
      Error(TYPE_ERROR_EVALUABLE, t,
	    "arithmetic expression %s/%d",
	    RepAtom(name)->StrOfAE,
	    1
	    );
      P = (yamop *)FAILCODE;
      return(FALSE);
    }
    OpNum = RepExpProp(p)->ENoOfEE;
  } else if (IsIntTerm(t2))
    OpNum = IntOfTerm(t2);
  else
    return (FALSE);
  t3 = Deref(ARG3);
  if (IsVarTerm(t3)) {
    int op = 0;
    
    while (InitTab[op].eno != OpNum) op++;
    Error(INSTANTIATION_ERROR, t3, "arithmetic expression %s/1", InitTab[op].OpName);
    P = (yamop *)FAILCODE;
    return(FALSE);
  }
  if (IsIntegerTerm(t3)) {
    flag = UnEvalInt(OpNum, IntegerOfTerm(t3));
  } else if (IsFloatTerm(t3)) {
    flag = UnEvalFl(OpNum, FloatOfTerm(t3));    
  } else {
    int aflag = Eval(t3);
    if (aflag == FError) {
      return(FALSE);
    } else if (aflag == FInt) {
      flag = UnEvalInt(OpNum, eval_int);
    } else {
      flag = UnEvalFl(OpNum, eval_flt);
    }
  }
  if (flag == FError) {
    return(FALSE);
  } else if (flag == FInt) {
    return(unify_constant(ARG1,MkIntegerTerm(eval_int)));
  } else {
    return(unify_constant(ARG1,MkFloatTerm(eval_flt)));    
  }
}