#include #include "object.h" template struct Valued { double operator ()(const O* q, bool* isok) {return q->Value();} }; template<> struct Valued { double operator ()(const ObjectString* q, bool* isok) {double d=0; if(!str2double(q->Value(),&d)) *isok=false; return d;} }; template struct Valuei { int64_t operator ()(const O* q, bool* isok) {return q->Value();} }; template<> struct Valuei { int64_t operator ()(const ObjectString* q, bool* isok) {int64_t i=0; if(!str2int(q->Value(),&i)) *isok=false; return i;} }; template class OpAdd {public: static T V(T a1, T a2) {return a1+a2;}}; template class OpSub {public: static T V(T a1, T a2) {return a1-a2;}}; template class OpMul {public: static T V(T a1, T a2) {return a1*a2;}}; template class OpDiv {public: static T V(T a1, T a2) {return a1/a2;}}; template class OpPow {public: static T V(T a1, T a2) {return pow(a1,a2);}}; template class OpNeg {public: static T V(T a) {return -a;}}; template class OpPos {public: static T V(T a) {return +a;}}; template 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 i1(arg1), i2(arg2); OBTypeM 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::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::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 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 i(arg); OBTypeM r(arg); bool isok; // Integer arifmetic isok=true; if(i && intArifm) { int64_t v=i(&isok); if(isok) return new ObjectInt(Op::V(v)); } // Real arifmetic isok=true; if(r) { double v=r(&isok); if(isok) return new ObjectReal(Op::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 }