1
1
Fork 0
mirror of https://github.com/NixOS/nix.git synced 2025-11-14 22:42:41 +01:00

- Split the definition of terms into multiple files.

- Improve the syntax to access Term fields.
- Add term::make/Name/ functions.
This commit is contained in:
Nicolas Pierron 2010-02-24 18:13:02 +00:00
parent 99e554e0e0
commit b0d21c1db8
9 changed files with 730 additions and 491 deletions

112
src/libterm/grammar.hh Normal file
View file

@ -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

94
src/libterm/pp.hh Normal file
View file

@ -0,0 +1,94 @@
#ifndef _LIBTERM_PP_HH
# define _LIBTERM_PP_HH
# include <boost/preprocessor/tuple.hpp>
# include <boost/preprocessor/seq.hpp>
# include <boost/preprocessor/cat.hpp>
# include <boost/preprocessor/array.hpp>
// 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_<fun> 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

View file

@ -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 <set>
# include <utility>
# include <boost/preprocessor/tuple.hpp>
# include <boost/preprocessor/seq.hpp>
# include <boost/preprocessor/cat.hpp>
# include <boost/preprocessor/array.hpp>
# 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 <typename T> \
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 <typename T>
struct Term : public ATermImpl
{
public:
typedef Term<T> this_type;
typedef std::set<T> 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<const ATermImpl*>(&*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_<fun> 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<const this_type*>(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<this_type> 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<const Name *>(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 <typename T> \
class Name : public Base<T> \
{ \
typedef Name<T> this_type; \
typedef Base<T> 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<Name> \
{ \
typedef Name this_type; \
typedef Base<Name> 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 <typename T>
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 <typename T>
T as(ATerm t)
{
impl::asVisitor<T> v(t);
return v.res;
}
# undef TRM_GENERIC_MAKE_DECL
}
#endif

28
src/libterm/term_fwd.hh Normal file
View file

@ -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

269
src/libterm/term_impl.hh Normal file
View file

@ -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<const Name *>(ptr_); \
} \
\
inline \
const Name* \
A ## Name :: operator-> () const \
{ \
return static_cast<const Name *>(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<const ATermImpl*>( \
&*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

View file

@ -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<AInt>(t.accept(*this))().value;
return as<AInt>(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));
}
};

23
src/libterm/visitor.hh Normal file
View file

@ -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

View file

@ -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

View file

@ -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 <typename T>
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 <typename T>
inline
T as(ATerm t)
{
impl::asVisitor<T> v(t);
return v.res;
}
}
#endif