diff --git a/src/libterm/term.hh b/src/libterm/term.hh index 5188d953a..8a52bd4d2 100644 --- a/src/libterm/term.hh +++ b/src/libterm/term.hh @@ -170,70 +170,123 @@ namespace term }; +// a few shortcuts to keep things clear. + # define TRM_NIL # define TRM_NIL_ARGS(...) +# define TRM_EMPTY_ARRAY (0, ()) -# define TRM_ARRAY_DATA(Array) BOOST_PP_ARRAY_DATA(Array) -# define TRM_ARRAY_SIZE(Array) BOOST_PP_ARRAY_SIZE(Array) +# define TRM_SEQ_HEAD BOOST_PP_SEQ_HEAD +# define TRM_SEQ_TAIL BOOST_PP_SEQ_TAIL + +# define TRM_ARRAY_DATA BOOST_PP_ARRAY_DATA +# define TRM_ARRAY_SIZE BOOST_PP_ARRAY_SIZE +# define TRM_ARRAY_ELEM BOOST_PP_ARRAY_ELEM +# define TRM_SEQ_TO_ARRAY BOOST_PP_SEQ_TO_ARRAY +# define TRM_ARRAY_TO_SEQ(Array) \ + BOOST_PP_TUPLE_TO_SEQ(TRM_ARRAY_SIZE(Array), TRM_ARRAY_DATA(Array)) + +// TRM_EVAL macros are used to do the convertion of array to sequence and to +// provide a default case when the array cannot be converted into a +// sequence. This case happens when you need to convert a zero size array. # define TRM_EVAL_0(Macro1, Macro2, Array, Default) Default - /* - define TRM_EVAL_1(Macro1, Macro2, Array, Default) \ - Macro1(Macro2, BOOST_PP_TUPLE_TO_SEQ(TRM_ARRAY_SIZE(Array), TRM_ARRAY_DATA(Array))) - */ +# define TRM_EVAL_1(Macro1, Macro2, Array, Default) \ + Macro1(Macro2, TRM_ARRAY_TO_SEQ(Array)) + # define TRM_EVAL_2 TRM_EVAL_1 # define TRM_EVAL_3 TRM_EVAL_1 # define TRM_EVAL_4 TRM_EVAL_1 # define TRM_EVAL_II(eval) eval -# define TRM_EVAL_I(n, tuple) TRM_EVAL_ ## n +# define TRM_EVAL_I(n, _) TRM_EVAL_ ## n # define TRM_EVAL(Macro1, Macro2, Array, Default) \ TRM_EVAL_II(TRM_EVAL_I Array (Macro1, Macro2, Array, Default)) +# define TRM_DEFAULT1(D0) D0 + +// Default TRM_ are taking an array and return a sequence. To keep the +// same type, you need to specify which type you expect to have. The reason +// is that array support to have no values where sequence do not support it. +// On the contrary, all operations are well defined on sequences but none +// are defined on arrays. # define TRM_MAP_HELPER(R, Macro, Elt) (Macro(Elt)) # define TRM_MAP_(Macro, Seq) \ BOOST_PP_SEQ_FOR_EACH(TRM_MAP_HELPER, Macro, Seq) # define TRM_MAP_SEQ(Macro, Seq) \ TRM_MAP_(Macro, Seq) -# define TRM_MAP_SEQ_TO_ARRAY(Macro, Seq) \ - BOOST_PP_SEQ_TO_ARRAY(TRM_MAP_SEQ(Macro, Seq)) -# define TRM_MAP_ARRAY(Macro, Array) \ - TRM_EVAL(TRM_MAP_SEQ_TO_ARRAY, Macro, Array, (0, ())) -# define TRM_MAP(Macro, Array) \ - TRM_EVAL(TRM_MAP_SEQ, Macro, Array, TRM_NIL) +# define TRM_MAP_ARRAY_(Macro, Seq) \ + TRM_SEQ_TO_ARRAY(TRM_MAP_SEQ(Macro, Seq)) +# define TRM_MAP_ARRAY(Macro, Array) \ + TRM_EVAL(TRM_MAP_ARRAY_, Macro, Array, \ + TRM_DEFAULT1(TRM_EMPTY_ARRAY) \ + ) +# define TRM_MAP(Macro, Array) \ + TRM_EVAL(TRM_MAP_SEQ, Macro, Array, \ + TRM_DEFAULT1(TRM_NIL) \ + ) + +// Apply a macro on all elements (array / sequence) # define TRM_APPLY_HELPER(R, Macro, Elt) Macro(Elt) # define TRM_APPLY_(Macro, Seq) \ - BOOST_PP_SEQ_FOR_EACH(TRM_MAP_HELPER, Macro, Seq) + BOOST_PP_SEQ_FOR_EACH(TRM_APPLY_HELPER, Macro, Seq) # define TRM_APPLY_SEQ(Macro, Seq) \ TRM_APPLY_(Macro, Seq) # define TRM_APPLY(Macro, Array) \ - TRM_EVAL(TRM_APPLY_, Macro, Array, TRM_NIL) + TRM_EVAL(TRM_APPLY_, Macro, Array, \ + TRM_DEFAULT1(TRM_NIL) \ + ) -# define TRM_HEAD(Seq) BOOST_PP_SEQ_HEAD(Seq) -# define TRM_TAIL(Seq) BOOST_PP_SEQ_TAIL(Seq) +// Apply a macro on all elements (array / sequence) and separate them by a +// comma. # define TRM_SEPARATE_COMMA_HELPER(Elt) , Elt # define TRM_SEPARATE_COMMA_(_, Seq) \ - TRM_HEAD(Seq) TRM_APPLY_SEQ(TRM_SEPARATE_COMMA_HELPER, TRM_TAIL(Seq)) + TRM_SEQ_HEAD(Seq) + TRM_APPLY_SEQ(TRM_SEPARATE_COMMA_HELPER, TRM_SEQ_TAIL(Seq)) # define TRM_SEPARATE_COMMA_SEQ(Seq) \ - TRM_SEPARATE_COMMA_(dummy, Seq) -# define TRM_SEPARATE_COMMA(Array) \ - TRM_EVAL(TRM_SEPARATE_COMMA_, dummy, Array, TRM_NIL) + TRM_SEPARATE_COMMA(TRM_SEQ_TO_ARRAY(Seq)) +# define TRM_SEPARATE_COMMA(Array) \ + TRM_EVAL(TRM_SEPARATE_COMMA_, dummy, Array, \ + TRM_DEFAULT1(TRM_NIL) \ + ) +// These macro are used to define how to manipulate each argument. If the +// argument should be given by reference or by copy. You should use +// references when the element goes over a specific size and if you accept +// to see it living on the stack. You should use copies when the element is +// small and if you prefer to have it inside a register. -# define TRM_TYPE_REF(Type, Name) const Type&, Type &, Name -# define TRM_TYPE_COPY(Type, Name) const Type, Type &, Name +# define TRM_TYPE_REF(Type, Name) (const Type&, Type &, Name) +# define TRM_TYPE_COPY(Type, Name) (const Type, Type &, Name) # define TRM_TYPE_TERM(Type, Name) TRM_TYPE_COPY(A ## Type, Name) -# define TRM_CONST_ABSTRACT_COPY_DECL(Copy, Ref, Name) Copy Name; -# define TRM_CONST_ABSTRACT_COPY_ARG(Copy, Ref, Name) Copy Name ## _ -# define TRM_ABSTRACT_REF_ARG(Copy, Ref, Name) Ref Name ## _ -# define TRM_INIT_ATTRIBUTES(Copy, Ref, Name) Name (Name ## _) -# define TRM_ARGUMENTS(Copy, Ref, Name) Name ## _ -# define TRM_COPY_IN_ARG(Copy, Ref, Name) Name ## _ = Name; -# define TRM_LESS_RHS_OR(Copy, Ref, Name) Name < rhs. Name || +// Handle the different usage of the variables. Arguments are suffixed with +// a '_' and attributes are not. + +# define TRM_CONST_ABSTRACT_COPY_DECL_(Copy, Ref, Name) Copy Name; +# define TRM_CONST_ABSTRACT_COPY_ARG_(Copy, Ref, Name) Copy Name ## _ +# define TRM_ABSTRACT_REF_ARG_(Copy, Ref, Name) Ref Name ## _ +# define TRM_INIT_ATTRIBUTES_(Copy, Ref, Name) Name (Name ## _) +# define TRM_ARGUMENTS_(Copy, Ref, Name) Name ## _ +# define TRM_COPY_IN_ARG_(Copy, Ref, Name) Name ## _ = Name; +# define TRM_LESS_RHS_OR_(Copy, Ref, Name) Name < rhs. Name || + +// These macro are shortcuts used to remove extra parenthesies added by +// TRM_TYPE_* macros. Without such parenthesies TRM_APPLY_HELPER won't be +// able to give the argument to these macros and arrays won't be well +// formed. + +# define TRM_CONST_ABSTRACT_COPY_DECL(Elt) TRM_CONST_ABSTRACT_COPY_DECL_ Elt +# define TRM_CONST_ABSTRACT_COPY_ARG(Elt) TRM_CONST_ABSTRACT_COPY_ARG_ Elt +# define TRM_ABSTRACT_REF_ARG(Elt) TRM_ABSTRACT_REF_ARG_ Elt +# define TRM_INIT_ATTRIBUTES(Elt) TRM_INIT_ATTRIBUTES_ Elt +# define TRM_ARGUMENTS(Elt) TRM_ARGUMENTS_ Elt +# define TRM_COPY_IN_ARG(Elt) TRM_COPY_IN_ARG_ Elt +# define TRM_LESS_RHS_OR(Elt) TRM_LESS_RHS_OR_ Elt + // Add the implementation class as a friend class to provide access to the // private constructor. This reduce interaction with the implementation of @@ -301,7 +354,7 @@ namespace term this_type* ptr; \ if (ptr = dynamic_cast(t.ptr_)) \ { \ - TRM_MAP(TRM_COPY_IN_ARG, Attributes); \ + TRM_APPLY(TRM_COPY_IN_ARG, Attributes); \ return parent::match ## Base ( \ TRM_SEPARATE_COMMA_SEQ( \ ( t ) \ @@ -321,7 +374,7 @@ namespace term inline \ bool operator <(const Name& rhs) \ { \ - return TRM_MAP(TRM_LESS_RHS_OR, Attributes) \ + return TRM_APPLY(TRM_LESS_RHS_OR, Attributes) \ parent::operator < (rhs); \ } @@ -329,7 +382,7 @@ namespace term // Declare all the attributes of the current class. # define TRM_ATTRIBUTE_DECLS(Name, Base, Attributes, BaseArgs) \ public: \ - TRM_MAP(TRM_CONST_ABSTRACT_COPY_DECL, Attributes) + TRM_APPLY(TRM_CONST_ABSTRACT_COPY_DECL, Attributes) // A class which provide static method (no virtual) to access the