From 47925bc14e80d0c33c491dabc3c3dd3ea787b63c Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Fri, 28 Apr 2017 14:33:52 +0100 Subject: Parse for statement in assembly parser / printer --- libjulia/backends/evm/EVMCodeTransform.cpp | 5 +++++ libjulia/backends/evm/EVMCodeTransform.h | 16 +--------------- libsolidity/inlineasm/AsmAnalysis.cpp | 5 +++++ libsolidity/inlineasm/AsmAnalysis.h | 4 +++- libsolidity/inlineasm/AsmAnalysisInfo.h | 3 ++- libsolidity/inlineasm/AsmData.h | 4 +++- libsolidity/inlineasm/AsmParser.cpp | 16 ++++++++++++++++ libsolidity/inlineasm/AsmParser.h | 1 + libsolidity/inlineasm/AsmPrinter.cpp | 13 +++++++++++++ libsolidity/inlineasm/AsmPrinter.h | 2 ++ libsolidity/inlineasm/AsmScopeFiller.cpp | 5 +++++ libsolidity/inlineasm/AsmScopeFiller.h | 2 ++ test/libsolidity/InlineAssembly.cpp | 17 +++++++++++++++++ 13 files changed, 75 insertions(+), 18 deletions(-) diff --git a/libjulia/backends/evm/EVMCodeTransform.cpp b/libjulia/backends/evm/EVMCodeTransform.cpp index 7c14eb8b..00d0bde5 100644 --- a/libjulia/backends/evm/EVMCodeTransform.cpp +++ b/libjulia/backends/evm/EVMCodeTransform.cpp @@ -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, ""); diff --git a/libjulia/backends/evm/EVMCodeTransform.h b/libjulia/backends/evm/EVMCodeTransform.h index 202f5051..9814f0f5 100644 --- a/libjulia/backends/evm/EVMCodeTransform.h +++ b/libjulia/backends/evm/EVMCodeTransform.h @@ -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; - 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: diff --git a/libsolidity/inlineasm/AsmAnalysis.cpp b/libsolidity/inlineasm/AsmAnalysis.cpp index 1a529118..68c940e7 100644 --- a/libsolidity/inlineasm/AsmAnalysis.cpp +++ b/libsolidity/inlineasm/AsmAnalysis.cpp @@ -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; diff --git a/libsolidity/inlineasm/AsmAnalysis.h b/libsolidity/inlineasm/AsmAnalysis.h index 2516722a..5cdf72b1 100644 --- a/libsolidity/inlineasm/AsmAnalysis.h +++ b/libsolidity/inlineasm/AsmAnalysis.h @@ -51,7 +51,8 @@ struct StackAssignment; struct FunctionDefinition; struct FunctionCall; struct Switch; -using Statement = boost::variant; +struct ForLoop; +using Statement = boost::variant; 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: diff --git a/libsolidity/inlineasm/AsmAnalysisInfo.h b/libsolidity/inlineasm/AsmAnalysisInfo.h index 78c1fbe0..a75413a2 100644 --- a/libsolidity/inlineasm/AsmAnalysisInfo.h +++ b/libsolidity/inlineasm/AsmAnalysisInfo.h @@ -45,10 +45,11 @@ struct StackAssignment; struct FunctionDefinition; struct FunctionCall; struct Switch; +struct ForLoop; struct Scope; -using Statement = boost::variant; +using Statement = boost::variant; struct AsmAnalysisInfo { diff --git a/libsolidity/inlineasm/AsmData.h b/libsolidity/inlineasm/AsmData.h index 72afeef1..c2458bd7 100644 --- a/libsolidity/inlineasm/AsmData.h +++ b/libsolidity/inlineasm/AsmData.h @@ -51,9 +51,10 @@ struct FunctionalInstruction; struct FunctionDefinition; struct FunctionCall; struct Switch; +struct ForLoop; struct Block; -using Statement = boost::variant; +using Statement = boost::variant; /// 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 value; Block body; }; /// Switch statement struct Switch { SourceLocation location; std::shared_ptr expression; std::vector cases; }; +struct ForLoop { SourceLocation location; Block pre; std::shared_ptr condition; Block post; Block body; }; struct LocationExtractor: boost::static_visitor { diff --git a/libsolidity/inlineasm/AsmParser.cpp b/libsolidity/inlineasm/AsmParser.cpp index f9b073ba..d282a30d 100644 --- a/libsolidity/inlineasm/AsmParser.cpp +++ b/libsolidity/inlineasm/AsmParser.cpp @@ -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(); + expectToken(Token::For); + forLoop.pre = parseBlock(); + forLoop.condition = make_shared(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); diff --git a/libsolidity/inlineasm/AsmParser.h b/libsolidity/inlineasm/AsmParser.h index 5fafad23..45708afd 100644 --- a/libsolidity/inlineasm/AsmParser.h +++ b/libsolidity/inlineasm/AsmParser.h @@ -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 const& instructions(); diff --git a/libsolidity/inlineasm/AsmPrinter.cpp b/libsolidity/inlineasm/AsmPrinter.cpp index e282e5e8..0d06fedd 100644 --- a/libsolidity/inlineasm/AsmPrinter.cpp +++ b/libsolidity/inlineasm/AsmPrinter.cpp @@ -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()) diff --git a/libsolidity/inlineasm/AsmPrinter.h b/libsolidity/inlineasm/AsmPrinter.h index b0d7fc09..8808b058 100644 --- a/libsolidity/inlineasm/AsmPrinter.h +++ b/libsolidity/inlineasm/AsmPrinter.h @@ -41,6 +41,7 @@ struct VariableDeclaration; struct FunctionDefinition; struct FunctionCall; struct Switch; +struct ForLoop; struct Block; class AsmPrinter: public boost::static_visitor @@ -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: diff --git a/libsolidity/inlineasm/AsmScopeFiller.cpp b/libsolidity/inlineasm/AsmScopeFiller.cpp index 4d26dcf8..1aac902a 100644 --- a/libsolidity/inlineasm/AsmScopeFiller.cpp +++ b/libsolidity/inlineasm/AsmScopeFiller.cpp @@ -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; diff --git a/libsolidity/inlineasm/AsmScopeFiller.h b/libsolidity/inlineasm/AsmScopeFiller.h index 1166d50f..f04352c9 100644 --- a/libsolidity/inlineasm/AsmScopeFiller.h +++ b/libsolidity/inlineasm/AsmScopeFiller.h @@ -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: diff --git a/test/libsolidity/InlineAssembly.cpp b/test/libsolidity/InlineAssembly.cpp index aae6dacd..a3339d47 100644 --- a/test/libsolidity/InlineAssembly.cpp +++ b/test/libsolidity/InlineAssembly.cpp @@ -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}"); -- cgit