diff --git a/libsolidity/codegen/ir/IRGenerator.cpp b/libsolidity/codegen/ir/IRGenerator.cpp index 17b44fcd8..34c2bf3b3 100644 --- a/libsolidity/codegen/ir/IRGenerator.cpp +++ b/libsolidity/codegen/ir/IRGenerator.cpp @@ -30,6 +30,7 @@ #include #include +#include #include #include @@ -45,8 +46,7 @@ using namespace dev::solidity; pair IRGenerator::run(ContractDefinition const& _contract) { - // TODO Would be nice to pretty-print this while retaining comments. - string ir = generate(_contract); + string const ir = yul::reindent(generate(_contract)); yul::AssemblyStack asmStack(m_evmVersion, yul::AssemblyStack::Language::StrictAssembly, m_optimiserSettings); if (!asmStack.parseAndAnalyze("", ir)) diff --git a/libyul/Utilities.cpp b/libyul/Utilities.cpp index b69df0e4f..6894c2319 100644 --- a/libyul/Utilities.cpp +++ b/libyul/Utilities.cpp @@ -26,10 +26,57 @@ #include #include +#include + +#include +#include +#include +#include + using namespace std; using namespace dev; using namespace yul; +using boost::split; +using boost::is_any_of; + +string yul::reindent(string const& _code) +{ + auto const static countBraces = [](string const& _s) noexcept -> int + { + auto const i = _s.find("//"); + auto const e = i == _s.npos ? end(_s) : next(begin(_s), i); + auto const opening = count_if(begin(_s), e, [](auto ch) { return ch == '{' || ch == '('; }); + auto const closing = count_if(begin(_s), e, [](auto ch) { return ch == '}' || ch == ')'; }); + return opening - closing; + }; + + vector lines; + split(lines, _code, is_any_of("\n")); + for (string& line: lines) + boost::trim(line); + + stringstream out; + int depth = 0; + + for (string const& line: lines) + { + int const diff = countBraces(line); + if (diff < 0) + depth += diff; + + for (int i = 0; i < depth; ++i) + out << '\t'; + + out << line << '\n'; + + if (diff > 0) + depth += diff; + } + + return out.str(); +} + u256 yul::valueOfNumberLiteral(Literal const& _literal) { yulAssert(_literal.kind == LiteralKind::Number, "Expected number literal!"); diff --git a/libyul/Utilities.h b/libyul/Utilities.h index 0103d74ec..092dc90c3 100644 --- a/libyul/Utilities.h +++ b/libyul/Utilities.h @@ -26,6 +26,8 @@ namespace yul { +std::string reindent(std::string const& _code); + dev::u256 valueOfNumberLiteral(Literal const& _literal); dev::u256 valueOfStringLiteral(Literal const& _literal); dev::u256 valueOfBoolLiteral(Literal const& _literal); diff --git a/test/cmdlineTests/standard_ir_requested/output.json b/test/cmdlineTests/standard_ir_requested/output.json index 6dad16f40..e64f4eea5 100644 --- a/test/cmdlineTests/standard_ir_requested/output.json +++ b/test/cmdlineTests/standard_ir_requested/output.json @@ -1 +1 @@ -{"contracts":{"A":{"C":{"ir":"/*******************************************************\n * WARNING *\n * Solidity to Yul compilation is still EXPERIMENTAL *\n * It can result in LOSS OF FUNDS or worse *\n * !USE AT YOUR OWN RISK! *\n *******************************************************/\n\n\n\t\tobject \"C_6\" {\n\t\t\tcode {\n\t\t\t\tmstore(64, 128)\n\t\t\t\t\n\t\t\t\t\n\t\tcodecopy(0, dataoffset(\"C_6_deployed\"), datasize(\"C_6_deployed\"))\n\t\treturn(0, datasize(\"C_6_deployed\"))\n\t\n\t\t\t\t\n\t\t\tfunction fun_f_5() {\n\t\t\t\tfor { let return_flag := 1 } return_flag {} {\n\t\t\t\t\t\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\n\t\t\t}\n\t\t\tobject \"C_6_deployed\" {\n\t\t\t\tcode {\n\t\t\t\t\tmstore(64, 128)\n\t\t\t\t\t\n\t\tif iszero(lt(calldatasize(), 4))\n\t\t{\n\t\t\tlet selector := shift_right_224_unsigned(calldataload(0))\n\t\t\tswitch selector\n\t\t\t\n\t\t\tcase 0x26121ff0\n\t\t\t{\n\t\t\t\t// f()\n\t\t\t\tif callvalue() { revert(0, 0) }\n\t\t\t\t abi_decode_tuple_(4, calldatasize())\n\t\t\t\t fun_f_5()\n\t\t\t\tlet memPos := allocateMemory(0)\n\t\t\t\tlet memEnd := abi_encode_tuple__to__fromStack(memPos )\n\t\t\t\treturn(memPos, sub(memEnd, memPos))\n\t\t\t}\n\t\t\t\n\t\t\tdefault {}\n\t\t}\n\t\trevert(0, 0)\n\t\n\t\t\t\t\t\n\t\t\tfunction abi_decode_tuple_(headStart, dataEnd) {\n\t\t\t\tif slt(sub(dataEnd, headStart), 0) { revert(0, 0) }\n\t\t\t\t\n\t\t\t}\n\t\t\n\t\t\tfunction abi_encode_tuple__to__fromStack(headStart ) -> tail {\n\t\t\t\ttail := add(headStart, 0)\n\t\t\t\t\n\t\t\t}\n\t\t\n\t\t\tfunction allocateMemory(size) -> memPtr {\n\t\t\t\tmemPtr := mload(64)\n\t\t\t\tlet newFreePtr := add(memPtr, size)\n\t\t\t\t// protect against overflow\n\t\t\t\tif or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { revert(0, 0) }\n\t\t\t\tmstore(64, newFreePtr)\n\t\t\t}\n\t\t\n\t\t\tfunction fun_f_5() {\n\t\t\t\tfor { let return_flag := 1 } return_flag {} {\n\t\t\t\t\t\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\n\t\t\tfunction shift_right_224_unsigned(value) -> newValue {\n\t\t\t\tnewValue :=\n\t\t\t\t\n\t\t\t\t\tshr(224, value)\n\t\t\t\t\n\t\t\t}\n\t\t\t\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t"}}},"sources":{"A":{"id":0}}} +{"contracts":{"A":{"C":{"ir":"/*******************************************************\n * WARNING *\n * Solidity to Yul compilation is still EXPERIMENTAL *\n * It can result in LOSS OF FUNDS or worse *\n * !USE AT YOUR OWN RISK! *\n *******************************************************/\n\n\nobject \"C_6\" {\n\tcode {\n\t\tmstore(64, 128)\n\t\t\n\t\t\n\t\tcodecopy(0, dataoffset(\"C_6_deployed\"), datasize(\"C_6_deployed\"))\n\t\treturn(0, datasize(\"C_6_deployed\"))\n\t\t\n\t\t\n\t\tfunction fun_f_5() {\n\t\t\tfor { let return_flag := 1 } return_flag {} {\n\t\t\t\t\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t\t\n\t}\n\tobject \"C_6_deployed\" {\n\t\tcode {\n\t\t\tmstore(64, 128)\n\t\t\t\n\t\t\tif iszero(lt(calldatasize(), 4))\n\t\t\t{\n\t\t\t\tlet selector := shift_right_224_unsigned(calldataload(0))\n\t\t\t\tswitch selector\n\t\t\t\t\n\t\t\t\tcase 0x26121ff0\n\t\t\t\t{\n\t\t\t\t\t// f()\n\t\t\t\t\tif callvalue() { revert(0, 0) }\n\t\t\t\t\tabi_decode_tuple_(4, calldatasize())\n\t\t\t\t\tfun_f_5()\n\t\t\t\t\tlet memPos := allocateMemory(0)\n\t\t\t\t\tlet memEnd := abi_encode_tuple__to__fromStack(memPos )\n\t\t\t\t\treturn(memPos, sub(memEnd, memPos))\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tdefault {}\n\t\t\t}\n\t\t\trevert(0, 0)\n\t\t\t\n\t\t\t\n\t\t\tfunction abi_decode_tuple_(headStart, dataEnd) {\n\t\t\t\tif slt(sub(dataEnd, headStart), 0) { revert(0, 0) }\n\t\t\t\t\n\t\t\t}\n\t\t\t\n\t\t\tfunction abi_encode_tuple__to__fromStack(headStart ) -> tail {\n\t\t\t\ttail := add(headStart, 0)\n\t\t\t\t\n\t\t\t}\n\t\t\t\n\t\t\tfunction allocateMemory(size) -> memPtr {\n\t\t\t\tmemPtr := mload(64)\n\t\t\t\tlet newFreePtr := add(memPtr, size)\n\t\t\t\t// protect against overflow\n\t\t\t\tif or(gt(newFreePtr, 0xffffffffffffffff), lt(newFreePtr, memPtr)) { revert(0, 0) }\n\t\t\t\tmstore(64, newFreePtr)\n\t\t\t}\n\t\t\t\n\t\t\tfunction fun_f_5() {\n\t\t\t\tfor { let return_flag := 1 } return_flag {} {\n\t\t\t\t\t\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t\tfunction shift_right_224_unsigned(value) -> newValue {\n\t\t\t\tnewValue :=\n\t\t\t\t\n\t\t\t\tshr(224, value)\n\t\t\t\t\n\t\t\t}\n\t\t\t\n\t\t}\n\t}\n}\n\n"}}},"sources":{"A":{"id":0}}}