aboutsummaryrefslogtreecommitdiffstats
path: root/libyul
diff options
context:
space:
mode:
authorchriseth <chris@ethereum.org>2018-12-03 22:48:03 +0800
committerGitHub <noreply@github.com>2018-12-03 22:48:03 +0800
commitc8a2cb62832afb2dc09ccee6fd42c1516dfdb981 (patch)
tree7977e9dcbbc215088c05b847f849871ef5d4ae66 /libyul
parent1d4f565a64988a3400847d2655ca24f73f234bc6 (diff)
parent590be1d84cea9850ce69b68be3dc5294b39041e5 (diff)
downloaddexon-solidity-c8a2cb62832afb2dc09ccee6fd42c1516dfdb981.tar
dexon-solidity-c8a2cb62832afb2dc09ccee6fd42c1516dfdb981.tar.gz
dexon-solidity-c8a2cb62832afb2dc09ccee6fd42c1516dfdb981.tar.bz2
dexon-solidity-c8a2cb62832afb2dc09ccee6fd42c1516dfdb981.tar.lz
dexon-solidity-c8a2cb62832afb2dc09ccee6fd42c1516dfdb981.tar.xz
dexon-solidity-c8a2cb62832afb2dc09ccee6fd42c1516dfdb981.tar.zst
dexon-solidity-c8a2cb62832afb2dc09ccee6fd42c1516dfdb981.zip
Merge pull request #5571 from ethereum/develop
Version 0.5.1
Diffstat (limited to 'libyul')
-rw-r--r--libyul/ASTDataForward.h55
-rw-r--r--libyul/AsmAnalysis.cpp632
-rw-r--r--libyul/AsmAnalysis.h122
-rw-r--r--libyul/AsmAnalysisInfo.cpp26
-rw-r--r--libyul/AsmAnalysisInfo.h46
-rw-r--r--libyul/AsmCodeGen.cpp163
-rw-r--r--libyul/AsmCodeGen.h54
-rw-r--r--libyul/AsmData.h96
-rw-r--r--libyul/AsmDataForward.h59
-rw-r--r--libyul/AsmParser.cpp617
-rw-r--r--libyul/AsmParser.h89
-rw-r--r--libyul/AsmPrinter.cpp250
-rw-r--r--libyul/AsmPrinter.h62
-rw-r--r--libyul/AsmScope.cpp98
-rw-r--r--libyul/AsmScope.h99
-rw-r--r--libyul/AsmScopeFiller.cpp181
-rw-r--r--libyul/AsmScopeFiller.h82
-rw-r--r--libyul/CMakeLists.txt45
-rw-r--r--libyul/Exceptions.h7
-rw-r--r--libyul/Object.cpp61
-rw-r--r--libyul/Object.h72
-rw-r--r--libyul/ObjectParser.cpp146
-rw-r--r--libyul/ObjectParser.h72
-rw-r--r--libyul/YulString.h3
-rw-r--r--libyul/backends/evm/AbstractAssembly.h27
-rw-r--r--libyul/backends/evm/EVMAssembly.cpp5
-rw-r--r--libyul/backends/evm/EVMAssembly.h44
-rw-r--r--libyul/backends/evm/EVMCodeTransform.cpp24
-rw-r--r--libyul/backends/evm/EVMCodeTransform.h36
-rw-r--r--libyul/optimiser/ASTCopier.cpp4
-rw-r--r--libyul/optimiser/ASTCopier.h35
-rw-r--r--libyul/optimiser/ASTWalker.cpp4
-rw-r--r--libyul/optimiser/ASTWalker.h5
-rw-r--r--libyul/optimiser/BlockFlattener.cpp4
-rw-r--r--libyul/optimiser/BlockFlattener.h3
-rw-r--r--libyul/optimiser/CommonSubexpressionEliminator.cpp5
-rw-r--r--libyul/optimiser/CommonSubexpressionEliminator.h5
-rw-r--r--libyul/optimiser/DataFlowAnalyzer.cpp5
-rw-r--r--libyul/optimiser/DataFlowAnalyzer.h18
-rw-r--r--libyul/optimiser/Disambiguator.cpp9
-rw-r--r--libyul/optimiser/Disambiguator.h29
-rw-r--r--libyul/optimiser/ExpressionInliner.cpp5
-rw-r--r--libyul/optimiser/ExpressionInliner.h10
-rw-r--r--libyul/optimiser/ExpressionJoiner.cpp5
-rw-r--r--libyul/optimiser/ExpressionJoiner.h6
-rw-r--r--libyul/optimiser/ExpressionSimplifier.cpp5
-rw-r--r--libyul/optimiser/ExpressionSimplifier.h5
-rw-r--r--libyul/optimiser/ExpressionSplitter.cpp5
-rw-r--r--libyul/optimiser/ExpressionSplitter.h17
-rw-r--r--libyul/optimiser/ForLoopInitRewriter.cpp43
-rw-r--r--libyul/optimiser/ForLoopInitRewriter.h36
-rw-r--r--libyul/optimiser/FullInliner.cpp5
-rw-r--r--libyul/optimiser/FullInliner.h15
-rw-r--r--libyul/optimiser/FunctionGrouper.cpp4
-rw-r--r--libyul/optimiser/FunctionGrouper.h5
-rw-r--r--libyul/optimiser/FunctionHoister.cpp5
-rw-r--r--libyul/optimiser/FunctionHoister.h6
-rw-r--r--libyul/optimiser/InlinableExpressionFunctionFinder.cpp5
-rw-r--r--libyul/optimiser/InlinableExpressionFunctionFinder.h11
-rw-r--r--libyul/optimiser/MainFunction.cpp4
-rw-r--r--libyul/optimiser/MainFunction.h5
-rw-r--r--libyul/optimiser/Metrics.cpp4
-rw-r--r--libyul/optimiser/Metrics.h7
-rw-r--r--libyul/optimiser/NameCollector.cpp4
-rw-r--r--libyul/optimiser/NameCollector.h9
-rw-r--r--libyul/optimiser/NameDispenser.cpp5
-rw-r--r--libyul/optimiser/NameDispenser.h5
-rw-r--r--libyul/optimiser/RedundantAssignEliminator.cpp5
-rw-r--r--libyul/optimiser/RedundantAssignEliminator.h6
-rw-r--r--libyul/optimiser/Rematerialiser.cpp5
-rw-r--r--libyul/optimiser/Rematerialiser.h5
-rw-r--r--libyul/optimiser/SSATransform.cpp6
-rw-r--r--libyul/optimiser/SSATransform.h6
-rw-r--r--libyul/optimiser/SSAValueTracker.cpp4
-rw-r--r--libyul/optimiser/SSAValueTracker.h7
-rw-r--r--libyul/optimiser/Semantics.cpp5
-rw-r--r--libyul/optimiser/Semantics.h11
-rw-r--r--libyul/optimiser/SimplificationRules.cpp12
-rw-r--r--libyul/optimiser/SimplificationRules.h24
-rw-r--r--libyul/optimiser/Substitution.cpp4
-rw-r--r--libyul/optimiser/Substitution.h6
-rw-r--r--libyul/optimiser/Suite.cpp14
-rw-r--r--libyul/optimiser/Suite.h16
-rw-r--r--libyul/optimiser/SyntacticalEquality.cpp5
-rw-r--r--libyul/optimiser/SyntacticalEquality.h5
-rw-r--r--libyul/optimiser/UnusedPruner.cpp5
-rw-r--r--libyul/optimiser/UnusedPruner.h5
-rw-r--r--libyul/optimiser/Utilities.cpp6
-rw-r--r--libyul/optimiser/Utilities.h5
-rw-r--r--libyul/optimiser/VarDeclPropagator.cpp7
-rw-r--r--libyul/optimiser/VarDeclPropagator.h7
91 files changed, 3389 insertions, 427 deletions
diff --git a/libyul/ASTDataForward.h b/libyul/ASTDataForward.h
deleted file mode 100644
index 8c49e68f..00000000
--- a/libyul/ASTDataForward.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- 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/>.
-*/
-/**
- * @date 2017
- * Pull in some identifiers from the solidity::assembly namespace.
- */
-
-#pragma once
-
-#include <libsolidity/inlineasm/AsmDataForward.h>
-
-namespace dev
-{
-namespace yul
-{
-
-using Instruction = solidity::assembly::Instruction;
-using Literal = solidity::assembly::Literal;
-using Label = solidity::assembly::Label;
-using StackAssignment = solidity::assembly::StackAssignment;
-using Identifier = solidity::assembly::Identifier;
-using Assignment = solidity::assembly::Assignment;
-using VariableDeclaration = solidity::assembly::VariableDeclaration;
-using FunctionalInstruction = solidity::assembly::FunctionalInstruction;
-using FunctionDefinition = solidity::assembly::FunctionDefinition;
-using FunctionCall = solidity::assembly::FunctionCall;
-using If = solidity::assembly::If;
-using Case = solidity::assembly::Case;
-using Switch = solidity::assembly::Switch;
-using ForLoop = solidity::assembly::ForLoop;
-using ExpressionStatement = solidity::assembly::ExpressionStatement;
-using Block = solidity::assembly::Block;
-
-using TypedName = solidity::assembly::TypedName;
-class YulString;
-
-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/libyul/AsmAnalysis.cpp b/libyul/AsmAnalysis.cpp
new file mode 100644
index 00000000..d3f6de84
--- /dev/null
+++ b/libyul/AsmAnalysis.cpp
@@ -0,0 +1,632 @@
+/*
+ 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/>.
+*/
+/**
+ * Analyzer part of inline assembly.
+ */
+
+#include <libyul/AsmAnalysis.h>
+
+#include <libyul/AsmData.h>
+#include <libyul/AsmScopeFiller.h>
+#include <libyul/AsmScope.h>
+#include <libyul/AsmAnalysisInfo.h>
+
+#include <liblangutil/ErrorReporter.h>
+
+#include <boost/range/adaptor/reversed.hpp>
+#include <boost/algorithm/string.hpp>
+
+#include <memory>
+#include <functional>
+
+using namespace std;
+using namespace dev;
+using namespace langutil;
+using namespace yul;
+using namespace dev;
+using namespace dev::solidity;
+
+namespace {
+
+set<string> const builtinTypes{"bool", "u8", "s8", "u32", "s32", "u64", "s64", "u128", "s128", "u256", "s256"};
+
+}
+
+bool AsmAnalyzer::analyze(Block const& _block)
+{
+ if (!(ScopeFiller(m_info, m_errorReporter))(_block))
+ return false;
+
+ return (*this)(_block);
+}
+
+bool AsmAnalyzer::operator()(Label const& _label)
+{
+ solAssert(!_label.name.empty(), "");
+ checkLooseFeature(
+ _label.location,
+ "The use of labels is disallowed. Please use \"if\", \"switch\", \"for\" or function calls instead."
+ );
+ m_info.stackHeightInfo[&_label] = m_stackHeight;
+ warnOnInstructions(solidity::Instruction::JUMPDEST, _label.location);
+ return true;
+}
+
+bool AsmAnalyzer::operator()(yul::Instruction const& _instruction)
+{
+ checkLooseFeature(
+ _instruction.location,
+ "The use of non-functional instructions is disallowed. Please use functional notation instead."
+ );
+ auto const& info = instructionInfo(_instruction.instruction);
+ m_stackHeight += info.ret - info.args;
+ m_info.stackHeightInfo[&_instruction] = m_stackHeight;
+ warnOnInstructions(_instruction.instruction, _instruction.location);
+ return true;
+}
+
+bool AsmAnalyzer::operator()(Literal const& _literal)
+{
+ expectValidType(_literal.type.str(), _literal.location);
+ ++m_stackHeight;
+ if (_literal.kind == LiteralKind::String && _literal.value.str().size() > 32)
+ {
+ m_errorReporter.typeError(
+ _literal.location,
+ "String literal too long (" + to_string(_literal.value.str().size()) + " > 32)"
+ );
+ return false;
+ }
+ else if (_literal.kind == LiteralKind::Number && bigint(_literal.value.str()) > u256(-1))
+ {
+ m_errorReporter.typeError(
+ _literal.location,
+ "Number literal too large (> 256 bits)"
+ );
+ return false;
+ }
+ else if (_literal.kind == LiteralKind::Boolean)
+ {
+ solAssert(m_flavour == AsmFlavour::Yul, "");
+ solAssert(_literal.value == YulString{string("true")} || _literal.value == YulString{string("false")}, "");
+ }
+ m_info.stackHeightInfo[&_literal] = m_stackHeight;
+ return true;
+}
+
+bool AsmAnalyzer::operator()(Identifier const& _identifier)
+{
+ solAssert(!_identifier.name.empty(), "");
+ size_t numErrorsBefore = m_errorReporter.errors().size();
+ bool success = true;
+ if (m_currentScope->lookup(_identifier.name, Scope::Visitor(
+ [&](Scope::Variable const& _var)
+ {
+ if (!m_activeVariables.count(&_var))
+ {
+ m_errorReporter.declarationError(
+ _identifier.location,
+ "Variable " + _identifier.name.str() + " used before it was declared."
+ );
+ success = false;
+ }
+ ++m_stackHeight;
+ },
+ [&](Scope::Label const&)
+ {
+ ++m_stackHeight;
+ },
+ [&](Scope::Function const&)
+ {
+ m_errorReporter.typeError(
+ _identifier.location,
+ "Function " + _identifier.name.str() + " used without being called."
+ );
+ success = false;
+ }
+ )))
+ {
+ }
+ else
+ {
+ size_t stackSize(-1);
+ if (m_resolver)
+ {
+ bool insideFunction = m_currentScope->insideFunction();
+ stackSize = m_resolver(_identifier, yul::IdentifierContext::RValue, insideFunction);
+ }
+ if (stackSize == size_t(-1))
+ {
+ // Only add an error message if the callback did not do it.
+ if (numErrorsBefore == m_errorReporter.errors().size())
+ m_errorReporter.declarationError(_identifier.location, "Identifier not found.");
+ success = false;
+ }
+ m_stackHeight += stackSize == size_t(-1) ? 1 : stackSize;
+ }
+ m_info.stackHeightInfo[&_identifier] = m_stackHeight;
+ return success;
+}
+
+bool AsmAnalyzer::operator()(FunctionalInstruction const& _instr)
+{
+ solAssert(m_flavour != AsmFlavour::Yul, "");
+ bool success = true;
+ for (auto const& arg: _instr.arguments | boost::adaptors::reversed)
+ if (!expectExpression(arg))
+ success = false;
+ // Parser already checks that the number of arguments is correct.
+ auto const& info = instructionInfo(_instr.instruction);
+ solAssert(info.args == int(_instr.arguments.size()), "");
+ m_stackHeight += info.ret - info.args;
+ m_info.stackHeightInfo[&_instr] = m_stackHeight;
+ warnOnInstructions(_instr.instruction, _instr.location);
+ return success;
+}
+
+bool AsmAnalyzer::operator()(ExpressionStatement const& _statement)
+{
+ int initialStackHeight = m_stackHeight;
+ bool success = boost::apply_visitor(*this, _statement.expression);
+ if (m_stackHeight != initialStackHeight && (m_flavour != AsmFlavour::Loose || m_errorTypeForLoose))
+ {
+ Error::Type errorType = m_flavour == AsmFlavour::Loose ? *m_errorTypeForLoose : Error::Type::TypeError;
+ string msg =
+ "Top-level expressions are not supposed to return values (this expression returns " +
+ to_string(m_stackHeight - initialStackHeight) +
+ " value" +
+ (m_stackHeight - initialStackHeight == 1 ? "" : "s") +
+ "). Use ``pop()`` or assign them.";
+ m_errorReporter.error(errorType, _statement.location, msg);
+ if (errorType != Error::Type::Warning)
+ success = false;
+ }
+ m_info.stackHeightInfo[&_statement] = m_stackHeight;
+ return success;
+}
+
+bool AsmAnalyzer::operator()(StackAssignment const& _assignment)
+{
+ checkLooseFeature(
+ _assignment.location,
+ "The use of stack assignment is disallowed. Please use assignment in functional notation instead."
+ );
+ bool success = checkAssignment(_assignment.variableName, size_t(-1));
+ m_info.stackHeightInfo[&_assignment] = m_stackHeight;
+ return success;
+}
+
+bool AsmAnalyzer::operator()(Assignment const& _assignment)
+{
+ solAssert(_assignment.value, "");
+ int const expectedItems = _assignment.variableNames.size();
+ solAssert(expectedItems >= 1, "");
+ int const stackHeight = m_stackHeight;
+ bool success = boost::apply_visitor(*this, *_assignment.value);
+ if ((m_stackHeight - stackHeight) != expectedItems)
+ {
+ m_errorReporter.declarationError(
+ _assignment.location,
+ "Variable count does not match number of values (" +
+ to_string(expectedItems) +
+ " vs. " +
+ to_string(m_stackHeight - stackHeight) +
+ ")"
+ );
+ return false;
+ }
+ for (auto const& variableName: _assignment.variableNames)
+ if (!checkAssignment(variableName, 1))
+ success = false;
+ m_info.stackHeightInfo[&_assignment] = m_stackHeight;
+ return success;
+}
+
+bool AsmAnalyzer::operator()(VariableDeclaration const& _varDecl)
+{
+ bool success = true;
+ int const numVariables = _varDecl.variables.size();
+ if (_varDecl.value)
+ {
+ int const stackHeight = m_stackHeight;
+ success = boost::apply_visitor(*this, *_varDecl.value);
+ if ((m_stackHeight - stackHeight) != numVariables)
+ {
+ m_errorReporter.declarationError(_varDecl.location, "Variable count mismatch.");
+ return false;
+ }
+ }
+ else
+ m_stackHeight += numVariables;
+
+ for (auto const& variable: _varDecl.variables)
+ {
+ expectValidType(variable.type.str(), variable.location);
+ m_activeVariables.insert(&boost::get<Scope::Variable>(m_currentScope->identifiers.at(variable.name)));
+ }
+ m_info.stackHeightInfo[&_varDecl] = m_stackHeight;
+ return success;
+}
+
+bool AsmAnalyzer::operator()(FunctionDefinition const& _funDef)
+{
+ solAssert(!_funDef.name.empty(), "");
+ Block const* virtualBlock = m_info.virtualBlocks.at(&_funDef).get();
+ solAssert(virtualBlock, "");
+ Scope& varScope = scope(virtualBlock);
+ for (auto const& var: _funDef.parameters + _funDef.returnVariables)
+ {
+ expectValidType(var.type.str(), var.location);
+ m_activeVariables.insert(&boost::get<Scope::Variable>(varScope.identifiers.at(var.name)));
+ }
+
+ int const stackHeight = m_stackHeight;
+ m_stackHeight = _funDef.parameters.size() + _funDef.returnVariables.size();
+
+ bool success = (*this)(_funDef.body);
+
+ m_stackHeight = stackHeight;
+ m_info.stackHeightInfo[&_funDef] = m_stackHeight;
+ return success;
+}
+
+bool AsmAnalyzer::operator()(FunctionCall const& _funCall)
+{
+ solAssert(!_funCall.functionName.name.empty(), "");
+ bool success = true;
+ size_t arguments = 0;
+ size_t returns = 0;
+ if (!m_currentScope->lookup(_funCall.functionName.name, Scope::Visitor(
+ [&](Scope::Variable const&)
+ {
+ m_errorReporter.typeError(
+ _funCall.functionName.location,
+ "Attempt to call variable instead of function."
+ );
+ success = false;
+ },
+ [&](Scope::Label const&)
+ {
+ m_errorReporter.typeError(
+ _funCall.functionName.location,
+ "Attempt to call label instead of function."
+ );
+ success = false;
+ },
+ [&](Scope::Function const& _fun)
+ {
+ /// TODO: compare types too
+ arguments = _fun.arguments.size();
+ returns = _fun.returns.size();
+ }
+ )))
+ {
+ m_errorReporter.declarationError(_funCall.functionName.location, "Function not found.");
+ success = false;
+ }
+ if (success)
+ {
+ if (_funCall.arguments.size() != arguments)
+ {
+ m_errorReporter.typeError(
+ _funCall.functionName.location,
+ "Expected " + to_string(arguments) + " arguments but got " +
+ to_string(_funCall.arguments.size()) + "."
+ );
+ success = false;
+ }
+ }
+ for (auto const& arg: _funCall.arguments | boost::adaptors::reversed)
+ if (!expectExpression(arg))
+ success = false;
+ m_stackHeight += int(returns) - int(arguments);
+ m_info.stackHeightInfo[&_funCall] = m_stackHeight;
+ return success;
+}
+
+bool AsmAnalyzer::operator()(If const& _if)
+{
+ bool success = true;
+
+ if (!expectExpression(*_if.condition))
+ success = false;
+ m_stackHeight--;
+
+ if (!(*this)(_if.body))
+ success = false;
+
+ m_info.stackHeightInfo[&_if] = m_stackHeight;
+
+ return success;
+}
+
+bool AsmAnalyzer::operator()(Switch const& _switch)
+{
+ solAssert(_switch.expression, "");
+
+ bool success = true;
+
+ if (!expectExpression(*_switch.expression))
+ success = false;
+
+ set<tuple<LiteralKind, YulString>> cases;
+ for (auto const& _case: _switch.cases)
+ {
+ if (_case.value)
+ {
+ int const initialStackHeight = m_stackHeight;
+ // We cannot use "expectExpression" here because *_case.value is not a
+ // Statement and would be converted to a Statement otherwise.
+ if (!(*this)(*_case.value))
+ success = false;
+ expectDeposit(1, initialStackHeight, _case.value->location);
+ m_stackHeight--;
+
+ /// Note: the parser ensures there is only one default case
+ auto val = make_tuple(_case.value->kind, _case.value->value);
+ if (!cases.insert(val).second)
+ {
+ m_errorReporter.declarationError(
+ _case.location,
+ "Duplicate case defined"
+ );
+ success = false;
+ }
+ }
+
+ if (!(*this)(_case.body))
+ success = false;
+ }
+
+ m_stackHeight--;
+ m_info.stackHeightInfo[&_switch] = m_stackHeight;
+
+ return success;
+}
+
+bool AsmAnalyzer::operator()(ForLoop const& _for)
+{
+ solAssert(_for.condition, "");
+
+ 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;
+ auto previousScope = m_currentScope;
+ m_currentScope = &scope(&_block);
+
+ int const initialStackHeight = m_stackHeight;
+
+ for (auto const& s: _block.statements)
+ if (!boost::apply_visitor(*this, s))
+ success = false;
+
+ m_stackHeight -= scope(&_block).numberOfVariables();
+
+ int const stackDiff = m_stackHeight - initialStackHeight;
+ if (stackDiff != 0)
+ {
+ m_errorReporter.declarationError(
+ _block.location,
+ "Unbalanced stack at the end of a block: " +
+ (
+ stackDiff > 0 ?
+ to_string(stackDiff) + string(" surplus item(s).") :
+ to_string(-stackDiff) + string(" missing item(s).")
+ )
+ );
+ success = false;
+ }
+
+ m_info.stackHeightInfo[&_block] = m_stackHeight;
+ m_currentScope = previousScope;
+ return success;
+}
+
+bool AsmAnalyzer::expectExpression(Expression const& _expr)
+{
+ bool success = true;
+ int const initialHeight = m_stackHeight;
+ if (!boost::apply_visitor(*this, _expr))
+ success = false;
+ if (!expectDeposit(1, initialHeight, locationOf(_expr)))
+ success = false;
+ return success;
+}
+
+bool AsmAnalyzer::expectDeposit(int _deposit, int _oldHeight, SourceLocation const& _location)
+{
+ if (m_stackHeight - _oldHeight != _deposit)
+ {
+ m_errorReporter.typeError(
+ _location,
+ "Expected expression to return one item to the stack, but did return " +
+ to_string(m_stackHeight - _oldHeight) +
+ " items."
+ );
+ return false;
+ }
+ return true;
+}
+
+bool AsmAnalyzer::checkAssignment(Identifier const& _variable, size_t _valueSize)
+{
+ solAssert(!_variable.name.empty(), "");
+ bool success = true;
+ size_t numErrorsBefore = m_errorReporter.errors().size();
+ size_t variableSize(-1);
+ if (Scope::Identifier const* var = m_currentScope->lookup(_variable.name))
+ {
+ // Check that it is a variable
+ if (var->type() != typeid(Scope::Variable))
+ {
+ m_errorReporter.typeError(_variable.location, "Assignment requires variable.");
+ success = false;
+ }
+ else if (!m_activeVariables.count(&boost::get<Scope::Variable>(*var)))
+ {
+ m_errorReporter.declarationError(
+ _variable.location,
+ "Variable " + _variable.name.str() + " used before it was declared."
+ );
+ success = false;
+ }
+ variableSize = 1;
+ }
+ else if (m_resolver)
+ {
+ bool insideFunction = m_currentScope->insideFunction();
+ variableSize = m_resolver(_variable, yul::IdentifierContext::LValue, insideFunction);
+ }
+ if (variableSize == size_t(-1))
+ {
+ // Only add message if the callback did not.
+ if (numErrorsBefore == m_errorReporter.errors().size())
+ m_errorReporter.declarationError(_variable.location, "Variable not found or variable not lvalue.");
+ success = false;
+ }
+ if (_valueSize == size_t(-1))
+ _valueSize = variableSize == size_t(-1) ? 1 : variableSize;
+
+ m_stackHeight -= _valueSize;
+
+ if (_valueSize != variableSize && variableSize != size_t(-1))
+ {
+ m_errorReporter.typeError(
+ _variable.location,
+ "Variable size (" +
+ to_string(variableSize) +
+ ") and value size (" +
+ to_string(_valueSize) +
+ ") do not match."
+ );
+ success = false;
+ }
+ return success;
+}
+
+Scope& AsmAnalyzer::scope(Block const* _block)
+{
+ solAssert(m_info.scopes.count(_block) == 1, "Scope requested but not present.");
+ auto scopePtr = m_info.scopes.at(_block);
+ solAssert(scopePtr, "Scope requested but not present.");
+ return *scopePtr;
+}
+void AsmAnalyzer::expectValidType(string const& type, SourceLocation const& _location)
+{
+ if (m_flavour != AsmFlavour::Yul)
+ return;
+
+ if (!builtinTypes.count(type))
+ m_errorReporter.typeError(
+ _location,
+ "\"" + type + "\" is not a valid type (user defined types are not yet supported)."
+ );
+}
+
+void AsmAnalyzer::warnOnInstructions(solidity::Instruction _instr, SourceLocation const& _location)
+{
+ // We assume that returndatacopy, returndatasize and staticcall are either all available
+ // or all not available.
+ solAssert(m_evmVersion.supportsReturndata() == m_evmVersion.hasStaticCall(), "");
+ // Similarly we assume bitwise shifting and create2 go together.
+ solAssert(m_evmVersion.hasBitwiseShifting() == m_evmVersion.hasCreate2(), "");
+
+ if (_instr == solidity::Instruction::EXTCODEHASH)
+ m_errorReporter.warning(
+ _location,
+ "The \"" +
+ boost::to_lower_copy(instructionInfo(_instr).name)
+ + "\" instruction is not supported by the VM version \"" +
+ "" + m_evmVersion.name() +
+ "\" you are currently compiling for. " +
+ "It will be interpreted as an invalid instruction on this VM."
+ );
+ else if ((
+ _instr == solidity::Instruction::RETURNDATACOPY ||
+ _instr == solidity::Instruction::RETURNDATASIZE ||
+ _instr == solidity::Instruction::STATICCALL
+ ) && !m_evmVersion.supportsReturndata())
+ m_errorReporter.warning(
+ _location,
+ "The \"" +
+ boost::to_lower_copy(instructionInfo(_instr).name)
+ + "\" instruction is only available for Byzantium-compatible VMs. " +
+ "You are currently compiling for \"" +
+ m_evmVersion.name() +
+ "\", where it will be interpreted as an invalid instruction."
+ );
+ else if ((
+ _instr == solidity::Instruction::SHL ||
+ _instr == solidity::Instruction::SHR ||
+ _instr == solidity::Instruction::SAR ||
+ _instr == solidity::Instruction::CREATE2
+ ) && !m_evmVersion.hasBitwiseShifting())
+ m_errorReporter.warning(
+ _location,
+ "The \"" +
+ boost::to_lower_copy(instructionInfo(_instr).name)
+ + "\" instruction is only available for Constantinople-compatible VMs. " +
+ "You are currently compiling for \"" +
+ m_evmVersion.name() +
+ "\", where it will be interpreted as an invalid instruction."
+ );
+
+ if (_instr == solidity::Instruction::JUMP || _instr == solidity::Instruction::JUMPI || _instr == solidity::Instruction::JUMPDEST)
+ {
+ solAssert(m_flavour == AsmFlavour::Loose, "");
+ m_errorReporter.error(
+ m_errorTypeForLoose ? *m_errorTypeForLoose : Error::Type::Warning,
+ _location,
+ "Jump instructions and labels are low-level EVM features that can lead to "
+ "incorrect stack access. Because of that they are discouraged. "
+ "Please consider using \"switch\", \"if\" or \"for\" statements instead."
+ );
+ }
+}
+
+void AsmAnalyzer::checkLooseFeature(SourceLocation const& _location, string const& _description)
+{
+ if (m_flavour != AsmFlavour::Loose)
+ solAssert(false, _description);
+ else if (m_errorTypeForLoose)
+ m_errorReporter.error(*m_errorTypeForLoose, _location, _description);
+}
diff --git a/libyul/AsmAnalysis.h b/libyul/AsmAnalysis.h
new file mode 100644
index 00000000..34e32eb0
--- /dev/null
+++ b/libyul/AsmAnalysis.h
@@ -0,0 +1,122 @@
+/*
+ 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/>.
+*/
+/**
+ * Analysis part of inline assembly.
+ */
+
+#pragma once
+
+#include <liblangutil/Exceptions.h>
+#include <liblangutil/EVMVersion.h>
+
+#include <libyul/AsmScope.h>
+
+#include <libyul/backends/evm/AbstractAssembly.h>
+
+#include <libyul/AsmDataForward.h>
+
+#include <boost/variant.hpp>
+#include <boost/optional.hpp>
+
+#include <functional>
+#include <memory>
+
+namespace langutil
+{
+class ErrorReporter;
+struct SourceLocation;
+}
+
+namespace yul
+{
+
+struct AsmAnalysisInfo;
+
+/**
+ * Performs the full analysis stage, calls the ScopeFiller internally, then resolves
+ * references and performs other checks.
+ * If all these checks pass, code generation should not throw errors.
+ */
+class AsmAnalyzer: public boost::static_visitor<bool>
+{
+public:
+ explicit AsmAnalyzer(
+ AsmAnalysisInfo& _analysisInfo,
+ langutil::ErrorReporter& _errorReporter,
+ dev::solidity::EVMVersion _evmVersion,
+ boost::optional<langutil::Error::Type> _errorTypeForLoose,
+ AsmFlavour _flavour = AsmFlavour::Loose,
+ ExternalIdentifierAccess::Resolver const& _resolver = ExternalIdentifierAccess::Resolver()
+ ):
+ m_resolver(_resolver),
+ m_info(_analysisInfo),
+ m_errorReporter(_errorReporter),
+ m_evmVersion(_evmVersion),
+ m_flavour(_flavour),
+ m_errorTypeForLoose(_errorTypeForLoose)
+ {}
+
+ bool analyze(Block const& _block);
+
+ bool operator()(Instruction const&);
+ bool operator()(Literal const& _literal);
+ bool operator()(Identifier const&);
+ bool operator()(FunctionalInstruction const& _functionalInstruction);
+ bool operator()(Label const& _label);
+ bool operator()(ExpressionStatement const&);
+ bool operator()(StackAssignment const&);
+ bool operator()(Assignment const& _assignment);
+ bool operator()(VariableDeclaration const& _variableDeclaration);
+ bool operator()(FunctionDefinition const& _functionDefinition);
+ bool operator()(FunctionCall const& _functionCall);
+ bool operator()(If const& _if);
+ bool operator()(Switch const& _switch);
+ bool operator()(ForLoop const& _forLoop);
+ bool operator()(Block const& _block);
+
+private:
+ /// Visits the statement and expects it to deposit one item onto the stack.
+ bool expectExpression(Expression const& _expr);
+ bool expectDeposit(int _deposit, int _oldHeight, langutil::SourceLocation const& _location);
+
+ /// Verifies that a variable to be assigned to exists and has the same size
+ /// as the value, @a _valueSize, unless that is equal to -1.
+ bool checkAssignment(Identifier const& _assignment, size_t _valueSize = size_t(-1));
+
+ Scope& scope(Block const* _block);
+ void expectValidType(std::string const& type, langutil::SourceLocation const& _location);
+ void warnOnInstructions(dev::solidity::Instruction _instr, langutil::SourceLocation const& _location);
+
+ /// Depending on @a m_flavour and @a m_errorTypeForLoose, throws an internal compiler
+ /// exception (if the flavour is not Loose), reports an error/warning
+ /// (if m_errorTypeForLoose is set) or does nothing.
+ void checkLooseFeature(langutil::SourceLocation const& _location, std::string const& _description);
+
+ int m_stackHeight = 0;
+ yul::ExternalIdentifierAccess::Resolver m_resolver;
+ Scope* m_currentScope = nullptr;
+ /// Variables that are active at the current point in assembly (as opposed to
+ /// "part of the scope but not yet declared")
+ std::set<Scope::Variable const*> m_activeVariables;
+ AsmAnalysisInfo& m_info;
+ langutil::ErrorReporter& m_errorReporter;
+ dev::solidity::EVMVersion m_evmVersion;
+ AsmFlavour m_flavour = AsmFlavour::Loose;
+ boost::optional<langutil::Error::Type> m_errorTypeForLoose;
+};
+
+}
diff --git a/libyul/AsmAnalysisInfo.cpp b/libyul/AsmAnalysisInfo.cpp
new file mode 100644
index 00000000..450c0f8f
--- /dev/null
+++ b/libyul/AsmAnalysisInfo.cpp
@@ -0,0 +1,26 @@
+/*
+ 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/>.
+*/
+/**
+ * Information generated during analyzer part of inline assembly.
+ */
+
+#include <libyul/AsmAnalysisInfo.h>
+
+#include <libyul/AsmScope.h>
+
+#include <ostream>
+
diff --git a/libyul/AsmAnalysisInfo.h b/libyul/AsmAnalysisInfo.h
new file mode 100644
index 00000000..08a35ade
--- /dev/null
+++ b/libyul/AsmAnalysisInfo.h
@@ -0,0 +1,46 @@
+/*
+ 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/>.
+*/
+/**
+ * Information generated during analyzer part of inline assembly.
+ */
+
+#pragma once
+
+#include <libyul/AsmDataForward.h>
+
+#include <boost/variant.hpp>
+
+#include <map>
+#include <memory>
+#include <vector>
+
+namespace yul
+{
+
+struct Scope;
+
+struct AsmAnalysisInfo
+{
+ using StackHeightInfo = std::map<void const*, int>;
+ using Scopes = std::map<Block const*, std::shared_ptr<Scope>>;
+ Scopes scopes;
+ StackHeightInfo stackHeightInfo;
+ /// Virtual blocks which will be used for scopes for function arguments and return values.
+ std::map<FunctionDefinition const*, std::shared_ptr<Block const>> virtualBlocks;
+};
+
+}
diff --git a/libyul/AsmCodeGen.cpp b/libyul/AsmCodeGen.cpp
new file mode 100644
index 00000000..23bf395d
--- /dev/null
+++ b/libyul/AsmCodeGen.cpp
@@ -0,0 +1,163 @@
+/*
+ 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
+ * Code-generating part of inline assembly.
+ */
+
+#include <libyul/AsmCodeGen.h>
+
+#include <libyul/AsmParser.h>
+#include <libyul/AsmData.h>
+#include <libyul/AsmScope.h>
+#include <libyul/AsmAnalysis.h>
+#include <libyul/AsmAnalysisInfo.h>
+
+#include <libyul/backends/evm/AbstractAssembly.h>
+#include <libyul/backends/evm/EVMCodeTransform.h>
+
+#include <libevmasm/Assembly.h>
+#include <libevmasm/Instruction.h>
+
+#include <liblangutil/SourceLocation.h>
+
+#include <libdevcore/CommonIO.h>
+
+#include <boost/range/adaptor/reversed.hpp>
+#include <boost/range/adaptor/map.hpp>
+#include <boost/range/algorithm/count_if.hpp>
+
+#include <memory>
+#include <functional>
+
+using namespace std;
+using namespace dev;
+using namespace langutil;
+using namespace yul;
+using namespace dev::solidity;
+
+class EthAssemblyAdapter: public AbstractAssembly
+{
+public:
+ explicit EthAssemblyAdapter(eth::Assembly& _assembly):
+ m_assembly(_assembly)
+ {
+ }
+ virtual void setSourceLocation(SourceLocation const& _location) override
+ {
+ m_assembly.setSourceLocation(_location);
+ }
+ virtual int stackHeight() const override { return m_assembly.deposit(); }
+ virtual void appendInstruction(solidity::Instruction _instruction) override
+ {
+ m_assembly.append(_instruction);
+ }
+ virtual void appendConstant(u256 const& _constant) override
+ {
+ m_assembly.append(_constant);
+ }
+ /// Append a label.
+ virtual void appendLabel(LabelID _labelId) override
+ {
+ m_assembly.append(eth::AssemblyItem(eth::Tag, _labelId));
+ }
+ /// Append a label reference.
+ virtual void appendLabelReference(LabelID _labelId) override
+ {
+ m_assembly.append(eth::AssemblyItem(eth::PushTag, _labelId));
+ }
+ virtual size_t newLabelId() override
+ {
+ return assemblyTagToIdentifier(m_assembly.newTag());
+ }
+ virtual size_t namedLabel(std::string const& _name) override
+ {
+ return assemblyTagToIdentifier(m_assembly.namedTag(_name));
+ }
+ virtual void appendLinkerSymbol(std::string const& _linkerSymbol) override
+ {
+ m_assembly.appendLibraryAddress(_linkerSymbol);
+ }
+ virtual void appendJump(int _stackDiffAfter) override
+ {
+ appendInstruction(solidity::Instruction::JUMP);
+ m_assembly.adjustDeposit(_stackDiffAfter);
+ }
+ virtual void appendJumpTo(LabelID _labelId, int _stackDiffAfter) override
+ {
+ appendLabelReference(_labelId);
+ appendJump(_stackDiffAfter);
+ }
+ virtual void appendJumpToIf(LabelID _labelId) override
+ {
+ appendLabelReference(_labelId);
+ appendInstruction(solidity::Instruction::JUMPI);
+ }
+ virtual void appendBeginsub(LabelID, int) override
+ {
+ // TODO we could emulate that, though
+ solAssert(false, "BEGINSUB not implemented for EVM 1.0");
+ }
+ /// Call a subroutine.
+ virtual void appendJumpsub(LabelID, int, int) override
+ {
+ // TODO we could emulate that, though
+ solAssert(false, "JUMPSUB not implemented for EVM 1.0");
+ }
+
+ /// Return from a subroutine.
+ virtual void appendReturnsub(int, int) override
+ {
+ // TODO we could emulate that, though
+ solAssert(false, "RETURNSUB not implemented for EVM 1.0");
+ }
+
+ virtual void appendAssemblySize() override
+ {
+ m_assembly.appendProgramSize();
+ }
+
+private:
+ static LabelID assemblyTagToIdentifier(eth::AssemblyItem const& _tag)
+ {
+ u256 id = _tag.data();
+ solAssert(id <= std::numeric_limits<LabelID>::max(), "Tag id too large.");
+ return LabelID(id);
+ }
+
+ eth::Assembly& m_assembly;
+};
+
+void CodeGenerator::assemble(
+ Block const& _parsedData,
+ AsmAnalysisInfo& _analysisInfo,
+ eth::Assembly& _assembly,
+ ExternalIdentifierAccess const& _identifierAccess,
+ bool _useNamedLabelsForFunctions
+)
+{
+ EthAssemblyAdapter assemblyAdapter(_assembly);
+ CodeTransform(
+ assemblyAdapter,
+ _analysisInfo,
+ false,
+ false,
+ _identifierAccess,
+ _useNamedLabelsForFunctions
+ )(_parsedData);
+}
diff --git a/libyul/AsmCodeGen.h b/libyul/AsmCodeGen.h
new file mode 100644
index 00000000..fd5ac0a1
--- /dev/null
+++ b/libyul/AsmCodeGen.h
@@ -0,0 +1,54 @@
+/*
+ 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
+ * Code-generating part of inline assembly.
+ */
+
+#pragma once
+
+#include <libyul/AsmAnalysis.h>
+
+#include <functional>
+
+namespace dev
+{
+namespace eth
+{
+class Assembly;
+}
+}
+
+namespace yul
+{
+struct Block;
+
+class CodeGenerator
+{
+public:
+ /// Performs code generation and appends generated to _assembly.
+ static void assemble(
+ Block const& _parsedData,
+ AsmAnalysisInfo& _analysisInfo,
+ dev::eth::Assembly& _assembly,
+ yul::ExternalIdentifierAccess const& _identifierAccess = yul::ExternalIdentifierAccess(),
+ bool _useNamedLabelsForFunctions = false
+ );
+};
+
+}
diff --git a/libyul/AsmData.h b/libyul/AsmData.h
new file mode 100644
index 00000000..86c373a4
--- /dev/null
+++ b/libyul/AsmData.h
@@ -0,0 +1,96 @@
+/*
+ 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
+ * Parsed inline assembly to be used by the AST
+ */
+
+#pragma once
+
+#include <libyul/AsmDataForward.h>
+#include <libyul/YulString.h>
+
+#include <libevmasm/Instruction.h>
+#include <liblangutil/SourceLocation.h>
+
+#include <boost/variant.hpp>
+#include <boost/noncopyable.hpp>
+
+#include <map>
+#include <memory>
+
+namespace yul
+{
+
+using Type = YulString;
+
+struct TypedName { langutil::SourceLocation location; YulString name; Type type; };
+using TypedNameList = std::vector<TypedName>;
+
+/// Direct EVM instruction (except PUSHi and JUMPDEST)
+struct Instruction { langutil::SourceLocation location; dev::solidity::Instruction instruction; };
+/// Literal number or string (up to 32 bytes)
+enum class LiteralKind { Number, Boolean, String };
+struct Literal { langutil::SourceLocation location; LiteralKind kind; YulString value; Type type; };
+/// External / internal identifier or label reference
+struct Identifier { langutil::SourceLocation location; YulString name; };
+/// Jump label ("name:")
+struct Label { langutil::SourceLocation location; YulString name; };
+/// Assignment from stack (":= x", moves stack top into x, potentially multiple slots)
+struct StackAssignment { langutil::SourceLocation location; Identifier variableName; };
+/// Assignment ("x := mload(20:u256)", expects push-1-expression on the right hand
+/// side and requires x to occupy exactly one stack slot.
+///
+/// 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 { langutil::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 { langutil::SourceLocation location; dev::solidity::Instruction instruction; std::vector<Expression> arguments; };
+struct FunctionCall { langutil::SourceLocation location; Identifier functionName; std::vector<Expression> arguments; };
+/// Statement that contains only a single expression
+struct ExpressionStatement { langutil::SourceLocation location; Expression expression; };
+/// Block-scope variable declaration ("let x:u256 := mload(20:u256)"), non-hoisted
+struct VariableDeclaration { langutil::SourceLocation location; TypedNameList variables; std::shared_ptr<Expression> value; };
+/// Block that creates a scope (frees declared stack variables)
+struct Block { langutil::SourceLocation location; std::vector<Statement> statements; };
+/// Function definition ("function f(a, b) -> (d, e) { ... }")
+struct FunctionDefinition { langutil::SourceLocation location; YulString name; TypedNameList parameters; TypedNameList returnVariables; Block body; };
+/// Conditional execution without "else" part.
+struct If { langutil::SourceLocation location; std::shared_ptr<Expression> condition; Block body; };
+/// Switch case or default case
+struct Case { langutil::SourceLocation location; std::shared_ptr<Literal> value; Block body; };
+/// Switch statement
+struct Switch { langutil::SourceLocation location; std::shared_ptr<Expression> expression; std::vector<Case> cases; };
+struct ForLoop { langutil::SourceLocation location; Block pre; std::shared_ptr<Expression> condition; Block post; Block body; };
+
+struct LocationExtractor: boost::static_visitor<langutil::SourceLocation>
+{
+ template <class T> langutil::SourceLocation operator()(T const& _node) const
+ {
+ return _node.location;
+ }
+};
+
+/// Extracts the source location from an inline assembly node.
+template <class T> inline langutil::SourceLocation locationOf(T const& _node)
+{
+ return boost::apply_visitor(LocationExtractor(), _node);
+}
+
+}
diff --git a/libyul/AsmDataForward.h b/libyul/AsmDataForward.h
new file mode 100644
index 00000000..046c8248
--- /dev/null
+++ b/libyul/AsmDataForward.h
@@ -0,0 +1,59 @@
+/*
+ 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 / Yul AST
+ */
+
+#pragma once
+
+#include <boost/variant.hpp>
+
+namespace yul
+{
+
+struct Instruction;
+struct Literal;
+struct Label;
+struct StackAssignment;
+struct Identifier;
+struct Assignment;
+struct VariableDeclaration;
+struct FunctionalInstruction;
+struct FunctionDefinition;
+struct FunctionCall;
+struct If;
+struct Switch;
+struct Case;
+struct ForLoop;
+struct ExpressionStatement;
+struct Block;
+
+struct TypedName;
+
+using Expression = boost::variant<FunctionalInstruction, FunctionCall, Identifier, Literal>;
+using Statement = boost::variant<ExpressionStatement, Instruction, Label, StackAssignment, Assignment, VariableDeclaration, FunctionDefinition, If, Switch, ForLoop, Block>;
+
+enum class AsmFlavour
+{
+ Loose, // no types, EVM instructions as function, jumps and direct stack manipulations
+ Strict, // no types, EVM instructions as functions, but no jumps and no direct stack manipulations
+ Yul // same as Strict mode with types
+};
+
+}
diff --git a/libyul/AsmParser.cpp b/libyul/AsmParser.cpp
new file mode 100644
index 00000000..2ce94f85
--- /dev/null
+++ b/libyul/AsmParser.cpp
@@ -0,0 +1,617 @@
+/*
+ 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
+ * Solidity inline assembly parser.
+ */
+
+#include <libyul/AsmParser.h>
+#include <liblangutil/Scanner.h>
+#include <liblangutil/ErrorReporter.h>
+
+#include <boost/algorithm/string.hpp>
+
+#include <cctype>
+#include <algorithm>
+
+using namespace std;
+using namespace dev;
+using namespace langutil;
+using namespace yul;
+using namespace dev::solidity;
+
+shared_ptr<Block> Parser::parse(std::shared_ptr<Scanner> const& _scanner, bool _reuseScanner)
+{
+ m_recursionDepth = 0;
+ try
+ {
+ m_scanner = _scanner;
+ auto block = make_shared<Block>(parseBlock());
+ if (!_reuseScanner)
+ expectToken(Token::EOS);
+ return block;
+ }
+ catch (FatalError const&)
+ {
+ if (m_errorReporter.errors().empty())
+ throw; // Something is weird here, rather throw again.
+ }
+ return nullptr;
+}
+
+Block Parser::parseBlock()
+{
+ RecursionGuard recursionGuard(*this);
+ Block block = createWithLocation<Block>();
+ expectToken(Token::LBrace);
+ while (currentToken() != Token::RBrace)
+ block.statements.emplace_back(parseStatement());
+ block.location.end = endPosition();
+ advance();
+ return block;
+}
+
+Statement Parser::parseStatement()
+{
+ RecursionGuard recursionGuard(*this);
+ switch (currentToken())
+ {
+ case Token::Let:
+ return parseVariableDeclaration();
+ case Token::Function:
+ return parseFunctionDefinition();
+ case Token::LBrace:
+ return parseBlock();
+ case Token::If:
+ {
+ If _if = createWithLocation<If>();
+ m_scanner->next();
+ _if.condition = make_shared<Expression>(parseExpression());
+ _if.body = parseBlock();
+ return _if;
+ }
+ case Token::Switch:
+ {
+ Switch _switch = createWithLocation<Switch>();
+ m_scanner->next();
+ _switch.expression = make_shared<Expression>(parseExpression());
+ while (m_scanner->currentToken() == Token::Case)
+ _switch.cases.emplace_back(parseCase());
+ if (m_scanner->currentToken() == Token::Default)
+ _switch.cases.emplace_back(parseCase());
+ if (m_scanner->currentToken() == Token::Default)
+ fatalParserError("Only one default case allowed.");
+ else if (m_scanner->currentToken() == Token::Case)
+ fatalParserError("Case not allowed after default case.");
+ if (_switch.cases.empty())
+ fatalParserError("Switch statement without any cases.");
+ _switch.location.end = _switch.cases.back().body.location.end;
+ return _switch;
+ }
+ case Token::For:
+ return parseForLoop();
+ case Token::Assign:
+ {
+ if (m_flavour != AsmFlavour::Loose)
+ break;
+ StackAssignment assignment = createWithLocation<StackAssignment>();
+ advance();
+ expectToken(Token::Colon);
+ assignment.variableName.location = location();
+ assignment.variableName.name = YulString(currentLiteral());
+ if (instructions().count(assignment.variableName.name.str()))
+ fatalParserError("Identifier expected, got instruction name.");
+ assignment.location.end = endPosition();
+ expectToken(Token::Identifier);
+ return assignment;
+ }
+ default:
+ break;
+ }
+ // Options left:
+ // Simple instruction (might turn into functional),
+ // literal,
+ // identifier (might turn into label or functional assignment)
+ ElementaryOperation elementary(parseElementaryOperation());
+ switch (currentToken())
+ {
+ case Token::LParen:
+ {
+ Expression expr = parseCall(std::move(elementary));
+ return ExpressionStatement{locationOf(expr), expr};
+ }
+ case Token::Comma:
+ {
+ // if a comma follows, a multiple assignment is assumed
+
+ if (elementary.type() != typeid(Identifier))
+ fatalParserError("Label name / variable name must precede \",\" (multiple assignment).");
+ Identifier const& identifier = boost::get<Identifier>(elementary);
+
+ Assignment assignment = createWithLocation<Assignment>(identifier.location);
+ assignment.variableNames.emplace_back(identifier);
+
+ do
+ {
+ expectToken(Token::Comma);
+ elementary = parseElementaryOperation();
+ if (elementary.type() != typeid(Identifier))
+ fatalParserError("Variable name expected in multiple assignment.");
+ assignment.variableNames.emplace_back(boost::get<Identifier>(elementary));
+ }
+ while (currentToken() == Token::Comma);
+
+ expectToken(Token::Colon);
+ expectToken(Token::Assign);
+
+ assignment.value.reset(new Expression(parseExpression()));
+ assignment.location.end = locationOf(*assignment.value).end;
+ return assignment;
+ }
+ case Token::Colon:
+ {
+ if (elementary.type() != typeid(Identifier))
+ fatalParserError("Label name / variable name must precede \":\".");
+ Identifier const& identifier = boost::get<Identifier>(elementary);
+ advance();
+ // identifier:=: should be parsed as identifier: =: (i.e. a label),
+ // while identifier:= (being followed by a non-colon) as identifier := (assignment).
+ if (currentToken() == Token::Assign && peekNextToken() != Token::Colon)
+ {
+ Assignment assignment = createWithLocation<Assignment>(identifier.location);
+ if (m_flavour != AsmFlavour::Yul && instructions().count(identifier.name.str()))
+ fatalParserError("Cannot use instruction names for identifier names.");
+ advance();
+ assignment.variableNames.emplace_back(identifier);
+ assignment.value.reset(new Expression(parseExpression()));
+ assignment.location.end = locationOf(*assignment.value).end;
+ return assignment;
+ }
+ else
+ {
+ // label
+ if (m_flavour != AsmFlavour::Loose)
+ fatalParserError("Labels are not supported.");
+ Label label = createWithLocation<Label>(identifier.location);
+ label.name = identifier.name;
+ return label;
+ }
+ }
+ default:
+ if (m_flavour != AsmFlavour::Loose)
+ fatalParserError("Call or assignment expected.");
+ break;
+ }
+ if (elementary.type() == typeid(Identifier))
+ {
+ Expression expr = boost::get<Identifier>(elementary);
+ return ExpressionStatement{locationOf(expr), expr};
+ }
+ else if (elementary.type() == typeid(Literal))
+ {
+ Expression expr = boost::get<Literal>(elementary);
+ return ExpressionStatement{locationOf(expr), expr};
+ }
+ else
+ {
+ solAssert(elementary.type() == typeid(Instruction), "Invalid elementary operation.");
+ return boost::get<Instruction>(elementary);
+ }
+}
+
+Case Parser::parseCase()
+{
+ RecursionGuard recursionGuard(*this);
+ Case _case = createWithLocation<Case>();
+ if (m_scanner->currentToken() == Token::Default)
+ m_scanner->next();
+ else if (m_scanner->currentToken() == Token::Case)
+ {
+ m_scanner->next();
+ ElementaryOperation literal = parseElementaryOperation();
+ if (literal.type() != typeid(Literal))
+ fatalParserError("Literal expected.");
+ _case.value = make_shared<Literal>(boost::get<Literal>(std::move(literal)));
+ }
+ else
+ fatalParserError("Case or default case expected.");
+ _case.body = parseBlock();
+ _case.location.end = _case.body.location.end;
+ return _case;
+}
+
+ForLoop Parser::parseForLoop()
+{
+ RecursionGuard recursionGuard(*this);
+ ForLoop forLoop = createWithLocation<ForLoop>();
+ expectToken(Token::For);
+ forLoop.pre = parseBlock();
+ forLoop.condition = make_shared<Expression>(parseExpression());
+ forLoop.post = parseBlock();
+ forLoop.body = parseBlock();
+ forLoop.location.end = forLoop.body.location.end;
+ return forLoop;
+}
+
+Expression Parser::parseExpression()
+{
+ RecursionGuard recursionGuard(*this);
+ // In strict mode, this might parse a plain Instruction, but
+ // it will be converted to a FunctionalInstruction inside
+ // parseCall below.
+ ElementaryOperation operation = parseElementaryOperation();
+ if (operation.type() == typeid(Instruction))
+ {
+ Instruction const& instr = boost::get<Instruction>(operation);
+ // Disallow instructions returning multiple values (and DUP/SWAP) as expression.
+ if (
+ instructionInfo(instr.instruction).ret != 1 ||
+ isDupInstruction(instr.instruction) ||
+ isSwapInstruction(instr.instruction)
+ )
+ fatalParserError(
+ "Instruction \"" +
+ instructionNames().at(instr.instruction) +
+ "\" not allowed in this context."
+ );
+ if (m_flavour != AsmFlavour::Loose && currentToken() != Token::LParen)
+ fatalParserError(
+ "Non-functional instructions are not allowed in this context."
+ );
+ // Enforce functional notation for instructions requiring multiple arguments.
+ int args = instructionInfo(instr.instruction).args;
+ if (args > 0 && currentToken() != Token::LParen)
+ fatalParserError(string(
+ "Expected '(' (instruction \"" +
+ instructionNames().at(instr.instruction) +
+ "\" expects " +
+ to_string(args) +
+ " arguments)"
+ ));
+ }
+ if (currentToken() == Token::LParen)
+ return parseCall(std::move(operation));
+ else if (operation.type() == typeid(Instruction))
+ {
+ // Instructions not taking arguments are allowed as expressions.
+ solAssert(m_flavour == AsmFlavour::Loose, "");
+ Instruction& instr = boost::get<Instruction>(operation);
+ return FunctionalInstruction{std::move(instr.location), instr.instruction, {}};
+ }
+ else if (operation.type() == typeid(Identifier))
+ return boost::get<Identifier>(operation);
+ else
+ {
+ solAssert(operation.type() == typeid(Literal), "");
+ return boost::get<Literal>(operation);
+ }
+}
+
+std::map<string, dev::solidity::Instruction> const& Parser::instructions()
+{
+ // Allowed instructions, lowercase names.
+ static map<string, dev::solidity::Instruction> s_instructions;
+ if (s_instructions.empty())
+ {
+ for (auto const& instruction: solidity::c_instructions)
+ {
+ if (
+ instruction.second == solidity::Instruction::JUMPDEST ||
+ solidity::isPushInstruction(instruction.second)
+ )
+ continue;
+ string name = instruction.first;
+ transform(name.begin(), name.end(), name.begin(), [](unsigned char _c) { return tolower(_c); });
+ s_instructions[name] = instruction.second;
+ }
+ }
+ return s_instructions;
+}
+
+std::map<dev::solidity::Instruction, string> const& Parser::instructionNames()
+{
+ static map<dev::solidity::Instruction, string> s_instructionNames;
+ if (s_instructionNames.empty())
+ {
+ for (auto const& instr: instructions())
+ s_instructionNames[instr.second] = instr.first;
+ // set the ambiguous instructions to a clear default
+ s_instructionNames[solidity::Instruction::SELFDESTRUCT] = "selfdestruct";
+ s_instructionNames[solidity::Instruction::KECCAK256] = "keccak256";
+ }
+ return s_instructionNames;
+}
+
+Parser::ElementaryOperation Parser::parseElementaryOperation()
+{
+ RecursionGuard recursionGuard(*this);
+ ElementaryOperation ret;
+ switch (currentToken())
+ {
+ case Token::Identifier:
+ case Token::Return:
+ case Token::Byte:
+ case Token::Address:
+ {
+ string literal;
+ if (currentToken() == Token::Return)
+ literal = "return";
+ else if (currentToken() == Token::Byte)
+ literal = "byte";
+ else if (currentToken() == Token::Address)
+ literal = "address";
+ else
+ literal = currentLiteral();
+ // first search the set of instructions.
+ if (m_flavour != AsmFlavour::Yul && instructions().count(literal))
+ {
+ dev::solidity::Instruction const& instr = instructions().at(literal);
+ ret = Instruction{location(), instr};
+ }
+ else
+ ret = Identifier{location(), YulString{literal}};
+ advance();
+ break;
+ }
+ case Token::StringLiteral:
+ case Token::Number:
+ case Token::TrueLiteral:
+ case Token::FalseLiteral:
+ {
+ LiteralKind kind = LiteralKind::Number;
+ switch (currentToken())
+ {
+ case Token::StringLiteral:
+ kind = LiteralKind::String;
+ break;
+ case Token::Number:
+ if (!isValidNumberLiteral(currentLiteral()))
+ fatalParserError("Invalid number literal.");
+ kind = LiteralKind::Number;
+ break;
+ case Token::TrueLiteral:
+ case Token::FalseLiteral:
+ kind = LiteralKind::Boolean;
+ break;
+ default:
+ break;
+ }
+
+ Literal literal{
+ location(),
+ kind,
+ YulString{currentLiteral()},
+ {}
+ };
+ advance();
+ if (m_flavour == AsmFlavour::Yul)
+ {
+ expectToken(Token::Colon);
+ literal.location.end = endPosition();
+ literal.type = YulString{expectAsmIdentifier()};
+ }
+ else if (kind == LiteralKind::Boolean)
+ fatalParserError("True and false are not valid literals.");
+ ret = std::move(literal);
+ break;
+ }
+ default:
+ fatalParserError(
+ m_flavour == AsmFlavour::Yul ?
+ "Literal or identifier expected." :
+ "Literal, identifier or instruction expected."
+ );
+ }
+ return ret;
+}
+
+VariableDeclaration Parser::parseVariableDeclaration()
+{
+ RecursionGuard recursionGuard(*this);
+ VariableDeclaration varDecl = createWithLocation<VariableDeclaration>();
+ expectToken(Token::Let);
+ while (true)
+ {
+ varDecl.variables.emplace_back(parseTypedName());
+ if (currentToken() == Token::Comma)
+ expectToken(Token::Comma);
+ else
+ break;
+ }
+ if (currentToken() == Token::Colon)
+ {
+ expectToken(Token::Colon);
+ expectToken(Token::Assign);
+ varDecl.value.reset(new Expression(parseExpression()));
+ varDecl.location.end = locationOf(*varDecl.value).end;
+ }
+ else
+ varDecl.location.end = varDecl.variables.back().location.end;
+ return varDecl;
+}
+
+FunctionDefinition Parser::parseFunctionDefinition()
+{
+ RecursionGuard recursionGuard(*this);
+ FunctionDefinition funDef = createWithLocation<FunctionDefinition>();
+ expectToken(Token::Function);
+ funDef.name = YulString{expectAsmIdentifier()};
+ expectToken(Token::LParen);
+ while (currentToken() != Token::RParen)
+ {
+ funDef.parameters.emplace_back(parseTypedName());
+ if (currentToken() == Token::RParen)
+ break;
+ expectToken(Token::Comma);
+ }
+ expectToken(Token::RParen);
+ if (currentToken() == Token::Sub)
+ {
+ expectToken(Token::Sub);
+ expectToken(Token::GreaterThan);
+ while (true)
+ {
+ funDef.returnVariables.emplace_back(parseTypedName());
+ if (currentToken() == Token::LBrace)
+ break;
+ expectToken(Token::Comma);
+ }
+ }
+ funDef.body = parseBlock();
+ funDef.location.end = funDef.body.location.end;
+ return funDef;
+}
+
+Expression Parser::parseCall(Parser::ElementaryOperation&& _initialOp)
+{
+ RecursionGuard recursionGuard(*this);
+ if (_initialOp.type() == typeid(Instruction))
+ {
+ solAssert(m_flavour != AsmFlavour::Yul, "Instructions are invalid in Yul");
+ Instruction& instruction = boost::get<Instruction>(_initialOp);
+ FunctionalInstruction ret;
+ ret.instruction = instruction.instruction;
+ ret.location = std::move(instruction.location);
+ solidity::Instruction instr = ret.instruction;
+ InstructionInfo instrInfo = instructionInfo(instr);
+ if (solidity::isDupInstruction(instr))
+ fatalParserError("DUPi instructions not allowed for functional notation");
+ if (solidity::isSwapInstruction(instr))
+ fatalParserError("SWAPi instructions not allowed for functional notation");
+ expectToken(Token::LParen);
+ unsigned args = unsigned(instrInfo.args);
+ for (unsigned i = 0; i < args; ++i)
+ {
+ /// check for premature closing parentheses
+ if (currentToken() == Token::RParen)
+ fatalParserError(string(
+ "Expected expression (instruction \"" +
+ instructionNames().at(instr) +
+ "\" expects " +
+ to_string(args) +
+ " arguments)"
+ ));
+
+ ret.arguments.emplace_back(parseExpression());
+ if (i != args - 1)
+ {
+ if (currentToken() != Token::Comma)
+ fatalParserError(string(
+ "Expected ',' (instruction \"" +
+ instructionNames().at(instr) +
+ "\" expects " +
+ to_string(args) +
+ " arguments)"
+ ));
+ else
+ advance();
+ }
+ }
+ ret.location.end = endPosition();
+ if (currentToken() == Token::Comma)
+ fatalParserError(string(
+ "Expected ')' (instruction \"" +
+ instructionNames().at(instr) +
+ "\" expects " +
+ to_string(args) +
+ " arguments)"
+ ));
+ expectToken(Token::RParen);
+ return ret;
+ }
+ else if (_initialOp.type() == typeid(Identifier))
+ {
+ FunctionCall ret;
+ ret.functionName = std::move(boost::get<Identifier>(_initialOp));
+ ret.location = ret.functionName.location;
+ expectToken(Token::LParen);
+ while (currentToken() != Token::RParen)
+ {
+ ret.arguments.emplace_back(parseExpression());
+ if (currentToken() == Token::RParen)
+ break;
+ expectToken(Token::Comma);
+ }
+ ret.location.end = endPosition();
+ expectToken(Token::RParen);
+ return ret;
+ }
+ else
+ fatalParserError(
+ m_flavour == AsmFlavour::Yul ?
+ "Function name expected." :
+ "Assembly instruction or function name required in front of \"(\")"
+ );
+
+ return {};
+}
+
+TypedName Parser::parseTypedName()
+{
+ RecursionGuard recursionGuard(*this);
+ TypedName typedName = createWithLocation<TypedName>();
+ typedName.name = YulString{expectAsmIdentifier()};
+ if (m_flavour == AsmFlavour::Yul)
+ {
+ expectToken(Token::Colon);
+ typedName.location.end = endPosition();
+ typedName.type = YulString{expectAsmIdentifier()};
+ }
+ return typedName;
+}
+
+string Parser::expectAsmIdentifier()
+{
+ string name = currentLiteral();
+ if (m_flavour == AsmFlavour::Yul)
+ {
+ switch (currentToken())
+ {
+ case Token::Return:
+ case Token::Byte:
+ case Token::Address:
+ case Token::Bool:
+ advance();
+ return name;
+ default:
+ break;
+ }
+ }
+ else if (instructions().count(name))
+ fatalParserError("Cannot use instruction names for identifier names.");
+ expectToken(Token::Identifier);
+ return name;
+}
+
+bool Parser::isValidNumberLiteral(string const& _literal)
+{
+ try
+ {
+ // Try to convert _literal to u256.
+ auto tmp = u256(_literal);
+ (void) tmp;
+ }
+ catch (...)
+ {
+ return false;
+ }
+ if (boost::starts_with(_literal, "0x"))
+ return true;
+ else
+ return _literal.find_first_not_of("0123456789") == string::npos;
+}
diff --git a/libyul/AsmParser.h b/libyul/AsmParser.h
new file mode 100644
index 00000000..52166a20
--- /dev/null
+++ b/libyul/AsmParser.h
@@ -0,0 +1,89 @@
+/*
+ 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
+ * Solidity inline assembly parser.
+ */
+
+#pragma once
+
+#include <memory>
+#include <vector>
+#include <libyul/AsmData.h>
+#include <liblangutil/SourceLocation.h>
+#include <liblangutil/Scanner.h>
+#include <liblangutil/ParserBase.h>
+
+namespace yul
+{
+
+class Parser: public langutil::ParserBase
+{
+public:
+ explicit Parser(langutil::ErrorReporter& _errorReporter, AsmFlavour _flavour = AsmFlavour::Loose):
+ ParserBase(_errorReporter), m_flavour(_flavour) {}
+
+ /// Parses an inline assembly block starting with `{` and ending with `}`.
+ /// @param _reuseScanner if true, do check for end of input after the `}`.
+ /// @returns an empty shared pointer on error.
+ std::shared_ptr<Block> parse(std::shared_ptr<langutil::Scanner> const& _scanner, bool _reuseScanner);
+
+protected:
+ using ElementaryOperation = boost::variant<Instruction, Literal, Identifier>;
+
+ /// Creates an inline assembly node with the given source location.
+ template <class T> T createWithLocation(langutil::SourceLocation const& _loc = {}) const
+ {
+ T r;
+ r.location = _loc;
+ if (r.location.isEmpty())
+ {
+ r.location.start = position();
+ r.location.end = endPosition();
+ }
+ if (!r.location.source)
+ r.location.source = m_scanner->charStream();
+ return r;
+ }
+ langutil::SourceLocation location() const { return {position(), endPosition(), m_scanner->charStream()}; }
+
+ Block parseBlock();
+ Statement parseStatement();
+ Case parseCase();
+ ForLoop parseForLoop();
+ /// Parses a functional expression that has to push exactly one stack element
+ Expression parseExpression();
+ static std::map<std::string, dev::solidity::Instruction> const& instructions();
+ static std::map<dev::solidity::Instruction, std::string> const& instructionNames();
+ /// Parses an elementary operation, i.e. a literal, identifier or instruction.
+ /// This will parse instructions even in strict mode as part of the full parser
+ /// for FunctionalInstruction.
+ ElementaryOperation parseElementaryOperation();
+ VariableDeclaration parseVariableDeclaration();
+ FunctionDefinition parseFunctionDefinition();
+ Expression parseCall(ElementaryOperation&& _initialOp);
+ TypedName parseTypedName();
+ std::string expectAsmIdentifier();
+
+ static bool isValidNumberLiteral(std::string const& _literal);
+
+private:
+ AsmFlavour m_flavour = AsmFlavour::Loose;
+};
+
+}
diff --git a/libyul/AsmPrinter.cpp b/libyul/AsmPrinter.cpp
new file mode 100644
index 00000000..eaaba9f3
--- /dev/null
+++ b/libyul/AsmPrinter.cpp
@@ -0,0 +1,250 @@
+/*
+ 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 2017
+ * Converts a parsed assembly into its textual form.
+ */
+
+#include <libyul/AsmPrinter.h>
+#include <libyul/AsmData.h>
+#include <liblangutil/Exceptions.h>
+
+#include <libdevcore/CommonData.h>
+
+#include <boost/algorithm/string.hpp>
+#include <boost/algorithm/string/replace.hpp>
+#include <boost/range/adaptor/transformed.hpp>
+
+#include <memory>
+#include <functional>
+
+using namespace std;
+using namespace dev;
+using namespace yul;
+using namespace dev::solidity;
+
+//@TODO source locations
+
+string AsmPrinter::operator()(yul::Instruction const& _instruction)
+{
+ solAssert(!m_yul, "");
+ solAssert(isValidInstruction(_instruction.instruction), "Invalid instruction");
+ return boost::to_lower_copy(instructionInfo(_instruction.instruction).name);
+}
+
+string AsmPrinter::operator()(Literal const& _literal)
+{
+ switch (_literal.kind)
+ {
+ case LiteralKind::Number:
+ solAssert(isValidDecimal(_literal.value.str()) || isValidHex(_literal.value.str()), "Invalid number literal");
+ return _literal.value.str() + appendTypeName(_literal.type);
+ case LiteralKind::Boolean:
+ solAssert(_literal.value.str() == "true" || _literal.value.str() == "false", "Invalid bool literal.");
+ return ((_literal.value.str() == "true") ? "true" : "false") + appendTypeName(_literal.type);
+ case LiteralKind::String:
+ break;
+ }
+
+ string out;
+ for (char c: _literal.value.str())
+ if (c == '\\')
+ out += "\\\\";
+ else if (c == '"')
+ out += "\\\"";
+ else if (c == '\b')
+ out += "\\b";
+ else if (c == '\f')
+ out += "\\f";
+ else if (c == '\n')
+ out += "\\n";
+ else if (c == '\r')
+ out += "\\r";
+ else if (c == '\t')
+ out += "\\t";
+ else if (c == '\v')
+ out += "\\v";
+ else if (!isprint(c, locale::classic()))
+ {
+ ostringstream o;
+ o << std::hex << setfill('0') << setw(2) << (unsigned)(unsigned char)(c);
+ out += "\\x" + o.str();
+ }
+ else
+ out += c;
+ return "\"" + out + "\"" + appendTypeName(_literal.type);
+}
+
+string AsmPrinter::operator()(Identifier const& _identifier)
+{
+ solAssert(!_identifier.name.empty(), "Invalid identifier.");
+ return _identifier.name.str();
+}
+
+string AsmPrinter::operator()(FunctionalInstruction const& _functionalInstruction)
+{
+ solAssert(!m_yul, "");
+ solAssert(isValidInstruction(_functionalInstruction.instruction), "Invalid instruction");
+ return
+ boost::to_lower_copy(instructionInfo(_functionalInstruction.instruction).name) +
+ "(" +
+ boost::algorithm::join(
+ _functionalInstruction.arguments | boost::adaptors::transformed(boost::apply_visitor(*this)),
+ ", ") +
+ ")";
+}
+
+string AsmPrinter::operator()(ExpressionStatement const& _statement)
+{
+ return boost::apply_visitor(*this, _statement.expression);
+}
+
+string AsmPrinter::operator()(Label const& _label)
+{
+ solAssert(!m_yul, "");
+ solAssert(!_label.name.empty(), "Invalid label.");
+ return _label.name.str() + ":";
+}
+
+string AsmPrinter::operator()(StackAssignment const& _assignment)
+{
+ solAssert(!m_yul, "");
+ solAssert(!_assignment.variableName.name.empty(), "Invalid variable name.");
+ return "=: " + (*this)(_assignment.variableName);
+}
+
+string AsmPrinter::operator()(Assignment const& _assignment)
+{
+ solAssert(_assignment.variableNames.size() >= 1, "");
+ string variables = (*this)(_assignment.variableNames.front());
+ for (size_t i = 1; i < _assignment.variableNames.size(); ++i)
+ variables += ", " + (*this)(_assignment.variableNames[i]);
+ return variables + " := " + boost::apply_visitor(*this, *_assignment.value);
+}
+
+string AsmPrinter::operator()(VariableDeclaration const& _variableDeclaration)
+{
+ string out = "let ";
+ out += boost::algorithm::join(
+ _variableDeclaration.variables | boost::adaptors::transformed(
+ [this](TypedName argument) { return formatTypedName(argument); }
+ ),
+ ", "
+ );
+ if (_variableDeclaration.value)
+ {
+ out += " := ";
+ out += boost::apply_visitor(*this, *_variableDeclaration.value);
+ }
+ return out;
+}
+
+string AsmPrinter::operator()(FunctionDefinition const& _functionDefinition)
+{
+ solAssert(!_functionDefinition.name.empty(), "Invalid function name.");
+ string out = "function " + _functionDefinition.name.str() + "(";
+ out += boost::algorithm::join(
+ _functionDefinition.parameters | boost::adaptors::transformed(
+ [this](TypedName argument) { return formatTypedName(argument); }
+ ),
+ ", "
+ );
+ out += ")";
+ if (!_functionDefinition.returnVariables.empty())
+ {
+ out += " -> ";
+ out += boost::algorithm::join(
+ _functionDefinition.returnVariables | boost::adaptors::transformed(
+ [this](TypedName argument) { return formatTypedName(argument); }
+ ),
+ ", "
+ );
+ }
+
+ return out + "\n" + (*this)(_functionDefinition.body);
+}
+
+string AsmPrinter::operator()(FunctionCall const& _functionCall)
+{
+ return
+ (*this)(_functionCall.functionName) + "(" +
+ boost::algorithm::join(
+ _functionCall.arguments | boost::adaptors::transformed(boost::apply_visitor(*this)),
+ ", " ) +
+ ")";
+}
+
+string AsmPrinter::operator()(If const& _if)
+{
+ solAssert(_if.condition, "Invalid if condition.");
+ return "if " + boost::apply_visitor(*this, *_if.condition) + "\n" + (*this)(_if.body);
+}
+
+string AsmPrinter::operator()(Switch const& _switch)
+{
+ solAssert(_switch.expression, "Invalid expression pointer.");
+ string out = "switch " + boost::apply_visitor(*this, *_switch.expression);
+ for (auto const& _case: _switch.cases)
+ {
+ if (!_case.value)
+ out += "\ndefault ";
+ else
+ out += "\ncase " + (*this)(*_case.value) + " ";
+ out += (*this)(_case.body);
+ }
+ return out;
+}
+
+string AsmPrinter::operator()(ForLoop const& _forLoop)
+{
+ solAssert(_forLoop.condition, "Invalid for loop condition.");
+ 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())
+ return "{\n}";
+ string body = boost::algorithm::join(
+ _block.statements | boost::adaptors::transformed(boost::apply_visitor(*this)),
+ "\n"
+ );
+ boost::replace_all(body, "\n", "\n ");
+ return "{\n " + body + "\n}";
+}
+
+string AsmPrinter::formatTypedName(TypedName _variable) const
+{
+ solAssert(!_variable.name.empty(), "Invalid variable name.");
+ return _variable.name.str() + appendTypeName(_variable.type);
+}
+
+string AsmPrinter::appendTypeName(YulString _type) const
+{
+ if (m_yul)
+ return ":" + _type.str();
+ return "";
+}
diff --git a/libyul/AsmPrinter.h b/libyul/AsmPrinter.h
new file mode 100644
index 00000000..61dfc18c
--- /dev/null
+++ b/libyul/AsmPrinter.h
@@ -0,0 +1,62 @@
+/*
+ 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 2017
+ * Converts a parsed assembly into its textual form.
+ */
+
+#pragma once
+
+#include <libyul/AsmDataForward.h>
+
+#include <libyul/YulString.h>
+
+#include <boost/variant.hpp>
+
+namespace yul
+{
+
+class AsmPrinter: public boost::static_visitor<std::string>
+{
+public:
+ explicit AsmPrinter(bool _yul = false): m_yul(_yul) {}
+
+ std::string operator()(Instruction const& _instruction);
+ std::string operator()(Literal const& _literal);
+ std::string operator()(Identifier const& _identifier);
+ std::string operator()(FunctionalInstruction const& _functionalInstruction);
+ std::string operator()(ExpressionStatement const& _expr);
+ std::string operator()(Label const& _label);
+ std::string operator()(StackAssignment const& _assignment);
+ std::string operator()(Assignment const& _assignment);
+ std::string operator()(VariableDeclaration const& _variableDeclaration);
+ std::string operator()(FunctionDefinition const& _functionDefinition);
+ std::string operator()(FunctionCall const& _functionCall);
+ std::string operator()(If const& _if);
+ std::string operator()(Switch const& _switch);
+ std::string operator()(ForLoop const& _forLoop);
+ std::string operator()(Block const& _block);
+
+private:
+ std::string formatTypedName(TypedName _variable) const;
+ std::string appendTypeName(YulString _type) const;
+
+ bool m_yul = false;
+};
+
+}
diff --git a/libyul/AsmScope.cpp b/libyul/AsmScope.cpp
new file mode 100644
index 00000000..b71f2367
--- /dev/null
+++ b/libyul/AsmScope.cpp
@@ -0,0 +1,98 @@
+/*
+ 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/>.
+*/
+/**
+ * Scopes for identifiers.
+ */
+
+#include <libyul/AsmScope.h>
+
+using namespace std;
+using namespace dev;
+using namespace yul;
+
+bool Scope::registerLabel(YulString _name)
+{
+ if (exists(_name))
+ return false;
+ identifiers[_name] = Label();
+ return true;
+}
+
+bool Scope::registerVariable(YulString _name, YulType const& _type)
+{
+ if (exists(_name))
+ return false;
+ Variable variable;
+ variable.type = _type;
+ identifiers[_name] = variable;
+ return true;
+}
+
+bool Scope::registerFunction(YulString _name, std::vector<YulType> const& _arguments, std::vector<YulType> const& _returns)
+{
+ if (exists(_name))
+ return false;
+ identifiers[_name] = Function{_arguments, _returns};
+ return true;
+}
+
+Scope::Identifier* Scope::lookup(YulString _name)
+{
+ bool crossedFunctionBoundary = false;
+ for (Scope* s = this; s; s = s->superScope)
+ {
+ auto id = s->identifiers.find(_name);
+ if (id != s->identifiers.end())
+ {
+ if (crossedFunctionBoundary && id->second.type() == typeid(Scope::Variable))
+ return nullptr;
+ else
+ return &id->second;
+ }
+
+ if (s->functionScope)
+ crossedFunctionBoundary = true;
+ }
+ return nullptr;
+}
+
+bool Scope::exists(YulString _name) const
+{
+ if (identifiers.count(_name))
+ return true;
+ else if (superScope)
+ return superScope->exists(_name);
+ else
+ 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)
+ if (s->functionScope)
+ return true;
+ return false;
+}
diff --git a/libyul/AsmScope.h b/libyul/AsmScope.h
new file mode 100644
index 00000000..2a8ef49e
--- /dev/null
+++ b/libyul/AsmScope.h
@@ -0,0 +1,99 @@
+/*
+ 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/>.
+*/
+/**
+ * Scopes for identifiers.
+ */
+
+#pragma once
+
+#include <liblangutil/Exceptions.h>
+
+#include <libyul/YulString.h>
+
+#include <libdevcore/Visitor.h>
+
+#include <boost/variant.hpp>
+#include <boost/optional.hpp>
+
+#include <functional>
+#include <memory>
+
+namespace yul
+{
+
+struct Scope
+{
+ using YulType = YulString;
+ using LabelID = size_t;
+
+ struct Variable { YulType type; };
+ struct Label { };
+ struct Function
+ {
+ std::vector<YulType> arguments;
+ std::vector<YulType> returns;
+ };
+
+ using Identifier = boost::variant<Variable, Label, Function>;
+ using Visitor = dev::GenericVisitor<Variable const, Label const, Function const>;
+ using NonconstVisitor = dev::GenericVisitor<Variable, Label, Function>;
+
+ bool registerVariable(YulString _name, YulType const& _type);
+ bool registerLabel(YulString _name);
+ bool registerFunction(
+ YulString _name,
+ std::vector<YulType> const& _arguments,
+ std::vector<YulType> const& _returns
+ );
+
+ /// Looks up the identifier in this or super scopes and returns a valid pointer if found
+ /// or a nullptr if not found. Variable lookups up across function boundaries will fail, as
+ /// will any lookups across assembly boundaries.
+ /// The pointer will be invalidated if the scope is modified.
+ /// @param _crossedFunction if true, we already crossed a function boundary during recursive lookup
+ Identifier* lookup(YulString _name);
+ /// Looks up the identifier in this and super scopes (will not find variables across function
+ /// boundaries and generally stops at assembly boundaries) and calls the visitor, returns
+ /// false if not found.
+ template <class V>
+ bool lookup(YulString _name, V const& _visitor)
+ {
+ if (Identifier* id = lookup(_name))
+ {
+ boost::apply_visitor(_visitor, *id);
+ return true;
+ }
+ else
+ return false;
+ }
+ /// @returns true if the name exists in this scope or in super scopes (also searches
+ /// across function and assembly boundaries).
+ bool exists(YulString _name) const;
+
+ /// @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;
+
+ Scope* superScope = nullptr;
+ /// If true, variables from the super scope are not visible here (other identifiers are),
+ /// but they are still taken into account to prevent shadowing.
+ bool functionScope = false;
+ std::map<YulString, Identifier> identifiers;
+};
+
+}
diff --git a/libyul/AsmScopeFiller.cpp b/libyul/AsmScopeFiller.cpp
new file mode 100644
index 00000000..ee797d6a
--- /dev/null
+++ b/libyul/AsmScopeFiller.cpp
@@ -0,0 +1,181 @@
+/*
+ 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/>.
+*/
+/**
+ * Module responsible for registering identifiers inside their scopes.
+ */
+
+#include <libyul/AsmScopeFiller.h>
+
+#include <libyul/AsmData.h>
+#include <libyul/AsmScope.h>
+#include <libyul/AsmAnalysisInfo.h>
+
+#include <liblangutil/ErrorReporter.h>
+#include <liblangutil/Exceptions.h>
+
+#include <libdevcore/CommonData.h>
+
+#include <boost/range/adaptor/reversed.hpp>
+
+#include <memory>
+#include <functional>
+
+using namespace std;
+using namespace dev;
+using namespace langutil;
+using namespace yul;
+using namespace dev::solidity;
+
+ScopeFiller::ScopeFiller(AsmAnalysisInfo& _info, ErrorReporter& _errorReporter):
+ m_info(_info), m_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))
+ {
+ //@TODO secondary location
+ m_errorReporter.declarationError(
+ _item.location,
+ "Label name " + _item.name.str() + " already taken in this scope."
+ );
+ return false;
+ }
+ return true;
+}
+
+bool ScopeFiller::operator()(VariableDeclaration const& _varDecl)
+{
+ for (auto const& variable: _varDecl.variables)
+ if (!registerVariable(variable, _varDecl.location, *m_currentScope))
+ return false;
+ return true;
+}
+
+bool ScopeFiller::operator()(FunctionDefinition const& _funDef)
+{
+ bool success = true;
+ vector<Scope::YulType> arguments;
+ for (auto const& _argument: _funDef.parameters)
+ arguments.emplace_back(_argument.type.str());
+ vector<Scope::YulType> returns;
+ for (auto const& _return: _funDef.returnVariables)
+ returns.emplace_back(_return.type.str());
+ if (!m_currentScope->registerFunction(_funDef.name, arguments, returns))
+ {
+ //@TODO secondary location
+ m_errorReporter.declarationError(
+ _funDef.location,
+ "Function name " + _funDef.name.str() + " already taken in this scope."
+ );
+ success = false;
+ }
+
+ auto virtualBlock = m_info.virtualBlocks[&_funDef] = make_shared<Block>();
+ Scope& varScope = scope(virtualBlock.get());
+ varScope.superScope = m_currentScope;
+ m_currentScope = &varScope;
+ varScope.functionScope = true;
+ for (auto const& var: _funDef.parameters + _funDef.returnVariables)
+ if (!registerVariable(var, _funDef.location, varScope))
+ success = false;
+
+ if (!(*this)(_funDef.body))
+ success = false;
+
+ solAssert(m_currentScope == &varScope, "");
+ m_currentScope = m_currentScope->superScope;
+
+ return success;
+}
+
+bool ScopeFiller::operator()(If const& _if)
+{
+ return (*this)(_if.body);
+}
+
+bool ScopeFiller::operator()(Switch const& _switch)
+{
+ bool success = true;
+ for (auto const& _case: _switch.cases)
+ if (!(*this)(_case.body))
+ success = false;
+ 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;
+ scope(&_block).superScope = m_currentScope;
+ m_currentScope = &scope(&_block);
+
+ for (auto const& s: _block.statements)
+ if (!boost::apply_visitor(*this, s))
+ success = false;
+
+ m_currentScope = m_currentScope->superScope;
+ return success;
+}
+
+bool ScopeFiller::registerVariable(TypedName const& _name, SourceLocation const& _location, Scope& _scope)
+{
+ if (!_scope.registerVariable(_name.name, _name.type))
+ {
+ //@TODO secondary location
+ m_errorReporter.declarationError(
+ _location,
+ "Variable name " + _name.name.str() + " already taken in this scope."
+ );
+ return false;
+ }
+ return true;
+}
+
+Scope& ScopeFiller::scope(Block const* _block)
+{
+ auto& scope = m_info.scopes[_block];
+ if (!scope)
+ scope = make_shared<Scope>();
+ return *scope;
+}
diff --git a/libyul/AsmScopeFiller.h b/libyul/AsmScopeFiller.h
new file mode 100644
index 00000000..e8fb88d5
--- /dev/null
+++ b/libyul/AsmScopeFiller.h
@@ -0,0 +1,82 @@
+/*
+ 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/>.
+*/
+/**
+ * Module responsible for registering identifiers inside their scopes.
+ */
+
+#pragma once
+
+#include <libyul/AsmDataForward.h>
+
+#include <boost/variant.hpp>
+
+#include <functional>
+#include <memory>
+
+namespace langutil
+{
+class ErrorReporter;
+struct SourceLocation;
+}
+
+namespace yul
+{
+
+struct TypedName;
+struct Scope;
+struct AsmAnalysisInfo;
+
+/**
+ * Fills scopes with identifiers and checks for name clashes.
+ * Does not resolve references.
+ */
+class ScopeFiller: public boost::static_visitor<bool>
+{
+public:
+ ScopeFiller(AsmAnalysisInfo& _info, langutil::ErrorReporter& _errorReporter);
+
+ bool operator()(Instruction const&) { return true; }
+ bool operator()(Literal const&) { return true; }
+ bool operator()(Identifier const&) { return true; }
+ bool operator()(FunctionalInstruction const&) { return true; }
+ bool operator()(ExpressionStatement const& _expr);
+ bool operator()(Label const& _label);
+ bool operator()(StackAssignment const&) { return true; }
+ bool operator()(Assignment const&) { return true; }
+ bool operator()(VariableDeclaration const& _variableDeclaration);
+ bool operator()(FunctionDefinition const& _functionDefinition);
+ bool operator()(FunctionCall const&) { return true; }
+ bool operator()(If const& _if);
+ bool operator()(Switch const& _switch);
+ bool operator()(ForLoop const& _forLoop);
+ bool operator()(Block const& _block);
+
+private:
+ bool registerVariable(
+ TypedName const& _name,
+ langutil::SourceLocation const& _location,
+ Scope& _scope
+ );
+
+ Scope& scope(Block const* _block);
+
+ Scope* m_currentScope = nullptr;
+ AsmAnalysisInfo& m_info;
+ langutil::ErrorReporter& m_errorReporter;
+};
+
+}
diff --git a/libyul/CMakeLists.txt b/libyul/CMakeLists.txt
new file mode 100644
index 00000000..7ed84ff5
--- /dev/null
+++ b/libyul/CMakeLists.txt
@@ -0,0 +1,45 @@
+add_library(yul
+ AsmAnalysis.cpp
+ AsmAnalysisInfo.cpp
+ AsmCodeGen.cpp
+ AsmParser.cpp
+ AsmPrinter.cpp
+ AsmScope.cpp
+ AsmScopeFiller.cpp
+ Object.cpp
+ ObjectParser.cpp
+ backends/evm/EVMAssembly.cpp
+ backends/evm/EVMCodeTransform.cpp
+ optimiser/ASTCopier.cpp
+ optimiser/ASTWalker.cpp
+ optimiser/BlockFlattener.cpp
+ optimiser/CommonSubexpressionEliminator.cpp
+ optimiser/DataFlowAnalyzer.cpp
+ optimiser/Disambiguator.cpp
+ optimiser/ExpressionInliner.cpp
+ optimiser/ExpressionJoiner.cpp
+ optimiser/ExpressionSimplifier.cpp
+ optimiser/ExpressionSplitter.cpp
+ optimiser/ForLoopInitRewriter.cpp
+ optimiser/FullInliner.cpp
+ optimiser/FunctionGrouper.cpp
+ optimiser/FunctionHoister.cpp
+ optimiser/InlinableExpressionFunctionFinder.cpp
+ optimiser/MainFunction.cpp
+ optimiser/Metrics.cpp
+ optimiser/NameCollector.cpp
+ optimiser/NameDispenser.cpp
+ optimiser/RedundantAssignEliminator.cpp
+ optimiser/Rematerialiser.cpp
+ optimiser/SSATransform.cpp
+ optimiser/SSAValueTracker.cpp
+ optimiser/Semantics.cpp
+ optimiser/SimplificationRules.cpp
+ optimiser/Substitution.cpp
+ optimiser/Suite.cpp
+ optimiser/SyntacticalEquality.cpp
+ optimiser/UnusedPruner.cpp
+ optimiser/Utilities.cpp
+ optimiser/VarDeclPropagator.cpp
+)
+target_link_libraries(yul PUBLIC devcore)
diff --git a/libyul/Exceptions.h b/libyul/Exceptions.h
index 0c421dbf..e10e53ef 100644
--- a/libyul/Exceptions.h
+++ b/libyul/Exceptions.h
@@ -23,18 +23,15 @@
#include <libdevcore/Exceptions.h>
#include <libdevcore/Assertions.h>
-namespace dev
-{
namespace yul
{
-struct YulException: virtual Exception {};
+struct YulException: virtual dev::Exception {};
struct OptimizerException: virtual YulException {};
struct YulAssertion: virtual YulException {};
/// Assertion that throws an YulAssertion containing the given description if it is not met.
#define yulAssert(CONDITION, DESCRIPTION) \
- assertThrow(CONDITION, ::dev::yul::YulException, DESCRIPTION)
+ assertThrow(CONDITION, ::yul::YulException, DESCRIPTION)
}
-}
diff --git a/libyul/Object.cpp b/libyul/Object.cpp
new file mode 100644
index 00000000..a5228793
--- /dev/null
+++ b/libyul/Object.cpp
@@ -0,0 +1,61 @@
+/*
+ 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/>.
+*/
+/**
+ * Yul code and data object container.
+ */
+
+#include <libyul/Object.h>
+
+#include <libyul/AsmPrinter.h>
+#include <libyul/Exceptions.h>
+
+#include <libdevcore/Visitor.h>
+#include <libdevcore/CommonData.h>
+
+#include <boost/algorithm/string/replace.hpp>
+
+using namespace dev;
+using namespace yul;
+using namespace std;
+
+namespace
+{
+
+string indent(std::string const& _input)
+{
+ if (_input.empty())
+ return _input;
+ return boost::replace_all_copy(" " + _input, "\n", "\n ");
+}
+
+}
+
+string Data::toString(bool) const
+{
+ return "data \"" + name.str() + "\" hex\"" + dev::toHex(data) + "\"";
+}
+
+string Object::toString(bool _yul) const
+{
+ yulAssert(code, "No code");
+ string inner = "code " + AsmPrinter{_yul}(*code);
+
+ for (auto const& obj: subObjects)
+ inner += "\n" + obj->toString(_yul);
+
+ return "object \"" + name.str() + "\" {\n" + indent(inner) + "\n}";
+}
diff --git a/libyul/Object.h b/libyul/Object.h
new file mode 100644
index 00000000..cfd8d02d
--- /dev/null
+++ b/libyul/Object.h
@@ -0,0 +1,72 @@
+/*
+ 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/>.
+*/
+/**
+ * Yul code and data object container.
+ */
+
+#pragma once
+
+#include <libyul/AsmDataForward.h>
+#include <libyul/YulString.h>
+
+#include <libdevcore/Common.h>
+
+#include <memory>
+
+namespace yul
+{
+struct AsmAnalysisInfo;
+
+
+/**
+ * Generic base class for both Yul objects and Yul data.
+ */
+struct ObjectNode
+{
+ virtual ~ObjectNode() {}
+ virtual std::string toString(bool _yul) const = 0;
+
+ YulString name;
+};
+
+/**
+ * Named data in Yul objects.
+ */
+struct Data: ObjectNode
+{
+ Data(YulString _name, dev::bytes _data): data(std::move(_data)) { name = _name; }
+ std::string toString(bool _yul) const override;
+
+ dev::bytes data;
+};
+
+/**
+ * Yul code and data object container.
+ */
+struct Object: ObjectNode
+{
+public:
+ /// @returns a (parseable) string representation. Includes types if @a _yul is set.
+ std::string toString(bool _yul) const override;
+
+ std::shared_ptr<Block> code;
+ std::vector<std::shared_ptr<ObjectNode>> subObjects;
+ std::map<YulString, size_t> subIndexByName;
+ std::shared_ptr<yul::AsmAnalysisInfo> analysisInfo;
+};
+
+}
diff --git a/libyul/ObjectParser.cpp b/libyul/ObjectParser.cpp
new file mode 100644
index 00000000..43dd4be9
--- /dev/null
+++ b/libyul/ObjectParser.cpp
@@ -0,0 +1,146 @@
+/*
+ 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/>.
+*/
+/**
+ * Parser for Yul code and data object container.
+ */
+
+#include <libyul/ObjectParser.h>
+
+#include <libyul/AsmParser.h>
+#include <libyul/Exceptions.h>
+
+#include <liblangutil/Token.h>
+
+using namespace dev;
+using namespace langutil;
+using namespace yul;
+using namespace std;
+
+
+shared_ptr<Object> ObjectParser::parse(shared_ptr<Scanner> const& _scanner, bool _reuseScanner)
+{
+ m_recursionDepth = 0;
+ try
+ {
+ shared_ptr<Object> object;
+ m_scanner = _scanner;
+ if (currentToken() == Token::LBrace)
+ {
+ // Special case: Code-only form.
+ object = make_shared<Object>();
+ object->name = YulString{"object"};
+ object->code = parseBlock();
+ if (!object->code)
+ return nullptr;
+ }
+ else
+ object = parseObject();
+ if (object && !_reuseScanner)
+ expectToken(Token::EOS);
+ return object;
+ }
+ catch (FatalError const&)
+ {
+ if (m_errorReporter.errors().empty())
+ throw; // Something is weird here, rather throw again.
+ }
+ return nullptr;
+}
+
+shared_ptr<Object> ObjectParser::parseObject(Object* _containingObject)
+{
+ RecursionGuard guard(*this);
+
+ if (currentToken() != Token::Identifier || currentLiteral() != "object")
+ fatalParserError("Expected keyword \"object\".");
+ advance();
+
+ shared_ptr<Object> ret = make_shared<Object>();
+ ret->name = parseUniqueName(_containingObject);
+
+ expectToken(Token::LBrace);
+
+ ret->code = parseCode();
+
+ while (currentToken() != Token::RBrace)
+ {
+ if (currentToken() == Token::Identifier && currentLiteral() == "object")
+ parseObject(ret.get());
+ else if (currentToken() == Token::Identifier && currentLiteral() == "data")
+ parseData(*ret);
+ else
+ fatalParserError("Expected keyword \"data\" or \"object\" or \"}\".");
+ }
+ if (_containingObject)
+ addNamedSubObject(*_containingObject, ret->name, ret);
+
+ expectToken(Token::RBrace);
+
+ return ret;
+}
+
+shared_ptr<Block> ObjectParser::parseCode()
+{
+ if (currentToken() != Token::Identifier || currentLiteral() != "code")
+ fatalParserError("Expected keyword \"code\".");
+ advance();
+
+ return parseBlock();
+}
+
+shared_ptr<Block> ObjectParser::parseBlock()
+{
+ Parser parser(m_errorReporter, m_flavour);
+ shared_ptr<Block> block = parser.parse(m_scanner, true);
+ yulAssert(block || m_errorReporter.hasErrors(), "Invalid block but no error!");
+ return block;
+}
+
+void ObjectParser::parseData(Object& _containingObject)
+{
+ solAssert(
+ currentToken() == Token::Identifier && currentLiteral() == "data",
+ "parseData called on wrong input."
+ );
+ advance();
+
+ YulString name = parseUniqueName(&_containingObject);
+
+ expectToken(Token::StringLiteral, false);
+ addNamedSubObject(_containingObject, name, make_shared<Data>(name, asBytes(currentLiteral())));
+ advance();
+}
+
+YulString ObjectParser::parseUniqueName(Object const* _containingObject)
+{
+ expectToken(Token::StringLiteral, false);
+ YulString name{currentLiteral()};
+ if (name.empty())
+ parserError("Object name cannot be empty.");
+ else if (_containingObject && _containingObject->name == name)
+ parserError("Object name cannot be the same as the name of the containing object.");
+ else if (_containingObject && _containingObject->subIndexByName.count(name))
+ parserError("Object name \"" + name.str() + "\" already exists inside the containing object.");
+ advance();
+ return name;
+}
+
+void ObjectParser::addNamedSubObject(Object& _container, YulString _name, shared_ptr<ObjectNode> _subObject)
+{
+ _container.subIndexByName[_name] = _container.subObjects.size();
+ _container.subObjects.emplace_back(std::move(_subObject));
+}
diff --git a/libyul/ObjectParser.h b/libyul/ObjectParser.h
new file mode 100644
index 00000000..1d88a119
--- /dev/null
+++ b/libyul/ObjectParser.h
@@ -0,0 +1,72 @@
+/*
+ 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/>.
+*/
+/**
+ * Parser for Yul code and data object container.
+ */
+
+#pragma once
+
+#include <libyul/YulString.h>
+#include <libyul/Object.h>
+
+#include <liblangutil/ErrorReporter.h>
+#include <liblangutil/ParserBase.h>
+
+#include <libdevcore/Common.h>
+
+#include <memory>
+
+namespace langutil
+{
+class Scanner;
+}
+
+namespace yul
+{
+
+/**
+ * Yul object parser. Invokes the inline assembly parser.
+ */
+class ObjectParser: public langutil::ParserBase
+{
+public:
+ explicit ObjectParser(
+ langutil::ErrorReporter& _errorReporter,
+ yul::AsmFlavour _flavour = yul::AsmFlavour::Loose
+ ):
+ ParserBase(_errorReporter), m_flavour(_flavour) {}
+
+ /// Parses a Yul object.
+ /// Falls back to code-only parsing if the source starts with `{`.
+ /// @param _reuseScanner if true, do check for end of input after the last `}`.
+ /// @returns an empty shared pointer on error.
+ std::shared_ptr<Object> parse(std::shared_ptr<langutil::Scanner> const& _scanner, bool _reuseScanner);
+
+private:
+ std::shared_ptr<Object> parseObject(Object* _containingObject = nullptr);
+ std::shared_ptr<Block> parseCode();
+ std::shared_ptr<Block> parseBlock();
+ void parseData(Object& _containingObject);
+
+ /// Tries to parse a name that is non-empty and unique inside the containing object.
+ YulString parseUniqueName(Object const* _containingObject);
+ void addNamedSubObject(Object& _container, YulString _name, std::shared_ptr<ObjectNode> _subObject);
+
+ yul::AsmFlavour m_flavour;
+};
+
+}
diff --git a/libyul/YulString.h b/libyul/YulString.h
index ad900a70..2179c23b 100644
--- a/libyul/YulString.h
+++ b/libyul/YulString.h
@@ -27,8 +27,6 @@
#include <vector>
#include <string>
-namespace dev
-{
namespace yul
{
@@ -130,4 +128,3 @@ private:
};
}
-}
diff --git a/libyul/backends/evm/AbstractAssembly.h b/libyul/backends/evm/AbstractAssembly.h
index d75058f7..97b1d305 100644
--- a/libyul/backends/evm/AbstractAssembly.h
+++ b/libyul/backends/evm/AbstractAssembly.h
@@ -22,24 +22,28 @@
#pragma once
+#include <libdevcore/Common.h>
#include <libdevcore/CommonData.h>
#include <functional>
-namespace dev
+namespace langutil
{
struct SourceLocation;
+}
+
+namespace dev
+{
namespace solidity
{
enum class Instruction: uint8_t;
-namespace assembly
-{
-struct Instruction;
-struct Identifier;
}
}
+
namespace yul
{
+struct Instruction;
+struct Identifier;
///
/// Assembly class that abstracts both the libevmasm assembly and the new Yul assembly.
@@ -52,14 +56,14 @@ public:
virtual ~AbstractAssembly() {}
/// Set a new source location valid starting from the next instruction.
- virtual void setSourceLocation(SourceLocation const& _location) = 0;
+ virtual void setSourceLocation(langutil::SourceLocation const& _location) = 0;
/// Retrieve the current height of the stack. This does not have to be zero
/// at the beginning.
virtual int stackHeight() const = 0;
/// Append an EVM instruction.
- virtual void appendInstruction(solidity::Instruction _instruction) = 0;
+ virtual void appendInstruction(dev::solidity::Instruction _instruction) = 0;
/// Append a constant.
- virtual void appendConstant(u256 const& _constant) = 0;
+ virtual void appendConstant(dev::u256 const& _constant) = 0;
/// Append a label.
virtual void appendLabel(LabelID _labelId) = 0;
/// Append a label reference.
@@ -102,18 +106,15 @@ enum class IdentifierContext { LValue, RValue };
/// to inline assembly (not used in standalone assembly mode).
struct ExternalIdentifierAccess
{
- using Resolver = std::function<size_t(solidity::assembly::Identifier const&, IdentifierContext, bool /*_crossesFunctionBoundary*/)>;
+ using Resolver = std::function<size_t(Identifier const&, IdentifierContext, bool /*_crossesFunctionBoundary*/)>;
/// Resolve an external reference given by the identifier in the given context.
/// @returns the size of the value (number of stack slots) or size_t(-1) if not found.
Resolver resolve;
- using CodeGenerator = std::function<void(solidity::assembly::Identifier const&, IdentifierContext, yul::AbstractAssembly&)>;
+ using CodeGenerator = std::function<void(Identifier const&, IdentifierContext, yul::AbstractAssembly&)>;
/// Generate code for retrieving the value (rvalue context) or storing the value (lvalue context)
/// of an identifier. The code should be appended to the assembly. In rvalue context, the value is supposed
/// to be put onto the stack, in lvalue context, the value is assumed to be at the top of the stack.
CodeGenerator generateCode;
};
-
-
-}
}
diff --git a/libyul/backends/evm/EVMAssembly.cpp b/libyul/backends/evm/EVMAssembly.cpp
index b37a3231..99506317 100644
--- a/libyul/backends/evm/EVMAssembly.cpp
+++ b/libyul/backends/evm/EVMAssembly.cpp
@@ -22,11 +22,12 @@
#include <libevmasm/Instruction.h>
-#include <libsolidity/interface/Exceptions.h>
+#include <liblangutil/Exceptions.h>
using namespace std;
using namespace dev;
-using namespace dev::yul;
+using namespace langutil;
+using namespace yul;
namespace
{
diff --git a/libyul/backends/evm/EVMAssembly.h b/libyul/backends/evm/EVMAssembly.h
index 556ed5a5..d0a437cc 100644
--- a/libyul/backends/evm/EVMAssembly.h
+++ b/libyul/backends/evm/EVMAssembly.h
@@ -26,8 +26,11 @@
#include <map>
-namespace dev
+namespace langutil
{
+struct SourceLocation;
+}
+
namespace yul
{
@@ -38,55 +41,55 @@ public:
virtual ~EVMAssembly() {}
/// Set a new source location valid starting from the next instruction.
- virtual void setSourceLocation(SourceLocation const& _location) override;
+ void setSourceLocation(langutil::SourceLocation const& _location) override;
/// Retrieve the current height of the stack. This does not have to be zero
/// at the beginning.
- virtual int stackHeight() const override { return m_stackHeight; }
+ int stackHeight() const override { return m_stackHeight; }
/// Append an EVM instruction.
- virtual void appendInstruction(solidity::Instruction _instruction) override;
+ void appendInstruction(dev::solidity::Instruction _instruction) override;
/// Append a constant.
- virtual void appendConstant(u256 const& _constant) override;
+ void appendConstant(dev::u256 const& _constant) override;
/// Append a label.
- virtual void appendLabel(LabelID _labelId) override;
+ void appendLabel(LabelID _labelId) override;
/// Append a label reference.
- virtual void appendLabelReference(LabelID _labelId) override;
+ void appendLabelReference(LabelID _labelId) override;
/// Generate a new unique label.
- virtual LabelID newLabelId() override;
+ LabelID newLabelId() override;
/// Returns a label identified by the given name. Creates it if it does not yet exist.
- virtual LabelID namedLabel(std::string const& _name) override;
+ LabelID namedLabel(std::string const& _name) override;
/// Append a reference to a to-be-linked symbol.
/// Currently, we assume that the value is always a 20 byte number.
- virtual void appendLinkerSymbol(std::string const& _name) override;
+ void appendLinkerSymbol(std::string const& _name) override;
/// Append a jump instruction.
/// @param _stackDiffAfter the stack adjustment after this instruction.
- virtual void appendJump(int _stackDiffAfter) override;
+ void appendJump(int _stackDiffAfter) override;
/// Append a jump-to-immediate operation.
- virtual void appendJumpTo(LabelID _labelId, int _stackDiffAfter) override;
+ void appendJumpTo(LabelID _labelId, int _stackDiffAfter) override;
/// Append a jump-to-if-immediate operation.
- virtual void appendJumpToIf(LabelID _labelId) override;
+ void appendJumpToIf(LabelID _labelId) override;
/// Start a subroutine.
- virtual void appendBeginsub(LabelID _labelId, int _arguments) override;
+ void appendBeginsub(LabelID _labelId, int _arguments) override;
/// Call a subroutine.
- virtual void appendJumpsub(LabelID _labelId, int _arguments, int _returns) override;
+ void appendJumpsub(LabelID _labelId, int _arguments, int _returns) override;
/// Return from a subroutine.
- virtual void appendReturnsub(int _returns, int _stackDiffAfter) override;
+ void appendReturnsub(int _returns, int _stackDiffAfter) override;
/// Append the assembled size as a constant.
- virtual void appendAssemblySize() override;
+ void appendAssemblySize() override;
/// Resolves references inside the bytecode and returns the linker object.
- eth::LinkerObject finalize();
+ dev::eth::LinkerObject finalize();
private:
void setLabelToCurrentPosition(AbstractAssembly::LabelID _labelId);
void appendLabelReferenceInternal(AbstractAssembly::LabelID _labelId);
- void updateReference(size_t pos, size_t size, u256 value);
+ void updateReference(size_t pos, size_t size, dev::u256 value);
bool m_evm15 = false; ///< if true, switch to evm1.5 mode
LabelID m_nextLabelId = 0;
int m_stackHeight = 0;
- bytes m_bytecode;
+ dev::bytes m_bytecode;
std::map<std::string, LabelID> m_namedLabels;
std::map<LabelID, size_t> m_labelPositions;
std::map<size_t, LabelID> m_labelReferences;
@@ -94,4 +97,3 @@ private:
};
}
-}
diff --git a/libyul/backends/evm/EVMCodeTransform.cpp b/libyul/backends/evm/EVMCodeTransform.cpp
index 650a8c0a..12abd754 100644
--- a/libyul/backends/evm/EVMCodeTransform.cpp
+++ b/libyul/backends/evm/EVMCodeTransform.cpp
@@ -20,20 +20,18 @@
#include <libyul/backends/evm/EVMCodeTransform.h>
-#include <libsolidity/inlineasm/AsmAnalysisInfo.h>
-#include <libsolidity/inlineasm/AsmData.h>
+#include <libyul/AsmAnalysisInfo.h>
+#include <libyul/AsmData.h>
-#include <libsolidity/interface/Exceptions.h>
+#include <liblangutil/Exceptions.h>
#include <boost/range/adaptor/reversed.hpp>
using namespace std;
using namespace dev;
-using namespace dev::yul;
+using namespace yul;
using namespace dev::solidity;
-using Scope = dev::solidity::assembly::Scope;
-
void CodeTransform::operator()(VariableDeclaration const& _varDecl)
{
solAssert(m_scope, "");
@@ -147,7 +145,7 @@ void CodeTransform::operator()(FunctionalInstruction const& _instruction)
solAssert(_instruction.arguments.size() == 1, "");
}
m_assembly.setSourceLocation(_instruction.location);
- auto label = labelFromIdentifier(boost::get<assembly::Identifier>(_instruction.arguments.at(0)));
+ auto label = labelFromIdentifier(boost::get<Identifier>(_instruction.arguments.at(0)));
if (isJumpI)
m_assembly.appendJumpToIf(label);
else
@@ -163,7 +161,7 @@ void CodeTransform::operator()(FunctionalInstruction const& _instruction)
checkStackHeight(&_instruction);
}
-void CodeTransform::operator()(assembly::Identifier const& _identifier)
+void CodeTransform::operator()(Identifier const& _identifier)
{
m_assembly.setSourceLocation(_identifier.location);
// First search internals, then externals.
@@ -197,12 +195,12 @@ void CodeTransform::operator()(assembly::Identifier const& _identifier)
checkStackHeight(&_identifier);
}
-void CodeTransform::operator()(assembly::Literal const& _literal)
+void CodeTransform::operator()(Literal const& _literal)
{
m_assembly.setSourceLocation(_literal.location);
- if (_literal.kind == assembly::LiteralKind::Number)
+ if (_literal.kind == LiteralKind::Number)
m_assembly.appendConstant(u256(_literal.value.str()));
- else if (_literal.kind == assembly::LiteralKind::Boolean)
+ else if (_literal.kind == LiteralKind::Boolean)
{
if (_literal.value.str() == "true")
m_assembly.appendConstant(u256(1));
@@ -217,7 +215,7 @@ void CodeTransform::operator()(assembly::Literal const& _literal)
checkStackHeight(&_literal);
}
-void CodeTransform::operator()(assembly::Instruction const& _instruction)
+void CodeTransform::operator()(yul::Instruction const& _instruction)
{
solAssert(!m_evm15 || _instruction.instruction != solidity::Instruction::JUMP, "Bare JUMP instruction used for EVM1.5");
solAssert(!m_evm15 || _instruction.instruction != solidity::Instruction::JUMPI, "Bare JUMPI instruction used for EVM1.5");
@@ -522,7 +520,7 @@ void CodeTransform::generateAssignment(Identifier const& _variableName)
}
}
-int CodeTransform::variableHeightDiff(solidity::assembly::Scope::Variable const& _var, bool _forSwap) const
+int CodeTransform::variableHeightDiff(Scope::Variable const& _var, bool _forSwap) const
{
solAssert(m_context->variableStackHeights.count(&_var), "");
int heightDiff = m_assembly.stackHeight() - m_context->variableStackHeights[&_var];
diff --git a/libyul/backends/evm/EVMCodeTransform.h b/libyul/backends/evm/EVMCodeTransform.h
index c0de8ad6..d559f85a 100644
--- a/libyul/backends/evm/EVMCodeTransform.h
+++ b/libyul/backends/evm/EVMCodeTransform.h
@@ -20,25 +20,21 @@
#include <libyul/backends/evm/EVMAssembly.h>
-#include <libyul/ASTDataForward.h>
+#include <libyul/AsmDataForward.h>
-#include <libsolidity/inlineasm/AsmScope.h>
+#include <libyul/AsmScope.h>
#include <boost/variant.hpp>
#include <boost/optional.hpp>
-namespace dev
-{
-namespace solidity
+namespace langutil
{
class ErrorReporter;
-namespace assembly
-{
-struct AsmAnalysisInfo;
-}
}
+
namespace yul
{
+struct AsmAnalysisInfo;
class EVMAssembly;
class CodeTransform: public boost::static_visitor<>
@@ -47,8 +43,8 @@ public:
/// Create the code transformer.
/// @param _identifierAccess used to resolve identifiers external to the inline assembly
CodeTransform(
- yul::AbstractAssembly& _assembly,
- solidity::assembly::AsmAnalysisInfo& _analysisInfo,
+ AbstractAssembly& _assembly,
+ AsmAnalysisInfo& _analysisInfo,
bool _yul = false,
bool _evm15 = false,
ExternalIdentifierAccess const& _identifierAccess = ExternalIdentifierAccess(),
@@ -69,15 +65,14 @@ public:
protected:
struct Context
{
- using Scope = solidity::assembly::Scope;
std::map<Scope::Label const*, AbstractAssembly::LabelID> labelIDs;
std::map<Scope::Function const*, AbstractAssembly::LabelID> functionEntryIDs;
std::map<Scope::Variable const*, int> variableStackHeights;
};
CodeTransform(
- yul::AbstractAssembly& _assembly,
- solidity::assembly::AsmAnalysisInfo& _analysisInfo,
+ AbstractAssembly& _assembly,
+ AsmAnalysisInfo& _analysisInfo,
bool _yul,
bool _evm15,
ExternalIdentifierAccess const& _identifierAccess,
@@ -116,8 +111,8 @@ private:
AbstractAssembly::LabelID labelFromIdentifier(Identifier const& _identifier);
/// @returns the label ID corresponding to the given label, allocating a new one if
/// necessary.
- AbstractAssembly::LabelID labelID(solidity::assembly::Scope::Label const& _label);
- AbstractAssembly::LabelID functionEntryID(YulString _name, solidity::assembly::Scope::Function const& _function);
+ AbstractAssembly::LabelID labelID(Scope::Label const& _label);
+ AbstractAssembly::LabelID functionEntryID(YulString _name, Scope::Function const& _function);
/// Generates code for an expression that is supposed to return a single value.
void visitExpression(Expression const& _expression);
@@ -133,15 +128,15 @@ private:
/// Determines the stack height difference to the given variables. Throws
/// if it is not yet in scope or the height difference is too large. Returns
/// the (positive) stack height difference otherwise.
- int variableHeightDiff(solidity::assembly::Scope::Variable const& _var, bool _forSwap) const;
+ int variableHeightDiff(Scope::Variable const& _var, bool _forSwap) const;
void expectDeposit(int _deposit, int _oldHeight) const;
void checkStackHeight(void const* _astElement) const;
- yul::AbstractAssembly& m_assembly;
- solidity::assembly::AsmAnalysisInfo& m_info;
- solidity::assembly::Scope* m_scope = nullptr;
+ AbstractAssembly& m_assembly;
+ AsmAnalysisInfo& m_info;
+ Scope* m_scope = nullptr;
bool m_yul = false;
bool m_evm15 = false;
bool m_useNamedLabelsForFunctions = false;
@@ -155,4 +150,3 @@ private:
};
}
-}
diff --git a/libyul/optimiser/ASTCopier.cpp b/libyul/optimiser/ASTCopier.cpp
index d0c8dd45..f18b0e6b 100644
--- a/libyul/optimiser/ASTCopier.cpp
+++ b/libyul/optimiser/ASTCopier.cpp
@@ -22,13 +22,13 @@
#include <libyul/Exceptions.h>
-#include <libsolidity/inlineasm/AsmData.h>
+#include <libyul/AsmData.h>
#include <libdevcore/Common.h>
using namespace std;
using namespace dev;
-using namespace dev::yul;
+using namespace yul;
Statement ASTCopier::operator()(Instruction const&)
{
diff --git a/libyul/optimiser/ASTCopier.h b/libyul/optimiser/ASTCopier.h
index b6aceee3..4d2f18ae 100644
--- a/libyul/optimiser/ASTCopier.h
+++ b/libyul/optimiser/ASTCopier.h
@@ -20,7 +20,7 @@
#pragma once
-#include <libyul/ASTDataForward.h>
+#include <libyul/AsmDataForward.h>
#include <libyul/YulString.h>
@@ -31,8 +31,6 @@
#include <set>
#include <memory>
-namespace dev
-{
namespace yul
{
@@ -71,21 +69,21 @@ class ASTCopier: public ExpressionCopier, public StatementCopier
{
public:
virtual ~ASTCopier() = default;
- virtual Expression operator()(Literal const& _literal) override;
- virtual Statement operator()(Instruction const& _instruction) override;
- virtual Expression operator()(Identifier const& _identifier) override;
- virtual Expression operator()(FunctionalInstruction const& _instr) override;
- virtual Expression operator()(FunctionCall const&) override;
- virtual Statement operator()(ExpressionStatement const& _statement) override;
- virtual Statement operator()(Label const& _label) override;
- virtual Statement operator()(StackAssignment const& _assignment) override;
- virtual Statement operator()(Assignment const& _assignment) override;
- virtual Statement operator()(VariableDeclaration const& _varDecl) override;
- virtual Statement operator()(If const& _if) override;
- virtual Statement operator()(Switch const& _switch) override;
- virtual Statement operator()(FunctionDefinition const&) override;
- virtual Statement operator()(ForLoop const&) override;
- virtual Statement operator()(Block const& _block) override;
+ Expression operator()(Literal const& _literal) override;
+ Statement operator()(Instruction const& _instruction) override;
+ Expression operator()(Identifier const& _identifier) override;
+ Expression operator()(FunctionalInstruction const& _instr) override;
+ Expression operator()(FunctionCall const&) override;
+ Statement operator()(ExpressionStatement const& _statement) override;
+ Statement operator()(Label const& _label) override;
+ Statement operator()(StackAssignment const& _assignment) override;
+ Statement operator()(Assignment const& _assignment) override;
+ Statement operator()(VariableDeclaration const& _varDecl) override;
+ Statement operator()(If const& _if) override;
+ Statement operator()(Switch const& _switch) override;
+ Statement operator()(FunctionDefinition const&) override;
+ Statement operator()(ForLoop const&) override;
+ Statement operator()(Block const& _block) override;
virtual Expression translate(Expression const& _expression);
virtual Statement translate(Statement const& _statement);
@@ -123,4 +121,3 @@ std::vector<T> ASTCopier::translateVector(std::vector<T> const& _values)
}
-}
diff --git a/libyul/optimiser/ASTWalker.cpp b/libyul/optimiser/ASTWalker.cpp
index e29dda6b..0d568007 100644
--- a/libyul/optimiser/ASTWalker.cpp
+++ b/libyul/optimiser/ASTWalker.cpp
@@ -20,13 +20,13 @@
#include <libyul/optimiser/ASTWalker.h>
-#include <libsolidity/inlineasm/AsmData.h>
+#include <libyul/AsmData.h>
#include <boost/range/adaptor/reversed.hpp>
using namespace std;
using namespace dev;
-using namespace dev::yul;
+using namespace yul;
using namespace dev::solidity;
diff --git a/libyul/optimiser/ASTWalker.h b/libyul/optimiser/ASTWalker.h
index 38cb85ea..b59b405e 100644
--- a/libyul/optimiser/ASTWalker.h
+++ b/libyul/optimiser/ASTWalker.h
@@ -20,7 +20,7 @@
#pragma once
-#include <libyul/ASTDataForward.h>
+#include <libyul/AsmDataForward.h>
#include <libyul/Exceptions.h>
#include <libyul/YulString.h>
@@ -32,8 +32,6 @@
#include <set>
#include <map>
-namespace dev
-{
namespace yul
{
@@ -120,4 +118,3 @@ protected:
};
}
-}
diff --git a/libyul/optimiser/BlockFlattener.cpp b/libyul/optimiser/BlockFlattener.cpp
index 04f3ad7f..e6f08524 100644
--- a/libyul/optimiser/BlockFlattener.cpp
+++ b/libyul/optimiser/BlockFlattener.cpp
@@ -15,14 +15,14 @@
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
#include <libyul/optimiser/BlockFlattener.h>
-#include <libsolidity/inlineasm/AsmData.h>
+#include <libyul/AsmData.h>
#include <libdevcore/Visitor.h>
#include <libdevcore/CommonData.h>
#include <functional>
using namespace std;
using namespace dev;
-using namespace dev::yul;
+using namespace yul;
void BlockFlattener::operator()(Block& _block)
{
diff --git a/libyul/optimiser/BlockFlattener.h b/libyul/optimiser/BlockFlattener.h
index 88c49dda..b732422d 100644
--- a/libyul/optimiser/BlockFlattener.h
+++ b/libyul/optimiser/BlockFlattener.h
@@ -18,8 +18,6 @@
#include <libyul/optimiser/ASTWalker.h>
-namespace dev
-{
namespace yul
{
@@ -31,4 +29,3 @@ public:
};
}
-}
diff --git a/libyul/optimiser/CommonSubexpressionEliminator.cpp b/libyul/optimiser/CommonSubexpressionEliminator.cpp
index 64605362..9b851333 100644
--- a/libyul/optimiser/CommonSubexpressionEliminator.cpp
+++ b/libyul/optimiser/CommonSubexpressionEliminator.cpp
@@ -24,12 +24,11 @@
#include <libyul/optimiser/Metrics.h>
#include <libyul/optimiser/SyntacticalEquality.h>
#include <libyul/Exceptions.h>
-
-#include <libsolidity/inlineasm/AsmData.h>
+#include <libyul/AsmData.h>
using namespace std;
using namespace dev;
-using namespace dev::yul;
+using namespace yul;
void CommonSubexpressionEliminator::visit(Expression& _e)
{
diff --git a/libyul/optimiser/CommonSubexpressionEliminator.h b/libyul/optimiser/CommonSubexpressionEliminator.h
index f8aa0ee1..ac1ebe3a 100644
--- a/libyul/optimiser/CommonSubexpressionEliminator.h
+++ b/libyul/optimiser/CommonSubexpressionEliminator.h
@@ -23,8 +23,6 @@
#include <libyul/optimiser/DataFlowAnalyzer.h>
-namespace dev
-{
namespace yul
{
@@ -38,8 +36,7 @@ class CommonSubexpressionEliminator: public DataFlowAnalyzer
{
protected:
using ASTModifier::visit;
- virtual void visit(Expression& _e) override;
+ void visit(Expression& _e) override;
};
}
-}
diff --git a/libyul/optimiser/DataFlowAnalyzer.cpp b/libyul/optimiser/DataFlowAnalyzer.cpp
index 134777d0..64c67b38 100644
--- a/libyul/optimiser/DataFlowAnalyzer.cpp
+++ b/libyul/optimiser/DataFlowAnalyzer.cpp
@@ -25,8 +25,7 @@
#include <libyul/optimiser/NameCollector.h>
#include <libyul/optimiser/Semantics.h>
#include <libyul/Exceptions.h>
-
-#include <libsolidity/inlineasm/AsmData.h>
+#include <libyul/AsmData.h>
#include <libdevcore/CommonData.h>
@@ -34,7 +33,7 @@
using namespace std;
using namespace dev;
-using namespace dev::yul;
+using namespace yul;
void DataFlowAnalyzer::operator()(Assignment& _assignment)
{
diff --git a/libyul/optimiser/DataFlowAnalyzer.h b/libyul/optimiser/DataFlowAnalyzer.h
index a0c21eee..cd134d48 100644
--- a/libyul/optimiser/DataFlowAnalyzer.h
+++ b/libyul/optimiser/DataFlowAnalyzer.h
@@ -23,14 +23,11 @@
#pragma once
#include <libyul/optimiser/ASTWalker.h>
-
#include <libyul/YulString.h>
#include <map>
#include <set>
-namespace dev
-{
namespace yul
{
@@ -45,13 +42,13 @@ class DataFlowAnalyzer: public ASTModifier
{
public:
using ASTModifier::operator();
- virtual void operator()(Assignment& _assignment) override;
- virtual void operator()(VariableDeclaration& _varDecl) override;
- virtual void operator()(If& _if) override;
- virtual void operator()(Switch& _switch) override;
- virtual void operator()(FunctionDefinition&) override;
- virtual void operator()(ForLoop&) override;
- virtual void operator()(Block& _block) override;
+ void operator()(Assignment& _assignment) override;
+ void operator()(VariableDeclaration& _varDecl) override;
+ void operator()(If& _if) override;
+ void operator()(Switch& _switch) override;
+ void operator()(FunctionDefinition&) override;
+ void operator()(ForLoop&) override;
+ void operator()(Block& _block) override;
protected:
/// Registers the assignment.
@@ -88,4 +85,3 @@ protected:
};
}
-}
diff --git a/libyul/optimiser/Disambiguator.cpp b/libyul/optimiser/Disambiguator.cpp
index 4303f412..fda5895b 100644
--- a/libyul/optimiser/Disambiguator.cpp
+++ b/libyul/optimiser/Disambiguator.cpp
@@ -21,17 +21,14 @@
#include <libyul/optimiser/Disambiguator.h>
#include <libyul/Exceptions.h>
-
-#include <libsolidity/inlineasm/AsmData.h>
-#include <libsolidity/inlineasm/AsmScope.h>
+#include <libyul/AsmData.h>
+#include <libyul/AsmScope.h>
using namespace std;
using namespace dev;
-using namespace dev::yul;
+using namespace yul;
using namespace dev::solidity;
-using Scope = dev::solidity::assembly::Scope;
-
YulString Disambiguator::translateIdentifier(YulString _originalName)
{
if ((m_externallyUsedIdentifiers.count(_originalName)))
diff --git a/libyul/optimiser/Disambiguator.h b/libyul/optimiser/Disambiguator.h
index bfb65682..bb83417b 100644
--- a/libyul/optimiser/Disambiguator.h
+++ b/libyul/optimiser/Disambiguator.h
@@ -20,20 +20,16 @@
#pragma once
-#include <libyul/ASTDataForward.h>
-
+#include <libyul/AsmDataForward.h>
+#include <libyul/AsmAnalysisInfo.h>
#include <libyul/optimiser/ASTCopier.h>
#include <libyul/optimiser/NameDispenser.h>
-#include <libsolidity/inlineasm/AsmAnalysisInfo.h>
-
#include <boost/variant.hpp>
#include <boost/optional.hpp>
#include <set>
-namespace dev
-{
namespace yul
{
@@ -44,7 +40,7 @@ class Disambiguator: public ASTCopier
{
public:
explicit Disambiguator(
- solidity::assembly::AsmAnalysisInfo const& _analysisInfo,
+ AsmAnalysisInfo const& _analysisInfo,
std::set<YulString> const& _externallyUsedIdentifiers = {}
):
m_info(_analysisInfo), m_externallyUsedIdentifiers(_externallyUsedIdentifiers), m_nameDispenser(m_externallyUsedIdentifiers)
@@ -52,22 +48,21 @@ public:
}
protected:
- virtual void enterScope(Block const& _block) override;
- virtual void leaveScope(Block const& _block) override;
- virtual void enterFunction(FunctionDefinition const& _function) override;
- virtual void leaveFunction(FunctionDefinition const& _function) override;
- virtual YulString translateIdentifier(YulString _name) override;
+ void enterScope(Block const& _block) override;
+ void leaveScope(Block const& _block) override;
+ void enterFunction(FunctionDefinition const& _function) override;
+ void leaveFunction(FunctionDefinition const& _function) override;
+ YulString translateIdentifier(YulString _name) override;
- void enterScopeInternal(solidity::assembly::Scope& _scope);
- void leaveScopeInternal(solidity::assembly::Scope& _scope);
+ void enterScopeInternal(Scope& _scope);
+ void leaveScopeInternal(Scope& _scope);
- solidity::assembly::AsmAnalysisInfo const& m_info;
+ AsmAnalysisInfo const& m_info;
std::set<YulString> const& m_externallyUsedIdentifiers;
- std::vector<solidity::assembly::Scope*> m_scopes;
+ std::vector<Scope*> m_scopes;
std::map<void const*, YulString> m_translations;
NameDispenser m_nameDispenser;
};
}
-}
diff --git a/libyul/optimiser/ExpressionInliner.cpp b/libyul/optimiser/ExpressionInliner.cpp
index 07e88191..27d43ac0 100644
--- a/libyul/optimiser/ExpressionInliner.cpp
+++ b/libyul/optimiser/ExpressionInliner.cpp
@@ -23,14 +23,13 @@
#include <libyul/optimiser/InlinableExpressionFunctionFinder.h>
#include <libyul/optimiser/Substitution.h>
#include <libyul/optimiser/Semantics.h>
-
-#include <libsolidity/inlineasm/AsmData.h>
+#include <libyul/AsmData.h>
#include <boost/algorithm/cxx11/all_of.hpp>
using namespace std;
using namespace dev;
-using namespace dev::yul;
+using namespace yul;
using namespace dev::solidity;
void ExpressionInliner::run()
diff --git a/libyul/optimiser/ExpressionInliner.h b/libyul/optimiser/ExpressionInliner.h
index d903664f..14e80c0a 100644
--- a/libyul/optimiser/ExpressionInliner.h
+++ b/libyul/optimiser/ExpressionInliner.h
@@ -20,16 +20,13 @@
#pragma once
#include <libyul/optimiser/ASTWalker.h>
-
-#include <libyul/ASTDataForward.h>
+#include <libyul/AsmDataForward.h>
#include <boost/variant.hpp>
#include <boost/optional.hpp>
#include <set>
-namespace dev
-{
namespace yul
{
@@ -54,9 +51,9 @@ public:
void run();
using ASTModifier::operator();
- virtual void operator()(FunctionDefinition& _fun) override;
+ void operator()(FunctionDefinition& _fun) override;
- virtual void visit(Expression& _expression) override;
+ void visit(Expression& _expression) override;
private:
std::map<YulString, FunctionDefinition const*> m_inlinableFunctions;
@@ -69,4 +66,3 @@ private:
}
-}
diff --git a/libyul/optimiser/ExpressionJoiner.cpp b/libyul/optimiser/ExpressionJoiner.cpp
index 7e57a629..de2b5d53 100644
--- a/libyul/optimiser/ExpressionJoiner.cpp
+++ b/libyul/optimiser/ExpressionJoiner.cpp
@@ -24,8 +24,7 @@
#include <libyul/optimiser/NameCollector.h>
#include <libyul/optimiser/Utilities.h>
#include <libyul/Exceptions.h>
-
-#include <libsolidity/inlineasm/AsmData.h>
+#include <libyul/AsmData.h>
#include <libdevcore/CommonData.h>
@@ -33,7 +32,7 @@
using namespace std;
using namespace dev;
-using namespace dev::yul;
+using namespace yul;
using namespace dev::solidity;
void ExpressionJoiner::operator()(FunctionalInstruction& _instruction)
diff --git a/libyul/optimiser/ExpressionJoiner.h b/libyul/optimiser/ExpressionJoiner.h
index 0cc61981..643d62b0 100644
--- a/libyul/optimiser/ExpressionJoiner.h
+++ b/libyul/optimiser/ExpressionJoiner.h
@@ -20,14 +20,11 @@
*/
#pragma once
-#include <libyul/ASTDataForward.h>
-
+#include <libyul/AsmDataForward.h>
#include <libyul/optimiser/ASTWalker.h>
#include <map>
-namespace dev
-{
namespace yul
{
@@ -99,4 +96,3 @@ private:
};
}
-}
diff --git a/libyul/optimiser/ExpressionSimplifier.cpp b/libyul/optimiser/ExpressionSimplifier.cpp
index 64e9d7e7..cda44e8e 100644
--- a/libyul/optimiser/ExpressionSimplifier.cpp
+++ b/libyul/optimiser/ExpressionSimplifier.cpp
@@ -23,14 +23,13 @@
#include <libyul/optimiser/SimplificationRules.h>
#include <libyul/optimiser/Semantics.h>
#include <libyul/optimiser/SSAValueTracker.h>
-
-#include <libsolidity/inlineasm/AsmData.h>
+#include <libyul/AsmData.h>
#include <libdevcore/CommonData.h>
using namespace std;
using namespace dev;
-using namespace dev::yul;
+using namespace yul;
using namespace dev::solidity;
diff --git a/libyul/optimiser/ExpressionSimplifier.h b/libyul/optimiser/ExpressionSimplifier.h
index 5965a1bb..fe3507f8 100644
--- a/libyul/optimiser/ExpressionSimplifier.h
+++ b/libyul/optimiser/ExpressionSimplifier.h
@@ -20,12 +20,10 @@
#pragma once
-#include <libyul/ASTDataForward.h>
+#include <libyul/AsmDataForward.h>
#include <libyul/optimiser/ASTWalker.h>
-namespace dev
-{
namespace yul
{
@@ -52,4 +50,3 @@ private:
};
}
-}
diff --git a/libyul/optimiser/ExpressionSplitter.cpp b/libyul/optimiser/ExpressionSplitter.cpp
index a4b7a909..a3b2dc11 100644
--- a/libyul/optimiser/ExpressionSplitter.cpp
+++ b/libyul/optimiser/ExpressionSplitter.cpp
@@ -23,7 +23,7 @@
#include <libyul/optimiser/ASTWalker.h>
-#include <libsolidity/inlineasm/AsmData.h>
+#include <libyul/AsmData.h>
#include <libdevcore/CommonData.h>
@@ -31,7 +31,8 @@
using namespace std;
using namespace dev;
-using namespace dev::yul;
+using namespace langutil;
+using namespace yul;
using namespace dev::solidity;
void ExpressionSplitter::operator()(FunctionalInstruction& _instruction)
diff --git a/libyul/optimiser/ExpressionSplitter.h b/libyul/optimiser/ExpressionSplitter.h
index 339acbf0..d4d2b3f6 100644
--- a/libyul/optimiser/ExpressionSplitter.h
+++ b/libyul/optimiser/ExpressionSplitter.h
@@ -20,15 +20,13 @@
*/
#pragma once
-#include <libyul/ASTDataForward.h>
+#include <libyul/AsmDataForward.h>
#include <libyul/optimiser/ASTWalker.h>
#include <libyul/optimiser/NameDispenser.h>
#include <vector>
-namespace dev
-{
namespace yul
{
@@ -63,12 +61,12 @@ public:
m_nameDispenser(_nameDispenser)
{ }
- virtual void operator()(FunctionalInstruction&) override;
- virtual void operator()(FunctionCall&) override;
- virtual void operator()(If&) override;
- virtual void operator()(Switch&) override;
- virtual void operator()(ForLoop&) override;
- virtual void operator()(Block& _block) override;
+ void operator()(FunctionalInstruction&) override;
+ void operator()(FunctionCall&) override;
+ void operator()(If&) override;
+ void operator()(Switch&) override;
+ void operator()(ForLoop&) override;
+ void operator()(Block& _block) override;
private:
/// Replaces the expression by a variable if it is a function call or functional
@@ -83,4 +81,3 @@ private:
};
}
-}
diff --git a/libyul/optimiser/ForLoopInitRewriter.cpp b/libyul/optimiser/ForLoopInitRewriter.cpp
new file mode 100644
index 00000000..80d39248
--- /dev/null
+++ b/libyul/optimiser/ForLoopInitRewriter.cpp
@@ -0,0 +1,43 @@
+/*
+ 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/>.
+*/
+#include <libyul/optimiser/ForLoopInitRewriter.h>
+#include <libyul/AsmData.h>
+#include <libdevcore/CommonData.h>
+#include <functional>
+
+using namespace std;
+using namespace dev;
+using namespace yul;
+
+void ForLoopInitRewriter::operator()(Block& _block)
+{
+ iterateReplacing(
+ _block.statements,
+ [](Statement& _stmt) -> boost::optional<vector<Statement>>
+ {
+ if (_stmt.type() == typeid(ForLoop))
+ {
+ auto& forLoop = boost::get<ForLoop>(_stmt);
+ vector<Statement> rewrite;
+ swap(rewrite, forLoop.pre.statements);
+ rewrite.emplace_back(move(forLoop));
+ return rewrite;
+ }
+ return {};
+ }
+ );
+}
diff --git a/libyul/optimiser/ForLoopInitRewriter.h b/libyul/optimiser/ForLoopInitRewriter.h
new file mode 100644
index 00000000..e925c6c2
--- /dev/null
+++ b/libyul/optimiser/ForLoopInitRewriter.h
@@ -0,0 +1,36 @@
+/*
+ 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/>.
+*/
+#pragma once
+
+#include <libyul/optimiser/ASTWalker.h>
+
+namespace yul
+{
+
+/**
+ * Rewrites ForLoop by moving the pre statement block in front of the ForLoop.
+ * Requirements:
+ * - The Disambiguator must be run upfront.
+ */
+class ForLoopInitRewriter: public ASTModifier
+{
+public:
+ using ASTModifier::operator();
+ void operator()(Block& _block) override;
+};
+
+}
diff --git a/libyul/optimiser/FullInliner.cpp b/libyul/optimiser/FullInliner.cpp
index c9057cf3..8ae26fbb 100644
--- a/libyul/optimiser/FullInliner.cpp
+++ b/libyul/optimiser/FullInliner.cpp
@@ -27,8 +27,7 @@
#include <libyul/optimiser/Metrics.h>
#include <libyul/optimiser/SSAValueTracker.h>
#include <libyul/Exceptions.h>
-
-#include <libsolidity/inlineasm/AsmData.h>
+#include <libyul/AsmData.h>
#include <libdevcore/CommonData.h>
#include <libdevcore/Visitor.h>
@@ -37,7 +36,7 @@
using namespace std;
using namespace dev;
-using namespace dev::yul;
+using namespace yul;
using namespace dev::solidity;
FullInliner::FullInliner(Block& _ast, NameDispenser& _dispenser):
diff --git a/libyul/optimiser/FullInliner.h b/libyul/optimiser/FullInliner.h
index 66ce8e2f..a8fe76c6 100644
--- a/libyul/optimiser/FullInliner.h
+++ b/libyul/optimiser/FullInliner.h
@@ -19,22 +19,20 @@
*/
#pragma once
-#include <libyul/ASTDataForward.h>
+#include <libyul/AsmDataForward.h>
#include <libyul/optimiser/ASTCopier.h>
#include <libyul/optimiser/ASTWalker.h>
#include <libyul/optimiser/NameDispenser.h>
#include <libyul/Exceptions.h>
-#include <libevmasm/SourceLocation.h>
+#include <liblangutil/SourceLocation.h>
#include <boost/variant.hpp>
#include <boost/optional.hpp>
#include <set>
-namespace dev
-{
namespace yul
{
@@ -110,7 +108,7 @@ public:
m_nameDispenser(_nameDispenser)
{ }
- virtual void operator()(Block& _block) override;
+ void operator()(Block& _block) override;
private:
boost::optional<std::vector<Statement>> tryInlineStatement(Statement& _statement);
@@ -141,10 +139,10 @@ public:
using ASTCopier::operator ();
- virtual Statement operator()(VariableDeclaration const& _varDecl) override;
- virtual Statement operator()(FunctionDefinition const& _funDef) override;
+ Statement operator()(VariableDeclaration const& _varDecl) override;
+ Statement operator()(FunctionDefinition const& _funDef) override;
- virtual YulString translateIdentifier(YulString _name) override;
+ YulString translateIdentifier(YulString _name) override;
NameDispenser& m_nameDispenser;
YulString m_varNamePrefix;
@@ -153,4 +151,3 @@ public:
}
-}
diff --git a/libyul/optimiser/FunctionGrouper.cpp b/libyul/optimiser/FunctionGrouper.cpp
index 3d2e5322..02ce22cd 100644
--- a/libyul/optimiser/FunctionGrouper.cpp
+++ b/libyul/optimiser/FunctionGrouper.cpp
@@ -21,13 +21,13 @@
#include <libyul/optimiser/FunctionGrouper.h>
-#include <libsolidity/inlineasm/AsmData.h>
+#include <libyul/AsmData.h>
#include <boost/range/algorithm_ext/erase.hpp>
using namespace std;
using namespace dev;
-using namespace dev::yul;
+using namespace yul;
using namespace dev::solidity;
diff --git a/libyul/optimiser/FunctionGrouper.h b/libyul/optimiser/FunctionGrouper.h
index 63cfbfb1..3b3f48a7 100644
--- a/libyul/optimiser/FunctionGrouper.h
+++ b/libyul/optimiser/FunctionGrouper.h
@@ -21,10 +21,8 @@
#pragma once
-#include <libyul/ASTDataForward.h>
+#include <libyul/AsmDataForward.h>
-namespace dev
-{
namespace yul
{
@@ -43,4 +41,3 @@ public:
};
}
-}
diff --git a/libyul/optimiser/FunctionHoister.cpp b/libyul/optimiser/FunctionHoister.cpp
index c196dead..bd1c781b 100644
--- a/libyul/optimiser/FunctionHoister.cpp
+++ b/libyul/optimiser/FunctionHoister.cpp
@@ -22,14 +22,13 @@
#include <libyul/optimiser/FunctionHoister.h>
#include <libyul/optimiser/Utilities.h>
-
-#include <libsolidity/inlineasm/AsmData.h>
+#include <libyul/AsmData.h>
#include <libdevcore/CommonData.h>
using namespace std;
using namespace dev;
-using namespace dev::yul;
+using namespace yul;
using namespace dev::solidity;
void FunctionHoister::operator()(Block& _block)
diff --git a/libyul/optimiser/FunctionHoister.h b/libyul/optimiser/FunctionHoister.h
index 823b9e2b..31092069 100644
--- a/libyul/optimiser/FunctionHoister.h
+++ b/libyul/optimiser/FunctionHoister.h
@@ -21,12 +21,9 @@
#pragma once
-#include <libyul/ASTDataForward.h>
-
+#include <libyul/AsmDataForward.h>
#include <libyul/optimiser/ASTWalker.h>
-namespace dev
-{
namespace yul
{
@@ -49,4 +46,3 @@ private:
};
}
-}
diff --git a/libyul/optimiser/InlinableExpressionFunctionFinder.cpp b/libyul/optimiser/InlinableExpressionFunctionFinder.cpp
index deaaee97..662cdf25 100644
--- a/libyul/optimiser/InlinableExpressionFunctionFinder.cpp
+++ b/libyul/optimiser/InlinableExpressionFunctionFinder.cpp
@@ -21,12 +21,11 @@
#include <libyul/optimiser/InlinableExpressionFunctionFinder.h>
#include <libyul/optimiser/Utilities.h>
-
-#include <libsolidity/inlineasm/AsmData.h>
+#include <libyul/AsmData.h>
using namespace std;
using namespace dev;
-using namespace dev::yul;
+using namespace yul;
void InlinableExpressionFunctionFinder::operator()(Identifier const& _identifier)
{
diff --git a/libyul/optimiser/InlinableExpressionFunctionFinder.h b/libyul/optimiser/InlinableExpressionFunctionFinder.h
index baf4bbfc..afde8a2a 100644
--- a/libyul/optimiser/InlinableExpressionFunctionFinder.h
+++ b/libyul/optimiser/InlinableExpressionFunctionFinder.h
@@ -20,13 +20,11 @@
#pragma once
-#include <libyul/ASTDataForward.h>
+#include <libyul/AsmDataForward.h>
#include <libyul/optimiser/ASTWalker.h>
#include <set>
-namespace dev
-{
namespace yul
{
@@ -49,9 +47,9 @@ public:
}
using ASTWalker::operator();
- virtual void operator()(Identifier const& _identifier) override;
- virtual void operator()(FunctionCall const& _funCall) override;
- virtual void operator()(FunctionDefinition const& _function) override;
+ void operator()(Identifier const& _identifier) override;
+ void operator()(FunctionCall const& _funCall) override;
+ void operator()(FunctionDefinition const& _function) override;
private:
void checkAllowed(YulString _name)
@@ -66,4 +64,3 @@ private:
};
}
-}
diff --git a/libyul/optimiser/MainFunction.cpp b/libyul/optimiser/MainFunction.cpp
index f3306598..63eea2db 100644
--- a/libyul/optimiser/MainFunction.cpp
+++ b/libyul/optimiser/MainFunction.cpp
@@ -24,13 +24,13 @@
#include <libyul/optimiser/NameCollector.h>
#include <libyul/Exceptions.h>
-#include <libsolidity/inlineasm/AsmData.h>
+#include <libyul/AsmData.h>
#include <libdevcore/CommonData.h>
using namespace std;
using namespace dev;
-using namespace dev::yul;
+using namespace yul;
using namespace dev::solidity;
void MainFunction::operator()(Block& _block)
diff --git a/libyul/optimiser/MainFunction.h b/libyul/optimiser/MainFunction.h
index 4a73283a..96acc0ac 100644
--- a/libyul/optimiser/MainFunction.h
+++ b/libyul/optimiser/MainFunction.h
@@ -21,10 +21,8 @@
#pragma once
-#include <libyul/ASTDataForward.h>
+#include <libyul/AsmDataForward.h>
-namespace dev
-{
namespace yul
{
@@ -38,4 +36,3 @@ public:
};
}
-}
diff --git a/libyul/optimiser/Metrics.cpp b/libyul/optimiser/Metrics.cpp
index 066c6b58..a5557fb3 100644
--- a/libyul/optimiser/Metrics.cpp
+++ b/libyul/optimiser/Metrics.cpp
@@ -20,10 +20,10 @@
#include <libyul/optimiser/Metrics.h>
-#include <libsolidity/inlineasm/AsmData.h>
+#include <libyul/AsmData.h>
using namespace dev;
-using namespace dev::yul;
+using namespace yul;
size_t CodeSize::codeSize(Statement const& _statement)
{
diff --git a/libyul/optimiser/Metrics.h b/libyul/optimiser/Metrics.h
index 47c7ec79..ca244600 100644
--- a/libyul/optimiser/Metrics.h
+++ b/libyul/optimiser/Metrics.h
@@ -22,8 +22,6 @@
#include <libyul/optimiser/ASTWalker.h>
-namespace dev
-{
namespace yul
{
@@ -41,12 +39,11 @@ public:
static size_t codeSize(Block const& _block);
private:
- virtual void visit(Statement const& _statement) override;
- virtual void visit(Expression const& _expression) override;
+ void visit(Statement const& _statement) override;
+ void visit(Expression const& _expression) override;
private:
size_t m_size = 0;
};
}
-}
diff --git a/libyul/optimiser/NameCollector.cpp b/libyul/optimiser/NameCollector.cpp
index 36f55b99..f9079827 100644
--- a/libyul/optimiser/NameCollector.cpp
+++ b/libyul/optimiser/NameCollector.cpp
@@ -20,11 +20,11 @@
#include <libyul/optimiser/NameCollector.h>
-#include <libsolidity/inlineasm/AsmData.h>
+#include <libyul/AsmData.h>
using namespace std;
using namespace dev;
-using namespace dev::yul;
+using namespace yul;
void NameCollector::operator()(VariableDeclaration const& _varDecl)
{
diff --git a/libyul/optimiser/NameCollector.h b/libyul/optimiser/NameCollector.h
index b76eec30..c177a399 100644
--- a/libyul/optimiser/NameCollector.h
+++ b/libyul/optimiser/NameCollector.h
@@ -25,8 +25,6 @@
#include <map>
#include <set>
-namespace dev
-{
namespace yul
{
@@ -42,8 +40,8 @@ public:
}
using ASTWalker::operator ();
- virtual void operator()(VariableDeclaration const& _varDecl) override;
- virtual void operator()(FunctionDefinition const& _funDef) override;
+ void operator()(VariableDeclaration const& _varDecl) override;
+ void operator()(FunctionDefinition const& _funDef) override;
std::set<YulString> names() const { return m_names; }
private:
@@ -75,7 +73,7 @@ class Assignments: public ASTWalker
{
public:
using ASTWalker::operator ();
- virtual void operator()(Assignment const& _assignment) override;
+ void operator()(Assignment const& _assignment) override;
std::set<YulString> const& names() const { return m_names; }
private:
@@ -83,4 +81,3 @@ private:
};
}
-}
diff --git a/libyul/optimiser/NameDispenser.cpp b/libyul/optimiser/NameDispenser.cpp
index 3c870fa5..e7cdc60f 100644
--- a/libyul/optimiser/NameDispenser.cpp
+++ b/libyul/optimiser/NameDispenser.cpp
@@ -21,12 +21,11 @@
#include <libyul/optimiser/NameDispenser.h>
#include <libyul/optimiser/NameCollector.h>
-
-#include <libsolidity/inlineasm/AsmData.h>
+#include <libyul/AsmData.h>
using namespace std;
using namespace dev;
-using namespace dev::yul;
+using namespace yul;
NameDispenser::NameDispenser(Block const& _ast):
NameDispenser(NameCollector(_ast).names())
diff --git a/libyul/optimiser/NameDispenser.h b/libyul/optimiser/NameDispenser.h
index 7311440b..664a5265 100644
--- a/libyul/optimiser/NameDispenser.h
+++ b/libyul/optimiser/NameDispenser.h
@@ -19,14 +19,12 @@
*/
#pragma once
-#include <libyul/ASTDataForward.h>
+#include <libyul/AsmDataForward.h>
#include <libyul/YulString.h>
#include <set>
-namespace dev
-{
namespace yul
{
@@ -58,4 +56,3 @@ private:
};
}
-}
diff --git a/libyul/optimiser/RedundantAssignEliminator.cpp b/libyul/optimiser/RedundantAssignEliminator.cpp
index b7217074..7b18e8ca 100644
--- a/libyul/optimiser/RedundantAssignEliminator.cpp
+++ b/libyul/optimiser/RedundantAssignEliminator.cpp
@@ -22,8 +22,7 @@
#include <libyul/optimiser/RedundantAssignEliminator.h>
#include <libyul/optimiser/Semantics.h>
-
-#include <libsolidity/inlineasm/AsmData.h>
+#include <libyul/AsmData.h>
#include <libdevcore/CommonData.h>
@@ -31,7 +30,7 @@
using namespace std;
using namespace dev;
-using namespace dev::yul;
+using namespace yul;
using namespace dev::solidity;
void RedundantAssignEliminator::operator()(Identifier const& _identifier)
diff --git a/libyul/optimiser/RedundantAssignEliminator.h b/libyul/optimiser/RedundantAssignEliminator.h
index 76106aae..54d65823 100644
--- a/libyul/optimiser/RedundantAssignEliminator.h
+++ b/libyul/optimiser/RedundantAssignEliminator.h
@@ -21,14 +21,11 @@
#pragma once
-#include <libyul/ASTDataForward.h>
-
+#include <libyul/AsmDataForward.h>
#include <libyul/optimiser/ASTWalker.h>
#include <map>
-namespace dev
-{
namespace yul
{
@@ -190,4 +187,3 @@ private:
};
}
-}
diff --git a/libyul/optimiser/Rematerialiser.cpp b/libyul/optimiser/Rematerialiser.cpp
index 38d50ef4..4180bfc3 100644
--- a/libyul/optimiser/Rematerialiser.cpp
+++ b/libyul/optimiser/Rematerialiser.cpp
@@ -23,12 +23,11 @@
#include <libyul/optimiser/Metrics.h>
#include <libyul/optimiser/ASTCopier.h>
#include <libyul/Exceptions.h>
-
-#include <libsolidity/inlineasm/AsmData.h>
+#include <libyul/AsmData.h>
using namespace std;
using namespace dev;
-using namespace dev::yul;
+using namespace yul;
void Rematerialiser::visit(Expression& _e)
{
diff --git a/libyul/optimiser/Rematerialiser.h b/libyul/optimiser/Rematerialiser.h
index f82465eb..b3841519 100644
--- a/libyul/optimiser/Rematerialiser.h
+++ b/libyul/optimiser/Rematerialiser.h
@@ -22,8 +22,6 @@
#include <libyul/optimiser/DataFlowAnalyzer.h>
-namespace dev
-{
namespace yul
{
@@ -36,9 +34,8 @@ class Rematerialiser: public DataFlowAnalyzer
{
protected:
using ASTModifier::visit;
- virtual void visit(Expression& _e) override;
+ void visit(Expression& _e) override;
};
}
-}
diff --git a/libyul/optimiser/SSATransform.cpp b/libyul/optimiser/SSATransform.cpp
index f209ee7b..928c0859 100644
--- a/libyul/optimiser/SSATransform.cpp
+++ b/libyul/optimiser/SSATransform.cpp
@@ -23,15 +23,15 @@
#include <libyul/optimiser/NameCollector.h>
#include <libyul/optimiser/NameDispenser.h>
-
-#include <libsolidity/inlineasm/AsmData.h>
+#include <libyul/AsmData.h>
#include <libdevcore/CommonData.h>
using namespace std;
using namespace dev;
-using namespace dev::yul;
+using namespace langutil;
+using namespace yul;
using namespace dev::solidity;
void SSATransform::operator()(Identifier& _identifier)
diff --git a/libyul/optimiser/SSATransform.h b/libyul/optimiser/SSATransform.h
index bb642549..4cb62f23 100644
--- a/libyul/optimiser/SSATransform.h
+++ b/libyul/optimiser/SSATransform.h
@@ -20,14 +20,11 @@
*/
#pragma once
-#include <libyul/ASTDataForward.h>
-
+#include <libyul/AsmDataForward.h>
#include <libyul/optimiser/ASTWalker.h>
#include <vector>
-namespace dev
-{
namespace yul
{
@@ -95,4 +92,3 @@ private:
};
}
-}
diff --git a/libyul/optimiser/SSAValueTracker.cpp b/libyul/optimiser/SSAValueTracker.cpp
index 491117da..35b29b04 100644
--- a/libyul/optimiser/SSAValueTracker.cpp
+++ b/libyul/optimiser/SSAValueTracker.cpp
@@ -21,11 +21,11 @@
#include <libyul/optimiser/SSAValueTracker.h>
-#include <libsolidity/inlineasm/AsmData.h>
+#include <libyul/AsmData.h>
using namespace std;
using namespace dev;
-using namespace dev::yul;
+using namespace yul;
void SSAValueTracker::operator()(Assignment const& _assignment)
{
diff --git a/libyul/optimiser/SSAValueTracker.h b/libyul/optimiser/SSAValueTracker.h
index d1539c86..e182e013 100644
--- a/libyul/optimiser/SSAValueTracker.h
+++ b/libyul/optimiser/SSAValueTracker.h
@@ -26,8 +26,6 @@
#include <map>
#include <set>
-namespace dev
-{
namespace yul
{
@@ -41,8 +39,8 @@ class SSAValueTracker: public ASTWalker
{
public:
using ASTWalker::operator();
- virtual void operator()(VariableDeclaration const& _varDecl) override;
- virtual void operator()(Assignment const& _assignment) override;
+ void operator()(VariableDeclaration const& _varDecl) override;
+ void operator()(Assignment const& _assignment) override;
std::map<YulString, Expression const*> const& values() const { return m_values; }
Expression const* value(YulString _name) const { return m_values.at(_name); }
@@ -54,4 +52,3 @@ private:
};
}
-}
diff --git a/libyul/optimiser/Semantics.cpp b/libyul/optimiser/Semantics.cpp
index 3c49016e..91bb2709 100644
--- a/libyul/optimiser/Semantics.cpp
+++ b/libyul/optimiser/Semantics.cpp
@@ -21,8 +21,7 @@
#include <libyul/optimiser/Semantics.h>
#include <libyul/Exceptions.h>
-
-#include <libsolidity/inlineasm/AsmData.h>
+#include <libyul/AsmData.h>
#include <libevmasm/SemanticInformation.h>
@@ -30,7 +29,7 @@
using namespace std;
using namespace dev;
-using namespace dev::yul;
+using namespace yul;
MovableChecker::MovableChecker(Expression const& _expression)
{
diff --git a/libyul/optimiser/Semantics.h b/libyul/optimiser/Semantics.h
index 620a91cb..70c50806 100644
--- a/libyul/optimiser/Semantics.h
+++ b/libyul/optimiser/Semantics.h
@@ -24,8 +24,6 @@
#include <set>
-namespace dev
-{
namespace yul
{
@@ -38,12 +36,12 @@ public:
MovableChecker() = default;
explicit MovableChecker(Expression const& _expression);
- virtual void operator()(Identifier const& _identifier) override;
- virtual void operator()(FunctionalInstruction const& _functionalInstruction) override;
- virtual void operator()(FunctionCall const& _functionCall) override;
+ void operator()(Identifier const& _identifier) override;
+ void operator()(FunctionalInstruction const& _functionalInstruction) override;
+ void operator()(FunctionCall const& _functionCall) override;
/// Disallow visiting anything apart from Expressions (this throws).
- virtual void visit(Statement const&) override;
+ void visit(Statement const&) override;
using ASTWalker::visit;
bool movable() const { return m_movable; }
@@ -57,4 +55,3 @@ private:
};
}
-}
diff --git a/libyul/optimiser/SimplificationRules.cpp b/libyul/optimiser/SimplificationRules.cpp
index 5721042f..b3190fef 100644
--- a/libyul/optimiser/SimplificationRules.cpp
+++ b/libyul/optimiser/SimplificationRules.cpp
@@ -24,14 +24,14 @@
#include <libyul/optimiser/ASTCopier.h>
#include <libyul/optimiser/Semantics.h>
#include <libyul/optimiser/SyntacticalEquality.h>
-
-#include <libsolidity/inlineasm/AsmData.h>
+#include <libyul/AsmData.h>
#include <libevmasm/RuleList.h>
using namespace std;
using namespace dev;
-using namespace dev::yul;
+using namespace langutil;
+using namespace yul;
SimplificationRule<Pattern> const* SimplificationRules::findFirstMatch(
@@ -123,7 +123,7 @@ bool Pattern::matches(Expression const& _expr, map<YulString, Expression const*>
if (expr->type() != typeid(Literal))
return false;
Literal const& literal = boost::get<Literal>(*expr);
- if (literal.kind != assembly::LiteralKind::Number)
+ if (literal.kind != LiteralKind::Number)
return false;
if (m_data && *m_data != u256(literal.value.str()))
return false;
@@ -193,7 +193,7 @@ Expression Pattern::toExpression(SourceLocation const& _location) const
if (m_kind == PatternKind::Constant)
{
assertThrow(m_data, OptimizerException, "No match group and no constant value given.");
- return Literal{_location, assembly::LiteralKind::Number, YulString{formatNumber(*m_data)}, {}};
+ return Literal{_location, LiteralKind::Number, YulString{formatNumber(*m_data)}, {}};
}
else if (m_kind == PatternKind::Operation)
{
@@ -208,7 +208,7 @@ Expression Pattern::toExpression(SourceLocation const& _location) const
u256 Pattern::d() const
{
Literal const& literal = boost::get<Literal>(matchGroupValue());
- assertThrow(literal.kind == assembly::LiteralKind::Number, OptimizerException, "");
+ assertThrow(literal.kind == LiteralKind::Number, OptimizerException, "");
assertThrow(isValidDecimal(literal.value.str()) || isValidHex(literal.value.str()), OptimizerException, "");
return u256(literal.value.str());
}
diff --git a/libyul/optimiser/SimplificationRules.h b/libyul/optimiser/SimplificationRules.h
index b608ca91..16aaba04 100644
--- a/libyul/optimiser/SimplificationRules.h
+++ b/libyul/optimiser/SimplificationRules.h
@@ -23,17 +23,14 @@
#include <libevmasm/ExpressionClasses.h>
#include <libevmasm/SimplificationRule.h>
-#include <libyul/ASTDataForward.h>
-
-#include <libsolidity/inlineasm/AsmData.h>
+#include <libyul/AsmDataForward.h>
+#include <libyul/AsmData.h>
#include <boost/noncopyable.hpp>
#include <functional>
#include <vector>
-namespace dev
-{
namespace yul
{
@@ -86,11 +83,11 @@ public:
/// Matches any expression.
Pattern(PatternKind _kind = PatternKind::Any): m_kind(_kind) {}
// Matches a specific constant value.
- Pattern(unsigned _value): Pattern(u256(_value)) {}
+ Pattern(unsigned _value): Pattern(dev::u256(_value)) {}
// Matches a specific constant value.
- Pattern(u256 const& _value): m_kind(PatternKind::Constant), m_data(std::make_shared<u256>(_value)) {}
+ Pattern(dev::u256 const& _value): m_kind(PatternKind::Constant), m_data(std::make_shared<dev::u256>(_value)) {}
// Matches a given instruction with given arguments
- Pattern(solidity::Instruction _instruction, std::vector<Pattern> const& _arguments = {});
+ Pattern(dev::solidity::Instruction _instruction, std::vector<Pattern> const& _arguments = {});
/// Sets this pattern to be part of the match group with the identifier @a _group.
/// Inside one rule, all patterns in the same match group have to match expressions from the
/// same expression equivalence class.
@@ -101,24 +98,23 @@ public:
std::vector<Pattern> arguments() const { return m_arguments; }
/// @returns the data of the matched expression if this pattern is part of a match group.
- u256 d() const;
+ dev::u256 d() const;
- solidity::Instruction instruction() const;
+ dev::solidity::Instruction instruction() const;
/// Turns this pattern into an actual expression. Should only be called
/// for patterns resulting from an action, i.e. with match groups assigned.
- Expression toExpression(SourceLocation const& _location) const;
+ Expression toExpression(langutil::SourceLocation const& _location) const;
private:
Expression const& matchGroupValue() const;
PatternKind m_kind = PatternKind::Any;
- solidity::Instruction m_instruction; ///< Only valid if m_kind is Operation
- std::shared_ptr<u256> m_data; ///< Only valid if m_kind is Constant
+ dev::solidity::Instruction m_instruction; ///< Only valid if m_kind is Operation
+ std::shared_ptr<dev::u256> m_data; ///< Only valid if m_kind is Constant
std::vector<Pattern> m_arguments;
unsigned m_matchGroup = 0;
std::map<unsigned, Expression const*>* m_matchGroups = nullptr;
};
}
-}
diff --git a/libyul/optimiser/Substitution.cpp b/libyul/optimiser/Substitution.cpp
index 9b3d4c03..bc9efe96 100644
--- a/libyul/optimiser/Substitution.cpp
+++ b/libyul/optimiser/Substitution.cpp
@@ -20,11 +20,11 @@
#include <libyul/optimiser/Substitution.h>
-#include <libsolidity/inlineasm/AsmData.h>
+#include <libyul/AsmData.h>
using namespace std;
using namespace dev;
-using namespace dev::yul;
+using namespace yul;
Expression Substitution::translate(Expression const& _expression)
{
diff --git a/libyul/optimiser/Substitution.h b/libyul/optimiser/Substitution.h
index 59ee4620..41f73b92 100644
--- a/libyul/optimiser/Substitution.h
+++ b/libyul/optimiser/Substitution.h
@@ -21,13 +21,10 @@
#pragma once
#include <libyul/optimiser/ASTCopier.h>
-
#include <libyul/YulString.h>
#include <map>
-namespace dev
-{
namespace yul
{
@@ -40,11 +37,10 @@ public:
Substitution(std::map<YulString, Expression const*> const& _substitutions):
m_substitutions(_substitutions)
{}
- virtual Expression translate(Expression const& _expression) override;
+ Expression translate(Expression const& _expression) override;
private:
std::map<YulString, Expression const*> const& m_substitutions;
};
}
-}
diff --git a/libyul/optimiser/Suite.cpp b/libyul/optimiser/Suite.cpp
index 7d52a5a8..36f0e1eb 100644
--- a/libyul/optimiser/Suite.cpp
+++ b/libyul/optimiser/Suite.cpp
@@ -27,6 +27,7 @@
#include <libyul/optimiser/ExpressionJoiner.h>
#include <libyul/optimiser/ExpressionInliner.h>
#include <libyul/optimiser/FullInliner.h>
+#include <libyul/optimiser/ForLoopInitRewriter.h>
#include <libyul/optimiser/Rematerialiser.h>
#include <libyul/optimiser/UnusedPruner.h>
#include <libyul/optimiser/ExpressionSimplifier.h>
@@ -34,21 +35,19 @@
#include <libyul/optimiser/SSATransform.h>
#include <libyul/optimiser/RedundantAssignEliminator.h>
#include <libyul/optimiser/VarDeclPropagator.h>
-
-#include <libsolidity/inlineasm/AsmAnalysisInfo.h>
-#include <libsolidity/inlineasm/AsmData.h>
-
-#include <libsolidity/inlineasm/AsmPrinter.h>
+#include <libyul/AsmAnalysisInfo.h>
+#include <libyul/AsmData.h>
+#include <libyul/AsmPrinter.h>
#include <libdevcore/CommonData.h>
using namespace std;
using namespace dev;
-using namespace dev::yul;
+using namespace yul;
void OptimiserSuite::run(
Block& _ast,
- solidity::assembly::AsmAnalysisInfo const& _analysisInfo,
+ AsmAnalysisInfo const& _analysisInfo,
set<YulString> const& _externallyUsedIdentifiers
)
{
@@ -58,6 +57,7 @@ void OptimiserSuite::run(
(FunctionHoister{})(ast);
(FunctionGrouper{})(ast);
+ (ForLoopInitRewriter{})(ast);
NameDispenser dispenser{ast};
diff --git a/libyul/optimiser/Suite.h b/libyul/optimiser/Suite.h
index 5b564c56..795326b4 100644
--- a/libyul/optimiser/Suite.h
+++ b/libyul/optimiser/Suite.h
@@ -20,23 +20,16 @@
#pragma once
-#include <libyul/ASTDataForward.h>
+#include <libyul/AsmDataForward.h>
#include <libyul/YulString.h>
#include <set>
-namespace dev
-{
-namespace solidity
-{
-namespace assembly
-{
-struct AsmAnalysisInfo;
-}
-}
namespace yul
{
+struct AsmAnalysisInfo;
+
/**
* Optimiser suite that combines all steps and also provides the settings for the heuristics
*/
@@ -45,11 +38,10 @@ class OptimiserSuite
public:
static void run(
Block& _ast,
- solidity::assembly::AsmAnalysisInfo const& _analysisInfo,
+ AsmAnalysisInfo const& _analysisInfo,
std::set<YulString> const& _externallyUsedIdentifiers = {}
);
};
}
-}
diff --git a/libyul/optimiser/SyntacticalEquality.cpp b/libyul/optimiser/SyntacticalEquality.cpp
index 66912383..99ce06e5 100644
--- a/libyul/optimiser/SyntacticalEquality.cpp
+++ b/libyul/optimiser/SyntacticalEquality.cpp
@@ -21,14 +21,13 @@
#include <libyul/optimiser/SyntacticalEquality.h>
#include <libyul/Exceptions.h>
-
-#include <libsolidity/inlineasm/AsmData.h>
+#include <libyul/AsmData.h>
#include <libdevcore/CommonData.h>
using namespace std;
using namespace dev;
-using namespace dev::yul;
+using namespace yul;
bool SyntacticalEqualityChecker::equal(Expression const& _e1, Expression const& _e2)
{
diff --git a/libyul/optimiser/SyntacticalEquality.h b/libyul/optimiser/SyntacticalEquality.h
index e9fbebe0..63c51b4f 100644
--- a/libyul/optimiser/SyntacticalEquality.h
+++ b/libyul/optimiser/SyntacticalEquality.h
@@ -20,12 +20,10 @@
#pragma once
-#include <libyul/ASTDataForward.h>
+#include <libyul/AsmDataForward.h>
#include <vector>
-namespace dev
-{
namespace yul
{
@@ -47,4 +45,3 @@ protected:
};
}
-}
diff --git a/libyul/optimiser/UnusedPruner.cpp b/libyul/optimiser/UnusedPruner.cpp
index 71e86798..31aead82 100644
--- a/libyul/optimiser/UnusedPruner.cpp
+++ b/libyul/optimiser/UnusedPruner.cpp
@@ -24,14 +24,13 @@
#include <libyul/optimiser/Semantics.h>
#include <libyul/optimiser/Utilities.h>
#include <libyul/Exceptions.h>
-
-#include <libsolidity/inlineasm/AsmData.h>
+#include <libyul/AsmData.h>
#include <boost/algorithm/cxx11/none_of.hpp>
using namespace std;
using namespace dev;
-using namespace dev::yul;
+using namespace yul;
UnusedPruner::UnusedPruner(Block& _ast, set<YulString> const& _externallyUsedFunctions)
{
diff --git a/libyul/optimiser/UnusedPruner.h b/libyul/optimiser/UnusedPruner.h
index b5aea3dd..64e02b35 100644
--- a/libyul/optimiser/UnusedPruner.h
+++ b/libyul/optimiser/UnusedPruner.h
@@ -26,8 +26,6 @@
#include <map>
#include <set>
-namespace dev
-{
namespace yul
{
@@ -45,7 +43,7 @@ public:
explicit UnusedPruner(Block& _ast, std::set<YulString> const& _externallyUsedFunctions = {});
using ASTModifier::operator();
- virtual void operator()(Block& _block) override;
+ void operator()(Block& _block) override;
// @returns true iff the code changed in the previous run.
bool shouldRunAgain() const { return m_shouldRunAgain; }
@@ -62,4 +60,3 @@ private:
};
}
-}
diff --git a/libyul/optimiser/Utilities.cpp b/libyul/optimiser/Utilities.cpp
index df01ed39..b8cdd339 100644
--- a/libyul/optimiser/Utilities.cpp
+++ b/libyul/optimiser/Utilities.cpp
@@ -20,7 +20,7 @@
#include <libyul/optimiser/Utilities.h>
-#include <libsolidity/inlineasm/AsmData.h>
+#include <libyul/AsmData.h>
#include <libdevcore/CommonData.h>
@@ -28,9 +28,9 @@
using namespace std;
using namespace dev;
-using namespace dev::yul;
+using namespace yul;
-void dev::yul::removeEmptyBlocks(Block& _block)
+void yul::removeEmptyBlocks(Block& _block)
{
auto isEmptyBlock = [](Statement const& _st) -> bool {
return _st.type() == typeid(Block) && boost::get<Block>(_st).statements.empty();
diff --git a/libyul/optimiser/Utilities.h b/libyul/optimiser/Utilities.h
index 5b18a27c..c543b119 100644
--- a/libyul/optimiser/Utilities.h
+++ b/libyul/optimiser/Utilities.h
@@ -20,10 +20,8 @@
#pragma once
-#include <libyul/ASTDataForward.h>
+#include <libyul/AsmDataForward.h>
-namespace dev
-{
namespace yul
{
@@ -31,4 +29,3 @@ namespace yul
void removeEmptyBlocks(Block& _block);
}
-}
diff --git a/libyul/optimiser/VarDeclPropagator.cpp b/libyul/optimiser/VarDeclPropagator.cpp
index 537b7020..bf974f44 100644
--- a/libyul/optimiser/VarDeclPropagator.cpp
+++ b/libyul/optimiser/VarDeclPropagator.cpp
@@ -16,7 +16,7 @@
*/
#include <libyul/optimiser/VarDeclPropagator.h>
-#include <libsolidity/inlineasm/AsmData.h>
+#include <libyul/AsmData.h>
#include <libdevcore/CommonData.h>
#include <boost/range/algorithm_ext/erase.hpp>
#include <algorithm>
@@ -24,10 +24,7 @@
using namespace std;
using namespace dev;
-using namespace dev::yul;
-
-using dev::solidity::assembly::TypedName;
-using dev::solidity::assembly::TypedNameList;
+using namespace yul;
void VarDeclPropagator::operator()(Block& _block)
{
diff --git a/libyul/optimiser/VarDeclPropagator.h b/libyul/optimiser/VarDeclPropagator.h
index 4522d23a..1908c214 100644
--- a/libyul/optimiser/VarDeclPropagator.h
+++ b/libyul/optimiser/VarDeclPropagator.h
@@ -17,16 +17,14 @@
#pragma once
-#include <libyul/ASTDataForward.h>
+#include <libyul/AsmDataForward.h>
#include <libyul/optimiser/ASTWalker.h>
#include <libyul/Exceptions.h>
-#include <libsolidity/inlineasm/AsmDataForward.h>
+#include <libyul/AsmDataForward.h>
#include <vector>
#include <set>
#include <map>
-namespace dev
-{
namespace yul
{
@@ -60,4 +58,3 @@ private:
};
}
-}