lsnes/include/library/mathexpr.hpp

281 lines
6.4 KiB
C++
Raw Normal View History

2014-01-10 12:09:19 +02:00
#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>
2014-05-14 11:43:25 +03:00
namespace mathexpr
{
struct typeinfo;
2014-01-10 12:09:19 +02:00
struct mathexpr;
2014-05-14 11:43:25 +03:00
struct value
2014-01-10 12:09:19 +02:00
{
2014-05-14 11:43:25 +03:00
typeinfo* type;
void* _value;
2014-01-10 12:09:19 +02:00
};
2014-05-14 11:43:25 +03:00
struct _format
2014-01-10 12:09:19 +02:00
{
enum _type
{
BOOLEAN,
BINARY,
OCTAL,
DECIMAL,
HEXADECIMAL,
STRING,
DEFAULT,
} type;
bool showsign;
bool fillzeros;
int width;
int precision;
bool uppercasehex;
};
2014-05-14 11:43:25 +03:00
struct operinfo
2014-01-10 12:09:19 +02:00
{
2014-05-14 11:43:25 +03:00
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;
2014-01-10 12:09:19 +02:00
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.
};
2014-05-14 11:43:25 +03:00
struct typeinfo
2014-01-10 12:09:19 +02:00
{
2014-05-14 11:43:25 +03:00
virtual ~typeinfo();
2014-01-10 12:09:19 +02:00
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;
2014-11-11 20:56:54 +02:00
virtual void parse_b(void* obj, bool v) = 0;
2014-01-10 12:09:19 +02:00
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;
2014-05-14 11:43:25 +03:00
virtual std::string format(void* obj, _format fmt) = 0;
2014-01-10 12:09:19 +02:00
virtual uint64_t tounsigned(void* obj) = 0;
virtual int64_t tosigned(void* obj) = 0;
virtual bool toboolean(void* obj) = 0;
2014-05-14 11:43:25 +03:00
virtual std::set<operinfo*> operations() = 0;
2014-01-10 12:09:19 +02:00
void* copy_allocate(void* src)
{
void* p = allocate();
try {
copy(p, src);
} catch(...) {
deallocate(p);
throw;
}
return p;
}
};
2014-05-14 11:43:25 +03:00
template<class T> struct operinfo_wrapper : public operinfo
2014-01-10 12:09:19 +02:00
{
2014-05-14 11:43:25 +03:00
operinfo_wrapper(std::string funcname, T (*_fn)(std::vector<std::function<T&()>> promises))
: operinfo(funcname), fn(_fn)
2014-01-10 12:09:19 +02:00
{
}
2014-05-14 11:43:25 +03:00
operinfo_wrapper(std::string opername, unsigned _operands, int _percedence, bool _rtl,
2014-01-10 12:09:19 +02:00
T (*_fn)(std::vector<std::function<T&()>> promises))
2014-05-14 11:43:25 +03:00
: operinfo(opername, _operands, _percedence, _rtl), fn(_fn)
2014-01-10 12:09:19 +02:00
{
}
2014-05-14 11:43:25 +03:00
~operinfo_wrapper()
2014-01-10 12:09:19 +02:00
{
}
2014-05-14 11:43:25 +03:00
void evaluate(value target, std::vector<std::function<value()>> promises)
2014-01-10 12:09:19 +02:00
{
std::vector<std::function<T&()>> _promises;
for(auto i : promises) {
2014-05-14 11:43:25 +03:00
std::function<value()> f = i;
2014-01-10 12:09:19 +02:00
_promises.push_back([f, this]() -> T& {
auto r = f();
2014-05-14 11:43:25 +03:00
return *(T*)r._value;
2014-01-10 12:09:19 +02:00
});
}
2014-05-14 11:43:25 +03:00
*(T*)(target._value) = fn(_promises);
2014-01-10 12:09:19 +02:00
}
private:
T (*fn)(std::vector<std::function<T&()>> promises);
};
2014-05-14 11:43:25 +03:00
template<class T> struct opfun_info
2014-01-10 12:09:19 +02:00
{
std::string name;
T (*_fn)(std::vector<std::function<T&()>> promises);
bool is_operator;
unsigned operands;
int precedence;
bool rtl;
};
2014-05-14 11:43:25 +03:00
template<class T> struct operinfo_set
2014-01-10 12:09:19 +02:00
{
2014-05-14 11:43:25 +03:00
operinfo_set(std::initializer_list<opfun_info<T>> list)
2014-01-10 12:09:19 +02:00
{
for(auto i : list) {
if(i.is_operator)
2014-05-14 11:43:25 +03:00
set.insert(new operinfo_wrapper<T>(i.name, i.operands, i.precedence,
2014-01-10 12:09:19 +02:00
i.rtl, i._fn));
else
2014-05-14 11:43:25 +03:00
set.insert(new operinfo_wrapper<T>(i.name, i._fn));
2014-01-10 12:09:19 +02:00
}
}
2014-05-14 11:43:25 +03:00
~operinfo_set()
2014-01-10 12:09:19 +02:00
{
for(auto i : set)
delete i;
}
2014-05-14 11:43:25 +03:00
std::set<operinfo*>& get_set()
2014-01-10 12:09:19 +02:00
{
return set;
}
private:
2014-05-14 11:43:25 +03:00
std::set<operinfo*> set;
2014-01-10 12:09:19 +02:00
};
2014-05-14 11:43:25 +03:00
template<class T> struct typeinfo_wrapper : public typeinfo
2014-01-10 12:09:19 +02:00
{
struct unsigned_tag {};
struct signed_tag {};
struct float_tag {};
2014-11-11 20:56:54 +02:00
struct boolean_tag {};
2014-05-14 11:43:25 +03:00
~typeinfo_wrapper()
2014-01-10 12:09:19 +02:00
{
}
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);
}
2014-11-11 20:56:54 +02:00
void parse_b(void* obj, bool b)
{
*(T*)obj = T(boolean_tag(), b);
}
2014-01-10 12:09:19 +02:00
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();
}
2014-05-14 11:43:25 +03:00
std::string format(void* obj, _format fmt)
2014-01-10 12:09:19 +02:00
{
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);
}
2014-05-14 11:43:25 +03:00
std::set<operinfo*> operations()
2014-01-10 12:09:19 +02:00
{
2014-05-14 11:43:25 +03:00
std::set<operinfo*> ret;
2014-01-10 12:09:19 +02:00
auto tmp = T::operations();
for(auto i : tmp)
ret.insert(i);
return ret;
}
};
class mathexpr : public GC::item
2014-01-10 12:09:19 +02:00
{
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.
2014-01-10 12:09:19 +02:00
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.
2014-05-14 11:43:25 +03:00
mathexpr(typeinfo* _type);
2014-01-10 12:09:19 +02:00
//Forward evaluation.
mathexpr(typeinfo* _type, GC::pointer<mathexpr> fwd);
2014-01-10 12:09:19 +02:00
//Value of specified type.
2014-05-14 11:43:25 +03:00
mathexpr(value value);
2014-01-10 12:09:19 +02:00
//Value of specified type.
2014-05-14 11:43:25 +03:00
mathexpr(typeinfo* _type, const std::string& value, bool string);
2014-01-10 12:09:19 +02:00
//Specified Operator.
mathexpr(typeinfo* _type, operinfo* fn, std::vector<GC::pointer<mathexpr>> _args,
2014-01-10 12:09:19 +02:00
bool _owns_operator = false);
//Dtor.
~mathexpr();
//Copy ctor.
mathexpr(const mathexpr& m);
mathexpr& operator=(const mathexpr& m);
//Evaluate. Returns pointer to internal state.
2014-05-14 11:43:25 +03:00
value evaluate();
2014-01-10 12:09:19 +02:00
//Get type.
2014-05-14 11:43:25 +03:00
typeinfo& get_type() { return type; }
2014-01-10 12:09:19 +02:00
//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);
2014-01-10 12:09:19 +02:00
protected:
void trace();
private:
2014-05-14 11:43:25 +03:00
void mark_error_and_throw(error::errorcode _errcode, const std::string& _error);
2014-01-10 12:09:19 +02:00
eval_state state;
2014-05-14 11:43:25 +03:00
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.
2014-01-10 12:09:19 +02:00
std::vector<mathexpr*> arguments;
mutable bool owns_operator;
};
2014-05-14 11:43:25 +03:00
}
2014-01-10 12:09:19 +02:00
#endif