aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Beregszaszi <alex@rtfs.hu>2017-04-28 21:27:56 +0800
committerAlex Beregszaszi <alex@rtfs.hu>2017-05-26 10:16:09 +0800
commitb5080860d5f2d141b8fccceaa635378a86c996a8 (patch)
treea68c289d101e5f4d3a990da2e8c7608bb4f0fcbc
parentaf2d2499c1ccd431f5ac9455c2cbb63d3891f9b0 (diff)
downloaddexon-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.cpp32
-rw-r--r--libsolidity/inlineasm/AsmAnalysis.h2
-rw-r--r--libsolidity/inlineasm/AsmAnalysisInfo.h3
-rw-r--r--libsolidity/inlineasm/AsmCodeGen.cpp4
-rw-r--r--libsolidity/inlineasm/AsmData.h7
-rw-r--r--libsolidity/inlineasm/AsmParser.cpp30
-rw-r--r--libsolidity/inlineasm/AsmParser.h1
-rw-r--r--libsolidity/inlineasm/AsmPrinter.cpp14
-rw-r--r--libsolidity/inlineasm/AsmPrinter.h2
-rw-r--r--libsolidity/inlineasm/AsmScopeFiller.h2
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: