aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity/inlineasm
diff options
context:
space:
mode:
authorAlex Beregszaszi <alex@rtfs.hu>2017-05-20 00:06:26 +0800
committerchriseth <chris@ethereum.org>2017-09-20 17:16:23 +0800
commit3b813ed29569dde02b965c97c9fdd60469876f66 (patch)
tree20a5ea09ab0bc99d48acabb0e567affb6c381ca4 /libsolidity/inlineasm
parentc0b3e5b0785efd1b601cff470d3e3d4a71b2c283 (diff)
downloaddexon-solidity-3b813ed29569dde02b965c97c9fdd60469876f66.tar
dexon-solidity-3b813ed29569dde02b965c97c9fdd60469876f66.tar.gz
dexon-solidity-3b813ed29569dde02b965c97c9fdd60469876f66.tar.bz2
dexon-solidity-3b813ed29569dde02b965c97c9fdd60469876f66.tar.lz
dexon-solidity-3b813ed29569dde02b965c97c9fdd60469876f66.tar.xz
dexon-solidity-3b813ed29569dde02b965c97c9fdd60469876f66.tar.zst
dexon-solidity-3b813ed29569dde02b965c97c9fdd60469876f66.zip
Support multiple assignment in inline assembly
Diffstat (limited to 'libsolidity/inlineasm')
-rw-r--r--libsolidity/inlineasm/AsmAnalysis.cpp20
-rw-r--r--libsolidity/inlineasm/AsmData.h6
-rw-r--r--libsolidity/inlineasm/AsmParser.cpp30
-rw-r--r--libsolidity/inlineasm/AsmPrinter.cpp6
4 files changed, 56 insertions, 6 deletions
diff --git a/libsolidity/inlineasm/AsmAnalysis.cpp b/libsolidity/inlineasm/AsmAnalysis.cpp
index 76b0bbd5..e5bdc90f 100644
--- a/libsolidity/inlineasm/AsmAnalysis.cpp
+++ b/libsolidity/inlineasm/AsmAnalysis.cpp
@@ -163,11 +163,25 @@ bool AsmAnalyzer::operator()(assembly::StackAssignment const& _assignment)
bool AsmAnalyzer::operator()(assembly::Assignment const& _assignment)
{
+ int const expectedItems = _assignment.variableNames.size();
+ solAssert(expectedItems >= 1, "");
int const stackHeight = m_stackHeight;
bool success = boost::apply_visitor(*this, *_assignment.value);
- solAssert(m_stackHeight >= stackHeight, "Negative value size.");
- if (!checkAssignment(_assignment.variableName, m_stackHeight - stackHeight))
- success = false;
+ if ((m_stackHeight - stackHeight) != expectedItems)
+ {
+ m_errorReporter.declarationError(
+ _assignment.location,
+ "Variable count does not match number of values (" +
+ to_string(expectedItems) +
+ " vs. " +
+ to_string(m_stackHeight - stackHeight) +
+ ")"
+ );
+ return false;
+ }
+ for (auto const& variableName: _assignment.variableNames)
+ if (!checkAssignment(variableName, 1))
+ success = false;
m_info.stackHeightInfo[&_assignment] = m_stackHeight;
return success;
}
diff --git a/libsolidity/inlineasm/AsmData.h b/libsolidity/inlineasm/AsmData.h
index db5840bc..b0dd85ca 100644
--- a/libsolidity/inlineasm/AsmData.h
+++ b/libsolidity/inlineasm/AsmData.h
@@ -54,7 +54,11 @@ struct Label { SourceLocation location; std::string name; };
struct StackAssignment { SourceLocation location; Identifier variableName; };
/// Assignment ("x := mload(20:u256)", expects push-1-expression on the right hand
/// side and requires x to occupy exactly one stack slot.
-struct Assignment { SourceLocation location; Identifier variableName; std::shared_ptr<Statement> value; };
+///
+/// Multiple assignment ("x, y := f()"), where the left hand side variables each occupy
+/// a single stack slot and expects a single expression on the right hand returning
+/// the same amount of items as the number of variables.
+struct Assignment { SourceLocation location; std::vector<Identifier> variableNames; std::shared_ptr<Statement> value; };
/// Functional instruction, e.g. "mul(mload(20:u256), add(2:u256, x))"
struct FunctionalInstruction { SourceLocation location; Instruction instruction; std::vector<Statement> arguments; };
struct FunctionCall { SourceLocation location; Identifier functionName; std::vector<Statement> arguments; };
diff --git a/libsolidity/inlineasm/AsmParser.cpp b/libsolidity/inlineasm/AsmParser.cpp
index d84fe999..3087ad86 100644
--- a/libsolidity/inlineasm/AsmParser.cpp
+++ b/libsolidity/inlineasm/AsmParser.cpp
@@ -122,6 +122,34 @@ assembly::Statement Parser::parseStatement()
{
case Token::LParen:
return parseCall(std::move(statement));
+ case Token::Comma:
+ {
+ // if a comma follows, a multiple assignment is assumed
+
+ if (statement.type() != typeid(assembly::Identifier))
+ fatalParserError("Label name / variable name must precede \",\" (multiple assignment).");
+ assembly::Identifier const& identifier = boost::get<assembly::Identifier>(statement);
+
+ Assignment assignment = createWithLocation<Assignment>(identifier.location);
+ assignment.variableNames.emplace_back(identifier);
+
+ do
+ {
+ expectToken(Token::Comma);
+ statement = parseElementaryOperation(false);
+ if (statement.type() != typeid(assembly::Identifier))
+ fatalParserError("Variable name expected in multiple assignemnt.");
+ assignment.variableNames.emplace_back(boost::get<assembly::Identifier>(statement));
+ }
+ while (currentToken() == Token::Comma);
+
+ expectToken(Token::Colon);
+ expectToken(Token::Assign);
+
+ assignment.value.reset(new Statement(parseExpression()));
+ assignment.location.end = locationOf(*assignment.value).end;
+ return assignment;
+ }
case Token::Colon:
{
if (statement.type() != typeid(assembly::Identifier))
@@ -136,7 +164,7 @@ assembly::Statement Parser::parseStatement()
if (!m_julia && instructions().count(identifier.name))
fatalParserError("Cannot use instruction names for identifier names.");
advance();
- assignment.variableName = identifier;
+ assignment.variableNames.emplace_back(identifier);
assignment.value.reset(new Statement(parseExpression()));
assignment.location.end = locationOf(*assignment.value).end;
return assignment;
diff --git a/libsolidity/inlineasm/AsmPrinter.cpp b/libsolidity/inlineasm/AsmPrinter.cpp
index 47ede91d..a5272808 100644
--- a/libsolidity/inlineasm/AsmPrinter.cpp
+++ b/libsolidity/inlineasm/AsmPrinter.cpp
@@ -116,7 +116,11 @@ string AsmPrinter::operator()(assembly::StackAssignment const& _assignment)
string AsmPrinter::operator()(assembly::Assignment const& _assignment)
{
- return (*this)(_assignment.variableName) + " := " + boost::apply_visitor(*this, *_assignment.value);
+ solAssert(_assignment.variableNames.size() >= 1, "");
+ string variables = (*this)(_assignment.variableNames.front());
+ for (size_t i = 1; i < _assignment.variableNames.size(); ++i)
+ variables += ", " + (*this)(_assignment.variableNames[i]);
+ return variables + " := " + boost::apply_visitor(*this, *_assignment.value);
}
string AsmPrinter::operator()(assembly::VariableDeclaration const& _variableDeclaration)