/* $Id$ 
 *
 * RegisterBuiltins: can register builtin functions for a given type
 * declaration.
 *
 * Copyright (C) 2008-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 __REGISTER_BUILTINS_HPP_INCLUDED
#define __REGISTER_BUILTINS_HPP_INCLUDED

#include "frontend/ast/RangeConstraintType.hpp"
#include "frontend/ast/PhysicalType.hpp"
#include "frontend/ast/SubtypeIndication.hpp"
#include "frontend/ast/ConstantDeclaration.hpp"
#include "frontend/misc/SymbolTable.hpp"
#include "frontend/misc/BuiltinFunction.hpp"
#include "frontend/visitor/GCBuiltins.hpp"

namespace ast {

//! register builtins for a given TypeDeclaration
class RegisterBuiltins {
public:
	/** register type operations for the given type.
	 *  @param type Type for which builtins should get registered.
	 *  @param s reference to the SymbolTable to which the type operations
	 *         should get registered to.
	 */
	static void regTypeOps(SymbolDeclaration &type, SymbolTable &s);

private:
	/** register type operations for given type.
	 *  @param type RangeConstraintType for which builtins should get
	 *         registered.
	 */
	static void 
	registerTypeOps(RangeConstraintType &type, SymbolTable &s);

	/** register type operations for given type.
	 *  @param type RangeConstraintType for which builtins should get
	 *         registered.
	 *  @param s reference to the SymbolTable to which the type operations
	 *         should get registered to.
	 */
	static void registerTypeOps(PhysicalType &type, SymbolTable &s);

	/** register type operations for given type.
	 *  @param type ArrayType for which builtins should get
	 *         registered.
	 *  @param s reference to the SymbolTable to which the type operations
	 *         should get registered to.
	 */
	static void 
	registerTypeOps(UnconstrainedArrayType &type, SymbolTable &s);

	/** register type operations for given type.
	 *  @param type EnumerationType for which builtins should get
	 *         registered.
	 *  @param s reference to the SymbolTable to which the type operations
	 *         should get registered to.
	 */
	static void registerTypeOps(EnumerationType &type, SymbolTable &s);

	/** register type operations for given type.
	 *  @param type RecordType for which builtins should get
	 *         registered.
	 *  @param s reference to the SymbolTable to which the type operations
	 *         should get registered to.
	 */
	static void registerTypeOps(RecordType &type, SymbolTable &s);

	/** generate a SubtypeIndication from a TypeDeclaration matching
	 *  the very type.
	 *  @param type referring TypeDeclaration.
	 *  @return generated SubtypeIndication
	 */
	static SubtypeIndication* 
	generateSubtypeIndic(const TypeDeclaration &type);

	/** generate one argument of given type for a builtin operator.
	 *  @param type type of the operand.
	 *  @param s SymbolTable instance.
	 *  @return ConstantDeclaration for parameter.
	 */
	static ConstantDeclaration* 
	generateArgument(const TypeDeclaration &type, const SymbolTable &s);

	/** generate a binary operator function where the operands are of the 
	 *  same type opType which results in the builtin boolean.
	 *
	 *  @param declName name of the operator.
	 *  @param opType type that both operands need to have.
	 *  @param bf BuiltinFunction to use for ConstantPropagation
	 *  @param gcBf builtin inliner for code generation.
	 *  @param s reference to the SymbolTable to which the type operations
	 *         should get registered to.
	 *  @return generated operator function.
	 */
	static FunctionDeclaration* 
	boolBinOp(
		const char *declName, 
		const TypeDeclaration &opType,
		BuiltinFunction *bf,
		GCBuiltins *gcBf,
		SymbolTable &s);

	/** generate a binary operator function where the operand are of the 
	 *  same type opType which results also in the same type opType.
	 *
	 *  @param declName name of the operator
	 *  @param opType type of the operands and result type.
	 *  @param gcBf inline code generator for builtin.
	 *  @param bf builtin function for ConstantPropagation
	 *  @param s reference to the SymbolTable to which type operations
	 *         should get registered to.
	 *  @return generated operator function.
	 */
	static FunctionDeclaration*
	binOpSameType(
		const char *declName,
		const TypeDeclaration &opType,
		BuiltinFunction *bf,
		GCBuiltins *gcBf,
		SymbolTable &s);

	/** generate a unary operator function where the operand and the 
	 *  result are of the type opType.
	 *
	 *  @param declName name of the operator
	 *  @param opType type of the operand and result.
	 *  @param bf instance of BuiltinFunction for ConstantPropagation
	 *  @param gcBf instance of builtin inline code generator
	 *  @param s reference to the SymbolTable to which type operations
	 *         should get registered to.
	 *  @return generated operator function.
	 */
	static FunctionDeclaration*
	unOpSameType(
		const char *declName,
		const TypeDeclaration &opType,
		BuiltinFunction *bf,
		GCBuiltins *gcBf,
		SymbolTable &s);

	/** generate a binary operator and register it in the SymbolTable.
	 *  @param declName name of the operator.
	 *  @param left type of left operand.
	 *  @param right type of right operand.
	 *  @param return return type.
	 *  @param s SymbolTable instance.
	 */
	static FunctionDeclaration*
	binOp(
		const char *declName,
		const TypeDeclaration &left,
		const TypeDeclaration &right,
		const TypeDeclaration &returnT,
		SymbolTable &s
	);

	/** generate a binary operator and register it in the SymbolTable.
	 *  @param declName name of the operator.
	 *  @param left type of left operand (member of std.standard).
	 *  @param right type of right operand.
	 *  @param return return type.
	 *  @param s SymbolTable instance.
	 */
	static FunctionDeclaration*
	binOp(
		const char *declName,
		const char *left,
		const TypeDeclaration &right,
		const TypeDeclaration &returnT,
		SymbolTable &s
	);

	/** generate a binary operator and register it in the SymbolTable.
	 *  @param declName name of the operator.
	 *  @param left type of left operand.
	 *  @param right type of right operand (member of std.standard).
	 *  @param return return type.
	 *  @param s SymbolTable instance.
	 */
	static FunctionDeclaration*
	binOp(
		const char *declName,
		const TypeDeclaration &left,
		const char *right,
		const TypeDeclaration &returnT,
		SymbolTable &s
	);

	/** check, if type is a discrete type. 
	 *  @param type type to check.
	 *  @return true, if it is a discrete type.
	 */
	static bool
	isDiscreteType(const TypeDeclaration *type);

	/** check, if type is either std.standard.boolean or std.standard.bit
	 *  @param type type to check.
	 *  @param s SymbolTable instance.
	 *  @return true if type is either boolean or bit.
	 */
	static bool
	isBoolOrBit(const TypeDeclaration *type, SymbolTable &s);

	/** check if t is a integer or float type and set the baseType 
	 *  accordingly.
	 *
	 *  @param t RangeConstraintType that will get the baseType set.
	 *  @param s SymbolTable instance.
	 */
	static void
	determineBaseType(RangeConstraintType &t, SymbolTable &s);
};

}; /* namespace ast */

#endif
