#ifndef _library__mathexpr__hpp__included__ #define _library__mathexpr__hpp__included__ #include #include #include #include "gc.hpp" #include "mathexpr-error.hpp" #include namespace mathexpr { struct typeinfo; struct mathexpr; struct value { typeinfo* type; void* _value; }; struct _format { enum _type { BOOLEAN, BINARY, OCTAL, DECIMAL, HEXADECIMAL, STRING, DEFAULT, } type; bool showsign; bool fillzeros; int width; int precision; bool uppercasehex; }; struct operinfo { operinfo(std::string funcname); operinfo(std::string opername, unsigned _operands, int _percedence, bool _rtl = false); virtual ~operinfo(); virtual void evaluate(value target, std::vector> promises) = 0; const std::string fnname; const bool is_operator; const unsigned operands; //Only for operators (max 2 operands). const int precedence; //Higher binds more tightly. const bool rtl; //If true, Right-to-left associvity. }; struct typeinfo { virtual ~typeinfo(); virtual void* allocate() = 0; virtual void* parse(const std::string& str, bool string) = 0; virtual void parse_u(void* obj, uint64_t v) = 0; virtual void parse_s(void* obj, int64_t v) = 0; virtual void parse_f(void* obj, double v) = 0; virtual void parse_b(void* obj, bool v) = 0; virtual void scale(void* val, uint64_t scale) = 0; virtual void deallocate(void* obj) = 0; virtual void copy(void* target, void* source) = 0; virtual std::string tostring(void* obj) = 0; virtual std::string format(void* obj, _format fmt) = 0; virtual uint64_t tounsigned(void* obj) = 0; virtual int64_t tosigned(void* obj) = 0; virtual bool toboolean(void* obj) = 0; virtual std::set operations() = 0; void* copy_allocate(void* src) { void* p = allocate(); try { copy(p, src); } catch(...) { deallocate(p); throw; } return p; } }; template struct operinfo_wrapper : public operinfo { operinfo_wrapper(std::string funcname, T (*_fn)(std::vector> promises)) : operinfo(funcname), fn(_fn) { } operinfo_wrapper(std::string opername, unsigned _operands, int _percedence, bool _rtl, T (*_fn)(std::vector> promises)) : operinfo(opername, _operands, _percedence, _rtl), fn(_fn) { } ~operinfo_wrapper() { } void evaluate(value target, std::vector> promises) { std::vector> _promises; for(auto i : promises) { std::function f = i; _promises.push_back([f, this]() -> T& { auto r = f(); return *(T*)r._value; }); } *(T*)(target._value) = fn(_promises); } private: T (*fn)(std::vector> promises); }; template struct opfun_info { std::string name; T (*_fn)(std::vector> promises); bool is_operator; unsigned operands; int precedence; bool rtl; }; template struct operinfo_set { operinfo_set(std::initializer_list> list) { for(auto i : list) { if(i.is_operator) set.insert(new operinfo_wrapper(i.name, i.operands, i.precedence, i.rtl, i._fn)); else set.insert(new operinfo_wrapper(i.name, i._fn)); } } ~operinfo_set() { for(auto i : set) delete i; } std::set& get_set() { return set; } private: std::set set; }; template struct typeinfo_wrapper : public typeinfo { struct unsigned_tag {}; struct signed_tag {}; struct float_tag {}; struct boolean_tag {}; ~typeinfo_wrapper() { } void* allocate() { return new T; } void* parse(const std::string& str, bool string) { return new T(str, string); } void parse_u(void* obj, uint64_t v) { *(T*)obj = T(unsigned_tag(), v); } void parse_s(void* obj, int64_t v) { *(T*)obj = T(signed_tag(), v); } void parse_f(void* obj, double v) { *(T*)obj = T(float_tag(), v); } void parse_b(void* obj, bool b) { *(T*)obj = T(boolean_tag(), b); } void deallocate(void* obj) { delete (T*)obj; } void copy(void* target, void* source) { *(T*)target = *(T*)source; } std::string tostring(void* obj) { return ((T*)obj)->tostring(); } std::string format(void* obj, _format fmt) { return ((T*)obj)->format(fmt); } uint64_t tounsigned(void* obj) { return ((T*)obj)->tounsigned(); } int64_t tosigned(void* obj) { return ((T*)obj)->tosigned(); } bool toboolean(void* obj) { return ((T*)obj)->toboolean(); } void scale(void* val, uint64_t _scale) { return ((T*)val)->scale(_scale); } std::set operations() { std::set ret; auto tmp = T::operations(); for(auto i : tmp) ret.insert(i); return ret; } }; class mathexpr : public GC::item { public: enum eval_state { TO_BE_EVALUATED, //Not even attempted to evaluate yet. EVALUATING, //Evaluation in progress. EVALUATED, //Evaluation completed, value available. FIXED, //This operand has fixed value. UNDEFINED, //This operand has undefined value. FAILED, //Evaluation failed. FORWARD, //Forward evaluation to first of args. FORWARD_EVALING, //Forward evaluation to first of args, evaluating. FORWARD_EVALD, //Forward evaluation to first of args, evaluated. }; //Undefined value of specified type. mathexpr(typeinfo* _type); //Forward evaluation. mathexpr(typeinfo* _type, GC::pointer fwd); //Value of specified type. mathexpr(value value); //Value of specified type. mathexpr(typeinfo* _type, const std::string& value, bool string); //Specified Operator. mathexpr(typeinfo* _type, operinfo* fn, std::vector> _args, bool _owns_operator = false); //Dtor. ~mathexpr(); //Copy ctor. mathexpr(const mathexpr& m); mathexpr& operator=(const mathexpr& m); //Evaluate. Returns pointer to internal state. value evaluate(); //Get type. typeinfo& get_type() { return type; } //Reset. void reset(); //Parse an expression. static GC::pointer parse(typeinfo& _type, const std::string& expr, std::function(const std::string&)> vars); protected: void trace(); private: void mark_error_and_throw(error::errorcode _errcode, const std::string& _error); eval_state state; typeinfo& type; //Type of value. void* _value; //Value if state is EVALUATED or FIXED. operinfo* fn; //Function (if state is TO_BE_EVALUATED, EVALUATING or EVALUATED) error::errorcode errcode; //Error code if state is FAILED. std::string _error; //Error message if state is FAILED. std::vector arguments; mutable bool owns_operator; }; } #endif