// $Header: /cvsroot/sourcenav/src/snavigator/demo/c++_demo/glish/BinOpExpr.h,v 1.1.1.1 2002/04/18 23:35:15 mdejong Exp $


// Definitions for arithmetic and relational Expr classes

#ifndef binopexpr_h
#define binopexpr_h

#include "Expr.h"


// Arithmetic operations supported on values.
typedef enum {
	OP_ADD, OP_SUBTRACT, OP_MULTIPLY, OP_DIVIDE, OP_MODULO, OP_POWER,
	OP_AND, OP_OR,
	OP_EQ, OP_NE, OP_LE, OP_GE, OP_LT, OP_GT
	} binop;


// An BinOpExpr is a binary expression which performs some arithmetic
// or relational operation.

class BinOpExpr : public BinaryExpr {
    public:
	BinOpExpr( binop op, Expr* op1, Expr* op2, const char* desc );

	Value* Eval( eval_type etype ) = 0;

    protected:
	// Returns true if the expression's operands type-check, false
	// (and generates an error message) otherwise.  The default TypeCheck
	// implements arithmetic type-checking (operands must be numeric).
	//
	// The third argument is set to true if this expression operates
	// element-by-element on arrays, false otherwise.
	virtual int TypeCheck( const Value* lhs, const Value* rhs,
				int& element_by_element ) const;

	// What type the BinOpExpr's operands should be promoted to.  The
	// default OperandsType implements numeric promotion (higher operand
	// type is used, where the hierarchy is double, float, int, and
	// bool is promoted to int).
	virtual glish_type OperandsType( const Value* lhs, const Value* rhs )
			const;

	// Called after type-checking is done.  Checks array lengths
	// for compatibility and promotes scalars to arrays as necessary.
	// Returns in lhs_len the array length at which lhs should be
	// used (if lhs is a scalar and rhs is an array then this will be
	// the length of rhs, otherwise the length of lhs).  Returns true
	// all checking was okay, false otherwise (in which case lhs_len
	// may not have been set).
	int Compute( const Value* lhs, const Value* rhs, int& lhs_len ) const;

	binop op;
	};


// A BinOp expression that performs an arithmetic operation: i.e., one
// in which the operands are of numeric type and the result is the same
// type as the operands.
class ArithExpr : public BinOpExpr {
    public:
	ArithExpr( binop op, Expr* op1, Expr* op2,
			const char* desc ) : BinOpExpr(op, op1, op2, desc)
		{ }

	Value* Eval( eval_type etype );

	virtual void Compute( byte lhs[], byte rhs[],
				int lhs_len, int rhs_incr ) = 0;
	virtual void Compute( short lhs[], short rhs[],
				int lhs_len, int rhs_incr ) = 0;
	virtual void Compute( int lhs[], int rhs[],
				int lhs_len, int rhs_incr ) = 0;
	virtual void Compute( float lhs[], float rhs[],
				int lhs_len, int rhs_incr ) = 0;
	virtual void Compute( double lhs[], double rhs[],
				int lhs_len, int rhs_incr ) = 0;
	virtual void Compute( complex lhs[], complex rhs[],
				int lhs_len, int rhs_incr ) = 0;
	virtual void Compute( dcomplex lhs[], dcomplex rhs[],
				int lhs_len, int rhs_incr ) = 0;

    protected:
	Value* OpCompute( Value* lhs, const Value* rhs, int lhs_len );
	};

#define DECLARE_ARITH_EXPR(name, op, op_name, overloads)		\
class name : public ArithExpr {						\
    public:								\
	name( Expr* op1, Expr* op2 )					\
		: ArithExpr(op, op1, op2, op_name)	{ }		\
	overloads							\
	void Compute( byte lhs[], byte rhs[], int lhs_len, int rhs_incr );\
	void Compute( short lhs[], short rhs[], int lhs_len, int rhs_incr );\
	void Compute( int lhs[], int rhs[], int lhs_len, int rhs_incr );\
	void Compute( float lhs[], float rhs[], int lhs_len, int rhs_incr );\
	void Compute( double lhs[], double rhs[], int lhs_len, int rhs_incr );\
	void Compute( complex lhs[], complex rhs[], int lhs_len,	\
			int rhs_incr );					\
	void Compute( dcomplex lhs[], dcomplex rhs[], int lhs_len,	\
			int rhs_incr );					\
	};

DECLARE_ARITH_EXPR(AddExpr, OP_ADD, "+",)
DECLARE_ARITH_EXPR(SubtractExpr, OP_SUBTRACT, "-",)
DECLARE_ARITH_EXPR(MultiplyExpr, OP_MULTIPLY, "*",)
DECLARE_ARITH_EXPR(DivideExpr, OP_DIVIDE, "/",
	glish_type OperandsType( const Value* lhs, const Value* rhs ) const;)
DECLARE_ARITH_EXPR(ModuloExpr, OP_MODULO, "/",
	glish_type OperandsType( const Value* lhs, const Value* rhs ) const;)
DECLARE_ARITH_EXPR(PowerExpr, OP_POWER, "^",
	glish_type OperandsType( const Value* lhs, const Value* rhs ) const;)


// A BinOpExpr that performs a relational operation; i.e., an operation with
// a boolean result value.
class RelExpr : public BinOpExpr {
    public:
	RelExpr( binop op, Expr* op1, Expr* op2, const char* desc )
			: BinOpExpr(op, op1, op2, desc) { }

	Value* Eval( eval_type etype );

	virtual void Compute( glish_bool lhs[], glish_bool rhs[],
				glish_bool result[],
				int lhs_len, int rhs_incr ) = 0;
	virtual void Compute( byte lhs[], byte rhs[], glish_bool result[],
				int lhs_len, int rhs_incr ) = 0;
	virtual void Compute( short lhs[], short rhs[], glish_bool result[],
				int lhs_len, int rhs_incr ) = 0;
	virtual void Compute( int lhs[], int rhs[], glish_bool result[],
				int lhs_len, int rhs_incr ) = 0;
	virtual void Compute( float lhs[], float rhs[], glish_bool result[],
				int lhs_len, int rhs_incr ) = 0;
	virtual void Compute( double lhs[], double rhs[], glish_bool result[],
				int lhs_len, int rhs_incr ) = 0;
	virtual void Compute( complex lhs[], complex rhs[], glish_bool result[],
				int lhs_len, int rhs_incr ) = 0;
	virtual void Compute( dcomplex lhs[], dcomplex rhs[],
				glish_bool result[],
				int lhs_len, int rhs_incr ) = 0;
	virtual void Compute( charptr lhs[], charptr rhs[], glish_bool result[],
				int lhs_len, int rhs_incr ) = 0;

    protected:
	int TypeCheck( const Value* lhs, const Value* rhs,
			int& element_by_element ) const;
	glish_type OperandsType( const Value* lhs, const Value* rhs ) const;
	Value* OpCompute( const Value* lhs, const Value* rhs, int lhs_len );
	};


#define DECLARE_REL_EXPR(name, op, op_name)				\
class name : public RelExpr {						\
    public:								\
	name( Expr* op1, Expr* op2 )					\
		: RelExpr(op, op1, op2, op_name)	{ }		\
	void Compute( glish_bool lhs[], glish_bool rhs[],		\
			glish_bool result[],				\
			int lhs_len, int rhs_incr );			\
	void Compute( byte lhs[], byte rhs[], glish_bool result[],	\
			int lhs_len, int rhs_incr );			\
	void Compute( short lhs[], short rhs[], glish_bool result[],	\
			int lhs_len, int rhs_incr );			\
	void Compute( int lhs[], int rhs[], glish_bool result[],	\
			int lhs_len, int rhs_incr );			\
	void Compute( float lhs[], float rhs[], glish_bool result[],	\
			int lhs_len, int rhs_incr );			\
	void Compute( double lhs[], double rhs[], glish_bool result[],	\
			int lhs_len, int rhs_incr );			\
	void Compute( complex lhs[], complex rhs[], glish_bool result[],\
			int lhs_len, int rhs_incr );			\
	void Compute( dcomplex lhs[], dcomplex rhs[], glish_bool result[],\
			int lhs_len, int rhs_incr );			\
	void Compute( charptr lhs[], charptr rhs[], glish_bool result[],\
			int lhs_len, int rhs_incr );			\
	};

DECLARE_REL_EXPR(EQ_Expr, OP_EQ, "==")
DECLARE_REL_EXPR(NE_Expr, OP_NE, "!=")
DECLARE_REL_EXPR(LE_Expr, OP_LE, "<=")
DECLARE_REL_EXPR(GE_Expr, OP_GE, ">=")
DECLARE_REL_EXPR(LT_Expr, OP_LT, "<")
DECLARE_REL_EXPR(GT_Expr, OP_GT, ">")


// A RelExpr that performs a logical operation; i.e., boolean operands with
// a boolean result value.
class LogExpr : public RelExpr {
    public:
	LogExpr( binop op, Expr* op1, Expr* op2, const char* desc )
			: RelExpr(op, op1, op2, desc)	{ }


	void Compute( glish_bool lhs[], glish_bool rhs[], glish_bool result[],
			int lhs_len, int rhs_incr );
	void Compute( byte lhs[], byte rhs[], glish_bool result[],
			int lhs_len, int rhs_incr );
	void Compute( short lhs[], short rhs[], glish_bool result[],
			int lhs_len, int rhs_incr );
	void Compute( int lhs[], int rhs[], glish_bool result[],
			int lhs_len, int rhs_incr );
	void Compute( float lhs[], float rhs[], glish_bool result[],
			int lhs_len, int rhs_incr );
	void Compute( double lhs[], double rhs[], glish_bool result[],
			int lhs_len, int rhs_incr );
	void Compute( complex lhs[], complex rhs[], glish_bool result[],
			int lhs_len, int rhs_incr );
	void Compute( dcomplex lhs[], dcomplex rhs[], glish_bool result[],
			int lhs_len, int rhs_incr );
	void Compute( charptr lhs[], charptr rhs[], glish_bool result[],
			int lhs_len, int rhs_incr );

    protected:
	int TypeCheck( const Value* lhs, const Value* rhs,
			int& element_by_element ) const;
	glish_type OperandsType( const Value* lhs, const Value* rhs ) const;
	};


#define DECLARE_LOG_EXPR(name, op, op_name)				\
class name : public LogExpr {						\
    public:								\
	name( Expr* op1, Expr* op2 )					\
		: LogExpr(op, op1, op2, op_name)	{ }		\
									\
	void Compute( glish_bool lhs[], glish_bool rhs[],		\
			glish_bool result[], int lhs_len, int rhs_incr );\
									\
	void Compute( int lhs[], int rhs[], glish_bool result[],	\
			int lhs_len, int rhs_incr )			\
		{ LogExpr::Compute(lhs,rhs,result,lhs_len,rhs_incr); }	\
	void Compute( float lhs[], float rhs[], glish_bool result[],	\
			int lhs_len, int rhs_incr )			\
		{ LogExpr::Compute(lhs,rhs,result,lhs_len,rhs_incr); }	\
	void Compute( double lhs[], double rhs[], glish_bool result[],	\
			int lhs_len, int rhs_incr )			\
		{ LogExpr::Compute(lhs,rhs,result,lhs_len,rhs_incr); }	\
	void Compute( complex lhs[], complex rhs[], glish_bool result[],\
			int lhs_len, int rhs_incr )			\
		{ LogExpr::Compute(lhs,rhs,result,lhs_len,rhs_incr); }	\
	void Compute( dcomplex lhs[], dcomplex rhs[], glish_bool result[],\
			int lhs_len, int rhs_incr )			\
		{ LogExpr::Compute(lhs,rhs,result,lhs_len,rhs_incr); }	\
	void Compute( charptr lhs[], charptr rhs[], glish_bool result[],\
			int lhs_len, int rhs_incr )			\
		{ LogExpr::Compute(lhs,rhs,result,lhs_len,rhs_incr); }	\
	void Compute( byte lhs[], byte rhs[], glish_bool result[],	\
			int lhs_len, int rhs_incr )			\
		{ LogExpr::Compute(lhs,rhs,result,lhs_len,rhs_incr); }	\
	void Compute( short lhs[], short rhs[], glish_bool result[],	\
			int lhs_len, int rhs_incr )			\
		{ LogExpr::Compute(lhs,rhs,result,lhs_len,rhs_incr); }	\
	};

DECLARE_LOG_EXPR(LogAndExpr, OP_AND, "&")
DECLARE_LOG_EXPR(LogOrExpr, OP_OR, "|")

#endif /* binopexpr_h */
