Merge pull request #6136 from ethereum/yul-break-continue

[Yul] introduce break/continue keywords.
This commit is contained in:
Christian Parpart
2019-03-11 20:38:57 +01:00
committed by GitHub
24 changed files with 277 additions and 10 deletions
+68
View File
@@ -295,6 +295,74 @@ BOOST_AUTO_TEST_CASE(if_statement)
BOOST_CHECK(successParse("{ function f() -> x:bool {} if f() { let b:bool := f() } }"));
}
BOOST_AUTO_TEST_CASE(for_statement)
{
auto dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion::constantinople());
BOOST_CHECK(successParse("{ for {let i := 0} iszero(eq(i, 10)) {i := add(i, 1)} {} }", dialect));
}
BOOST_AUTO_TEST_CASE(for_statement_break)
{
auto dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion::constantinople());
BOOST_CHECK(successParse("{ for {let i := 0} iszero(eq(i, 10)) {i := add(i, 1)} {break} }", dialect));
}
BOOST_AUTO_TEST_CASE(for_statement_break_init)
{
auto dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion::constantinople());
CHECK_ERROR_DIALECT(
"{ for {let i := 0 break} iszero(eq(i, 10)) {i := add(i, 1)} {} }",
SyntaxError,
"Keyword break outside for-loop body is not allowed.",
dialect);
}
BOOST_AUTO_TEST_CASE(for_statement_break_post)
{
auto dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion::constantinople());
CHECK_ERROR_DIALECT(
"{ for {let i := 0} iszero(eq(i, 10)) {i := add(i, 1) break} {} }",
SyntaxError,
"Keyword break outside for-loop body is not allowed.",
dialect);
}
BOOST_AUTO_TEST_CASE(for_statement_nested_break)
{
auto dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion::constantinople());
CHECK_ERROR_DIALECT(
"{ for {let i := 0} iszero(eq(i, 10)) {} { function f() { break } } }",
SyntaxError,
"Keyword break outside for-loop body is not allowed.",
dialect);
}
BOOST_AUTO_TEST_CASE(for_statement_continue)
{
auto dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion::constantinople());
BOOST_CHECK(successParse("{ for {let i := 0} iszero(eq(i, 10)) {i := add(i, 1)} {continue} }", dialect));
}
BOOST_AUTO_TEST_CASE(for_statement_continue_fail_init)
{
auto dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion::constantinople());
CHECK_ERROR_DIALECT(
"{ for {let i := 0 continue} iszero(eq(i, 10)) {i := add(i, 1)} {} }",
SyntaxError,
"Keyword continue outside for-loop body is not allowed.",
dialect);
}
BOOST_AUTO_TEST_CASE(for_statement_continue_fail_post)
{
auto dialect = EVMDialect::strictAssemblyForEVMObjects(EVMVersion::constantinople());
CHECK_ERROR_DIALECT(
"{ for {let i := 0} iszero(eq(i, 10)) {i := add(i, 1) continue} {} }",
SyntaxError,
"Keyword continue outside for-loop body is not allowed.",
dialect);
}
BOOST_AUTO_TEST_CASE(if_statement_invalid)
{
CHECK_ERROR("{ if let x:u256 {} }", ParserError, "Literal or identifier expected.");
+23 -1
View File
@@ -105,12 +105,27 @@ void Interpreter::operator()(ForLoop const& _forLoop)
visit(statement);
while (evaluate(*_forLoop.condition) != 0)
{
m_state.loopState = LoopState::Default;
(*this)(_forLoop.body);
if (m_state.loopState == LoopState::Break)
break;
(*this)(_forLoop.post);
}
m_state.loopState = LoopState::Default;
closeScope();
}
void Interpreter::operator()(Break const&)
{
m_state.loopState = LoopState::Break;
}
void Interpreter::operator()(Continue const&)
{
m_state.loopState = LoopState::Continue;
}
void Interpreter::operator()(Block const& _block)
{
openScope();
@@ -122,7 +137,14 @@ void Interpreter::operator()(Block const& _block)
m_functions[funDef.name] = &funDef;
m_scopes.back().insert(funDef.name);
}
ASTWalker::operator()(_block);
for (auto const& statement: _block.statements)
{
visit(statement);
if (m_state.loopState != LoopState::Default)
break;
}
closeScope();
}
+10
View File
@@ -39,6 +39,13 @@ class InterpreterTerminated: dev::Exception
{
};
enum class LoopState
{
Default,
Continue,
Break,
};
struct InterpreterState
{
dev::bytes calldata;
@@ -65,6 +72,7 @@ struct InterpreterState
std::vector<std::string> trace;
/// This is actually an input parameter that more or less limits the runtime.
size_t maxTraceSize = 0;
LoopState loopState = LoopState::Default;
};
/**
@@ -90,6 +98,8 @@ public:
void operator()(Switch const& _switch) override;
void operator()(FunctionDefinition const&) override;
void operator()(ForLoop const&) override;
void operator()(Break const&) override;
void operator()(Continue const&) override;
void operator()(Block const& _block) override;
std::vector<std::string> const& trace() const { return m_state.trace; }