Last active
August 29, 2015 14:04
-
-
Save 2sin18/25be652b3e6b158a1dcb to your computer and use it in GitHub Desktop.
Boolang for DSL in C++
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdlib.h> | |
#include <stdint.h> | |
/* | |
//////////////////////////////////////////////////////////////////////////////// | |
== [[bet]] binary expression tree | |
A 'bet' is a binary expression tree, which could be any type as below: | |
- An indicator, e.g. dpa, dpb | |
- An arithmetic combination of indicators, e.g. dpa + dpb, max(dpa, dpb) | |
- A simple logic expression, e.g. dpa > dpb + 3, dpa + dpb > 5 | |
- A combination of logic expression, e.g. dpa > dpb + 3 || dpa + dpb > 5 | |
- An aggregation expression, e.g. countif(dpa > dpb + 3) | |
Above all, a 'bet' could be numeric, or boolean. And a 'bet' could be at | |
'for-each' level (e.g. dpa + 2) or at 'for-all' level (e.g. countif(dpa > 0)). | |
//////////////////////////////////////////////////////////////////////////////// | |
*/ | |
namespace boo { | |
/* | |
//////////////////////////////////////////////////////////////////////////////// | |
== [[handle_base]] class template `handle_base` | |
A `handle_base` is the base class of all bets. | |
//////////////////////////////////////////////////////////////////////////////// | |
*/ | |
struct handle_base | |
{ | |
bool retain() | |
{ | |
return ++_rc; | |
} | |
bool release() | |
{ | |
return --_rc; | |
} | |
protected: | |
handle_base(): | |
_rc(0) | |
{ | |
} | |
~handle_base() | |
{ | |
} | |
private: | |
handle_base(const handle_base&); | |
handle_base& operator=(const handle_base&); | |
volatile size_t _rc; | |
}; | |
/* | |
//////////////////////////////////////////////////////////////////////////////// | |
== [[handle]] class template `handle` | |
A `handle` is a reference-counted const pointer to a binary expression tree. | |
A lot of operators have been overrided for this type to benefit filter | |
combination. | |
//////////////////////////////////////////////////////////////////////////////// | |
*/ | |
template<class T> | |
struct handle | |
{ | |
handle(const handle<T>& handle1): | |
_ptr(handle1._ptr) | |
{ | |
if (_ptr) { | |
_ptr->retain(); | |
} | |
} | |
handle(const T* ptr1): | |
_ptr(const_cast<T*>(ptr1)) | |
{ | |
if (_ptr) { | |
_ptr->retain(); | |
} | |
} | |
~handle() | |
{ | |
if (!_ptr) { | |
return; | |
} | |
if (_ptr->release()) { | |
return; | |
} | |
typedef char type_must_be_complete[sizeof(T) ? 1 : -1]; | |
(void) sizeof(type_must_be_complete); | |
delete (_ptr); | |
_ptr = NULL; | |
} | |
const T* | |
get() const | |
{ | |
return _ptr; | |
} | |
operator bool() const | |
{ | |
return _ptr != NULL; | |
} | |
const T* | |
operator->() const | |
{ | |
return _ptr; | |
} | |
bool | |
operator==(const handle<T>& handle1) const | |
{ | |
return handle1._ptr == _ptr; | |
} | |
private: | |
handle<T>& operator=(const handle<T>&); | |
static int EXTENDS(handle_base*); | |
static void EXTENDS(...); | |
enum { CHECK_EXTENDS = sizeof(EXTENDS((T*) NULL)) }; | |
template<handle<typename T::left_type> (T::*) () const, | |
handle<typename T::right_type> (T::*) () const> class METHODS {}; | |
static int EXISTS(METHODS<& T::left, & T::right>*); | |
static void EXISTS(...); | |
enum { CHECK_EXISTS = sizeof(EXISTS(NULL)) }; | |
T* _ptr; | |
}; | |
template<class T> | |
handle<T> | |
handle_to(const T* ptr1) | |
{ | |
return handle<T>(ptr1); | |
} | |
/* | |
//////////////////////////////////////////////////////////////////////////////// | |
== [[bet]] class template `bet` | |
A `bet` is a binary expression tree. It's base class of all bets. | |
//////////////////////////////////////////////////////////////////////////////// | |
*/ | |
enum bet_type | |
{ | |
VOID, | |
NUMERIC, | |
BOOLEAN | |
}; | |
template<bet_type TYPE, class TAG> | |
struct bet | |
{ | |
protected: | |
bet() | |
{ | |
} | |
}; | |
struct nil_tag | |
{ | |
}; | |
typedef bet<VOID, nil_tag> NIL; | |
typedef handle<NIL> nil_t; | |
template<> | |
struct bet<VOID, nil_tag>: public handle_base | |
{ | |
typedef NIL left_type; | |
typedef NIL right_type; | |
bet(): | |
handle_base() | |
{ | |
} | |
handle<left_type> left() const | |
{ | |
return NULL; | |
} | |
handle<right_type> right() const | |
{ | |
return NULL; | |
} | |
}; | |
struct fact_tag | |
{ | |
}; | |
typedef bet<NUMERIC, fact_tag> FACT; | |
typedef handle<FACT> fact_t; | |
template<> | |
struct bet<NUMERIC, fact_tag>: public handle_base | |
{ | |
typedef NIL left_type; | |
typedef NIL right_type; | |
bet(const char* id1): handle_base() | |
{ | |
} | |
handle<left_type> left() const | |
{ | |
return NULL; | |
} | |
handle<right_type> right() const | |
{ | |
return NULL; | |
} | |
const char* id() const | |
{ | |
return _id; | |
} | |
private: | |
static const char* _id; | |
}; | |
fact_t | |
fact(const char* id1) | |
{ | |
return handle_to(new FACT(id1)); | |
} | |
template<class LTAG> | |
struct arith_tag | |
{ | |
}; | |
template<class LTAG> | |
struct bet<NUMERIC, arith_tag<LTAG> >: public handle_base | |
{ | |
typedef bet<NUMERIC, LTAG> left_type; | |
typedef NIL right_type; | |
bet(const handle<left_type>& left1, double multiply1, double plus1): | |
handle_base(), | |
_left(left1), | |
_multiply(multiply1), | |
_plus(plus1) | |
{ | |
} | |
handle<left_type> left() const | |
{ | |
return _left; | |
} | |
handle<right_type> right() const | |
{ | |
return NULL; | |
} | |
double multiply() const | |
{ | |
return _multiply; | |
} | |
double plus() const | |
{ | |
return _plus; | |
} | |
private: | |
handle<left_type> _left; | |
double _multiply; | |
double _plus; | |
}; | |
template<class LTAG> | |
handle<bet<NUMERIC, arith_tag<LTAG> > > | |
operator+(const handle<bet<NUMERIC, LTAG> >& b1, const double x) | |
{ | |
return handle_to(new bet<NUMERIC, arith_tag<LTAG> > (b1, 1.0, x)); | |
} | |
template<class LTAG> | |
handle<bet<NUMERIC, arith_tag<LTAG> > > | |
operator-(const handle<bet<NUMERIC, LTAG> >& b1, const double x) | |
{ | |
return handle_to(new bet<NUMERIC, arith_tag<LTAG> > (b1, 1.0, -x)); | |
} | |
template<class LTAG> | |
handle<bet<NUMERIC, arith_tag<LTAG> > > | |
operator+(const handle<bet<NUMERIC, arith_tag<LTAG> > >& b1, const double x) | |
{ | |
return handle_to(new bet<NUMERIC, arith_tag<LTAG> > (b1->left(), | |
b1->multiply(), b1->plus() + x)); | |
} | |
template<class LTAG> | |
handle<bet<NUMERIC, arith_tag<LTAG> > > | |
operator*(const handle<bet<NUMERIC, LTAG> >& b1, const double x) | |
{ | |
return handle_to(new bet<NUMERIC, arith_tag<LTAG> > (b1, x, 0)); | |
} | |
template<class LTAG> | |
handle<bet<NUMERIC, arith_tag<LTAG> > > | |
operator*(const handle<bet<NUMERIC, arith_tag<LTAG> > >& b1, const double x) | |
{ | |
return handle_to(new bet<NUMERIC, arith_tag<LTAG> > (b1->left(), | |
b1->multiply() * x, b1->plus() * x)); | |
} | |
template<class LTAG, class RTAG> | |
struct numeric_binary_tag | |
{ | |
enum mode | |
{ | |
PLUS, MULTIPLY | |
}; | |
}; | |
template<class LTAG, class RTAG> | |
struct bet<NUMERIC, numeric_binary_tag<LTAG, RTAG> >: public handle_base | |
{ | |
typedef bet<NUMERIC, LTAG> left_type; | |
typedef bet<NUMERIC, RTAG> right_type; | |
typedef typename numeric_binary_tag<LTAG, RTAG>::mode mode_type; | |
bet(const handle<left_type>& left1, const handle<right_type>& right1, | |
mode_type mode1): | |
handle_base(), | |
_left(left1), | |
_right(right1), | |
_mode(mode1) | |
{ | |
} | |
handle<left_type> left() const | |
{ | |
return _left; | |
} | |
handle<right_type> right() const | |
{ | |
return _right; | |
} | |
private: | |
handle<left_type> _left; | |
handle<right_type> _right; | |
mode_type _mode; | |
}; | |
template<class LTAG, class RTAG> | |
handle<bet<NUMERIC, numeric_binary_tag<LTAG, RTAG> > > | |
operator+(const handle<bet<NUMERIC, LTAG> >& b1, | |
const handle<bet<NUMERIC, RTAG> >& b2) | |
{ | |
return handle_to(new bet<NUMERIC, numeric_binary_tag<LTAG, RTAG> > (b1, b2, | |
numeric_binary_tag<LTAG, RTAG>::PLUS)); | |
} | |
template<class LTAG, class RTAG> | |
handle<bet<NUMERIC, numeric_binary_tag<LTAG, RTAG> > > | |
operator*(const handle<bet<NUMERIC, LTAG> >& b1, | |
const handle<bet<NUMERIC, RTAG> >& b2) | |
{ | |
return handle_to(new bet<NUMERIC, | |
numeric_binary_tag<LTAG, RTAG> > (b1, b2, | |
numeric_binary_tag<LTAG, RTAG>::MULTIPLY)); | |
} | |
template<class LTAG> | |
struct positive_tag | |
{ | |
}; | |
template<class LTAG> | |
struct bet<BOOLEAN, positive_tag<LTAG> >: public handle_base | |
{ | |
typedef bet<NUMERIC, LTAG> left_type; | |
typedef NIL right_type; | |
bet(const handle<left_type>& left1): | |
handle_base(), | |
_left(left1) | |
{ | |
} | |
handle<left_type> left() const | |
{ | |
return _left; | |
} | |
handle<right_type> right() const | |
{ | |
return NULL; | |
} | |
private: | |
handle<left_type> _left; | |
}; | |
template<class LTAG> | |
handle<bet<BOOLEAN, positive_tag<arith_tag<LTAG> > > > | |
operator>(const handle<bet<NUMERIC, LTAG> >& b1, const double x) | |
{ | |
return handle_to(new bet<BOOLEAN, positive_tag<arith_tag<LTAG> > > (b1 - x)); | |
} | |
template<class LTAG, class RTAG> | |
struct boolean_binary_tag | |
{ | |
enum mode | |
{ | |
AND, OR | |
}; | |
}; | |
template<class LTAG, class RTAG> | |
struct bet<BOOLEAN, boolean_binary_tag<LTAG, RTAG> >: public handle_base | |
{ | |
typedef bet<BOOLEAN, LTAG> left_type; | |
typedef bet<BOOLEAN, RTAG> right_type; | |
typedef typename boolean_binary_tag<LTAG, RTAG>::mode mode_type; | |
bet(const handle<left_type>& left1, const handle<right_type>& right1, | |
mode_type mode1): | |
handle_base(), | |
_left(left1), | |
_right(right1), | |
_mode(mode1) | |
{ | |
} | |
private: | |
handle<left_type> _left; | |
handle<right_type> _right; | |
mode_type _mode; | |
}; | |
template<class LTAG, class RTAG> | |
handle<bet<BOOLEAN, boolean_binary_tag<LTAG, RTAG> > > | |
operator&&(const handle<bet<BOOLEAN, LTAG> >& b1, | |
const handle<bet<BOOLEAN, RTAG> >& b2) | |
{ | |
return handle_to(new bet<BOOLEAN, | |
boolean_binary_tag<LTAG, RTAG> > (b1, b2, | |
boolean_binary_tag<LTAG, RTAG>::AND)); | |
} | |
template<class LTAG> | |
struct aggregate_if_tag | |
{ | |
enum mode | |
{ | |
COUNT, SUM | |
}; | |
}; | |
template<class LTAG> | |
struct bet<BOOLEAN, aggregate_if_tag<LTAG> >: public handle_base | |
{ | |
typedef bet<BOOLEAN, LTAG> left_type; | |
typedef NIL right_type; | |
typedef typename aggregate_if_tag<LTAG>::mode mode_type; | |
bet(const handle<left_type>& left1, mode_type mode1): | |
handle_base(), | |
_left(left1), | |
_mode(mode1) | |
{ | |
} | |
handle<left_type> left() const | |
{ | |
return _left; | |
} | |
handle<right_type> right() const | |
{ | |
return NULL; | |
} | |
private: | |
handle<left_type> _left; | |
mode_type _mode; | |
}; | |
template<class LTAG> | |
handle<bet<BOOLEAN, aggregate_if_tag<LTAG> > > | |
countif(const handle<bet<BOOLEAN, LTAG> >& b1) | |
{ | |
return handle_to(new bet<BOOLEAN, | |
aggregate_if_tag<LTAG> > (b1, aggregate_if_tag<LTAG>::COUNT)); | |
} | |
} | |
using namespace boo; | |
int main() | |
{ | |
fact_t profit = fact("profit"); | |
auto cond = profit + fact("revenue") * 5.0 + 2.0 > 12.0; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment