<commit_before>/*
    This file is part of cpp-ethereum.

    cpp-ethereum is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    cpp-ethereum is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * @author Christian <<EMAIL>>
 * @date 2014
 * Solidity data types
 */

#include <libdevcore/CommonIO.h>
#include <libdevcore/CommonData.h>
#include <libsolidity/Utils.h>
#include <libsolidity/Types.h>
#include <libsolidity/AST.h>

#include <limits>

using namespace std;

namespace dev
{
namespace solidity
{

TypePointer Type::fromElementaryTypeName(Token::Value _typeToken)
{
	solAssert(Token::isElementaryTypeName(_typeToken), "Elementary type name expected.");

	if (Token::Int <= _typeToken && _typeToken <= Token::Hash256)
	{
		int offset = _typeToken - Token::Int;
		int bytes = offset % 33;
		if (bytes == 0)
			bytes = 32;
		int modifier = offset / 33;
		return make_shared<IntegerType>(bytes * 8,
										modifier == 0 ? IntegerType::Modifier::Signed :
										modifier == 1 ? IntegerType::Modifier::Unsigned :
										IntegerType::Modifier::Hash);
	}
	else if (_typeToken == Token::Address)
		return make_shared<IntegerType>(0, IntegerType::Modifier::Address);
	else if (_typeToken == Token::Bool)
		return make_shared<BoolType>();
	else if (Token::String0 <= _typeToken && _typeToken <= Token::String32)
		return make_shared<StaticStringType>(int(_typeToken) - int(Token::String0));
	else if (_typeToken == Token::Bytes)
		return make_shared<ByteArrayType>(ByteArrayType::Location::Storage);
	else
		BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unable to convert elementary typename " +
																		 std::string(Token::toString(_typeToken)) + " to type."));
}

TypePointer Type::fromElementaryTypeName(string const& _name)
{
	return fromElementaryTypeName(Token::fromIdentifierOrKeyword(_name));
}

TypePointer Type::fromUserDefinedTypeName(UserDefinedTypeName const& _typeName)
{
	Declaration const* declaration = _typeName.getReferencedDeclaration();
	if (StructDefinition const* structDef = dynamic_cast<StructDefinition const*>(declaration))
		return make_shared<StructType>(*structDef);
	else if (EnumDefinition const* enumDef = dynamic_cast<EnumDefinition const*>(declaration))
		return make_shared<EnumType>(*enumDef);
	else if (FunctionDefinition const* function = dynamic_cast<FunctionDefinition const*>(declaration))
		return make_shared<FunctionType>(*function);
	else if (ContractDefinition const* contract = dynamic_cast<ContractDefinition const*>(declaration))
		return make_shared<ContractType>(*contract);
	return TypePointer();
}

TypePointer Type::fromMapping(Mapping const& _typeName)
{
	TypePointer keyType = _typeName.getKeyType().toType();
	if (!keyType)
		BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Error resolving type name."));
	TypePointer valueType = _typeName.getValueType().toType();
	if (!valueType)
		BOOST_THROW_EXCEPTION(_typeName.getValueType().createTypeError("Invalid type name"));
	return make_shared<MappingType>(keyType, valueType);
}

TypePointer Type::forLiteral(Literal const& _literal)
{
	switch (_literal.getToken())
	{
	case Token::TrueLiteral:
	case Token::FalseLiteral:
		return make_shared<BoolType>();
	case Token::Number:
		return make_shared<IntegerConstantType>(_literal);
	case Token::StringLiteral:
		//@todo put larger strings into dynamic strings
		return StaticStringType::smallestTypeForLiteral(_literal.getValue());
	default:
		return shared_ptr<Type>();
	}
}

TypePointer Type::commonType(TypePointer const& _a, TypePointer const& _b)
{
	if (_b->isImplicitlyConvertibleTo(*_a))
		return _a;
	else if (_a->isImplicitlyConvertibleTo(*_b))
		return _b;
	else
		return TypePointer();
}

const MemberList Type::EmptyMemberList = MemberList();

IntegerType::IntegerType(int _bits, IntegerType::Modifier _modifier):
	m_bits(_bits), m_modifier(_modifier)
{
	if (isAddress())
		m_bits = 160;
	solAssert(m_bits > 0 && m_bits <= 256 && m_bits % 8 == 0,
			  "Invalid bit number for integer type: " + dev::toString(_bits));
}

bool IntegerType::isImplicitlyConvertibleTo(Type const& _convertTo) const
{
	if (_convertTo.getCategory() != getCategory())
		return false;
	IntegerType const& convertTo = dynamic_cast<IntegerType const&>(_convertTo);
	if (convertTo.m_bits < m_bits)
		return false;
	if (isAddress())
		return convertTo.isAddress();
	else if (isHash())
		return convertTo.isHash();
	else if (isSigned())
		return convertTo.isSigned();
	else
		return !convertTo.isSigned() || convertTo.m_bits > m_bits;
}

bool IntegerType::isExplicitlyConvertibleTo(Type const& _convertTo) const
{
	if (_convertTo.getCategory() == Category::String)
	{
		StaticStringType const& convertTo = dynamic_cast<StaticStringType const&>(_convertTo);
		return isHash() && (m_bits == convertTo.getNumBytes() * 8);
	}
	return _convertTo.getCategory() == getCategory() || _convertTo.getCategory() == Category::Contract;
}

TypePointer IntegerType::unaryOperatorResult(Token::Value _operator) const
{
	// "delete" is ok for all integer types
	if (_operator == Token::Delete)
		return make_shared<VoidType>();
	// no further unary operators for addresses
	else if (isAddress())
		return TypePointer();
	// "~" is ok for all other types
	else if (_operator == Token::BitNot)<commit_msg>Explicit conversion from int to Enum<commit_after>/*
    This file is part of cpp-ethereum.

    cpp-ethereum is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    cpp-ethereum is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * @author Christian <<EMAIL>>
 * @date 2014
 * Solidity data types
 */

#include <libdevcore/CommonIO.h>
#include <libdevcore/CommonData.h>
#include <libsolidity/Utils.h>
#include <libsolidity/Types.h>
#include <libsolidity/AST.h>

#include <limits>

using namespace std;

namespace dev
{
namespace solidity
{

TypePointer Type::fromElementaryTypeName(Token::Value _typeToken)
{
	solAssert(Token::isElementaryTypeName(_typeToken), "Elementary type name expected.");

	if (Token::Int <= _typeToken && _typeToken <= Token::Hash256)
	{
		int offset = _typeToken - Token::Int;
		int bytes = offset % 33;
		if (bytes == 0)
			bytes = 32;
		int modifier = offset / 33;
		return make_shared<IntegerType>(bytes * 8,
										modifier == 0 ? IntegerType::Modifier::Signed :
										modifier == 1 ? IntegerType::Modifier::Unsigned :
										IntegerType::Modifier::Hash);
	}
	else if (_typeToken == Token::Address)
		return make_shared<IntegerType>(0, IntegerType::Modifier::Address);
	else if (_typeToken == Token::Bool)
		return make_shared<BoolType>();
	else if (Token::String0 <= _typeToken && _typeToken <= Token::String32)
		return make_shared<StaticStringType>(int(_typeToken) - int(Token::String0));
	else if (_typeToken == Token::Bytes)
		return make_shared<ByteArrayType>(ByteArrayType::Location::Storage);
	else
		BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Unable to convert elementary typename " +
																		 std::string(Token::toString(_typeToken)) + " to type."));
}

TypePointer Type::fromElementaryTypeName(string const& _name)
{
	return fromElementaryTypeName(Token::fromIdentifierOrKeyword(_name));
}

TypePointer Type::fromUserDefinedTypeName(UserDefinedTypeName const& _typeName)
{
	Declaration const* declaration = _typeName.getReferencedDeclaration();
	if (StructDefinition const* structDef = dynamic_cast<StructDefinition const*>(declaration))
		return make_shared<StructType>(*structDef);
	else if (EnumDefinition const* enumDef = dynamic_cast<EnumDefinition const*>(declaration))
		return make_shared<EnumType>(*enumDef);
	else if (FunctionDefinition const* function = dynamic_cast<FunctionDefinition const*>(declaration))
		return make_shared<FunctionType>(*function);
	else if (ContractDefinition const* contract = dynamic_cast<ContractDefinition const*>(declaration))
		return make_shared<ContractType>(*contract);
	return TypePointer();
}

TypePointer Type::fromMapping(Mapping const& _typeName)
{
	TypePointer keyType = _typeName.getKeyType().toType();
	if (!keyType)
		BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Error resolving type name."));
	TypePointer valueType = _typeName.getValueType().toType();
	if (!valueType)
		BOOST_THROW_EXCEPTION(_typeName.getValueType().createTypeError("Invalid type name"));
	return make_shared<MappingType>(keyType, valueType);
}

TypePointer Type::forLiteral(Literal const& _literal)
{
	switch (_literal.getToken())
	{
	case Token::TrueLiteral:
	case Token::FalseLiteral:
		return make_shared<BoolType>();
	case Token::Number:
		return make_shared<IntegerConstantType>(_literal);
	case Token::StringLiteral:
		//@todo put larger strings into dynamic strings
		return StaticStringType::smallestTypeForLiteral(_literal.getValue());
	default:
		return shared_ptr<Type>();
	}
}

TypePointer Type::commonType(TypePointer const& _a, TypePointer const& _b)
{
	if (_b->isImplicitlyConvertibleTo(*_a))
		return _a;
	else if (_a->isImplicitlyConvertibleTo(*_b))
		return _b;
	else
		return TypePointer();
}

const MemberList Type::EmptyMemberList = MemberList();

IntegerType::IntegerType(int _bits, IntegerType::Modifier _modifier):
	m_bits(_bits), m_modifier(_modifier)
{
	if (isAddress())
		m_bits = 160;
	solAssert(m_bits > 0 && m_bits <= 256 && m_bits % 8 == 0,
			  "Invalid bit number for integer type: " + dev::toString(_bits));
}

bool IntegerType::isImplicitlyConvertibleTo(Type const& _convertTo) const
{
	if (_convertTo.getCategory() != getCategory())
		return false;
	IntegerType const& convertTo = dynamic_cast<IntegerType const&>(_convertTo);
	if (convertTo.m_bits < m_bits)
		return false;
	if (isAddress())
		return convertTo.isAddress();
	else if (isHash())
		return convertTo.isHash();
	else if (isSigned())
		return convertTo.isSigned();
	else
		return !convertTo.isSigned() || convertTo.m_bits > m_bits;
}

bool IntegerType::isExplicitlyConvertibleTo(Type const& _convertTo) const
{
	if (_convertTo.getCategory() == Category::String)
	{
		StaticStringType const& convertTo = dynamic_cast<StaticStringType const&>(_convertTo);
		return isHash() && (m_bits == convertTo.getNumBytes() * 8);
	}
	return _convertTo.getCategory() == getCategory() ||
		   _convertTo.getCategory() == Category::Contract ||
		   _convertTo.getCategory() == Category::Enum;
}

TypePointer IntegerType::unaryOperatorResult(Token::Value _operator) const
{
	// "delete" is ok for all integer types
	if (_operator == Token::Delete)
		return make_shared<VoidType>();
	// no further unary operators for addresses
	else if (isAddress())
		return TypePointer();
	// "~" is ok for all other types
	else if (_operator == Token::BitNot)
{'fraction_non_alphanumeric': 0.11828693790149893, 'fraction_numerical': 0.005653104925053533, 'mean_word_length': 5.600339174674958, 'pattern_counts': {'":': 0, '<': 81, '<?xml version=': 0, '>': 69, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '159710', 'n_tokens_mistral': 3731, 'n_tokens_neox': 3483, 'n_words': 926}