diff options
author | Alex Beregszaszi <alex@rtfs.hu> | 2017-04-28 21:27:56 +0800 |
---|---|---|
committer | Alex Beregszaszi <alex@rtfs.hu> | 2017-05-26 10:16:09 +0800 |
commit | b5080860d5f2d141b8fccceaa635378a86c996a8 (patch) | |
tree | a68c289d101e5f4d3a990da2e8c7608bb4f0fcbc | |
parent | af2d2499c1ccd431f5ac9455c2cbb63d3891f9b0 (diff) | |
download | dexon-solidity-b5080860d5f2d141b8fccceaa635378a86c996a8.tar.gz dexon-solidity-b5080860d5f2d141b8fccceaa635378a86c996a8.tar.zst dexon-solidity-b5080860d5f2d141b8fccceaa635378a86c996a8.zip |
Implement switch statement in the assembly parser/printer
-rw-r--r-- | libsolidity/inlineasm/AsmAnalysis.cpp | 32 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmAnalysis.h | 2 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmAnalysisInfo.h | 3 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmCodeGen.cpp | 4 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmData.h | 7 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmParser.cpp | 30 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmParser.h | 1 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmPrinter.cpp | 14 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmPrinter.h | 2 | ||||
-rw-r--r-- | libsolidity/inlineasm/AsmScopeFiller.h | 2 |
10 files changed, 95 insertions, 2 deletions
diff --git a/libsolidity/inlineasm/AsmAnalysis.cpp b/libsolidity/inlineasm/AsmAnalysis.cpp index 65b935f2..ecc63372 100644 --- a/libsolidity/inlineasm/AsmAnalysis.cpp +++ b/libsolidity/inlineasm/AsmAnalysis.cpp @@ -285,6 +285,38 @@ bool AsmAnalyzer::operator()(assembly::FunctionCall const& _funCall) return success; } +bool AsmAnalyzer::operator()(Switch const& _switch) +{ + int const initialStackHeight = m_stackHeight; + if (!boost::apply_visitor(*this, *_switch.expression)) + return false; + expectDeposit(1, initialStackHeight, locationOf(*_switch.expression)); + + map<string, bool> caseNames; + for (auto const& _case: _switch.cases) + { + /// Note: the parser ensures there is only one default case + if (caseNames[_case.name]) + { + m_errors.push_back(make_shared<Error>( + Error::Type::DeclarationError, + "Duplicate case defined: " + _case.name, + _case.location + )); + return false; + } + else + caseNames[_case.name] = true; + + if (!(*this)(_case.body)) + return false; + } + + m_stackHeight--; + + return true; +} + bool AsmAnalyzer::operator()(Block const& _block) { bool success = true; diff --git a/libsolidity/inlineasm/AsmAnalysis.h b/libsolidity/inlineasm/AsmAnalysis.h index f09e4b59..9f022b12 100644 --- a/libsolidity/inlineasm/AsmAnalysis.h +++ b/libsolidity/inlineasm/AsmAnalysis.h @@ -47,6 +47,7 @@ struct Identifier; struct StackAssignment; struct FunctionDefinition; struct FunctionCall; +struct Switch; struct Scope; @@ -78,6 +79,7 @@ public: bool operator()(assembly::VariableDeclaration const& _variableDeclaration); bool operator()(assembly::FunctionDefinition const& _functionDefinition); bool operator()(assembly::FunctionCall const& _functionCall); + bool operator()(assembly::Switch const& _switch); bool operator()(assembly::Block const& _block); private: diff --git a/libsolidity/inlineasm/AsmAnalysisInfo.h b/libsolidity/inlineasm/AsmAnalysisInfo.h index d2253c78..18382db0 100644 --- a/libsolidity/inlineasm/AsmAnalysisInfo.h +++ b/libsolidity/inlineasm/AsmAnalysisInfo.h @@ -43,10 +43,11 @@ struct Identifier; struct StackAssignment; struct FunctionDefinition; struct FunctionCall; +struct Switch; struct Scope; -using Statement = boost::variant<Instruction, Literal, Label, StackAssignment, Identifier, Assignment, FunctionCall, FunctionalInstruction, VariableDeclaration, FunctionDefinition, Block>; +using Statement = boost::variant<Instruction, Literal, Label, StackAssignment, Identifier, Assignment, FunctionCall, FunctionalInstruction, VariableDeclaration, FunctionDefinition, Switch, Block>; struct AsmAnalysisInfo { diff --git a/libsolidity/inlineasm/AsmCodeGen.cpp b/libsolidity/inlineasm/AsmCodeGen.cpp index 53eafc96..5c66b125 100644 --- a/libsolidity/inlineasm/AsmCodeGen.cpp +++ b/libsolidity/inlineasm/AsmCodeGen.cpp @@ -266,6 +266,10 @@ public: CodeTransform(m_state, m_assembly, _block, m_identifierAccess, m_initialStackHeight); checkStackHeight(&_block); } + void operator()(assembly::Switch const&) + { + solAssert(false, "Switch not removed during desugaring phase."); + } void operator()(assembly::FunctionDefinition const&) { solAssert(false, "Function definition not removed during desugaring phase."); diff --git a/libsolidity/inlineasm/AsmData.h b/libsolidity/inlineasm/AsmData.h index 3b4048c3..92ff1c5a 100644 --- a/libsolidity/inlineasm/AsmData.h +++ b/libsolidity/inlineasm/AsmData.h @@ -50,9 +50,10 @@ struct VariableDeclaration; struct FunctionalInstruction; struct FunctionDefinition; struct FunctionCall; +struct Switch; struct Block; -using Statement = boost::variant<Instruction, Literal, Label, StackAssignment, Identifier, Assignment, FunctionCall, FunctionalInstruction, VariableDeclaration, FunctionDefinition, Block>; +using Statement = boost::variant<Instruction, Literal, Label, StackAssignment, Identifier, Assignment, FunctionCall, FunctionalInstruction, VariableDeclaration, FunctionDefinition, Switch, Block>; /// Direct EVM instruction (except PUSHi and JUMPDEST) struct Instruction { SourceLocation location; solidity::Instruction instruction; }; @@ -77,6 +78,10 @@ struct VariableDeclaration { SourceLocation location; TypedNameList variables; s struct Block { SourceLocation location; std::vector<Statement> statements; }; /// Function definition ("function f(a, b) -> (d, e) { ... }") struct FunctionDefinition { SourceLocation location; std::string name; TypedNameList arguments; TypedNameList returns; Block body; }; +/// Switch case or default case +struct Case { SourceLocation location; std::string name; Block body; }; +/// Switch statement +struct Switch { SourceLocation location; std::shared_ptr<Statement> expression; std::vector<Case> cases; }; struct LocationExtractor: boost::static_visitor<SourceLocation> { diff --git a/libsolidity/inlineasm/AsmParser.cpp b/libsolidity/inlineasm/AsmParser.cpp index 530cd726..a3a25a42 100644 --- a/libsolidity/inlineasm/AsmParser.cpp +++ b/libsolidity/inlineasm/AsmParser.cpp @@ -67,6 +67,20 @@ assembly::Statement Parser::parseStatement() return parseFunctionDefinition(); case Token::LBrace: return parseBlock(); + case Token::Switch: + { + assembly::Switch _switch = createWithLocation<assembly::Switch>(); + m_scanner->next(); + _switch.expression = make_shared<Statement>(parseExpression()); + while (m_scanner->currentToken() == Token::Case) + _switch.cases.emplace_back(parseCase()); + if (m_scanner->currentToken() == Token::Default) + _switch.cases.emplace_back(parseCase(true)); + if (_switch.cases.size() == 0) + fatalParserError("Switch statement without any cases."); + _switch.location.end = _switch.cases.back().body.location.end; + return _switch; + } case Token::Assign: { if (m_julia) @@ -134,6 +148,22 @@ assembly::Statement Parser::parseStatement() return statement; } +assembly::Case Parser::parseCase(bool _defaultCase) +{ + assembly::Case _case = createWithLocation<assembly::Case>(); + if (_defaultCase) + expectToken(Token::Default); + else + { + expectToken(Token::Case); + _case.name = expectAsmIdentifier(); + } + expectToken(Token::Colon); + _case.body = parseBlock(); + _case.location.end = _case.body.location.end; + return _case; +} + assembly::Statement Parser::parseExpression() { Statement operation = parseElementaryOperation(true); diff --git a/libsolidity/inlineasm/AsmParser.h b/libsolidity/inlineasm/AsmParser.h index 812762a6..d1d0c1cc 100644 --- a/libsolidity/inlineasm/AsmParser.h +++ b/libsolidity/inlineasm/AsmParser.h @@ -62,6 +62,7 @@ protected: Block parseBlock(); Statement parseStatement(); + Case parseCase(bool _defaultCase = false); /// Parses a functional expression that has to push exactly one stack element Statement parseExpression(); std::map<std::string, dev::solidity::Instruction> const& instructions(); diff --git a/libsolidity/inlineasm/AsmPrinter.cpp b/libsolidity/inlineasm/AsmPrinter.cpp index 92b12423..92200f84 100644 --- a/libsolidity/inlineasm/AsmPrinter.cpp +++ b/libsolidity/inlineasm/AsmPrinter.cpp @@ -167,6 +167,20 @@ string AsmPrinter::operator()(assembly::FunctionCall const& _functionCall) ")"; } +string AsmPrinter::operator()(Switch const& _switch) +{ + string out = "switch " + boost::apply_visitor(*this, *_switch.expression); + for (auto const& _case: _switch.cases) + { + if (_case.name.empty()) + out += "\ndefault: "; + else + out += "\ncase " + _case.name + ": "; + out += (*this)(_case.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 423eeefa..b0d7fc09 100644 --- a/libsolidity/inlineasm/AsmPrinter.h +++ b/libsolidity/inlineasm/AsmPrinter.h @@ -40,6 +40,7 @@ struct Assignment; struct VariableDeclaration; struct FunctionDefinition; struct FunctionCall; +struct Switch; struct Block; class AsmPrinter: public boost::static_visitor<std::string> @@ -57,6 +58,7 @@ public: std::string operator()(assembly::VariableDeclaration const& _variableDeclaration); 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::Block const& _block); private: diff --git a/libsolidity/inlineasm/AsmScopeFiller.h b/libsolidity/inlineasm/AsmScopeFiller.h index b1b0833b..0f5a5dd6 100644 --- a/libsolidity/inlineasm/AsmScopeFiller.h +++ b/libsolidity/inlineasm/AsmScopeFiller.h @@ -46,6 +46,7 @@ struct Identifier; struct StackAssignment; struct FunctionDefinition; struct FunctionCall; +struct Switch; struct Scope; @@ -69,6 +70,7 @@ public: bool operator()(assembly::VariableDeclaration const& _variableDeclaration); bool operator()(assembly::FunctionDefinition const& _functionDefinition); bool operator()(assembly::FunctionCall const&) { return true; } + bool operator()(assembly::Switch const&) { return true; }; bool operator()(assembly::Block const& _block); private: |