mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #2244 from ethereum/inlineasm-let-multi
Support tuple assignment in inline assembly
This commit is contained in:
commit
14b22150a1
@ -181,10 +181,21 @@ bool AsmAnalyzer::operator()(FunctionalAssignment const& _assignment)
|
|||||||
|
|
||||||
bool AsmAnalyzer::operator()(assembly::VariableDeclaration const& _varDecl)
|
bool AsmAnalyzer::operator()(assembly::VariableDeclaration const& _varDecl)
|
||||||
{
|
{
|
||||||
|
int const expectedItems = _varDecl.variables.size();
|
||||||
int const stackHeight = m_stackHeight;
|
int const stackHeight = m_stackHeight;
|
||||||
bool success = boost::apply_visitor(*this, *_varDecl.value);
|
bool success = boost::apply_visitor(*this, *_varDecl.value);
|
||||||
solAssert(m_stackHeight - stackHeight == 1, "Invalid value size.");
|
if ((m_stackHeight - stackHeight) != expectedItems)
|
||||||
boost::get<Scope::Variable>(m_currentScope->identifiers.at(_varDecl.variable.name)).active = true;
|
{
|
||||||
|
m_errors.push_back(make_shared<Error>(
|
||||||
|
Error::Type::DeclarationError,
|
||||||
|
"Variable count mismatch.",
|
||||||
|
_varDecl.location
|
||||||
|
));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto const& variable: _varDecl.variables)
|
||||||
|
boost::get<Scope::Variable>(m_currentScope->identifiers.at(variable.name)).active = true;
|
||||||
m_info.stackHeightInfo[&_varDecl] = m_stackHeight;
|
m_info.stackHeightInfo[&_varDecl] = m_stackHeight;
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
@ -251,11 +251,15 @@ public:
|
|||||||
void operator()(assembly::VariableDeclaration const& _varDecl)
|
void operator()(assembly::VariableDeclaration const& _varDecl)
|
||||||
{
|
{
|
||||||
int height = m_assembly.stackHeight();
|
int height = m_assembly.stackHeight();
|
||||||
|
int expectedItems = _varDecl.variables.size();
|
||||||
boost::apply_visitor(*this, *_varDecl.value);
|
boost::apply_visitor(*this, *_varDecl.value);
|
||||||
expectDeposit(1, height);
|
expectDeposit(expectedItems, height);
|
||||||
auto& var = boost::get<Scope::Variable>(m_scope.identifiers.at(_varDecl.variable.name));
|
for (auto const& variable: _varDecl.variables)
|
||||||
var.stackHeight = height;
|
{
|
||||||
var.active = true;
|
auto& var = boost::get<Scope::Variable>(m_scope.identifiers.at(variable.name));
|
||||||
|
var.stackHeight = height++;
|
||||||
|
var.active = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
void operator()(assembly::Block const& _block)
|
void operator()(assembly::Block const& _block)
|
||||||
{
|
{
|
||||||
|
@ -65,7 +65,7 @@ struct FunctionalAssignment { SourceLocation location; Identifier variableName;
|
|||||||
struct FunctionalInstruction { SourceLocation location; Instruction instruction; std::vector<Statement> arguments; };
|
struct FunctionalInstruction { SourceLocation location; Instruction instruction; std::vector<Statement> arguments; };
|
||||||
struct FunctionCall { SourceLocation location; Identifier functionName; std::vector<Statement> arguments; };
|
struct FunctionCall { SourceLocation location; Identifier functionName; std::vector<Statement> arguments; };
|
||||||
/// Block-scope variable declaration ("let x:u256 := mload(20:u256)"), non-hoisted
|
/// Block-scope variable declaration ("let x:u256 := mload(20:u256)"), non-hoisted
|
||||||
struct VariableDeclaration { SourceLocation location; TypedName variable; std::shared_ptr<Statement> value; };
|
struct VariableDeclaration { SourceLocation location; TypedNameList variables; std::shared_ptr<Statement> value; };
|
||||||
/// Block that creates a scope (frees declared stack variables)
|
/// Block that creates a scope (frees declared stack variables)
|
||||||
struct Block { SourceLocation location; std::vector<Statement> statements; };
|
struct Block { SourceLocation location; std::vector<Statement> statements; };
|
||||||
/// Function definition ("function f(a, b) -> (d, e) { ... }")
|
/// Function definition ("function f(a, b) -> (d, e) { ... }")
|
||||||
|
@ -258,7 +258,14 @@ assembly::VariableDeclaration Parser::parseVariableDeclaration()
|
|||||||
{
|
{
|
||||||
VariableDeclaration varDecl = createWithLocation<VariableDeclaration>();
|
VariableDeclaration varDecl = createWithLocation<VariableDeclaration>();
|
||||||
expectToken(Token::Let);
|
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::Colon);
|
||||||
expectToken(Token::Assign);
|
expectToken(Token::Assign);
|
||||||
varDecl.value.reset(new Statement(parseExpression()));
|
varDecl.value.reset(new Statement(parseExpression()));
|
||||||
|
@ -121,7 +121,16 @@ string AsmPrinter::operator()(assembly::FunctionalAssignment const& _functionalA
|
|||||||
|
|
||||||
string AsmPrinter::operator()(assembly::VariableDeclaration const& _variableDeclaration)
|
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::apply_visitor(*this, *_variableDeclaration.value);
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
string AsmPrinter::operator()(assembly::FunctionDefinition const& _functionDefinition)
|
string AsmPrinter::operator()(assembly::FunctionDefinition const& _functionDefinition)
|
||||||
|
@ -59,7 +59,10 @@ bool ScopeFiller::operator()(Label const& _item)
|
|||||||
|
|
||||||
bool ScopeFiller::operator()(assembly::VariableDeclaration const& _varDecl)
|
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)
|
bool ScopeFiller::operator()(assembly::FunctionDefinition const& _funDef)
|
||||||
|
@ -161,6 +161,11 @@ BOOST_AUTO_TEST_CASE(function_calls)
|
|||||||
BOOST_CHECK(successParse("{ function f(a:u256) -> b:u256 {} function g(a:u256, b:u256, c:u256) {} function x() { g(1:u256, 2:u256, f(mul(2:u256, 3:u256))) x() } }"));
|
BOOST_CHECK(successParse("{ function f(a:u256) -> b:u256 {} function g(a:u256, b:u256, c:u256) {} function x() { g(1:u256, 2:u256, f(mul(2:u256, 3:u256))) x() } }"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(tuple_assignment)
|
||||||
|
{
|
||||||
|
BOOST_CHECK(successParse("{ function f() -> a:u256, b:u256, c:u256 {} let x:u256, y:u256, z:u256 := f() }"));
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(label)
|
BOOST_AUTO_TEST_CASE(label)
|
||||||
{
|
{
|
||||||
CHECK_ERROR("{ label: }", ParserError, "Labels are not supported.");
|
CHECK_ERROR("{ label: }", ParserError, "Labels are not supported.");
|
||||||
|
@ -161,6 +161,21 @@ BOOST_AUTO_TEST_CASE(vardecl)
|
|||||||
BOOST_CHECK(successParse("{ let x := 7 }"));
|
BOOST_CHECK(successParse("{ let x := 7 }"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(vardecl_name_clashes)
|
||||||
|
{
|
||||||
|
CHECK_PARSE_ERROR("{ let x := 1 let x := 2 }", DeclarationError, "Variable name x already taken in this scope.");
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(vardecl_multi)
|
||||||
|
{
|
||||||
|
BOOST_CHECK(successParse("{ function f() -> x, y {} let x, y := f() }"));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(vardecl_multi_conflict)
|
||||||
|
{
|
||||||
|
CHECK_PARSE_ERROR("{ function f() -> x, y {} let x, x := f() }", DeclarationError, "Variable name x already taken in this scope.");
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(vardecl_bool)
|
BOOST_AUTO_TEST_CASE(vardecl_bool)
|
||||||
{
|
{
|
||||||
CHECK_PARSE_ERROR("{ let x := true }", ParserError, "True and false are not valid literals.");
|
CHECK_PARSE_ERROR("{ let x := true }", ParserError, "True and false are not valid literals.");
|
||||||
@ -249,6 +264,12 @@ BOOST_AUTO_TEST_CASE(variable_access_cross_functions)
|
|||||||
CHECK_PARSE_ERROR("{ let x := 2 function g() { x pop } }", DeclarationError, "Identifier not found.");
|
CHECK_PARSE_ERROR("{ let x := 2 function g() { x pop } }", DeclarationError, "Identifier not found.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(invalid_tuple_assignment)
|
||||||
|
{
|
||||||
|
/// The push(42) is added here to silence the unbalanced stack error, so that there's only one error reported.
|
||||||
|
CHECK_PARSE_ERROR("{ 42 let x, y := 1 }", DeclarationError, "Variable count mismatch.");
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE_END()
|
BOOST_AUTO_TEST_SUITE_END()
|
||||||
|
|
||||||
BOOST_AUTO_TEST_SUITE(Printing)
|
BOOST_AUTO_TEST_SUITE(Printing)
|
||||||
@ -283,6 +304,11 @@ BOOST_AUTO_TEST_CASE(print_assignments)
|
|||||||
parsePrintCompare("{\n let x := mul(2, 3)\n 7\n =: x\n x := add(1, 2)\n}");
|
parsePrintCompare("{\n let x := mul(2, 3)\n 7\n =: x\n x := add(1, 2)\n}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(print_multi_assignments)
|
||||||
|
{
|
||||||
|
parsePrintCompare("{\n function f() -> x, y\n {\n }\n let x, y := f()\n}");
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(print_string_literals)
|
BOOST_AUTO_TEST_CASE(print_string_literals)
|
||||||
{
|
{
|
||||||
parsePrintCompare("{\n \"\\n'\\xab\\x95\\\"\"\n pop\n}");
|
parsePrintCompare("{\n \"\\n'\\xab\\x95\\\"\"\n pop\n}");
|
||||||
|
Loading…
Reference in New Issue
Block a user