mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Copying structs.
This commit is contained in:
parent
0e40b21c56
commit
1c3c1f1e5d
6
AST.cpp
6
AST.cpp
@ -402,10 +402,8 @@ void Assignment::checkTypeRequirements()
|
|||||||
{
|
{
|
||||||
m_leftHandSide->checkTypeRequirements();
|
m_leftHandSide->checkTypeRequirements();
|
||||||
m_leftHandSide->requireLValue();
|
m_leftHandSide->requireLValue();
|
||||||
//@todo later, assignments to structs might be possible, but not to mappings
|
if (m_leftHandSide->getType()->getCategory() == Type::Category::Mapping)
|
||||||
if (m_leftHandSide->getType()->getCategory() != Type::Category::ByteArray &&
|
BOOST_THROW_EXCEPTION(createTypeError("Mappings cannot be assigned to."));
|
||||||
!m_leftHandSide->getType()->isValueType() && !m_leftHandSide->isLocalLValue())
|
|
||||||
BOOST_THROW_EXCEPTION(createTypeError("Assignment to non-local non-value lvalue."));
|
|
||||||
m_type = m_leftHandSide->getType();
|
m_type = m_leftHandSide->getType();
|
||||||
if (m_assigmentOperator == Token::Assign)
|
if (m_assigmentOperator == Token::Assign)
|
||||||
m_rightHandSide->expectType(*m_type);
|
m_rightHandSide->expectType(*m_type);
|
||||||
|
@ -70,12 +70,12 @@ bool ExpressionCompiler::visit(Assignment const& _assignment)
|
|||||||
solAssert(_assignment.getType()->isValueType(), "Compound operators not implemented for non-value types.");
|
solAssert(_assignment.getType()->isValueType(), "Compound operators not implemented for non-value types.");
|
||||||
if (m_currentLValue.storesReferenceOnStack())
|
if (m_currentLValue.storesReferenceOnStack())
|
||||||
m_context << eth::Instruction::SWAP1 << eth::Instruction::DUP2;
|
m_context << eth::Instruction::SWAP1 << eth::Instruction::DUP2;
|
||||||
m_currentLValue.retrieveValue(_assignment.getType(), _assignment.getLocation(), true);
|
m_currentLValue.retrieveValue(_assignment.getLocation(), true);
|
||||||
appendOrdinaryBinaryOperatorCode(Token::AssignmentToBinaryOp(op), *_assignment.getType());
|
appendOrdinaryBinaryOperatorCode(Token::AssignmentToBinaryOp(op), *_assignment.getType());
|
||||||
if (m_currentLValue.storesReferenceOnStack())
|
if (m_currentLValue.storesReferenceOnStack())
|
||||||
m_context << eth::Instruction::SWAP1;
|
m_context << eth::Instruction::SWAP1;
|
||||||
}
|
}
|
||||||
m_currentLValue.storeValue(_assignment, *_assignment.getRightHandSide().getType());
|
m_currentLValue.storeValue(*_assignment.getRightHandSide().getType(), _assignment.getLocation());
|
||||||
m_currentLValue.reset();
|
m_currentLValue.reset();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -105,13 +105,13 @@ bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation)
|
|||||||
break;
|
break;
|
||||||
case Token::Delete: // delete
|
case Token::Delete: // delete
|
||||||
solAssert(m_currentLValue.isValid(), "LValue not retrieved.");
|
solAssert(m_currentLValue.isValid(), "LValue not retrieved.");
|
||||||
m_currentLValue.setToZero(_unaryOperation, *_unaryOperation.getSubExpression().getType());
|
m_currentLValue.setToZero(_unaryOperation.getLocation());
|
||||||
m_currentLValue.reset();
|
m_currentLValue.reset();
|
||||||
break;
|
break;
|
||||||
case Token::Inc: // ++ (pre- or postfix)
|
case Token::Inc: // ++ (pre- or postfix)
|
||||||
case Token::Dec: // -- (pre- or postfix)
|
case Token::Dec: // -- (pre- or postfix)
|
||||||
solAssert(m_currentLValue.isValid(), "LValue not retrieved.");
|
solAssert(m_currentLValue.isValid(), "LValue not retrieved.");
|
||||||
m_currentLValue.retrieveValue(_unaryOperation.getType(), _unaryOperation.getLocation());
|
m_currentLValue.retrieveValue(_unaryOperation.getLocation());
|
||||||
if (!_unaryOperation.isPrefixOperation())
|
if (!_unaryOperation.isPrefixOperation())
|
||||||
{
|
{
|
||||||
if (m_currentLValue.storesReferenceOnStack())
|
if (m_currentLValue.storesReferenceOnStack())
|
||||||
@ -128,7 +128,8 @@ bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation)
|
|||||||
// Stack for postfix: *ref [ref] (*ref)+-1
|
// Stack for postfix: *ref [ref] (*ref)+-1
|
||||||
if (m_currentLValue.storesReferenceOnStack())
|
if (m_currentLValue.storesReferenceOnStack())
|
||||||
m_context << eth::Instruction::SWAP1;
|
m_context << eth::Instruction::SWAP1;
|
||||||
m_currentLValue.storeValue(_unaryOperation, *_unaryOperation.getType(), !_unaryOperation.isPrefixOperation());
|
m_currentLValue.storeValue(*_unaryOperation.getType(), _unaryOperation.getLocation(),
|
||||||
|
!_unaryOperation.isPrefixOperation());
|
||||||
m_currentLValue.reset();
|
m_currentLValue.reset();
|
||||||
break;
|
break;
|
||||||
case Token::Add: // +
|
case Token::Add: // +
|
||||||
@ -484,7 +485,7 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess)
|
|||||||
{
|
{
|
||||||
StructType const& type = dynamic_cast<StructType const&>(*_memberAccess.getExpression().getType());
|
StructType const& type = dynamic_cast<StructType const&>(*_memberAccess.getExpression().getType());
|
||||||
m_context << type.getStorageOffsetOfMember(member) << eth::Instruction::ADD;
|
m_context << type.getStorageOffsetOfMember(member) << eth::Instruction::ADD;
|
||||||
m_currentLValue = LValue(m_context, LValue::LValueType::Storage, *_memberAccess.getType());
|
m_currentLValue = LValue(m_context, LValue::LValueType::Storage, _memberAccess.getType());
|
||||||
m_currentLValue.retrieveValueIfLValueNotRequested(_memberAccess);
|
m_currentLValue.retrieveValueIfLValueNotRequested(_memberAccess);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -530,7 +531,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
|
|||||||
appendTypeMoveToMemory(IntegerType(256));
|
appendTypeMoveToMemory(IntegerType(256));
|
||||||
m_context << u256(0) << eth::Instruction::SHA3;
|
m_context << u256(0) << eth::Instruction::SHA3;
|
||||||
|
|
||||||
m_currentLValue = LValue(m_context, LValue::LValueType::Storage, *_indexAccess.getType());
|
m_currentLValue = LValue(m_context, LValue::LValueType::Storage, _indexAccess.getType());
|
||||||
m_currentLValue.retrieveValueIfLValueNotRequested(_indexAccess);
|
m_currentLValue.retrieveValueIfLValueNotRequested(_indexAccess);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -939,8 +940,8 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
|
|||||||
m_context << eth::Instruction::DUP1
|
m_context << eth::Instruction::DUP1
|
||||||
<< structType->getStorageOffsetOfMember(names[i])
|
<< structType->getStorageOffsetOfMember(names[i])
|
||||||
<< eth::Instruction::ADD;
|
<< eth::Instruction::ADD;
|
||||||
m_currentLValue = LValue(m_context, LValue::LValueType::Storage, *types[i]);
|
m_currentLValue = LValue(m_context, LValue::LValueType::Storage, types[i]);
|
||||||
m_currentLValue.retrieveValue(types[i], Location(), true);
|
m_currentLValue.retrieveValue(Location(), true);
|
||||||
solAssert(types[i]->getSizeOnStack() == 1, "Returning struct elements with stack size != 1 not yet implemented.");
|
solAssert(types[i]->getSizeOnStack() == 1, "Returning struct elements with stack size != 1 not yet implemented.");
|
||||||
m_context << eth::Instruction::SWAP1;
|
m_context << eth::Instruction::SWAP1;
|
||||||
retSizeOnStack += types[i]->getSizeOnStack();
|
retSizeOnStack += types[i]->getSizeOnStack();
|
||||||
@ -951,27 +952,51 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
|
|||||||
{
|
{
|
||||||
// simple value
|
// simple value
|
||||||
solAssert(accessorType.getReturnParameterTypes().size() == 1, "");
|
solAssert(accessorType.getReturnParameterTypes().size() == 1, "");
|
||||||
m_currentLValue = LValue(m_context, LValue::LValueType::Storage, *returnType);
|
m_currentLValue = LValue(m_context, LValue::LValueType::Storage, returnType);
|
||||||
m_currentLValue.retrieveValue(returnType, Location(), true);
|
m_currentLValue.retrieveValue(Location(), true);
|
||||||
retSizeOnStack = returnType->getSizeOnStack();
|
retSizeOnStack = returnType->getSizeOnStack();
|
||||||
}
|
}
|
||||||
solAssert(retSizeOnStack <= 15, "Stack too deep.");
|
solAssert(retSizeOnStack <= 15, "Stack too deep.");
|
||||||
m_context << eth::dupInstruction(retSizeOnStack + 1) << eth::Instruction::JUMP;
|
m_context << eth::dupInstruction(retSizeOnStack + 1) << eth::Instruction::JUMP;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExpressionCompiler::LValue::LValue(CompilerContext& _compilerContext, LValueType _type, Type const& _dataType,
|
ExpressionCompiler::LValue::LValue(CompilerContext& _compilerContext, LValueType _type,
|
||||||
unsigned _baseStackOffset):
|
TypePointer const& _dataType, unsigned _baseStackOffset):
|
||||||
m_context(&_compilerContext), m_type(_type), m_baseStackOffset(_baseStackOffset)
|
m_context(&_compilerContext), m_type(_type), m_dataType(_dataType),
|
||||||
|
m_baseStackOffset(_baseStackOffset)
|
||||||
{
|
{
|
||||||
//@todo change the type cast for arrays
|
//@todo change the type cast for arrays
|
||||||
solAssert(_dataType.getStorageSize() <= numeric_limits<unsigned>::max(), "The storage size of " +_dataType.toString() + " should fit in unsigned");
|
solAssert(m_dataType->getStorageSize() <= numeric_limits<unsigned>::max(),
|
||||||
|
"The storage size of " + m_dataType->toString() + " should fit in unsigned");
|
||||||
if (m_type == LValueType::Storage)
|
if (m_type == LValueType::Storage)
|
||||||
m_size = unsigned(_dataType.getStorageSize());
|
m_size = unsigned(m_dataType->getStorageSize());
|
||||||
else
|
else
|
||||||
m_size = unsigned(_dataType.getSizeOnStack());
|
m_size = unsigned(m_dataType->getSizeOnStack());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExpressionCompiler::LValue::retrieveValue(TypePointer const& _type, Location const& _location, bool _remove) const
|
void ExpressionCompiler::LValue::fromIdentifier(Identifier const& _identifier, Declaration const& _declaration)
|
||||||
|
{
|
||||||
|
if (m_context->isLocalVariable(&_declaration))
|
||||||
|
{
|
||||||
|
m_type = LValueType::Stack;
|
||||||
|
m_dataType = _identifier.getType();
|
||||||
|
m_size = m_dataType->getSizeOnStack();
|
||||||
|
m_baseStackOffset = m_context->getBaseStackOffsetOfVariable(_declaration);
|
||||||
|
}
|
||||||
|
else if (m_context->isStateVariable(&_declaration))
|
||||||
|
{
|
||||||
|
*m_context << m_context->getStorageLocationOfVariable(_declaration);
|
||||||
|
m_type = LValueType::Storage;
|
||||||
|
m_dataType = _identifier.getType();
|
||||||
|
solAssert(m_dataType->getStorageSize() <= numeric_limits<unsigned>::max(),
|
||||||
|
"The storage size of " + m_dataType->toString() + " should fit in an unsigned");
|
||||||
|
m_size = unsigned(m_dataType->getStorageSize()); }
|
||||||
|
else
|
||||||
|
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_identifier.getLocation())
|
||||||
|
<< errinfo_comment("Identifier type not supported or identifier not found."));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExpressionCompiler::LValue::retrieveValue(Location const& _location, bool _remove) const
|
||||||
{
|
{
|
||||||
switch (m_type)
|
switch (m_type)
|
||||||
{
|
{
|
||||||
@ -986,10 +1011,10 @@ void ExpressionCompiler::LValue::retrieveValue(TypePointer const& _type, Locatio
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LValueType::Storage:
|
case LValueType::Storage:
|
||||||
retrieveValueFromStorage(_type, _remove);
|
retrieveValueFromStorage(_remove);
|
||||||
break;
|
break;
|
||||||
case LValueType::Memory:
|
case LValueType::Memory:
|
||||||
if (!_type->isValueType())
|
if (!m_dataType->isValueType())
|
||||||
break; // no distinction between value and reference for non-value types
|
break; // no distinction between value and reference for non-value types
|
||||||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_location)
|
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_location)
|
||||||
<< errinfo_comment("Location type not yet implemented."));
|
<< errinfo_comment("Location type not yet implemented."));
|
||||||
@ -1001,9 +1026,9 @@ void ExpressionCompiler::LValue::retrieveValue(TypePointer const& _type, Locatio
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExpressionCompiler::LValue::retrieveValueFromStorage(TypePointer const& _type, bool _remove) const
|
void ExpressionCompiler::LValue::retrieveValueFromStorage(bool _remove) const
|
||||||
{
|
{
|
||||||
if (!_type->isValueType())
|
if (!m_dataType->isValueType())
|
||||||
return; // no distinction between value and reference for non-value types
|
return; // no distinction between value and reference for non-value types
|
||||||
if (!_remove)
|
if (!_remove)
|
||||||
*m_context << eth::Instruction::DUP1;
|
*m_context << eth::Instruction::DUP1;
|
||||||
@ -1020,7 +1045,7 @@ void ExpressionCompiler::LValue::retrieveValueFromStorage(TypePointer const& _ty
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExpressionCompiler::LValue::storeValue(Expression const& _expression, Type const& _sourceType, bool _move) const
|
void ExpressionCompiler::LValue::storeValue(Type const& _sourceType, Location const& _location, bool _move) const
|
||||||
{
|
{
|
||||||
switch (m_type)
|
switch (m_type)
|
||||||
{
|
{
|
||||||
@ -1028,23 +1053,23 @@ void ExpressionCompiler::LValue::storeValue(Expression const& _expression, Type
|
|||||||
{
|
{
|
||||||
unsigned stackDiff = m_context->baseToCurrentStackOffset(unsigned(m_baseStackOffset)) - m_size + 1;
|
unsigned stackDiff = m_context->baseToCurrentStackOffset(unsigned(m_baseStackOffset)) - m_size + 1;
|
||||||
if (stackDiff > 16)
|
if (stackDiff > 16)
|
||||||
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_expression.getLocation())
|
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_location)
|
||||||
<< errinfo_comment("Stack too deep."));
|
<< errinfo_comment("Stack too deep."));
|
||||||
else if (stackDiff > 0)
|
else if (stackDiff > 0)
|
||||||
for (unsigned i = 0; i < m_size; ++i)
|
for (unsigned i = 0; i < m_size; ++i)
|
||||||
*m_context << eth::swapInstruction(stackDiff) << eth::Instruction::POP;
|
*m_context << eth::swapInstruction(stackDiff) << eth::Instruction::POP;
|
||||||
if (!_move)
|
if (!_move)
|
||||||
retrieveValue(_expression.getType(), _expression.getLocation());
|
retrieveValue(_location);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LValueType::Storage:
|
case LValueType::Storage:
|
||||||
// stack layout: value value ... value target_ref
|
// stack layout: value value ... value target_ref
|
||||||
if (_expression.getType()->isValueType())
|
if (m_dataType->isValueType())
|
||||||
{
|
{
|
||||||
if (!_move) // copy values
|
if (!_move) // copy values
|
||||||
{
|
{
|
||||||
if (m_size + 1 > 16)
|
if (m_size + 1 > 16)
|
||||||
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_expression.getLocation())
|
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_location)
|
||||||
<< errinfo_comment("Stack too deep."));
|
<< errinfo_comment("Stack too deep."));
|
||||||
for (unsigned i = 0; i < m_size; ++i)
|
for (unsigned i = 0; i < m_size; ++i)
|
||||||
*m_context << eth::dupInstruction(m_size + 1) << eth::Instruction::SWAP1;
|
*m_context << eth::dupInstruction(m_size + 1) << eth::Instruction::SWAP1;
|
||||||
@ -1064,36 +1089,60 @@ void ExpressionCompiler::LValue::storeValue(Expression const& _expression, Type
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
solAssert(!_move, "Move assign for non-value types not implemented.");
|
solAssert(_sourceType.getCategory() == m_dataType->getCategory(), "");
|
||||||
solAssert(_sourceType.getCategory() == _expression.getType()->getCategory(), "");
|
if (m_dataType->getCategory() == Type::Category::ByteArray)
|
||||||
if (_expression.getType()->getCategory() == Type::Category::ByteArray)
|
|
||||||
CompilerUtils(*m_context).copyByteArrayToStorage(
|
CompilerUtils(*m_context).copyByteArrayToStorage(
|
||||||
dynamic_cast<ByteArrayType const&>(*_expression.getType()),
|
dynamic_cast<ByteArrayType const&>(*m_dataType),
|
||||||
dynamic_cast<ByteArrayType const&>(_sourceType));
|
dynamic_cast<ByteArrayType const&>(_sourceType));
|
||||||
else if (_expression.getType()->getCategory() == Type::Category::Struct)
|
else if (m_dataType->getCategory() == Type::Category::Struct)
|
||||||
{
|
{
|
||||||
//@todo
|
// stack layout: source_ref target_ref
|
||||||
solAssert(false, "Struct copy not yet implemented.");
|
auto const& structType = dynamic_cast<StructType const&>(*m_dataType);
|
||||||
|
solAssert(structType == _sourceType, "Struct assignment with conversion.");
|
||||||
|
for (auto const& member: structType.getMembers())
|
||||||
|
{
|
||||||
|
// assign each member that is not a mapping
|
||||||
|
TypePointer const& memberType = member.second;
|
||||||
|
if (memberType->getCategory() == Type::Category::Mapping)
|
||||||
|
continue;
|
||||||
|
*m_context << structType.getStorageOffsetOfMember(member.first)
|
||||||
|
<< eth::Instruction::DUP3 << eth::Instruction::DUP2
|
||||||
|
<< eth::Instruction::ADD;
|
||||||
|
LValue rightHandSide(*m_context, LValueType::Storage, memberType);
|
||||||
|
rightHandSide.retrieveValue(_location, true);
|
||||||
|
// stack: source_ref target_ref offset source_value...
|
||||||
|
*m_context << eth::dupInstruction(2 + memberType->getSizeOnStack())
|
||||||
|
<< eth::dupInstruction(2 + memberType->getSizeOnStack())
|
||||||
|
<< eth::Instruction::ADD;
|
||||||
|
LValue memberLValue(*m_context, LValueType::Storage, memberType);
|
||||||
|
memberLValue.storeValue(*memberType, _location, true);
|
||||||
|
*m_context << eth::Instruction::POP;
|
||||||
|
}
|
||||||
|
if (_move)
|
||||||
|
*m_context << eth::Instruction::POP;
|
||||||
|
else
|
||||||
|
*m_context << eth::Instruction::SWAP1;
|
||||||
|
*m_context << eth::Instruction::POP;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_expression.getLocation())
|
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_location)
|
||||||
<< errinfo_comment("Invalid non-value type for assignment."));
|
<< errinfo_comment("Invalid non-value type for assignment."));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case LValueType::Memory:
|
case LValueType::Memory:
|
||||||
if (!_expression.getType()->isValueType())
|
if (!m_dataType->isValueType())
|
||||||
break; // no distinction between value and reference for non-value types
|
break; // no distinction between value and reference for non-value types
|
||||||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_expression.getLocation())
|
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_location)
|
||||||
<< errinfo_comment("Location type not yet implemented."));
|
<< errinfo_comment("Location type not yet implemented."));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_expression.getLocation())
|
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_location)
|
||||||
<< errinfo_comment("Unsupported location type."));
|
<< errinfo_comment("Unsupported location type."));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExpressionCompiler::LValue::setToZero(Expression const& _expression, Type const& _type) const
|
void ExpressionCompiler::LValue::setToZero(Location const& _location) const
|
||||||
{
|
{
|
||||||
switch (m_type)
|
switch (m_type)
|
||||||
{
|
{
|
||||||
@ -1101,7 +1150,7 @@ void ExpressionCompiler::LValue::setToZero(Expression const& _expression, Type c
|
|||||||
{
|
{
|
||||||
unsigned stackDiff = m_context->baseToCurrentStackOffset(unsigned(m_baseStackOffset));
|
unsigned stackDiff = m_context->baseToCurrentStackOffset(unsigned(m_baseStackOffset));
|
||||||
if (stackDiff > 16)
|
if (stackDiff > 16)
|
||||||
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_expression.getLocation())
|
BOOST_THROW_EXCEPTION(CompilerError() << errinfo_sourceLocation(_location)
|
||||||
<< errinfo_comment("Stack too deep."));
|
<< errinfo_comment("Stack too deep."));
|
||||||
solAssert(stackDiff >= m_size - 1, "");
|
solAssert(stackDiff >= m_size - 1, "");
|
||||||
for (unsigned i = 0; i < m_size; ++i)
|
for (unsigned i = 0; i < m_size; ++i)
|
||||||
@ -1110,8 +1159,8 @@ void ExpressionCompiler::LValue::setToZero(Expression const& _expression, Type c
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case LValueType::Storage:
|
case LValueType::Storage:
|
||||||
if (_type.getCategory() == Type::Category::ByteArray)
|
if (m_dataType->getCategory() == Type::Category::ByteArray)
|
||||||
CompilerUtils(*m_context).clearByteArray(dynamic_cast<ByteArrayType const&>(_type));
|
CompilerUtils(*m_context).clearByteArray(dynamic_cast<ByteArrayType const&>(*m_dataType));
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (m_size == 0)
|
if (m_size == 0)
|
||||||
@ -1125,11 +1174,11 @@ void ExpressionCompiler::LValue::setToZero(Expression const& _expression, Type c
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case LValueType::Memory:
|
case LValueType::Memory:
|
||||||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_expression.getLocation())
|
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_location)
|
||||||
<< errinfo_comment("Location type not yet implemented."));
|
<< errinfo_comment("Location type not yet implemented."));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_expression.getLocation())
|
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_location)
|
||||||
<< errinfo_comment("Unsupported location type."));
|
<< errinfo_comment("Unsupported location type."));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1139,36 +1188,10 @@ void ExpressionCompiler::LValue::retrieveValueIfLValueNotRequested(Expression co
|
|||||||
{
|
{
|
||||||
if (!_expression.lvalueRequested())
|
if (!_expression.lvalueRequested())
|
||||||
{
|
{
|
||||||
retrieveValue(_expression.getType(), _expression.getLocation(), true);
|
retrieveValue(_expression.getLocation(), true);
|
||||||
reset();
|
reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExpressionCompiler::LValue::fromStateVariable(Declaration const& _varDecl, TypePointer const& _type)
|
|
||||||
{
|
|
||||||
m_type = LValueType::Storage;
|
|
||||||
solAssert(_type->getStorageSize() <= numeric_limits<unsigned>::max(), "The storage size of " + _type->toString() + " should fit in an unsigned");
|
|
||||||
*m_context << m_context->getStorageLocationOfVariable(_varDecl);
|
|
||||||
m_size = unsigned(_type->getStorageSize());
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExpressionCompiler::LValue::fromIdentifier(Identifier const& _identifier, Declaration const& _declaration)
|
|
||||||
{
|
|
||||||
if (m_context->isLocalVariable(&_declaration))
|
|
||||||
{
|
|
||||||
m_type = LValueType::Stack;
|
|
||||||
m_size = _identifier.getType()->getSizeOnStack();
|
|
||||||
m_baseStackOffset = m_context->getBaseStackOffsetOfVariable(_declaration);
|
|
||||||
}
|
|
||||||
else if (m_context->isStateVariable(&_declaration))
|
|
||||||
{
|
|
||||||
fromStateVariable(_declaration, _identifier.getType());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_sourceLocation(_identifier.getLocation())
|
|
||||||
<< errinfo_comment("Identifier type not supported or identifier not found."));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,8 +22,10 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
#include <boost/noncopyable.hpp>
|
#include <boost/noncopyable.hpp>
|
||||||
#include <libdevcore/Common.h>
|
#include <libdevcore/Common.h>
|
||||||
|
#include <libsolidity/BaseTypes.h>
|
||||||
#include <libsolidity/ASTVisitor.h>
|
#include <libsolidity/ASTVisitor.h>
|
||||||
|
|
||||||
namespace dev {
|
namespace dev {
|
||||||
@ -37,6 +39,7 @@ namespace solidity {
|
|||||||
class CompilerContext;
|
class CompilerContext;
|
||||||
class Type;
|
class Type;
|
||||||
class IntegerType;
|
class IntegerType;
|
||||||
|
class ByteArrayType;
|
||||||
class StaticStringType;
|
class StaticStringType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -119,14 +122,13 @@ private:
|
|||||||
enum class LValueType { None, Stack, Memory, Storage };
|
enum class LValueType { None, Stack, Memory, Storage };
|
||||||
|
|
||||||
explicit LValue(CompilerContext& _compilerContext): m_context(&_compilerContext) { reset(); }
|
explicit LValue(CompilerContext& _compilerContext): m_context(&_compilerContext) { reset(); }
|
||||||
LValue(CompilerContext& _compilerContext, LValueType _type, Type const& _dataType, unsigned _baseStackOffset = 0);
|
LValue(CompilerContext& _compilerContext, LValueType _type,
|
||||||
|
std::shared_ptr<Type const> const& _dataType, unsigned _baseStackOffset = 0);
|
||||||
|
|
||||||
/// Set type according to the declaration and retrieve the reference.
|
/// Set type according to the declaration and retrieve the reference.
|
||||||
/// @a _expression is the current expression
|
/// @a _expression is the current expression
|
||||||
void fromIdentifier(Identifier const& _identifier, Declaration const& _declaration);
|
void fromIdentifier(Identifier const& _identifier, Declaration const& _declaration);
|
||||||
/// Convenience function to set type for a state variable and retrieve the reference
|
void reset() { m_type = LValueType::None; m_dataType.reset(); m_baseStackOffset = 0; m_size = 0; }
|
||||||
void fromStateVariable(Declaration const& _varDecl, TypePointer const& _type);
|
|
||||||
void reset() { m_type = LValueType::None; m_baseStackOffset = 0; m_size = 0; }
|
|
||||||
|
|
||||||
bool isValid() const { return m_type != LValueType::None; }
|
bool isValid() const { return m_type != LValueType::None; }
|
||||||
bool isInOnStack() const { return m_type == LValueType::Stack; }
|
bool isInOnStack() const { return m_type == LValueType::Stack; }
|
||||||
@ -138,30 +140,29 @@ private:
|
|||||||
|
|
||||||
/// Copies the value of the current lvalue to the top of the stack and, if @a _remove is true,
|
/// Copies the value of the current lvalue to the top of the stack and, if @a _remove is true,
|
||||||
/// also removes the reference from the stack (note that is does not reset the type to @a NONE).
|
/// also removes the reference from the stack (note that is does not reset the type to @a NONE).
|
||||||
/// @a _type is the type of the current expression and @ _location its location, used for error reporting.
|
/// @a _location source location of the current expression, used for error reporting.
|
||||||
/// @a _location can be a nullptr for expressions that don't have an actual ASTNode equivalent
|
void retrieveValue(Location const& _location, bool _remove = false) const;
|
||||||
void retrieveValue(TypePointer const& _type, Location const& _location, bool _remove = false) const;
|
/// Moves a value from the stack to the lvalue. Removes the value if @a _move is true.
|
||||||
/// Stores a value (from the stack directly beneath the reference, which is assumed to
|
/// @a _location is the source location of the expression that caused this operation.
|
||||||
/// be on the top of the stack, if any) in the lvalue and removes the reference.
|
/// Stack pre: [lvalue_ref] value
|
||||||
/// Also removes the stored value from the stack if @a _move is
|
/// Stack post if !_move: value_of(lvalue_ref)
|
||||||
/// true. @a _expression is the current expression, used for error reporting.
|
void storeValue(Type const& _sourceType, Location const& _location = Location(), bool _move = false) const;
|
||||||
/// @a _sourceType is the type of the expression that is assigned.
|
|
||||||
void storeValue(Expression const& _expression, Type const& _sourceType, bool _move = false) const;
|
|
||||||
/// Stores zero in the lvalue.
|
/// Stores zero in the lvalue.
|
||||||
/// @a _expression is the current expression, used for error reporting.
|
/// @a _location is the source location of the requested operation
|
||||||
void setToZero(Expression const& _expression, Type const& _type) const;
|
void setToZero(Location const& _location = Location()) const;
|
||||||
/// Convenience function to convert the stored reference to a value and reset type to NONE if
|
/// Convenience function to convert the stored reference to a value and reset type to NONE if
|
||||||
/// the reference was not requested by @a _expression.
|
/// the reference was not requested by @a _expression.
|
||||||
void retrieveValueIfLValueNotRequested(Expression const& _expression);
|
void retrieveValueIfLValueNotRequested(Expression const& _expression);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// Convenience function to retrieve Value from Storage. Specific version of @ref retrieveValue
|
/// Convenience function to retrieve Value from Storage. Specific version of @ref retrieveValue
|
||||||
void retrieveValueFromStorage(TypePointer const& _type, bool _remove = false) const;
|
void retrieveValueFromStorage(bool _remove = false) const;
|
||||||
/// Copies from a byte array to a byte array in storage, both references on the stack.
|
/// Copies from a byte array to a byte array in storage, both references on the stack.
|
||||||
void copyByteArrayToStorage(ByteArrayType const& _targetType, ByteArrayType const& _sourceType) const;
|
void copyByteArrayToStorage(ByteArrayType const& _targetType, ByteArrayType const& _sourceType) const;
|
||||||
|
|
||||||
CompilerContext* m_context;
|
CompilerContext* m_context;
|
||||||
LValueType m_type = LValueType::None;
|
LValueType m_type = LValueType::None;
|
||||||
|
std::shared_ptr<Type const> m_dataType;
|
||||||
/// If m_type is STACK, this is base stack offset (@see
|
/// If m_type is STACK, this is base stack offset (@see
|
||||||
/// CompilerContext::getBaseStackOffsetOfVariable) of a local variable.
|
/// CompilerContext::getBaseStackOffsetOfVariable) of a local variable.
|
||||||
unsigned m_baseStackOffset = 0;
|
unsigned m_baseStackOffset = 0;
|
||||||
|
@ -653,7 +653,7 @@ u256 StructType::getStorageOffsetOfMember(string const& _name) const
|
|||||||
{
|
{
|
||||||
//@todo cache member offset?
|
//@todo cache member offset?
|
||||||
u256 offset;
|
u256 offset;
|
||||||
for (ASTPointer<VariableDeclaration> variable: m_struct.getMembers())
|
for (ASTPointer<VariableDeclaration> const& variable: m_struct.getMembers())
|
||||||
{
|
{
|
||||||
if (variable->getName() == _name)
|
if (variable->getName() == _name)
|
||||||
return offset;
|
return offset;
|
||||||
|
Loading…
Reference in New Issue
Block a user