aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity/inlineasm
diff options
context:
space:
mode:
Diffstat (limited to 'libsolidity/inlineasm')
-rw-r--r--libsolidity/inlineasm/AsmAnalysis.cpp631
-rw-r--r--libsolidity/inlineasm/AsmAnalysis.h128
-rw-r--r--libsolidity/inlineasm/AsmAnalysisInfo.cpp26
-rw-r--r--libsolidity/inlineasm/AsmAnalysisInfo.h52
-rw-r--r--libsolidity/inlineasm/AsmCodeGen.cpp162
-rw-r--r--libsolidity/inlineasm/AsmCodeGen.h56
-rw-r--r--libsolidity/inlineasm/AsmData.h104
-rw-r--r--libsolidity/inlineasm/AsmDataForward.h65
-rw-r--r--libsolidity/inlineasm/AsmParser.cpp617
-rw-r--r--libsolidity/inlineasm/AsmParser.h95
-rw-r--r--libsolidity/inlineasm/AsmPrinter.cpp250
-rw-r--r--libsolidity/inlineasm/AsmPrinter.h68
-rw-r--r--libsolidity/inlineasm/AsmScope.cpp98
-rw-r--r--libsolidity/inlineasm/AsmScope.h105
-rw-r--r--libsolidity/inlineasm/AsmScopeFiller.cpp181
-rw-r--r--libsolidity/inlineasm/AsmScopeFiller.h88
16 files changed, 0 insertions, 2726 deletions
diff --git a/libsolidity/inlineasm/AsmAnalysis.cpp b/libsolidity/inlineasm/AsmAnalysis.cpp
deleted file mode 100644
index fb96f73c..00000000
--- a/libsolidity/inlineasm/AsmAnalysis.cpp
+++ /dev/null
@@ -1,631 +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/>.
-*/
-/**
- * Analyzer part of inline assembly.
- */
-
-#include <libsolidity/inlineasm/AsmAnalysis.h>
-
-#include <libsolidity/inlineasm/AsmData.h>
-#include <libsolidity/inlineasm/AsmScopeFiller.h>
-#include <libsolidity/inlineasm/AsmScope.h>
-#include <libsolidity/inlineasm/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 dev::solidity;
-using namespace dev::solidity::assembly;
-
-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()(assembly::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()(assembly::Literal const& _literal)
-{
- expectValidType(_literal.type.str(), _literal.location);
- ++m_stackHeight;
- if (_literal.kind == assembly::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 == assembly::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 == assembly::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()(assembly::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()(assembly::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()(assembly::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()(assembly::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()(assembly::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()(assembly::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()(assembly::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()(assembly::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(assembly::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/libsolidity/inlineasm/AsmAnalysis.h b/libsolidity/inlineasm/AsmAnalysis.h
deleted file mode 100644
index 194f736e..00000000
--- a/libsolidity/inlineasm/AsmAnalysis.h
+++ /dev/null
@@ -1,128 +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/>.
-*/
-/**
- * Analysis part of inline assembly.
- */
-
-#pragma once
-
-#include <liblangutil/Exceptions.h>
-#include <liblangutil/EVMVersion.h>
-
-#include <libsolidity/inlineasm/AsmScope.h>
-
-#include <libyul/backends/evm/AbstractAssembly.h>
-
-#include <libsolidity/inlineasm/AsmDataForward.h>
-
-#include <boost/variant.hpp>
-#include <boost/optional.hpp>
-
-#include <functional>
-#include <memory>
-
-namespace langutil
-{
-class ErrorReporter;
-struct SourceLocation;
-}
-
-namespace dev
-{
-namespace solidity
-{
-namespace assembly
-{
-
-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,
- EVMVersion _evmVersion,
- boost::optional<langutil::Error::Type> _errorTypeForLoose,
- AsmFlavour _flavour = AsmFlavour::Loose,
- yul::ExternalIdentifierAccess::Resolver const& _resolver = yul::ExternalIdentifierAccess::Resolver()
- ):
- m_resolver(_resolver),
- m_info(_analysisInfo),
- m_errorReporter(_errorReporter),
- m_evmVersion(_evmVersion),
- m_flavour(_flavour),
- m_errorTypeForLoose(_errorTypeForLoose)
- {}
-
- bool analyze(assembly::Block const& _block);
-
- bool operator()(assembly::Instruction const&);
- bool operator()(assembly::Literal const& _literal);
- bool operator()(assembly::Identifier const&);
- bool operator()(assembly::FunctionalInstruction const& _functionalInstruction);
- bool operator()(assembly::Label const& _label);
- bool operator()(assembly::ExpressionStatement const&);
- bool operator()(assembly::StackAssignment const&);
- bool operator()(assembly::Assignment const& _assignment);
- bool operator()(assembly::VariableDeclaration const& _variableDeclaration);
- bool operator()(assembly::FunctionDefinition const& _functionDefinition);
- bool operator()(assembly::FunctionCall const& _functionCall);
- bool operator()(assembly::If const& _if);
- bool operator()(assembly::Switch const& _switch);
- bool operator()(assembly::ForLoop const& _forLoop);
- bool operator()(assembly::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(assembly::Identifier const& _assignment, size_t _valueSize = size_t(-1));
-
- Scope& scope(assembly::Block const* _block);
- void expectValidType(std::string const& type, langutil::SourceLocation const& _location);
- void warnOnInstructions(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;
- EVMVersion m_evmVersion;
- AsmFlavour m_flavour = AsmFlavour::Loose;
- boost::optional<langutil::Error::Type> m_errorTypeForLoose;
-};
-
-}
-}
-}
diff --git a/libsolidity/inlineasm/AsmAnalysisInfo.cpp b/libsolidity/inlineasm/AsmAnalysisInfo.cpp
deleted file mode 100644
index 22318b12..00000000
--- a/libsolidity/inlineasm/AsmAnalysisInfo.cpp
+++ /dev/null
@@ -1,26 +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/>.
-*/
-/**
- * Information generated during analyzer part of inline assembly.
- */
-
-#include <libsolidity/inlineasm/AsmAnalysisInfo.h>
-
-#include <libsolidity/inlineasm/AsmScope.h>
-
-#include <ostream>
-
diff --git a/libsolidity/inlineasm/AsmAnalysisInfo.h b/libsolidity/inlineasm/AsmAnalysisInfo.h
deleted file mode 100644
index bd3b28c4..00000000
--- a/libsolidity/inlineasm/AsmAnalysisInfo.h
+++ /dev/null
@@ -1,52 +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/>.
-*/
-/**
- * Information generated during analyzer part of inline assembly.
- */
-
-#pragma once
-
-#include <libsolidity/inlineasm/AsmDataForward.h>
-
-#include <boost/variant.hpp>
-
-#include <map>
-#include <memory>
-#include <vector>
-
-namespace dev
-{
-namespace solidity
-{
-namespace assembly
-{
-
-struct Scope;
-
-struct AsmAnalysisInfo
-{
- using StackHeightInfo = std::map<void const*, int>;
- using Scopes = std::map<assembly::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<assembly::Block const>> virtualBlocks;
-};
-
-}
-}
-}
diff --git a/libsolidity/inlineasm/AsmCodeGen.cpp b/libsolidity/inlineasm/AsmCodeGen.cpp
deleted file mode 100644
index 2800cc7b..00000000
--- a/libsolidity/inlineasm/AsmCodeGen.cpp
+++ /dev/null
@@ -1,162 +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/>.
-*/
-/**
- * @author Christian <c@ethdev.com>
- * @date 2016
- * Code-generating part of inline assembly.
- */
-
-#include <libsolidity/inlineasm/AsmCodeGen.h>
-
-#include <libsolidity/inlineasm/AsmParser.h>
-#include <libsolidity/inlineasm/AsmData.h>
-#include <libsolidity/inlineasm/AsmScope.h>
-#include <libsolidity/inlineasm/AsmAnalysis.h>
-#include <libsolidity/inlineasm/AsmAnalysisInfo.h>
-
-#include <libevmasm/Assembly.h>
-#include <liblangutil/SourceLocation.h>
-#include <libevmasm/Instruction.h>
-
-#include <libyul/backends/evm/AbstractAssembly.h>
-#include <libyul/backends/evm/EVMCodeTransform.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 dev::solidity;
-using namespace dev::solidity::assembly;
-
-class EthAssemblyAdapter: public yul::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 assembly::CodeGenerator::assemble(
- Block const& _parsedData,
- AsmAnalysisInfo& _analysisInfo,
- eth::Assembly& _assembly,
- yul::ExternalIdentifierAccess const& _identifierAccess,
- bool _useNamedLabelsForFunctions
-)
-{
- EthAssemblyAdapter assemblyAdapter(_assembly);
- yul::CodeTransform(
- assemblyAdapter,
- _analysisInfo,
- false,
- false,
- _identifierAccess,
- _useNamedLabelsForFunctions
- )(_parsedData);
-}
diff --git a/libsolidity/inlineasm/AsmCodeGen.h b/libsolidity/inlineasm/AsmCodeGen.h
deleted file mode 100644
index bbc31397..00000000
--- a/libsolidity/inlineasm/AsmCodeGen.h
+++ /dev/null
@@ -1,56 +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/>.
-*/
-/**
- * @author Christian <c@ethdev.com>
- * @date 2016
- * Code-generating part of inline assembly.
- */
-
-#pragma once
-
-#include <libsolidity/inlineasm/AsmAnalysis.h>
-
-#include <functional>
-
-namespace dev
-{
-namespace eth
-{
-class Assembly;
-}
-namespace solidity
-{
-namespace assembly
-{
-struct Block;
-
-class CodeGenerator
-{
-public:
- /// Performs code generation and appends generated to _assembly.
- static void assemble(
- Block const& _parsedData,
- AsmAnalysisInfo& _analysisInfo,
- eth::Assembly& _assembly,
- yul::ExternalIdentifierAccess const& _identifierAccess = yul::ExternalIdentifierAccess(),
- bool _useNamedLabelsForFunctions = false
- );
-};
-
-}
-}
-}
diff --git a/libsolidity/inlineasm/AsmData.h b/libsolidity/inlineasm/AsmData.h
deleted file mode 100644
index 23a9db75..00000000
--- a/libsolidity/inlineasm/AsmData.h
+++ /dev/null
@@ -1,104 +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/>.
-*/
-/**
- * @author Christian <c@ethdev.com>
- * @date 2016
- * Parsed inline assembly to be used by the AST
- */
-
-#pragma once
-
-#include <libsolidity/inlineasm/AsmDataForward.h>
-
-#include <libevmasm/Instruction.h>
-#include <liblangutil/SourceLocation.h>
-
-#include <libyul/YulString.h>
-
-#include <boost/variant.hpp>
-#include <boost/noncopyable.hpp>
-
-#include <map>
-#include <memory>
-
-namespace dev
-{
-namespace solidity
-{
-namespace assembly
-{
-
-using YulString = dev::yul::YulString;
-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; 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; 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/libsolidity/inlineasm/AsmDataForward.h b/libsolidity/inlineasm/AsmDataForward.h
deleted file mode 100644
index 69cf8f1d..00000000
--- a/libsolidity/inlineasm/AsmDataForward.h
+++ /dev/null
@@ -1,65 +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/>.
-*/
-/**
- * @author Christian <c@ethdev.com>
- * @date 2016
- * Forward declaration of classes for inline assembly / Yul AST
- */
-
-#pragma once
-
-#include <boost/variant.hpp>
-
-namespace dev
-{
-namespace solidity
-{
-namespace assembly
-{
-
-struct Instruction;
-struct Literal;
-struct Label;
-struct StackAssignment;
-struct Identifier;
-struct Assignment;
-struct VariableDeclaration;
-struct FunctionalInstruction;
-struct FunctionDefinition;
-struct FunctionCall;
-struct 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/libsolidity/inlineasm/AsmParser.cpp b/libsolidity/inlineasm/AsmParser.cpp
deleted file mode 100644
index b11f70e0..00000000
--- a/libsolidity/inlineasm/AsmParser.cpp
+++ /dev/null
@@ -1,617 +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/>.
-*/
-/**
- * @author Christian <c@ethdev.com>
- * @date 2016
- * Solidity inline assembly parser.
- */
-
-#include <libsolidity/inlineasm/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 dev::solidity;
-using namespace dev::solidity::assembly;
-
-shared_ptr<assembly::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;
-}
-
-assembly::Block Parser::parseBlock()
-{
- RecursionGuard recursionGuard(*this);
- assembly::Block block = createWithLocation<Block>();
- expectToken(Token::LBrace);
- while (currentToken() != Token::RBrace)
- block.statements.emplace_back(parseStatement());
- block.location.end = endPosition();
- advance();
- return block;
-}
-
-assembly::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:
- {
- assembly::If _if = createWithLocation<assembly::If>();
- m_scanner->next();
- _if.condition = make_shared<Expression>(parseExpression());
- _if.body = parseBlock();
- return _if;
- }
- case Token::Switch:
- {
- assembly::Switch _switch = createWithLocation<assembly::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;
- assembly::StackAssignment assignment = createWithLocation<assembly::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(assembly::Identifier))
- fatalParserError("Label name / variable name must precede \",\" (multiple assignment).");
- assembly::Identifier const& identifier = boost::get<assembly::Identifier>(elementary);
-
- Assignment assignment = createWithLocation<Assignment>(identifier.location);
- assignment.variableNames.emplace_back(identifier);
-
- do
- {
- expectToken(Token::Comma);
- elementary = parseElementaryOperation();
- if (elementary.type() != typeid(assembly::Identifier))
- fatalParserError("Variable name expected in multiple assignment.");
- assignment.variableNames.emplace_back(boost::get<assembly::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(assembly::Identifier))
- fatalParserError("Label name / variable name must precede \":\".");
- assembly::Identifier const& identifier = boost::get<assembly::Identifier>(elementary);
- advance();
- // identifier:=: should be parsed as identifier: =: (i.e. a label),
- // while identifier:= (being followed by a non-colon) as identifier := (assignment).
- if (currentToken() == Token::Assign && peekNextToken() != Token::Colon)
- {
- assembly::Assignment assignment = createWithLocation<assembly::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(assembly::Identifier))
- {
- Expression expr = boost::get<assembly::Identifier>(elementary);
- return ExpressionStatement{locationOf(expr), expr};
- }
- else if (elementary.type() == typeid(assembly::Literal))
- {
- Expression expr = boost::get<assembly::Literal>(elementary);
- return ExpressionStatement{locationOf(expr), expr};
- }
- else
- {
- solAssert(elementary.type() == typeid(assembly::Instruction), "Invalid elementary operation.");
- return boost::get<assembly::Instruction>(elementary);
- }
-}
-
-assembly::Case Parser::parseCase()
-{
- RecursionGuard recursionGuard(*this);
- assembly::Case _case = createWithLocation<assembly::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(assembly::Literal))
- fatalParserError("Literal expected.");
- _case.value = make_shared<Literal>(boost::get<assembly::Literal>(std::move(literal)));
- }
- else
- fatalParserError("Case or default case expected.");
- _case.body = parseBlock();
- _case.location.end = _case.body.location.end;
- return _case;
-}
-
-assembly::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;
-}
-
-assembly::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(assembly::Identifier))
- return boost::get<assembly::Identifier>(operation);
- else
- {
- solAssert(operation.type() == typeid(assembly::Literal), "");
- return boost::get<assembly::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;
-}
-
-assembly::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;
-}
-
-assembly::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;
-}
-
-assembly::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/libsolidity/inlineasm/AsmParser.h b/libsolidity/inlineasm/AsmParser.h
deleted file mode 100644
index 9e13799a..00000000
--- a/libsolidity/inlineasm/AsmParser.h
+++ /dev/null
@@ -1,95 +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/>.
-*/
-/**
- * @author Christian <c@ethdev.com>
- * @date 2016
- * Solidity inline assembly parser.
- */
-
-#pragma once
-
-#include <memory>
-#include <vector>
-#include <libsolidity/inlineasm/AsmData.h>
-#include <liblangutil/SourceLocation.h>
-#include <liblangutil/Scanner.h>
-#include <liblangutil/ParserBase.h>
-
-namespace dev
-{
-namespace solidity
-{
-namespace assembly
-{
-
-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<assembly::Instruction, assembly::Literal, assembly::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.sourceName)
- r.location.sourceName = sourceName();
- return r;
- }
- langutil::SourceLocation location() const { return {position(), endPosition(), sourceName()}; }
-
- Block parseBlock();
- Statement parseStatement();
- Case parseCase();
- ForLoop parseForLoop();
- /// Parses a functional expression that has to push exactly one stack element
- assembly::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();
- assembly::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/libsolidity/inlineasm/AsmPrinter.cpp b/libsolidity/inlineasm/AsmPrinter.cpp
deleted file mode 100644
index 7151fcfa..00000000
--- a/libsolidity/inlineasm/AsmPrinter.cpp
+++ /dev/null
@@ -1,250 +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/>.
-*/
-/**
- * @author Christian <c@ethdev.com>
- * @date 2017
- * Converts a parsed assembly into its textual form.
- */
-
-#include <libsolidity/inlineasm/AsmPrinter.h>
-#include <libsolidity/inlineasm/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 dev::solidity;
-using namespace dev::solidity::assembly;
-
-//@TODO source locations
-
-string AsmPrinter::operator()(assembly::Instruction const& _instruction)
-{
- solAssert(!m_yul, "");
- solAssert(isValidInstruction(_instruction.instruction), "Invalid instruction");
- return boost::to_lower_copy(instructionInfo(_instruction.instruction).name);
-}
-
-string AsmPrinter::operator()(assembly::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()(assembly::Identifier const& _identifier)
-{
- solAssert(!_identifier.name.empty(), "Invalid identifier.");
- return _identifier.name.str();
-}
-
-string AsmPrinter::operator()(assembly::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()(assembly::Label const& _label)
-{
- solAssert(!m_yul, "");
- solAssert(!_label.name.empty(), "Invalid label.");
- return _label.name.str() + ":";
-}
-
-string AsmPrinter::operator()(assembly::StackAssignment const& _assignment)
-{
- solAssert(!m_yul, "");
- solAssert(!_assignment.variableName.name.empty(), "Invalid variable name.");
- return "=: " + (*this)(_assignment.variableName);
-}
-
-string AsmPrinter::operator()(assembly::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()(assembly::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()(assembly::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()(assembly::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()(assembly::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/libsolidity/inlineasm/AsmPrinter.h b/libsolidity/inlineasm/AsmPrinter.h
deleted file mode 100644
index 72048975..00000000
--- a/libsolidity/inlineasm/AsmPrinter.h
+++ /dev/null
@@ -1,68 +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/>.
-*/
-/**
- * @author Christian <c@ethdev.com>
- * @date 2017
- * Converts a parsed assembly into its textual form.
- */
-
-#pragma once
-
-#include <libsolidity/inlineasm/AsmDataForward.h>
-
-#include <libyul/YulString.h>
-
-#include <boost/variant.hpp>
-
-namespace dev
-{
-namespace solidity
-{
-namespace assembly
-{
-
-class AsmPrinter: public boost::static_visitor<std::string>
-{
-public:
- explicit AsmPrinter(bool _yul = false): m_yul(_yul) {}
-
- std::string operator()(assembly::Instruction const& _instruction);
- std::string operator()(assembly::Literal const& _literal);
- std::string operator()(assembly::Identifier const& _identifier);
- std::string operator()(assembly::FunctionalInstruction const& _functionalInstruction);
- std::string operator()(assembly::ExpressionStatement const& _expr);
- std::string operator()(assembly::Label const& _label);
- std::string operator()(assembly::StackAssignment const& _assignment);
- std::string operator()(assembly::Assignment const& _assignment);
- std::string operator()(assembly::VariableDeclaration const& _variableDeclaration);
- std::string operator()(assembly::FunctionDefinition const& _functionDefinition);
- std::string operator()(assembly::FunctionCall const& _functionCall);
- std::string operator()(assembly::If const& _if);
- std::string operator()(assembly::Switch const& _switch);
- std::string operator()(assembly::ForLoop const& _forLoop);
- std::string operator()(assembly::Block const& _block);
-
-private:
- std::string formatTypedName(TypedName _variable) const;
- std::string appendTypeName(yul::YulString _type) const;
-
- bool m_yul = false;
-};
-
-}
-}
-}
diff --git a/libsolidity/inlineasm/AsmScope.cpp b/libsolidity/inlineasm/AsmScope.cpp
deleted file mode 100644
index 10893b96..00000000
--- a/libsolidity/inlineasm/AsmScope.cpp
+++ /dev/null
@@ -1,98 +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/>.
-*/
-/**
- * Scopes for identifiers.
- */
-
-#include <libsolidity/inlineasm/AsmScope.h>
-
-using namespace std;
-using namespace dev;
-using namespace dev::solidity::assembly;
-
-bool Scope::registerLabel(yul::YulString _name)
-{
- if (exists(_name))
- return false;
- identifiers[_name] = Label();
- return true;
-}
-
-bool Scope::registerVariable(yul::YulString _name, YulType const& _type)
-{
- if (exists(_name))
- return false;
- Variable variable;
- variable.type = _type;
- identifiers[_name] = variable;
- return true;
-}
-
-bool Scope::registerFunction(yul::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(yul::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(yul::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/libsolidity/inlineasm/AsmScope.h b/libsolidity/inlineasm/AsmScope.h
deleted file mode 100644
index 12c05716..00000000
--- a/libsolidity/inlineasm/AsmScope.h
+++ /dev/null
@@ -1,105 +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/>.
-*/
-/**
- * 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 dev
-{
-namespace solidity
-{
-namespace assembly
-{
-
-struct Scope
-{
- using YulType = yul::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 = GenericVisitor<Variable const, Label const, Function const>;
- using NonconstVisitor = GenericVisitor<Variable, Label, Function>;
-
- bool registerVariable(yul::YulString _name, YulType const& _type);
- bool registerLabel(yul::YulString _name);
- bool registerFunction(
- yul::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(yul::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(yul::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(yul::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<yul::YulString, Identifier> identifiers;
-};
-
-}
-}
-}
diff --git a/libsolidity/inlineasm/AsmScopeFiller.cpp b/libsolidity/inlineasm/AsmScopeFiller.cpp
deleted file mode 100644
index 09934bd8..00000000
--- a/libsolidity/inlineasm/AsmScopeFiller.cpp
+++ /dev/null
@@ -1,181 +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/>.
-*/
-/**
- * Module responsible for registering identifiers inside their scopes.
- */
-
-#include <libsolidity/inlineasm/AsmScopeFiller.h>
-
-#include <libsolidity/inlineasm/AsmData.h>
-#include <libsolidity/inlineasm/AsmScope.h>
-#include <libsolidity/inlineasm/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 dev::solidity;
-using namespace dev::solidity::assembly;
-
-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()(assembly::VariableDeclaration const& _varDecl)
-{
- for (auto const& variable: _varDecl.variables)
- if (!registerVariable(variable, _varDecl.location, *m_currentScope))
- return false;
- return true;
-}
-
-bool ScopeFiller::operator()(assembly::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/libsolidity/inlineasm/AsmScopeFiller.h b/libsolidity/inlineasm/AsmScopeFiller.h
deleted file mode 100644
index 7454fd6c..00000000
--- a/libsolidity/inlineasm/AsmScopeFiller.h
+++ /dev/null
@@ -1,88 +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/>.
-*/
-/**
- * Module responsible for registering identifiers inside their scopes.
- */
-
-#pragma once
-
-#include <libsolidity/inlineasm/AsmDataForward.h>
-
-#include <boost/variant.hpp>
-
-#include <functional>
-#include <memory>
-
-namespace langutil
-{
-class ErrorReporter;
-struct SourceLocation;
-}
-
-namespace dev
-{
-namespace solidity
-{
-namespace assembly
-{
-
-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()(assembly::Instruction const&) { return true; }
- bool operator()(assembly::Literal const&) { return true; }
- bool operator()(assembly::Identifier const&) { return true; }
- bool operator()(assembly::FunctionalInstruction const&) { return true; }
- bool operator()(assembly::ExpressionStatement const& _expr);
- bool operator()(assembly::Label const& _label);
- bool operator()(assembly::StackAssignment const&) { return true; }
- bool operator()(assembly::Assignment const&) { return true; }
- bool operator()(assembly::VariableDeclaration const& _variableDeclaration);
- bool operator()(assembly::FunctionDefinition const& _functionDefinition);
- bool operator()(assembly::FunctionCall const&) { return true; }
- bool operator()(assembly::If const& _if);
- bool operator()(assembly::Switch const& _switch);
- bool operator()(assembly::ForLoop const& _forLoop);
- bool operator()(assembly::Block const& _block);
-
-private:
- bool registerVariable(
- TypedName const& _name,
- langutil::SourceLocation const& _location,
- Scope& _scope
- );
-
- Scope& scope(assembly::Block const* _block);
-
- Scope* m_currentScope = nullptr;
- AsmAnalysisInfo& m_info;
- langutil::ErrorReporter& m_errorReporter;
-};
-
-}
-}
-}