//
// 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 : Sat Mar  4 06:58:47 2017
// Update Count     : 509
//

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

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

using namespace std;

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

// 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.

Type::Qualifiers emptyQualifiers;				// no qualifiers on constants

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 checkD( char c ) { return c == 'd' || c == 'D'; }
static inline bool checkI( char c ) { return c == 'i' || c == 'I'; }
static inline bool checkX( char c ) { return c == 'x' || c == 'X'; }

Expression *build_constantInteger( const std::string & str ) {
	static const BasicType::Kind kind[2][3] = {
		{ BasicType::SignedInt, BasicType::LongSignedInt, BasicType::LongLongSignedInt },
		{ BasicType::UnsignedInt, BasicType::LongUnsignedInt, BasicType::LongLongUnsignedInt },
	};
	bool dec = true, Unsigned = false;					// decimal, unsigned constant
	int size;											// 0 => int, 1 => long, 2 => long long
	unsigned long long v;								// converted integral value
	size_t last = str.length() - 1;						// last character of constant

	if ( str[0] == '0' ) {								// octal/hex constant ?
		dec = false;
		if ( last != 0 && checkX( str[1] ) ) {			// hex constant ?
			sscanf( (char *)str.c_str(), "%llx", &v );
			//printf( "%llx %llu\n", v, v );
		} else {										// octal constant
			sscanf( (char *)str.c_str(), "%llo", &v );
			//printf( "%llo %llu\n", v, v );
		} // if
	} else {											// decimal constant ?
		sscanf( (char *)str.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( str[last] ) ) {						// suffix 'u' ?
		Unsigned = true;
		if ( last > 0 && checkL( str[last - 1] ) ) {	// suffix 'l' ?
			size = 1;
			if ( last > 1 && checkL( str[last - 2] ) ) { // suffix 'll' ?
				size = 2;
			} // if
		} // if
	} else if ( checkL( str[ last ] ) ) {				// suffix 'l' ?
		size = 1;
		if ( last > 0 && checkL( str[last - 1] ) ) {	// suffix 'll' ?
			size = 2;
			if ( last > 1 && checkU( str[last - 2] ) ) { // suffix 'u' ?
				Unsigned = true;
			} // if
		} else {
			if ( last > 0 && checkU( str[last - 1] ) ) { // suffix 'u' ?
				Unsigned = true;
			} // if
		} // if
	} // if

	Expression * ret = new ConstantExpr( Constant( new BasicType( emptyQualifiers, kind[Unsigned][size] ), str ) );
	delete &str;										// created by lex
	return ret;
} // build_constantInteger

Expression *build_constantFloat( const std::string & str ) {
	static const BasicType::Kind kind[2][3] = {
		{ BasicType::Float, BasicType::Double, BasicType::LongDouble },
		{ BasicType::FloatComplex, BasicType::DoubleComplex, BasicType::LongDoubleComplex },
	};

	bool complx = false;								// real, complex
	int size = 1;										// 0 => float, 1 => double (default), 2 => long double
	// floating-point constant has minimum of 2 characters: 1. or .1
	size_t last = str.length() - 1;

	if ( checkI( str[last] ) ) {						// imaginary ?
		complx = true;
		last -= 1;										// backup one character
	} // if

	if ( checkF( str[last] ) ) {						// float ?
		size = 0;
	} else if ( checkD( str[last] ) ) {					// double ?
		size = 1;
	} else if ( checkL( str[last] ) ) {					// long double ?
		size = 2;
	} // if
	if ( ! complx && checkI( str[last - 1] ) ) {		// imaginary ?
		complx = true;
	} // if

	Expression * ret = new ConstantExpr( Constant( new BasicType( emptyQualifiers, kind[complx][size] ), str ) );
	delete &str;										// created by lex
	return ret;
} // build_constantFloat

Expression *build_constantChar( const std::string & str ) {
	Expression * ret = new ConstantExpr( Constant( new BasicType( emptyQualifiers, BasicType::Char ), str ) );
	delete &str;										// created by lex
	return ret;
} // build_constantChar

ConstantExpr *build_constantStr( const std::string & str ) {
	// string should probably be a primitive type
	ArrayType *at = new ArrayType( emptyQualifiers, new BasicType( emptyQualifiers, BasicType::Char ),
				new ConstantExpr( Constant( new BasicType( emptyQualifiers, BasicType::UnsignedInt ),
											toString( str.size()+1-2 ) ) ),  // +1 for '\0' and -2 for '"'
								   false, false );
	ConstantExpr * ret = new ConstantExpr( Constant( at, str ) );
	delete &str;										// created by lex
	return ret;
} // build_constantStr

Expression *build_constantZeroOne( const std::string & str ) {
	Expression * ret = new ConstantExpr( Constant( str == "0" ? (Type *)new ZeroType( emptyQualifiers ) : (Type*)new OneType( emptyQualifiers ), str ) );
	delete &str;										// created by lex
	return ret;
} // build_constantChar

Expression * build_field_name_FLOATINGconstant( const std::string & str ) {
	// str is of the form A.B -> separate at the . and return member expression
	int a, b;
	char dot;
	std::stringstream ss( str );
	ss >> a >> dot >> b;
	UntypedMemberExpr * ret = new UntypedMemberExpr(
		new ConstantExpr( Constant( new BasicType( emptyQualifiers, BasicType::SignedInt ), toString( b ) ) ),
		new ConstantExpr( Constant( new BasicType( emptyQualifiers, BasicType::SignedInt ), toString( a ) ) ) );
	delete &str;
	return ret;
} // build_field_name_FLOATINGconstant

Expression * make_field_name_fraction_constants( Expression * fieldName, Expression * fracts ) {
	if ( fracts ) {
		if ( UntypedMemberExpr * memberExpr = dynamic_cast< UntypedMemberExpr * >( fracts ) ) {
			memberExpr->set_member( make_field_name_fraction_constants( fieldName, memberExpr->get_aggregate() ) );
			return memberExpr;
		} else {
			return new UntypedMemberExpr( fracts, fieldName );
		}
	}
	return fieldName;
} // make_field_name_fraction_constants

Expression * build_field_name_fraction_constants( Expression * fieldName, ExpressionNode * fracts ) {
	return make_field_name_fraction_constants( fieldName, maybeMoveBuild< Expression >( fracts ) );
} // build_field_name_fraction_constants

Expression * build_field_name_REALFRACTIONconstant( const std::string & str ) {
	assert( str[0] == '.' );
	Expression * ret = build_constantInteger( *new std::string( str.substr(1) ) );
	delete &str;
	return ret;
} // build_field_name_REALFRACTIONconstant

Expression * build_field_name_REALDECIMALconstant( const std::string & str ) {
	assert( str[str.size()-1] == '.' );
	Expression * ret = build_constantInteger( *new std::string( str.substr( 0, str.size()-1 ) ) );
	delete &str;
	return ret;
} // build_field_name_REALDECIMALconstant

NameExpr * build_varref( const string *name, bool labelp ) {
	NameExpr *expr = new NameExpr( *name, nullptr );
	delete name;
	return expr;
}

static const char *OperName[] = {
	// diadic
	"SizeOf", "AlignOf", "OffsetOf", "?+?", "?-?", "?*?", "?/?", "?%?", "||", "&&",
	"?|?", "?&?", "?^?", "Cast", "?<<?", "?>>?", "?<?", "?>?", "?<=?", "?>=?", "?==?", "?!=?",
	"?=?", "?@=?", "?*=?", "?/=?", "?%=?", "?+=?", "?-=?", "?<<=?", "?>>=?", "?&=?", "?^=?", "?|=?",
	"?[?]", "...",
	// monadic
	"+?", "-?", "AddressOf", "*?", "!?", "~?", "++?", "?++", "--?", "?--", "&&"
};

Expression *build_cast( DeclarationNode *decl_node, ExpressionNode *expr_node ) {
	Type *targetType = maybeMoveBuildType( decl_node );
	if ( dynamic_cast< VoidType * >( targetType ) ) {
		delete targetType;
		return new CastExpr( maybeMoveBuild< Expression >(expr_node) );
	} else {
		return new CastExpr( maybeMoveBuild< Expression >(expr_node), targetType );
	} // if
}

Expression *build_fieldSel( ExpressionNode *expr_node, Expression *member ) {
	UntypedMemberExpr *ret = new UntypedMemberExpr( member, maybeMoveBuild< Expression >(expr_node) );
	return ret;
}

Expression *build_pfieldSel( ExpressionNode *expr_node, Expression *member ) {
	UntypedExpr *deref = new UntypedExpr( new NameExpr( "*?" ) );
	deref->get_args().push_back( maybeMoveBuild< Expression >(expr_node) );
	UntypedMemberExpr *ret = new UntypedMemberExpr( member, deref );
	return ret;
}

Expression *build_addressOf( ExpressionNode *expr_node ) {
		return new AddressExpr( maybeMoveBuild< Expression >(expr_node) );
}
Expression *build_sizeOfexpr( ExpressionNode *expr_node ) {
	return new SizeofExpr( maybeMoveBuild< Expression >(expr_node) );
}
Expression *build_sizeOftype( DeclarationNode *decl_node ) {
	return new SizeofExpr( maybeMoveBuildType( decl_node ) );
}
Expression *build_alignOfexpr( ExpressionNode *expr_node ) {
	return new AlignofExpr( maybeMoveBuild< Expression >(expr_node) );
}
Expression *build_alignOftype( DeclarationNode *decl_node ) {
	return new AlignofExpr( maybeMoveBuildType( decl_node) );
}
Expression *build_offsetOf( DeclarationNode *decl_node, NameExpr *member ) {
	Expression * ret = new UntypedOffsetofExpr( maybeMoveBuildType( decl_node ), member->get_name() );
	delete member;
	return ret;
}

Expression *build_and_or( ExpressionNode *expr_node1, ExpressionNode *expr_node2, bool kind ) {
	return new LogicalExpr( notZeroExpr( maybeMoveBuild< Expression >(expr_node1) ), notZeroExpr( maybeMoveBuild< Expression >(expr_node2) ), kind );
}

Expression *build_unary_val( OperKinds op, ExpressionNode *expr_node ) {
	std::list< Expression * > args;
	args.push_back( maybeMoveBuild< Expression >(expr_node) );
	return new UntypedExpr( new NameExpr( OperName[ (int)op ] ), args );
}
Expression *build_unary_ptr( OperKinds op, ExpressionNode *expr_node ) {
	std::list< Expression * > args;
	args.push_back( new AddressExpr( maybeMoveBuild< Expression >(expr_node) ) );
	return new UntypedExpr( new NameExpr( OperName[ (int)op ] ), args );
}
Expression *build_binary_val( OperKinds op, ExpressionNode *expr_node1, ExpressionNode *expr_node2 ) {
	std::list< Expression * > args;
	args.push_back( maybeMoveBuild< Expression >(expr_node1) );
	args.push_back( maybeMoveBuild< Expression >(expr_node2) );
	return new UntypedExpr( new NameExpr( OperName[ (int)op ] ), args );
}
Expression *build_binary_ptr( OperKinds op, ExpressionNode *expr_node1, ExpressionNode *expr_node2 ) {
	std::list< Expression * > args;
	args.push_back( new AddressExpr( maybeMoveBuild< Expression >(expr_node1) ) );
	args.push_back( maybeMoveBuild< Expression >(expr_node2) );
	return new UntypedExpr( new NameExpr( OperName[ (int)op ] ), args );
}

Expression *build_cond( ExpressionNode *expr_node1, ExpressionNode *expr_node2, ExpressionNode *expr_node3 ) {
	return new ConditionalExpr( notZeroExpr( maybeMoveBuild< Expression >(expr_node1) ), maybeMoveBuild< Expression >(expr_node2), maybeMoveBuild< Expression >(expr_node3) );
}

Expression *build_comma( ExpressionNode *expr_node1, ExpressionNode *expr_node2 ) {
	return new CommaExpr( maybeMoveBuild< Expression >(expr_node1), maybeMoveBuild< Expression >(expr_node2) );
}

Expression *build_attrexpr( NameExpr *var, ExpressionNode * expr_node ) {
	return new AttrExpr( var, maybeMoveBuild< Expression >(expr_node) );
}
Expression *build_attrtype( NameExpr *var, DeclarationNode * decl_node ) {
	return new AttrExpr( var, maybeMoveBuildType( decl_node ) );
}

Expression *build_tuple( ExpressionNode * expr_node ) {
	std::list< Expression * > exprs;
	buildMoveList( expr_node, exprs );
	return new UntypedTupleExpr( exprs );;
}

Expression *build_func( ExpressionNode * function, ExpressionNode * expr_node ) {
	std::list< Expression * > args;
	buildMoveList( expr_node, args );
	return new UntypedExpr( maybeMoveBuild< Expression >(function), args, nullptr );
}

Expression *build_range( ExpressionNode * low, ExpressionNode *high ) {
	return new RangeExpr( maybeMoveBuild< Expression >( low ), maybeMoveBuild< Expression >( high ) );
}

Expression *build_asmexpr( ExpressionNode *inout, ConstantExpr *constraint, ExpressionNode *operand ) {
	return new AsmExpr( maybeMoveBuild< Expression >( inout ), constraint, maybeMoveBuild< Expression >(operand) );
}

Expression *build_valexpr( StatementNode *s ) {
	return new UntypedValofExpr( maybeMoveBuild< Statement >(s), nullptr );
}
Expression *build_typevalue( DeclarationNode *decl ) {
	return new TypeExpr( maybeMoveBuildType( decl ) );
}

Expression *build_compoundLiteral( DeclarationNode *decl_node, InitializerNode *kids ) {
	Declaration * newDecl = maybeBuild< Declaration >(decl_node); // compound literal type
	if ( DeclarationWithType * newDeclWithType = dynamic_cast< DeclarationWithType * >( newDecl ) ) { // non-sue compound-literal type
		return new CompoundLiteralExpr( newDeclWithType->get_type(), maybeMoveBuild< Initializer >(kids) );
	// these types do not have associated type information
	} else if ( StructDecl * newDeclStructDecl = dynamic_cast< StructDecl * >( newDecl )  ) {
		return new CompoundLiteralExpr( new StructInstType( Type::Qualifiers(), newDeclStructDecl->get_name() ), maybeMoveBuild< Initializer >(kids) );
	} else if ( UnionDecl * newDeclUnionDecl = dynamic_cast< UnionDecl * >( newDecl )  ) {
		return new CompoundLiteralExpr( new UnionInstType( Type::Qualifiers(), newDeclUnionDecl->get_name() ), maybeMoveBuild< Initializer >(kids) );
	} else if ( EnumDecl * newDeclEnumDecl = dynamic_cast< EnumDecl * >( newDecl )  ) {
		return new CompoundLiteralExpr( new EnumInstType( Type::Qualifiers(), newDeclEnumDecl->get_name() ), maybeMoveBuild< Initializer >(kids) );
	} else {
		assert( false );
	} // if
}

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