aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorchriseth <chris@ethereum.org>2017-02-15 22:41:45 +0800
committerGitHub <noreply@github.com>2017-02-15 22:41:45 +0800
commitad751bd3e6f22fadc01d43610ec2e2e008c32f11 (patch)
tree12a9fe2556bd87a0d7e2695db724d65434f40f42
parent4189ff5b68f119878807104ebac0137171c8ecd6 (diff)
parent5e8a1e0ae6dcd269258fe4239060bcc890abacb5 (diff)
downloaddexon-solidity-ad751bd3e6f22fadc01d43610ec2e2e008c32f11.tar.gz
dexon-solidity-ad751bd3e6f22fadc01d43610ec2e2e008c32f11.tar.zst
dexon-solidity-ad751bd3e6f22fadc01d43610ec2e2e008c32f11.zip
Merge pull request #1674 from ethereum/assemblyPrinter
Assembly printer.
-rw-r--r--libsolidity/inlineasm/AsmPrinter.cpp125
-rw-r--r--libsolidity/inlineasm/AsmPrinter.h61
-rw-r--r--libsolidity/inlineasm/AsmStack.cpp18
-rw-r--r--libsolidity/inlineasm/AsmStack.h4
-rw-r--r--test/libsolidity/InlineAssembly.cpp67
5 files changed, 271 insertions, 4 deletions
diff --git a/libsolidity/inlineasm/AsmPrinter.cpp b/libsolidity/inlineasm/AsmPrinter.cpp
new file mode 100644
index 00000000..ab2a03ff
--- /dev/null
+++ b/libsolidity/inlineasm/AsmPrinter.cpp
@@ -0,0 +1,125 @@
+/*
+ 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 <http://www.gnu.org/licenses/>.
+*/
+/**
+ * @author Christian <c@ethdev.com>
+ * @date 2017
+ * Converts a parsed assembly into its textual form.
+ */
+
+#include <libsolidity/inlineasm/AsmPrinter.h>
+
+#include <libsolidity/inlineasm/AsmData.h>
+
+#include <boost/algorithm/string.hpp>
+#include <boost/algorithm/string/replace.hpp>
+#include <boost/range/adaptor/transformed.hpp>
+
+#include <memory>
+#include <functional>
+
+using namespace std;
+using namespace dev;
+using namespace dev::solidity;
+using namespace dev::solidity::assembly;
+
+//@TODO source locations
+
+string AsmPrinter::operator()(assembly::Instruction const& _instruction)
+{
+ return boost::to_lower_copy(instructionInfo(_instruction.instruction).name);
+}
+
+string AsmPrinter::operator()(assembly::Literal const& _literal)
+{
+ if (_literal.isNumber)
+ return _literal.value;
+ string out;
+ for (char c: _literal.value)
+ if (c == '\\')
+ out += "\\\\";
+ else if (c == '"')
+ out += "\\\"";
+ else if (c == '\b')
+ out += "\\b";
+ else if (c == '\f')
+ out += "\\f";
+ else if (c == '\n')
+ out += "\\n";
+ else if (c == '\r')
+ out += "\\r";
+ else if (c == '\t')
+ out += "\\t";
+ else if (c == '\v')
+ out += "\\v";
+ else if (!isprint(c, locale::classic()))
+ {
+ ostringstream o;
+ o << std::hex << setfill('0') << setw(2) << (unsigned)(unsigned char)(c);
+ out += "\\x" + o.str();
+ }
+ else
+ out += c;
+ return "\"" + out + "\"";
+}
+
+string AsmPrinter::operator()(assembly::Identifier const& _identifier)
+{
+ return _identifier.name;
+}
+
+string AsmPrinter::operator()(assembly::FunctionalInstruction const& _functionalInstruction)
+{
+ return
+ (*this)(_functionalInstruction.instruction) +
+ "(" +
+ boost::algorithm::join(
+ _functionalInstruction.arguments | boost::adaptors::transformed(boost::apply_visitor(*this)),
+ ", " ) +
+ ")";
+}
+
+string AsmPrinter::operator()(assembly::Label const& _label)
+{
+ return _label.name + ":";
+}
+
+string AsmPrinter::operator()(assembly::Assignment const& _assignment)
+{
+ return "=: " + (*this)(_assignment.variableName);
+}
+
+string AsmPrinter::operator()(assembly::FunctionalAssignment const& _functionalAssignment)
+{
+ return (*this)(_functionalAssignment.variableName) + " := " + boost::apply_visitor(*this, *_functionalAssignment.value);
+}
+
+string AsmPrinter::operator()(assembly::VariableDeclaration const& _variableDeclaration)
+{
+ return "let " + _variableDeclaration.name + " := " + boost::apply_visitor(*this, *_variableDeclaration.value);
+}
+
+string AsmPrinter::operator()(Block const& _block)
+{
+ if (_block.statements.empty())
+ return "{\n}";
+ string body = boost::algorithm::join(
+ _block.statements | boost::adaptors::transformed(boost::apply_visitor(*this)),
+ "\n"
+ );
+ boost::replace_all(body, "\n", "\n ");
+ return "{\n " + body + "\n}";
+}
diff --git a/libsolidity/inlineasm/AsmPrinter.h b/libsolidity/inlineasm/AsmPrinter.h
new file mode 100644
index 00000000..39069d02
--- /dev/null
+++ b/libsolidity/inlineasm/AsmPrinter.h
@@ -0,0 +1,61 @@
+/*
+ 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 <http://www.gnu.org/licenses/>.
+*/
+/**
+ * @author Christian <c@ethdev.com>
+ * @date 2017
+ * Converts a parsed assembly into its textual form.
+ */
+
+#pragma once
+
+#include <boost/variant.hpp>
+
+namespace dev
+{
+namespace solidity
+{
+namespace assembly
+{
+struct Instruction;
+struct Literal;
+struct Identifier;
+struct FunctionalInstruction;
+struct Label;
+struct Assignment;
+struct FunctionalAssignment;
+struct VariableDeclaration;
+struct FunctionDefinition;
+struct FunctionCall;
+struct Block;
+
+class AsmPrinter: public boost::static_visitor<std::string>
+{
+public:
+ std::string operator()(assembly::Instruction const& _instruction);
+ std::string operator()(assembly::Literal const& _literal);
+ std::string operator()(assembly::Identifier const& _identifier);
+ std::string operator()(assembly::FunctionalInstruction const& _functionalInstruction);
+ std::string operator()(assembly::Label const& _label);
+ std::string operator()(assembly::Assignment const& _assignment);
+ std::string operator()(assembly::FunctionalAssignment const& _functionalAssignment);
+ std::string operator()(assembly::VariableDeclaration const& _variableDeclaration);
+ std::string operator()(assembly::Block const& _block);
+};
+
+}
+}
+}
diff --git a/libsolidity/inlineasm/AsmStack.cpp b/libsolidity/inlineasm/AsmStack.cpp
index b8e0e857..38d688c1 100644
--- a/libsolidity/inlineasm/AsmStack.cpp
+++ b/libsolidity/inlineasm/AsmStack.cpp
@@ -21,12 +21,17 @@
*/
#include <libsolidity/inlineasm/AsmStack.h>
-#include <memory>
-#include <libevmasm/Assembly.h>
-#include <libevmasm/SourceLocation.h>
-#include <libsolidity/parsing/Scanner.h>
+
#include <libsolidity/inlineasm/AsmParser.h>
#include <libsolidity/inlineasm/AsmCodeGen.h>
+#include <libsolidity/inlineasm/AsmPrinter.h>
+
+#include <libsolidity/parsing/Scanner.h>
+
+#include <libevmasm/Assembly.h>
+#include <libevmasm/SourceLocation.h>
+
+#include <memory>
using namespace std;
using namespace dev;
@@ -44,6 +49,11 @@ bool InlineAssemblyStack::parse(shared_ptr<Scanner> const& _scanner)
return true;
}
+string InlineAssemblyStack::toString()
+{
+ return AsmPrinter()(*m_parserResult);
+}
+
eth::Assembly InlineAssemblyStack::assemble()
{
CodeGenerator codeGen(*m_parserResult, m_errors);
diff --git a/libsolidity/inlineasm/AsmStack.h b/libsolidity/inlineasm/AsmStack.h
index 1543cb2a..4d5a99a4 100644
--- a/libsolidity/inlineasm/AsmStack.h
+++ b/libsolidity/inlineasm/AsmStack.h
@@ -46,6 +46,10 @@ public:
/// Parse the given inline assembly chunk starting with `{` and ending with the corresponding `}`.
/// @return false or error.
bool parse(std::shared_ptr<Scanner> const& _scanner);
+ /// Converts the parser result back into a string form (not necessarily the same form
+ /// as the source form, but it should parse into the same parsed form again).
+ std::string toString();
+
eth::Assembly assemble();
/// Parse and assemble a string in one run - for use in Solidity code generation itself.
diff --git a/test/libsolidity/InlineAssembly.cpp b/test/libsolidity/InlineAssembly.cpp
index 37d17495..8744d96f 100644
--- a/test/libsolidity/InlineAssembly.cpp
+++ b/test/libsolidity/InlineAssembly.cpp
@@ -73,11 +73,22 @@ bool successAssemble(string const& _source, bool _allowWarnings = true)
return successParse(_source, true, _allowWarnings);
}
+void parsePrintCompare(string const& _source)
+{
+ assembly::InlineAssemblyStack stack;
+ BOOST_REQUIRE(stack.parse(std::make_shared<Scanner>(CharStream(_source))));
+ BOOST_REQUIRE(stack.errors().empty());
+ BOOST_CHECK_EQUAL(stack.toString(), _source);
+}
+
}
BOOST_AUTO_TEST_SUITE(SolidityInlineAssembly)
+
+BOOST_AUTO_TEST_SUITE(Parsing)
+
BOOST_AUTO_TEST_CASE(smoke_test)
{
BOOST_CHECK(successParse("{ }"));
@@ -148,6 +159,60 @@ BOOST_AUTO_TEST_CASE(blocks)
BOOST_CHECK(successParse("{ let x := 7 { let y := 3 } { let z := 2 } }"));
}
+BOOST_AUTO_TEST_SUITE_END()
+
+BOOST_AUTO_TEST_SUITE(Printing)
+
+BOOST_AUTO_TEST_CASE(print_smoke)
+{
+ parsePrintCompare("{\n}");
+}
+
+BOOST_AUTO_TEST_CASE(print_instructions)
+{
+ parsePrintCompare("{\n 7\n 8\n mul\n dup10\n add\n}");
+}
+
+BOOST_AUTO_TEST_CASE(print_subblock)
+{
+ parsePrintCompare("{\n {\n dup4\n add\n }\n}");
+}
+
+BOOST_AUTO_TEST_CASE(print_functional)
+{
+ parsePrintCompare("{\n mul(sload(0x12), 7)\n}");
+}
+
+BOOST_AUTO_TEST_CASE(print_label)
+{
+ parsePrintCompare("{\n loop:\n jump(loop)\n}");
+}
+
+BOOST_AUTO_TEST_CASE(print_assignments)
+{
+ parsePrintCompare("{\n let x := mul(2, 3)\n 7\n =: x\n x := add(1, 2)\n}");
+}
+
+BOOST_AUTO_TEST_CASE(print_string_literals)
+{
+ parsePrintCompare("{\n \"\\n'\\xab\\x95\\\"\"\n}");
+}
+
+BOOST_AUTO_TEST_CASE(print_string_literal_unicode)
+{
+ string source = "{ \"\\u1bac\" }";
+ string parsed = "{\n \"\\xe1\\xae\\xac\"\n}";
+ assembly::InlineAssemblyStack stack;
+ BOOST_REQUIRE(stack.parse(std::make_shared<Scanner>(CharStream(source))));
+ BOOST_REQUIRE(stack.errors().empty());
+ BOOST_CHECK_EQUAL(stack.toString(), parsed);
+ parsePrintCompare(parsed);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
+BOOST_AUTO_TEST_SUITE(Analysis)
+
BOOST_AUTO_TEST_CASE(string_literals)
{
BOOST_CHECK(successAssemble("{ let x := \"12345678901234567890123456789012\" }"));
@@ -212,6 +277,8 @@ BOOST_AUTO_TEST_CASE(revert)
BOOST_AUTO_TEST_SUITE_END()
+BOOST_AUTO_TEST_SUITE_END()
+
}
}
} // end namespaces