mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Parse for statement in assembly parser / printer
This commit is contained in:
parent
54e97d1c34
commit
47925bc14e
@ -53,6 +53,11 @@ void CodeTransform::run(Block const& _block)
|
||||
}
|
||||
|
||||
|
||||
void CodeTransform::operator()(ForLoop const&)
|
||||
{
|
||||
solAssert(false, "For loop not removed during desugaring phase.");
|
||||
}
|
||||
|
||||
void CodeTransform::operator()(VariableDeclaration const& _varDecl)
|
||||
{
|
||||
solAssert(m_scope, "");
|
||||
|
@ -32,21 +32,6 @@ namespace solidity
|
||||
class ErrorReporter;
|
||||
namespace assembly
|
||||
{
|
||||
struct Literal;
|
||||
struct Block;
|
||||
struct Switch;
|
||||
struct Label;
|
||||
struct FunctionalInstruction;
|
||||
struct Assignment;
|
||||
struct VariableDeclaration;
|
||||
struct Instruction;
|
||||
struct Identifier;
|
||||
struct StackAssignment;
|
||||
struct FunctionDefinition;
|
||||
struct FunctionCall;
|
||||
|
||||
using Statement = boost::variant<Instruction, Literal, Label, StackAssignment, Identifier, Assignment, FunctionCall, FunctionalInstruction, VariableDeclaration, FunctionDefinition, Switch, Block>;
|
||||
|
||||
struct AsmAnalysisInfo;
|
||||
}
|
||||
}
|
||||
@ -115,6 +100,7 @@ public:
|
||||
void operator()(solidity::assembly::VariableDeclaration const& _varDecl);
|
||||
void operator()(solidity::assembly::Switch const& _switch);
|
||||
void operator()(solidity::assembly::FunctionDefinition const&);
|
||||
void operator()(solidity::assembly::ForLoop const&);
|
||||
void operator()(solidity::assembly::Block const& _block);
|
||||
|
||||
private:
|
||||
|
@ -310,6 +310,11 @@ bool AsmAnalyzer::operator()(Switch const& _switch)
|
||||
return success;
|
||||
}
|
||||
|
||||
bool AsmAnalyzer::operator()(assembly::ForLoop const&)
|
||||
{
|
||||
solAssert(false, "For loop not supported.");
|
||||
}
|
||||
|
||||
bool AsmAnalyzer::operator()(Block const& _block)
|
||||
{
|
||||
bool success = true;
|
||||
|
@ -51,7 +51,8 @@ struct StackAssignment;
|
||||
struct FunctionDefinition;
|
||||
struct FunctionCall;
|
||||
struct Switch;
|
||||
using Statement = boost::variant<Instruction, Literal, Label, StackAssignment, Identifier, Assignment, FunctionCall, FunctionalInstruction, VariableDeclaration, FunctionDefinition, Switch, Block>;
|
||||
struct ForLoop;
|
||||
using Statement = boost::variant<Instruction, Literal, Label, StackAssignment, Identifier, Assignment, FunctionCall, FunctionalInstruction, VariableDeclaration, FunctionDefinition, Switch, Block, ForLoop>;
|
||||
|
||||
struct AsmAnalysisInfo;
|
||||
|
||||
@ -83,6 +84,7 @@ public:
|
||||
bool operator()(assembly::FunctionDefinition const& _functionDefinition);
|
||||
bool operator()(assembly::FunctionCall const& _functionCall);
|
||||
bool operator()(assembly::Switch const& _switch);
|
||||
bool operator()(assembly::ForLoop const& _forLoop);
|
||||
bool operator()(assembly::Block const& _block);
|
||||
|
||||
private:
|
||||
|
@ -45,10 +45,11 @@ struct StackAssignment;
|
||||
struct FunctionDefinition;
|
||||
struct FunctionCall;
|
||||
struct Switch;
|
||||
struct ForLoop;
|
||||
|
||||
struct Scope;
|
||||
|
||||
using Statement = boost::variant<Instruction, Literal, Label, StackAssignment, Identifier, Assignment, FunctionCall, FunctionalInstruction, VariableDeclaration, FunctionDefinition, Switch, Block>;
|
||||
using Statement = boost::variant<Instruction, Literal, Label, StackAssignment, Identifier, Assignment, FunctionCall, FunctionalInstruction, VariableDeclaration, FunctionDefinition, Switch, ForLoop, Block>;
|
||||
|
||||
struct AsmAnalysisInfo
|
||||
{
|
||||
|
@ -51,9 +51,10 @@ struct FunctionalInstruction;
|
||||
struct FunctionDefinition;
|
||||
struct FunctionCall;
|
||||
struct Switch;
|
||||
struct ForLoop;
|
||||
struct Block;
|
||||
|
||||
using Statement = boost::variant<Instruction, Literal, Label, StackAssignment, Identifier, Assignment, FunctionCall, FunctionalInstruction, VariableDeclaration, FunctionDefinition, Switch, Block>;
|
||||
using Statement = boost::variant<Instruction, Literal, Label, StackAssignment, Identifier, Assignment, FunctionCall, FunctionalInstruction, VariableDeclaration, FunctionDefinition, Switch, ForLoop, Block>;
|
||||
|
||||
/// Direct EVM instruction (except PUSHi and JUMPDEST)
|
||||
struct Instruction { SourceLocation location; solidity::Instruction instruction; };
|
||||
@ -82,6 +83,7 @@ struct FunctionDefinition { SourceLocation location; std::string name; TypedName
|
||||
struct Case { SourceLocation location; std::shared_ptr<Literal> value; Block body; };
|
||||
/// Switch statement
|
||||
struct Switch { SourceLocation location; std::shared_ptr<Statement> expression; std::vector<Case> cases; };
|
||||
struct ForLoop { SourceLocation location; Block pre; std::shared_ptr<Statement> condition; Block post; Block body; };
|
||||
|
||||
struct LocationExtractor: boost::static_visitor<SourceLocation>
|
||||
{
|
||||
|
@ -87,6 +87,8 @@ assembly::Statement Parser::parseStatement()
|
||||
_switch.location.end = _switch.cases.back().body.location.end;
|
||||
return _switch;
|
||||
}
|
||||
case Token::For:
|
||||
return parseForLoop();
|
||||
case Token::Assign:
|
||||
{
|
||||
if (m_julia)
|
||||
@ -171,6 +173,20 @@ assembly::Case Parser::parseCase()
|
||||
return _case;
|
||||
}
|
||||
|
||||
assembly::ForLoop Parser::parseForLoop()
|
||||
{
|
||||
ForLoop forLoop = createWithLocation<ForLoop>();
|
||||
expectToken(Token::For);
|
||||
forLoop.pre = parseBlock();
|
||||
forLoop.condition = make_shared<Statement>(parseExpression());
|
||||
if (forLoop.condition->type() == typeid(assembly::Instruction))
|
||||
fatalParserError("Instructions are not supported as conditions for the for statement.");
|
||||
forLoop.post = parseBlock();
|
||||
forLoop.body = parseBlock();
|
||||
forLoop.location.end = forLoop.body.location.end;
|
||||
return forLoop;
|
||||
}
|
||||
|
||||
assembly::Statement Parser::parseExpression()
|
||||
{
|
||||
Statement operation = parseElementaryOperation(true);
|
||||
|
@ -63,6 +63,7 @@ protected:
|
||||
Block parseBlock();
|
||||
Statement parseStatement();
|
||||
Case parseCase();
|
||||
ForLoop parseForLoop();
|
||||
/// Parses a functional expression that has to push exactly one stack element
|
||||
Statement parseExpression();
|
||||
static std::map<std::string, dev::solidity::Instruction> const& instructions();
|
||||
|
@ -181,6 +181,19 @@ string AsmPrinter::operator()(Switch const& _switch)
|
||||
return out;
|
||||
}
|
||||
|
||||
string AsmPrinter::operator()(assembly::ForLoop const& _forLoop)
|
||||
{
|
||||
string out = "for ";
|
||||
out += (*this)(_forLoop.pre);
|
||||
out += "\n";
|
||||
out += boost::apply_visitor(*this, *_forLoop.condition);
|
||||
out += "\n";
|
||||
out += (*this)(_forLoop.post);
|
||||
out += "\n";
|
||||
out += (*this)(_forLoop.body);
|
||||
return out;
|
||||
}
|
||||
|
||||
string AsmPrinter::operator()(Block const& _block)
|
||||
{
|
||||
if (_block.statements.empty())
|
||||
|
@ -41,6 +41,7 @@ struct VariableDeclaration;
|
||||
struct FunctionDefinition;
|
||||
struct FunctionCall;
|
||||
struct Switch;
|
||||
struct ForLoop;
|
||||
struct Block;
|
||||
|
||||
class AsmPrinter: public boost::static_visitor<std::string>
|
||||
@ -59,6 +60,7 @@ public:
|
||||
std::string operator()(assembly::FunctionDefinition const& _functionDefinition);
|
||||
std::string operator()(assembly::FunctionCall const& _functionCall);
|
||||
std::string operator()(assembly::Switch const& _switch);
|
||||
std::string operator()(assembly::ForLoop const& _forLoop);
|
||||
std::string operator()(assembly::Block const& _block);
|
||||
|
||||
private:
|
||||
|
@ -111,6 +111,11 @@ bool ScopeFiller::operator()(Switch const& _switch)
|
||||
return success;
|
||||
}
|
||||
|
||||
bool ScopeFiller::operator()(ForLoop const&)
|
||||
{
|
||||
solAssert(false, "For loop not supported.");
|
||||
}
|
||||
|
||||
bool ScopeFiller::operator()(Block const& _block)
|
||||
{
|
||||
bool success = true;
|
||||
|
@ -47,6 +47,7 @@ struct StackAssignment;
|
||||
struct FunctionDefinition;
|
||||
struct FunctionCall;
|
||||
struct Switch;
|
||||
struct ForLoop;
|
||||
|
||||
struct Scope;
|
||||
struct AsmAnalysisInfo;
|
||||
@ -71,6 +72,7 @@ public:
|
||||
bool operator()(assembly::FunctionDefinition const& _functionDefinition);
|
||||
bool operator()(assembly::FunctionCall const&) { return true; }
|
||||
bool operator()(assembly::Switch const& _switch);
|
||||
bool operator()(assembly::ForLoop const& _forLoop);
|
||||
bool operator()(assembly::Block const& _block);
|
||||
|
||||
private:
|
||||
|
@ -291,6 +291,18 @@ BOOST_AUTO_TEST_CASE(switch_invalid_body)
|
||||
CHECK_PARSE_ERROR("{ switch 42 case 1 mul case 2 {} default {} }", ParserError, "Expected token LBrace got 'Identifier'");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(for_statement)
|
||||
{
|
||||
BOOST_CHECK(successParse("{ for {} 1 {} {} }"));
|
||||
BOOST_CHECK(successParse("{ for { let i := 1 } le(i, 5) { i := add(i, 1) } {} }"));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(for_invalid_expression)
|
||||
{
|
||||
CHECK_PARSE_ERROR("{ for {} {} {} {} }", ParserError, "Literal, identifier or instruction expected.");
|
||||
CHECK_PARSE_ERROR("{ 1 2 for {} mul {} {} }", ParserError, "Instructions are not supported as conditions for the for statement.");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(blocks)
|
||||
{
|
||||
BOOST_CHECK(successParse("{ let x := 7 { let y := 3 } { let z := 2 } }"));
|
||||
@ -409,6 +421,11 @@ BOOST_AUTO_TEST_CASE(print_switch)
|
||||
parsePrintCompare("{\n switch 42\n case 1 {\n }\n case 2 {\n }\n default {\n }\n}");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(print_for)
|
||||
{
|
||||
parsePrintCompare("{\n let ret := 5\n for {\n let i := 1\n }\n le(i, 15)\n {\n i := add(i, 1)\n }\n {\n ret := mul(ret, i)\n }\n}");
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(function_definitions_multiple_args)
|
||||
{
|
||||
parsePrintCompare("{\n function f(a, d)\n {\n mstore(a, d)\n }\n function g(a, d) -> x, y\n {\n }\n}");
|
||||
|
Loading…
Reference in New Issue
Block a user