Skip to content

Instantly share code, notes, and snippets.

@2sin18
Last active August 29, 2015 14:04
Show Gist options
  • Save 2sin18/25be652b3e6b158a1dcb to your computer and use it in GitHub Desktop.
Save 2sin18/25be652b3e6b158a1dcb to your computer and use it in GitHub Desktop.
Boolang for DSL in C++
#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