//
// Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo
//
// The contents of this file are covered under the licence agreement in the
// file "LICENCE" distributed with Cforall.
//
// Expression.h --
//
// Author           : Richard C. Bilson
// Created On       : Mon May 18 07:44:20 2015
// Last Modified By : Rob Schluntz
// Last Modified On : Wed Dec 09 14:10:21 2015
// Update Count     : 19
//

#ifndef EXPRESSION_H
#define EXPRESSION_H

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

/// Expression is the root type for all expressions
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;
};

/// NameExpr 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();

	const 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;
};

// xxx - this doesn't appear to actually be hooked in anywhere. We should use this instead of the "&&"" UntypedExpr hack
class LabelAddressExpr : public Expression {
  public:
	LabelAddressExpr( Expression *arg );
	LabelAddressExpr( const LabelAddressExpr &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;
};

/// AlignofExpr represents an alignof expression
class AlignofExpr : public Expression {
  public:
	AlignofExpr( Expression *expr, Expression *_aname = 0 );
	AlignofExpr( const AlignofExpr &other );
	AlignofExpr( Type *type, Expression *_aname = 0 );
	virtual ~AlignofExpr();

	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 AlignofExpr *clone() const { return new AlignofExpr( *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;
};

/// UntypedOffsetofExpr represents an offsetof expression before resolution
class UntypedOffsetofExpr : public Expression {
  public:
	UntypedOffsetofExpr( Type *type, const std::string &member, Expression *_aname = 0 );
	UntypedOffsetofExpr( const UntypedOffsetofExpr &other );
	virtual ~UntypedOffsetofExpr();

	std::string get_member() const { return member; }
	void set_member( const std::string &newValue ) { member = newValue; }
	Type *get_type() const { return type; }
	void set_type( Type *newValue ) { type = newValue; }

	virtual UntypedOffsetofExpr *clone() const { return new UntypedOffsetofExpr( *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;
	std::string member;
};

/// OffsetofExpr represents an offsetof expression
class OffsetofExpr : public Expression {
  public:
	OffsetofExpr( Type *type, DeclarationWithType *member, Expression *_aname = 0 );
	OffsetofExpr( const OffsetofExpr &other );
	virtual ~OffsetofExpr();

	Type *get_type() const { return type; }
	void set_type( Type *newValue ) { type = newValue; }
	DeclarationWithType *get_member() const { return member; }
	void set_member( DeclarationWithType *newValue ) { member = newValue; }

	virtual OffsetofExpr *clone() const { return new OffsetofExpr( *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;
	DeclarationWithType *member;
};

/// 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;
};

/// AsmExpr represents a GCC 'asm constraint operand' used in an asm statement: [output] "=f" (result)
class AsmExpr : public Expression {
  public:
	AsmExpr( Expression *inout, ConstantExpr *constraint, Expression *operand ) : inout( inout ), constraint( constraint ), operand( operand ) {}
	AsmExpr( const AsmExpr & other );
	virtual ~AsmExpr() { delete inout; delete constraint; delete operand; };

	Expression *get_inout() const { return inout; }
	void set_inout( Expression *newValue ) { inout = newValue; }

	ConstantExpr *get_constraint() const { return constraint; }
	void set_constraint( ConstantExpr *newValue ) { constraint = newValue; }

	Expression *get_operand() const { return operand; }
	void set_operand( Expression *newValue ) { operand = newValue; }

	virtual AsmExpr *clone() const { return new AsmExpr( *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:
	// https://gcc.gnu.org/onlinedocs/gcc-4.7.1/gcc/Machine-Constraints.html#Machine-Constraints
	Expression *inout;
	ConstantExpr *constraint;
	Expression *operand;
};

/// ValofExpr represents a GCC 'lambda expression'
class UntypedValofExpr : public Expression {
  public:
	UntypedValofExpr( Statement *_body, Expression *_aname = 0 ) : Expression( _aname ), body ( _body ) {}
	UntypedValofExpr( const UntypedValofExpr & other );
	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;
};

std::ostream & operator<<( std::ostream & out, Expression * expr );

#endif // EXPRESSION_H

// Local Variables: //
// tab-width: 4 //
// mode: c++ //
// compile-command: "make install" //
// End: //
