mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
[Yul] Adds break/continue statements and some general tests for for-loop syntax.
This commit is contained in:
committed by
Christian Parpart
parent
4704ef843d
commit
05e2d362c8
@@ -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.");
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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; }
|
||||
|
||||
Reference in New Issue
Block a user