Boost logo

Boost :

Subject: Re: [boost] [contract] syntax redesign
From: Lorenzo Caminiti (lorcaminiti_at_[hidden])
Date: 2012-01-15 04:48:10


On Sat, Jan 14, 2012 at 9:58 PM, paul Fultz <pfultz2_at_[hidden]> wrote:
> It is very impressive. I wonder if a library could be built for writing DSLs using the preprocessor. Much like Boost.Proto lets you write DSLs using C++ operators, another library could be used to build grammars and define transformations based on preprocessor tokens.

Indeed, my library uses the pp to defined a DSEL for function
declarations with contracts, concepts, named parameters, and some
C++11 declaration extensions (override, final, etc). Some
generalization of the tools used by my library should be possible
maybe along the lines of Proto (but I have not looked at implementing
such generalization).

For now the library implementation performs the following /distinct/ steps:
1) Parse the class and function declarations into their traits
(preprocessor-meta-traits) using the pp (pp metaprogramming).
2) Expand the macros based on the parsed function pp-meta-traits
generating code for contract, concept, named parameter, etc using the
both the pp and the compiler (pp and template metaprogramming, plus
C++ programming).

These steps are distinct so you can replace step 2 to generate some
feature other than contracts, concepts, or named parameters. But step
1) always parses the syntax of the DSEL for declarations with
contracts, concepts, and named parameters. So step 1) should be broken
down into subtools (maybe like a Preprocessor/Proto)...

For example, imagine you want to program a DSEL where a virtual
function shall never be public:

#define VFUNC_(f) ... // expand to RESULT_TYPE(f) NAME(f) ( PARAMS(f) ) ...

#define VFUNC_(f) \
    /* if !EMPTY(virtual) && ACCESS == public then error */ \
    BOOST_PP_IIF(BOOST_PP_AND(
            BOOST_COMPL(BOOST_PP_IS_EMPTY(CONTRACT_PP_FUNC_TRAITS_VIRTUAL(f))),
            CONTRACT_PP_KEYWORD_IS_PUBLIC_FRONT(CONTRACT_PP_FUNC_TRAITS_ACCESS(f))),
        static_assert(false, "virtual functions cannot be public");
BOOST_PP_TUPLE_EAT(1) \
    , \
        VFUNC_DECL_ \
    )(f)

#define VFUNC(sign) \
    VFUNC_(CONTRACT_PP_FUNC_TRAITS(sign))

struct x {
    VFUNC( public int (id) ( int x ) ) { return x; } // ok
    VFUNC( virtual public int (add) ( int x, int y ) ) { return x + y;
} // error- expand to the static assert
};

Note that the function pp-meta-traits "f" parsed by step 1) contain
/all/ traits of a function declaration because they are parsed using
pp metaprogramming so they are not limited by the compiler (which
unfortunately does not allow us to detect virtual, public, and other
function traits). This is what allows me for example to program "if a
function is public then check the class invariants; otherwise do not
check class invariants for protected and private functions" (this is a
Contract Programming requirement that, without language support, it is
perhaps impossible to program unless you use the pp the way I do it
here).

--Lorenzo


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk