From 0fd1db533e260970f8af2285f1c290afa6fa1881 Mon Sep 17 00:00:00 2001 From: Christian Parpart Date: Fri, 21 Jun 2019 17:33:35 +0200 Subject: [PATCH] yul: adds reindent() function to reindent yul source code and makes use of it in IRGenerator. This function does count curly and round braces and reindents accordingly the beginning of each line. It does consider line-comments (// and ///) but not multiline comments (/* ... */). --- libsolidity/codegen/ir/IRGenerator.cpp | 4 +- libyul/Utilities.cpp | 47 +++++++++++++++++++ libyul/Utilities.h | 2 + .../standard_ir_requested/output.json | 2 +- 4 files changed, 52 insertions(+), 3 deletions(-) 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}}}