mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Implement switch statement in the assembly parser/printer
This commit is contained in:
parent
af2d2499c1
commit
b5080860d5
@ -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;
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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.");
|
||||
|
@ -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>
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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())
|
||||
|
@ -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:
|
||||
|
@ -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:
|
||||
|
Loading…
Reference in New Issue
Block a user