|
|
|
#include <cmath>
|
|
|
|
#include "object.h"
|
|
|
|
|
|
|
|
template<class O>
|
|
|
|
struct Valued
|
|
|
|
{
|
|
|
|
double operator ()(const O* q, bool* isok) {return q->Value();}
|
|
|
|
};
|
|
|
|
|
|
|
|
template<>
|
|
|
|
struct Valued<ObjectString>
|
|
|
|
{
|
|
|
|
double operator ()(const ObjectString* q, bool* isok) {double d=0; if(!str2double(q->Value(),&d)) *isok=false; return d;}
|
|
|
|
};
|
|
|
|
|
|
|
|
template<class O>
|
|
|
|
struct Valuei
|
|
|
|
{
|
|
|
|
int64_t operator ()(const O* q, bool* isok) {return q->Value();}
|
|
|
|
};
|
|
|
|
|
|
|
|
template<>
|
|
|
|
struct Valuei<ObjectString>
|
|
|
|
{
|
|
|
|
int64_t operator ()(const ObjectString* q, bool* isok) {int64_t i=0; if(!str2int(q->Value(),&i)) *isok=false; return i;}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
template<class T> class OpAdd {public: static T V(T a1, T a2) {return a1+a2;}};
|
|
|
|
template<class T> class OpSub {public: static T V(T a1, T a2) {return a1-a2;}};
|
|
|
|
template<class T> class OpMul {public: static T V(T a1, T a2) {return a1*a2;}};
|
|
|
|
template<class T> class OpDiv {public: static T V(T a1, T a2) {return a1/a2;}};
|
|
|
|
template<class T> class OpPow {public: static T V(T a1, T a2) {return pow(a1,a2);}};
|
|
|
|
template<class T> class OpNeg {public: static T V(T a) {return -a;}};
|
|
|
|
template<class T> class OpPos {public: static T V(T a) {return +a;}};
|
|
|
|
|
|
|
|
template<template<typename> class Op, bool intArifm=true>
|
|
|
|
ObjectBase* Arifm2(const ObjectList* input)
|
|
|
|
{
|
|
|
|
if(input->Size()!=2) return new ObjectError("Arifmetic binary operator","incorrect number of arguments");
|
|
|
|
const ObjectBase *arg1=input->At(0),*arg2=input->At(1);
|
|
|
|
OBTypeM<Valuei,ObjectInt,ObjectString> i1(arg1), i2(arg2);
|
|
|
|
OBTypeM<Valued,ObjectReal,ObjectInt,ObjectString> r1(arg1), r2(arg2);
|
|
|
|
bool isok1=true, isok2=true;
|
|
|
|
|
|
|
|
// Integer arifmetic
|
|
|
|
if(i1 && i2 && intArifm)
|
|
|
|
{
|
|
|
|
int64_t v1=i1(&isok1),v2=i2(&isok2);
|
|
|
|
if(isok1 && isok2) return new ObjectInt(Op<int64_t>::V(v1,v2));
|
|
|
|
}
|
|
|
|
|
|
|
|
isok1=isok2=true;
|
|
|
|
// Real arifmetic
|
|
|
|
if(r1 && r2)
|
|
|
|
{
|
|
|
|
double v1=r1(&isok1),v2=r2(&isok2);
|
|
|
|
if(isok1 && isok2) return new ObjectReal(Op<double>::V(v1,v2));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Analyze error
|
|
|
|
// Check first argument
|
|
|
|
switch(r1.Error())
|
|
|
|
{
|
|
|
|
case(OBTypeErr::OK): if(!isok1) return new ObjectError("Arifmetic binary operator","failed conversion of first argument to double"); else break;
|
|
|
|
case(OBTypeErr::NULLPTR): return new ObjectError("Arifmetic binary operator","first argument is nullptr"); // Impossible case
|
|
|
|
case(OBTypeErr::TYPEMISMATCH): return new ObjectError("Arifmetic binary operator","first argument has incorrect type");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Firs argument is ok, check second
|
|
|
|
switch(r2.Error())
|
|
|
|
{
|
|
|
|
case(OBTypeErr::OK): if(!isok2) return new ObjectError("Arifmetic binary operator","failed conversion of second argument to double"); else break;
|
|
|
|
case(OBTypeErr::NULLPTR): return new ObjectError("Arifmetic binary operator","second argument is nullptr"); // Impossible case
|
|
|
|
case(OBTypeErr::TYPEMISMATCH): return new ObjectError("Arifmetic binary operator","second argument has incorrect type");
|
|
|
|
}
|
|
|
|
|
|
|
|
return new ObjectError("Arifmetic binary operator","unknown error"); // Impossible case
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
template<template<typename> class Op, bool intArifm=true>
|
|
|
|
ObjectBase* Arifm1(const ObjectList* input)
|
|
|
|
{
|
|
|
|
if(input->Size()!=1) return new ObjectError("Arifmetic unary operator","incorrect number of arguments");
|
|
|
|
const ObjectBase *arg=input->At(0);
|
|
|
|
OBTypeM<Valuei,ObjectInt,ObjectString> i(arg);
|
|
|
|
OBTypeM<Valued,ObjectReal,ObjectString> r(arg);
|
|
|
|
bool isok;
|
|
|
|
|
|
|
|
// Integer arifmetic
|
|
|
|
isok=true;
|
|
|
|
if(i && intArifm)
|
|
|
|
{
|
|
|
|
int64_t v=i(&isok);
|
|
|
|
if(isok) return new ObjectInt(Op<int64_t>::V(v));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Real arifmetic
|
|
|
|
isok=true;
|
|
|
|
if(r)
|
|
|
|
{
|
|
|
|
double v=r(&isok);
|
|
|
|
if(isok) return new ObjectReal(Op<double>::V(v));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Analyze error
|
|
|
|
switch(r.Error())
|
|
|
|
{
|
|
|
|
case(OBTypeErr::OK): if(!isok) return new ObjectError("Arifmetic unary operator","failed conversion of argument to double"); else break;
|
|
|
|
case(OBTypeErr::NULLPTR): return new ObjectError("Arifmetic unary operator","argument is nullptr"); // Impossible case
|
|
|
|
case(OBTypeErr::TYPEMISMATCH): return new ObjectError("Arifmetic unary operator","argument has incorrect type");
|
|
|
|
}
|
|
|
|
|
|
|
|
return new ObjectError("Arifmetic unary operator","unknown error"); // Impossible case
|
|
|
|
}
|