diff options
author | Lefteris Karapetsas <lefteris@refu.co> | 2015-10-13 22:55:59 +0800 |
---|---|---|
committer | Lefteris Karapetsas <lefteris@refu.co> | 2015-10-15 16:52:30 +0800 |
commit | a521843f6b0bf019a19d9a377f4bbbc473083151 (patch) | |
tree | b8d2d294cccefceadc0c8582adbfcdee72b13ebc | |
parent | 3287cd464fc6b73ba5da2a94030ab202370f647a (diff) | |
download | dexon-solidity-a521843f6b0bf019a19d9a377f4bbbc473083151.tar.gz dexon-solidity-a521843f6b0bf019a19d9a377f4bbbc473083151.tar.zst dexon-solidity-a521843f6b0bf019a19d9a377f4bbbc473083151.zip |
Implement Dynamic array push and fix test
Still a work in progress. There is a disturbance in the stack at the
moment and that's why there are some cout statements left for debugging.
-rw-r--r-- | libsolidity/ExpressionCompiler.cpp | 51 | ||||
-rw-r--r-- | libsolidity/Types.cpp | 26 | ||||
-rw-r--r-- | libsolidity/Types.h | 12 | ||||
-rw-r--r-- | test/libsolidity/SolidityEndToEndTest.cpp | 11 |
4 files changed, 79 insertions, 21 deletions
diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index c25202b6..5ff1363f 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -623,6 +623,43 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) appendExternalFunctionCall(function, arguments); break; } + case Location::ArrayPush: + { + cout << "Beginning " << m_context.stackHeight() << endl; + solAssert(function.parameterTypes().size() == 1, ""); + solAssert(!!function.parameterTypes()[0], ""); + TypePointer const& paramType = function.parameterTypes()[0]; + ArrayType arrayType(DataLocation::Storage, paramType); + // get the current length + ArrayUtils(m_context).retrieveLength(arrayType); + m_context << eth::Instruction::DUP1; + cout << "After DUP1 " << m_context.stackHeight() << endl; + // stack: ArrayReference currentLength currentLength + m_context << u256(1) << eth::Instruction::ADD; + // stack: ArrayReference currentLength newLength + m_context << eth::Instruction::DUP3 << eth::Instruction::DUP2; + ArrayUtils(m_context).resizeDynamicArray(arrayType); + cout << "After Resize Dynamic Array " << m_context.stackHeight() << endl; + m_context << eth::Instruction::SWAP2 << eth::Instruction::SWAP1; + // stack: newLength ArrayReference oldLength + ArrayUtils(m_context).accessIndex(arrayType, false); + cout << "After Access Index " << m_context.stackHeight() << endl; + + // stack: newLength storageSlot slotOffset + arguments[0]->accept(*this); + // stack: newLength storageSlot slotOffset argValue + TypePointer type = arguments[0]->annotation().type; + utils().convertType(*type, *type->mobileType()); + type = type->mobileType(); + utils().moveToStackTop(1 + type->sizeOnStack()); + utils().moveToStackTop(1 + type->sizeOnStack()); + // stack: newLength argValue storageSlot slotOffset + StorageItem(m_context, *paramType).storeValue(*type, _functionCall.location(), true); + break; + } + case Location::ByteArrayPush: + // TODO + break; default: BOOST_THROW_EXCEPTION(InternalCompilerError() << errinfo_comment("Invalid function type.")); } @@ -806,16 +843,12 @@ void ExpressionCompiler::endVisit(MemberAccess const& _memberAccess) break; } } - else if (member == "push" && type.isDynamicallySized() && type.location() == DataLocation::Storage) + else if (member == "push") { - if (type.isByteArray()) - { - solAssert(!type.isString(), "Index access to string is not allowed."); - setLValue<StorageByteArrayElement>(_indexAccess); - } - else - setLValueToStorageItem(_indexAccess); - setLValue<StorageArrayLength>(_memberAccess, type); + solAssert( + type.isDynamicallySized() && type.location() == DataLocation::Storage, + "Tried to use .push() on a non-dynamically sized array" + ); } else solAssert(false, "Illegal array member."); diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index c800e288..371a3456 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -858,6 +858,28 @@ string ArrayType::canonicalName(bool _addDataLocation) const return ret; } +MemberList const& ArrayType::members() const +{ + if (!m_members) + { + MemberList::MemberMap members; + if (!isString()) + { + members.push_back({"length", make_shared<IntegerType>(256)}); + if (isDynamicallySized() && location() == DataLocation::Storage) + members.push_back({"push", make_shared<FunctionType>( + TypePointers{baseType()}, + TypePointers{make_shared<IntegerType>(256)}, + strings{string()}, + strings{string()}, + isByteArray() ? FunctionType::Location::ByteArrayPush : FunctionType::Location::ArrayPush + )}); + } + m_members.reset(new MemberList(members)); + } + return *m_members; +} + TypePointer ArrayType::encodingType() const { if (location() == DataLocation::Storage) @@ -913,8 +935,6 @@ TypePointer ArrayType::copyForLocation(DataLocation _location, bool _isPointer) return copy; } -const MemberList ArrayType::s_arrayTypeMemberList({{"length", make_shared<IntegerType>(256)}}); - bool ContractType::operator==(Type const& _other) const { if (_other.category() != category()) @@ -1422,6 +1442,8 @@ unsigned FunctionType::sizeOnStack() const size = 1; else if (location == Location::Internal) size = 1; + else if (location == Location::ArrayPush || location == Location::ByteArrayPush) + size = 1; if (m_gasSet) size++; if (m_valueSet) diff --git a/libsolidity/Types.h b/libsolidity/Types.h index e73cd3cd..5c4aacdc 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -505,10 +505,7 @@ public: virtual unsigned sizeOnStack() const override; virtual std::string toString(bool _short) const override; virtual std::string canonicalName(bool _addDataLocation) const override; - virtual MemberList const& members() const override - { - return isString() ? EmptyMemberList : s_arrayTypeMemberList; - } + virtual MemberList const& members() const override; virtual TypePointer encodingType() const override; virtual TypePointer decodingType() const override; virtual TypePointer interfaceType(bool _inLibrary) const override; @@ -532,7 +529,8 @@ private: TypePointer m_baseType; bool m_hasDynamicLength = true; u256 m_length; - static const MemberList s_arrayTypeMemberList; + /// List of member types, will be lazy-initialized because of recursive references. + mutable std::unique_ptr<MemberList> m_members; }; /** @@ -736,7 +734,9 @@ public: Event, ///< syntactic sugar for LOG* SetGas, ///< modify the default gas value for the function call SetValue, ///< modify the default value transfer for the function call - BlockHash ///< BLOCKHASH + BlockHash, ///< BLOCKHASH + ArrayPush, ///< .push() to a dynamically sized array in storage + ByteArrayPush ///< .push() to a dynamically sized byte array in storage }; virtual Category category() const override { return Category::Function; } diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index b78ea8ec..7ae97db2 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -3481,16 +3481,19 @@ BOOST_AUTO_TEST_CASE(array_push) { char const* sourceCode = R"( contract c { - int[] data; - function test() returns (uint) { + uint[] data; + function test() returns (uint x, uint y, uint z, uint l) { data.push(5); + x = data[0]; data.push(4); - return data.push(3); + y = data[1]; + l = data.push(3); + z = data[2]; } } )"; compileAndRun(sourceCode); - BOOST_CHECK(callContractFunction("test()") == encodeArgs(3)); + BOOST_CHECK(callContractFunction("test()") == encodeArgs(5, 4, 3, 2)); } BOOST_AUTO_TEST_CASE(external_array_args) |