From b0d21c1db8271345a1580b0e2a9ca2c7f5f0c321 Mon Sep 17 00:00:00 2001 From: Nicolas Pierron Date: Wed, 24 Feb 2010 18:13:02 +0000 Subject: [PATCH] - Split the definition of terms into multiple files. - Improve the syntax to access Term fields. - Add term::make/Name/ functions. --- src/libterm/grammar.hh | 112 +++++++ src/libterm/pp.hh | 94 ++++++ src/libterm/term.hh | 612 ++++++++---------------------------- src/libterm/term_fwd.hh | 28 ++ src/libterm/term_impl.hh | 269 ++++++++++++++++ src/libterm/test.cc | 7 +- src/libterm/visitor.hh | 23 ++ src/libterm/visitor_fwd.hh | 19 ++ src/libterm/visitor_impl.hh | 57 ++++ 9 files changed, 730 insertions(+), 491 deletions(-) create mode 100644 src/libterm/grammar.hh create mode 100644 src/libterm/pp.hh create mode 100644 src/libterm/term_fwd.hh create mode 100644 src/libterm/term_impl.hh create mode 100644 src/libterm/visitor.hh create mode 100644 src/libterm/visitor_fwd.hh create mode 100644 src/libterm/visitor_impl.hh diff --git a/src/libterm/grammar.hh b/src/libterm/grammar.hh new file mode 100644 index 000000000..b7817f21a --- /dev/null +++ b/src/libterm/grammar.hh @@ -0,0 +1,112 @@ +// This file contains macro used to define the grammar. You should use +// these to define the macro named TRM_GRAMMAR_NODES(Interface, Final) +// before inluding any of the libterm files. + +#ifndef _LIBTERM_GRAMMAR_HH +# define _LIBTERM_GRAMMAR_HH + +# include "pp.hh" + + +// 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_TERM(Type, Name) TRM_TYPE_COPY(A ## Type, Name) + + +// These macro are used as shortcuts for the declaration of common type of +// grammar nodes. + +# define TRM_GRAMMAR_NODE_BINOP(Final, Name) \ + Final( \ + Name, Expr, \ + (2, (TRM_TYPE_TERM(Expr, lhs), TRM_TYPE_TERM(Expr, rhs))), \ + (0,()) \ + ) + +# define TRM_GRAMMAR_NODE_SINGLETON(Final, Name) \ + Final(Name, Expr, (0,()), (0,())) + + +// Handle the different usage of the variables and attributes. Arguments +// are suffixed with a '_' and attributes are not. These macro are +// expecting the result of the TRM_TYPE macros as argument. + +# 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_PTR_ATTR_IN_ARG_(Copy, Ref, Name) Name ## _ = ptr-> Name; +# define TRM_LESS_RHS_OR_(Copy, Ref, Name) Name < arg_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_PTR_ATTR_IN_ARG(Elt) TRM_COPY_PTR_ATTR_IN_ARG_ Elt +# define TRM_LESS_RHS_OR(Elt) TRM_LESS_RHS_OR_ Elt + + + +/* +// Test case. This should be moved inside the libexpr or generated in +// another manner. +# define TRM_GAMMAR_NODES(Interface, Final) + Interface(Loc, Term, TRM_NIL, TRM_NIL) + Interface(Pattern, Term, TRM_NIL, TRM_NIL) + Interface(Expr, Term, TRM_NIL, TRM_NIL) + Final(Pos, Loc, (TRM_TYPE_REF(std::string, file) + TRM_TYPE_COPY(int, line) + TRM_TYPE_COPY(int, column)), TRM_NIL) + Final(NoPos, Loc, TRM_NIL, TRM_NIL) + Final(String, Expr, (TRM_TYPE_REF(std::string, value)), TRM_NIL) + Final(Var, Expr, (TRM_TYPE_REF(std::string, name)), TRM_NIL) + Final(Path, Expr, (TRM_TYPE_REF(std::string, filename)), TRM_NIL) + Final(Int, Expr, (TRM_TYPE_COPY(int, value)), TRM_NIL) + Final(Function, Expr, (TRM_TYPE_TERM(Pattern, pattern) + TRM_TYPE_TERM(Expr, body) + TRM_TYPE_TERM(Pos, position)), TRM_NIL) + Final(Assert, Expr, (TRM_TYPE_TERM(Expr, cond) + TRM_TYPE_TERM(Expr, body) + TRM_TYPE_TERM(Pos, position)), TRM_NIL) + Final(With, Expr, (TRM_TYPE_TERM(Expr, set) + TRM_TYPE_TERM(Expr, body) + TRM_TYPE_TERM(Pos, position)), TRM_NIL) + Final(If, Expr, (TRM_TYPE_TERM(Expr, cond) + TRM_TYPE_TERM(Expr, thenPart) + TRM_TYPE_TERM(Expr, elsePart)), TRM_NIL) + Final(OpNot, Expr, (TRM_TYPE_TERM(Expr, cond)), TRM_NIL) + TRM_GRAMMAR_NODE_BINOP(Final, OpEq) + TRM_GRAMMAR_NODE_BINOP(Final, OpNEq) + TRM_GRAMMAR_NODE_BINOP(Final, OpAnd) + TRM_GRAMMAR_NODE_BINOP(Final, OpOr) + TRM_GRAMMAR_NODE_BINOP(Final, OpImpl) + TRM_GRAMMAR_NODE_BINOP(Final, OpUpdate) + TRM_GRAMMAR_NODE_BINOP(Final, SubPath) + TRM_GRAMMAR_NODE_BINOP(Final, OpHasAttr) + TRM_GRAMMAR_NODE_BINOP(Final, OpPlus) + TRM_GRAMMAR_NODE_BINOP(Final, OpConcat) + Final(Call, Expr, (TRM_TYPE_TERM(Expr, function) + TRM_TYPE_TERM(Expr, argument)), TRM_NIL) + Final(Select, Expr, (TRM_TYPE_TERM(Expr, set) + TRM_TYPE_TERM(Var, var)), TRM_NIL) + Final(BlackHole, Expr, TRM_NIL, TRM_NIL) + Final(Undefined, Expr, TRM_NIL, TRM_NIL) + Final(Removed, Expr, TRM_NIL, TRM_NIL) + +*/ + + +#endif diff --git a/src/libterm/pp.hh b/src/libterm/pp.hh new file mode 100644 index 000000000..99fe92810 --- /dev/null +++ b/src/libterm/pp.hh @@ -0,0 +1,94 @@ + +#ifndef _LIBTERM_PP_HH +# define _LIBTERM_PP_HH + +# include +# include +# include +# include + +// a few shortcuts to keep things clear. + +# define TRM_NIL +# define TRM_NIL_ARGS(...) +# define TRM_EMPTY_ARRAY (0, ()) + +# 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, 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, _) 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_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_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_DEFAULT1(TRM_NIL) \ + ) + +// 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_SEQ_HEAD(Seq) \ + TRM_APPLY_SEQ(TRM_SEPARATE_COMMA_HELPER, TRM_SEQ_TAIL(Seq)) +# define TRM_SEPARATE_COMMA_SEQ(Seq) \ + TRM_SEPARATE_COMMA(TRM_SEQ_TO_ARRAY(Seq)) +# define TRM_SEPARATE_COMMA(Array) \ + TRM_EVAL(TRM_SEPARATE_COMMA_, dummy, Array, \ + TRM_DEFAULT1(TRM_NIL) \ + ) + + +#endif diff --git a/src/libterm/term.hh b/src/libterm/term.hh index 34cf598dc..fb8bab561 100644 --- a/src/libterm/term.hh +++ b/src/libterm/term.hh @@ -1,35 +1,12 @@ -#ifndef _LIBTERM_TERM_HH -# define _LIBTERM_TERM_HH +#ifndef _LIBTERM_TERM_CLASS_FWD_HH +# define _LIBTERM_TERM_CLASS_FWD_HH # include -# include - -# include -# include -# include -# include - - -# define TRM_GRAMMAR_NODE_BINOP(Final, Name) \ - Final( \ - Name, Expr, \ - (2, (TRM_TYPE_TERM(Expr, lhs), TRM_TYPE_TERM(Expr, rhs))), \ - (0,()) \ - ) - -# define TRM_GRAMMAR_NODE_SINGLETON(Final, Name) \ - Final(Name, Expr, (0,()), (0,())) +# include "visitor_fwd.hh" namespace term { - // user manipulable terms. - class ATerm; - // internal implementation which is not visible to the user. - class ATermImpl; - // base class for visitor implementation. - class ATermVisitor; - // Performance issue: Abstract classes should be copied where fully // defined terms should be used with constant references. An ATerm is // only composed by a pointer and should not use any virtual method. By @@ -39,13 +16,8 @@ namespace term class ATermImpl { public: - ATermImpl() - { - }; - - virtual ~ATermImpl() - { - }; + ATermImpl(); + virtual ~ATermImpl(); public: virtual ATerm accept(ATermVisitor& v) const = 0; @@ -55,348 +27,57 @@ namespace term class ATerm { public: - inline - ATerm(const ATerm& t) - : ptr_(t.ptr_) - { - } - - inline - ATerm() - : ptr_(0) - { - } + ATerm(const ATerm& t); + ATerm(); protected: - inline - ATerm(const ATermImpl* ptr) - : ptr_(ptr) - { - } + ATerm(const ATermImpl* ptr); public: - inline - ATerm accept(ATermVisitor& v) const - { - return ptr_->accept(v); - } + ATerm accept(ATermVisitor& v) const; public: - inline - bool operator== (const ATerm& rhs) const - { - return ptr_ == rhs.ptr_; - } - - inline - bool operator!= (const ATerm& rhs) const - { - return ptr_ != rhs.ptr_; - } - - inline - bool operator <(const ATerm& rhs) const - { - return ptr_ < rhs.ptr_; - } - - inline - operator bool() - { - return ptr_; - } + bool operator== (const ATerm& rhs) const; + bool operator!= (const ATerm& rhs) const; + bool operator <(const ATerm& rhs) const; + operator bool(); public: - inline - const ATermImpl* - get_ptr() const - { - return ptr_; - } + const ATermImpl* get_ptr() const; protected: const ATermImpl* ptr_; }; -# define TRM_ABSTRACT_DECLARE(Name, Base, Attributes, BaseArgs) \ - class A ## Name; - -# define TRM_INTERFACE_DECLARE(Name, Base, Attributes, BaseArgs) \ - TRM_ABSTRACT_DECLARE(Name, Base, Attributes, BaseArgs) \ - template \ - class Name; - -# define TRM_FINAL_DECLARE(Name, Base, Attributes, BaseArgs) \ - TRM_ABSTRACT_DECLARE(Name, Base, Attributes, BaseArgs) \ - class Name; - - TRM_GRAMMAR_NODES(TRM_INTERFACE_DECLARE, TRM_FINAL_DECLARE) - - -# undef TRM_FINAL_DECLARE -# undef TRM_INTERFACE_DECLARE -# undef TRM_ABSTRACT_DECLARE - - - class ATermVisitor - { - public: -# define TRM_VISITOR(Name, Base, Attributes, BaseArgs) \ - virtual ATerm visit(const A ## Name); - - TRM_VISITOR(Term, TRM_NIL, TRM_NIL, TRM_NIL) - TRM_GRAMMAR_NODES(TRM_VISITOR, TRM_VISITOR) -# undef TRM_VISITOR - }; - - - template struct Term : public ATermImpl { public: - typedef Term this_type; - typedef std::set term_set_type; + typedef Term this_type; + typedef ATerm term; public: - inline - bool operator <(const this_type&) const - { - return false; - } - - static inline - bool - match(const ATerm) - { - return true; - } - - protected: - static inline - const ATermImpl* - get_identity(const T& t) - { - return static_cast(&*set_instance().insert(t).first); - } - - static inline - term_set_type& set_instance() - { - static term_set_type set; - return set; - } + bool operator <(const this_type&) const; }; -// a few shortcuts to keep things clear. + // [ -# define TRM_NIL -# define TRM_NIL_ARGS(...) -# define TRM_EMPTY_ARRAY (0, ()) - -# 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, 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, _) 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_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_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_DEFAULT1(TRM_NIL) \ - ) - -// 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_SEQ_HEAD(Seq) \ - TRM_APPLY_SEQ(TRM_SEPARATE_COMMA_HELPER, TRM_SEQ_TAIL(Seq)) -# define TRM_SEPARATE_COMMA_SEQ(Seq) \ - 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_TERM(Type, Name) TRM_TYPE_COPY(A ## Type, 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_PTR_ATTR_IN_ARG_(Copy, Ref, Name) Name ## _ = ptr-> Name; -# define TRM_LESS_RHS_OR_(Copy, Ref, Name) Name < arg_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_PTR_ATTR_IN_ARG(Elt) TRM_COPY_PTR_ATTR_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 -// the terms. -# define TRM_ADD_FRIEND(Name, Base, Attributes, BaseArgs) \ - friend class Name; - - -// Initialized all attributes of the current class and call the base class -// with the expected arguments. -# define TRM_GRAMMAR_NODE_CTR(Name, Base, Attributes, BaseArgs) \ - protected: \ +// Declare the constructor +# define TRM_IMPL_CTR_DECL(Name, Base, Attributes, BaseArgs) \ Name ( TRM_SEPARATE_COMMA( \ TRM_MAP_ARRAY(TRM_CONST_ABSTRACT_COPY_ARG, Attributes) \ - ) ) \ - : TRM_SEPARATE_COMMA_SEQ( \ - TRM_MAP(TRM_INIT_ATTRIBUTES, Attributes) \ - ( parent(TRM_SEPARATE_COMMA( \ - TRM_MAP_ARRAY(TRM_ARGUMENTS, BaseArgs) \ - )) \ - ) \ - ) \ - { \ - } - - - -// This method is used to provide maximal sharing among node of the same -// types. This create the class with the private constructor and register -// it if this is not already done. It returns a term which has a small -// memory impact (only a pointer) which refers to the created element. -# define TRM_GRAMMAR_NODE_MAKE_METHOD(Name, Base, Attributes, BaseArgs) \ - public: \ - static inline \ - term \ - make( \ - TRM_SEPARATE_COMMA( \ - TRM_MAP_ARRAY(TRM_CONST_ABSTRACT_COPY_ARG, Attributes) \ - ) \ - ) \ - { \ - return term(get_identity(this_type( \ - TRM_SEPARATE_COMMA( \ - TRM_MAP_ARRAY(TRM_ARGUMENTS, Attributes) \ - ) \ - ))); \ - } - - -// This method provides backward compatibility but it is inefficient. The -// macro produce a match function which deconstruct the node by copying all -// attributes values into references given as arguments of this function. -// The first argument is the term which has to be deconstructed. -# define TRM_GRAMMAR_NODE_MATCH_METHOD(Name, Base, Attributes, BaseArgs) \ - public: \ - static inline \ - bool \ - match( \ - TRM_SEPARATE_COMMA_SEQ( \ - ( const ATerm t ) \ - TRM_MAP(TRM_ABSTRACT_REF_ARG, Attributes) \ - ) \ - ) \ - { \ - const this_type* ptr; \ - if (ptr = dynamic_cast(t.get_ptr())) \ - { \ - TRM_APPLY(TRM_COPY_PTR_ATTR_IN_ARG, Attributes); \ - return parent::match ( \ - TRM_SEPARATE_COMMA_SEQ( \ - ( t ) \ - TRM_MAP(TRM_ARGUMENTS, BaseArgs) \ - ) \ - ); \ - } \ - return false; \ - } - - -// This operator is used for checking if the current ellement has not been -// create before. It compares each attributes of the current class and -// delegate other attribute comparison to his parent class. -# define TRM_LESS_GRAMMAR_NODE_OP(Name, Base, Attributes, BaseArgs) \ - public: \ - inline \ - bool operator <(const Name& arg_rhs) const \ - { \ - return TRM_APPLY(TRM_LESS_RHS_OR, Attributes) \ - parent::operator < (arg_rhs); \ - } + ) ); +// Declare the make method which create an abstract term. +# define TRM_IMPL_MAKE_DECL(Name, Base, Attributes, BaseArgs) \ + static \ + term \ + make( \ + TRM_SEPARATE_COMMA( \ + TRM_MAP_ARRAY(TRM_CONST_ABSTRACT_COPY_ARG, Attributes) \ + ) \ + ); // Declare all the attributes of the current class. # define TRM_ATTRIBUTE_DECLS(Name, Base, Attributes, BaseArgs) \ @@ -407,160 +88,115 @@ namespace term // A class which provide static method (no virtual) to access the // implementation of the term. This class is a wrapper over a pointer which // should derivate from the ATerm class. -# define TRM_ABSTRACT_INTER_GRAMMAR_NODE(Name, Base, Attributes, BaseArgs) \ +# define TRM_ABSTRACT_INTERFACE(Name, Base, Attributes, BaseArgs) \ class A ## Name : public A ## Base \ { \ typedef A ## Base parent; \ \ public: \ - A ## Name (const A ## Name& t) \ - : parent(t) \ - { \ - } \ - \ - A ## Name () \ - : parent() \ - { \ - } \ + A ## Name (const A ## Name& t); \ + A ## Name (); \ \ protected: \ - explicit A ## Name (const ATermImpl* ptr) \ - : parent(ptr) \ - { \ - } \ + explicit A ## Name (const ATermImpl* ptr); \ + }; + +// Add the implementation class as a friend class to provide access to the +// private constructor. This reduce interaction with the implementation of +// the terms. +# define TRM_ABSTRACT_FINAL(Name, Base, Attributes, BaseArgs) \ + class A ## Name : public A ## Base \ + { \ + typedef A ## Base parent; \ + \ + public: \ + A ## Name (const A ## Name& t); \ + A ## Name (); \ + \ + const Name & \ + operator* () const; \ + \ + const Name* \ + operator-> () const; \ + \ + protected: \ + explicit A ## Name (const ATermImpl* ptr); \ + \ + friend class Name; \ + }; + +# define TRM_IMPL_INTERFACE(Name, Base, Attributes, BaseArgs) \ + class Name : public Base \ + { \ + typedef Name this_type; \ + typedef Base parent; \ + \ + public: \ + bool operator <(const Name& arg_rhs) const; \ + \ + protected: \ + TRM_IMPL_CTR_DECL(Name, Base, Attributes, BaseArgs) \ + \ + public: \ + TRM_ATTRIBUTE_DECLS(Name, Base, Attributes, BaseArgs) \ + }; + +# define TRM_IMPL_FINAL(Name, Base, Attributes, BaseArgs) \ + class Name : public Base \ + { \ + typedef Name this_type; \ + typedef Base parent; \ + public: \ + typedef A ## Name term; \ + typedef std::set term_set_type; \ + \ + public: \ + TRM_IMPL_MAKE_DECL(Name, Base, Attributes, BaseArgs) \ + ATerm accept(ATermVisitor& v) const; \ + bool operator <(const Name& arg_rhs) const; \ + \ + protected: \ + TRM_IMPL_CTR_DECL(Name, Base, Attributes, BaseArgs) \ + \ + public: \ + TRM_ATTRIBUTE_DECLS(Name, Base, Attributes, BaseArgs) \ + \ + private: \ + \ + static \ + const ATermImpl* \ + get_identity(const this_type& t); \ + \ + static \ + term_set_type& set_instance(); \ }; -# define TRM_ABSTRACT_FINAL_GRAMMAR_NODE(Name, Base, Attributes, BaseArgs) \ - class A ## Name : public A ## Base \ - { \ - typedef A ## Base parent; \ - \ - public: \ - A ## Name (const A ## Name& t) \ - : parent(t) \ - { \ - } \ - \ - A ## Name () \ - : parent() \ - { \ - } \ - \ - const Name & \ - operator() () const; \ - \ - protected: \ - explicit A ## Name (const ATermImpl* ptr) \ - : parent(ptr) \ - { \ - } \ - \ - TRM_ADD_FRIEND(Name, Base, Attributes, BaseArgs) \ - }; + TRM_GRAMMAR_NODES(TRM_ABSTRACT_INTERFACE, TRM_ABSTRACT_FINAL) + TRM_GRAMMAR_NODES(TRM_IMPL_INTERFACE, TRM_IMPL_FINAL) -# define TRM_ABSTRACT_FINAL_DEF_GRAMMAR_NODE(Name, Base, Attributes, BaseArgs) \ - inline \ - const Name & \ - A ## Name :: operator() () const \ - { \ - return *static_cast(ptr_); \ - } +# undef TRM_ABSTRACT_INTERFACE +# undef TRM_ABSTRACT_FINAL +# undef TRM_IMPL_INTERFACE +# undef TRM_IMPL_FINAL + +# undef TRM_IMPL_CTR_DECL +# undef TRM_ATTRIBUTE_DECLS +# undef TRM_IMPL_MAKE_DECL + // ] -# define TRM_INTERFACE_GRAMMAR_NODE(Name, Base, Attributes, BaseArgs) \ - template \ - class Name : public Base \ - { \ - typedef Name this_type; \ - typedef Base parent; \ - \ - TRM_GRAMMAR_NODE_CTR(Name, Base, Attributes, BaseArgs) \ - TRM_GRAMMAR_NODE_MATCH_METHOD(Name, Base, Attributes, BaseArgs) \ - TRM_LESS_GRAMMAR_NODE_OP(Name, Base, Attributes, BaseArgs) \ - TRM_ATTRIBUTE_DECLS(Name, Base, Attributes, BaseArgs) \ - }; +# define TRM_GENERIC_MAKE_DECL(Name, Base, Attributes, BaseArgs) \ + Name :: term \ + make ## Name( \ + TRM_SEPARATE_COMMA( \ + TRM_MAP_ARRAY(TRM_CONST_ABSTRACT_COPY_ARG, Attributes) \ + ) \ + ); + TRM_GRAMMAR_NODES(TRM_NIL_ARGS, TRM_GENERIC_MAKE_DECL) -# define TRM_FINAL_GRAMMAR_NODE(Name, Base, Attributes, BaseArgs) \ - class Name : public Base \ - { \ - typedef Name this_type; \ - typedef Base parent; \ - typedef A ## Name term; \ - \ - TRM_GRAMMAR_NODE_CTR(Name, Base, Attributes, BaseArgs) \ - TRM_GRAMMAR_NODE_MAKE_METHOD(Name, Base, Attributes, BaseArgs) \ - TRM_GRAMMAR_NODE_MATCH_METHOD(Name, Base, Attributes, BaseArgs) \ - \ - public: \ - ATerm accept(ATermVisitor& v) const \ - { \ - return v.visit(term(this)); \ - } \ - \ - TRM_LESS_GRAMMAR_NODE_OP(Name, Base, Attributes, BaseArgs) \ - TRM_ATTRIBUTE_DECLS(Name, Base, Attributes, BaseArgs) \ - }; - - -# define TRM_INTERFACE(Name, Base, Attributes, BaseArgs) \ - TRM_ABSTRACT_INTER_GRAMMAR_NODE(Name, Base, Attributes, BaseArgs) \ - TRM_INTERFACE_GRAMMAR_NODE(Name, Base, Attributes, BaseArgs) - -# define TRM_FINAL(Name, Base, Attributes, BaseArgs) \ - TRM_ABSTRACT_FINAL_GRAMMAR_NODE(Name, Base, Attributes, BaseArgs) \ - TRM_FINAL_GRAMMAR_NODE(Name, Base, Attributes, BaseArgs) \ - TRM_ABSTRACT_FINAL_DEF_GRAMMAR_NODE(Name, Base, Attributes, BaseArgs) - - TRM_GRAMMAR_NODES(TRM_INTERFACE, TRM_FINAL) - -# undef TRM_FINAL -# undef TRM_INTERFACE - - -// definition of the ATermVisitor visit functions. -# define TRM_VISITOR(Name, Base, Attributes, BaseArgs) \ - ATerm \ - ATermVisitor::visit(const A ## Name t) { \ - return t; \ - } - - TRM_VISITOR(Term, TRM_NIL, TRM_NIL, TRM_NIL) - TRM_GRAMMAR_NODES(TRM_VISITOR, TRM_VISITOR) -# undef TRM_VISITOR - - namespace impl - { - template - class asVisitor : ATermVisitor - { - public: - asVisitor(ATerm t) - : res() - { - t.accept(*this); - } - - ATerm visit(const T t) - { - return res = t; - } - - public: - T res; - }; - } - - // This function will return a zero ATerm if the element does not have the - // expected type. - template - T as(ATerm t) - { - impl::asVisitor v(t); - return v.res; - } - +# undef TRM_GENERIC_MAKE_DECL } #endif diff --git a/src/libterm/term_fwd.hh b/src/libterm/term_fwd.hh new file mode 100644 index 000000000..a8607bafb --- /dev/null +++ b/src/libterm/term_fwd.hh @@ -0,0 +1,28 @@ + +#ifndef _LIBTERM_TERM_FWD_HH +# define _LIBTERM_TERM_FWD_HH + +# include "grammar.hh" + +// Types prefixed by an 'A' are the terms which should be manipulated by the +// user. The 'A' letter stands for Abstract. Their content should be +// limited to a pointer and they must not use any virtual keyword. On the +// other hand, the implementation of terms can declare more than one +// attribute and use virtual keywords as long as they don't cost too much. + +namespace term +{ + class ATerm; + class ATermImpl; // should be renamed to TermImpl + +# define TRM_DECLARE(Name, Base, Attributes, BaseArgs) \ + class A ## Name; \ + class Name; + + TRM_GRAMMAR_NODES(TRM_DECLARE, TRM_DECLARE) + +# undef TRM_DECLARE + +} + +#endif diff --git a/src/libterm/term_impl.hh b/src/libterm/term_impl.hh new file mode 100644 index 000000000..0cd842af3 --- /dev/null +++ b/src/libterm/term_impl.hh @@ -0,0 +1,269 @@ + +#ifndef _LIBTERM_TERM_HH +# define _LIBTERM_TERM_HH + +# include "term.hh" +# include "visitor.hh" + +namespace term +{ + inline + ATermImpl::ATermImpl() + { + } + + inline + ATermImpl::~ATermImpl() + { + } + + + inline + ATerm::ATerm(const ATerm& t) + : ptr_(t.ptr_) + { + } + + inline + ATerm::ATerm() + : ptr_(0) + { + } + + inline + ATerm::ATerm(const ATermImpl* ptr) + : ptr_(ptr) + { + } + + inline + ATerm + ATerm::accept(ATermVisitor& v) const + { + return ptr_->accept(v); + } + + inline + bool + ATerm::operator== (const ATerm& rhs) const + { + return ptr_ == rhs.ptr_; + } + + inline + bool + ATerm::operator!= (const ATerm& rhs) const + { + return ptr_ != rhs.ptr_; + } + + inline + bool + ATerm::operator <(const ATerm& rhs) const + { + return ptr_ < rhs.ptr_; + } + + inline + ATerm::operator bool() + { + return ptr_; + } + + inline + const ATermImpl* + ATerm::get_ptr() const + { + return ptr_; + } + + + inline + bool + Term::operator <(const this_type&) const + { + return false; + } + + +// define the contructors of the Abstract terms. These constructors are +// just delegating the work to the ATerm constructors. +# define TRM_ABSTRACT_CTR(Name, Base, Attributes, BaseArgs) \ + inline \ + A ## Name :: A ## Name (const A ## Name& t) : \ + parent(t) \ + { \ + } \ + \ + inline \ + A ## Name :: A ## Name () : \ + parent() \ + { \ + } \ + \ + inline \ + A ## Name :: A ## Name (const ATermImpl* ptr) : \ + parent(ptr) \ + { \ + } + + TRM_GRAMMAR_NODES(TRM_ABSTRACT_CTR, TRM_ABSTRACT_CTR) + +# undef TRM_ABSTRACT_CTR + + +// Give acces to the implementation in order to get access to each field of +// the term. +# define TRM_ABSTRACT_FINAL_ACCESS(Name, Base, Attributes, BaseArgs) \ + inline \ + const Name & \ + A ## Name :: operator* () const \ + { \ + return *static_cast(ptr_); \ + } \ + \ + inline \ + const Name* \ + A ## Name :: operator-> () const \ + { \ + return static_cast(ptr_); \ + } + + TRM_GRAMMAR_NODES(TRM_NIL_ARGS, TRM_ABSTRACT_FINAL_ACCESS) + +# undef TRM_ABSTRACT_FINAL_ACCESS + + + +// Initialized all attributes of the current class and call the base class +// with the expected arguments. +# define TRM_IMPL_CTR(Name, Base, Attributes, BaseArgs) \ + inline \ + Name :: Name ( \ + TRM_SEPARATE_COMMA( \ + TRM_MAP_ARRAY(TRM_CONST_ABSTRACT_COPY_ARG, Attributes) \ + ) \ + ) \ + : TRM_SEPARATE_COMMA_SEQ( \ + TRM_MAP(TRM_INIT_ATTRIBUTES, Attributes) \ + ( parent(TRM_SEPARATE_COMMA( \ + TRM_MAP_ARRAY(TRM_ARGUMENTS, BaseArgs) \ + )) \ + ) \ + ) \ + { \ + } + + TRM_GRAMMAR_NODES(TRM_IMPL_CTR, TRM_IMPL_CTR) + +# undef TRM_IMPL_CTR + + +// This operator is used for checking if the current ellement has not been +// create before. It compares each attributes of the current class and +// delegate other attribute comparison to his parent class. +# define TRM_IMPL_LESS(Name, Base, Attributes, BaseArgs) \ + inline \ + bool \ + Name :: operator <(const Name& arg_rhs) const \ + { \ + return TRM_APPLY(TRM_LESS_RHS_OR, Attributes) \ + parent::operator < (arg_rhs); \ + } + + TRM_GRAMMAR_NODES(TRM_IMPL_LESS, TRM_IMPL_LESS) + +# undef TRM_IMPL_LESS + + +// This method is used to provide maximal sharing among node of the same +// types. This create the class with the private constructor and register +// it if this is not already done. It returns a term which has a small +// memory impact (only a pointer) which refers to the created element. +# define TRM_IMPL_FINAL_MAKE(Name, Base, Attributes, BaseArgs) \ + inline \ + Name :: term \ + Name :: make( \ + TRM_SEPARATE_COMMA( \ + TRM_MAP_ARRAY(TRM_CONST_ABSTRACT_COPY_ARG, Attributes) \ + ) \ + ) \ + { \ + return term(get_identity(this_type( \ + TRM_SEPARATE_COMMA( \ + TRM_MAP_ARRAY(TRM_ARGUMENTS, Attributes) \ + ) \ + ))); \ + } + + TRM_GRAMMAR_NODES(TRM_NIL_ARGS, TRM_IMPL_FINAL_MAKE) + +# undef TRM_IMPL_FINAL_MAKE + + +// Handle visit from the ATermVisitor and forward them to the Abstract term +// of the current term. +# define TRM_IMPL_FINAL_VISIT(Name, Base, Attributes, BaseArgs) \ + inline \ + ATerm \ + Name :: accept(ATermVisitor& v) const \ + { \ + return v.visit(term(this)); \ + } + + TRM_GRAMMAR_NODES(TRM_NIL_ARGS, TRM_IMPL_FINAL_VISIT) + +# undef TRM_IMPL_FINAL_VISIT + + +// These functions are used to provide maximal sharing between the terms. +// All terms are stored inside a set only the address the element contained +// in the set is used. +# define TRM_IMPL_FINAL_SHARED(Name, Base, Attributes, BaseArgs) \ + inline \ + const ATermImpl* \ + Name :: get_identity(const this_type& t) \ + { \ + return static_cast( \ + &*set_instance().insert(t).first \ + ); \ + } \ + \ + inline \ + Name :: term_set_type& \ + Name :: set_instance() \ + { \ + static term_set_type set; \ + return set; \ + } + + TRM_GRAMMAR_NODES(TRM_NIL_ARGS, TRM_IMPL_FINAL_SHARED) + +# undef TRM_IMPL_FINAL_SHARED + + +// Improve user experience by providing function to create Abstract terms +// without any manipulation of the implementation class names. +# define TRM_GENERIC_MAKE(Name, Base, Attributes, BaseArgs) \ + inline \ + Name :: term \ + make ## Name( \ + TRM_SEPARATE_COMMA( \ + TRM_MAP_ARRAY(TRM_CONST_ABSTRACT_COPY_ARG, Attributes) \ + ) \ + ) \ + { \ + return Name :: make( \ + TRM_SEPARATE_COMMA( \ + TRM_MAP_ARRAY(TRM_ARGUMENTS, Attributes) \ + ) \ + ); \ + } + + TRM_GRAMMAR_NODES(TRM_NIL_ARGS, TRM_GENERIC_MAKE) + +# undef TRM_GENERIC_MAKE + +} + +#endif diff --git a/src/libterm/test.cc b/src/libterm/test.cc index 228fba595..a1339309b 100644 --- a/src/libterm/test.cc +++ b/src/libterm/test.cc @@ -7,7 +7,8 @@ TRM_GRAMMAR_NODE_BINOP(Final, Plus) \ Final(Int, Expr, (1, (TRM_TYPE_COPY(int, value))), (0, ())) -#include "term.hh" +#include "term_impl.hh" +#include "visitor_impl.hh" #undef TRM_GRAMMAR_NODES using namespace term; @@ -16,12 +17,12 @@ struct Eval : public ATermVisitor { int run(const ATerm t) { - return as(t.accept(*this))().value; + return as(t.accept(*this))->value; } ATerm visit(const APlus p) { - return Int::make(run(p().lhs) + run(p().rhs)); + return Int::make(run(p->lhs) + run(p->rhs)); } }; diff --git a/src/libterm/visitor.hh b/src/libterm/visitor.hh new file mode 100644 index 000000000..660b5fe96 --- /dev/null +++ b/src/libterm/visitor.hh @@ -0,0 +1,23 @@ + +#ifndef _LIBTERM_VISITOR_CLASS_FWD_HH +# define _LIBTERM_VISITOR_CLASS_FWD_HH + +# include "term.hh" + +namespace term +{ + // base class for visitor implementation. + class ATermVisitor + { + public: +# define TRM_VISITOR(Name, Base, Attributes, BaseArgs) \ + virtual ATerm visit(const A ## Name); + + TRM_VISITOR(Term, TRM_NIL, TRM_NIL, TRM_NIL) + TRM_GRAMMAR_NODES(TRM_VISITOR, TRM_VISITOR) +# undef TRM_VISITOR + }; +} + +#endif + diff --git a/src/libterm/visitor_fwd.hh b/src/libterm/visitor_fwd.hh new file mode 100644 index 000000000..b6c08dbfc --- /dev/null +++ b/src/libterm/visitor_fwd.hh @@ -0,0 +1,19 @@ + +#ifndef _LIBTERM_VISITOR_FWD_HH +# define _LIBTERM_VISITOR_FWD_HH + +# include "term_fwd.hh" + +// Types prefixed by an 'A' are the terms which should be manipulated by the +// user. The 'A' letter stands for Abstract. Their content should be +// limited to a pointer and they must not use any virtual keyword. On the +// other hand, the implementation of terms can declare more than one +// attribute and use virtual keywords as long as they don't cost too much. + +namespace term +{ + // base class for visitor implementation. + class ATermVisitor; +} + +#endif diff --git a/src/libterm/visitor_impl.hh b/src/libterm/visitor_impl.hh new file mode 100644 index 000000000..f450db31e --- /dev/null +++ b/src/libterm/visitor_impl.hh @@ -0,0 +1,57 @@ + +#ifndef _LIBTERM_VISITOR_HH +# define _LIBTERM_VISITOR_HH + +# include "visitor.hh" +# include "term.hh" + +namespace term +{ + +// definition of the ATermVisitor visit functions. +# define TRM_VISITOR(Name, Base, Attributes, BaseArgs) \ + ATerm \ + ATermVisitor::visit(const A ## Name t) { \ + return t; \ + } + + TRM_VISITOR(Term, TRM_NIL, TRM_NIL, TRM_NIL) + TRM_GRAMMAR_NODES(TRM_VISITOR, TRM_VISITOR) + +# undef TRM_VISITOR + + namespace impl + { + template + class asVisitor : ATermVisitor + { + public: + asVisitor(ATerm t) + : res() + { + t.accept(*this); + } + + ATerm visit(const T t) + { + return res = t; + } + + public: + T res; + }; + } + + // This function will return a zero ATerm if the element does not have the + // expected type. + template + inline + T as(ATerm t) + { + impl::asVisitor v(t); + return v.res; + } + +} + +#endif