/* 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 . */ // SPDX-License-Identifier: GPL-3.0 /** * Yul code and data object container. */ #include #include #include #include #include #include #include using namespace std; using namespace solidity; using namespace solidity::yul; using namespace solidity::util; namespace { string indent(std::string const& _input) { if (_input.empty()) return _input; return boost::replace_all_copy(" " + _input, "\n", "\n "); } } string Data::toString(Dialect const*) const { return "data \"" + name.str() + "\" hex\"" + util::toHex(data) + "\""; } string Object::toString(Dialect const* _dialect) const { yulAssert(code, "No code"); string inner = "code " + (_dialect ? AsmPrinter{*_dialect} : AsmPrinter{})(*code); for (auto const& obj: subObjects) inner += "\n" + obj->toString(_dialect); return "object \"" + name.str() + "\" {\n" + indent(inner) + "\n}"; } set Object::qualifiedDataNames() const { set qualifiedNames = name.empty() || contains(name.str(), '.') ? set{} : set{name}; for (shared_ptr const& subObjectNode: subObjects) { yulAssert(qualifiedNames.count(subObjectNode->name) == 0, ""); if (contains(subObjectNode->name.str(), '.')) continue; qualifiedNames.insert(subObjectNode->name); if (auto const* subObject = dynamic_cast(subObjectNode.get())) for (YulString const& subSubObj: subObject->qualifiedDataNames()) if (subObject->name != subSubObj) { yulAssert(qualifiedNames.count(YulString{subObject->name.str() + "." + subSubObj.str()}) == 0, ""); qualifiedNames.insert(YulString{subObject->name.str() + "." + subSubObj.str()}); } } yulAssert(qualifiedNames.count(YulString{}) == 0, ""); qualifiedNames.erase(YulString{}); return qualifiedNames; } vector Object::pathToSubObject(YulString _qualifiedName) const { yulAssert(_qualifiedName != name, ""); yulAssert(subIndexByName.count(name) == 0, ""); if (boost::algorithm::starts_with(_qualifiedName.str(), name.str() + ".")) _qualifiedName = YulString{_qualifiedName.str().substr(name.str().length() + 1)}; yulAssert(!_qualifiedName.empty(), ""); vector subObjectPathComponents; boost::algorithm::split(subObjectPathComponents, _qualifiedName.str(), boost::is_any_of(".")); vector path; Object const* object = this; for (string const& currentSubObjectName: subObjectPathComponents) { yulAssert(!currentSubObjectName.empty(), ""); auto subIndexIt = object->subIndexByName.find(YulString{currentSubObjectName}); yulAssert( subIndexIt != object->subIndexByName.end(), "Assembly object <" + _qualifiedName.str() + "> not found or does not contain code." ); object = dynamic_cast(object->subObjects[subIndexIt->second].get()); yulAssert(object, "Assembly object <" + _qualifiedName.str() + "> not found or does not contain code."); yulAssert(object->subId != numeric_limits::max(), ""); path.push_back({object->subId}); } return path; }