/* $Id$ 
 *
 * Symbol: A symbol refers to a named entity.
 *
 * Copyright (C) 2007-2009 FAUmachine Team <info@faumachine.org>.
 * This program is free software. You can redistribute it and/or modify it
 * under the terms of the GNU General Public License, either version 2 of
 * the License, or (at your option) any later version. See COPYING.
 */


#ifndef __SYMBOL_HPP_INCLUDED
#define __SYMBOL_HPP_INCLUDED

#include <string>
#include <ostream>
#include "frontend/ast/SymbolDeclaration.hpp"
#include "frontend/ast/SubtypeIndication.hpp"

namespace ast {

/** type of the symbol */
enum symType {
	/** symbol is an Entity */
	SYMBOL_ENTITY = 	1 << 0,
	/** symbol is a procedure declaration */
	SYMBOL_PROCEDURE = 	1 << 1,
	/** symbol is a function declaration */
	SYMBOL_FUNCTION = 	1 << 2,
	/** symbol is a signal declaration */
	SYMBOL_SIGNAL = 	1 << 3,	
	/** symbol is a variable or constant declaration */
	SYMBOL_VARIABLE = 	1 << 4,
	/** symbol is a type declaration */
	SYMBOL_TYPE = 		1 << 5,
	/** symbol is a unit of a physical unit */
	SYMBOL_UNIT = 		1 << 6,
	/** symbol is an element of a record type */
	SYMBOL_ELEMENT = 	1 << 7,
	/** symbol is an attribute declaration */
	SYMBOL_ATTRIBUTE = 	1 << 8,
	/** symbol is an Architecture */
	SYMBOL_ARCHITECTURE = 	1 << 9,
	/** symbol is a Process */
	SYMBOL_PROCESS = 	1 << 10,
	/** symbol is a Loop label */
	SYMBOL_LOOP = 		1 << 11,
	/** symbol denotes a library */
	SYMBOL_LIBRARY = 	1 << 12,
	/** symbol denotes a package */
	SYMBOL_PACKAGE = 	1 << 13,
	/** pseudo symbol denoting "all" token */
	SYMBOL_ALL = 		1 << 14,
	/** symbol is a paramter */
	SYMBOL_PARAMETER = 	1 << 15,
	/** symbol is a port */
	SYMBOL_PORT = 		1 << 16
};

// forward declaration of DeclarativeRegion
class DeclarativeRegion;

//! symbol entry in the SymbolTable.
/** The class Symbol represents one entry in the SymbolTable.
 *  TODO path of symbol
 */
class Symbol {
public:
	//! c'tor
	/** @param sname name of the Symbol
	 *  @param stype type of the Symbol.
	 *  @param decl reference to declaration.
	 *  @param reg DeclarativeRegion the Symbol belongs to.
	 */
	Symbol(
		const std::string* sname, 
		enum symType stype,
		DeclarativeRegion* reg,
		SymbolDeclaration& decl
		) : 	name(sname), 
			type(stype), 
			declaration(decl), 
			region(reg) {}

	//! d'tor
	~Symbol() {
		SymbolDeclaration* decl = &(this->declaration);
		util::MiscUtil::terminate(decl);
	}

	/** check if other is a Homograph of this. */
	bool isHomograph(const Symbol& other) const;

	/** name of the symbol */
	const std::string* name;

	/** type of the symbol */
	enum symType type;

	/** referring declaration of the Symbol. */
	SymbolDeclaration &declaration;

	/** possibly asssociated DeclarativeRegion of the symbol,
	 *  NULL possible. */
	DeclarativeRegion *region;

	/** write the Symbol to stream.
	 *  @param stream write the symbol to this stream
	 */
	void put(std::ostream& stream) const;

private:
	/** does the other symbol, which points to a callable have the
	 *  same parameter type profile (LRM 2.3)?
	 *
	 *  @param other other symbol that points to a Callable.
	 *  @return true, if the other symbol has the same parameter type
	 *          profile, false otherwise.
	 */
	bool sameParameterProfile(const Symbol& other) const;


	/** does the other symbol, which points to a FunctionDeclaration
	 *  as well as this have the same result type profile?
	 *
	 *  @param other other symbol that points to a FunctionDeclaration.
	 *  @return true if the result profile match, false otherwise.
	 */
	bool sameResultProfile(const Symbol& other) const;

	/** are the base types of given SubtypeIndication's equal?
	 *  Note: both SubtypeIndications need to have been resolved already.
	 *
	 *  @param s1 first SubtypeIndication.
	 *  @param s2 second SubtypeIndication.
	 *  @return true if the base types are identical, false otherwise.
	 */
	static bool baseTypeEqual(
		const SubtypeIndication& s1,
		const SubtypeIndication& s2
	);

};

/** write a symbol to a stream.
 *  @param stream stream to which the symbol should get written to.
 *  @param sym symbol that should get written.
 *  @return modified stream.
 */
std::ostream& operator<<(std::ostream& stream, const Symbol& sym);


}; /* namespace ast */

#endif /* __SYMBOL_HPP_INCLUDED */
