//
// 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.
//
// Type.cpp --
//
// Author           : Aaron B. Moss
// Created On       : Mon May 13 15:00:00 2019
// Last Modified By : Andrew Beach
// Last Modified On : Thu Apr  6 15:59:00 2023
// Update Count     : 7
//

#include "Type.hpp"

#include <cassert>
#include <utility>               // for move
#include <vector>

#include "Decl.hpp"
#include "Init.hpp"
#include "Inspect.hpp"
#include "Common/utility.h"      // for copy, move
#include "Tuples/Tuples.h"       // for isTtype

namespace ast {

const Type * Type::getComponent( unsigned i ) const {
	assertf( size() == 1 && i == 0, "Type::getComponent was called with size %d and index %d\n", size(), i );
	return this;
}

const Type * Type::stripDeclarator() const {
	const Type * t;
	const Type * a;
	for ( t = this; (a = ast::getPointerBase( t )); t = a );
	return t;
}

const Type * Type::stripReferences() const {
	const Type * t;
	const ReferenceType * r;
	for ( t = this; (r = dynamic_cast<const ReferenceType *>(t) ); t = r->base );
	return t;
}

// --- BasicType

// GENERATED START, DO NOT EDIT
// GENERATED BY BasicTypes-gen.cc
const char * BasicType::typeNames[] = {
	"_Bool",
	"char",
	"signed char",
	"unsigned char",
	"signed short int",
	"unsigned short int",
	"signed int",
	"unsigned int",
	"signed long int",
	"unsigned long int",
	"signed long long int",
	"unsigned long long int",
	"__int128",
	"unsigned __int128",
	"_Float16",
	"_Float16 _Complex",
	"_Float32",
	"_Float32 _Complex",
	"float",
	"float _Complex",
	"_Float32x",
	"_Float32x _Complex",
	"_Float64",
	"_Float64 _Complex",
	"double",
	"double _Complex",
	"_Float64x",
	"_Float64x _Complex",
	"__float80",
	"_Float128",
	"_Float128 _Complex",
	"__float128",
	"long double",
	"long double _Complex",
	"_Float128x",
	"_Float128x _Complex",
};
// GENERATED END

// --- FunctionType
namespace {
	bool containsTtype( const std::vector<ptr<Type>> & l ) {
		if ( ! l.empty() ) {
			return Tuples::isTtype( l.back() );
		}
		return false;
	}
}

bool FunctionType::isTtype() const {
	return containsTtype( returns ) || containsTtype( params );
}

// --- BaseInstType

std::vector<readonly<Decl>> BaseInstType::lookup( const std::string& name ) const {
	assertf( aggr(), "Must have aggregate to perform lookup" );

	std::vector<readonly<Decl>> found;
	for ( const Decl * decl : aggr()->members ) {
		if ( decl->name == name ) { found.emplace_back( decl ); }
	}
	return found;
}

// --- SueInstType (StructInstType, UnionInstType, EnumInstType)

template<typename decl_t>
SueInstType<decl_t>::SueInstType(
	const base_type * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as )
: BaseInstType( b->name, q, std::move(as) ), base( b ) {}

template<typename decl_t>
SueInstType<decl_t>::SueInstType(
	const base_type * b, std::vector<ptr<Expr>> && params,
	CV::Qualifiers q, std::vector<ptr<Attribute>> && as )
: BaseInstType( b->name, std::move(params), q, std::move(as) ), base( b ) {}

template<typename decl_t>
bool SueInstType<decl_t>::isComplete() const {
	return base ? base->body : false;
}

template class SueInstType<StructDecl>;
template class SueInstType<UnionDecl>;
template class SueInstType<EnumDecl>;

// --- TraitInstType

TraitInstType::TraitInstType(
	const TraitDecl * b, CV::Qualifiers q, std::vector<ptr<Attribute>>&& as )
: BaseInstType( b->name, q, std::move(as) ), base( b ) {}

// --- TypeInstType

TypeInstType::TypeInstType( const TypeEnvKey & key )
: BaseInstType(key.base->name), base(key.base), kind(key.base->kind), formal_usage(key.formal_usage), expr_id(key.expr_id) {}

bool TypeInstType::operator==( const TypeInstType & other ) const {
	return base == other.base
		&& formal_usage == other.formal_usage
		&& expr_id == other.expr_id;
}

TypeInstType::TypeInstType( const TypeDecl * b,
	CV::Qualifiers q, std::vector<ptr<Attribute>> && as )
: BaseInstType( b->name, q, std::move(as) ), base( b ), kind( b->kind ) {}

void TypeInstType::set_base( const TypeDecl * b ) {
	base = b;
	kind = b->kind;
}

bool TypeInstType::isComplete() const { return base->sized; }

std::string TypeEnvKey::typeString() const {
	return std::string("_") + std::to_string(formal_usage)
		+ "_" + std::to_string(expr_id) + "_" + base->name;
}

bool TypeEnvKey::operator==(
		const TypeEnvKey & other ) const {
	return base == other.base
		&& formal_usage == other.formal_usage
		&& expr_id == other.expr_id;
}

bool TypeEnvKey::operator<(
		const TypeEnvKey & other ) const {
	// TypeEnvKey ordering is an arbitrary total ordering.
	// It doesn't mean anything but allows for a sorting.
	if ( base < other.base ) {
		return true;
	} else if ( other.base < base ) {
		return false;
	} else if ( formal_usage < other.formal_usage ) {
		return true;
	} else if ( other.formal_usage < formal_usage ) {
		return false;
	} else {
		return expr_id < other.expr_id;
	}
}

// --- TupleType

TupleType::TupleType( std::vector<ptr<Type>> && ts, CV::Qualifiers q )
: Type( q ), types( std::move(ts) ) {}

bool isUnboundType(const Type * type) {
	if (auto typeInst = dynamic_cast<const TypeInstType *>(type)) {
		// xxx - look for a type name produced by renameTyVars.

		// TODO: once TypeInstType representation is updated, it should properly check
		// if the context id is filled. this is a temporary hack for now
		return typeInst->formal_usage > 0;
	}
	return false;
}

}

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