From 15b4d4def23bcf0feb93c67dccc137baa59d5102 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Fri, 5 May 2017 18:35:40 +0100 Subject: Support multiple variables in a variable declaration in inline assembly --- libsolidity/inlineasm/AsmAnalysis.cpp | 28 ++++++++++++++++++++++++---- libsolidity/inlineasm/AsmCodeGen.cpp | 15 ++++++++++----- libsolidity/inlineasm/AsmData.h | 2 +- libsolidity/inlineasm/AsmParser.cpp | 20 +++++++++++++++++--- libsolidity/inlineasm/AsmPrinter.cpp | 16 +++++++++++++++- libsolidity/inlineasm/AsmScopeFiller.cpp | 5 ++++- 6 files changed, 71 insertions(+), 15 deletions(-) (limited to 'libsolidity/inlineasm') diff --git a/libsolidity/inlineasm/AsmAnalysis.cpp b/libsolidity/inlineasm/AsmAnalysis.cpp index e03eea2e..8d3d1fd2 100644 --- a/libsolidity/inlineasm/AsmAnalysis.cpp +++ b/libsolidity/inlineasm/AsmAnalysis.cpp @@ -181,12 +181,32 @@ bool AsmAnalyzer::operator()(FunctionalAssignment const& _assignment) bool AsmAnalyzer::operator()(assembly::VariableDeclaration const& _varDecl) { + // The number of variable names and values must match. One exception + // is a single value, where a tuple assignment is assumed from a function. + if (_varDecl.variables.size() != _varDecl.values.size()) + { + if (_varDecl.values.size() != 1) + { + m_errors.push_back(make_shared( + Error::Type::DeclarationError, + "Variable declaration name and value count mismatch.", + _varDecl.location + )); + return false; + } + } + + int const expectedItems = _varDecl.variables.size(); int const stackHeight = m_stackHeight; - bool success = boost::apply_visitor(*this, *_varDecl.value); - solAssert(m_stackHeight - stackHeight == 1, "Invalid value size."); - boost::get(m_currentScope->identifiers.at(_varDecl.variable.name)).active = true; + for (auto const& value: _varDecl.values) + if (!boost::apply_visitor(*this, value)) + return false; + solAssert(m_stackHeight - stackHeight == expectedItems, "Invalid value size."); + + for (auto const& variable: _varDecl.variables) + boost::get(m_currentScope->identifiers.at(variable.name)).active = true; m_info.stackHeightInfo[&_varDecl] = m_stackHeight; - return success; + return true; } bool AsmAnalyzer::operator()(assembly::FunctionDefinition const& _funDef) diff --git a/libsolidity/inlineasm/AsmCodeGen.cpp b/libsolidity/inlineasm/AsmCodeGen.cpp index b8af9dc6..1063d552 100644 --- a/libsolidity/inlineasm/AsmCodeGen.cpp +++ b/libsolidity/inlineasm/AsmCodeGen.cpp @@ -251,11 +251,16 @@ public: void operator()(assembly::VariableDeclaration const& _varDecl) { int height = m_assembly.stackHeight(); - boost::apply_visitor(*this, *_varDecl.value); - expectDeposit(1, height); - auto& var = boost::get(m_scope.identifiers.at(_varDecl.variable.name)); - var.stackHeight = height; - var.active = true; + int expectedItems = _varDecl.variables.size(); + for (auto const& value: _varDecl.values) + boost::apply_visitor(*this, value); + expectDeposit(expectedItems, height); + for (auto const& variable: _varDecl.variables) + { + auto& var = boost::get(m_scope.identifiers.at(variable.name)); + var.stackHeight = height++; + var.active = true; + } } void operator()(assembly::Block const& _block) { diff --git a/libsolidity/inlineasm/AsmData.h b/libsolidity/inlineasm/AsmData.h index 8efe1f07..bf21ba00 100644 --- a/libsolidity/inlineasm/AsmData.h +++ b/libsolidity/inlineasm/AsmData.h @@ -65,7 +65,7 @@ struct FunctionalAssignment { SourceLocation location; Identifier variableName; struct FunctionalInstruction { SourceLocation location; Instruction instruction; std::vector arguments; }; struct FunctionCall { SourceLocation location; Identifier functionName; std::vector arguments; }; /// Block-scope variable declaration ("let x:u256 := mload(20:u256)"), non-hoisted -struct VariableDeclaration { SourceLocation location; TypedName variable; std::shared_ptr value; }; +struct VariableDeclaration { SourceLocation location; TypedNameList variables; std::vector values; }; /// Block that creates a scope (frees declared stack variables) struct Block { SourceLocation location; std::vector statements; }; /// Function definition ("function f(a, b) -> (d, e) { ... }") diff --git a/libsolidity/inlineasm/AsmParser.cpp b/libsolidity/inlineasm/AsmParser.cpp index a96984f5..53954a49 100644 --- a/libsolidity/inlineasm/AsmParser.cpp +++ b/libsolidity/inlineasm/AsmParser.cpp @@ -258,11 +258,25 @@ assembly::VariableDeclaration Parser::parseVariableDeclaration() { VariableDeclaration varDecl = createWithLocation(); expectToken(Token::Let); - varDecl.variable = parseTypedName(); + while (true) + { + varDecl.variables.push_back(parseTypedName()); + if (m_scanner->currentToken() == Token::Comma) + expectToken(Token::Comma); + else + break; + } expectToken(Token::Colon); expectToken(Token::Assign); - varDecl.value.reset(new Statement(parseExpression())); - varDecl.location.end = locationOf(*varDecl.value).end; + while (true) + { + varDecl.values.emplace_back(new Statement(parseExpression())); + if (m_scanner->currentToken() == Token::Comma) + expectToken(Token::Comma); + else + break; + } + varDecl.location.end = locationOf(varDecl.values.back()).end; return varDecl; } diff --git a/libsolidity/inlineasm/AsmPrinter.cpp b/libsolidity/inlineasm/AsmPrinter.cpp index 636e61b8..845aefb9 100644 --- a/libsolidity/inlineasm/AsmPrinter.cpp +++ b/libsolidity/inlineasm/AsmPrinter.cpp @@ -121,7 +121,21 @@ string AsmPrinter::operator()(assembly::FunctionalAssignment const& _functionalA string AsmPrinter::operator()(assembly::VariableDeclaration const& _variableDeclaration) { - return "let " + _variableDeclaration.variable.name + appendTypeName(_variableDeclaration.variable.type) + " := " + boost::apply_visitor(*this, *_variableDeclaration.value); + string out = "let "; + out += boost::algorithm::join( + _variableDeclaration.variables | boost::adaptors::transformed( + [this](TypedName variable) { return variable.name + appendTypeName(variable.type); } + ), + ", " + ); + out += " := "; + out += boost::algorithm::join( + _variableDeclaration.values | boost::adaptors::transformed( + [this](Statement statement) { return boost::apply_visitor(*this, statement); } + ), + ", " + ); + return out; } string AsmPrinter::operator()(assembly::FunctionDefinition const& _functionDefinition) diff --git a/libsolidity/inlineasm/AsmScopeFiller.cpp b/libsolidity/inlineasm/AsmScopeFiller.cpp index eb10dbb3..05b1b211 100644 --- a/libsolidity/inlineasm/AsmScopeFiller.cpp +++ b/libsolidity/inlineasm/AsmScopeFiller.cpp @@ -59,7 +59,10 @@ bool ScopeFiller::operator()(Label const& _item) bool ScopeFiller::operator()(assembly::VariableDeclaration const& _varDecl) { - return registerVariable(_varDecl.variable, _varDecl.location, *m_currentScope); + for (auto const& variable: _varDecl.variables) + if (!registerVariable(variable, _varDecl.location, *m_currentScope)) + return false; + return true; } bool ScopeFiller::operator()(assembly::FunctionDefinition const& _funDef) -- cgit v1.2.3