//
// 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.
//
// ExpressionNode.cc -- 
// 
// Author           : Rodolfo G. Esteves
// Created On       : Sat May 16 13:17:07 2015
// Last Modified By : Peter A. Buhr
// Last Modified On : Mon Oct  5 16:37:24 2015
// Update Count     : 255
// 

#include <cassert>
#include <cctype>
#include <algorithm>
#include <sstream>
#include <cstdio>
#include <climits>

#include "ParseNode.h"
#include "SynTree/Constant.h"
#include "SynTree/Expression.h"
#include "UnimplementedError.h"
#include "parseutility.h"
#include "utility.h"

using namespace std;

ExpressionNode::ExpressionNode() : ParseNode(), argName( 0 ) {}

ExpressionNode::ExpressionNode( const string *name ) : ParseNode( name ), argName( 0 ) {}

ExpressionNode::ExpressionNode( const ExpressionNode &other ) : ParseNode( other.name ) {
	if ( other.argName ) {
		argName = other.argName->clone();
	} else {
		argName = 0;
	} // if
}

ExpressionNode * ExpressionNode::set_argName( const std::string *aName ) {
	argName = new VarRefNode( aName );
	return this;
}

ExpressionNode * ExpressionNode::set_argName( ExpressionNode *aDesignator ) {
	argName = aDesignator;
	return this;
}

void ExpressionNode::printDesignation( std::ostream &os, int indent ) const {
	if ( argName ) {
		os << string( indent, ' ' ) << "(designated by:  ";
		argName->printOneLine( os, indent );
		os << ")" << std::endl;
	} // if
}

//##############################################################################

NullExprNode::NullExprNode() {}

NullExprNode *NullExprNode::clone() const {
	return new NullExprNode();
}

void NullExprNode::print( std::ostream & os, int indent ) const {
	printDesignation( os );
	os << "null expression";
}

void NullExprNode::printOneLine( std::ostream & os, int indent ) const {
	printDesignation( os );
	os << "null";
}

Expression *NullExprNode::build() const {
	return 0;
}

CommaExprNode *ExpressionNode::add_to_list( ExpressionNode *exp ) {
	return new CommaExprNode( this, exp );
}

//##############################################################################

static inline bool checkU( char c ) { return c == 'u' || c == 'U'; }
static inline bool checkL( char c ) { return c == 'l' || c == 'L'; }
static inline bool checkF( char c ) { return c == 'f' || c == 'F'; }
static inline bool checkX( char c ) { return c == 'x' || c == 'X'; }

// Difficult to separate extra parts of constants during lexing because actions are not allow in the middle of patterns:
//
//		prefix action constant action suffix
//
// Alternatively, breaking a pattern using BEGIN does not work if the following pattern can be empty:
//
//		constant BEGIN CONT ...
//		<CONT>(...)? BEGIN 0 ... // possible empty suffix
//
// because the CONT rule is NOT triggered if the pattern is empty. Hence, constants are reparsed here to determine their
// type.

ConstantNode::ConstantNode( Type t, string *inVal ) : type( t ), value( *inVal ) {
	// lexing divides constants into 4 kinds
	switch ( type ) {
	  case Integer:
		{
			static const BasicType::Kind kind[2][3] = {
				{ BasicType::SignedInt, BasicType::LongSignedInt, BasicType::LongLongSignedInt },
				{ BasicType::UnsignedInt, BasicType::LongUnsignedInt, BasicType::LongLongUnsignedInt },
			};
			size_t last = value.length() - 1;			// last character of constant
			unsigned long long v;						// converted integral value
			bool dec = true, Unsigned = false;			// decimal, unsigned constant
			int size;									// 0 => int, 1 => long, 2 => long long

			if ( value[0] == '0' ) {					// octal constant ?
				dec = false;
				if ( last != 0 && checkX( value[1] ) ) { // hex constant ?
					sscanf( (char *)value.c_str(), "%llx", &v );
					//printf( "%llx %llu\n", v, v );
				} else {
					sscanf( (char *)value.c_str(), "%llo", &v );
					//printf( "%llo %llu\n", v, v );
				} // if
			} else {									// decimal constant ?
				sscanf( (char *)value.c_str(), "%llu", &v );
				//printf( "%llu %llu\n", v, v );
			} // if

			if ( v <= INT_MAX ) {						// signed int
				size = 0;
			} else if ( v <= UINT_MAX && ! dec ) {		// unsigned int
				size = 0;
				Unsigned = true;						// unsigned
			} else if ( v <= LONG_MAX ) {				// signed long int
				size = 1;
			} else if ( v <= ULONG_MAX && ( ! dec || LONG_MAX == LLONG_MAX ) ) { // signed long int
				size = 1;
				Unsigned = true;						// unsigned long int
			} else if ( v <= LLONG_MAX ) {				// signed long long int
				size = 2;
			} else {									// unsigned long long int
				size = 2;
				Unsigned = true;						// unsigned long long int
			} // if

			if ( checkU( value[last] ) ) {				// suffix 'u' ?
				Unsigned = true;
				if ( last > 0 && checkL( value[ last - 1 ] ) ) { // suffix 'l' ?
					size = 1;
					if ( last > 1 && checkL( value[ last - 2 ] ) ) { // suffix 'll' ?
						size = 2;
					} // if
				} // if
			} else if ( checkL( value[ last ] ) ) {		// suffix 'l' ?
				size = 1;
				if ( last > 0 && checkL( value[ last - 1 ] ) ) { // suffix 'll' ?
					size = 2;
					if ( last > 1 && checkU( value[ last - 2 ] ) ) { // suffix 'u' ?
						Unsigned = true;
					} // if
				} else {
					if ( last > 0 && checkU( value[ last - 1 ] ) ) { // suffix 'u' ?
						Unsigned = true;
					} // if
				} // if
			} // if
			btype = kind[Unsigned][size];				// lookup constant type
			break;
		}
	  case Float:
		{
			size_t len = value.length() - 1;

			btype = BasicType::Double;					// default
			if ( checkF( value[len] ) ) {				// float ?
				btype = BasicType::Float;
			} // if
			if ( checkL( value[len] ) ) {				// long double ?
				btype = BasicType::LongDouble;
			} // if
			break;
		}
	  case Character:
		btype = BasicType::Char;						// default
		if ( string( "LUu" ).find( value[0] ) != string::npos ) {
			// ???
		} // if
		break;
	  case String:
		// array of char
		if ( string( "LUu" ).find( value[0] ) != string::npos ) {
			if ( value[0] == 'u' && value[1] == '8' ) {
				// ???
			} else {
				// ???
			} // if
		} // if
		break;
	} // switch
} // ConstantNode::ConstantNode

ConstantNode *ConstantNode::appendstr( const std::string *newValue ) {
	assert( newValue != 0 );
	assert( type == String );

	// "abc" "def" "ghi" => "abcdefghi", remove new text from quotes and insert before last quote in old string.
	value.insert( value.length() - 1, newValue->substr( 1, newValue->length() - 2 ) );
	
	delete newValue;									// allocated by lexer
	return this;
}

void ConstantNode::printOneLine( std::ostream &os, int indent ) const {
	os << string( indent, ' ' );
	printDesignation( os );

	switch ( type ) {
	  case Integer:
	  case Float:
		os << value ;
		break;
	  case Character:
		os << "'" << value << "'";
		break;
	  case String:
		os << '"' << value << '"';
		break;
	} // switch

	os << ' ';
}

void ConstantNode::print( std::ostream &os, int indent ) const {
	printOneLine( os, indent );
	os << endl;
}

Expression *ConstantNode::build() const {
	::Type::Qualifiers q;								// no qualifiers on constants

	switch ( get_type() ) {
	  case String:
		{
			// string should probably be a primitive type
			ArrayType *at = new ArrayType( q, new BasicType( q, BasicType::Char ),
										   new ConstantExpr(
											   Constant( new BasicType( q, BasicType::UnsignedInt ),
														 toString( value.size()+1-2 ) ) ),  // +1 for '\0' and -2 for '"'
										   false, false );
			return new ConstantExpr( Constant( at, value ), maybeBuild< Expression >( get_argName() ) );
		}
	  default:
		return new ConstantExpr( Constant( new BasicType( q, btype ), get_value() ), maybeBuild< Expression >( get_argName() ) );
	}
}

//##############################################################################

VarRefNode::VarRefNode() : isLabel( false ) {}

VarRefNode::VarRefNode( const string *name_, bool labelp ) : ExpressionNode( name_ ), isLabel( labelp ) {}

VarRefNode::VarRefNode( const VarRefNode &other ) : ExpressionNode( other ), isLabel( other.isLabel ) {
}

Expression *VarRefNode::build() const {
	return new NameExpr( get_name(), maybeBuild< Expression >( get_argName() ) );
}

void VarRefNode::printOneLine( std::ostream &os, int indent ) const {
	printDesignation( os );
	os << get_name() << ' ';
}

void VarRefNode::print( std::ostream &os, int indent ) const {
	printDesignation( os );
	os << string( indent, ' ' ) << "Referencing: ";
	os << "Variable: " << get_name();
	os << endl;
}

//##############################################################################

DesignatorNode::DesignatorNode( ExpressionNode *expr, bool isArrayIndex ) : isArrayIndex( isArrayIndex ) {
	set_argName( expr );
	assert( get_argName() );

	if ( ! isArrayIndex ) {
		if ( VarRefNode * var = dynamic_cast< VarRefNode * >( expr ) ) {

			stringstream ss( var->get_name() );
			double value;
			if ( ss >> value ) {
				// this is a floating point constant. It MUST be
				// ".0" or ".1", otherwise the program is invalid
				if ( ! (var->get_name() == ".0" || var->get_name() == ".1") ) {
					throw SemanticError( "invalid designator name: " + var->get_name() );
				} // if
				var->set_name( var->get_name().substr(1) );
			} // if
		} // if
	} // if
}

DesignatorNode::DesignatorNode( const DesignatorNode &other ) : ExpressionNode( other ), isArrayIndex( other.isArrayIndex ) {
}

class DesignatorFixer : public Mutator {
public:
	virtual Expression* mutate( NameExpr *nameExpr ) {
		if ( nameExpr->get_name() == "0" || nameExpr->get_name() == "1" ) {
			Constant val( new BasicType( Type::Qualifiers(), BasicType::SignedInt ), nameExpr->get_name() );
			delete nameExpr;
			return new ConstantExpr( val );
		}
		return nameExpr;
	}
};

Expression *DesignatorNode::build() const {
	Expression * ret = get_argName()->build();

	if ( isArrayIndex ) {
		// need to traverse entire structure and change any instances of 0 or 1 to 
		// ConstantExpr
		DesignatorFixer fixer;
		ret = ret->acceptMutator( fixer );
	} // if

	return ret;
}

void DesignatorNode::printOneLine( std::ostream &os, int indent ) const {
	if ( get_argName() ) {
		if ( isArrayIndex ) {
			os << "[";
			get_argName()->printOneLine( os, indent );
			os << "]";
		} else {
			os << ".";
			get_argName()->printOneLine( os, indent );
		}
	} // if
}

void DesignatorNode::print( std::ostream &os, int indent ) const {
	if ( get_argName() ) {
		if ( isArrayIndex ) {
			os << "[";
			get_argName()->print( os, indent );
			os << "]";
		} else {
			os << ".";
			get_argName()->print( os, indent );
		}
	} // if
}

//##############################################################################

OperatorNode::OperatorNode( Type t ) : type( t ) {}

OperatorNode::OperatorNode( const OperatorNode &other ) : ExpressionNode( other ), type( other.type ) {
}

OperatorNode::~OperatorNode() {}

OperatorNode::Type OperatorNode::get_type( void ) const{
	return type;
}

void OperatorNode::printOneLine( std::ostream &os, int indent ) const {
	printDesignation( os );
	os << OpName[ type ] << ' ';
}

void OperatorNode::print( std::ostream &os, int indent ) const{
	printDesignation( os );
	os << string( indent, ' ' ) << "Operator: " << OpName[type] << endl;
	return;
}

const char *OperatorNode::get_typename( void ) const{
	return OpName[ type ];
}

const char *OperatorNode::OpName[] = {
	"TupleC",  "Comma", "TupleFieldSel",// "TuplePFieldSel", //n-adic
	// triadic
	"Cond",   "NCond",
	// diadic
	"SizeOf",     "AlignOf", "Attr", "CompLit", "Plus",    "Minus",   "Mul",     "Div",     "Mod",      "Or",
	"And",       "BitOr",   "BitAnd",  "Xor",     "Cast",    "LShift",  "RShift",  "LThan",   "GThan",
	"LEThan",    "GEThan", "Eq",      "Neq",     "Assign",  "MulAssn", "DivAssn", "ModAssn", "PlusAssn",
	"MinusAssn", "LSAssn", "RSAssn",  "AndAssn", "ERAssn",  "OrAssn",  "Index",   "FieldSel","PFieldSel",
	"Range",
	// monadic
	"UnPlus", "UnMinus", "AddressOf", "PointTo", "Neg", "BitNeg", "Incr", "IncrPost", "Decr", "DecrPost", "LabelAddress"
};

//##############################################################################

CompositeExprNode::CompositeExprNode() : ExpressionNode(), function( 0 ), arguments( 0 ) {
}

CompositeExprNode::CompositeExprNode( const string *name_ ) : ExpressionNode( name_ ), function( 0 ), arguments( 0 ) {
}

CompositeExprNode::CompositeExprNode( ExpressionNode *f, ExpressionNode *args ):
	function( f ), arguments( args ) {
}

CompositeExprNode::CompositeExprNode( ExpressionNode *f, ExpressionNode *arg1, ExpressionNode *arg2):
	function( f ), arguments( arg1 ) {
	arguments->set_link( arg2 );
}

CompositeExprNode::CompositeExprNode( const CompositeExprNode &other ) : ExpressionNode( other ), function( maybeClone( other.function ) ) {
	ParseNode *cur = other.arguments;
	while ( cur ) {
		if ( arguments ) {
			arguments->set_link( cur->clone() );
		} else {
			arguments = ( ExpressionNode*)cur->clone();
		} // if
		cur = cur->get_link();
	}
}

CompositeExprNode::~CompositeExprNode() {
	delete function;
	delete arguments;
}

// the names that users use to define operator functions
static const char *opFuncName[] = {
	"",		"",		"",
	"",		"",
	//diadic
	"",		"",		"",		"",		"?+?",		"?-?",	"?*?",	"?/?",	"?%?",	"",		 "",
	"?|?",		"?&?",		"?^?",	"",		"?<<?",	"?>>?",	"?<?",	"?>?",	"?<=?",
	"?>=?",		"?==?",		"?!=?",	"?=?",	"?*=?",	"?/=?",	"?%=?",	"?+=?",	"?-=?",
	"?<<=?",	"?>>=?",	"?&=?",	"?^=?",	"?|=?",	"?[?]",	"",		"",		"Range",
	//monadic
	"+?",		"-?",		"",		"*?",	"!?",	"~?",	"++?",	"?++",	"--?",	"?--",	"&&"
};

#include "utility.h"

Expression *CompositeExprNode::build() const {
	OperatorNode *op;
	std::list<Expression *> args;

	buildList( get_args(), args );

	if ( ! ( op = dynamic_cast<OperatorNode *>( function ) ) ) { // function as opposed to operator
		return new UntypedExpr( function->build(), args, maybeBuild< Expression >( get_argName() ));
	} // if

	switch ( op->get_type()) {
	  case OperatorNode::Incr:
	  case OperatorNode::Decr:
	  case OperatorNode::IncrPost:
	  case OperatorNode::DecrPost:
	  case OperatorNode::Assign:
	  case OperatorNode::MulAssn:
	  case OperatorNode::DivAssn:
	  case OperatorNode::ModAssn:
	  case OperatorNode::PlusAssn:
	  case OperatorNode::MinusAssn:
	  case OperatorNode::LSAssn:
	  case OperatorNode::RSAssn:
	  case OperatorNode::AndAssn:
	  case OperatorNode::ERAssn:
	  case OperatorNode::OrAssn:
		// the rewrite rules for these expressions specify that the first argument has its address taken
		assert( ! args.empty() );
		args.front() = new AddressExpr( args.front() );
		break;
	  default:
		/* do nothing */
		;
	}

	switch ( op->get_type() ) {
	  case OperatorNode::Incr:
	  case OperatorNode::Decr:
	  case OperatorNode::IncrPost:
	  case OperatorNode::DecrPost:
	  case OperatorNode::Assign:
	  case OperatorNode::MulAssn:
	  case OperatorNode::DivAssn:
	  case OperatorNode::ModAssn:
	  case OperatorNode::PlusAssn:
	  case OperatorNode::MinusAssn:
	  case OperatorNode::LSAssn:
	  case OperatorNode::RSAssn:
	  case OperatorNode::AndAssn:
	  case OperatorNode::ERAssn:
	  case OperatorNode::OrAssn:
	  case OperatorNode::Plus:
	  case OperatorNode::Minus:
	  case OperatorNode::Mul:
	  case OperatorNode::Div:
	  case OperatorNode::Mod:
	  case OperatorNode::BitOr:
	  case OperatorNode::BitAnd:
	  case OperatorNode::Xor:
	  case OperatorNode::LShift:
	  case OperatorNode::RShift:
	  case OperatorNode::LThan:
	  case OperatorNode::GThan:
	  case OperatorNode::LEThan:
	  case OperatorNode::GEThan:
	  case OperatorNode::Eq:
	  case OperatorNode::Neq:
	  case OperatorNode::Index:
	  case OperatorNode::Range:
	  case OperatorNode::UnPlus:
	  case OperatorNode::UnMinus:
	  case OperatorNode::PointTo:
	  case OperatorNode::Neg:
	  case OperatorNode::BitNeg:
	  case OperatorNode::LabelAddress:
		return new UntypedExpr( new NameExpr( opFuncName[ op->get_type() ] ), args );
	  case OperatorNode::AddressOf:
		assert( args.size() == 1 );
		assert( args.front() );

		return new AddressExpr( args.front() );
	  case OperatorNode::Cast:
		{
			TypeValueNode * arg = dynamic_cast<TypeValueNode *>( get_args());
			assert( arg );

			DeclarationNode *decl_node = arg->get_decl();
			ExpressionNode *expr_node = dynamic_cast<ExpressionNode *>( arg->get_link());

			Type *targetType = decl_node->buildType();
			if ( dynamic_cast< VoidType* >( targetType ) ) {
				delete targetType;
				return new CastExpr( expr_node->build(), maybeBuild< Expression >( get_argName() ) );
			} else {
				return new CastExpr( expr_node->build(),targetType, maybeBuild< Expression >( get_argName() ) );
			} // if
		}
	  case OperatorNode::FieldSel:
		{
			assert( args.size() == 2 );

			NameExpr *member = dynamic_cast<NameExpr *>( args.back());
			// TupleExpr *memberTup = dynamic_cast<TupleExpr *>( args.back());

			if ( member != 0 ) {
				UntypedMemberExpr *ret = new UntypedMemberExpr( member->get_name(), args.front());
				delete member;
				return ret;
				/* else if ( memberTup != 0 )
				   {
				   UntypedMemberExpr *ret = new UntypedMemberExpr( memberTup->get_name(), args.front());
				   delete member;
				   return ret;
				   } */
			} else
				assert( false );
		}
	  case OperatorNode::PFieldSel:
		{
			assert( args.size() == 2 );

			NameExpr *member = dynamic_cast<NameExpr *>( args.back());  // modify for Tuples   xxx
			assert( member != 0 );

			UntypedExpr *deref = new UntypedExpr( new NameExpr( "*?" ) );
			deref->get_args().push_back( args.front() );

			UntypedMemberExpr *ret = new UntypedMemberExpr( member->get_name(), deref );
			delete member;
			return ret;
		}
	  case OperatorNode::AlignOf:
	  case OperatorNode::SizeOf:
		{
/// 	bool isSizeOf = ( op->get_type() == OperatorNode::SizeOf );

			if ( TypeValueNode * arg = dynamic_cast<TypeValueNode *>( get_args()) ) {
				return new SizeofExpr( arg->get_decl()->buildType());
			} else {
				return new SizeofExpr( args.front());
			} // if
		}
	  case OperatorNode::Attr:
		{
			VarRefNode *var = dynamic_cast<VarRefNode *>( get_args());
			assert( var );
			if ( ! get_args()->get_link() ) {
				return new AttrExpr( var->build(), ( Expression*)0);
			} else if ( TypeValueNode * arg = dynamic_cast<TypeValueNode *>( get_args()->get_link()) ) {
				return new AttrExpr( var->build(), arg->get_decl()->buildType());
			} else {
				return new AttrExpr( var->build(), args.back());
			} // if
		}
	  case OperatorNode::CompLit:
		throw UnimplementedError( "C99 compound literals" );
		// the short-circuited operators
	  case OperatorNode::Or:
	  case OperatorNode::And:
		assert( args.size() == 2);
		return new LogicalExpr( notZeroExpr( args.front() ), notZeroExpr( args.back() ), ( op->get_type() == OperatorNode::And ) );
	  case OperatorNode::Cond:
		{
			assert( args.size() == 3);
			std::list< Expression * >::const_iterator i = args.begin();
			Expression *arg1 = notZeroExpr( *i++ );
			Expression *arg2 = *i++;
			Expression *arg3 = *i++;
			return new ConditionalExpr( arg1, arg2, arg3 );
		}
	  case OperatorNode::NCond:
		throw UnimplementedError( "GNU 2-argument conditional expression" );
	  case OperatorNode::Comma:
		{
			assert( args.size() == 2);
			std::list< Expression * >::const_iterator i = args.begin();
			Expression *ret = *i++;
			while ( i != args.end() ) {
				ret = new CommaExpr( ret, *i++ );
			}
			return ret;
		}
		// Tuples
	  case OperatorNode::TupleC:
		{
			TupleExpr *ret = new TupleExpr();
			std::copy( args.begin(), args.end(), back_inserter( ret->get_exprs() ) );
			return ret;
		}
	  default:
		// shouldn't happen
		return 0;
	} // switch
}

void CompositeExprNode::printOneLine( std::ostream &os, int indent ) const {
	printDesignation( os );
	os << "( ";
	function->printOneLine( os, indent );
	for ( ExpressionNode *cur = arguments; cur != 0; cur = dynamic_cast< ExpressionNode* >( cur->get_link() ) ) {
		cur->printOneLine( os, indent );
	}
	os << ") ";
}

void CompositeExprNode::print( std::ostream &os, int indent ) const {
	printDesignation( os );
	os << string( indent, ' ' ) << "Application of: " << endl;
	function->print( os, indent + ParseNode::indent_by );

	os << string( indent, ' ' ) ;
	if ( arguments ) {
		os << "... on arguments: " << endl;
		arguments->printList( os, indent + ParseNode::indent_by );
	} else
		os << "... on no arguments: " << endl;
}

void CompositeExprNode::set_function( ExpressionNode *f ) {
	function = f;
}

void CompositeExprNode::set_args( ExpressionNode *args ) {
	arguments = args;
}

ExpressionNode *CompositeExprNode::get_function( void ) const {
	return function;
}

ExpressionNode *CompositeExprNode::get_args( void ) const {
	return arguments;
}

void CompositeExprNode::add_arg( ExpressionNode *arg ) {
	if ( arguments )
		arguments->set_link( arg );
	else
		set_args( arg );
}

//##############################################################################

Expression *AsmExprNode::build() const {
	return new AsmExpr( maybeBuild< Expression >( inout ), (ConstantExpr *)constraint->build(), operand->build() );
}

void AsmExprNode::print( std::ostream &os, int indent ) const {
	os << string( indent, ' ' ) << "Assembler Expression:" << endl;
	if ( inout ) {
		os << string( indent, ' ' ) << "inout: " << std::endl;
		inout->print( os, indent + 2 );
	} // if
	if ( constraint ) {
		os << string( indent, ' ' ) << "constraint: " << std::endl;
		constraint->print( os, indent + 2 );
	} // if
	if ( operand ) {
		os << string( indent, ' ' ) << "operand: " << std::endl;
		operand->print( os, indent + 2 );
	} // if
}

void AsmExprNode::printOneLine( std::ostream &os, int indent ) const {
	printDesignation( os );
	os << "( ";
	if ( inout ) inout->printOneLine( os, indent + 2 );
	os << ", ";
	if ( constraint ) constraint->printOneLine( os, indent + 2 );
	os << ", ";
	if ( operand ) operand->printOneLine( os, indent + 2 );
	os << ") ";
}

//##############################################################################

void LabelNode::print( std::ostream &os, int indent ) const {}

void LabelNode::printOneLine( std::ostream &os, int indent ) const {}

//##############################################################################

CommaExprNode::CommaExprNode(): CompositeExprNode( new OperatorNode( OperatorNode::Comma )) {}

CommaExprNode::CommaExprNode( ExpressionNode *exp ) : CompositeExprNode( new OperatorNode( OperatorNode::Comma ), exp ) {
}

CommaExprNode::CommaExprNode( ExpressionNode *exp1, ExpressionNode *exp2) : CompositeExprNode( new OperatorNode( OperatorNode::Comma ), exp1, exp2) {
}

CommaExprNode *CommaExprNode::add_to_list( ExpressionNode *exp ) {
	add_arg( exp );

	return this;
}

CommaExprNode::CommaExprNode( const CommaExprNode &other ) : CompositeExprNode( other ) {
}

//##############################################################################

ValofExprNode::ValofExprNode( StatementNode *s ): body( s ) {}

ValofExprNode::ValofExprNode( const ValofExprNode &other ) : ExpressionNode( other ), body( maybeClone( body ) ) {
}

ValofExprNode::~ValofExprNode() {
	delete body;
}

void ValofExprNode::print( std::ostream &os, int indent ) const {
	printDesignation( os );
	os << string( indent, ' ' ) << "Valof Expression:" << std::endl;
	get_body()->print( os, indent + 4);
}

void ValofExprNode::printOneLine( std::ostream &, int indent ) const {
	assert( false );
}

Expression *ValofExprNode::build() const {
	return new UntypedValofExpr ( get_body()->build(), maybeBuild< Expression >( get_argName() ) );
}

//##############################################################################

ForCtlExprNode::ForCtlExprNode( ParseNode *init_, ExpressionNode *cond, ExpressionNode *incr ) throw ( SemanticError ) : condition( cond ), change( incr ) {
	if ( init_ == 0 )
		init = 0;
	else {
		DeclarationNode *decl;
		ExpressionNode *exp;

		if (( decl = dynamic_cast<DeclarationNode *>(init_) ) != 0)
			init = new StatementNode( decl );
		else if (( exp = dynamic_cast<ExpressionNode *>( init_)) != 0)
			init = new StatementNode( StatementNode::Exp, exp );
		else
			throw SemanticError("Error in for control expression");
	}
}

ForCtlExprNode::ForCtlExprNode( const ForCtlExprNode &other )
	: ExpressionNode( other ), init( maybeClone( other.init ) ), condition( maybeClone( other.condition ) ), change( maybeClone( other.change ) ) {
}

ForCtlExprNode::~ForCtlExprNode() {
	delete init;
	delete condition;
	delete change;
}

Expression *ForCtlExprNode::build() const {
	// this shouldn't be used!
	assert( false );
	return 0;
}

void ForCtlExprNode::print( std::ostream &os, int indent ) const{
	os << string( indent,' ' ) << "For Control Expression -- :" << endl;

	os << string( indent + 2, ' ' ) << "initialization:" << endl;
	if ( init != 0 )
		init->printList( os, indent + 4 );

	os << string( indent + 2, ' ' ) << "condition: " << endl;
	if ( condition != 0 )
		condition->print( os, indent + 4 );
	os << string( indent + 2, ' ' ) << "increment: " << endl;
	if ( change != 0 )
		change->print( os, indent + 4 );
}

void ForCtlExprNode::printOneLine( std::ostream &, int indent ) const {
	assert( false );
}

//##############################################################################

TypeValueNode::TypeValueNode( DeclarationNode *decl ) : decl( decl ) {
}

TypeValueNode::TypeValueNode( const TypeValueNode &other ) : ExpressionNode( other ), decl( maybeClone( other.decl ) ) {
}

Expression *TypeValueNode::build() const {
	return new TypeExpr( decl->buildType() );
}

void TypeValueNode::print( std::ostream &os, int indent ) const {
	os << std::string( indent, ' ' ) << "Type:";
	get_decl()->print( os, indent + 2);
}

void TypeValueNode::printOneLine( std::ostream &os, int indent ) const {
	os << "Type:";
	get_decl()->print( os, indent + 2);
}

ExpressionNode *flattenCommas( ExpressionNode *list ) {
	if ( CompositeExprNode *composite = dynamic_cast< CompositeExprNode * >( list ) ) {
		OperatorNode *op;
		if ( ( op = dynamic_cast< OperatorNode * >( composite->get_function() )) && ( op->get_type() == OperatorNode::Comma ) ) {
			if ( ExpressionNode *next = dynamic_cast< ExpressionNode * >( list->get_link() ) )
				composite->add_arg( next );
			return flattenCommas( composite->get_args() );
		} // if
	} // if

	if ( ExpressionNode *next = dynamic_cast< ExpressionNode * >( list->get_link() ) )
		list->set_next( flattenCommas( next ) );

	return list;
}

ExpressionNode *tupleContents( ExpressionNode *tuple ) {
	if ( CompositeExprNode *composite = dynamic_cast< CompositeExprNode * >( tuple ) ) {
		OperatorNode *op = 0;
		if ( ( op = dynamic_cast< OperatorNode * >( composite->get_function() )) && ( op->get_type() == OperatorNode::TupleC ) )
			return composite->get_args();
	} // if
	return tuple;
}

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