aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity/inlineasm
diff options
context:
space:
mode:
Diffstat (limited to 'libsolidity/inlineasm')
-rw-r--r--libsolidity/inlineasm/AsmAnalysis.cpp16
-rw-r--r--libsolidity/inlineasm/AsmAnalysis.h3
-rw-r--r--libsolidity/inlineasm/AsmData.h16
-rw-r--r--libsolidity/inlineasm/AsmDataForward.h4
-rw-r--r--libsolidity/inlineasm/AsmParser.cpp91
-rw-r--r--libsolidity/inlineasm/AsmParser.h8
-rw-r--r--libsolidity/inlineasm/AsmPrinter.cpp5
-rw-r--r--libsolidity/inlineasm/AsmPrinter.h1
-rw-r--r--libsolidity/inlineasm/AsmScopeFiller.cpp5
-rw-r--r--libsolidity/inlineasm/AsmScopeFiller.h1
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; }