Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ad751bd

Browse files
authored
Merge pull request argotorg#1674 from ethereum/assemblyPrinter
Assembly printer.
2 parents 4189ff5 + 5e8a1e0 commit ad751bd

File tree

5 files changed

+271
-4
lines changed

5 files changed

+271
-4
lines changed
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/*
2+
This file is part of solidity.
3+
4+
solidity is free software: you can redistribute it and/or modify
5+
it under the terms of the GNU General Public License as published by
6+
the Free Software Foundation, either version 3 of the License, or
7+
(at your option) any later version.
8+
9+
solidity is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
GNU General Public License for more details.
13+
14+
You should have received a copy of the GNU General Public License
15+
along with solidity. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
/**
18+
* @author Christian <[email protected]>
19+
* @date 2017
20+
* Converts a parsed assembly into its textual form.
21+
*/
22+
23+
#include <libsolidity/inlineasm/AsmPrinter.h>
24+
25+
#include <libsolidity/inlineasm/AsmData.h>
26+
27+
#include <boost/algorithm/string.hpp>
28+
#include <boost/algorithm/string/replace.hpp>
29+
#include <boost/range/adaptor/transformed.hpp>
30+
31+
#include <memory>
32+
#include <functional>
33+
34+
using namespace std;
35+
using namespace dev;
36+
using namespace dev::solidity;
37+
using namespace dev::solidity::assembly;
38+
39+
//@TODO source locations
40+
41+
string AsmPrinter::operator()(assembly::Instruction const& _instruction)
42+
{
43+
return boost::to_lower_copy(instructionInfo(_instruction.instruction).name);
44+
}
45+
46+
string AsmPrinter::operator()(assembly::Literal const& _literal)
47+
{
48+
if (_literal.isNumber)
49+
return _literal.value;
50+
string out;
51+
for (char c: _literal.value)
52+
if (c == '\\')
53+
out += "\\\\";
54+
else if (c == '"')
55+
out += "\\\"";
56+
else if (c == '\b')
57+
out += "\\b";
58+
else if (c == '\f')
59+
out += "\\f";
60+
else if (c == '\n')
61+
out += "\\n";
62+
else if (c == '\r')
63+
out += "\\r";
64+
else if (c == '\t')
65+
out += "\\t";
66+
else if (c == '\v')
67+
out += "\\v";
68+
else if (!isprint(c, locale::classic()))
69+
{
70+
ostringstream o;
71+
o << std::hex << setfill('0') << setw(2) << (unsigned)(unsigned char)(c);
72+
out += "\\x" + o.str();
73+
}
74+
else
75+
out += c;
76+
return "\"" + out + "\"";
77+
}
78+
79+
string AsmPrinter::operator()(assembly::Identifier const& _identifier)
80+
{
81+
return _identifier.name;
82+
}
83+
84+
string AsmPrinter::operator()(assembly::FunctionalInstruction const& _functionalInstruction)
85+
{
86+
return
87+
(*this)(_functionalInstruction.instruction) +
88+
"(" +
89+
boost::algorithm::join(
90+
_functionalInstruction.arguments | boost::adaptors::transformed(boost::apply_visitor(*this)),
91+
", " ) +
92+
")";
93+
}
94+
95+
string AsmPrinter::operator()(assembly::Label const& _label)
96+
{
97+
return _label.name + ":";
98+
}
99+
100+
string AsmPrinter::operator()(assembly::Assignment const& _assignment)
101+
{
102+
return "=: " + (*this)(_assignment.variableName);
103+
}
104+
105+
string AsmPrinter::operator()(assembly::FunctionalAssignment const& _functionalAssignment)
106+
{
107+
return (*this)(_functionalAssignment.variableName) + " := " + boost::apply_visitor(*this, *_functionalAssignment.value);
108+
}
109+
110+
string AsmPrinter::operator()(assembly::VariableDeclaration const& _variableDeclaration)
111+
{
112+
return "let " + _variableDeclaration.name + " := " + boost::apply_visitor(*this, *_variableDeclaration.value);
113+
}
114+
115+
string AsmPrinter::operator()(Block const& _block)
116+
{
117+
if (_block.statements.empty())
118+
return "{\n}";
119+
string body = boost::algorithm::join(
120+
_block.statements | boost::adaptors::transformed(boost::apply_visitor(*this)),
121+
"\n"
122+
);
123+
boost::replace_all(body, "\n", "\n ");
124+
return "{\n " + body + "\n}";
125+
}

libsolidity/inlineasm/AsmPrinter.h

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
This file is part of solidity.
3+
4+
solidity is free software: you can redistribute it and/or modify
5+
it under the terms of the GNU General Public License as published by
6+
the Free Software Foundation, either version 3 of the License, or
7+
(at your option) any later version.
8+
9+
solidity is distributed in the hope that it will be useful,
10+
but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
GNU General Public License for more details.
13+
14+
You should have received a copy of the GNU General Public License
15+
along with solidity. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
/**
18+
* @author Christian <[email protected]>
19+
* @date 2017
20+
* Converts a parsed assembly into its textual form.
21+
*/
22+
23+
#pragma once
24+
25+
#include <boost/variant.hpp>
26+
27+
namespace dev
28+
{
29+
namespace solidity
30+
{
31+
namespace assembly
32+
{
33+
struct Instruction;
34+
struct Literal;
35+
struct Identifier;
36+
struct FunctionalInstruction;
37+
struct Label;
38+
struct Assignment;
39+
struct FunctionalAssignment;
40+
struct VariableDeclaration;
41+
struct FunctionDefinition;
42+
struct FunctionCall;
43+
struct Block;
44+
45+
class AsmPrinter: public boost::static_visitor<std::string>
46+
{
47+
public:
48+
std::string operator()(assembly::Instruction const& _instruction);
49+
std::string operator()(assembly::Literal const& _literal);
50+
std::string operator()(assembly::Identifier const& _identifier);
51+
std::string operator()(assembly::FunctionalInstruction const& _functionalInstruction);
52+
std::string operator()(assembly::Label const& _label);
53+
std::string operator()(assembly::Assignment const& _assignment);
54+
std::string operator()(assembly::FunctionalAssignment const& _functionalAssignment);
55+
std::string operator()(assembly::VariableDeclaration const& _variableDeclaration);
56+
std::string operator()(assembly::Block const& _block);
57+
};
58+
59+
}
60+
}
61+
}

libsolidity/inlineasm/AsmStack.cpp

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,17 @@
2121
*/
2222

2323
#include <libsolidity/inlineasm/AsmStack.h>
24-
#include <memory>
25-
#include <libevmasm/Assembly.h>
26-
#include <libevmasm/SourceLocation.h>
27-
#include <libsolidity/parsing/Scanner.h>
24+
2825
#include <libsolidity/inlineasm/AsmParser.h>
2926
#include <libsolidity/inlineasm/AsmCodeGen.h>
27+
#include <libsolidity/inlineasm/AsmPrinter.h>
28+
29+
#include <libsolidity/parsing/Scanner.h>
30+
31+
#include <libevmasm/Assembly.h>
32+
#include <libevmasm/SourceLocation.h>
33+
34+
#include <memory>
3035

3136
using namespace std;
3237
using namespace dev;
@@ -44,6 +49,11 @@ bool InlineAssemblyStack::parse(shared_ptr<Scanner> const& _scanner)
4449
return true;
4550
}
4651

52+
string InlineAssemblyStack::toString()
53+
{
54+
return AsmPrinter()(*m_parserResult);
55+
}
56+
4757
eth::Assembly InlineAssemblyStack::assemble()
4858
{
4959
CodeGenerator codeGen(*m_parserResult, m_errors);

libsolidity/inlineasm/AsmStack.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,10 @@ class InlineAssemblyStack
4646
/// Parse the given inline assembly chunk starting with `{` and ending with the corresponding `}`.
4747
/// @return false or error.
4848
bool parse(std::shared_ptr<Scanner> const& _scanner);
49+
/// Converts the parser result back into a string form (not necessarily the same form
50+
/// as the source form, but it should parse into the same parsed form again).
51+
std::string toString();
52+
4953
eth::Assembly assemble();
5054

5155
/// Parse and assemble a string in one run - for use in Solidity code generation itself.

test/libsolidity/InlineAssembly.cpp

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,11 +73,22 @@ bool successAssemble(string const& _source, bool _allowWarnings = true)
7373
return successParse(_source, true, _allowWarnings);
7474
}
7575

76+
void parsePrintCompare(string const& _source)
77+
{
78+
assembly::InlineAssemblyStack stack;
79+
BOOST_REQUIRE(stack.parse(std::make_shared<Scanner>(CharStream(_source))));
80+
BOOST_REQUIRE(stack.errors().empty());
81+
BOOST_CHECK_EQUAL(stack.toString(), _source);
82+
}
83+
7684
}
7785

7886

7987
BOOST_AUTO_TEST_SUITE(SolidityInlineAssembly)
8088

89+
90+
BOOST_AUTO_TEST_SUITE(Parsing)
91+
8192
BOOST_AUTO_TEST_CASE(smoke_test)
8293
{
8394
BOOST_CHECK(successParse("{ }"));
@@ -148,6 +159,60 @@ BOOST_AUTO_TEST_CASE(blocks)
148159
BOOST_CHECK(successParse("{ let x := 7 { let y := 3 } { let z := 2 } }"));
149160
}
150161

162+
BOOST_AUTO_TEST_SUITE_END()
163+
164+
BOOST_AUTO_TEST_SUITE(Printing)
165+
166+
BOOST_AUTO_TEST_CASE(print_smoke)
167+
{
168+
parsePrintCompare("{\n}");
169+
}
170+
171+
BOOST_AUTO_TEST_CASE(print_instructions)
172+
{
173+
parsePrintCompare("{\n 7\n 8\n mul\n dup10\n add\n}");
174+
}
175+
176+
BOOST_AUTO_TEST_CASE(print_subblock)
177+
{
178+
parsePrintCompare("{\n {\n dup4\n add\n }\n}");
179+
}
180+
181+
BOOST_AUTO_TEST_CASE(print_functional)
182+
{
183+
parsePrintCompare("{\n mul(sload(0x12), 7)\n}");
184+
}
185+
186+
BOOST_AUTO_TEST_CASE(print_label)
187+
{
188+
parsePrintCompare("{\n loop:\n jump(loop)\n}");
189+
}
190+
191+
BOOST_AUTO_TEST_CASE(print_assignments)
192+
{
193+
parsePrintCompare("{\n let x := mul(2, 3)\n 7\n =: x\n x := add(1, 2)\n}");
194+
}
195+
196+
BOOST_AUTO_TEST_CASE(print_string_literals)
197+
{
198+
parsePrintCompare("{\n \"\\n'\\xab\\x95\\\"\"\n}");
199+
}
200+
201+
BOOST_AUTO_TEST_CASE(print_string_literal_unicode)
202+
{
203+
string source = "{ \"\\u1bac\" }";
204+
string parsed = "{\n \"\\xe1\\xae\\xac\"\n}";
205+
assembly::InlineAssemblyStack stack;
206+
BOOST_REQUIRE(stack.parse(std::make_shared<Scanner>(CharStream(source))));
207+
BOOST_REQUIRE(stack.errors().empty());
208+
BOOST_CHECK_EQUAL(stack.toString(), parsed);
209+
parsePrintCompare(parsed);
210+
}
211+
212+
BOOST_AUTO_TEST_SUITE_END()
213+
214+
BOOST_AUTO_TEST_SUITE(Analysis)
215+
151216
BOOST_AUTO_TEST_CASE(string_literals)
152217
{
153218
BOOST_CHECK(successAssemble("{ let x := \"12345678901234567890123456789012\" }"));
@@ -212,6 +277,8 @@ BOOST_AUTO_TEST_CASE(revert)
212277

213278
BOOST_AUTO_TEST_SUITE_END()
214279

280+
BOOST_AUTO_TEST_SUITE_END()
281+
215282
}
216283
}
217284
} // end namespaces

0 commit comments

Comments
 (0)