Browse Source

Accessors for structs.

cl-refactor
Christian 10 years ago
parent
commit
6219085ad9
  1. 47
      libsolidity/ExpressionCompiler.cpp
  2. 23
      libsolidity/Types.cpp
  3. 18
      test/SolidityEndToEndTest.cpp

47
libsolidity/ExpressionCompiler.cpp

@ -867,19 +867,17 @@ unsigned ExpressionCompiler::appendExpressionCopyToMemory(Type const& _expectedT
void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& _varDecl) void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const& _varDecl)
{ {
FunctionType thisType(_varDecl); FunctionType accessorType(_varDecl);
solAssert(thisType.getReturnParameterTypes().size() == 1, "");
TypePointer const& resultType = thisType.getReturnParameterTypes().front();
unsigned sizeOnStack;
unsigned length = 0; unsigned length = 0;
TypePointers const& params = thisType.getParameterTypes(); TypePointers const& params = accessorType.getParameterTypes();
// move arguments to memory // move arguments to memory
for (TypePointer const& param: boost::adaptors::reverse(params)) for (TypePointer const& param: boost::adaptors::reverse(params))
length += appendTypeConversionAndMoveToMemory(*param, *param, Location(), length); length += appendTypeConversionAndMoveToMemory(*param, *param, Location(), length);
// retrieve the position of the mapping // retrieve the position of the variable
m_context << m_context.getStorageLocationOfVariable(_varDecl); m_context << m_context.getStorageLocationOfVariable(_varDecl);
TypePointer returnType = _varDecl.getType();
for (TypePointer const& param: params) for (TypePointer const& param: params)
{ {
@ -888,13 +886,40 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
unsigned argLen = CompilerUtils::getPaddedSize(param->getCalldataEncodedSize()); unsigned argLen = CompilerUtils::getPaddedSize(param->getCalldataEncodedSize());
length -= argLen; length -= argLen;
m_context << u256(argLen + 32) << u256(length) << eth::Instruction::SHA3; m_context << u256(argLen + 32) << u256(length) << eth::Instruction::SHA3;
returnType = dynamic_cast<MappingType const&>(*returnType).getValueType();
} }
m_currentLValue = LValue(m_context, LValue::STORAGE, *resultType); unsigned retSizeOnStack = 0;
m_currentLValue.retrieveValue(resultType, Location(), true); solAssert(accessorType.getReturnParameterTypes().size() >= 1, "");
sizeOnStack = resultType->getSizeOnStack(); if (StructType const* structType = dynamic_cast<StructType const*>(returnType.get()))
solAssert(sizeOnStack <= 15, "Stack too deep."); {
m_context << eth::dupInstruction(sizeOnStack + 1) << eth::Instruction::JUMP; auto const& names = accessorType.getReturnParameterNames();
auto const& types = accessorType.getReturnParameterTypes();
// struct
for (size_t i = 0; i < names.size(); ++i)
{
m_context << eth::Instruction::DUP1
<< structType->getStorageOffsetOfMember(names[i])
<< eth::Instruction::ADD;
m_currentLValue = LValue(m_context, LValue::STORAGE, *types[i]);
m_currentLValue.retrieveValue(types[i], Location(), true);
solAssert(types[i]->getSizeOnStack() == 1, "Returning struct elements with stack size != 1 not yet implemented.");
m_context << eth::Instruction::SWAP1;
retSizeOnStack += types[i]->getSizeOnStack();
}
m_context << eth::Instruction::POP;
}
else
{
// simple value
solAssert(accessorType.getReturnParameterTypes().size() == 1, "");
m_currentLValue = LValue(m_context, LValue::STORAGE, *returnType);
m_currentLValue.retrieveValue(returnType, Location(), true);
retSizeOnStack = returnType->getSizeOnStack();
}
solAssert(retSizeOnStack <= 15, "Stack too deep.");
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, Type const& _dataType,

23
libsolidity/Types.cpp

@ -643,22 +643,31 @@ FunctionType::FunctionType(VariableDeclaration const& _varDecl):
{ {
TypePointers params; TypePointers params;
vector<string> paramNames; vector<string> paramNames;
TypePointers retParams; auto returnType = _varDecl.getType();
vector<string> retParamNames;
TypePointer varDeclType = _varDecl.getType();
auto mappingType = dynamic_cast<MappingType const*>(varDeclType.get());
auto returnType = varDeclType;
while (mappingType != nullptr) while (auto mappingType = dynamic_cast<MappingType const*>(returnType.get()))
{ {
params.push_back(mappingType->getKeyType()); params.push_back(mappingType->getKeyType());
paramNames.push_back(""); paramNames.push_back("");
returnType = mappingType->getValueType(); returnType = mappingType->getValueType();
mappingType = dynamic_cast<MappingType const*>(mappingType->getValueType().get());
} }
TypePointers retParams;
vector<string> retParamNames;
if (auto structType = dynamic_cast<StructType const*>(returnType.get()))
{
for (pair<string, TypePointer> const& member: structType->getMembers())
if (member.second->canLiveOutsideStorage())
{
retParamNames.push_back(member.first);
retParams.push_back(member.second);
}
}
else
{
retParams.push_back(returnType); retParams.push_back(returnType);
retParamNames.push_back(""); retParamNames.push_back("");
}
swap(params, m_parameterTypes); swap(params, m_parameterTypes);
swap(paramNames, m_parameterNames); swap(paramNames, m_parameterNames);

18
test/SolidityEndToEndTest.cpp

@ -959,6 +959,24 @@ BOOST_AUTO_TEST_CASE(complex_accessors)
BOOST_CHECK(callContractFunction("to_multiple_map(uint256,uint256)", 42, 23) == encodeArgs(31)); BOOST_CHECK(callContractFunction("to_multiple_map(uint256,uint256)", 42, 23) == encodeArgs(31));
} }
BOOST_AUTO_TEST_CASE(struct_accessor)
{
char const* sourceCode = R"(
contract test {
struct Data { uint a; uint8 b; mapping(uint => uint) c; bool d; }
mapping(uint => Data) public data;
function test() {
data[7].a = 1;
data[7].b = 2;
data[7].c[0] = 3;
data[7].d = true;
}
}
)";
compileAndRun(sourceCode);
BOOST_CHECK(callContractFunction("data(uint256)", 7) == encodeArgs(1, 2, true));
}
BOOST_AUTO_TEST_CASE(balance) BOOST_AUTO_TEST_CASE(balance)
{ {
char const* sourceCode = "contract test {\n" char const* sourceCode = "contract test {\n"

Loading…
Cancel
Save