Compare commits

...

9 Commits

Author SHA1 Message Date
Nicolas Pierron 00ad497494 Replace "Type::make" by "makeType". 2010-02-24 18:28:08 +00:00
Nicolas Pierron b0d21c1db8 - Split the definition of terms into multiple files.
- Improve the syntax to access Term fields.
- Add term::make/Name/ functions.
2010-02-24 18:13:02 +00:00
Nicolas Pierron 99e554e0e0 Make the test more robust. 2010-02-19 19:39:03 +00:00
Nicolas Pierron e0406330fa Fix compilations errors of the dummy test. 2010-02-19 19:36:03 +00:00
Nicolas Pierron 405c763aa8 Remove some compilations errors. 2010-02-18 20:49:07 +00:00
Nicolas Pierron 61198a89a1 Improve C++ code generation for terms. 2010-02-16 20:22:06 +00:00
Nicolas Pierron 02a4ea0617 - Fix some preprocessing issues.
- Add a simple test to show how the user can to manipulate Terms.
2010-02-15 20:41:44 +00:00
Nicolas Pierron adc5231106 Work in progress. Add to file to create new terms and to handle maximal
sharing between terms.
2010-02-15 17:59:42 +00:00
Lluís Batlle i Rossell d34e538025 Creating a branch to try to get a nix without aterm. 2010-02-13 16:27:50 +00:00
9 changed files with 860 additions and 0 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

202
src/libterm/term.hh Normal file
View File

@ -0,0 +1,202 @@
#ifndef _LIBTERM_TERM_CLASS_FWD_HH
# define _LIBTERM_TERM_CLASS_FWD_HH
# include <set>
# include "visitor_fwd.hh"
namespace term
{
// 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
// following this rule, the compiler can optimize the size to the size of
// its members (which is a pointer).
class ATermImpl
{
public:
ATermImpl();
virtual ~ATermImpl();
public:
virtual ATerm accept(ATermVisitor& v) const = 0;
};
class ATerm
{
public:
ATerm(const ATerm& t);
ATerm();
protected:
ATerm(const ATermImpl* ptr);
public:
ATerm accept(ATermVisitor& v) const;
public:
bool operator== (const ATerm& rhs) const;
bool operator!= (const ATerm& rhs) const;
bool operator <(const ATerm& rhs) const;
operator bool();
public:
const ATermImpl* get_ptr() const;
protected:
const ATermImpl* ptr_;
};
struct Term : public ATermImpl
{
public:
typedef Term this_type;
typedef ATerm term;
public:
bool operator <(const this_type&) const;
};
// [
// 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) \
) );
// 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) \
public: \
TRM_APPLY(TRM_CONST_ABSTRACT_COPY_DECL, Attributes)
// 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_INTERFACE(Name, Base, Attributes, BaseArgs) \
class A ## Name : public A ## Base \
{ \
typedef A ## Base parent; \
\
public: \
A ## Name (const A ## Name& t); \
A ## Name (); \
\
protected: \
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(); \
};
TRM_GRAMMAR_NODES(TRM_ABSTRACT_INTERFACE, TRM_ABSTRACT_FINAL)
TRM_GRAMMAR_NODES(TRM_IMPL_INTERFACE, TRM_IMPL_FINAL)
# 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_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)
# 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

56
src/libterm/test.cc Normal file
View File

@ -0,0 +1,56 @@
#include <vector>
#include <iostream>
#define TRM_GRAMMAR_NODES(Interface, Final) \
Interface(Expr, Term, (0, ()), (0, ())) \
TRM_GRAMMAR_NODE_BINOP(Final, Plus) \
Final(Int, Expr, (1, (TRM_TYPE_COPY(int, value))), (0, ()))
#include "term_impl.hh"
#include "visitor_impl.hh"
#undef TRM_GRAMMAR_NODES
using namespace term;
struct Eval : public ATermVisitor
{
int run(const ATerm t)
{
return as<AInt>(t.accept(*this))->value;
}
ATerm visit(const APlus p)
{
return Int::make(run(p->lhs) + run(p->rhs));
}
};
#define CHECK(Cond, Msg) \
if (Cond) \
{ \
good++; \
std::cout << "Ok: " << Msg << std::endl; \
} \
else \
{ \
std::cout << "Ko: " << Msg << std::endl; \
} \
tests++
int main()
{
unsigned good, tests;
using namespace term;
AInt a = makeInt(1);
AInt b = makeInt(2);
AInt c = makeInt(1);
Eval e;
CHECK(a == c, "Terms are shared.");
CHECK(!as<APlus>(a), "Bad convertion returns a zero ATerm.");
CHECK(as<AInt>(a) == a, "Good convertion returns the same ATerm.");
CHECK(e.run(makePlus(a, makePlus(b, c))) == 4, "Visitors are working.");
return tests - good;
}

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