Browse Source

added implementation to append code for State variable accessor

fixed tests
cl-refactor
Liana Husikyan 10 years ago
parent
commit
46eb3f366b
  1. 8
      libsolidity/CompilerUtils.cpp
  2. 2
      libsolidity/CompilerUtils.h
  3. 48
      libsolidity/ExpressionCompiler.cpp
  4. 25
      libsolidity/Types.cpp
  5. 9
      test/SolidityEndToEndTest.cpp

8
libsolidity/CompilerUtils.cpp

@ -157,8 +157,12 @@ void CompilerUtils::copyToStackTop(unsigned _stackDepth, unsigned _itemSize)
void CompilerUtils::popStackElement(Type const& _type) void CompilerUtils::popStackElement(Type const& _type)
{ {
unsigned const size = _type.getSizeOnStack(); popStackSlots(_type.getSizeOnStack());
for (unsigned i = 0; i < size; ++i) }
void CompilerUtils::popStackSlots(size_t _amount)
{
for (size_t i = 0; i < _amount; ++i)
m_context << eth::Instruction::POP; m_context << eth::Instruction::POP;
} }

2
libsolidity/CompilerUtils.h

@ -79,6 +79,8 @@ public:
void copyToStackTop(unsigned _stackDepth, unsigned _itemSize); void copyToStackTop(unsigned _stackDepth, unsigned _itemSize);
/// Removes the current value from the top of the stack. /// Removes the current value from the top of the stack.
void popStackElement(Type const& _type); void popStackElement(Type const& _type);
/// Removes element from the top of the stack _amount times.
void popStackSlots(size_t _amount);
template <class T> template <class T>
static unsigned getSizeOnStack(std::vector<T> const& _variables); static unsigned getSizeOnStack(std::vector<T> const& _variables);

48
libsolidity/ExpressionCompiler.cpp

@ -60,43 +60,37 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
CompilerContext::LocationSetter locationSetter(m_context, _varDecl); CompilerContext::LocationSetter locationSetter(m_context, _varDecl);
FunctionType accessorType(_varDecl); FunctionType accessorType(_varDecl);
unsigned length = 0;
TypePointers const& paramTypes = accessorType.getParameterTypes(); TypePointers const& paramTypes = accessorType.getParameterTypes();
// to exclude the last key if it is an array
TypePointer finalMappingValueType = _varDecl.getType();
while (finalMappingValueType->getCategory() == Type::Category::Mapping)
finalMappingValueType = dynamic_cast<MappingType const&>(*finalMappingValueType).getValueType();
bool finalIsArrayType = finalMappingValueType->getCategory() == Type::Category::Array;
TypePointers mappingKeys(paramTypes);
if (finalIsArrayType)
mappingKeys.pop_back();
// move mapping arguments to memory
for (TypePointer const& paramType: boost::adaptors::reverse(mappingKeys))
length += CompilerUtils(m_context).storeInMemory(length, *paramType, true);
// retrieve the position of the variable // retrieve the position of the variable
auto const& location = m_context.getStorageLocationOfVariable(_varDecl); auto const& location = m_context.getStorageLocationOfVariable(_varDecl);
m_context << location.first; m_context << location.first;
TypePointer returnType = _varDecl.getType(); TypePointer returnType = _varDecl.getType();
for (TypePointer const& paramType: mappingKeys) for (size_t i = 0; i < paramTypes.size(); ++i)
{
// move offset to memory
CompilerUtils(m_context).storeInMemory(length);
unsigned argLen = paramType->getCalldataEncodedSize();
length -= argLen;
m_context << u256(argLen + 32) << u256(length) << eth::Instruction::SHA3;
returnType = dynamic_cast<MappingType const&>(*returnType).getValueType();
}
if (finalMappingValueType->isDynamicallySized())
{ {
if (auto mappingType = dynamic_cast<MappingType const*>(returnType.get()))
{
// move storage offset to memory.
CompilerUtils(m_context).storeInMemory(32);
//move key to memory.
CompilerUtils(m_context).copyToStackTop(paramTypes.size() - i, 1);
CompilerUtils(m_context).storeInMemory(0);
m_context << u256(64) << u256(0) << eth::Instruction::SHA3;
returnType = mappingType->getValueType();
}
else if (auto arrayType = dynamic_cast<ArrayType const*>(returnType.get()))
{
CompilerUtils(m_context).copyToStackTop(paramTypes.size() - i + 1, 1);
ArrayUtils(m_context).accessIndex(*arrayType);
returnType = arrayType->getBaseType();
}
else
solAssert(false, "Index access is allowed only for \"mapping\" and \"array\" types.");
} }
//remove index arguments.
CompilerUtils(m_context).popStackSlots(paramTypes.size());
unsigned retSizeOnStack = 0; unsigned retSizeOnStack = 0;
solAssert(accessorType.getReturnParameterTypes().size() >= 1, ""); solAssert(accessorType.getReturnParameterTypes().size() >= 1, "");

25
libsolidity/Types.cpp

@ -985,11 +985,23 @@ FunctionType::FunctionType(VariableDeclaration const& _varDecl):
vector<string> paramNames; vector<string> paramNames;
auto returnType = _varDecl.getType(); auto returnType = _varDecl.getType();
while (auto mappingType = dynamic_cast<MappingType const*>(returnType.get())) while (true)
{ {
params.push_back(mappingType->getKeyType()); auto mappingType = dynamic_cast<MappingType const*>(returnType.get());
paramNames.push_back(""); auto arrayType = dynamic_cast<ArrayType const*>(returnType.get());
returnType = mappingType->getValueType(); if (mappingType)
{
params.push_back(mappingType->getKeyType());
paramNames.push_back("");
returnType = mappingType->getValueType();
}
else if (arrayType)
{
returnType = arrayType->getBaseType();
params.push_back(make_shared<IntegerType>(256));
}
else
break;
} }
TypePointers retParams; TypePointers retParams;
@ -1002,11 +1014,6 @@ FunctionType::FunctionType(VariableDeclaration const& _varDecl):
retParamNames.push_back(member.first); retParamNames.push_back(member.first);
retParams.push_back(member.second); retParams.push_back(member.second);
} }
} else if (auto arrayType = dynamic_cast<ArrayType const*>(returnType.get()))
{
params.push_back(make_shared<IntegerType>(256));
paramNames.push_back("");
returnType = arrayType->getBaseType();
} }
else else
{ {

9
test/SolidityEndToEndTest.cpp

@ -970,8 +970,8 @@ BOOST_AUTO_TEST_CASE(array_accessor)
{ {
char const* sourceCode = R"( char const* sourceCode = R"(
contract test { contract test {
uint[8] data; uint[8] public data;
uint[] dynamicData; uint[] public dynamicData;
function test() { function test() {
data[2] = 8; data[2] = 8;
dynamicData.length = 3; dynamicData.length = 3;
@ -980,6 +980,7 @@ BOOST_AUTO_TEST_CASE(array_accessor)
} }
)"; )";
compileAndRun(sourceCode); compileAndRun(sourceCode);
auto res = callContractFunction("data(uint256)", 2) ;
BOOST_CHECK(callContractFunction("data(uint256)", 2) == encodeArgs(8)); BOOST_CHECK(callContractFunction("data(uint256)", 2) == encodeArgs(8));
BOOST_CHECK(callContractFunction("data(uint256)", 8) == encodeArgs()); BOOST_CHECK(callContractFunction("data(uint256)", 8) == encodeArgs());
BOOST_CHECK(callContractFunction("dynamicData(uint256)", 2) == encodeArgs(8)); BOOST_CHECK(callContractFunction("dynamicData(uint256)", 2) == encodeArgs(8));
@ -990,8 +991,8 @@ BOOST_AUTO_TEST_CASE(accessors_mapping_for_array)
{ {
char const* sourceCode = R"( char const* sourceCode = R"(
contract test { contract test {
mapping(uint => uint[8]) data; mapping(uint => uint[8]) public data;
mapping(uint => uint[]) dynamicData; mapping(uint => uint[]) public dynamicData;
function test() { function test() {
data[2][2] = 8; data[2][2] = 8;
dynamicData[2].length = 3; dynamicData[2].length = 3;

Loading…
Cancel
Save