mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #2225 from ethereum/julia-for
Implement for statement in assembly parser / printer / code generator
This commit is contained in:
@@ -310,6 +310,33 @@ bool AsmAnalyzer::operator()(Switch const& _switch)
|
||||
return success;
|
||||
}
|
||||
|
||||
bool AsmAnalyzer::operator()(assembly::ForLoop const& _for)
|
||||
{
|
||||
Scope* originalScope = m_currentScope;
|
||||
|
||||
bool success = true;
|
||||
if (!(*this)(_for.pre))
|
||||
success = false;
|
||||
// The block was closed already, but we re-open it again and stuff the
|
||||
// condition, the body and the post part inside.
|
||||
m_stackHeight += scope(&_for.pre).numberOfVariables();
|
||||
m_currentScope = &scope(&_for.pre);
|
||||
|
||||
if (!expectExpression(*_for.condition))
|
||||
success = false;
|
||||
m_stackHeight--;
|
||||
if (!(*this)(_for.body))
|
||||
success = false;
|
||||
if (!(*this)(_for.post))
|
||||
success = false;
|
||||
|
||||
m_stackHeight -= scope(&_for.pre).numberOfVariables();
|
||||
m_info.stackHeightInfo[&_for] = m_stackHeight;
|
||||
m_currentScope = originalScope;
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool AsmAnalyzer::operator()(Block const& _block)
|
||||
{
|
||||
bool success = true;
|
||||
@@ -322,9 +349,7 @@ bool AsmAnalyzer::operator()(Block const& _block)
|
||||
if (!boost::apply_visitor(*this, s))
|
||||
success = false;
|
||||
|
||||
for (auto const& identifier: scope(&_block).identifiers)
|
||||
if (identifier.second.type() == typeid(Scope::Variable))
|
||||
--m_stackHeight;
|
||||
m_stackHeight -= scope(&_block).numberOfVariables();
|
||||
|
||||
int const stackDiff = m_stackHeight - initialStackHeight;
|
||||
if (stackDiff != 0)
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
|
||||
#include <libjulia/backends/evm/AbstractAssembly.h>
|
||||
|
||||
#include <libsolidity/inlineasm/AsmDataForward.h>
|
||||
|
||||
#include <boost/variant.hpp>
|
||||
|
||||
#include <functional>
|
||||
@@ -39,20 +41,6 @@ class ErrorReporter;
|
||||
namespace assembly
|
||||
{
|
||||
|
||||
struct Literal;
|
||||
struct Block;
|
||||
struct Label;
|
||||
struct FunctionalInstruction;
|
||||
struct Assignment;
|
||||
struct VariableDeclaration;
|
||||
struct Instruction;
|
||||
struct Identifier;
|
||||
struct StackAssignment;
|
||||
struct FunctionDefinition;
|
||||
struct FunctionCall;
|
||||
struct Switch;
|
||||
using Statement = boost::variant<Instruction, Literal, Label, StackAssignment, Identifier, Assignment, FunctionCall, FunctionalInstruction, VariableDeclaration, FunctionDefinition, Switch, Block>;
|
||||
|
||||
struct AsmAnalysisInfo;
|
||||
|
||||
/**
|
||||
@@ -83,6 +71,7 @@ public:
|
||||
bool operator()(assembly::FunctionDefinition const& _functionDefinition);
|
||||
bool operator()(assembly::FunctionCall const& _functionCall);
|
||||
bool operator()(assembly::Switch const& _switch);
|
||||
bool operator()(assembly::ForLoop const& _forLoop);
|
||||
bool operator()(assembly::Block const& _block);
|
||||
|
||||
private:
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <libsolidity/inlineasm/AsmDataForward.h>
|
||||
|
||||
#include <boost/variant.hpp>
|
||||
|
||||
#include <map>
|
||||
@@ -33,23 +35,8 @@ namespace solidity
|
||||
namespace assembly
|
||||
{
|
||||
|
||||
struct Literal;
|
||||
struct Block;
|
||||
struct Label;
|
||||
struct FunctionalInstruction;
|
||||
struct Assignment;
|
||||
struct VariableDeclaration;
|
||||
struct Instruction;
|
||||
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, Switch, Block>;
|
||||
|
||||
struct AsmAnalysisInfo
|
||||
{
|
||||
using StackHeightInfo = std::map<void const*, int>;
|
||||
|
||||
@@ -141,5 +141,5 @@ void assembly::CodeGenerator::assemble(
|
||||
)
|
||||
{
|
||||
EthAssemblyAdapter assemblyAdapter(_assembly);
|
||||
julia::CodeTransform(assemblyAdapter, _analysisInfo, false, _identifierAccess).run(_parsedData);
|
||||
julia::CodeTransform(assemblyAdapter, _analysisInfo, false, _identifierAccess)(_parsedData);
|
||||
}
|
||||
|
||||
@@ -22,10 +22,13 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/variant.hpp>
|
||||
#include <libsolidity/inlineasm/AsmDataForward.h>
|
||||
|
||||
#include <libevmasm/Instruction.h>
|
||||
#include <libevmasm/SourceLocation.h>
|
||||
|
||||
#include <boost/variant.hpp>
|
||||
|
||||
namespace dev
|
||||
{
|
||||
namespace solidity
|
||||
@@ -38,23 +41,6 @@ using Type = std::string;
|
||||
struct TypedName { SourceLocation location; std::string name; Type type; };
|
||||
using TypedNameList = std::vector<TypedName>;
|
||||
|
||||
/// What follows are the AST nodes for assembly.
|
||||
|
||||
struct Instruction;
|
||||
struct Literal;
|
||||
struct Label;
|
||||
struct StackAssignment;
|
||||
struct Identifier;
|
||||
struct Assignment;
|
||||
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, Switch, Block>;
|
||||
|
||||
/// Direct EVM instruction (except PUSHi and JUMPDEST)
|
||||
struct Instruction { SourceLocation location; solidity::Instruction instruction; };
|
||||
/// Literal number or string (up to 32 bytes)
|
||||
@@ -82,6 +68,7 @@ struct FunctionDefinition { SourceLocation location; std::string name; TypedName
|
||||
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 LocationExtractor: boost::static_visitor<SourceLocation>
|
||||
{
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
This file is part of solidity.
|
||||
|
||||
solidity is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
solidity is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with solidity. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/**
|
||||
* @author Christian <c@ethdev.com>
|
||||
* @date 2016
|
||||
* Forward declaration of classes for inline assembly / JULIA AST
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <boost/variant.hpp>
|
||||
|
||||
namespace dev
|
||||
{
|
||||
namespace solidity
|
||||
{
|
||||
namespace assembly
|
||||
{
|
||||
|
||||
struct Instruction;
|
||||
struct Literal;
|
||||
struct Label;
|
||||
struct StackAssignment;
|
||||
struct Identifier;
|
||||
struct Assignment;
|
||||
struct VariableDeclaration;
|
||||
struct FunctionalInstruction;
|
||||
struct FunctionDefinition;
|
||||
struct FunctionCall;
|
||||
struct Switch;
|
||||
struct ForLoop;
|
||||
struct Block;
|
||||
|
||||
using Statement = boost::variant<Instruction, Literal, Label, StackAssignment, Identifier, Assignment, FunctionCall, FunctionalInstruction, VariableDeclaration, FunctionDefinition, Switch, ForLoop, Block>;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -87,6 +87,8 @@ assembly::Statement Parser::parseStatement()
|
||||
_switch.location.end = _switch.cases.back().body.location.end;
|
||||
return _switch;
|
||||
}
|
||||
case Token::For:
|
||||
return parseForLoop();
|
||||
case Token::Assign:
|
||||
{
|
||||
if (m_julia)
|
||||
@@ -171,6 +173,20 @@ assembly::Case Parser::parseCase()
|
||||
return _case;
|
||||
}
|
||||
|
||||
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.post = parseBlock();
|
||||
forLoop.body = parseBlock();
|
||||
forLoop.location.end = forLoop.body.location.end;
|
||||
return forLoop;
|
||||
}
|
||||
|
||||
assembly::Statement Parser::parseExpression()
|
||||
{
|
||||
Statement operation = parseElementaryOperation(true);
|
||||
|
||||
@@ -63,6 +63,7 @@ protected:
|
||||
Block parseBlock();
|
||||
Statement parseStatement();
|
||||
Case parseCase();
|
||||
ForLoop parseForLoop();
|
||||
/// Parses a functional expression that has to push exactly one stack element
|
||||
Statement parseExpression();
|
||||
static std::map<std::string, dev::solidity::Instruction> const& instructions();
|
||||
|
||||
@@ -181,6 +181,19 @@ string AsmPrinter::operator()(Switch const& _switch)
|
||||
return out;
|
||||
}
|
||||
|
||||
string AsmPrinter::operator()(assembly::ForLoop const& _forLoop)
|
||||
{
|
||||
string out = "for ";
|
||||
out += (*this)(_forLoop.pre);
|
||||
out += "\n";
|
||||
out += boost::apply_visitor(*this, *_forLoop.condition);
|
||||
out += "\n";
|
||||
out += (*this)(_forLoop.post);
|
||||
out += "\n";
|
||||
out += (*this)(_forLoop.body);
|
||||
return out;
|
||||
}
|
||||
|
||||
string AsmPrinter::operator()(Block const& _block)
|
||||
{
|
||||
if (_block.statements.empty())
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <libsolidity/inlineasm/AsmDataForward.h>
|
||||
|
||||
#include <boost/variant.hpp>
|
||||
|
||||
namespace dev
|
||||
@@ -30,18 +32,6 @@ namespace solidity
|
||||
{
|
||||
namespace assembly
|
||||
{
|
||||
struct Instruction;
|
||||
struct Literal;
|
||||
struct Identifier;
|
||||
struct FunctionalInstruction;
|
||||
struct Label;
|
||||
struct StackAssignment;
|
||||
struct Assignment;
|
||||
struct VariableDeclaration;
|
||||
struct FunctionDefinition;
|
||||
struct FunctionCall;
|
||||
struct Switch;
|
||||
struct Block;
|
||||
|
||||
class AsmPrinter: public boost::static_visitor<std::string>
|
||||
{
|
||||
@@ -59,6 +49,7 @@ public:
|
||||
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::ForLoop const& _forLoop);
|
||||
std::string operator()(assembly::Block const& _block);
|
||||
|
||||
private:
|
||||
|
||||
@@ -80,6 +80,15 @@ bool Scope::exists(string const& _name)
|
||||
return false;
|
||||
}
|
||||
|
||||
size_t Scope::numberOfVariables() const
|
||||
{
|
||||
size_t count = 0;
|
||||
for (auto const& identifier: identifiers)
|
||||
if (identifier.second.type() == typeid(Scope::Variable))
|
||||
count++;
|
||||
return count;
|
||||
}
|
||||
|
||||
bool Scope::insideFunction() const
|
||||
{
|
||||
for (Scope const* s = this; s; s = s->superScope)
|
||||
|
||||
@@ -109,6 +109,8 @@ struct Scope
|
||||
/// across function and assembly boundaries).
|
||||
bool exists(std::string const& _name);
|
||||
|
||||
/// @returns the number of variables directly registered inside the scope.
|
||||
size_t numberOfVariables() const;
|
||||
/// @returns true if this scope is inside a function.
|
||||
bool insideFunction() const;
|
||||
|
||||
|
||||
@@ -111,6 +111,26 @@ bool ScopeFiller::operator()(Switch const& _switch)
|
||||
return success;
|
||||
}
|
||||
|
||||
bool ScopeFiller::operator()(ForLoop const& _forLoop)
|
||||
{
|
||||
Scope* originalScope = m_currentScope;
|
||||
|
||||
bool success = true;
|
||||
if (!(*this)(_forLoop.pre))
|
||||
success = false;
|
||||
m_currentScope = &scope(&_forLoop.pre);
|
||||
if (!boost::apply_visitor(*this, *_forLoop.condition))
|
||||
success = false;
|
||||
if (!(*this)(_forLoop.body))
|
||||
success = false;
|
||||
if (!(*this)(_forLoop.post))
|
||||
success = false;
|
||||
|
||||
m_currentScope = originalScope;
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool ScopeFiller::operator()(Block const& _block)
|
||||
{
|
||||
bool success = true;
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <libsolidity/inlineasm/AsmDataForward.h>
|
||||
|
||||
#include <boost/variant.hpp>
|
||||
|
||||
#include <functional>
|
||||
@@ -35,19 +37,6 @@ namespace assembly
|
||||
{
|
||||
|
||||
struct TypedName;
|
||||
struct Literal;
|
||||
struct Block;
|
||||
struct Label;
|
||||
struct FunctionalInstruction;
|
||||
struct Assignment;
|
||||
struct VariableDeclaration;
|
||||
struct Instruction;
|
||||
struct Identifier;
|
||||
struct StackAssignment;
|
||||
struct FunctionDefinition;
|
||||
struct FunctionCall;
|
||||
struct Switch;
|
||||
|
||||
struct Scope;
|
||||
struct AsmAnalysisInfo;
|
||||
|
||||
@@ -71,6 +60,7 @@ public:
|
||||
bool operator()(assembly::FunctionDefinition const& _functionDefinition);
|
||||
bool operator()(assembly::FunctionCall const&) { return true; }
|
||||
bool operator()(assembly::Switch const& _switch);
|
||||
bool operator()(assembly::ForLoop const& _forLoop);
|
||||
bool operator()(assembly::Block const& _block);
|
||||
|
||||
private:
|
||||
|
||||
@@ -100,7 +100,7 @@ MachineAssemblyObject AssemblyStack::assemble(Machine _machine) const
|
||||
{
|
||||
MachineAssemblyObject object;
|
||||
julia::EVMAssembly assembly(true);
|
||||
julia::CodeTransform(assembly, *m_analysisInfo, true).run(*m_parserResult);
|
||||
julia::CodeTransform(assembly, *m_analysisInfo, true)(*m_parserResult);
|
||||
object.bytecode = make_shared<eth::LinkerObject>(assembly.finalize());
|
||||
/// TOOD: fill out text representation
|
||||
return object;
|
||||
|
||||
Reference in New Issue
Block a user