diff options
author | Alex Beregszaszi <alex@rtfs.hu> | 2018-01-04 20:04:19 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-01-04 20:04:19 +0800 |
commit | 2cdd789b5d371de6612dadb4ae9a18359cf150df (patch) | |
tree | 963ca2fdf9cf4859fb894205576592622ca934da | |
parent | 14db10b21480ef0876e05ececa7e395ae05326a0 (diff) | |
parent | ca0d244bf7252e76b640f88fbefd6b497a4e9d09 (diff) | |
download | dexon-solidity-2cdd789b5d371de6612dadb4ae9a18359cf150df.tar.gz dexon-solidity-2cdd789b5d371de6612dadb4ae9a18359cf150df.tar.zst dexon-solidity-2cdd789b5d371de6612dadb4ae9a18359cf150df.zip |
Merge pull request #3297 from ethereum/separate_expression_and_statement
Separate expression and statement
-rw-r--r-- | libjulia/ASTDataForward.h | 4 | ||||
-rw-r--r-- | libjulia/backends/evm/EVMCodeTransform.cpp | 9 | ||||
-rw-r--r-- | libjulia/backends/evm/EVMCodeTransform.h | 3 | ||||
-rw-r--r-- | libjulia/optimiser/ASTCopier.cpp | 20 | ||||
-rw-r--r-- | libjulia/optimiser/ASTCopier.h | 59 | ||||
-rw-r--r-- | libjulia/optimiser/ASTWalker.cpp | 10 | ||||
-rw-r--r-- | libjulia/optimiser/ASTWalker.h | 6 | ||||
-rw-r--r-- | libjulia/optimiser/Substitution.cpp | 8 | ||||
-rw-r--r-- | libjulia/optimiser/Substitution.h | 7 | ||||
-rw-r--r-- | libsolidity/analysis/ViewPureChecker.cpp | 4 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmAnalysis.cpp | 16 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmAnalysis.h | 3 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmData.h | 16 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmDataForward.h | 4 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmParser.cpp | 91 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmParser.h | 8 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmPrinter.cpp | 5 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmPrinter.h | 1 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmScopeFiller.cpp | 5 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmScopeFiller.h | 1 | ||||
-rw-r--r-- | test/libsolidity/InlineAssembly.cpp | 8 |
21 files changed, 202 insertions, 86 deletions
diff --git a/libjulia/ASTDataForward.h b/libjulia/ASTDataForward.h index 3806e321..143b9c46 100644 --- a/libjulia/ASTDataForward.h +++ b/libjulia/ASTDataForward.h @@ -42,11 +42,13 @@ using If = solidity::assembly::If; using Case = solidity::assembly::Case; using Switch = solidity::assembly::Switch; using ForLoop = solidity::assembly::ForLoop; +using ExpressionStatement = solidity::assembly::ExpressionStatement; using Block = solidity::assembly::Block; using TypedName = solidity::assembly::TypedName; -using Statement = boost::variant<Instruction, Literal, Label, StackAssignment, Identifier, Assignment, FunctionCall, FunctionalInstruction, VariableDeclaration, FunctionDefinition, If, Switch, ForLoop, Block>; +using Expression = boost::variant<FunctionalInstruction, FunctionCall, Identifier, Literal>; +using Statement = boost::variant<ExpressionStatement, Instruction, Label, StackAssignment, Assignment, VariableDeclaration, FunctionDefinition, If, Switch, ForLoop, Block>; } } diff --git a/libjulia/backends/evm/EVMCodeTransform.cpp b/libjulia/backends/evm/EVMCodeTransform.cpp index f92939be..0c7365fb 100644 --- a/libjulia/backends/evm/EVMCodeTransform.cpp +++ b/libjulia/backends/evm/EVMCodeTransform.cpp @@ -77,6 +77,13 @@ void CodeTransform::operator()(StackAssignment const& _assignment) checkStackHeight(&_assignment); } +void CodeTransform::operator()(ExpressionStatement const& _statement) +{ + m_assembly.setSourceLocation(_statement.location); + boost::apply_visitor(*this, _statement.expression); + checkStackHeight(&_statement); +} + void CodeTransform::operator()(Label const& _label) { m_assembly.setSourceLocation(_label.location); @@ -460,7 +467,7 @@ AbstractAssembly::LabelID CodeTransform::functionEntryID(string const& _name, Sc return m_context->functionEntryIDs[&_function]; } -void CodeTransform::visitExpression(Statement const& _expression) +void CodeTransform::visitExpression(Expression const& _expression) { int height = m_assembly.stackHeight(); boost::apply_visitor(*this, _expression); diff --git a/libjulia/backends/evm/EVMCodeTransform.h b/libjulia/backends/evm/EVMCodeTransform.h index 577cc8ba..0f2aaf95 100644 --- a/libjulia/backends/evm/EVMCodeTransform.h +++ b/libjulia/backends/evm/EVMCodeTransform.h @@ -101,6 +101,7 @@ public: void operator()(Identifier const& _identifier); void operator()(FunctionalInstruction const& _instr); void operator()(FunctionCall const&); + void operator()(ExpressionStatement const& _statement); void operator()(Label const& _label); void operator()(StackAssignment const& _assignment); void operator()(Assignment const& _assignment); @@ -118,7 +119,7 @@ private: AbstractAssembly::LabelID labelID(solidity::assembly::Scope::Label const& _label); AbstractAssembly::LabelID functionEntryID(std::string const& _name, solidity::assembly::Scope::Function const& _function); /// Generates code for an expression that is supposed to return a single value. - void visitExpression(Statement const& _expression); + void visitExpression(Expression const& _expression); void visitStatements(std::vector<Statement> const& _statements); diff --git a/libjulia/optimiser/ASTCopier.cpp b/libjulia/optimiser/ASTCopier.cpp index a461f434..5c47be64 100644 --- a/libjulia/optimiser/ASTCopier.cpp +++ b/libjulia/optimiser/ASTCopier.cpp @@ -37,6 +37,11 @@ Statement ASTCopier::operator()(Instruction const&) return {}; } +Statement ASTCopier::operator()(ExpressionStatement const& _statement) +{ + return ExpressionStatement{ _statement.location, translate(_statement.expression) }; +} + Statement ASTCopier::operator()(VariableDeclaration const& _varDecl) { return VariableDeclaration{ @@ -67,7 +72,7 @@ Statement ASTCopier::operator()(Label const&) return {}; } -Statement ASTCopier::operator()(FunctionCall const& _call) +Expression ASTCopier::operator()(FunctionCall const& _call) { return FunctionCall{ _call.location, @@ -76,7 +81,7 @@ Statement ASTCopier::operator()(FunctionCall const& _call) }; } -Statement ASTCopier::operator()(FunctionalInstruction const& _instruction) +Expression ASTCopier::operator()(FunctionalInstruction const& _instruction) { return FunctionalInstruction{ _instruction.location, @@ -85,12 +90,12 @@ Statement ASTCopier::operator()(FunctionalInstruction const& _instruction) }; } -Statement ASTCopier::operator()(Identifier const& _identifier) +Expression ASTCopier::operator()(Identifier const& _identifier) { return Identifier{_identifier.location, translateIdentifier(_identifier.name)}; } -Statement ASTCopier::operator()(Literal const& _literal) +Expression ASTCopier::operator()(Literal const& _literal) { return translate(_literal); } @@ -140,9 +145,14 @@ Statement ASTCopier::operator ()(Block const& _block) return translate(_block); } +Expression ASTCopier::translate(Expression const& _expression) +{ + return _expression.apply_visitor(static_cast<ExpressionCopier&>(*this)); +} + Statement ASTCopier::translate(Statement const& _statement) { - return boost::apply_visitor(*this, _statement); + return _statement.apply_visitor(static_cast<StatementCopier&>(*this)); } Block ASTCopier::translate(Block const& _block) diff --git a/libjulia/optimiser/ASTCopier.h b/libjulia/optimiser/ASTCopier.h index 5dde2ce9..36a1ced5 100644 --- a/libjulia/optimiser/ASTCopier.h +++ b/libjulia/optimiser/ASTCopier.h @@ -34,28 +34,55 @@ namespace dev namespace julia { +class ExpressionCopier: public boost::static_visitor<Expression> +{ +public: + virtual Expression operator()(Literal const& _literal) = 0; + virtual Expression operator()(Identifier const& _identifier) = 0; + virtual Expression operator()(FunctionalInstruction const& _instr) = 0; + virtual Expression operator()(FunctionCall const&) = 0; +}; + +class StatementCopier: public boost::static_visitor<Statement> +{ +public: + virtual Statement operator()(ExpressionStatement const& _statement) = 0; + virtual Statement operator()(Instruction const& _instruction) = 0; + virtual Statement operator()(Label const& _label) = 0; + virtual Statement operator()(StackAssignment const& _assignment) = 0; + virtual Statement operator()(Assignment const& _assignment) = 0; + virtual Statement operator()(VariableDeclaration const& _varDecl) = 0; + virtual Statement operator()(If const& _if) = 0; + virtual Statement operator()(Switch const& _switch) = 0; + virtual Statement operator()(FunctionDefinition const&) = 0; + virtual Statement operator()(ForLoop const&) = 0; + virtual Statement operator()(Block const& _block) = 0; +}; + /** * Creates a copy of a iulia AST potentially replacing identifier names. * Base class to be extended. */ -class ASTCopier: public boost::static_visitor<Statement> +class ASTCopier: public ExpressionCopier, public StatementCopier { public: - Statement operator()(Literal const& _literal); - Statement operator()(Instruction const& _instruction); - Statement operator()(Identifier const& _identifier); - Statement operator()(FunctionalInstruction const& _instr); - Statement operator()(FunctionCall const&); - Statement operator()(Label const& _label); - Statement operator()(StackAssignment const& _assignment); - Statement operator()(Assignment const& _assignment); - Statement operator()(VariableDeclaration const& _varDecl); - Statement operator()(If const& _if); - Statement operator()(Switch const& _switch); - Statement operator()(FunctionDefinition const&); - Statement operator()(ForLoop const&); - Statement operator()(Block const& _block); - + virtual Expression operator()(Literal const& _literal) override; + virtual Statement operator()(Instruction const& _instruction) override; + virtual Expression operator()(Identifier const& _identifier) override; + virtual Expression operator()(FunctionalInstruction const& _instr) override; + virtual Expression operator()(FunctionCall const&) override; + virtual Statement operator()(ExpressionStatement const& _statement) override; + virtual Statement operator()(Label const& _label) override; + virtual Statement operator()(StackAssignment const& _assignment) override; + virtual Statement operator()(Assignment const& _assignment) override; + virtual Statement operator()(VariableDeclaration const& _varDecl) override; + virtual Statement operator()(If const& _if) override; + virtual Statement operator()(Switch const& _switch) override; + virtual Statement operator()(FunctionDefinition const&) override; + virtual Statement operator()(ForLoop const&) override; + virtual Statement operator()(Block const& _block) override; + + virtual Expression translate(Expression const& _expression); virtual Statement translate(Statement const& _statement); protected: diff --git a/libjulia/optimiser/ASTWalker.cpp b/libjulia/optimiser/ASTWalker.cpp index 0caef04e..499b4bf2 100644 --- a/libjulia/optimiser/ASTWalker.cpp +++ b/libjulia/optimiser/ASTWalker.cpp @@ -42,6 +42,11 @@ void ASTWalker::operator()(FunctionCall const& _funCall) walkVector(_funCall.arguments | boost::adaptors::reversed); } +void ASTWalker::operator()(ExpressionStatement const& _statement) +{ + boost::apply_visitor(*this, _statement.expression); +} + void ASTWalker::operator()(Assignment const& _assignment) { for (auto const& name: _assignment.variableNames) @@ -100,6 +105,11 @@ void ASTModifier::operator()(FunctionCall& _funCall) walkVector(_funCall.arguments | boost::adaptors::reversed); } +void ASTModifier::operator()(ExpressionStatement& _statement) +{ + boost::apply_visitor(*this, _statement.expression); +} + void ASTModifier::operator()(Assignment& _assignment) { for (auto& name: _assignment.variableNames) diff --git a/libjulia/optimiser/ASTWalker.h b/libjulia/optimiser/ASTWalker.h index 8bd867d5..4652a353 100644 --- a/libjulia/optimiser/ASTWalker.h +++ b/libjulia/optimiser/ASTWalker.h @@ -47,6 +47,7 @@ public: virtual void operator()(Identifier const&) {} virtual void operator()(FunctionalInstruction const& _instr); virtual void operator()(FunctionCall const& _funCall); + virtual void operator()(ExpressionStatement const& _statement); virtual void operator()(Label const&) { solAssert(false, ""); } virtual void operator()(StackAssignment const&) { solAssert(false, ""); } virtual void operator()(Assignment const& _assignment); @@ -77,6 +78,7 @@ public: virtual void operator()(Identifier&) {} virtual void operator()(FunctionalInstruction& _instr); virtual void operator()(FunctionCall& _funCall); + virtual void operator()(ExpressionStatement& _statement); virtual void operator()(Label&) { solAssert(false, ""); } virtual void operator()(StackAssignment&) { solAssert(false, ""); } virtual void operator()(Assignment& _assignment); @@ -98,6 +100,10 @@ protected: { boost::apply_visitor(*this, _st); } + virtual void visit(Expression& _e) + { + boost::apply_visitor(*this, _e); + } }; } diff --git a/libjulia/optimiser/Substitution.cpp b/libjulia/optimiser/Substitution.cpp index a49f1f7a..668b6cb6 100644 --- a/libjulia/optimiser/Substitution.cpp +++ b/libjulia/optimiser/Substitution.cpp @@ -26,14 +26,14 @@ using namespace std; using namespace dev; using namespace dev::julia; -Statement Substitution::translate(Statement const& _statement) +Expression Substitution::translate(Expression const& _expression) { - if (_statement.type() == typeid(Identifier)) + if (_expression.type() == typeid(Identifier)) { - string const& name = boost::get<Identifier>(_statement).name; + string const& name = boost::get<Identifier>(_expression).name; if (m_substitutions.count(name)) // No recursive substitution return ASTCopier().translate(*m_substitutions.at(name)); } - return ASTCopier::translate(_statement); + return ASTCopier::translate(_expression); } diff --git a/libjulia/optimiser/Substitution.h b/libjulia/optimiser/Substitution.h index 10bdf32e..313a08d7 100644 --- a/libjulia/optimiser/Substitution.h +++ b/libjulia/optimiser/Substitution.h @@ -33,18 +33,17 @@ namespace julia /** * Specific AST copier that replaces certain identifiers with expressions. - * Only works on ASTs that are expressions. */ class Substitution: public ASTCopier { public: - Substitution(std::map<std::string, Statement const*> const& _substitutions): + Substitution(std::map<std::string, Expression const*> const& _substitutions): m_substitutions(_substitutions) {} - virtual Statement translate(Statement const& _statement) override; + virtual Expression translate(Expression const& _expression) override; private: - std::map<std::string, Statement const*> const& m_substitutions; + std::map<std::string, Expression const*> const& m_substitutions; }; } diff --git a/libsolidity/analysis/ViewPureChecker.cpp b/libsolidity/analysis/ViewPureChecker.cpp index 6788cb05..6257ac6d 100644 --- a/libsolidity/analysis/ViewPureChecker.cpp +++ b/libsolidity/analysis/ViewPureChecker.cpp @@ -50,6 +50,10 @@ public: for (auto const& arg: _instr.arguments) boost::apply_visitor(*this, arg); } + void operator()(assembly::ExpressionStatement const& _expr) + { + boost::apply_visitor(*this, _expr.expression); + } void operator()(assembly::StackAssignment const&) {} void operator()(assembly::Assignment const& _assignment) { diff --git a/libsolidity/inlineasm/AsmAnalysis.cpp b/libsolidity/inlineasm/AsmAnalysis.cpp index 049af65f..17b7cce0 100644 --- a/libsolidity/inlineasm/AsmAnalysis.cpp +++ b/libsolidity/inlineasm/AsmAnalysis.cpp @@ -155,6 +155,16 @@ bool AsmAnalyzer::operator()(FunctionalInstruction const& _instr) return success; } +bool AsmAnalyzer::operator()(assembly::ExpressionStatement const& _statement) +{ +// size_t initialStackHeight = m_stackHeight; + bool success = boost::apply_visitor(*this, _statement.expression); +// if (!expectDeposit(0, initialStackHeight, _statement.location)) +// success = false; + m_info.stackHeightInfo[&_statement] = m_stackHeight; + return success; +} + bool AsmAnalyzer::operator()(assembly::StackAssignment const& _assignment) { solAssert(!m_julia, ""); @@ -407,13 +417,13 @@ bool AsmAnalyzer::operator()(Block const& _block) return success; } -bool AsmAnalyzer::expectExpression(Statement const& _statement) +bool AsmAnalyzer::expectExpression(Expression const& _expr) { bool success = true; int const initialHeight = m_stackHeight; - if (!boost::apply_visitor(*this, _statement)) + if (!boost::apply_visitor(*this, _expr)) success = false; - if (!expectDeposit(1, initialHeight, locationOf(_statement))) + if (!expectDeposit(1, initialHeight, locationOf(_expr))) success = false; return success; } diff --git a/libsolidity/inlineasm/AsmAnalysis.h b/libsolidity/inlineasm/AsmAnalysis.h index e484b876..00a33db3 100644 --- a/libsolidity/inlineasm/AsmAnalysis.h +++ b/libsolidity/inlineasm/AsmAnalysis.h @@ -65,6 +65,7 @@ public: bool operator()(assembly::Identifier const&); bool operator()(assembly::FunctionalInstruction const& _functionalInstruction); bool operator()(assembly::Label const& _label); + bool operator()(assembly::ExpressionStatement const&); bool operator()(assembly::StackAssignment const&); bool operator()(assembly::Assignment const& _assignment); bool operator()(assembly::VariableDeclaration const& _variableDeclaration); @@ -77,7 +78,7 @@ public: private: /// Visits the statement and expects it to deposit one item onto the stack. - bool expectExpression(Statement const& _statement); + bool expectExpression(Expression const& _expr); bool expectDeposit(int _deposit, int _oldHeight, SourceLocation const& _location); /// Verifies that a variable to be assigned to exists and has the same size diff --git a/libsolidity/inlineasm/AsmData.h b/libsolidity/inlineasm/AsmData.h index 11e56fae..2982d5e0 100644 --- a/libsolidity/inlineasm/AsmData.h +++ b/libsolidity/inlineasm/AsmData.h @@ -58,23 +58,25 @@ struct StackAssignment { SourceLocation location; Identifier variableName; }; /// Multiple assignment ("x, y := f()"), where the left hand side variables each occupy /// a single stack slot and expects a single expression on the right hand returning /// the same amount of items as the number of variables. -struct Assignment { SourceLocation location; std::vector<Identifier> variableNames; std::shared_ptr<Statement> value; }; +struct Assignment { SourceLocation location; std::vector<Identifier> variableNames; std::shared_ptr<Expression> value; }; /// Functional instruction, e.g. "mul(mload(20:u256), add(2:u256, x))" -struct FunctionalInstruction { SourceLocation location; solidity::Instruction instruction; std::vector<Statement> arguments; }; -struct FunctionCall { SourceLocation location; Identifier functionName; std::vector<Statement> arguments; }; +struct FunctionalInstruction { SourceLocation location; solidity::Instruction instruction; std::vector<Expression> arguments; }; +struct FunctionCall { SourceLocation location; Identifier functionName; std::vector<Expression> arguments; }; +/// Statement that contains only a single expression +struct ExpressionStatement { SourceLocation location; Expression expression; }; /// Block-scope variable declaration ("let x:u256 := mload(20:u256)"), non-hoisted -struct VariableDeclaration { SourceLocation location; TypedNameList variables; std::shared_ptr<Statement> value; }; +struct VariableDeclaration { SourceLocation location; TypedNameList variables; std::shared_ptr<Expression> value; }; /// Block that creates a scope (frees declared stack variables) struct Block { SourceLocation location; std::vector<Statement> statements; }; /// Function definition ("function f(a, b) -> (d, e) { ... }") struct FunctionDefinition { SourceLocation location; std::string name; TypedNameList parameters; TypedNameList returnVariables; Block body; }; /// Conditional execution without "else" part. -struct If { SourceLocation location; std::shared_ptr<Statement> condition; Block body; }; +struct If { SourceLocation location; std::shared_ptr<Expression> condition; Block body; }; /// Switch case or default case 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 Switch { SourceLocation location; std::shared_ptr<Expression> expression; std::vector<Case> cases; }; +struct ForLoop { SourceLocation location; Block pre; std::shared_ptr<Expression> condition; Block post; Block body; }; struct LocationExtractor: boost::static_visitor<SourceLocation> { diff --git a/libsolidity/inlineasm/AsmDataForward.h b/libsolidity/inlineasm/AsmDataForward.h index 1ab62cc0..317e257c 100644 --- a/libsolidity/inlineasm/AsmDataForward.h +++ b/libsolidity/inlineasm/AsmDataForward.h @@ -45,11 +45,13 @@ struct If; struct Switch; struct Case; struct ForLoop; +struct ExpressionStatement; struct Block; struct TypedName; -using Statement = boost::variant<Instruction, Literal, Label, StackAssignment, Identifier, Assignment, FunctionCall, FunctionalInstruction, VariableDeclaration, FunctionDefinition, If, Switch, ForLoop, Block>; +using Expression = boost::variant<FunctionalInstruction, FunctionCall, Identifier, Literal>; +using Statement = boost::variant<ExpressionStatement, Instruction, Label, StackAssignment, Assignment, VariableDeclaration, FunctionDefinition, If, Switch, ForLoop, Block>; } } diff --git a/libsolidity/inlineasm/AsmParser.cpp b/libsolidity/inlineasm/AsmParser.cpp index 4f8802a0..273e1d5c 100644 --- a/libsolidity/inlineasm/AsmParser.cpp +++ b/libsolidity/inlineasm/AsmParser.cpp @@ -77,9 +77,7 @@ assembly::Statement Parser::parseStatement() { assembly::If _if = createWithLocation<assembly::If>(); m_scanner->next(); - _if.condition = make_shared<Statement>(parseExpression()); - if (_if.condition->type() == typeid(assembly::Instruction)) - fatalParserError("Instructions are not supported as conditions for if - try to append \"()\"."); + _if.condition = make_shared<Expression>(parseExpression()); _if.body = parseBlock(); return _if; } @@ -87,9 +85,7 @@ assembly::Statement Parser::parseStatement() { assembly::Switch _switch = createWithLocation<assembly::Switch>(); m_scanner->next(); - _switch.expression = make_shared<Statement>(parseExpression()); - if (_switch.expression->type() == typeid(assembly::Instruction)) - fatalParserError("Instructions are not supported as expressions for switch - try to append \"()\"."); + _switch.expression = make_shared<Expression>(parseExpression()); while (m_scanner->currentToken() == Token::Case) _switch.cases.emplace_back(parseCase()); if (m_scanner->currentToken() == Token::Default) @@ -127,18 +123,21 @@ assembly::Statement Parser::parseStatement() // Simple instruction (might turn into functional), // literal, // identifier (might turn into label or functional assignment) - Statement statement(parseElementaryOperation(false)); + ElementaryOperation elementary(parseElementaryOperation(false)); switch (currentToken()) { case Token::LParen: - return parseCall(std::move(statement)); + { + Expression expr = parseCall(std::move(elementary)); + return ExpressionStatement{locationOf(expr), expr}; + } case Token::Comma: { // if a comma follows, a multiple assignment is assumed - if (statement.type() != typeid(assembly::Identifier)) + if (elementary.type() != typeid(assembly::Identifier)) fatalParserError("Label name / variable name must precede \",\" (multiple assignment)."); - assembly::Identifier const& identifier = boost::get<assembly::Identifier>(statement); + assembly::Identifier const& identifier = boost::get<assembly::Identifier>(elementary); Assignment assignment = createWithLocation<Assignment>(identifier.location); assignment.variableNames.emplace_back(identifier); @@ -146,25 +145,25 @@ assembly::Statement Parser::parseStatement() do { expectToken(Token::Comma); - statement = parseElementaryOperation(false); - if (statement.type() != typeid(assembly::Identifier)) + elementary = parseElementaryOperation(false); + if (elementary.type() != typeid(assembly::Identifier)) fatalParserError("Variable name expected in multiple assignemnt."); - assignment.variableNames.emplace_back(boost::get<assembly::Identifier>(statement)); + assignment.variableNames.emplace_back(boost::get<assembly::Identifier>(elementary)); } while (currentToken() == Token::Comma); expectToken(Token::Colon); expectToken(Token::Assign); - assignment.value.reset(new Statement(parseExpression())); + assignment.value.reset(new Expression(parseExpression())); assignment.location.end = locationOf(*assignment.value).end; return assignment; } case Token::Colon: { - if (statement.type() != typeid(assembly::Identifier)) + if (elementary.type() != typeid(assembly::Identifier)) fatalParserError("Label name / variable name must precede \":\"."); - assembly::Identifier const& identifier = boost::get<assembly::Identifier>(statement); + assembly::Identifier const& identifier = boost::get<assembly::Identifier>(elementary); advance(); // identifier:=: should be parsed as identifier: =: (i.e. a label), // while identifier:= (being followed by a non-colon) as identifier := (assignment). @@ -175,7 +174,7 @@ assembly::Statement Parser::parseStatement() fatalParserError("Cannot use instruction names for identifier names."); advance(); assignment.variableNames.emplace_back(identifier); - assignment.value.reset(new Statement(parseExpression())); + assignment.value.reset(new Expression(parseExpression())); assignment.location.end = locationOf(*assignment.value).end; return assignment; } @@ -194,7 +193,21 @@ assembly::Statement Parser::parseStatement() fatalParserError("Call or assignment expected."); break; } - return statement; + if (elementary.type() == typeid(assembly::Identifier)) + { + Expression expr = boost::get<assembly::Identifier>(elementary); + return ExpressionStatement{locationOf(expr), expr}; + } + else if (elementary.type() == typeid(assembly::Literal)) + { + Expression expr = boost::get<assembly::Literal>(elementary); + return ExpressionStatement{locationOf(expr), expr}; + } + else + { + solAssert(elementary.type() == typeid(assembly::Instruction), "Invalid elementary operation."); + return boost::get<assembly::Instruction>(elementary); + } } assembly::Case Parser::parseCase() @@ -206,10 +219,10 @@ assembly::Case Parser::parseCase() else if (m_scanner->currentToken() == Token::Case) { m_scanner->next(); - assembly::Statement statement = parseElementaryOperation(); - if (statement.type() != typeid(assembly::Literal)) + ElementaryOperation literal = parseElementaryOperation(); + if (literal.type() != typeid(assembly::Literal)) fatalParserError("Literal expected."); - _case.value = make_shared<Literal>(std::move(boost::get<assembly::Literal>(statement))); + _case.value = make_shared<Literal>(boost::get<assembly::Literal>(std::move(literal))); } else fatalParserError("Case or default case expected."); @@ -224,19 +237,17 @@ 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.condition = make_shared<Expression>(parseExpression()); forLoop.post = parseBlock(); forLoop.body = parseBlock(); forLoop.location.end = forLoop.body.location.end; return forLoop; } -assembly::Statement Parser::parseExpression() +assembly::Expression Parser::parseExpression() { RecursionGuard recursionGuard(*this); - Statement operation = parseElementaryOperation(true); + ElementaryOperation operation = parseElementaryOperation(true); if (operation.type() == typeid(Instruction)) { Instruction const& instr = boost::get<Instruction>(operation); @@ -252,8 +263,18 @@ assembly::Statement Parser::parseExpression() } if (currentToken() == Token::LParen) return parseCall(std::move(operation)); + else if (operation.type() == typeid(Instruction)) + { + Instruction& instr = boost::get<Instruction>(operation); + return FunctionalInstruction{std::move(instr.location), instr.instruction, {}}; + } + else if (operation.type() == typeid(assembly::Identifier)) + return boost::get<assembly::Identifier>(operation); else - return operation; + { + solAssert(operation.type() == typeid(assembly::Literal), ""); + return boost::get<assembly::Literal>(operation); + } } std::map<string, dev::solidity::Instruction> const& Parser::instructions() @@ -296,10 +317,10 @@ std::map<dev::solidity::Instruction, string> const& Parser::instructionNames() return s_instructionNames; } -assembly::Statement Parser::parseElementaryOperation(bool _onlySinglePusher) +Parser::ElementaryOperation Parser::parseElementaryOperation(bool _onlySinglePusher) { RecursionGuard recursionGuard(*this); - Statement ret; + ElementaryOperation ret; switch (currentToken()) { case Token::Identifier: @@ -402,7 +423,7 @@ assembly::VariableDeclaration Parser::parseVariableDeclaration() { expectToken(Token::Colon); expectToken(Token::Assign); - varDecl.value.reset(new Statement(parseExpression())); + varDecl.value.reset(new Expression(parseExpression())); varDecl.location.end = locationOf(*varDecl.value).end; } else @@ -442,13 +463,13 @@ assembly::FunctionDefinition Parser::parseFunctionDefinition() return funDef; } -assembly::Statement Parser::parseCall(assembly::Statement&& _instruction) +assembly::Expression Parser::parseCall(Parser::ElementaryOperation&& _initialOp) { RecursionGuard recursionGuard(*this); - if (_instruction.type() == typeid(Instruction)) + if (_initialOp.type() == typeid(Instruction)) { solAssert(!m_julia, "Instructions are invalid in JULIA"); - Instruction const& instruction = std::move(boost::get<Instruction>(_instruction)); + Instruction& instruction = boost::get<Instruction>(_initialOp); FunctionalInstruction ret; ret.instruction = instruction.instruction; ret.location = std::move(instruction.location); @@ -499,10 +520,10 @@ assembly::Statement Parser::parseCall(assembly::Statement&& _instruction) expectToken(Token::RParen); return ret; } - else if (_instruction.type() == typeid(Identifier)) + else if (_initialOp.type() == typeid(Identifier)) { FunctionCall ret; - ret.functionName = std::move(boost::get<Identifier>(_instruction)); + ret.functionName = std::move(boost::get<Identifier>(_initialOp)); ret.location = ret.functionName.location; expectToken(Token::LParen); while (currentToken() != Token::RParen) diff --git a/libsolidity/inlineasm/AsmParser.h b/libsolidity/inlineasm/AsmParser.h index e46d1732..44889a13 100644 --- a/libsolidity/inlineasm/AsmParser.h +++ b/libsolidity/inlineasm/AsmParser.h @@ -44,6 +44,8 @@ public: std::shared_ptr<Block> parse(std::shared_ptr<Scanner> const& _scanner); protected: + using ElementaryOperation = boost::variant<assembly::Instruction, assembly::Literal, assembly::Identifier>; + /// Creates an inline assembly node with the given source location. template <class T> T createWithLocation(SourceLocation const& _loc = SourceLocation()) const { @@ -65,13 +67,13 @@ protected: Case parseCase(); ForLoop parseForLoop(); /// Parses a functional expression that has to push exactly one stack element - Statement parseExpression(); + assembly::Expression parseExpression(); static std::map<std::string, dev::solidity::Instruction> const& instructions(); static std::map<dev::solidity::Instruction, std::string> const& instructionNames(); - Statement parseElementaryOperation(bool _onlySinglePusher = false); + ElementaryOperation parseElementaryOperation(bool _onlySinglePusher = false); VariableDeclaration parseVariableDeclaration(); FunctionDefinition parseFunctionDefinition(); - Statement parseCall(Statement&& _instruction); + assembly::Expression parseCall(ElementaryOperation&& _initialOp); TypedName parseTypedName(); std::string expectAsmIdentifier(); diff --git a/libsolidity/inlineasm/AsmPrinter.cpp b/libsolidity/inlineasm/AsmPrinter.cpp index c72586cb..bacd7a94 100644 --- a/libsolidity/inlineasm/AsmPrinter.cpp +++ b/libsolidity/inlineasm/AsmPrinter.cpp @@ -102,6 +102,11 @@ string AsmPrinter::operator()(assembly::FunctionalInstruction const& _functional ")"; } +string AsmPrinter::operator()(ExpressionStatement const& _statement) +{ + return boost::apply_visitor(*this, _statement.expression); +} + string AsmPrinter::operator()(assembly::Label const& _label) { solAssert(!m_julia, ""); diff --git a/libsolidity/inlineasm/AsmPrinter.h b/libsolidity/inlineasm/AsmPrinter.h index eadf81d9..5bd87aba 100644 --- a/libsolidity/inlineasm/AsmPrinter.h +++ b/libsolidity/inlineasm/AsmPrinter.h @@ -42,6 +42,7 @@ public: std::string operator()(assembly::Literal const& _literal); std::string operator()(assembly::Identifier const& _identifier); std::string operator()(assembly::FunctionalInstruction const& _functionalInstruction); + std::string operator()(assembly::ExpressionStatement const& _expr); std::string operator()(assembly::Label const& _label); std::string operator()(assembly::StackAssignment const& _assignment); std::string operator()(assembly::Assignment const& _assignment); diff --git a/libsolidity/inlineasm/AsmScopeFiller.cpp b/libsolidity/inlineasm/AsmScopeFiller.cpp index 0984e7d2..86f3809c 100644 --- a/libsolidity/inlineasm/AsmScopeFiller.cpp +++ b/libsolidity/inlineasm/AsmScopeFiller.cpp @@ -45,6 +45,11 @@ ScopeFiller::ScopeFiller(AsmAnalysisInfo& _info, ErrorReporter& _errorReporter): m_currentScope = &scope(nullptr); } +bool ScopeFiller::operator()(ExpressionStatement const& _expr) +{ + return boost::apply_visitor(*this, _expr.expression); +} + bool ScopeFiller::operator()(Label const& _item) { if (!m_currentScope->registerLabel(_item.name)) diff --git a/libsolidity/inlineasm/AsmScopeFiller.h b/libsolidity/inlineasm/AsmScopeFiller.h index ed28abbf..bb023f61 100644 --- a/libsolidity/inlineasm/AsmScopeFiller.h +++ b/libsolidity/inlineasm/AsmScopeFiller.h @@ -53,6 +53,7 @@ public: bool operator()(assembly::Literal const&) { return true; } bool operator()(assembly::Identifier const&) { return true; } bool operator()(assembly::FunctionalInstruction const&) { return true; } + bool operator()(assembly::ExpressionStatement const& _expr); bool operator()(assembly::Label const& _label); bool operator()(assembly::StackAssignment const&) { return true; } bool operator()(assembly::Assignment const&) { return true; } diff --git a/test/libsolidity/InlineAssembly.cpp b/test/libsolidity/InlineAssembly.cpp index 82bafd49..94e02b8f 100644 --- a/test/libsolidity/InlineAssembly.cpp +++ b/test/libsolidity/InlineAssembly.cpp @@ -266,7 +266,7 @@ BOOST_AUTO_TEST_CASE(if_statement_scope) BOOST_AUTO_TEST_CASE(if_statement_invalid) { - CHECK_PARSE_ERROR("{ if calldatasize {}", ParserError, "Instructions are not supported as conditions for if"); + CHECK_PARSE_ERROR("{ if mload {} }", ParserError, "Expected token \"(\""); BOOST_CHECK("{ if calldatasize() {}"); CHECK_PARSE_ERROR("{ if mstore(1, 1) {} }", ParserError, "Instruction \"mstore\" not allowed in this context"); CHECK_PARSE_ERROR("{ if 32 let x := 3 }", ParserError, "Expected token LBrace"); @@ -296,7 +296,7 @@ BOOST_AUTO_TEST_CASE(switch_duplicate_case) BOOST_AUTO_TEST_CASE(switch_invalid_expression) { CHECK_PARSE_ERROR("{ switch {} default {} }", ParserError, "Literal, identifier or instruction expected."); - CHECK_PARSE_ERROR("{ switch calldatasize default {} }", ParserError, "Instructions are not supported as expressions for switch"); + CHECK_PARSE_ERROR("{ switch mload default {} }", ParserError, "Expected token \"(\""); CHECK_PARSE_ERROR("{ switch mstore(1, 1) default {} }", ParserError, "Instruction \"mstore\" not allowed in this context"); } @@ -332,7 +332,7 @@ BOOST_AUTO_TEST_CASE(for_invalid_expression) CHECK_PARSE_ERROR("{ for 1 1 {} {} }", ParserError, "Expected token LBrace got 'Number'"); CHECK_PARSE_ERROR("{ for {} 1 1 {} }", ParserError, "Expected token LBrace got 'Number'"); CHECK_PARSE_ERROR("{ for {} 1 {} 1 }", ParserError, "Expected token LBrace got 'Number'"); - CHECK_PARSE_ERROR("{ for {} calldatasize {} {} }", ParserError, "Instructions are not supported as conditions for the for statement."); + CHECK_PARSE_ERROR("{ for {} mload {} {} }", ParserError, "Expected token \"(\""); CHECK_PARSE_ERROR("{ for {} mstore(1, 1) {} {} }", ParserError, "Instruction \"mstore\" not allowed in this context"); } @@ -540,7 +540,7 @@ BOOST_AUTO_TEST_CASE(function_calls) function g(a, b, c) { } - g(1, mul(2, address), f(mul(2, caller))) + g(1, mul(2, address()), f(mul(2, caller()))) y() })"; boost::replace_all(source, "\t", " "); |