Support multiple assignment in inline assembly

This commit is contained in:
Alex Beregszaszi
2017-09-20 11:16:23 +02:00
committed by chriseth
parent c0b3e5b078
commit 3b813ed295
10 changed files with 145 additions and 25 deletions
+17 -3
View File
@@ -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;
}
+5 -1
View File
@@ -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; };
+29 -1
View File
@@ -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;
+5 -1
View File
@@ -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)