/* This file is part of solidity. solidity is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. solidity is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with solidity. If not, see . */ /** * Generator for code that handles LValues. */ #include #include #include #include #include #include using namespace std; using namespace solidity; using namespace solidity::frontend; IRLocalVariable::IRLocalVariable( IRGenerationContext& _context, VariableDeclaration const& _varDecl ): IRLValue(_context.utils(), _varDecl.annotation().type), m_variableName(_context.localVariableName(_varDecl)) { } string IRLocalVariable::storeValue(string const& _value, Type const& _type) const { solAssert(_type == *m_type, "Storing different types - not necessarily a problem."); return m_variableName + " := " + _value + "\n"; } string IRLocalVariable::setToZero() const { return storeValue(m_utils.zeroValueFunction(*m_type) + "()", *m_type); } IRStorageItem::IRStorageItem( IRGenerationContext& _context, VariableDeclaration const& _varDecl ): IRStorageItem( _context.utils(), *_varDecl.annotation().type, _context.storageLocationOfVariable(_varDecl) ) { } IRStorageItem::IRStorageItem( YulUtilFunctions _utils, Type const& _type, std::pair slot_offset ): IRLValue(std::move(_utils), &_type), m_slot(util::toCompactHexWithPrefix(slot_offset.first)), m_offset(slot_offset.second) { } IRStorageItem::IRStorageItem( YulUtilFunctions _utils, string _slot, boost::variant _offset, Type const& _type ): IRLValue(std::move(_utils), &_type), m_slot(std::move(_slot)), m_offset(std::move(_offset)) { solAssert(!m_offset.empty(), ""); solAssert(!m_slot.empty(), ""); } string IRStorageItem::retrieveValue() const { if (!m_type->isValueType()) return m_slot; solUnimplementedAssert(m_type->category() != Type::Category::Function, ""); if (m_offset.type() == typeid(string)) return m_utils.readFromStorageDynamic(*m_type, false) + "(" + m_slot + ", " + boost::get(m_offset) + ")"; else if (m_offset.type() == typeid(unsigned)) return m_utils.readFromStorage(*m_type, boost::get(m_offset), false) + "(" + m_slot + ")"; solAssert(false, ""); } string IRStorageItem::storeValue(string const& _value, Type const& _sourceType) const { if (m_type->isValueType()) solAssert(_sourceType == *m_type, "Different type, but might not be an error."); std::optional offset; if (m_offset.type() == typeid(unsigned)) offset = get(m_offset); return m_utils.updateStorageValueFunction(*m_type, offset) + "(" + m_slot + (m_offset.type() == typeid(string) ? (", " + get(m_offset)) : "" ) + ", " + _value + ")\n"; } string IRStorageItem::setToZero() const { return m_utils.storageSetToZeroFunction(*m_type) + "(" + m_slot + ", " + ( m_offset.type() == typeid(unsigned) ? to_string(get(m_offset)) : get(m_offset) ) + ")\n"; } IRMemoryItem::IRMemoryItem( YulUtilFunctions _utils, std::string _address, bool _byteArrayElement, Type const& _type ): IRLValue(std::move(_utils), &_type), m_address(move(_address)), m_byteArrayElement(_byteArrayElement) { } string IRMemoryItem::retrieveValue() const { if (m_byteArrayElement) return m_utils.cleanupFunction(*m_type) + "(mload(" + m_address + "))"; if (m_type->isValueType()) return m_utils.readFromMemory(*m_type) + "(" + m_address + ")"; else return "mload(" + m_address + ")"; } string IRMemoryItem::storeValue(string const& _value, Type const& _type) const { if (!m_type->isValueType()) { solUnimplementedAssert(_type == *m_type, "Conversion not implemented for assignment to memory."); solAssert(m_type->sizeOnStack() == 1, ""); solAssert(dynamic_cast(m_type), ""); return "mstore(" + m_address + ", " + _value + ")\n"; } solAssert(_type.isValueType(), ""); string prepared = _value; // Exists to see if this case ever happens solAssert(_type == *m_type, ""); if (_type != *m_type) prepared = m_utils.conversionFunction(_type, *m_type) + "(" + _value + ")"; else prepared = m_utils.cleanupFunction(*m_type) + "(" + _value + ")"; if (m_byteArrayElement) { solAssert(*m_type == *TypeProvider::byte(), ""); return "mstore8(" + m_address + ", byte(0, " + prepared + "))\n"; } else return m_utils.writeToMemoryFunction(*m_type) + "(" + m_address + ", " + prepared + ")\n"; } string IRMemoryItem::setToZero() const { return storeValue(m_utils.zeroValueFunction(*m_type) + "()", *m_type); }