lsnes/include/library/mathexpr.hpp
2014-11-11 20:56:54 +02:00

280 lines
6.4 KiB
C++

#ifndef _library__mathexpr__hpp__included__
#define _library__mathexpr__hpp__included__
#include <functional>
#include <vector>
#include <stdexcept>
#include "gc.hpp"
#include "mathexpr-error.hpp"
#include <set>
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<std::function<value()>> 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<operinfo*> operations() = 0;
void* copy_allocate(void* src)
{
void* p = allocate();
try {
copy(p, src);
} catch(...) {
deallocate(p);
throw;
}
return p;
}
};
template<class T> struct operinfo_wrapper : public operinfo
{
operinfo_wrapper(std::string funcname, T (*_fn)(std::vector<std::function<T&()>> promises))
: operinfo(funcname), fn(_fn)
{
}
operinfo_wrapper(std::string opername, unsigned _operands, int _percedence, bool _rtl,
T (*_fn)(std::vector<std::function<T&()>> promises))
: operinfo(opername, _operands, _percedence, _rtl), fn(_fn)
{
}
~operinfo_wrapper()
{
}
void evaluate(value target, std::vector<std::function<value()>> promises)
{
std::vector<std::function<T&()>> _promises;
for(auto i : promises) {
std::function<value()> 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<std::function<T&()>> promises);
};
template<class T> struct opfun_info
{
std::string name;
T (*_fn)(std::vector<std::function<T&()>> promises);
bool is_operator;
unsigned operands;
int precedence;
bool rtl;
};
template<class T> struct operinfo_set
{
operinfo_set(std::initializer_list<opfun_info<T>> list)
{
for(auto i : list) {
if(i.is_operator)
set.insert(new operinfo_wrapper<T>(i.name, i.operands, i.precedence,
i.rtl, i._fn));
else
set.insert(new operinfo_wrapper<T>(i.name, i._fn));
}
}
~operinfo_set()
{
for(auto i : set)
delete i;
}
std::set<operinfo*>& get_set()
{
return set;
}
private:
std::set<operinfo*> set;
};
template<class T> 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<operinfo*> operations()
{
std::set<operinfo*> 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<mathexpr> 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<GC::pointer<mathexpr>> _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<mathexpr> parse(typeinfo& _type, const std::string& expr,
std::function<GC::pointer<mathexpr>(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<mathexpr*> arguments;
mutable bool owns_operator;
};
}
#endif