/*
 * This file is part of the Cforall project
 *
 * $Id: Expression.h,v 1.31 2005/08/29 20:59:25 rcbilson Exp $
 *
 */

#ifndef EXPRESSION_H
#define EXPRESSION_H

#include <map>
#include "SynTree.h"
#include "Visitor.h"
#include "Mutator.h"
#include "Constant.h"


class Expression
{
public:
    Expression(Expression *_aname = 0 );
    Expression( const Expression &other );
    virtual ~Expression();

    std::list<Type *>& get_results() { return results; }
    void add_result(Type *t);

    TypeSubstitution *get_env() const { return env; }
    void set_env( TypeSubstitution *newValue ) { env = newValue; }
    Expression *get_argName() const { return argName; }
    void set_argName( Expression *name ) { argName = name; }

    virtual Expression *clone() const = 0;
    virtual void accept( Visitor &v ) = 0;
    virtual Expression *acceptMutator( Mutator &m ) = 0;
    virtual void print( std::ostream &os, int indent = 0 ) const;
    
protected:
    std::list<Type *> results;
    TypeSubstitution *env;
    Expression* argName; // if expression is used as an argument, it can be "designated" by this name
};

// ParamEntry contains the i.d. of a declaration and a type that is derived from that declaration,
// but subject to decay-to-pointer and type parameter renaming
struct ParamEntry
{
    ParamEntry(): decl( 0 ), actualType( 0 ), formalType( 0 ), expr( 0 ) {}
    ParamEntry( UniqueId decl, Type *actualType, Type *formalType, Expression* expr ): decl( decl ), actualType( actualType ), formalType( formalType ), expr( expr ) {}
    ParamEntry( const ParamEntry &other );
    ~ParamEntry();
    ParamEntry &operator=( const ParamEntry &other );

    UniqueId decl;
    Type *actualType;
    Type *formalType;
    Expression* expr;
};

typedef std::map< UniqueId, ParamEntry > InferredParams;

// ApplicationExpr represents the application of a function to a set of parameters.  This is the
// result of running an UntypedExpr through the expression analyzer.
class ApplicationExpr : public Expression
{
public:
    ApplicationExpr( Expression *function );
    ApplicationExpr( const ApplicationExpr &other );
    virtual ~ApplicationExpr();

    Expression *get_function() const { return function; }
    void set_function( Expression *newValue ) { function = newValue; }
    std::list<Expression *>& get_args() { return args; }
    InferredParams &get_inferParams() { return inferParams; }

    virtual ApplicationExpr *clone() const { return new ApplicationExpr( *this ); }
    virtual void accept( Visitor &v ) { v.visit( this ); }
    virtual Expression *acceptMutator( Mutator &m ) { return m.mutate( this ); }
    virtual void print( std::ostream &os, int indent = 0 ) const;
    
private:
    Expression *function;
    std::list<Expression *> args;
    InferredParams inferParams;
};

// UntypedExpr represents the application of a function to a set of parameters, but where the
// particular overload for the function name has not yet been determined.  Most operators are
// converted into functional form automatically, to permit operator overloading.
class UntypedExpr : public Expression
{
public:
    UntypedExpr( Expression *function, Expression *_aname = 0 );
    UntypedExpr( const UntypedExpr &other );
    UntypedExpr( Expression *function, std::list<Expression *> &args, Expression *_aname = 0 );
    virtual ~UntypedExpr();

    Expression *get_function() const { return function; }
    void set_function( Expression *newValue ) { function = newValue; }

    void set_args( std::list<Expression *> &listArgs ) { args = listArgs; }
    std::list<Expression*>::iterator begin_args() { return args.begin(); }
    std::list<Expression*>::iterator end_args() { return args.end(); }
    std::list<Expression*>& get_args() { return args; }

    virtual UntypedExpr *clone() const { return new UntypedExpr( *this ); }
    virtual void accept( Visitor &v ) { v.visit( this ); }
    virtual Expression *acceptMutator( Mutator &m ) { return m.mutate( this ); }
    virtual void print( std::ostream &os, int indent = 0 ) const;
    virtual void printArgs(std::ostream &os, int indent = 0) const;
    
private:
    
    Expression *function;
    std::list<Expression*> args;
};

// this class contains a name whose meaning is still not determined
class NameExpr : public Expression
{
public:
    NameExpr( std::string name, Expression *_aname = 0 );
    NameExpr( const NameExpr &other );
    virtual ~NameExpr();

    std::string get_name() const { return name; }
    void set_name( std::string newValue ) { name = newValue; }

    virtual NameExpr *clone() const { return new NameExpr( *this ); }
    virtual void accept( Visitor &v ) { v.visit( this ); }
    virtual Expression *acceptMutator( Mutator &m ) { return m.mutate( this ); }
    virtual void print( std::ostream &os, int indent = 0 ) const;
    
private:
    
    std::string name;
};

// The following classes are used to represent expression types that cannot be converted into
// function-call format.

// AddressExpr represents a address-of expression, e.g. &e
class AddressExpr : public Expression
{
public:
    AddressExpr( Expression *arg, Expression *_aname = 0 );
    AddressExpr( const AddressExpr &other );
    virtual ~AddressExpr();

    Expression *get_arg() const { return arg; }
    void set_arg(Expression *newValue ) { arg = newValue; }

    virtual AddressExpr *clone() const { return new AddressExpr( *this ); }
    virtual void accept( Visitor &v ) { v.visit( this ); }
    virtual Expression *acceptMutator( Mutator &m ) { return m.mutate( this ); }
    virtual void print( std::ostream &os, int indent = 0 ) const;
    
private:
    Expression *arg;
};

class LabelAddressExpr : public Expression
{
public:
    LabelAddressExpr( Expression *arg );
    LabelAddressExpr( const AddressExpr &other );
    virtual ~LabelAddressExpr();

    Expression *get_arg() const { return arg; }
    void set_arg(Expression *newValue ) { arg = newValue; }

    virtual LabelAddressExpr *clone() const { return new LabelAddressExpr( *this ); }
    virtual void accept( Visitor &v ) { v.visit( this ); }
    virtual Expression *acceptMutator( Mutator &m ) { return m.mutate( this ); }
    virtual void print( std::ostream &os, int indent = 0 ) const;
    
private:
    Expression *arg;
};

// CastExpr represents a type cast expression, e.g. (int)e
class CastExpr : public Expression
{
public:
    CastExpr( Expression *arg, Expression *_aname = 0 );
    CastExpr( Expression *arg, Type *toType, Expression *_aname = 0 );
    CastExpr( const CastExpr &other );
    virtual ~CastExpr();

    Expression *get_arg() const { return arg; }
    void set_arg(Expression *newValue ) { arg = newValue; }

    virtual CastExpr *clone() const { return new CastExpr( *this ); }
    virtual void accept( Visitor &v ) { v.visit( this ); }
    virtual Expression *acceptMutator( Mutator &m ) { return m.mutate( this ); }
    virtual void print( std::ostream &os, int indent = 0 ) const;
    
private:
    Expression *arg;
};

// UntypedMemberExpr represents a member selection operation, e.g. q.p
// before processing by the expression analyzer
class UntypedMemberExpr : public Expression
{
public:
    UntypedMemberExpr( std::string member, Expression *aggregate, Expression *_aname = 0 );
    UntypedMemberExpr( const UntypedMemberExpr &other );
    virtual ~UntypedMemberExpr();

    std::string get_member() const { return member; }
    void set_member( const std::string &newValue ) { member = newValue; }
    Expression *get_aggregate() const { return aggregate; }
    void set_aggregate( Expression *newValue ) { aggregate = newValue; }

    virtual UntypedMemberExpr *clone() const { return new UntypedMemberExpr( *this ); }
    virtual void accept( Visitor &v ) { v.visit( this ); }
    virtual Expression *acceptMutator( Mutator &m ) { return m.mutate( this ); }
    virtual void print( std::ostream &os, int indent = 0 ) const;
    
private:
    std::string member;
    Expression *aggregate;
};

// MemberExpr represents a member selection operation, e.g. q.p
// after processing by the expression analyzer
class MemberExpr : public Expression
{
public:
    MemberExpr( DeclarationWithType *member, Expression *aggregate, Expression *_aname = 0 );
    MemberExpr( const MemberExpr &other );
    virtual ~MemberExpr();

    DeclarationWithType *get_member() const { return member; }
    void set_member( DeclarationWithType *newValue ) { member = newValue; }
    Expression *get_aggregate() const { return aggregate; }
    void set_aggregate( Expression *newValue ) { aggregate = newValue; }

    virtual MemberExpr *clone() const { return new MemberExpr( *this ); }
    virtual void accept( Visitor &v ) { v.visit( this ); }
    virtual Expression *acceptMutator( Mutator &m ) { return m.mutate( this ); }
    virtual void print( std::ostream &os, int indent = 0 ) const;
    
private:
    DeclarationWithType *member;
    Expression *aggregate;
};

// VariableExpr represents an expression that simply refers to the value of a named variable
class VariableExpr : public Expression
{
public:
    VariableExpr( DeclarationWithType *var, Expression *_aname = 0 );
    VariableExpr( const VariableExpr &other );
    virtual ~VariableExpr();

    DeclarationWithType *get_var() const { return var; }
    void set_var( DeclarationWithType *newValue ) { var = newValue; }

    virtual VariableExpr *clone() const { return new VariableExpr( *this ); }
    virtual void accept( Visitor &v ) { v.visit( this ); }
    virtual Expression *acceptMutator( Mutator &m ) { return m.mutate( this ); }
    virtual void print( std::ostream &os, int indent = 0 ) const;
    
private:
    DeclarationWithType *var;
};

// ConstantExpr represents an expression that simply refers to the value of a constant 
class ConstantExpr : public Expression
{
public:
    ConstantExpr( Constant constant, Expression *_aname = 0 );
    ConstantExpr( const ConstantExpr &other );
    virtual ~ConstantExpr();

    Constant *get_constant() { return &constant; }
    void set_constant( const Constant &newValue ) { constant = newValue; }

    virtual ConstantExpr *clone() const { return new ConstantExpr( *this ); }
    virtual void accept( Visitor &v ) { v.visit( this ); }
    virtual Expression *acceptMutator( Mutator &m ) { return m.mutate( this ); }
    virtual void print( std::ostream &os, int indent = 0 ) const;
    
private:
    Constant constant;
};

// SizeofExpr represents a sizeof expression (could be sizeof(int) or sizeof 3+4)
class SizeofExpr : public Expression
{
public:
    SizeofExpr( Expression *expr, Expression *_aname = 0 );
    SizeofExpr( const SizeofExpr &other );
    SizeofExpr( Type *type, Expression *_aname = 0 );
    virtual ~SizeofExpr();

    Expression *get_expr() const { return expr; }
    void set_expr( Expression *newValue ) { expr = newValue; }
    Type *get_type() const { return type; }
    void set_type( Type *newValue ) { type = newValue; }
    bool get_isType() const { return isType; }
    void set_isType( bool newValue ) { isType = newValue; }

    virtual SizeofExpr *clone() const { return new SizeofExpr( *this ); }
    virtual void accept( Visitor &v ) { v.visit( this ); }
    virtual Expression *acceptMutator( Mutator &m ) { return m.mutate( this ); }
    virtual void print( std::ostream &os, int indent = 0 ) const;
    
private:
    Expression *expr;
    Type *type;
    bool isType;
};

// AttrExpr represents an @attribute expression (like sizeof, but user-defined)
class AttrExpr : public Expression
{
public:
    AttrExpr(Expression *attr, Expression *expr, Expression *_aname = 0 );
    AttrExpr( const AttrExpr &other );
    AttrExpr( Expression *attr, Type *type, Expression *_aname = 0 );
    virtual ~AttrExpr();

    Expression *get_attr() const { return attr; }
    void set_attr( Expression *newValue ) { attr = newValue; }
    Expression *get_expr() const { return expr; }
    void set_expr( Expression *newValue ) { expr = newValue; }
    Type *get_type() const { return type; }
    void set_type( Type *newValue ) { type = newValue; }
    bool get_isType() const { return isType; }
    void set_isType( bool newValue ) { isType = newValue; }

    virtual AttrExpr *clone() const { return new AttrExpr( *this ); }
    virtual void accept( Visitor &v ) { v.visit( this ); }
    virtual Expression *acceptMutator( Mutator &m ) { return m.mutate( this ); }
    virtual void print( std::ostream &os, int indent = 0 ) const;
    
private:
    Expression *attr;
    Expression *expr;
    Type *type;
    bool isType;
};

// LogicalExpr represents a short-circuit boolean expression (&& or ||)
class LogicalExpr : public Expression
{
public:
    LogicalExpr( Expression *arg1, Expression *arg2, bool andp = true, Expression *_aname = 0 );
    LogicalExpr( const LogicalExpr &other );
    virtual ~LogicalExpr();

    bool get_isAnd() const { return isAnd; }
    Expression *get_arg1() { return arg1; }
    void set_arg1( Expression *newValue ) { arg1 = newValue; }
    Expression *get_arg2() const { return arg2; }
    void set_arg2( Expression *newValue ) { arg2 = newValue; }

    virtual LogicalExpr *clone() const { return new LogicalExpr( *this ); }
    virtual void accept( Visitor &v ) { v.visit( this ); }
    virtual Expression *acceptMutator( Mutator &m ) { return m.mutate( this ); }
    virtual void print( std::ostream &os, int indent = 0 ) const;
    
private:
    Expression *arg1;
    Expression *arg2;
    bool isAnd;
};

// ConditionalExpr represents the three-argument conditional ( p ? a : b )
class ConditionalExpr : public Expression
{
public:
    ConditionalExpr( Expression *arg1, Expression *arg2, Expression *arg3, Expression *_aname = 0 );
    ConditionalExpr( const ConditionalExpr &other );
    virtual ~ConditionalExpr();

    Expression *get_arg1() const { return arg1; }
    void set_arg1( Expression *newValue ) { arg1 = newValue; }
    Expression *get_arg2() const { return arg2; }
    void set_arg2( Expression *newValue ) { arg2 = newValue; }
    Expression *get_arg3() const { return arg3; }
    void set_arg3( Expression *newValue ) { arg3 = newValue; }

    virtual ConditionalExpr *clone() const { return new ConditionalExpr( *this ); }
    virtual void accept( Visitor &v ) { v.visit( this ); }
    virtual Expression *acceptMutator( Mutator &m ) { return m.mutate( this ); }
    virtual void print( std::ostream &os, int indent = 0 ) const;
    
private:
    Expression *arg1;
    Expression *arg2;
    Expression *arg3;
};

// CommaExpr represents the sequence operator ( a, b )
class CommaExpr : public Expression
{
public:
    CommaExpr( Expression *arg1, Expression *arg2, Expression *_aname = 0 );
    CommaExpr( const CommaExpr &other );
    virtual ~CommaExpr();

    Expression *get_arg1() const { return arg1; }
    void set_arg1( Expression *newValue ) { arg1 = newValue; }
    Expression *get_arg2() const { return arg2; }
    void set_arg2( Expression *newValue ) { arg2 = newValue; }

    virtual CommaExpr *clone() const { return new CommaExpr( *this ); }
    virtual void accept( Visitor &v ) { v.visit( this ); }
    virtual Expression *acceptMutator( Mutator &m ) { return m.mutate( this ); }
    virtual void print( std::ostream &os, int indent = 0 ) const;
    
private:
    Expression *arg1;
    Expression *arg2;
};

// TupleExpr represents a tuple expression ( [a, b, c] )
class TupleExpr : public Expression
{
public:
    TupleExpr( Expression *_aname = 0 );
    TupleExpr( const TupleExpr &other );
    virtual ~TupleExpr();

    void set_exprs( std::list<Expression*> newValue ) { exprs = newValue; }
    std::list<Expression*>& get_exprs() { return exprs; }

    virtual TupleExpr *clone() const { return new TupleExpr( *this ); }
    virtual void accept( Visitor &v ) { v.visit( this ); }
    virtual Expression *acceptMutator( Mutator &m ) { return m.mutate( this ); }
    virtual void print( std::ostream &os, int indent = 0 ) const;
    
private:
    std::list<Expression*> exprs;
};

// SolvedTupleExpr represents a TupleExpr whose components have been type-resolved. It is effectively a shell for the code generator to work on
class SolvedTupleExpr : public Expression
{
public:

    SolvedTupleExpr( Expression *_aname = 0 ) : Expression( _aname ) {}
    SolvedTupleExpr( std::list<Expression *> &, Expression *_aname = 0 );
    SolvedTupleExpr( const SolvedTupleExpr &other );
    virtual ~SolvedTupleExpr() {}

    std::list<Expression*> &get_exprs() { return exprs; }

    virtual SolvedTupleExpr *clone() const { return new SolvedTupleExpr( *this ); }
    virtual void accept( Visitor &v ) { v.visit( this ); }
    virtual Expression *acceptMutator( Mutator &m ) { return m.mutate( this ); }
    virtual void print( std::ostream &os, int indent = 0 ) const;
private:
    std::list<Expression*> exprs;
};

// TypeExpr represents a type used in an expression (e.g. as a type generator parameter)
class TypeExpr : public Expression
{
public:
    TypeExpr( Type *type );
    TypeExpr( const TypeExpr &other );
    virtual ~TypeExpr();

    Type *get_type() const { return type; }
    void set_type( Type *newValue ) { type = newValue; }

    virtual TypeExpr *clone() const { return new TypeExpr( *this ); }
    virtual void accept( Visitor &v ) { v.visit( this ); }
    virtual Expression *acceptMutator( Mutator &m ) { return m.mutate( this ); }
    virtual void print( std::ostream &os, int indent = 0 ) const;
    
private:
    Type *type;
};

// ValofExpr represents a GCC 'lambda expression'
class UntypedValofExpr : public Expression
{
public:
    UntypedValofExpr( Statement *_body, Expression *_aname = 0 ) : Expression( _aname ), body ( _body ) {}
    virtual ~UntypedValofExpr() {}

    Expression *get_value();
    Statement *get_body() const { return body; }

    virtual UntypedValofExpr *clone() const { return new UntypedValofExpr( *this ); }
    virtual void accept( Visitor &v ) { v.visit( this ); }
    virtual Expression *acceptMutator( Mutator &m ) { return m.mutate( this ); }
    virtual void print( std::ostream &os, int indent = 0 ) const;
    
private:
    Statement *body;
};


#endif /* #ifndef EXPRESSION_H */

/*
    Local Variables:
    mode: c++
    End:
*/
