//
// 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.
//
// OperatorTable.cc --
//
// Author           : Richard C. Bilson
// Created On       : Mon May 18 07:44:20 2015
// Last Modified By : Peter A. Buhr
// Last Modified On : Sat Jul 15 17:12:22 2017
// Update Count     : 15
//

#include <algorithm>  // for any_of
#include <map>        // for map, _Rb_tree_const_iterator, map<>::const_iterator
#include <utility>    // for pair

#include "OperatorTable.h"
#include "Common/utility.h"

namespace CodeGen {
	namespace {
		const OperatorInfo tableValues[] = {
			{	"?[?]",		"",		"_operator_index",				OT_INDEX			},
			{	"?{}",		"=",	"_constructor",					OT_CTOR				},
			{	"^?{}",		"",		"_destructor",					OT_DTOR				},
			{	"?()",		"",		"_operator_call",				OT_CALL				},
			{	"?++",		"++",	"_operator_postincr",			OT_POSTFIXASSIGN	},
			{	"?--",		"--",	"_operator_postdecr",			OT_POSTFIXASSIGN	},
			{	"*?",		"*",	"_operator_deref",				OT_PREFIX			},
			{	"+?",		"+",	"_operator_unaryplus",			OT_PREFIX			},
			{	"-?",		"-",	"_operator_unaryminus",			OT_PREFIX			},
			{	"~?",		"~",	"_operator_bitnot",				OT_PREFIX			},
			{	"!?",		"!",	"_operator_lognot",				OT_PREFIX			},
			{	"++?",		"++",	"_operator_preincr",			OT_PREFIXASSIGN		},
			{	"--?",		"--",	"_operator_predecr",			OT_PREFIXASSIGN		},
			{	"?\\?",		"\\",	"_operator_exponential",		OT_INFIX			},
			{	"?*?",		"*",	"_operator_multiply",			OT_INFIX			},
			{	"?/?",		"/",	"_operator_divide",				OT_INFIX			},
			{	"?%?",		"%",	"_operator_modulus",			OT_INFIX			},
			{	"?+?",		"+",	"_operator_add",				OT_INFIX			},
			{	"?-?",		"-",	"_operator_subtract",			OT_INFIX			},
			{	"?<<?",		"<<",	"_operator_shiftleft",			OT_INFIX			},
			{	"?>>?",		">>",	"_operator_shiftright",			OT_INFIX			},
			{	"?<?",		"<",	"_operator_less",				OT_INFIX			},
			{	"?>?",		">",	"_operator_greater",			OT_INFIX			},
			{	"?<=?",		"<=",	"_operator_lessequal",			OT_INFIX			},
			{	"?>=?",		">=",	"_operator_greaterequal",		OT_INFIX			},
			{	"?==?",		"==",	"_operator_equal",				OT_INFIX			},
			{	"?!=?",		"!=",	"_operator_notequal",			OT_INFIX			},
			{	"?&?",		"&",	"_operator_bitand",				OT_INFIX			},
			{	"?^?",		"^",	"_operator_bitxor",				OT_INFIX			},
			{	"?|?",		"|",	"_operator_bitor",				OT_INFIX			},
			{	"?=?",		"=",	"_operator_assign",				OT_INFIXASSIGN		},
			{	"?\\=?",	"\\=",	"_operator_expassign",			OT_INFIXASSIGN		},
			{	"?*=?",		"*=",	"_operator_multassign",			OT_INFIXASSIGN		},
			{	"?/=?",		"/=",	"_operator_divassign",			OT_INFIXASSIGN		},
			{	"?%=?",		"%=",	"_operator_modassign",			OT_INFIXASSIGN		},
			{	"?+=?",		"+=",	"_operator_addassign",			OT_INFIXASSIGN		},
			{	"?-=?",		"-=",	"_operator_subassign",			OT_INFIXASSIGN		},
			{	"?<<=?",	"<<=",	"_operator_shiftleftassign",	OT_INFIXASSIGN		},
			{	"?>>=?",	">>=",	"_operator_shiftrightassign",	OT_INFIXASSIGN		},
			{	"?&=?",		"&=",	"_operator_bitandassign",		OT_INFIXASSIGN		},
			{	"?^=?",		"^=",	"_operator_bitxorassign",		OT_INFIXASSIGN		},
			{	"?|=?",		"|=",	"_operator_bitorassign",		OT_INFIXASSIGN		},
		};

		const int numOps = sizeof( tableValues ) / sizeof( OperatorInfo );

		std::map< std::string, OperatorInfo > table;

		void initialize() {
			for ( int i = 0; i < numOps; ++i ) {
				table[ tableValues[i].inputName ] = tableValues[i];
			} // for
		}
	} // namespace

	bool operatorLookup( const std::string & funcName, OperatorInfo & info ) {
		static bool init = false;
		if ( ! init ) {
			initialize();
		} // if

		std::map< std::string, OperatorInfo >::const_iterator i = table.find( funcName );
		if ( i == table.end() ) {
			if ( isPrefix( funcName, "?`" ) ) {
				// handle literal suffixes, which are user-defined postfix operators
				info.inputName = funcName;
				info.symbol = funcName.substr(2);
				info.outputName = toString( "__operator_literal_", info.symbol );
				info.type = OT_POSTFIX;
				return true;
			}
			return false;
		} else {
			info = i->second;
			return true;
		} // if
	}

	bool isOperator( const std::string & funcName ) {
		OperatorInfo info;
		return operatorLookup( funcName, info );
	}

	/// determines if a given function name is one of the operator types between [begin, end)
	template<typename Iterator>
	bool isOperatorType( const std::string & funcName, Iterator begin, Iterator end ) {
		OperatorInfo info;
		if ( operatorLookup( funcName, info ) ) {
			return std::find( begin, end, info.type ) != end;
		}
		return false;
	}

	bool isConstructor( const std::string & funcName ) {
		static OperatorType types[] = { OT_CTOR };
		return isOperatorType( funcName, std::begin(types), std::end(types) );
	}

	bool isDestructor( const std::string & funcName ) {
		static OperatorType types[] = { OT_DTOR };
		return isOperatorType( funcName, std::begin(types), std::end(types) );
	}

	bool isAssignment( const std::string & funcName ) {
		static OperatorType types[] = { OT_PREFIXASSIGN, OT_POSTFIXASSIGN, OT_INFIXASSIGN };
		return isOperatorType( funcName, std::begin(types), std::end(types) );
	}

	bool isCtorDtor( const std::string & funcName ) {
		static OperatorType types[] = { OT_CTOR, OT_DTOR };
		return isOperatorType( funcName, std::begin(types), std::end(types) );
	}

	bool isCtorDtorAssign( const std::string & funcName ) {
		static OperatorType types[] = { OT_CTOR, OT_DTOR, OT_PREFIXASSIGN, OT_POSTFIXASSIGN, OT_INFIXASSIGN };
		return isOperatorType( funcName, std::begin(types), std::end(types) );
	}
} // namespace CodeGen

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