mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Support multiple assignment in inline assembly
This commit is contained in:
committed by
chriseth
parent
c0b3e5b078
commit
3b813ed295
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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; };
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user