mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Flexible string literals, convertible to bytesX, bytes and string.
This commit is contained in:
parent
aa6182ab87
commit
46dde467e7
@ -113,6 +113,16 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound
|
|||||||
solAssert(ref->location() == DataLocation::Memory, "");
|
solAssert(ref->location() == DataLocation::Memory, "");
|
||||||
storeInMemoryDynamic(IntegerType(256), _padToWordBoundaries);
|
storeInMemoryDynamic(IntegerType(256), _padToWordBoundaries);
|
||||||
}
|
}
|
||||||
|
else if (auto str = dynamic_cast<StringLiteralType const*>(&_type))
|
||||||
|
{
|
||||||
|
m_context << eth::Instruction::DUP1;
|
||||||
|
storeStringData(bytesConstRef(str->value()));
|
||||||
|
if (_padToWordBoundaries)
|
||||||
|
m_context << u256(((str->value().size() + 31) / 32) * 32);
|
||||||
|
else
|
||||||
|
m_context << u256(str->value().size());
|
||||||
|
m_context << eth::Instruction::ADD;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
unsigned numBytes = prepareMemoryStore(_type, _padToWordBoundaries);
|
unsigned numBytes = prepareMemoryStore(_type, _padToWordBoundaries);
|
||||||
@ -169,7 +179,8 @@ void CompilerUtils::encodeToMemory(
|
|||||||
TypePointer type = targetType;
|
TypePointer type = targetType;
|
||||||
if (
|
if (
|
||||||
_givenTypes[i]->dataStoredIn(DataLocation::Storage) ||
|
_givenTypes[i]->dataStoredIn(DataLocation::Storage) ||
|
||||||
_givenTypes[i]->dataStoredIn(DataLocation::CallData)
|
_givenTypes[i]->dataStoredIn(DataLocation::CallData) ||
|
||||||
|
_givenTypes[i]->getCategory() == Type::Category::StringLiteral
|
||||||
)
|
)
|
||||||
type = _givenTypes[i]; // delay conversion
|
type = _givenTypes[i]; // delay conversion
|
||||||
else
|
else
|
||||||
@ -192,36 +203,48 @@ void CompilerUtils::encodeToMemory(
|
|||||||
solAssert(!!targetType, "Externalable type expected.");
|
solAssert(!!targetType, "Externalable type expected.");
|
||||||
if (targetType->isDynamicallySized() && !_copyDynamicDataInPlace)
|
if (targetType->isDynamicallySized() && !_copyDynamicDataInPlace)
|
||||||
{
|
{
|
||||||
solAssert(_givenTypes[i]->getCategory() == Type::Category::Array, "Unknown dynamic type.");
|
|
||||||
auto const& arrayType = dynamic_cast<ArrayType const&>(*_givenTypes[i]);
|
|
||||||
// copy tail pointer (=mem_end - mem_start) to memory
|
// copy tail pointer (=mem_end - mem_start) to memory
|
||||||
m_context << eth::dupInstruction(2 + dynPointers) << eth::Instruction::DUP2;
|
m_context << eth::dupInstruction(2 + dynPointers) << eth::Instruction::DUP2;
|
||||||
m_context << eth::Instruction::SUB;
|
m_context << eth::Instruction::SUB;
|
||||||
m_context << eth::dupInstruction(2 + dynPointers - thisDynPointer);
|
m_context << eth::dupInstruction(2 + dynPointers - thisDynPointer);
|
||||||
m_context << eth::Instruction::MSTORE;
|
m_context << eth::Instruction::MSTORE;
|
||||||
// now copy the array
|
// stack: ... <end_of_mem>
|
||||||
copyToStackTop(argSize - stackPos + dynPointers + 2, arrayType.getSizeOnStack());
|
if (_givenTypes[i]->getCategory() == Type::Category::StringLiteral)
|
||||||
// stack: ... <end_of_mem> <value...>
|
{
|
||||||
// copy length to memory
|
auto const& strType = dynamic_cast<StringLiteralType const&>(*_givenTypes[i]);
|
||||||
m_context << eth::dupInstruction(1 + arrayType.getSizeOnStack());
|
m_context << u256(strType.value().size());
|
||||||
if (arrayType.location() == DataLocation::CallData)
|
storeInMemoryDynamic(IntegerType(256), true);
|
||||||
m_context << eth::Instruction::DUP2; // length is on stack
|
// stack: ... <end_of_mem'>
|
||||||
else if (arrayType.location() == DataLocation::Storage)
|
storeInMemoryDynamic(strType, _padToWordBoundaries);
|
||||||
m_context << eth::Instruction::DUP3 << eth::Instruction::SLOAD;
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
solAssert(arrayType.location() == DataLocation::Memory, "");
|
solAssert(_givenTypes[i]->getCategory() == Type::Category::Array, "Unknown dynamic type.");
|
||||||
m_context << eth::Instruction::DUP2 << eth::Instruction::MLOAD;
|
auto const& arrayType = dynamic_cast<ArrayType const&>(*_givenTypes[i]);
|
||||||
|
// now copy the array
|
||||||
|
copyToStackTop(argSize - stackPos + dynPointers + 2, arrayType.getSizeOnStack());
|
||||||
|
// stack: ... <end_of_mem> <value...>
|
||||||
|
// copy length to memory
|
||||||
|
m_context << eth::dupInstruction(1 + arrayType.getSizeOnStack());
|
||||||
|
if (arrayType.location() == DataLocation::CallData)
|
||||||
|
m_context << eth::Instruction::DUP2; // length is on stack
|
||||||
|
else if (arrayType.location() == DataLocation::Storage)
|
||||||
|
m_context << eth::Instruction::DUP3 << eth::Instruction::SLOAD;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
solAssert(arrayType.location() == DataLocation::Memory, "");
|
||||||
|
m_context << eth::Instruction::DUP2 << eth::Instruction::MLOAD;
|
||||||
|
}
|
||||||
|
// stack: ... <end_of_mem> <value...> <end_of_mem'> <length>
|
||||||
|
storeInMemoryDynamic(IntegerType(256), true);
|
||||||
|
// stack: ... <end_of_mem> <value...> <end_of_mem''>
|
||||||
|
// copy the new memory pointer
|
||||||
|
m_context << eth::swapInstruction(arrayType.getSizeOnStack() + 1) << eth::Instruction::POP;
|
||||||
|
// stack: ... <end_of_mem''> <value...>
|
||||||
|
// copy data part
|
||||||
|
ArrayUtils(m_context).copyArrayToMemory(arrayType, _padToWordBoundaries);
|
||||||
|
// stack: ... <end_of_mem'''>
|
||||||
}
|
}
|
||||||
// stack: ... <end_of_mem> <value...> <end_of_mem'> <length>
|
|
||||||
storeInMemoryDynamic(IntegerType(256), true);
|
|
||||||
// stack: ... <end_of_mem> <value...> <end_of_mem''>
|
|
||||||
// copy the new memory pointer
|
|
||||||
m_context << eth::swapInstruction(arrayType.getSizeOnStack() + 1) << eth::Instruction::POP;
|
|
||||||
// stack: ... <end_of_mem''> <value...>
|
|
||||||
// copy data part
|
|
||||||
ArrayUtils(m_context).copyArrayToMemory(arrayType, _padToWordBoundaries);
|
|
||||||
// stack: ... <end_of_mem'''>
|
|
||||||
|
|
||||||
thisDynPointer++;
|
thisDynPointer++;
|
||||||
}
|
}
|
||||||
@ -269,22 +292,22 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp
|
|||||||
// conversion from bytes to integer. no need to clean the high bit
|
// conversion from bytes to integer. no need to clean the high bit
|
||||||
// only to shift right because of opposite alignment
|
// only to shift right because of opposite alignment
|
||||||
IntegerType const& targetIntegerType = dynamic_cast<IntegerType const&>(_targetType);
|
IntegerType const& targetIntegerType = dynamic_cast<IntegerType const&>(_targetType);
|
||||||
m_context << (u256(1) << (256 - typeOnStack.getNumBytes() * 8)) << eth::Instruction::SWAP1 << eth::Instruction::DIV;
|
m_context << (u256(1) << (256 - typeOnStack.numBytes() * 8)) << eth::Instruction::SWAP1 << eth::Instruction::DIV;
|
||||||
if (targetIntegerType.getNumBits() < typeOnStack.getNumBytes() * 8)
|
if (targetIntegerType.getNumBits() < typeOnStack.numBytes() * 8)
|
||||||
convertType(IntegerType(typeOnStack.getNumBytes() * 8), _targetType, _cleanupNeeded);
|
convertType(IntegerType(typeOnStack.numBytes() * 8), _targetType, _cleanupNeeded);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// clear lower-order bytes for conversion to shorter bytes - we always clean
|
// clear lower-order bytes for conversion to shorter bytes - we always clean
|
||||||
solAssert(targetTypeCategory == Type::Category::FixedBytes, "Invalid type conversion requested.");
|
solAssert(targetTypeCategory == Type::Category::FixedBytes, "Invalid type conversion requested.");
|
||||||
FixedBytesType const& targetType = dynamic_cast<FixedBytesType const&>(_targetType);
|
FixedBytesType const& targetType = dynamic_cast<FixedBytesType const&>(_targetType);
|
||||||
if (targetType.getNumBytes() < typeOnStack.getNumBytes())
|
if (targetType.numBytes() < typeOnStack.numBytes())
|
||||||
{
|
{
|
||||||
if (targetType.getNumBytes() == 0)
|
if (targetType.numBytes() == 0)
|
||||||
m_context << eth::Instruction::DUP1 << eth::Instruction::XOR;
|
m_context << eth::Instruction::DUP1 << eth::Instruction::XOR;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_context << (u256(1) << (256 - targetType.getNumBytes() * 8));
|
m_context << (u256(1) << (256 - targetType.numBytes() * 8));
|
||||||
m_context << eth::Instruction::DUP1 << eth::Instruction::SWAP2;
|
m_context << eth::Instruction::DUP1 << eth::Instruction::SWAP2;
|
||||||
m_context << eth::Instruction::DIV << eth::Instruction::MUL;
|
m_context << eth::Instruction::DIV << eth::Instruction::MUL;
|
||||||
}
|
}
|
||||||
@ -306,9 +329,9 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp
|
|||||||
// only to shift left because of opposite alignment
|
// only to shift left because of opposite alignment
|
||||||
FixedBytesType const& targetBytesType = dynamic_cast<FixedBytesType const&>(_targetType);
|
FixedBytesType const& targetBytesType = dynamic_cast<FixedBytesType const&>(_targetType);
|
||||||
if (auto typeOnStack = dynamic_cast<IntegerType const*>(&_typeOnStack))
|
if (auto typeOnStack = dynamic_cast<IntegerType const*>(&_typeOnStack))
|
||||||
if (targetBytesType.getNumBytes() * 8 > typeOnStack->getNumBits())
|
if (targetBytesType.numBytes() * 8 > typeOnStack->getNumBits())
|
||||||
cleanHigherOrderBits(*typeOnStack);
|
cleanHigherOrderBits(*typeOnStack);
|
||||||
m_context << (u256(1) << (256 - targetBytesType.getNumBytes() * 8)) << eth::Instruction::MUL;
|
m_context << (u256(1) << (256 - targetBytesType.numBytes() * 8)) << eth::Instruction::MUL;
|
||||||
}
|
}
|
||||||
else if (targetTypeCategory == Type::Category::Enum)
|
else if (targetTypeCategory == Type::Category::Enum)
|
||||||
// just clean
|
// just clean
|
||||||
@ -340,6 +363,37 @@ void CompilerUtils::convertType(Type const& _typeOnStack, Type const& _targetTyp
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case Type::Category::StringLiteral:
|
||||||
|
{
|
||||||
|
auto const& literalType = dynamic_cast<StringLiteralType const&>(_typeOnStack);
|
||||||
|
string const& value = literalType.value();
|
||||||
|
bytesConstRef data(value);
|
||||||
|
if (targetTypeCategory == Type::Category::FixedBytes)
|
||||||
|
{
|
||||||
|
solAssert(data.size() <= 32, "");
|
||||||
|
m_context << h256::Arith(h256(data, h256::AlignLeft));
|
||||||
|
}
|
||||||
|
else if (targetTypeCategory == Type::Category::Array)
|
||||||
|
{
|
||||||
|
auto const& arrayType = dynamic_cast<ArrayType const&>(_targetType);
|
||||||
|
solAssert(arrayType.isByteArray(), "");
|
||||||
|
u256 storageSize(32 + ((data.size() + 31) / 32) * 32);
|
||||||
|
m_context << storageSize;
|
||||||
|
allocateMemory();
|
||||||
|
// stack: mempos
|
||||||
|
m_context << eth::Instruction::DUP1 << u256(data.size());
|
||||||
|
storeInMemoryDynamic(IntegerType(256));
|
||||||
|
// stack: mempos datapos
|
||||||
|
storeStringData(data);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
solAssert(
|
||||||
|
false,
|
||||||
|
"Invalid conversion from string literal to " + _targetType.toString(false) + " requested."
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
case Type::Category::Array:
|
case Type::Category::Array:
|
||||||
{
|
{
|
||||||
solAssert(targetTypeCategory == stackTypeCategory, "");
|
solAssert(targetTypeCategory == stackTypeCategory, "");
|
||||||
@ -606,6 +660,28 @@ void CompilerUtils::computeHashStatic()
|
|||||||
m_context << u256(32) << u256(0) << eth::Instruction::SHA3;
|
m_context << u256(32) << u256(0) << eth::Instruction::SHA3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CompilerUtils::storeStringData(bytesConstRef _data)
|
||||||
|
{
|
||||||
|
//@todo provide both alternatives to the optimiser
|
||||||
|
// stack: mempos
|
||||||
|
if (_data.size() <= 128)
|
||||||
|
{
|
||||||
|
for (unsigned i = 0; i < _data.size(); i += 32)
|
||||||
|
{
|
||||||
|
m_context << h256::Arith(h256(_data.cropped(i), h256::AlignLeft));
|
||||||
|
storeInMemoryDynamic(IntegerType(256));
|
||||||
|
}
|
||||||
|
m_context << eth::Instruction::POP;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// stack: mempos mempos_data
|
||||||
|
m_context.appendData(_data.toBytes());
|
||||||
|
m_context << u256(_data.size()) << eth::Instruction::SWAP2;
|
||||||
|
m_context << eth::Instruction::CODECOPY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCalldata, bool _padToWordBoundaries)
|
unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCalldata, bool _padToWordBoundaries)
|
||||||
{
|
{
|
||||||
unsigned numBytes = _type.getCalldataEncodedSize(_padToWordBoundaries);
|
unsigned numBytes = _type.getCalldataEncodedSize(_padToWordBoundaries);
|
||||||
|
@ -148,7 +148,12 @@ private:
|
|||||||
/// Address of the precompiled identity contract.
|
/// Address of the precompiled identity contract.
|
||||||
static const unsigned identityContractAddress;
|
static const unsigned identityContractAddress;
|
||||||
|
|
||||||
//// Appends code that cleans higher-order bits for integer types.
|
/// Stores the given string in memory.
|
||||||
|
/// Stack pre: mempos
|
||||||
|
/// Stack post:
|
||||||
|
void storeStringData(bytesConstRef _data);
|
||||||
|
|
||||||
|
/// Appends code that cleans higher-order bits for integer types.
|
||||||
void cleanHigherOrderBits(IntegerType const& _typeOnStack);
|
void cleanHigherOrderBits(IntegerType const& _typeOnStack);
|
||||||
|
|
||||||
/// Prepares the given type for storing in memory by shifting it if necessary.
|
/// Prepares the given type for storing in memory by shifting it if necessary.
|
||||||
|
@ -158,6 +158,11 @@ bool ExpressionCompiler::visit(Assignment const& _assignment)
|
|||||||
utils().convertType(*type, *_assignment.getType());
|
utils().convertType(*type, *_assignment.getType());
|
||||||
type = _assignment.getType();
|
type = _assignment.getType();
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
utils().convertType(*type, *type->mobileType());
|
||||||
|
type = type->mobileType();
|
||||||
|
}
|
||||||
|
|
||||||
_assignment.getLeftHandSide().accept(*this);
|
_assignment.getLeftHandSide().accept(*this);
|
||||||
solAssert(!!m_currentLValue, "LValue not retrieved.");
|
solAssert(!!m_currentLValue, "LValue not retrieved.");
|
||||||
@ -898,13 +903,15 @@ void ExpressionCompiler::endVisit(Identifier const& _identifier)
|
|||||||
void ExpressionCompiler::endVisit(Literal const& _literal)
|
void ExpressionCompiler::endVisit(Literal const& _literal)
|
||||||
{
|
{
|
||||||
CompilerContext::LocationSetter locationSetter(m_context, _literal);
|
CompilerContext::LocationSetter locationSetter(m_context, _literal);
|
||||||
switch (_literal.getType()->getCategory())
|
TypePointer type = _literal.getType();
|
||||||
|
switch (type->getCategory())
|
||||||
{
|
{
|
||||||
case Type::Category::IntegerConstant:
|
case Type::Category::IntegerConstant:
|
||||||
case Type::Category::Bool:
|
case Type::Category::Bool:
|
||||||
case Type::Category::FixedBytes:
|
m_context << type->literalValue(&_literal);
|
||||||
m_context << _literal.getType()->literalValue(&_literal);
|
|
||||||
break;
|
break;
|
||||||
|
case Type::Category::StringLiteral:
|
||||||
|
break; // will be done during conversion
|
||||||
default:
|
default:
|
||||||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Only integer, boolean and string literals implemented for now."));
|
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Only integer, boolean and string literals implemented for now."));
|
||||||
}
|
}
|
||||||
|
@ -209,7 +209,7 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
|
|||||||
// stack: value storage_ref cleared_value multiplier value
|
// stack: value storage_ref cleared_value multiplier value
|
||||||
if (m_dataType.getCategory() == Type::Category::FixedBytes)
|
if (m_dataType.getCategory() == Type::Category::FixedBytes)
|
||||||
m_context
|
m_context
|
||||||
<< (u256(0x1) << (256 - 8 * dynamic_cast<FixedBytesType const&>(m_dataType).getNumBytes()))
|
<< (u256(0x1) << (256 - 8 * dynamic_cast<FixedBytesType const&>(m_dataType).numBytes()))
|
||||||
<< eth::Instruction::SWAP1 << eth::Instruction::DIV;
|
<< eth::Instruction::SWAP1 << eth::Instruction::DIV;
|
||||||
else if (
|
else if (
|
||||||
m_dataType.getCategory() == Type::Category::Integer &&
|
m_dataType.getCategory() == Type::Category::Integer &&
|
||||||
|
41
Types.cpp
41
Types.cpp
@ -212,8 +212,7 @@ TypePointer Type::forLiteral(Literal const& _literal)
|
|||||||
case Token::Number:
|
case Token::Number:
|
||||||
return make_shared<IntegerConstantType>(_literal);
|
return make_shared<IntegerConstantType>(_literal);
|
||||||
case Token::StringLiteral:
|
case Token::StringLiteral:
|
||||||
//@todo put larger strings into dynamic strings
|
return make_shared<StringLiteralType>(_literal);
|
||||||
return FixedBytesType::smallestTypeForLiteral(_literal.getValue());
|
|
||||||
default:
|
default:
|
||||||
return shared_ptr<Type>();
|
return shared_ptr<Type>();
|
||||||
}
|
}
|
||||||
@ -378,7 +377,7 @@ bool IntegerConstantType::isImplicitlyConvertibleTo(Type const& _convertTo) cons
|
|||||||
else if (_convertTo.getCategory() == Category::FixedBytes)
|
else if (_convertTo.getCategory() == Category::FixedBytes)
|
||||||
{
|
{
|
||||||
FixedBytesType const& fixedBytes = dynamic_cast<FixedBytesType const&>(_convertTo);
|
FixedBytesType const& fixedBytes = dynamic_cast<FixedBytesType const&>(_convertTo);
|
||||||
return fixedBytes.getNumBytes() * 8 >= getIntegerType()->getNumBits();
|
return fixedBytes.numBytes() * 8 >= getIntegerType()->getNumBits();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
@ -530,6 +529,33 @@ shared_ptr<IntegerType const> IntegerConstantType::getIntegerType() const
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StringLiteralType::StringLiteralType(Literal const& _literal):
|
||||||
|
m_value(_literal.getValue())
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StringLiteralType::isImplicitlyConvertibleTo(Type const& _convertTo) const
|
||||||
|
{
|
||||||
|
if (auto fixedBytes = dynamic_cast<FixedBytesType const*>(&_convertTo))
|
||||||
|
return size_t(fixedBytes->numBytes()) >= m_value.size();
|
||||||
|
else if (auto arrayType = dynamic_cast<ArrayType const*>(&_convertTo))
|
||||||
|
return arrayType->isByteArray();
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StringLiteralType::operator==(const Type& _other) const
|
||||||
|
{
|
||||||
|
if (_other.getCategory() != getCategory())
|
||||||
|
return false;
|
||||||
|
return m_value == dynamic_cast<StringLiteralType const&>(_other).m_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
TypePointer StringLiteralType::mobileType() const
|
||||||
|
{
|
||||||
|
return make_shared<ArrayType>(DataLocation::Memory, true);
|
||||||
|
}
|
||||||
|
|
||||||
shared_ptr<FixedBytesType> FixedBytesType::smallestTypeForLiteral(string const& _literal)
|
shared_ptr<FixedBytesType> FixedBytesType::smallestTypeForLiteral(string const& _literal)
|
||||||
{
|
{
|
||||||
if (_literal.length() <= 32)
|
if (_literal.length() <= 32)
|
||||||
@ -590,15 +616,6 @@ bool FixedBytesType::operator==(Type const& _other) const
|
|||||||
return other.m_bytes == m_bytes;
|
return other.m_bytes == m_bytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
u256 FixedBytesType::literalValue(const Literal* _literal) const
|
|
||||||
{
|
|
||||||
solAssert(_literal, "");
|
|
||||||
u256 value = 0;
|
|
||||||
for (char c: _literal->getValue())
|
|
||||||
value = (value << 8) | byte(c);
|
|
||||||
return value << ((32 - _literal->getValue().length()) * 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BoolType::isExplicitlyConvertibleTo(Type const& _convertTo) const
|
bool BoolType::isExplicitlyConvertibleTo(Type const& _convertTo) const
|
||||||
{
|
{
|
||||||
// conversion to integer is fine, but not to address
|
// conversion to integer is fine, but not to address
|
||||||
|
36
Types.h
36
Types.h
@ -131,7 +131,7 @@ class Type: private boost::noncopyable, public std::enable_shared_from_this<Type
|
|||||||
public:
|
public:
|
||||||
enum class Category
|
enum class Category
|
||||||
{
|
{
|
||||||
Integer, IntegerConstant, Bool, Real, Array,
|
Integer, IntegerConstant, StringLiteral, Bool, Real, Array,
|
||||||
FixedBytes, Contract, Struct, Function, Enum,
|
FixedBytes, Contract, Struct, Function, Enum,
|
||||||
Mapping, Void, TypeType, Modifier, Magic
|
Mapping, Void, TypeType, Modifier, Magic
|
||||||
};
|
};
|
||||||
@ -311,6 +311,37 @@ private:
|
|||||||
bigint m_value;
|
bigint m_value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Literal string, can be converted to bytes, bytesX or string.
|
||||||
|
*/
|
||||||
|
class StringLiteralType: public Type
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual Category getCategory() const override { return Category::StringLiteral; }
|
||||||
|
|
||||||
|
explicit StringLiteralType(Literal const& _literal);
|
||||||
|
|
||||||
|
virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||||
|
virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override
|
||||||
|
{
|
||||||
|
return TypePointer();
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool operator==(Type const& _other) const override;
|
||||||
|
|
||||||
|
virtual bool canBeStored() const override { return false; }
|
||||||
|
virtual bool canLiveOutsideStorage() const override { return false; }
|
||||||
|
virtual unsigned getSizeOnStack() const override { return 0; }
|
||||||
|
|
||||||
|
virtual std::string toString(bool) const override { return "literal_string \"" + m_value + "\""; }
|
||||||
|
virtual TypePointer mobileType() const override;
|
||||||
|
|
||||||
|
std::string const& value() const { return m_value; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_value;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Bytes type with fixed length of up to 32 bytes.
|
* Bytes type with fixed length of up to 32 bytes.
|
||||||
*/
|
*/
|
||||||
@ -336,10 +367,9 @@ public:
|
|||||||
virtual bool isValueType() const override { return true; }
|
virtual bool isValueType() const override { return true; }
|
||||||
|
|
||||||
virtual std::string toString(bool) const override { return "bytes" + dev::toString(m_bytes); }
|
virtual std::string toString(bool) const override { return "bytes" + dev::toString(m_bytes); }
|
||||||
virtual u256 literalValue(Literal const* _literal) const override;
|
|
||||||
virtual TypePointer externalType() const override { return shared_from_this(); }
|
virtual TypePointer externalType() const override { return shared_from_this(); }
|
||||||
|
|
||||||
int getNumBytes() const { return m_bytes; }
|
int numBytes() const { return m_bytes; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int m_bytes;
|
int m_bytes;
|
||||||
|
Loading…
Reference in New Issue
Block a user