diff options
author | chriseth <chris@ethereum.org> | 2017-12-08 21:01:22 +0800 |
---|---|---|
committer | chriseth <chris@ethereum.org> | 2017-12-13 19:28:15 +0800 |
commit | 54b6739962ef45319777ce2aebafdf4b91412d84 (patch) | |
tree | d15c289ebb4e57b16678b93e223bc477e9093b6c /libsolidity/inlineasm | |
parent | 7614b16dc9b2bb1e267e8f46834b40220fb9f9fb (diff) | |
download | dexon-solidity-54b6739962ef45319777ce2aebafdf4b91412d84.tar.gz dexon-solidity-54b6739962ef45319777ce2aebafdf4b91412d84.tar.zst dexon-solidity-54b6739962ef45319777ce2aebafdf4b91412d84.zip |
Separate expression and statement.
Diffstat (limited to 'libsolidity/inlineasm')
-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 |
10 files changed, 100 insertions, 50 deletions
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; } |