aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity
diff options
context:
space:
mode:
Diffstat (limited to 'libsolidity')
-rw-r--r--libsolidity/CMakeLists.txt59
-rw-r--r--libsolidity/analysis/ConstantEvaluator.cpp2
-rw-r--r--libsolidity/analysis/ConstantEvaluator.h10
-rw-r--r--libsolidity/analysis/ContractLevelChecker.cpp463
-rw-r--r--libsolidity/analysis/ContractLevelChecker.h87
-rw-r--r--libsolidity/analysis/ControlFlowAnalyzer.cpp2
-rw-r--r--libsolidity/analysis/ControlFlowAnalyzer.h6
-rw-r--r--libsolidity/analysis/ControlFlowBuilder.h28
-rw-r--r--libsolidity/analysis/ControlFlowGraph.cpp3
-rw-r--r--libsolidity/analysis/ControlFlowGraph.h10
-rw-r--r--libsolidity/analysis/DocStringAnalyser.cpp3
-rw-r--r--libsolidity/analysis/DocStringAnalyser.h19
-rw-r--r--libsolidity/analysis/NameAndTypeResolver.cpp15
-rw-r--r--libsolidity/analysis/NameAndTypeResolver.h19
-rw-r--r--libsolidity/analysis/PostTypeChecker.cpp3
-rw-r--r--libsolidity/analysis/PostTypeChecker.h24
-rw-r--r--libsolidity/analysis/ReferencesResolver.cpp26
-rw-r--r--libsolidity/analysis/ReferencesResolver.h55
-rw-r--r--libsolidity/analysis/SemVerHandler.h3
-rw-r--r--libsolidity/analysis/StaticAnalyzer.cpp3
-rw-r--r--libsolidity/analysis/StaticAnalyzer.h33
-rw-r--r--libsolidity/analysis/SyntaxChecker.cpp3
-rw-r--r--libsolidity/analysis/SyntaxChecker.h51
-rw-r--r--libsolidity/analysis/TypeChecker.cpp542
-rw-r--r--libsolidity/analysis/TypeChecker.h95
-rw-r--r--libsolidity/analysis/ViewPureChecker.cpp35
-rw-r--r--libsolidity/analysis/ViewPureChecker.h42
-rw-r--r--libsolidity/ast/AST.h278
-rw-r--r--libsolidity/ast/ASTAnnotations.h16
-rw-r--r--libsolidity/ast/ASTEnums.h2
-rw-r--r--libsolidity/ast/ASTJsonConverter.cpp13
-rw-r--r--libsolidity/ast/ASTJsonConverter.h11
-rw-r--r--libsolidity/ast/ASTPrinter.cpp1
-rw-r--r--libsolidity/ast/ASTVisitor.h4
-rw-r--r--libsolidity/ast/Types.cpp31
-rw-r--r--libsolidity/ast/Types.h539
-rw-r--r--libsolidity/codegen/ABIFunctions.cpp2
-rw-r--r--libsolidity/codegen/ABIFunctions.h2
-rw-r--r--libsolidity/codegen/ArrayUtils.cpp3
-rw-r--r--libsolidity/codegen/Compiler.h2
-rw-r--r--libsolidity/codegen/CompilerContext.cpp37
-rw-r--r--libsolidity/codegen/CompilerContext.h7
-rw-r--r--libsolidity/codegen/CompilerUtils.cpp28
-rw-r--r--libsolidity/codegen/CompilerUtils.h2
-rw-r--r--libsolidity/codegen/ContractCompiler.cpp18
-rw-r--r--libsolidity/codegen/ContractCompiler.h32
-rw-r--r--libsolidity/codegen/ExpressionCompiler.cpp28
-rw-r--r--libsolidity/codegen/ExpressionCompiler.h26
-rw-r--r--libsolidity/codegen/LValue.cpp1
-rw-r--r--libsolidity/codegen/LValue.h54
-rw-r--r--libsolidity/formal/CVC4Interface.cpp73
-rw-r--r--libsolidity/formal/CVC4Interface.h10
-rw-r--r--libsolidity/formal/SMTChecker.cpp80
-rw-r--r--libsolidity/formal/SMTChecker.h74
-rw-r--r--libsolidity/formal/SMTLib2Interface.cpp104
-rw-r--r--libsolidity/formal/SMTLib2Interface.h23
-rw-r--r--libsolidity/formal/SMTPortfolio.cpp25
-rw-r--r--libsolidity/formal/SMTPortfolio.h10
-rw-r--r--libsolidity/formal/SolverInterface.h214
-rw-r--r--libsolidity/formal/SymbolicTypes.cpp73
-rw-r--r--libsolidity/formal/SymbolicTypes.h16
-rw-r--r--libsolidity/formal/SymbolicVariables.cpp31
-rw-r--r--libsolidity/formal/SymbolicVariables.h23
-rw-r--r--libsolidity/formal/Z3Interface.cpp51
-rw-r--r--libsolidity/formal/Z3Interface.h9
-rw-r--r--libsolidity/inlineasm/AsmAnalysis.cpp630
-rw-r--r--libsolidity/inlineasm/AsmAnalysis.h123
-rw-r--r--libsolidity/inlineasm/AsmAnalysisInfo.cpp26
-rw-r--r--libsolidity/inlineasm/AsmAnalysisInfo.h52
-rw-r--r--libsolidity/inlineasm/AsmCodeGen.cpp161
-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.cpp616
-rw-r--r--libsolidity/inlineasm/AsmParser.h93
-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.cpp180
-rw-r--r--libsolidity/inlineasm/AsmScopeFiller.h84
-rw-r--r--libsolidity/interface/AssemblyStack.cpp64
-rw-r--r--libsolidity/interface/AssemblyStack.h36
-rw-r--r--libsolidity/interface/CompilerStack.cpp84
-rw-r--r--libsolidity/interface/CompilerStack.h36
-rw-r--r--libsolidity/interface/EVMVersion.h94
-rw-r--r--libsolidity/interface/ErrorReporter.cpp226
-rw-r--r--libsolidity/interface/ErrorReporter.h126
-rw-r--r--libsolidity/interface/Exceptions.cpp66
-rw-r--r--libsolidity/interface/Exceptions.h132
-rw-r--r--libsolidity/interface/GasEstimator.cpp1
-rw-r--r--libsolidity/interface/GasEstimator.h2
-rw-r--r--libsolidity/interface/SourceReferenceFormatter.cpp135
-rw-r--r--libsolidity/interface/SourceReferenceFormatter.h79
-rw-r--r--libsolidity/interface/StandardCompiler.cpp34
-rw-r--r--libsolidity/interface/Version.cpp2
-rw-r--r--libsolidity/parsing/DocStringParser.cpp5
-rw-r--r--libsolidity/parsing/DocStringParser.h11
-rw-r--r--libsolidity/parsing/Parser.cpp21
-rw-r--r--libsolidity/parsing/Parser.h17
-rw-r--r--libsolidity/parsing/ParserBase.cpp115
-rw-r--r--libsolidity/parsing/ParserBase.h93
-rw-r--r--libsolidity/parsing/Scanner.cpp920
-rw-r--r--libsolidity/parsing/Scanner.h249
-rw-r--r--libsolidity/parsing/Token.cpp207
-rw-r--r--libsolidity/parsing/Token.h394
-rw-r--r--libsolidity/parsing/UndefMacros.h46
107 files changed, 2276 insertions, 7224 deletions
diff --git a/libsolidity/CMakeLists.txt b/libsolidity/CMakeLists.txt
index 136d39b1..dc4c6d15 100644
--- a/libsolidity/CMakeLists.txt
+++ b/libsolidity/CMakeLists.txt
@@ -1,14 +1,60 @@
# Until we have a clear separation, libyul has to be included here
-file(GLOB_RECURSE sources "*.cpp" "../libyul/*.cpp")
-file(GLOB_RECURSE headers "*.h" "../libyul/*.h")
+set(sources
+ analysis/ConstantEvaluator.cpp
+ analysis/ContractLevelChecker.cpp
+ analysis/ControlFlowAnalyzer.cpp
+ analysis/ControlFlowBuilder.cpp
+ analysis/ControlFlowGraph.cpp
+ analysis/DeclarationContainer.cpp
+ analysis/DocStringAnalyser.cpp
+ analysis/GlobalContext.cpp
+ analysis/NameAndTypeResolver.cpp
+ analysis/PostTypeChecker.cpp
+ analysis/ReferencesResolver.cpp
+ analysis/SemVerHandler.cpp
+ analysis/StaticAnalyzer.cpp
+ analysis/SyntaxChecker.cpp
+ analysis/TypeChecker.cpp
+ analysis/ViewPureChecker.cpp
+ ast/AST.cpp
+ ast/ASTAnnotations.cpp
+ ast/ASTJsonConverter.cpp
+ ast/ASTPrinter.cpp
+ ast/Types.cpp
+ codegen/ABIFunctions.cpp
+ codegen/ArrayUtils.cpp
+ codegen/Compiler.cpp
+ codegen/CompilerContext.cpp
+ codegen/CompilerUtils.cpp
+ codegen/ContractCompiler.cpp
+ codegen/ExpressionCompiler.cpp
+ codegen/LValue.cpp
+ formal/SMTChecker.cpp
+ formal/SMTLib2Interface.cpp
+ formal/SMTPortfolio.cpp
+ formal/SSAVariable.cpp
+ formal/SymbolicTypes.cpp
+ formal/SymbolicVariables.cpp
+ formal/VariableUsage.cpp
+ interface/ABI.cpp
+ interface/AssemblyStack.cpp
+ interface/CompilerStack.cpp
+ interface/GasEstimator.cpp
+ interface/Natspec.cpp
+ interface/StandardCompiler.cpp
+ interface/Version.cpp
+ parsing/DocStringParser.cpp
+ parsing/Parser.cpp
+)
find_package(Z3 QUIET)
if (${Z3_FOUND})
include_directories(${Z3_INCLUDE_DIR})
add_definitions(-DHAVE_Z3)
message("Z3 SMT solver found. This enables optional SMT checking with Z3.")
+ set(z3_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/formal/Z3Interface.cpp")
else()
- list(REMOVE_ITEM sources "${CMAKE_CURRENT_SOURCE_DIR}/formal/Z3Interface.cpp")
+ set(z3_SRCS)
endif()
find_package(CVC4 QUIET)
@@ -16,8 +62,9 @@ if (${CVC4_FOUND})
include_directories(${CVC4_INCLUDE_DIR})
add_definitions(-DHAVE_CVC4)
message("CVC4 SMT solver found. This enables optional SMT checking with CVC4.")
+ set(cvc4_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/formal/CVC4Interface.cpp")
else()
- list(REMOVE_ITEM sources "${CMAKE_CURRENT_SOURCE_DIR}/formal/CVC4Interface.cpp")
+ set(cvc4_SRCS)
endif()
if (NOT (${Z3_FOUND} OR ${CVC4_FOUND}))
@@ -25,8 +72,8 @@ if (NOT (${Z3_FOUND} OR ${CVC4_FOUND}))
\nPlease install Z3 or CVC4 or remove the option disabling them (USE_Z3, USE_CVC4).")
endif()
-add_library(solidity ${sources} ${headers})
-target_link_libraries(solidity PUBLIC evmasm devcore ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY})
+add_library(solidity ${sources} ${z3_SRCS} ${cvc4_SRCS})
+target_link_libraries(solidity PUBLIC yul evmasm langutil devcore ${Boost_FILESYSTEM_LIBRARY} ${Boost_SYSTEM_LIBRARY})
if (${Z3_FOUND})
target_link_libraries(solidity PUBLIC ${Z3_LIBRARY})
diff --git a/libsolidity/analysis/ConstantEvaluator.cpp b/libsolidity/analysis/ConstantEvaluator.cpp
index f9b00927..9d041ce5 100644
--- a/libsolidity/analysis/ConstantEvaluator.cpp
+++ b/libsolidity/analysis/ConstantEvaluator.cpp
@@ -22,7 +22,7 @@
#include <libsolidity/analysis/ConstantEvaluator.h>
#include <libsolidity/ast/AST.h>
-#include <libsolidity/interface/ErrorReporter.h>
+#include <liblangutil/ErrorReporter.h>
using namespace std;
using namespace dev;
diff --git a/libsolidity/analysis/ConstantEvaluator.h b/libsolidity/analysis/ConstantEvaluator.h
index ac3a24a1..23ca3628 100644
--- a/libsolidity/analysis/ConstantEvaluator.h
+++ b/libsolidity/analysis/ConstantEvaluator.h
@@ -24,12 +24,16 @@
#include <libsolidity/ast/ASTVisitor.h>
+namespace langutil
+{
+class ErrorReporter;
+}
+
namespace dev
{
namespace solidity
{
-class ErrorReporter;
class TypeChecker;
/**
@@ -39,7 +43,7 @@ class ConstantEvaluator: private ASTConstVisitor
{
public:
ConstantEvaluator(
- ErrorReporter& _errorReporter,
+ langutil::ErrorReporter& _errorReporter,
size_t _newDepth = 0,
std::shared_ptr<std::map<ASTNode const*, TypePointer>> _types = std::make_shared<std::map<ASTNode const*, TypePointer>>()
):
@@ -61,7 +65,7 @@ private:
void setType(ASTNode const& _node, TypePointer const& _type);
TypePointer type(ASTNode const& _node);
- ErrorReporter& m_errorReporter;
+ langutil::ErrorReporter& m_errorReporter;
/// Current recursion depth.
size_t m_depth = 0;
std::shared_ptr<std::map<ASTNode const*, TypePointer>> m_types;
diff --git a/libsolidity/analysis/ContractLevelChecker.cpp b/libsolidity/analysis/ContractLevelChecker.cpp
new file mode 100644
index 00000000..6dc564de
--- /dev/null
+++ b/libsolidity/analysis/ContractLevelChecker.cpp
@@ -0,0 +1,463 @@
+/*
+ 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/>.
+*/
+/**
+ * Component that verifies overloads, abstract contracts, function clashes and others
+ * checks at contract or function level.
+ */
+
+#include <libsolidity/analysis/ContractLevelChecker.h>
+#include <libsolidity/ast/AST.h>
+
+#include <liblangutil/ErrorReporter.h>
+
+#include <boost/range/adaptor/reversed.hpp>
+
+
+using namespace std;
+using namespace dev;
+using namespace langutil;
+using namespace dev::solidity;
+
+
+bool ContractLevelChecker::check(ContractDefinition const& _contract)
+{
+ checkDuplicateFunctions(_contract);
+ checkDuplicateEvents(_contract);
+ checkIllegalOverrides(_contract);
+ checkAbstractFunctions(_contract);
+ checkBaseConstructorArguments(_contract);
+ checkConstructor(_contract);
+ checkFallbackFunction(_contract);
+ checkExternalTypeClashes(_contract);
+ checkHashCollisions(_contract);
+ checkLibraryRequirements(_contract);
+
+ return Error::containsOnlyWarnings(m_errorReporter.errors());
+}
+
+void ContractLevelChecker::checkDuplicateFunctions(ContractDefinition const& _contract)
+{
+ /// Checks that two functions with the same name defined in this contract have different
+ /// argument types and that there is at most one constructor.
+ map<string, vector<FunctionDefinition const*>> functions;
+ FunctionDefinition const* constructor = nullptr;
+ FunctionDefinition const* fallback = nullptr;
+ for (FunctionDefinition const* function: _contract.definedFunctions())
+ if (function->isConstructor())
+ {
+ if (constructor)
+ m_errorReporter.declarationError(
+ function->location(),
+ SecondarySourceLocation().append("Another declaration is here:", constructor->location()),
+ "More than one constructor defined."
+ );
+ constructor = function;
+ }
+ else if (function->isFallback())
+ {
+ if (fallback)
+ m_errorReporter.declarationError(
+ function->location(),
+ SecondarySourceLocation().append("Another declaration is here:", fallback->location()),
+ "Only one fallback function is allowed."
+ );
+ fallback = function;
+ }
+ else
+ {
+ solAssert(!function->name().empty(), "");
+ functions[function->name()].push_back(function);
+ }
+
+ findDuplicateDefinitions(functions, "Function with same name and arguments defined twice.");
+}
+
+void ContractLevelChecker::checkDuplicateEvents(ContractDefinition const& _contract)
+{
+ /// Checks that two events with the same name defined in this contract have different
+ /// argument types
+ map<string, vector<EventDefinition const*>> events;
+ for (EventDefinition const* event: _contract.events())
+ events[event->name()].push_back(event);
+
+ findDuplicateDefinitions(events, "Event with same name and arguments defined twice.");
+}
+
+template <class T>
+void ContractLevelChecker::findDuplicateDefinitions(map<string, vector<T>> const& _definitions, string _message)
+{
+ for (auto const& it: _definitions)
+ {
+ vector<T> const& overloads = it.second;
+ set<size_t> reported;
+ for (size_t i = 0; i < overloads.size() && !reported.count(i); ++i)
+ {
+ SecondarySourceLocation ssl;
+
+ for (size_t j = i + 1; j < overloads.size(); ++j)
+ if (FunctionType(*overloads[i]).asCallableFunction(false)->hasEqualParameterTypes(
+ *FunctionType(*overloads[j]).asCallableFunction(false))
+ )
+ {
+ ssl.append("Other declaration is here:", overloads[j]->location());
+ reported.insert(j);
+ }
+
+ if (ssl.infos.size() > 0)
+ {
+ ssl.limitSize(_message);
+
+ m_errorReporter.declarationError(
+ overloads[i]->location(),
+ ssl,
+ _message
+ );
+ }
+ }
+ }
+}
+
+void ContractLevelChecker::checkIllegalOverrides(ContractDefinition const& _contract)
+{
+ // TODO unify this at a later point. for this we need to put the constness and the access specifier
+ // into the types
+ map<string, vector<FunctionDefinition const*>> functions;
+ map<string, ModifierDefinition const*> modifiers;
+
+ // We search from derived to base, so the stored item causes the error.
+ for (ContractDefinition const* contract: _contract.annotation().linearizedBaseContracts)
+ {
+ for (FunctionDefinition const* function: contract->definedFunctions())
+ {
+ if (function->isConstructor())
+ continue; // constructors can neither be overridden nor override anything
+ string const& name = function->name();
+ if (modifiers.count(name))
+ m_errorReporter.typeError(modifiers[name]->location(), "Override changes function to modifier.");
+
+ for (FunctionDefinition const* overriding: functions[name])
+ checkFunctionOverride(*overriding, *function);
+
+ functions[name].push_back(function);
+ }
+ for (ModifierDefinition const* modifier: contract->functionModifiers())
+ {
+ string const& name = modifier->name();
+ ModifierDefinition const*& override = modifiers[name];
+ if (!override)
+ override = modifier;
+ else if (ModifierType(*override) != ModifierType(*modifier))
+ m_errorReporter.typeError(override->location(), "Override changes modifier signature.");
+ if (!functions[name].empty())
+ m_errorReporter.typeError(override->location(), "Override changes modifier to function.");
+ }
+ }
+}
+
+void ContractLevelChecker::checkFunctionOverride(FunctionDefinition const& _function, FunctionDefinition const& _super)
+{
+ FunctionTypePointer functionType = FunctionType(_function).asCallableFunction(false);
+ FunctionTypePointer superType = FunctionType(_super).asCallableFunction(false);
+
+ if (!functionType->hasEqualParameterTypes(*superType))
+ return;
+ if (!functionType->hasEqualReturnTypes(*superType))
+ overrideError(_function, _super, "Overriding function return types differ.");
+
+ if (!_function.annotation().superFunction)
+ _function.annotation().superFunction = &_super;
+
+ if (_function.visibility() != _super.visibility())
+ {
+ // Visibility change from external to public is fine.
+ // Any other change is disallowed.
+ if (!(
+ _super.visibility() == FunctionDefinition::Visibility::External &&
+ _function.visibility() == FunctionDefinition::Visibility::Public
+ ))
+ overrideError(_function, _super, "Overriding function visibility differs.");
+ }
+ if (_function.stateMutability() != _super.stateMutability())
+ overrideError(
+ _function,
+ _super,
+ "Overriding function changes state mutability from \"" +
+ stateMutabilityToString(_super.stateMutability()) +
+ "\" to \"" +
+ stateMutabilityToString(_function.stateMutability()) +
+ "\"."
+ );
+}
+
+void ContractLevelChecker::overrideError(FunctionDefinition const& function, FunctionDefinition const& super, string message)
+{
+ m_errorReporter.typeError(
+ function.location(),
+ SecondarySourceLocation().append("Overridden function is here:", super.location()),
+ message
+ );
+}
+
+void ContractLevelChecker::checkAbstractFunctions(ContractDefinition const& _contract)
+{
+ // Mapping from name to function definition (exactly one per argument type equality class) and
+ // flag to indicate whether it is fully implemented.
+ using FunTypeAndFlag = std::pair<FunctionTypePointer, bool>;
+ map<string, vector<FunTypeAndFlag>> functions;
+
+ auto registerFunction = [&](Declaration const& _declaration, FunctionTypePointer const& _type, bool _implemented)
+ {
+ auto& overloads = functions[_declaration.name()];
+ auto it = find_if(overloads.begin(), overloads.end(), [&](FunTypeAndFlag const& _funAndFlag)
+ {
+ return _type->hasEqualParameterTypes(*_funAndFlag.first);
+ });
+ if (it == overloads.end())
+ overloads.push_back(make_pair(_type, _implemented));
+ else if (it->second)
+ {
+ if (!_implemented)
+ m_errorReporter.typeError(_declaration.location(), "Redeclaring an already implemented function as abstract");
+ }
+ else if (_implemented)
+ it->second = true;
+ };
+
+ // Search from base to derived, collect all functions and update
+ // the 'implemented' flag.
+ for (ContractDefinition const* contract: boost::adaptors::reverse(_contract.annotation().linearizedBaseContracts))
+ {
+ for (VariableDeclaration const* v: contract->stateVariables())
+ if (v->isPartOfExternalInterface())
+ registerFunction(*v, make_shared<FunctionType>(*v), true);
+
+ for (FunctionDefinition const* function: contract->definedFunctions())
+ if (!function->isConstructor())
+ registerFunction(
+ *function,
+ make_shared<FunctionType>(*function)->asCallableFunction(false),
+ function->isImplemented()
+ );
+ }
+
+ // Set to not fully implemented if at least one flag is false.
+ for (auto const& it: functions)
+ for (auto const& funAndFlag: it.second)
+ if (!funAndFlag.second)
+ {
+ FunctionDefinition const* function = dynamic_cast<FunctionDefinition const*>(&funAndFlag.first->declaration());
+ solAssert(function, "");
+ _contract.annotation().unimplementedFunctions.push_back(function);
+ break;
+ }
+}
+
+
+void ContractLevelChecker::checkBaseConstructorArguments(ContractDefinition const& _contract)
+{
+ vector<ContractDefinition const*> const& bases = _contract.annotation().linearizedBaseContracts;
+
+ // Determine the arguments that are used for the base constructors.
+ for (ContractDefinition const* contract: bases)
+ {
+ if (FunctionDefinition const* constructor = contract->constructor())
+ for (auto const& modifier: constructor->modifiers())
+ if (auto baseContract = dynamic_cast<ContractDefinition const*>(
+ modifier->name()->annotation().referencedDeclaration
+ ))
+ {
+ if (modifier->arguments())
+ {
+ if (baseContract->constructor())
+ annotateBaseConstructorArguments(_contract, baseContract->constructor(), modifier.get());
+ }
+ else
+ m_errorReporter.declarationError(
+ modifier->location(),
+ "Modifier-style base constructor call without arguments."
+ );
+ }
+
+ for (ASTPointer<InheritanceSpecifier> const& base: contract->baseContracts())
+ {
+ ContractDefinition const* baseContract = dynamic_cast<ContractDefinition const*>(
+ base->name().annotation().referencedDeclaration
+ );
+ solAssert(baseContract, "");
+
+ if (baseContract->constructor() && base->arguments() && !base->arguments()->empty())
+ annotateBaseConstructorArguments(_contract, baseContract->constructor(), base.get());
+ }
+ }
+
+ // check that we get arguments for all base constructors that need it.
+ // If not mark the contract as abstract (not fully implemented)
+ for (ContractDefinition const* contract: bases)
+ if (FunctionDefinition const* constructor = contract->constructor())
+ if (contract != &_contract && !constructor->parameters().empty())
+ if (!_contract.annotation().baseConstructorArguments.count(constructor))
+ _contract.annotation().unimplementedFunctions.push_back(constructor);
+}
+
+void ContractLevelChecker::annotateBaseConstructorArguments(
+ ContractDefinition const& _currentContract,
+ FunctionDefinition const* _baseConstructor,
+ ASTNode const* _argumentNode
+)
+{
+ solAssert(_baseConstructor, "");
+ solAssert(_argumentNode, "");
+
+ auto insertionResult = _currentContract.annotation().baseConstructorArguments.insert(
+ std::make_pair(_baseConstructor, _argumentNode)
+ );
+ if (!insertionResult.second)
+ {
+ ASTNode const* previousNode = insertionResult.first->second;
+
+ SourceLocation const* mainLocation = nullptr;
+ SecondarySourceLocation ssl;
+
+ if (
+ _currentContract.location().contains(previousNode->location()) ||
+ _currentContract.location().contains(_argumentNode->location())
+ )
+ {
+ mainLocation = &previousNode->location();
+ ssl.append("Second constructor call is here:", _argumentNode->location());
+ }
+ else
+ {
+ mainLocation = &_currentContract.location();
+ ssl.append("First constructor call is here: ", _argumentNode->location());
+ ssl.append("Second constructor call is here: ", previousNode->location());
+ }
+
+ m_errorReporter.declarationError(
+ *mainLocation,
+ ssl,
+ "Base constructor arguments given twice."
+ );
+ }
+
+}
+
+void ContractLevelChecker::checkConstructor(ContractDefinition const& _contract)
+{
+ FunctionDefinition const* constructor = _contract.constructor();
+ if (!constructor)
+ return;
+
+ if (!constructor->returnParameters().empty())
+ m_errorReporter.typeError(constructor->returnParameterList()->location(), "Non-empty \"returns\" directive for constructor.");
+ if (constructor->stateMutability() != StateMutability::NonPayable && constructor->stateMutability() != StateMutability::Payable)
+ m_errorReporter.typeError(
+ constructor->location(),
+ "Constructor must be payable or non-payable, but is \"" +
+ stateMutabilityToString(constructor->stateMutability()) +
+ "\"."
+ );
+ if (constructor->visibility() != FunctionDefinition::Visibility::Public && constructor->visibility() != FunctionDefinition::Visibility::Internal)
+ m_errorReporter.typeError(constructor->location(), "Constructor must be public or internal.");
+}
+
+void ContractLevelChecker::checkFallbackFunction(ContractDefinition const& _contract)
+{
+ FunctionDefinition const* fallback = _contract.fallbackFunction();
+ if (!fallback)
+ return;
+
+ if (_contract.isLibrary())
+ m_errorReporter.typeError(fallback->location(), "Libraries cannot have fallback functions.");
+ if (fallback->stateMutability() != StateMutability::NonPayable && fallback->stateMutability() != StateMutability::Payable)
+ m_errorReporter.typeError(
+ fallback->location(),
+ "Fallback function must be payable or non-payable, but is \"" +
+ stateMutabilityToString(fallback->stateMutability()) +
+ "\"."
+ );
+ if (!fallback->parameters().empty())
+ m_errorReporter.typeError(fallback->parameterList().location(), "Fallback function cannot take parameters.");
+ if (!fallback->returnParameters().empty())
+ m_errorReporter.typeError(fallback->returnParameterList()->location(), "Fallback function cannot return values.");
+ if (fallback->visibility() != FunctionDefinition::Visibility::External)
+ m_errorReporter.typeError(fallback->location(), "Fallback function must be defined as \"external\".");
+}
+
+void ContractLevelChecker::checkExternalTypeClashes(ContractDefinition const& _contract)
+{
+ map<string, vector<pair<Declaration const*, FunctionTypePointer>>> externalDeclarations;
+ for (ContractDefinition const* contract: _contract.annotation().linearizedBaseContracts)
+ {
+ for (FunctionDefinition const* f: contract->definedFunctions())
+ if (f->isPartOfExternalInterface())
+ {
+ auto functionType = make_shared<FunctionType>(*f);
+ // under non error circumstances this should be true
+ if (functionType->interfaceFunctionType())
+ externalDeclarations[functionType->externalSignature()].push_back(
+ make_pair(f, functionType->asCallableFunction(false))
+ );
+ }
+ for (VariableDeclaration const* v: contract->stateVariables())
+ if (v->isPartOfExternalInterface())
+ {
+ auto functionType = make_shared<FunctionType>(*v);
+ // under non error circumstances this should be true
+ if (functionType->interfaceFunctionType())
+ externalDeclarations[functionType->externalSignature()].push_back(
+ make_pair(v, functionType->asCallableFunction(false))
+ );
+ }
+ }
+ for (auto const& it: externalDeclarations)
+ for (size_t i = 0; i < it.second.size(); ++i)
+ for (size_t j = i + 1; j < it.second.size(); ++j)
+ if (!it.second[i].second->hasEqualParameterTypes(*it.second[j].second))
+ m_errorReporter.typeError(
+ it.second[j].first->location(),
+ "Function overload clash during conversion to external types for arguments."
+ );
+}
+
+void ContractLevelChecker::checkHashCollisions(ContractDefinition const& _contract)
+{
+ set<FixedHash<4>> hashes;
+ for (auto const& it: _contract.interfaceFunctionList())
+ {
+ FixedHash<4> const& hash = it.first;
+ if (hashes.count(hash))
+ m_errorReporter.typeError(
+ _contract.location(),
+ string("Function signature hash collision for ") + it.second->externalSignature()
+ );
+ hashes.insert(hash);
+ }
+}
+
+void ContractLevelChecker::checkLibraryRequirements(ContractDefinition const& _contract)
+{
+ if (!_contract.isLibrary())
+ return;
+
+ if (!_contract.baseContracts().empty())
+ m_errorReporter.typeError(_contract.location(), "Library is not allowed to inherit.");
+
+ for (auto const& var: _contract.stateVariables())
+ if (!var->isConstant())
+ m_errorReporter.typeError(var->location(), "Library cannot have non-constant state variables");
+}
diff --git a/libsolidity/analysis/ContractLevelChecker.h b/libsolidity/analysis/ContractLevelChecker.h
new file mode 100644
index 00000000..15cbf45d
--- /dev/null
+++ b/libsolidity/analysis/ContractLevelChecker.h
@@ -0,0 +1,87 @@
+/*
+ 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/>.
+*/
+/**
+ * Component that verifies overloads, abstract contracts, function clashes and others
+ * checks at contract or function level.
+ */
+
+#pragma once
+
+#include <libsolidity/ast/ASTForward.h>
+
+#include <map>
+
+namespace langutil
+{
+class ErrorReporter;
+}
+
+namespace dev
+{
+namespace solidity
+{
+
+/**
+ * Component that verifies overloads, abstract contracts, function clashes and others
+ * checks at contract or function level.
+ */
+class ContractLevelChecker
+{
+public:
+ /// @param _errorReporter provides the error logging functionality.
+ explicit ContractLevelChecker(langutil::ErrorReporter& _errorReporter):
+ m_errorReporter(_errorReporter)
+ {}
+
+ /// Performs checks on the given contract.
+ /// @returns true iff all checks passed. Note even if all checks passed, errors() can still contain warnings
+ bool check(ContractDefinition const& _contract);
+
+private:
+ /// Checks that two functions defined in this contract with the same name have different
+ /// arguments and that there is at most one constructor.
+ void checkDuplicateFunctions(ContractDefinition const& _contract);
+ void checkDuplicateEvents(ContractDefinition const& _contract);
+ template <class T>
+ void findDuplicateDefinitions(std::map<std::string, std::vector<T>> const& _definitions, std::string _message);
+ void checkIllegalOverrides(ContractDefinition const& _contract);
+ /// Reports a type error with an appropriate message if overridden function signature differs.
+ /// Also stores the direct super function in the AST annotations.
+ void checkFunctionOverride(FunctionDefinition const& function, FunctionDefinition const& super);
+ void overrideError(FunctionDefinition const& function, FunctionDefinition const& super, std::string message);
+ void checkAbstractFunctions(ContractDefinition const& _contract);
+ void checkBaseConstructorArguments(ContractDefinition const& _contract);
+ void annotateBaseConstructorArguments(
+ ContractDefinition const& _currentContract,
+ FunctionDefinition const* _baseConstructor,
+ ASTNode const* _argumentNode
+ );
+ void checkConstructor(ContractDefinition const& _contract);
+ void checkFallbackFunction(ContractDefinition const& _contract);
+ /// Checks that different functions with external visibility end up having different
+ /// external argument types (i.e. different signature).
+ void checkExternalTypeClashes(ContractDefinition const& _contract);
+ /// Checks for hash collisions in external function signatures.
+ void checkHashCollisions(ContractDefinition const& _contract);
+ /// Checks that all requirements for a library are fulfilled if this is a library.
+ void checkLibraryRequirements(ContractDefinition const& _contract);
+
+ langutil::ErrorReporter& m_errorReporter;
+};
+
+}
+}
diff --git a/libsolidity/analysis/ControlFlowAnalyzer.cpp b/libsolidity/analysis/ControlFlowAnalyzer.cpp
index 8a608552..fe58f0aa 100644
--- a/libsolidity/analysis/ControlFlowAnalyzer.cpp
+++ b/libsolidity/analysis/ControlFlowAnalyzer.cpp
@@ -16,8 +16,10 @@
*/
#include <libsolidity/analysis/ControlFlowAnalyzer.h>
+#include <liblangutil/SourceLocation.h>
using namespace std;
+using namespace langutil;
using namespace dev::solidity;
bool ControlFlowAnalyzer::analyze(ASTNode const& _astRoot)
diff --git a/libsolidity/analysis/ControlFlowAnalyzer.h b/libsolidity/analysis/ControlFlowAnalyzer.h
index 43e13fb6..411d57ff 100644
--- a/libsolidity/analysis/ControlFlowAnalyzer.h
+++ b/libsolidity/analysis/ControlFlowAnalyzer.h
@@ -29,12 +29,12 @@ namespace solidity
class ControlFlowAnalyzer: private ASTConstVisitor
{
public:
- explicit ControlFlowAnalyzer(CFG const& _cfg, ErrorReporter& _errorReporter):
+ explicit ControlFlowAnalyzer(CFG const& _cfg, langutil::ErrorReporter& _errorReporter):
m_cfg(_cfg), m_errorReporter(_errorReporter) {}
bool analyze(ASTNode const& _astRoot);
- virtual bool visit(FunctionDefinition const& _function) override;
+ bool visit(FunctionDefinition const& _function) override;
private:
static std::set<VariableDeclaration const*> variablesAssignedInNode(CFGNode const *node);
@@ -45,7 +45,7 @@ private:
) const;
CFG const& m_cfg;
- ErrorReporter& m_errorReporter;
+ langutil::ErrorReporter& m_errorReporter;
};
}
diff --git a/libsolidity/analysis/ControlFlowBuilder.h b/libsolidity/analysis/ControlFlowBuilder.h
index e9d96e5f..40605e00 100644
--- a/libsolidity/analysis/ControlFlowBuilder.h
+++ b/libsolidity/analysis/ControlFlowBuilder.h
@@ -46,19 +46,19 @@ public:
private:
explicit ControlFlowBuilder(CFG::NodeContainer& _nodeContainer, FunctionFlow const& _functionFlow);
- virtual bool visit(BinaryOperation const& _operation) override;
- virtual bool visit(Conditional const& _conditional) override;
- virtual bool visit(IfStatement const& _ifStatement) override;
- virtual bool visit(ForStatement const& _forStatement) override;
- virtual bool visit(WhileStatement const& _whileStatement) override;
- virtual bool visit(Break const&) override;
- virtual bool visit(Continue const&) override;
- virtual bool visit(Throw const&) override;
- virtual bool visit(Block const&) override;
- virtual void endVisit(Block const&) override;
- virtual bool visit(Return const& _return) override;
- virtual bool visit(PlaceholderStatement const&) override;
- virtual bool visit(FunctionCall const& _functionCall) override;
+ bool visit(BinaryOperation const& _operation) override;
+ bool visit(Conditional const& _conditional) override;
+ bool visit(IfStatement const& _ifStatement) override;
+ bool visit(ForStatement const& _forStatement) override;
+ bool visit(WhileStatement const& _whileStatement) override;
+ bool visit(Break const&) override;
+ bool visit(Continue const&) override;
+ bool visit(Throw const&) override;
+ bool visit(Block const&) override;
+ void endVisit(Block const&) override;
+ bool visit(Return const& _return) override;
+ bool visit(PlaceholderStatement const&) override;
+ bool visit(FunctionCall const& _functionCall) override;
/// Appends the control flow of @a _node to the current control flow.
@@ -74,7 +74,7 @@ private:
protected:
- virtual bool visitNode(ASTNode const& node) override;
+ bool visitNode(ASTNode const& node) override;
private:
diff --git a/libsolidity/analysis/ControlFlowGraph.cpp b/libsolidity/analysis/ControlFlowGraph.cpp
index 9b3da0eb..b8860158 100644
--- a/libsolidity/analysis/ControlFlowGraph.cpp
+++ b/libsolidity/analysis/ControlFlowGraph.cpp
@@ -23,6 +23,7 @@
#include <algorithm>
using namespace std;
+using namespace langutil;
using namespace dev::solidity;
bool CFG::constructFlow(ASTNode const& _astRoot)
@@ -133,4 +134,4 @@ void CFG::applyModifierFlowToFunctionFlow(
_functionFlow->entry = copySrcToCopyDst[_modifierFlow.entry];
_functionFlow->exit = copySrcToCopyDst[_modifierFlow.exit];
-} \ No newline at end of file
+}
diff --git a/libsolidity/analysis/ControlFlowGraph.h b/libsolidity/analysis/ControlFlowGraph.h
index c646e4f1..8fe9fe8e 100644
--- a/libsolidity/analysis/ControlFlowGraph.h
+++ b/libsolidity/analysis/ControlFlowGraph.h
@@ -19,7 +19,7 @@
#include <libsolidity/ast/AST.h>
#include <libsolidity/ast/ASTVisitor.h>
-#include <libsolidity/interface/ErrorReporter.h>
+#include <liblangutil/ErrorReporter.h>
#include <map>
#include <memory>
@@ -101,12 +101,12 @@ struct ModifierFlow: FunctionFlow
class CFG: private ASTConstVisitor
{
public:
- explicit CFG(ErrorReporter& _errorReporter): m_errorReporter(_errorReporter) {}
+ explicit CFG(langutil::ErrorReporter& _errorReporter): m_errorReporter(_errorReporter) {}
bool constructFlow(ASTNode const& _astRoot);
- virtual bool visit(ModifierDefinition const& _modifier) override;
- virtual bool visit(FunctionDefinition const& _function) override;
+ bool visit(ModifierDefinition const& _modifier) override;
+ bool visit(FunctionDefinition const& _function) override;
FunctionFlow const& functionFlow(FunctionDefinition const& _function) const;
@@ -133,7 +133,7 @@ private:
FunctionFlow* _functionFlow
);
- ErrorReporter& m_errorReporter;
+ langutil::ErrorReporter& m_errorReporter;
/// Node container.
/// All nodes allocated during the construction of the control flow graph
diff --git a/libsolidity/analysis/DocStringAnalyser.cpp b/libsolidity/analysis/DocStringAnalyser.cpp
index c1b97def..69a7a43c 100644
--- a/libsolidity/analysis/DocStringAnalyser.cpp
+++ b/libsolidity/analysis/DocStringAnalyser.cpp
@@ -23,11 +23,12 @@
#include <libsolidity/analysis/DocStringAnalyser.h>
#include <libsolidity/ast/AST.h>
-#include <libsolidity/interface/ErrorReporter.h>
+#include <liblangutil/ErrorReporter.h>
#include <libsolidity/parsing/DocStringParser.h>
using namespace std;
using namespace dev;
+using namespace langutil;
using namespace dev::solidity;
bool DocStringAnalyser::analyseDocStrings(SourceUnit const& _sourceUnit)
diff --git a/libsolidity/analysis/DocStringAnalyser.h b/libsolidity/analysis/DocStringAnalyser.h
index 5d339428..f6b236db 100644
--- a/libsolidity/analysis/DocStringAnalyser.h
+++ b/libsolidity/analysis/DocStringAnalyser.h
@@ -25,13 +25,16 @@
#include <libsolidity/ast/ASTVisitor.h>
+namespace langutil
+{
+class ErrorReporter;
+}
+
namespace dev
{
namespace solidity
{
-class ErrorReporter;
-
/**
* Parses and analyses the doc strings.
* Stores the parsing results in the AST annotations and reports errors.
@@ -39,14 +42,14 @@ class ErrorReporter;
class DocStringAnalyser: private ASTConstVisitor
{
public:
- DocStringAnalyser(ErrorReporter& _errorReporter): m_errorReporter(_errorReporter) {}
+ DocStringAnalyser(langutil::ErrorReporter& _errorReporter): m_errorReporter(_errorReporter) {}
bool analyseDocStrings(SourceUnit const& _sourceUnit);
private:
- virtual bool visit(ContractDefinition const& _contract) override;
- virtual bool visit(FunctionDefinition const& _function) override;
- virtual bool visit(ModifierDefinition const& _modifier) override;
- virtual bool visit(EventDefinition const& _event) override;
+ bool visit(ContractDefinition const& _contract) override;
+ bool visit(FunctionDefinition const& _function) override;
+ bool visit(ModifierDefinition const& _modifier) override;
+ bool visit(EventDefinition const& _event) override;
void checkParameters(
CallableDeclaration const& _callable,
@@ -75,7 +78,7 @@ private:
void appendError(std::string const& _description);
bool m_errorOccured = false;
- ErrorReporter& m_errorReporter;
+ langutil::ErrorReporter& m_errorReporter;
};
}
diff --git a/libsolidity/analysis/NameAndTypeResolver.cpp b/libsolidity/analysis/NameAndTypeResolver.cpp
index b452a49a..0528a200 100644
--- a/libsolidity/analysis/NameAndTypeResolver.cpp
+++ b/libsolidity/analysis/NameAndTypeResolver.cpp
@@ -24,12 +24,13 @@
#include <libsolidity/ast/AST.h>
#include <libsolidity/analysis/TypeChecker.h>
-#include <libsolidity/interface/ErrorReporter.h>
+#include <liblangutil/ErrorReporter.h>
#include <libdevcore/StringUtils.h>
#include <boost/algorithm/string.hpp>
using namespace std;
+using namespace langutil;
namespace dev
{
@@ -59,7 +60,7 @@ bool NameAndTypeResolver::registerDeclarations(SourceUnit& _sourceUnit, ASTNode
{
DeclarationRegistrationHelper registrar(m_scopes, _sourceUnit, m_errorReporter, _currentScope);
}
- catch (FatalError const&)
+ catch (langutil::FatalError const&)
{
if (m_errorReporter.errors().empty())
throw; // Something is weird here, rather throw again.
@@ -129,7 +130,7 @@ bool NameAndTypeResolver::resolveNamesAndTypes(ASTNode& _node, bool _resolveInsi
{
return resolveNamesAndTypesInternal(_node, _resolveInsideCode);
}
- catch (FatalError const&)
+ catch (langutil::FatalError const&)
{
if (m_errorReporter.errors().empty())
throw; // Something is weird here, rather throw again.
@@ -144,7 +145,7 @@ bool NameAndTypeResolver::updateDeclaration(Declaration const& _declaration)
m_scopes[nullptr]->registerDeclaration(_declaration, nullptr, false, true);
solAssert(_declaration.scope() == nullptr, "Updated declaration outside global scope.");
}
- catch (FatalError const&)
+ catch (langutil::FatalError const&)
{
if (m_errorReporter.errors().empty())
throw; // Something is weird here, rather throw again.
@@ -491,9 +492,9 @@ bool DeclarationRegistrationHelper::registerDeclaration(
Declaration const* conflictingDeclaration = _container.conflictingDeclaration(_declaration, _name);
solAssert(conflictingDeclaration, "");
bool const comparable =
- _errorLocation->sourceName &&
- conflictingDeclaration->location().sourceName &&
- *_errorLocation->sourceName == *conflictingDeclaration->location().sourceName;
+ _errorLocation->source &&
+ conflictingDeclaration->location().source &&
+ _errorLocation->source->name() == conflictingDeclaration->location().source->name();
if (comparable && _errorLocation->start < conflictingDeclaration->location().start)
{
firstDeclarationLocation = *_errorLocation;
diff --git a/libsolidity/analysis/NameAndTypeResolver.h b/libsolidity/analysis/NameAndTypeResolver.h
index a72c21e3..1b034ef4 100644
--- a/libsolidity/analysis/NameAndTypeResolver.h
+++ b/libsolidity/analysis/NameAndTypeResolver.h
@@ -30,13 +30,16 @@
#include <libsolidity/ast/ASTVisitor.h>
#include <libsolidity/ast/ASTAnnotations.h>
+namespace langutil
+{
+class ErrorReporter;
+}
+
namespace dev
{
namespace solidity
{
-class ErrorReporter;
-
/**
* Resolves name references, typenames and sets the (explicitly given) types for all variable
* declarations.
@@ -50,7 +53,7 @@ public:
NameAndTypeResolver(
std::vector<Declaration const*> const& _globals,
std::map<ASTNode const*, std::shared_ptr<DeclarationContainer>>& _scopes,
- ErrorReporter& _errorReporter
+ langutil::ErrorReporter& _errorReporter
);
/// Registers all declarations found in the AST node, usually a source unit.
/// @returns false in case of error.
@@ -125,7 +128,7 @@ private:
std::map<ASTNode const*, std::shared_ptr<DeclarationContainer>>& m_scopes;
DeclarationContainer* m_currentScope = nullptr;
- ErrorReporter& m_errorReporter;
+ langutil::ErrorReporter& m_errorReporter;
};
/**
@@ -142,7 +145,7 @@ public:
DeclarationRegistrationHelper(
std::map<ASTNode const*, std::shared_ptr<DeclarationContainer>>& _scopes,
ASTNode& _astRoot,
- ErrorReporter& _errorReporter,
+ langutil::ErrorReporter& _errorReporter,
ASTNode const* _currentScope = nullptr
);
@@ -150,10 +153,10 @@ public:
DeclarationContainer& _container,
Declaration const& _declaration,
std::string const* _name,
- SourceLocation const* _errorLocation,
+ langutil::SourceLocation const* _errorLocation,
bool _warnOnShadow,
bool _inactive,
- ErrorReporter& _errorReporter
+ langutil::ErrorReporter& _errorReporter
);
private:
@@ -194,7 +197,7 @@ private:
std::map<ASTNode const*, std::shared_ptr<DeclarationContainer>>& m_scopes;
ASTNode const* m_currentScope = nullptr;
VariableScope* m_currentFunction = nullptr;
- ErrorReporter& m_errorReporter;
+ langutil::ErrorReporter& m_errorReporter;
};
}
diff --git a/libsolidity/analysis/PostTypeChecker.cpp b/libsolidity/analysis/PostTypeChecker.cpp
index 240d7973..27cbcd45 100644
--- a/libsolidity/analysis/PostTypeChecker.cpp
+++ b/libsolidity/analysis/PostTypeChecker.cpp
@@ -18,7 +18,7 @@
#include <libsolidity/analysis/PostTypeChecker.h>
#include <libsolidity/ast/AST.h>
#include <libsolidity/analysis/SemVerHandler.h>
-#include <libsolidity/interface/ErrorReporter.h>
+#include <liblangutil/ErrorReporter.h>
#include <libsolidity/interface/Version.h>
#include <libdevcore/Algorithms.h>
@@ -29,6 +29,7 @@
using namespace std;
using namespace dev;
+using namespace langutil;
using namespace dev::solidity;
diff --git a/libsolidity/analysis/PostTypeChecker.h b/libsolidity/analysis/PostTypeChecker.h
index 4f9dac6e..e428b81a 100644
--- a/libsolidity/analysis/PostTypeChecker.h
+++ b/libsolidity/analysis/PostTypeChecker.h
@@ -23,13 +23,17 @@
#include <libsolidity/ast/ASTForward.h>
#include <libsolidity/ast/ASTVisitor.h>
+namespace langutil
+{
+class ErrorReporter;
+struct SourceLocation;
+}
+
namespace dev
{
namespace solidity
{
-class ErrorReporter;
-
/**
* This module performs analyses on the AST that are done after type checking and assignments of types:
* - whether there are circular references in constant state variables
@@ -39,25 +43,25 @@ class PostTypeChecker: private ASTConstVisitor
{
public:
/// @param _errorReporter provides the error logging functionality.
- PostTypeChecker(ErrorReporter& _errorReporter): m_errorReporter(_errorReporter) {}
+ PostTypeChecker(langutil::ErrorReporter& _errorReporter): m_errorReporter(_errorReporter) {}
bool check(ASTNode const& _astRoot);
private:
/// Adds a new error to the list of errors.
- void typeError(SourceLocation const& _location, std::string const& _description);
+ void typeError(langutil::SourceLocation const& _location, std::string const& _description);
- virtual bool visit(ContractDefinition const& _contract) override;
- virtual void endVisit(ContractDefinition const& _contract) override;
+ bool visit(ContractDefinition const& _contract) override;
+ void endVisit(ContractDefinition const& _contract) override;
- virtual bool visit(VariableDeclaration const& _variable) override;
- virtual void endVisit(VariableDeclaration const& _variable) override;
+ bool visit(VariableDeclaration const& _variable) override;
+ void endVisit(VariableDeclaration const& _variable) override;
- virtual bool visit(Identifier const& _identifier) override;
+ bool visit(Identifier const& _identifier) override;
VariableDeclaration const* findCycle(VariableDeclaration const& _startingFrom);
- ErrorReporter& m_errorReporter;
+ langutil::ErrorReporter& m_errorReporter;
VariableDeclaration const* m_currentConstVariable = nullptr;
std::vector<VariableDeclaration const*> m_constVariables; ///< Required for determinism.
diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp
index 2adc8e77..c4931d98 100644
--- a/libsolidity/analysis/ReferencesResolver.cpp
+++ b/libsolidity/analysis/ReferencesResolver.cpp
@@ -23,12 +23,12 @@
#include <libsolidity/analysis/ReferencesResolver.h>
#include <libsolidity/ast/AST.h>
#include <libsolidity/analysis/NameAndTypeResolver.h>
-#include <libsolidity/interface/Exceptions.h>
#include <libsolidity/analysis/ConstantEvaluator.h>
-#include <libsolidity/inlineasm/AsmAnalysis.h>
-#include <libsolidity/inlineasm/AsmAnalysisInfo.h>
-#include <libsolidity/inlineasm/AsmData.h>
-#include <libsolidity/interface/ErrorReporter.h>
+#include <libyul/AsmAnalysis.h>
+#include <libyul/AsmAnalysisInfo.h>
+#include <libyul/AsmData.h>
+#include <liblangutil/ErrorReporter.h>
+#include <liblangutil/Exceptions.h>
#include <libdevcore/StringUtils.h>
@@ -36,9 +36,12 @@
#include <boost/range/adaptor/transformed.hpp>
using namespace std;
-using namespace dev;
-using namespace dev::solidity;
+using namespace langutil;
+namespace dev
+{
+namespace solidity
+{
bool ReferencesResolver::resolve(ASTNode const& _root)
{
@@ -270,7 +273,7 @@ bool ReferencesResolver::visit(InlineAssembly const& _inlineAssembly)
ErrorList errors;
ErrorReporter errorsIgnored(errors);
yul::ExternalIdentifierAccess::Resolver resolver =
- [&](assembly::Identifier const& _identifier, yul::IdentifierContext, bool _crossesFunctionBoundary) {
+ [&](yul::Identifier const& _identifier, yul::IdentifierContext, bool _crossesFunctionBoundary) {
auto declarations = m_resolver.nameFromCurrentScope(_identifier.name.str());
bool isSlot = boost::algorithm::ends_with(_identifier.name.str(), "_slot");
bool isOffset = boost::algorithm::ends_with(_identifier.name.str(), "_offset");
@@ -311,9 +314,9 @@ bool ReferencesResolver::visit(InlineAssembly const& _inlineAssembly)
// Will be re-generated later with correct information
// We use the latest EVM version because we will re-run it anyway.
- assembly::AsmAnalysisInfo analysisInfo;
+ yul::AsmAnalysisInfo analysisInfo;
boost::optional<Error::Type> errorTypeForLoose = Error::Type::SyntaxError;
- assembly::AsmAnalyzer(analysisInfo, errorsIgnored, EVMVersion(), errorTypeForLoose, assembly::AsmFlavour::Loose, resolver).analyze(_inlineAssembly.operations());
+ yul::AsmAnalyzer(analysisInfo, errorsIgnored, EVMVersion(), errorTypeForLoose, yul::AsmFlavour::Loose, resolver).analyze(_inlineAssembly.operations());
return false;
}
@@ -454,3 +457,6 @@ void ReferencesResolver::fatalDeclarationError(SourceLocation const& _location,
m_errorOccurred = true;
m_errorReporter.fatalDeclarationError(_location, _description);
}
+
+}
+}
diff --git a/libsolidity/analysis/ReferencesResolver.h b/libsolidity/analysis/ReferencesResolver.h
index 24ec4643..32c0553f 100644
--- a/libsolidity/analysis/ReferencesResolver.h
+++ b/libsolidity/analysis/ReferencesResolver.h
@@ -28,12 +28,17 @@
#include <libsolidity/ast/ASTVisitor.h>
#include <libsolidity/ast/ASTAnnotations.h>
+namespace langutil
+{
+class ErrorReporter;
+struct SourceLocation;
+}
+
namespace dev
{
namespace solidity
{
-class ErrorReporter;
class NameAndTypeResolver;
/**
@@ -44,7 +49,7 @@ class ReferencesResolver: private ASTConstVisitor
{
public:
ReferencesResolver(
- ErrorReporter& _errorReporter,
+ langutil::ErrorReporter& _errorReporter,
NameAndTypeResolver& _resolver,
bool _resolveInsideCode = false
):
@@ -57,38 +62,38 @@ public:
bool resolve(ASTNode const& _root);
private:
- virtual bool visit(Block const& _block) override;
- virtual void endVisit(Block const& _block) override;
- virtual bool visit(ForStatement const& _for) override;
- virtual void endVisit(ForStatement const& _for) override;
- virtual void endVisit(VariableDeclarationStatement const& _varDeclStatement) override;
- virtual bool visit(Identifier const& _identifier) override;
- virtual bool visit(ElementaryTypeName const& _typeName) override;
- virtual bool visit(FunctionDefinition const& _functionDefinition) override;
- virtual void endVisit(FunctionDefinition const& _functionDefinition) override;
- virtual bool visit(ModifierDefinition const& _modifierDefinition) override;
- virtual void endVisit(ModifierDefinition const& _modifierDefinition) override;
- virtual void endVisit(UserDefinedTypeName const& _typeName) override;
- virtual void endVisit(FunctionTypeName const& _typeName) override;
- virtual void endVisit(Mapping const& _typeName) override;
- virtual void endVisit(ArrayTypeName const& _typeName) override;
- virtual bool visit(InlineAssembly const& _inlineAssembly) override;
- virtual bool visit(Return const& _return) override;
- virtual void endVisit(VariableDeclaration const& _variable) override;
+ bool visit(Block const& _block) override;
+ void endVisit(Block const& _block) override;
+ bool visit(ForStatement const& _for) override;
+ void endVisit(ForStatement const& _for) override;
+ void endVisit(VariableDeclarationStatement const& _varDeclStatement) override;
+ bool visit(Identifier const& _identifier) override;
+ bool visit(ElementaryTypeName const& _typeName) override;
+ bool visit(FunctionDefinition const& _functionDefinition) override;
+ void endVisit(FunctionDefinition const& _functionDefinition) override;
+ bool visit(ModifierDefinition const& _modifierDefinition) override;
+ void endVisit(ModifierDefinition const& _modifierDefinition) override;
+ void endVisit(UserDefinedTypeName const& _typeName) override;
+ void endVisit(FunctionTypeName const& _typeName) override;
+ void endVisit(Mapping const& _typeName) override;
+ void endVisit(ArrayTypeName const& _typeName) override;
+ bool visit(InlineAssembly const& _inlineAssembly) override;
+ bool visit(Return const& _return) override;
+ void endVisit(VariableDeclaration const& _variable) override;
/// Adds a new error to the list of errors.
- void typeError(SourceLocation const& _location, std::string const& _description);
+ void typeError(langutil::SourceLocation const& _location, std::string const& _description);
/// Adds a new error to the list of errors and throws to abort reference resolving.
- void fatalTypeError(SourceLocation const& _location, std::string const& _description);
+ void fatalTypeError(langutil::SourceLocation const& _location, std::string const& _description);
/// Adds a new error to the list of errors.
- void declarationError(SourceLocation const& _location, std::string const& _description);
+ void declarationError(langutil::SourceLocation const& _location, std::string const& _description);
/// Adds a new error to the list of errors and throws to abort reference resolving.
- void fatalDeclarationError(SourceLocation const& _location, std::string const& _description);
+ void fatalDeclarationError(langutil::SourceLocation const& _location, std::string const& _description);
- ErrorReporter& m_errorReporter;
+ langutil::ErrorReporter& m_errorReporter;
NameAndTypeResolver& m_resolver;
/// Stack of return parameters.
std::vector<ParameterList const*> m_returnParameters;
diff --git a/libsolidity/analysis/SemVerHandler.h b/libsolidity/analysis/SemVerHandler.h
index 03a557c5..80185612 100644
--- a/libsolidity/analysis/SemVerHandler.h
+++ b/libsolidity/analysis/SemVerHandler.h
@@ -22,8 +22,9 @@
#pragma once
-#include <vector>
#include <libsolidity/parsing/Token.h>
+#include <string>
+#include <vector>
namespace dev
{
diff --git a/libsolidity/analysis/StaticAnalyzer.cpp b/libsolidity/analysis/StaticAnalyzer.cpp
index 487a5cca..38391841 100644
--- a/libsolidity/analysis/StaticAnalyzer.cpp
+++ b/libsolidity/analysis/StaticAnalyzer.cpp
@@ -23,11 +23,12 @@
#include <libsolidity/analysis/StaticAnalyzer.h>
#include <libsolidity/analysis/ConstantEvaluator.h>
#include <libsolidity/ast/AST.h>
-#include <libsolidity/interface/ErrorReporter.h>
+#include <liblangutil/ErrorReporter.h>
#include <memory>
using namespace std;
using namespace dev;
+using namespace langutil;
using namespace dev::solidity;
bool StaticAnalyzer::analyze(SourceUnit const& _sourceUnit)
diff --git a/libsolidity/analysis/StaticAnalyzer.h b/libsolidity/analysis/StaticAnalyzer.h
index 7f5c743a..ff33fa3a 100644
--- a/libsolidity/analysis/StaticAnalyzer.h
+++ b/libsolidity/analysis/StaticAnalyzer.h
@@ -28,6 +28,11 @@
#include <libsolidity/ast/ASTForward.h>
#include <libsolidity/ast/ASTVisitor.h>
+namespace langutil
+{
+class ErrorReporter;
+}
+
namespace dev
{
namespace solidity
@@ -44,7 +49,7 @@ class StaticAnalyzer: private ASTConstVisitor
{
public:
/// @param _errorReporter provides the error logging functionality.
- explicit StaticAnalyzer(ErrorReporter& _errorReporter): m_errorReporter(_errorReporter) {}
+ explicit StaticAnalyzer(langutil::ErrorReporter& _errorReporter): m_errorReporter(_errorReporter) {}
/// Performs static analysis on the given source unit and all of its sub-nodes.
/// @returns true iff all checks passed. Note even if all checks passed, errors() can still contain warnings
@@ -52,25 +57,25 @@ public:
private:
- virtual bool visit(ContractDefinition const& _contract) override;
- virtual void endVisit(ContractDefinition const& _contract) override;
+ bool visit(ContractDefinition const& _contract) override;
+ void endVisit(ContractDefinition const& _contract) override;
- virtual bool visit(FunctionDefinition const& _function) override;
- virtual void endVisit(FunctionDefinition const& _function) override;
+ bool visit(FunctionDefinition const& _function) override;
+ void endVisit(FunctionDefinition const& _function) override;
- virtual bool visit(ExpressionStatement const& _statement) override;
- virtual bool visit(VariableDeclaration const& _variable) override;
- virtual bool visit(Identifier const& _identifier) override;
- virtual bool visit(Return const& _return) override;
- virtual bool visit(MemberAccess const& _memberAccess) override;
- virtual bool visit(InlineAssembly const& _inlineAssembly) override;
- virtual bool visit(BinaryOperation const& _operation) override;
- virtual bool visit(FunctionCall const& _functionCall) override;
+ bool visit(ExpressionStatement const& _statement) override;
+ bool visit(VariableDeclaration const& _variable) override;
+ bool visit(Identifier const& _identifier) override;
+ bool visit(Return const& _return) override;
+ bool visit(MemberAccess const& _memberAccess) override;
+ bool visit(InlineAssembly const& _inlineAssembly) override;
+ bool visit(BinaryOperation const& _operation) override;
+ bool visit(FunctionCall const& _functionCall) override;
/// @returns the size of this type in storage, including all sub-types.
static bigint structureSizeEstimate(Type const& _type, std::set<StructDefinition const*>& _structsSeen);
- ErrorReporter& m_errorReporter;
+ langutil::ErrorReporter& m_errorReporter;
/// Flag that indicates whether the current contract definition is a library.
bool m_library = false;
diff --git a/libsolidity/analysis/SyntaxChecker.cpp b/libsolidity/analysis/SyntaxChecker.cpp
index 3f9f8373..a73d7e5c 100644
--- a/libsolidity/analysis/SyntaxChecker.cpp
+++ b/libsolidity/analysis/SyntaxChecker.cpp
@@ -20,7 +20,7 @@
#include <libsolidity/ast/AST.h>
#include <libsolidity/ast/ExperimentalFeatures.h>
#include <libsolidity/analysis/SemVerHandler.h>
-#include <libsolidity/interface/ErrorReporter.h>
+#include <liblangutil/ErrorReporter.h>
#include <libsolidity/interface/Version.h>
#include <boost/algorithm/cxx11/all_of.hpp>
@@ -29,6 +29,7 @@
using namespace std;
using namespace dev;
+using namespace langutil;
using namespace dev::solidity;
diff --git a/libsolidity/analysis/SyntaxChecker.h b/libsolidity/analysis/SyntaxChecker.h
index f5716bf9..c2463955 100644
--- a/libsolidity/analysis/SyntaxChecker.h
+++ b/libsolidity/analysis/SyntaxChecker.h
@@ -23,6 +23,11 @@
#include <libsolidity/ast/ASTForward.h>
#include <libsolidity/ast/ASTVisitor.h>
+namespace langutil
+{
+class ErrorReporter;
+}
+
namespace dev
{
namespace solidity
@@ -39,49 +44,49 @@ class SyntaxChecker: private ASTConstVisitor
{
public:
/// @param _errorReporter provides the error logging functionality.
- SyntaxChecker(ErrorReporter& _errorReporter): m_errorReporter(_errorReporter) {}
+ SyntaxChecker(langutil::ErrorReporter& _errorReporter): m_errorReporter(_errorReporter) {}
bool checkSyntax(ASTNode const& _astRoot);
private:
- virtual bool visit(SourceUnit const& _sourceUnit) override;
- virtual void endVisit(SourceUnit const& _sourceUnit) override;
- virtual bool visit(PragmaDirective const& _pragma) override;
+ bool visit(SourceUnit const& _sourceUnit) override;
+ void endVisit(SourceUnit const& _sourceUnit) override;
+ bool visit(PragmaDirective const& _pragma) override;
- virtual bool visit(ModifierDefinition const& _modifier) override;
- virtual void endVisit(ModifierDefinition const& _modifier) override;
+ bool visit(ModifierDefinition const& _modifier) override;
+ void endVisit(ModifierDefinition const& _modifier) override;
/// Reports an error if _statement is a VariableDeclarationStatement.
/// Used by if/while/for to check for single statement variable declarations
/// without a block.
void checkSingleStatementVariableDeclaration(ASTNode const& _statement);
- virtual bool visit(IfStatement const& _ifStatement) override;
- virtual bool visit(WhileStatement const& _whileStatement) override;
- virtual void endVisit(WhileStatement const& _whileStatement) override;
- virtual bool visit(ForStatement const& _forStatement) override;
- virtual void endVisit(ForStatement const& _forStatement) override;
+ bool visit(IfStatement const& _ifStatement) override;
+ bool visit(WhileStatement const& _whileStatement) override;
+ void endVisit(WhileStatement const& _whileStatement) override;
+ bool visit(ForStatement const& _forStatement) override;
+ void endVisit(ForStatement const& _forStatement) override;
- virtual bool visit(Continue const& _continueStatement) override;
- virtual bool visit(Break const& _breakStatement) override;
+ bool visit(Continue const& _continueStatement) override;
+ bool visit(Break const& _breakStatement) override;
- virtual bool visit(Throw const& _throwStatement) override;
+ bool visit(Throw const& _throwStatement) override;
- virtual bool visit(UnaryOperation const& _operation) override;
+ bool visit(UnaryOperation const& _operation) override;
- virtual bool visit(PlaceholderStatement const& _placeholderStatement) override;
+ bool visit(PlaceholderStatement const& _placeholderStatement) override;
- virtual bool visit(ContractDefinition const& _contract) override;
- virtual bool visit(FunctionDefinition const& _function) override;
- virtual bool visit(FunctionTypeName const& _node) override;
+ bool visit(ContractDefinition const& _contract) override;
+ bool visit(FunctionDefinition const& _function) override;
+ bool visit(FunctionTypeName const& _node) override;
- virtual bool visit(VariableDeclarationStatement const& _statement) override;
+ bool visit(VariableDeclarationStatement const& _statement) override;
- virtual bool visit(StructDefinition const& _struct) override;
- virtual bool visit(Literal const& _literal) override;
+ bool visit(StructDefinition const& _struct) override;
+ bool visit(Literal const& _literal) override;
- ErrorReporter& m_errorReporter;
+ langutil::ErrorReporter& m_errorReporter;
/// Flag that indicates whether a function modifier actually contains '_'.
bool m_placeholderFound = false;
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp
index c5e6488b..9350df05 100644
--- a/libsolidity/analysis/TypeChecker.cpp
+++ b/libsolidity/analysis/TypeChecker.cpp
@@ -21,20 +21,27 @@
*/
#include <libsolidity/analysis/TypeChecker.h>
-#include <memory>
+#include <libsolidity/ast/AST.h>
+
+#include <libyul/AsmAnalysis.h>
+#include <libyul/AsmAnalysisInfo.h>
+#include <libyul/AsmData.h>
+
+#include <liblangutil/ErrorReporter.h>
+
+#include <libdevcore/Algorithms.h>
+#include <libdevcore/StringUtils.h>
+
#include <boost/algorithm/cxx11/all_of.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/join.hpp>
-#include <boost/range/adaptor/reversed.hpp>
-#include <libsolidity/ast/AST.h>
-#include <libsolidity/inlineasm/AsmAnalysis.h>
-#include <libsolidity/inlineasm/AsmAnalysisInfo.h>
-#include <libsolidity/inlineasm/AsmData.h>
-#include <libsolidity/interface/ErrorReporter.h>
-#include <libdevcore/Algorithms.h>
+
+#include <memory>
+#include <vector>
using namespace std;
using namespace dev;
+using namespace langutil;
using namespace dev::solidity;
namespace
@@ -81,418 +88,14 @@ bool TypeChecker::visit(ContractDefinition const& _contract)
{
m_scope = &_contract;
- // We force our own visiting order here. The structs have to be excluded below.
- set<ASTNode const*> visited;
- for (auto const& s: _contract.definedStructs())
- visited.insert(s);
- ASTNode::listAccept(_contract.definedStructs(), *this);
ASTNode::listAccept(_contract.baseContracts(), *this);
- checkContractDuplicateFunctions(_contract);
- checkContractDuplicateEvents(_contract);
- checkContractIllegalOverrides(_contract);
- checkContractAbstractFunctions(_contract);
- checkContractBaseConstructorArguments(_contract);
-
- FunctionDefinition const* function = _contract.constructor();
- if (function)
- {
- if (!function->returnParameters().empty())
- m_errorReporter.typeError(function->returnParameterList()->location(), "Non-empty \"returns\" directive for constructor.");
- if (function->stateMutability() != StateMutability::NonPayable && function->stateMutability() != StateMutability::Payable)
- m_errorReporter.typeError(
- function->location(),
- "Constructor must be payable or non-payable, but is \"" +
- stateMutabilityToString(function->stateMutability()) +
- "\"."
- );
- if (function->visibility() != FunctionDefinition::Visibility::Public && function->visibility() != FunctionDefinition::Visibility::Internal)
- m_errorReporter.typeError(function->location(), "Constructor must be public or internal.");
- }
-
- for (FunctionDefinition const* function: _contract.definedFunctions())
- if (function->isFallback())
- {
- if (_contract.isLibrary())
- m_errorReporter.typeError(function->location(), "Libraries cannot have fallback functions.");
- if (function->stateMutability() != StateMutability::NonPayable && function->stateMutability() != StateMutability::Payable)
- m_errorReporter.typeError(
- function->location(),
- "Fallback function must be payable or non-payable, but is \"" +
- stateMutabilityToString(function->stateMutability()) +
- "\"."
- );
- if (!function->parameters().empty())
- m_errorReporter.typeError(function->parameterList().location(), "Fallback function cannot take parameters.");
- if (!function->returnParameters().empty())
- m_errorReporter.typeError(function->returnParameterList()->location(), "Fallback function cannot return values.");
- if (function->visibility() != FunctionDefinition::Visibility::External)
- m_errorReporter.typeError(function->location(), "Fallback function must be defined as \"external\".");
- }
-
for (auto const& n: _contract.subNodes())
- if (!visited.count(n.get()))
- n->accept(*this);
-
- checkContractExternalTypeClashes(_contract);
- // check for hash collisions in function signatures
- set<FixedHash<4>> hashes;
- for (auto const& it: _contract.interfaceFunctionList())
- {
- FixedHash<4> const& hash = it.first;
- if (hashes.count(hash))
- m_errorReporter.typeError(
- _contract.location(),
- string("Function signature hash collision for ") + it.second->externalSignature()
- );
- hashes.insert(hash);
- }
-
- if (_contract.isLibrary())
- checkLibraryRequirements(_contract);
+ n->accept(*this);
return false;
}
-void TypeChecker::checkContractDuplicateFunctions(ContractDefinition const& _contract)
-{
- /// Checks that two functions with the same name defined in this contract have different
- /// argument types and that there is at most one constructor.
- map<string, vector<FunctionDefinition const*>> functions;
- FunctionDefinition const* constructor = nullptr;
- FunctionDefinition const* fallback = nullptr;
- for (FunctionDefinition const* function: _contract.definedFunctions())
- if (function->isConstructor())
- {
- if (constructor)
- m_errorReporter.declarationError(
- function->location(),
- SecondarySourceLocation().append("Another declaration is here:", constructor->location()),
- "More than one constructor defined."
- );
- constructor = function;
- }
- else if (function->isFallback())
- {
- if (fallback)
- m_errorReporter.declarationError(
- function->location(),
- SecondarySourceLocation().append("Another declaration is here:", fallback->location()),
- "Only one fallback function is allowed."
- );
- fallback = function;
- }
- else
- {
- solAssert(!function->name().empty(), "");
- functions[function->name()].push_back(function);
- }
-
- findDuplicateDefinitions(functions, "Function with same name and arguments defined twice.");
-}
-
-void TypeChecker::checkContractDuplicateEvents(ContractDefinition const& _contract)
-{
- /// Checks that two events with the same name defined in this contract have different
- /// argument types
- map<string, vector<EventDefinition const*>> events;
- for (EventDefinition const* event: _contract.events())
- events[event->name()].push_back(event);
-
- findDuplicateDefinitions(events, "Event with same name and arguments defined twice.");
-}
-
-template <class T>
-void TypeChecker::findDuplicateDefinitions(map<string, vector<T>> const& _definitions, string _message)
-{
- for (auto const& it: _definitions)
- {
- vector<T> const& overloads = it.second;
- set<size_t> reported;
- for (size_t i = 0; i < overloads.size() && !reported.count(i); ++i)
- {
- SecondarySourceLocation ssl;
-
- for (size_t j = i + 1; j < overloads.size(); ++j)
- if (FunctionType(*overloads[i]).hasEqualParameterTypes(FunctionType(*overloads[j])))
- {
- ssl.append("Other declaration is here:", overloads[j]->location());
- reported.insert(j);
- }
-
- if (ssl.infos.size() > 0)
- {
- ssl.limitSize(_message);
-
- m_errorReporter.declarationError(
- overloads[i]->location(),
- ssl,
- _message
- );
- }
- }
- }
-}
-
-void TypeChecker::checkContractAbstractFunctions(ContractDefinition const& _contract)
-{
- // Mapping from name to function definition (exactly one per argument type equality class) and
- // flag to indicate whether it is fully implemented.
- using FunTypeAndFlag = std::pair<FunctionTypePointer, bool>;
- map<string, vector<FunTypeAndFlag>> functions;
-
- // Search from base to derived
- for (ContractDefinition const* contract: boost::adaptors::reverse(_contract.annotation().linearizedBaseContracts))
- for (FunctionDefinition const* function: contract->definedFunctions())
- {
- // Take constructors out of overload hierarchy
- if (function->isConstructor())
- continue;
- auto& overloads = functions[function->name()];
- FunctionTypePointer funType = make_shared<FunctionType>(*function);
- auto it = find_if(overloads.begin(), overloads.end(), [&](FunTypeAndFlag const& _funAndFlag)
- {
- return funType->hasEqualParameterTypes(*_funAndFlag.first);
- });
- if (it == overloads.end())
- overloads.push_back(make_pair(funType, function->isImplemented()));
- else if (it->second)
- {
- if (!function->isImplemented())
- m_errorReporter.typeError(function->location(), "Redeclaring an already implemented function as abstract");
- }
- else if (function->isImplemented())
- it->second = true;
- }
-
- // Set to not fully implemented if at least one flag is false.
- for (auto const& it: functions)
- for (auto const& funAndFlag: it.second)
- if (!funAndFlag.second)
- {
- FunctionDefinition const* function = dynamic_cast<FunctionDefinition const*>(&funAndFlag.first->declaration());
- solAssert(function, "");
- _contract.annotation().unimplementedFunctions.push_back(function);
- break;
- }
-}
-
-void TypeChecker::checkContractBaseConstructorArguments(ContractDefinition const& _contract)
-{
- vector<ContractDefinition const*> const& bases = _contract.annotation().linearizedBaseContracts;
-
- // Determine the arguments that are used for the base constructors.
- for (ContractDefinition const* contract: bases)
- {
- if (FunctionDefinition const* constructor = contract->constructor())
- for (auto const& modifier: constructor->modifiers())
- if (auto baseContract = dynamic_cast<ContractDefinition const*>(&dereference(*modifier->name())))
- {
- if (modifier->arguments())
- {
- if (baseContract->constructor())
- annotateBaseConstructorArguments(_contract, baseContract->constructor(), modifier.get());
- }
- else
- m_errorReporter.declarationError(
- modifier->location(),
- "Modifier-style base constructor call without arguments."
- );
- }
-
- for (ASTPointer<InheritanceSpecifier> const& base: contract->baseContracts())
- {
- auto baseContract = dynamic_cast<ContractDefinition const*>(&dereference(base->name()));
- solAssert(baseContract, "");
-
- if (baseContract->constructor() && base->arguments() && !base->arguments()->empty())
- annotateBaseConstructorArguments(_contract, baseContract->constructor(), base.get());
- }
- }
-
- // check that we get arguments for all base constructors that need it.
- // If not mark the contract as abstract (not fully implemented)
- for (ContractDefinition const* contract: bases)
- if (FunctionDefinition const* constructor = contract->constructor())
- if (contract != &_contract && !constructor->parameters().empty())
- if (!_contract.annotation().baseConstructorArguments.count(constructor))
- _contract.annotation().unimplementedFunctions.push_back(constructor);
-}
-
-void TypeChecker::annotateBaseConstructorArguments(
- ContractDefinition const& _currentContract,
- FunctionDefinition const* _baseConstructor,
- ASTNode const* _argumentNode
-)
-{
- solAssert(_baseConstructor, "");
- solAssert(_argumentNode, "");
-
- auto insertionResult = _currentContract.annotation().baseConstructorArguments.insert(
- std::make_pair(_baseConstructor, _argumentNode)
- );
- if (!insertionResult.second)
- {
- ASTNode const* previousNode = insertionResult.first->second;
-
- SourceLocation const* mainLocation = nullptr;
- SecondarySourceLocation ssl;
-
- if (
- _currentContract.location().contains(previousNode->location()) ||
- _currentContract.location().contains(_argumentNode->location())
- )
- {
- mainLocation = &previousNode->location();
- ssl.append("Second constructor call is here:", _argumentNode->location());
- }
- else
- {
- mainLocation = &_currentContract.location();
- ssl.append("First constructor call is here: ", _argumentNode->location());
- ssl.append("Second constructor call is here: ", previousNode->location());
- }
-
- m_errorReporter.declarationError(
- *mainLocation,
- ssl,
- "Base constructor arguments given twice."
- );
- }
-
-}
-
-void TypeChecker::checkContractIllegalOverrides(ContractDefinition const& _contract)
-{
- // TODO unify this at a later point. for this we need to put the constness and the access specifier
- // into the types
- map<string, vector<FunctionDefinition const*>> functions;
- map<string, ModifierDefinition const*> modifiers;
-
- // We search from derived to base, so the stored item causes the error.
- for (ContractDefinition const* contract: _contract.annotation().linearizedBaseContracts)
- {
- for (FunctionDefinition const* function: contract->definedFunctions())
- {
- if (function->isConstructor())
- continue; // constructors can neither be overridden nor override anything
- string const& name = function->name();
- if (modifiers.count(name))
- m_errorReporter.typeError(modifiers[name]->location(), "Override changes function to modifier.");
-
- for (FunctionDefinition const* overriding: functions[name])
- checkFunctionOverride(*overriding, *function);
-
- functions[name].push_back(function);
- }
- for (ModifierDefinition const* modifier: contract->functionModifiers())
- {
- string const& name = modifier->name();
- ModifierDefinition const*& override = modifiers[name];
- if (!override)
- override = modifier;
- else if (ModifierType(*override) != ModifierType(*modifier))
- m_errorReporter.typeError(override->location(), "Override changes modifier signature.");
- if (!functions[name].empty())
- m_errorReporter.typeError(override->location(), "Override changes modifier to function.");
- }
- }
-}
-
-void TypeChecker::checkFunctionOverride(FunctionDefinition const& function, FunctionDefinition const& super)
-{
- FunctionType functionType(function);
- FunctionType superType(super);
-
- if (!functionType.hasEqualParameterTypes(superType))
- return;
-
- if (!function.annotation().superFunction)
- function.annotation().superFunction = &super;
-
- if (function.visibility() != super.visibility())
- {
- // visibility is enforced to be external in interfaces, but a contract can override that with public
- if (
- super.inContractKind() == ContractDefinition::ContractKind::Interface &&
- function.inContractKind() != ContractDefinition::ContractKind::Interface &&
- function.visibility() == FunctionDefinition::Visibility::Public
- )
- return;
- overrideError(function, super, "Overriding function visibility differs.");
- }
-
- else if (function.stateMutability() != super.stateMutability())
- overrideError(
- function,
- super,
- "Overriding function changes state mutability from \"" +
- stateMutabilityToString(super.stateMutability()) +
- "\" to \"" +
- stateMutabilityToString(function.stateMutability()) +
- "\"."
- );
-
- else if (functionType != superType)
- overrideError(function, super, "Overriding function return types differ.");
-}
-
-void TypeChecker::overrideError(FunctionDefinition const& function, FunctionDefinition const& super, string message)
-{
- m_errorReporter.typeError(
- function.location(),
- SecondarySourceLocation().append("Overridden function is here:", super.location()),
- message
- );
-}
-
-void TypeChecker::checkContractExternalTypeClashes(ContractDefinition const& _contract)
-{
- map<string, vector<pair<Declaration const*, FunctionTypePointer>>> externalDeclarations;
- for (ContractDefinition const* contract: _contract.annotation().linearizedBaseContracts)
- {
- for (FunctionDefinition const* f: contract->definedFunctions())
- if (f->isPartOfExternalInterface())
- {
- auto functionType = make_shared<FunctionType>(*f);
- // under non error circumstances this should be true
- if (functionType->interfaceFunctionType())
- externalDeclarations[functionType->externalSignature()].push_back(
- make_pair(f, functionType)
- );
- }
- for (VariableDeclaration const* v: contract->stateVariables())
- if (v->isPartOfExternalInterface())
- {
- auto functionType = make_shared<FunctionType>(*v);
- // under non error circumstances this should be true
- if (functionType->interfaceFunctionType())
- externalDeclarations[functionType->externalSignature()].push_back(
- make_pair(v, functionType)
- );
- }
- }
- for (auto const& it: externalDeclarations)
- for (size_t i = 0; i < it.second.size(); ++i)
- for (size_t j = i + 1; j < it.second.size(); ++j)
- if (!it.second[i].second->hasEqualParameterTypes(*it.second[j].second))
- m_errorReporter.typeError(
- it.second[j].first->location(),
- "Function overload clash during conversion to external types for arguments."
- );
-}
-
-void TypeChecker::checkLibraryRequirements(ContractDefinition const& _contract)
-{
- solAssert(_contract.isLibrary(), "");
- if (!_contract.baseContracts().empty())
- m_errorReporter.typeError(_contract.location(), "Library is not allowed to inherit.");
-
- for (auto const& var: _contract.stateVariables())
- if (!var->isConstant())
- m_errorReporter.typeError(var->location(), "Library cannot have non-constant state variables");
-}
-
void TypeChecker::checkDoubleStorageAssignment(Assignment const& _assignment)
{
TupleType const& lhs = dynamic_cast<TupleType const&>(*type(_assignment.leftHandSide()));
@@ -697,20 +300,22 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
}
for (ASTPointer<VariableDeclaration> const& var: _function.parameters() + _function.returnParameters())
{
+ if (type(*var)->category() == Type::Category::Mapping)
+ {
+ if (!type(*var)->dataStoredIn(DataLocation::Storage))
+ m_errorReporter.typeError(var->location(), "Mapping types can only have a data location of \"storage\"." );
+ else if (!isLibraryFunction && _function.isPublic())
+ m_errorReporter.typeError(var->location(), "Mapping types for parameters or return variables can only be used in internal or library functions.");
+ }
+ else
+ {
+ if (!type(*var)->canLiveOutsideStorage() && _function.isPublic())
+ m_errorReporter.typeError(var->location(), "Type is required to live outside storage.");
+ if (_function.isPublic() && !(type(*var)->interfaceType(isLibraryFunction)))
+ m_errorReporter.fatalTypeError(var->location(), "Internal or recursive type is not allowed for public or external functions.");
+ }
if (
- type(*var)->category() == Type::Category::Mapping &&
- !type(*var)->dataStoredIn(DataLocation::Storage)
- )
- m_errorReporter.typeError(var->location(), "Mapping types can only have a data location of \"storage\".");
- else if (
- !type(*var)->canLiveOutsideStorage() &&
- _function.visibility() > FunctionDefinition::Visibility::Internal
- )
- m_errorReporter.typeError(var->location(), "Type is required to live outside storage.");
- if (_function.visibility() >= FunctionDefinition::Visibility::Public && !(type(*var)->interfaceType(isLibraryFunction)))
- m_errorReporter.fatalTypeError(var->location(), "Internal or recursive type is not allowed for public or external functions.");
- if (
- _function.visibility() > FunctionDefinition::Visibility::Internal &&
+ _function.isPublic() &&
!_function.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::ABIEncoderV2) &&
!typeSupportedByOldABIEncoder(*type(*var))
)
@@ -775,15 +380,10 @@ bool TypeChecker::visit(VariableDeclaration const& _variable)
)
m_errorReporter.typeError(_variable.location(), "Variables cannot be declared in interfaces.");
- // Variables can be declared without type (with "var"), in which case the first assignment
- // sets the type.
- // Note that assignments before the first declaration are legal because of the special scoping
- // rules inherited from JavaScript.
-
// type is filled either by ReferencesResolver directly from the type name or by
// TypeChecker at the VariableDeclarationStatement level.
TypePointer varType = _variable.annotation().type;
- solAssert(!!varType, "Failed to infer variable type.");
+ solAssert(!!varType, "Variable type not provided.");
if (_variable.value())
expectType(*_variable.value(), *varType);
@@ -812,11 +412,25 @@ bool TypeChecker::visit(VariableDeclaration const& _variable)
if (!varType->canLiveOutsideStorage())
m_errorReporter.typeError(_variable.location(), "Type " + varType->toString() + " is only valid in storage.");
}
- else if (
- _variable.visibility() >= VariableDeclaration::Visibility::Public &&
- !FunctionType(_variable).interfaceFunctionType()
- )
- m_errorReporter.typeError(_variable.location(), "Internal or recursive type is not allowed for public state variables.");
+ else if (_variable.visibility() >= VariableDeclaration::Visibility::Public)
+ {
+ FunctionType getter(_variable);
+ if (!_variable.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::ABIEncoderV2))
+ {
+ vector<string> unsupportedTypes;
+ for (auto const& param: getter.parameterTypes() + getter.returnParameterTypes())
+ if (!typeSupportedByOldABIEncoder(*param))
+ unsupportedTypes.emplace_back(param->toString());
+ if (!unsupportedTypes.empty())
+ m_errorReporter.typeError(_variable.location(),
+ "The following types are only supported for getters in the new experimental ABI encoder: " +
+ joinHumanReadable(unsupportedTypes) +
+ ". Either remove \"public\" or use \"pragma experimental ABIEncoderV2;\" to enable the feature."
+ );
+ }
+ if (!getter.interfaceFunctionType())
+ m_errorReporter.typeError(_variable.location(), "Internal or recursive type is not allowed for public state variables.");
+ }
switch (varType->category())
{
@@ -953,7 +567,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
// External references have already been resolved in a prior stage and stored in the annotation.
// We run the resolve step again regardless.
yul::ExternalIdentifierAccess::Resolver identifierAccess = [&](
- assembly::Identifier const& _identifier,
+ yul::Identifier const& _identifier,
yul::IdentifierContext _context,
bool
)
@@ -1038,13 +652,13 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
return size_t(1);
};
solAssert(!_inlineAssembly.annotation().analysisInfo, "");
- _inlineAssembly.annotation().analysisInfo = make_shared<assembly::AsmAnalysisInfo>();
- assembly::AsmAnalyzer analyzer(
+ _inlineAssembly.annotation().analysisInfo = make_shared<yul::AsmAnalysisInfo>();
+ yul::AsmAnalyzer analyzer(
*_inlineAssembly.annotation().analysisInfo,
m_errorReporter,
m_evmVersion,
Error::Type::SyntaxError,
- assembly::AsmFlavour::Loose,
+ yul::AsmFlavour::Loose,
identifierAccess
);
if (!analyzer.analyze(_inlineAssembly.operations()))
@@ -1590,6 +1204,9 @@ bool TypeChecker::visit(TupleExpression const& _tuple)
{
if (!inlineArrayType)
m_errorReporter.fatalTypeError(_tuple.location(), "Unable to deduce common type for array elements.");
+ else if (!inlineArrayType->canLiveOutsideStorage())
+ m_errorReporter.fatalTypeError(_tuple.location(), "Type " + inlineArrayType->toString() + " is only valid in storage.");
+
_tuple.annotation().type = make_shared<ArrayType>(DataLocation::Memory, inlineArrayType, types.size());
}
else
@@ -1806,26 +1423,6 @@ void TypeChecker::typeCheckFunctionCall(
"\"staticcall\" is not supported by the VM version."
);
- // Check for deprecated function names
- if (_functionType->kind() == FunctionType::Kind::KECCAK256)
- {
- if (auto functionName = dynamic_cast<Identifier const*>(&_functionCall.expression()))
- if (functionName->name() == "sha3")
- m_errorReporter.typeError(
- _functionCall.location(),
- "\"sha3\" has been deprecated in favour of \"keccak256\""
- );
- }
- else if (_functionType->kind() == FunctionType::Kind::Selfdestruct)
- {
- if (auto functionName = dynamic_cast<Identifier const*>(&_functionCall.expression()))
- if (functionName->name() == "suicide")
- m_errorReporter.typeError(
- _functionCall.location(),
- "\"suicide\" has been deprecated in favour of \"selfdestruct\""
- );
- }
-
// Check for event outside of emit statement
if (!m_insideEmitStatement && _functionType->kind() == FunctionType::Kind::Event)
m_errorReporter.typeError(
@@ -2488,7 +2085,7 @@ bool TypeChecker::visit(IndexAccess const& _access)
}
else
{
- expectType(*index, IntegerType(256));
+ expectType(*index, IntegerType::uint256());
if (!m_errorReporter.hasErrors())
if (auto numberType = dynamic_cast<RationalNumberType const*>(type(*index).get()))
{
@@ -2519,7 +2116,7 @@ bool TypeChecker::visit(IndexAccess const& _access)
resultType = make_shared<TypeType>(make_shared<ArrayType>(DataLocation::Memory, typeType.actualType()));
else
{
- expectType(*index, IntegerType(256));
+ expectType(*index, IntegerType::uint256());
if (auto length = dynamic_cast<RationalNumberType const*>(type(*index).get()))
resultType = make_shared<TypeType>(make_shared<ArrayType>(
DataLocation::Memory,
@@ -2538,7 +2135,7 @@ bool TypeChecker::visit(IndexAccess const& _access)
m_errorReporter.typeError(_access.location(), "Index expression cannot be omitted.");
else
{
- if (!expectType(*index, IntegerType(256)))
+ if (!expectType(*index, IntegerType::uint256()))
m_errorReporter.fatalTypeError(_access.location(), "Index expression cannot be represented as an unsigned integer.");
if (auto integerType = dynamic_cast<RationalNumberType const*>(type(*index).get()))
if (bytesType.numBytes() <= integerType->literalValue(nullptr))
@@ -2621,6 +2218,23 @@ bool TypeChecker::visit(Identifier const& _identifier)
else if (dynamic_cast<MagicVariableDeclaration const*>(annotation.referencedDeclaration))
if (dynamic_cast<FunctionType const*>(annotation.type.get()))
annotation.isPure = true;
+
+ // Check for deprecated function names.
+ // The check is done here for the case without an actual function call.
+ if (FunctionType const* fType = dynamic_cast<FunctionType const*>(_identifier.annotation().type.get()))
+ {
+ if (_identifier.name() == "sha3" && fType->kind() == FunctionType::Kind::KECCAK256)
+ m_errorReporter.typeError(
+ _identifier.location(),
+ "\"sha3\" has been deprecated in favour of \"keccak256\""
+ );
+ else if (_identifier.name() == "suicide" && fType->kind() == FunctionType::Kind::Selfdestruct)
+ m_errorReporter.typeError(
+ _identifier.location(),
+ "\"suicide\" has been deprecated in favour of \"selfdestruct\""
+ );
+ }
+
return false;
}
diff --git a/libsolidity/analysis/TypeChecker.h b/libsolidity/analysis/TypeChecker.h
index c76fa466..ebfcdadc 100644
--- a/libsolidity/analysis/TypeChecker.h
+++ b/libsolidity/analysis/TypeChecker.h
@@ -22,20 +22,23 @@
#pragma once
-#include <libsolidity/interface/EVMVersion.h>
+#include <liblangutil/EVMVersion.h>
#include <libsolidity/ast/Types.h>
#include <libsolidity/ast/ASTAnnotations.h>
#include <libsolidity/ast/ASTForward.h>
#include <libsolidity/ast/ASTVisitor.h>
+namespace langutil
+{
+class ErrorReporter;
+}
+
namespace dev
{
namespace solidity
{
-class ErrorReporter;
-
/**
* The module that performs type analysis on the AST, checks the applicability of operations on
* those types and stores errors for invalid operations.
@@ -45,7 +48,7 @@ class TypeChecker: private ASTConstVisitor
{
public:
/// @param _errorReporter provides the error logging functionality.
- TypeChecker(EVMVersion _evmVersion, ErrorReporter& _errorReporter):
+ TypeChecker(EVMVersion _evmVersion, langutil::ErrorReporter& _errorReporter):
m_evmVersion(_evmVersion),
m_errorReporter(_errorReporter)
{}
@@ -62,28 +65,7 @@ public:
private:
- virtual bool visit(ContractDefinition const& _contract) override;
- /// Checks that two functions defined in this contract with the same name have different
- /// arguments and that there is at most one constructor.
- void checkContractDuplicateFunctions(ContractDefinition const& _contract);
- void checkContractDuplicateEvents(ContractDefinition const& _contract);
- void checkContractIllegalOverrides(ContractDefinition const& _contract);
- /// Reports a type error with an appropriate message if overridden function signature differs.
- /// Also stores the direct super function in the AST annotations.
- void checkFunctionOverride(FunctionDefinition const& function, FunctionDefinition const& super);
- void overrideError(FunctionDefinition const& function, FunctionDefinition const& super, std::string message);
- void checkContractAbstractFunctions(ContractDefinition const& _contract);
- void checkContractBaseConstructorArguments(ContractDefinition const& _contract);
- void annotateBaseConstructorArguments(
- ContractDefinition const& _currentContract,
- FunctionDefinition const* _baseConstructor,
- ASTNode const* _argumentNode
- );
- /// Checks that different functions with external visibility end up having different
- /// external argument types (i.e. different signature).
- void checkContractExternalTypeClashes(ContractDefinition const& _contract);
- /// Checks that all requirements for a library are fulfilled if this is a library.
- void checkLibraryRequirements(ContractDefinition const& _contract);
+ bool visit(ContractDefinition const& _contract) override;
/// Checks (and warns) if a tuple assignment might cause unexpected overwrites in storage.
/// Should only be called if the left hand side is tuple-typed.
void checkDoubleStorageAssignment(Assignment const& _assignment);
@@ -122,40 +104,37 @@ private:
FunctionTypePointer _functionType
);
- virtual void endVisit(InheritanceSpecifier const& _inheritance) override;
- virtual void endVisit(UsingForDirective const& _usingFor) override;
- virtual bool visit(StructDefinition const& _struct) override;
- virtual bool visit(FunctionDefinition const& _function) override;
- virtual bool visit(VariableDeclaration const& _variable) override;
+ void endVisit(InheritanceSpecifier const& _inheritance) override;
+ void endVisit(UsingForDirective const& _usingFor) override;
+ bool visit(StructDefinition const& _struct) override;
+ bool visit(FunctionDefinition const& _function) override;
+ bool visit(VariableDeclaration const& _variable) override;
/// We need to do this manually because we want to pass the bases of the current contract in
/// case this is a base constructor call.
void visitManually(ModifierInvocation const& _modifier, std::vector<ContractDefinition const*> const& _bases);
- virtual bool visit(EventDefinition const& _eventDef) override;
- virtual void endVisit(FunctionTypeName const& _funType) override;
- virtual bool visit(InlineAssembly const& _inlineAssembly) override;
- virtual bool visit(IfStatement const& _ifStatement) override;
- virtual bool visit(WhileStatement const& _whileStatement) override;
- virtual bool visit(ForStatement const& _forStatement) override;
- virtual void endVisit(Return const& _return) override;
- virtual bool visit(EmitStatement const&) override { m_insideEmitStatement = true; return true; }
- virtual void endVisit(EmitStatement const& _emit) override;
- virtual bool visit(VariableDeclarationStatement const& _variable) override;
- virtual void endVisit(ExpressionStatement const& _statement) override;
- virtual bool visit(Conditional const& _conditional) override;
- virtual bool visit(Assignment const& _assignment) override;
- virtual bool visit(TupleExpression const& _tuple) override;
- virtual void endVisit(BinaryOperation const& _operation) override;
- virtual bool visit(UnaryOperation const& _operation) override;
- virtual bool visit(FunctionCall const& _functionCall) override;
- virtual void endVisit(NewExpression const& _newExpression) override;
- virtual bool visit(MemberAccess const& _memberAccess) override;
- virtual bool visit(IndexAccess const& _indexAccess) override;
- virtual bool visit(Identifier const& _identifier) override;
- virtual void endVisit(ElementaryTypeNameExpression const& _expr) override;
- virtual void endVisit(Literal const& _literal) override;
-
- template <class T>
- void findDuplicateDefinitions(std::map<std::string, std::vector<T>> const& _definitions, std::string _message);
+ bool visit(EventDefinition const& _eventDef) override;
+ void endVisit(FunctionTypeName const& _funType) override;
+ bool visit(InlineAssembly const& _inlineAssembly) override;
+ bool visit(IfStatement const& _ifStatement) override;
+ bool visit(WhileStatement const& _whileStatement) override;
+ bool visit(ForStatement const& _forStatement) override;
+ void endVisit(Return const& _return) override;
+ bool visit(EmitStatement const&) override { m_insideEmitStatement = true; return true; }
+ void endVisit(EmitStatement const& _emit) override;
+ bool visit(VariableDeclarationStatement const& _variable) override;
+ void endVisit(ExpressionStatement const& _statement) override;
+ bool visit(Conditional const& _conditional) override;
+ bool visit(Assignment const& _assignment) override;
+ bool visit(TupleExpression const& _tuple) override;
+ void endVisit(BinaryOperation const& _operation) override;
+ bool visit(UnaryOperation const& _operation) override;
+ bool visit(FunctionCall const& _functionCall) override;
+ void endVisit(NewExpression const& _newExpression) override;
+ bool visit(MemberAccess const& _memberAccess) override;
+ bool visit(IndexAccess const& _indexAccess) override;
+ bool visit(Identifier const& _identifier) override;
+ void endVisit(ElementaryTypeNameExpression const& _expr) override;
+ void endVisit(Literal const& _literal) override;
bool contractDependenciesAreCyclic(
ContractDefinition const& _contract,
@@ -183,7 +162,7 @@ private:
/// Flag indicating whether we are currently inside a StructDefinition.
bool m_insideStruct = false;
- ErrorReporter& m_errorReporter;
+ langutil::ErrorReporter& m_errorReporter;
};
}
diff --git a/libsolidity/analysis/ViewPureChecker.cpp b/libsolidity/analysis/ViewPureChecker.cpp
index b0cacc43..1112d682 100644
--- a/libsolidity/analysis/ViewPureChecker.cpp
+++ b/libsolidity/analysis/ViewPureChecker.cpp
@@ -19,13 +19,16 @@
#include <libevmasm/SemanticInformation.h>
-#include <libsolidity/inlineasm/AsmData.h>
#include <libsolidity/ast/ExperimentalFeatures.h>
+#include <libyul/AsmData.h>
+
+#include <liblangutil/ErrorReporter.h>
#include <functional>
using namespace std;
using namespace dev;
+using namespace langutil;
using namespace dev::solidity;
namespace
@@ -37,48 +40,48 @@ public:
explicit AssemblyViewPureChecker(std::function<void(StateMutability, SourceLocation const&)> _reportMutability):
m_reportMutability(_reportMutability) {}
- void operator()(assembly::Label const&) { }
- void operator()(assembly::Instruction const& _instruction)
+ void operator()(yul::Label const&) { }
+ void operator()(yul::Instruction const& _instruction)
{
checkInstruction(_instruction.location, _instruction.instruction);
}
- void operator()(assembly::Literal const&) {}
- void operator()(assembly::Identifier const&) {}
- void operator()(assembly::FunctionalInstruction const& _instr)
+ void operator()(yul::Literal const&) {}
+ void operator()(yul::Identifier const&) {}
+ void operator()(yul::FunctionalInstruction const& _instr)
{
checkInstruction(_instr.location, _instr.instruction);
for (auto const& arg: _instr.arguments)
boost::apply_visitor(*this, arg);
}
- void operator()(assembly::ExpressionStatement const& _expr)
+ void operator()(yul::ExpressionStatement const& _expr)
{
boost::apply_visitor(*this, _expr.expression);
}
- void operator()(assembly::StackAssignment const&) {}
- void operator()(assembly::Assignment const& _assignment)
+ void operator()(yul::StackAssignment const&) {}
+ void operator()(yul::Assignment const& _assignment)
{
boost::apply_visitor(*this, *_assignment.value);
}
- void operator()(assembly::VariableDeclaration const& _varDecl)
+ void operator()(yul::VariableDeclaration const& _varDecl)
{
if (_varDecl.value)
boost::apply_visitor(*this, *_varDecl.value);
}
- void operator()(assembly::FunctionDefinition const& _funDef)
+ void operator()(yul::FunctionDefinition const& _funDef)
{
(*this)(_funDef.body);
}
- void operator()(assembly::FunctionCall const& _funCall)
+ void operator()(yul::FunctionCall const& _funCall)
{
for (auto const& arg: _funCall.arguments)
boost::apply_visitor(*this, arg);
}
- void operator()(assembly::If const& _if)
+ void operator()(yul::If const& _if)
{
boost::apply_visitor(*this, *_if.condition);
(*this)(_if.body);
}
- void operator()(assembly::Switch const& _switch)
+ void operator()(yul::Switch const& _switch)
{
boost::apply_visitor(*this, *_switch.expression);
for (auto const& _case: _switch.cases)
@@ -88,14 +91,14 @@ public:
(*this)(_case.body);
}
}
- void operator()(assembly::ForLoop const& _for)
+ void operator()(yul::ForLoop const& _for)
{
(*this)(_for.pre);
boost::apply_visitor(*this, *_for.condition);
(*this)(_for.body);
(*this)(_for.post);
}
- void operator()(assembly::Block const& _block)
+ void operator()(yul::Block const& _block)
{
for (auto const& s: _block.statements)
boost::apply_visitor(*this, s);
diff --git a/libsolidity/analysis/ViewPureChecker.h b/libsolidity/analysis/ViewPureChecker.h
index faa5b698..fd2432a7 100644
--- a/libsolidity/analysis/ViewPureChecker.h
+++ b/libsolidity/analysis/ViewPureChecker.h
@@ -21,11 +21,15 @@
#include <libsolidity/ast/ASTForward.h>
#include <libsolidity/ast/ASTVisitor.h>
-#include <libsolidity/interface/ErrorReporter.h>
-
#include <map>
#include <memory>
+namespace langutil
+{
+class ErrorReporter;
+struct SourceLocation;
+}
+
namespace dev
{
namespace solidity
@@ -34,7 +38,7 @@ namespace solidity
class ViewPureChecker: private ASTConstVisitor
{
public:
- ViewPureChecker(std::vector<std::shared_ptr<ASTNode>> const& _ast, ErrorReporter& _errorReporter):
+ ViewPureChecker(std::vector<std::shared_ptr<ASTNode>> const& _ast, langutil::ErrorReporter& _errorReporter):
m_ast(_ast), m_errorReporter(_errorReporter) {}
bool check();
@@ -43,34 +47,34 @@ private:
struct MutabilityAndLocation
{
StateMutability mutability;
- SourceLocation location;
+ langutil::SourceLocation location;
};
- virtual bool visit(FunctionDefinition const& _funDef) override;
- virtual void endVisit(FunctionDefinition const& _funDef) override;
- virtual bool visit(ModifierDefinition const& _modifierDef) override;
- virtual void endVisit(ModifierDefinition const& _modifierDef) override;
- virtual void endVisit(Identifier const& _identifier) override;
- virtual bool visit(MemberAccess const& _memberAccess) override;
- virtual void endVisit(MemberAccess const& _memberAccess) override;
- virtual void endVisit(IndexAccess const& _indexAccess) override;
- virtual void endVisit(ModifierInvocation const& _modifier) override;
- virtual void endVisit(FunctionCall const& _functionCall) override;
- virtual void endVisit(InlineAssembly const& _inlineAssembly) override;
+ bool visit(FunctionDefinition const& _funDef) override;
+ void endVisit(FunctionDefinition const& _funDef) override;
+ bool visit(ModifierDefinition const& _modifierDef) override;
+ void endVisit(ModifierDefinition const& _modifierDef) override;
+ void endVisit(Identifier const& _identifier) override;
+ bool visit(MemberAccess const& _memberAccess) override;
+ void endVisit(MemberAccess const& _memberAccess) override;
+ void endVisit(IndexAccess const& _indexAccess) override;
+ void endVisit(ModifierInvocation const& _modifier) override;
+ void endVisit(FunctionCall const& _functionCall) override;
+ void endVisit(InlineAssembly const& _inlineAssembly) override;
/// Called when an element of mutability @a _mutability is encountered.
/// Creates appropriate warnings and errors and sets @a m_currentBestMutability.
void reportMutability(
StateMutability _mutability,
- SourceLocation const& _location,
- boost::optional<SourceLocation> const& _nestedLocation = {}
+ langutil::SourceLocation const& _location,
+ boost::optional<langutil::SourceLocation> const& _nestedLocation = {}
);
std::vector<std::shared_ptr<ASTNode>> const& m_ast;
- ErrorReporter& m_errorReporter;
+ langutil::ErrorReporter& m_errorReporter;
bool m_errors = false;
- MutabilityAndLocation m_bestMutabilityAndLocation = MutabilityAndLocation{StateMutability::Payable, SourceLocation()};
+ MutabilityAndLocation m_bestMutabilityAndLocation = MutabilityAndLocation{StateMutability::Payable, langutil::SourceLocation()};
FunctionDefinition const* m_currentFunction = nullptr;
std::map<ModifierDefinition const*, MutabilityAndLocation> m_inferredMutability;
};
diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h
index 4fd2bcb8..2f418b09 100644
--- a/libsolidity/ast/AST.h
+++ b/libsolidity/ast/AST.h
@@ -23,13 +23,13 @@
#pragma once
-#include <libsolidity/ast/ASTForward.h>
#include <libsolidity/parsing/Token.h>
+#include <libsolidity/ast/ASTForward.h>
#include <libsolidity/ast/Types.h>
#include <libsolidity/ast/ASTAnnotations.h>
#include <libsolidity/ast/ASTEnums.h>
-#include <libevmasm/SourceLocation.h>
+#include <liblangutil/SourceLocation.h>
#include <libevmasm/Instruction.h>
#include <libdevcore/FixedHash.h>
@@ -41,6 +41,12 @@
#include <vector>
#include <memory>
+namespace yul
+{
+// Forward-declaration to <yul/AsmData.h>
+struct Block;
+}
+
namespace dev
{
namespace solidity
@@ -58,6 +64,8 @@ class ASTConstVisitor;
class ASTNode: private boost::noncopyable
{
public:
+ using SourceLocation = langutil::SourceLocation;
+
explicit ASTNode(SourceLocation const& _location);
virtual ~ASTNode();
@@ -126,9 +134,9 @@ public:
SourceUnit(SourceLocation const& _location, std::vector<ASTPointer<ASTNode>> const& _nodes):
ASTNode(_location), m_nodes(_nodes) {}
- virtual void accept(ASTVisitor& _visitor) override;
- virtual void accept(ASTConstVisitor& _visitor) const override;
- virtual SourceUnitAnnotation& annotation() const override;
+ void accept(ASTVisitor& _visitor) override;
+ void accept(ASTConstVisitor& _visitor) const override;
+ SourceUnitAnnotation& annotation() const override;
std::vector<ASTPointer<ASTNode>> nodes() const { return m_nodes; }
@@ -242,8 +250,8 @@ public:
): ASTNode(_location), m_tokens(_tokens), m_literals(_literals)
{}
- virtual void accept(ASTVisitor& _visitor) override;
- virtual void accept(ASTConstVisitor& _visitor) const override;
+ void accept(ASTVisitor& _visitor) override;
+ void accept(ASTConstVisitor& _visitor) const override;
std::vector<Token> const& tokens() const { return m_tokens; }
std::vector<ASTString> const& literals() const { return m_literals; }
@@ -279,17 +287,17 @@ public:
m_symbolAliases(_symbolAliases)
{ }
- virtual void accept(ASTVisitor& _visitor) override;
- virtual void accept(ASTConstVisitor& _visitor) const override;
+ void accept(ASTVisitor& _visitor) override;
+ void accept(ASTConstVisitor& _visitor) const override;
ASTString const& path() const { return *m_path; }
std::vector<std::pair<ASTPointer<Identifier>, ASTPointer<ASTString>>> const& symbolAliases() const
{
return m_symbolAliases;
}
- virtual ImportAnnotation& annotation() const override;
+ ImportAnnotation& annotation() const override;
- virtual TypePointer type() const override;
+ TypePointer type() const override;
private:
ASTPointer<ASTString> m_path;
@@ -375,8 +383,8 @@ public:
m_contractKind(_contractKind)
{}
- virtual void accept(ASTVisitor& _visitor) override;
- virtual void accept(ASTConstVisitor& _visitor) const override;
+ void accept(ASTVisitor& _visitor) override;
+ void accept(ASTConstVisitor& _visitor) const override;
std::vector<ASTPointer<InheritanceSpecifier>> const& baseContracts() const { return m_baseContracts; }
std::vector<ASTPointer<ASTNode>> const& subNodes() const { return m_subNodes; }
@@ -407,9 +415,9 @@ public:
std::string fullyQualifiedName() const { return sourceUnitName() + ":" + name(); }
- virtual TypePointer type() const override;
+ TypePointer type() const override;
- virtual ContractDefinitionAnnotation& annotation() const override;
+ ContractDefinitionAnnotation& annotation() const override;
ContractKind contractKind() const { return m_contractKind; }
@@ -434,8 +442,8 @@ public:
):
ASTNode(_location), m_baseName(_baseName), m_arguments(std::move(_arguments)) {}
- virtual void accept(ASTVisitor& _visitor) override;
- virtual void accept(ASTConstVisitor& _visitor) const override;
+ void accept(ASTVisitor& _visitor) override;
+ void accept(ASTConstVisitor& _visitor) const override;
UserDefinedTypeName const& name() const { return *m_baseName; }
// Returns nullptr if no argument list was given (``C``).
@@ -463,8 +471,8 @@ public:
):
ASTNode(_location), m_libraryName(_libraryName), m_typeName(_typeName) {}
- virtual void accept(ASTVisitor& _visitor) override;
- virtual void accept(ASTConstVisitor& _visitor) const override;
+ void accept(ASTVisitor& _visitor) override;
+ void accept(ASTConstVisitor& _visitor) const override;
UserDefinedTypeName const& libraryName() const { return *m_libraryName; }
/// @returns the type name the library is attached to, null for `*`.
@@ -485,14 +493,14 @@ public:
):
Declaration(_location, _name), m_members(_members) {}
- virtual void accept(ASTVisitor& _visitor) override;
- virtual void accept(ASTConstVisitor& _visitor) const override;
+ void accept(ASTVisitor& _visitor) override;
+ void accept(ASTConstVisitor& _visitor) const override;
std::vector<ASTPointer<VariableDeclaration>> const& members() const { return m_members; }
- virtual TypePointer type() const override;
+ TypePointer type() const override;
- virtual TypeDeclarationAnnotation& annotation() const override;
+ TypeDeclarationAnnotation& annotation() const override;
private:
std::vector<ASTPointer<VariableDeclaration>> m_members;
@@ -507,14 +515,14 @@ public:
std::vector<ASTPointer<EnumValue>> const& _members
):
Declaration(_location, _name), m_members(_members) {}
- virtual void accept(ASTVisitor& _visitor) override;
- virtual void accept(ASTConstVisitor& _visitor) const override;
+ void accept(ASTVisitor& _visitor) override;
+ void accept(ASTConstVisitor& _visitor) const override;
std::vector<ASTPointer<EnumValue>> const& members() const { return m_members; }
- virtual TypePointer type() const override;
+ TypePointer type() const override;
- virtual TypeDeclarationAnnotation& annotation() const override;
+ TypeDeclarationAnnotation& annotation() const override;
private:
std::vector<ASTPointer<EnumValue>> m_members;
@@ -529,10 +537,10 @@ public:
EnumValue(SourceLocation const& _location, ASTPointer<ASTString> const& _name):
Declaration(_location, _name) {}
- virtual void accept(ASTVisitor& _visitor) override;
- virtual void accept(ASTConstVisitor& _visitor) const override;
+ void accept(ASTVisitor& _visitor) override;
+ void accept(ASTConstVisitor& _visitor) const override;
- virtual TypePointer type() const override;
+ TypePointer type() const override;
};
/**
@@ -548,8 +556,8 @@ public:
std::vector<ASTPointer<VariableDeclaration>> const& _parameters
):
ASTNode(_location), m_parameters(_parameters) {}
- virtual void accept(ASTVisitor& _visitor) override;
- virtual void accept(ASTConstVisitor& _visitor) const override;
+ void accept(ASTVisitor& _visitor) override;
+ void accept(ASTConstVisitor& _visitor) const override;
std::vector<ASTPointer<VariableDeclaration>> const& parameters() const { return m_parameters; }
@@ -610,8 +618,8 @@ public:
m_body(_body)
{}
- virtual void accept(ASTVisitor& _visitor) override;
- virtual void accept(ASTConstVisitor& _visitor) const override;
+ void accept(ASTVisitor& _visitor) override;
+ void accept(ASTConstVisitor& _visitor) const override;
StateMutability stateMutability() const { return m_stateMutability; }
bool isConstructor() const { return m_isConstructor; }
@@ -620,11 +628,11 @@ public:
std::vector<ASTPointer<ModifierInvocation>> const& modifiers() const { return m_functionModifiers; }
std::vector<ASTPointer<VariableDeclaration>> const& returnParameters() const { return m_returnParameters->parameters(); }
Block const& body() const { solAssert(m_body, ""); return *m_body; }
- virtual bool isVisibleInContract() const override
+ bool isVisibleInContract() const override
{
return Declaration::isVisibleInContract() && !isConstructor() && !isFallback();
}
- virtual bool isPartOfExternalInterface() const override { return isPublic() && !isConstructor() && !isFallback(); }
+ bool isPartOfExternalInterface() const override { return isPublic() && !isConstructor() && !isFallback(); }
/// @returns the external signature of the function
/// That consists of the name of the function followed by the types of the
@@ -633,13 +641,13 @@ public:
ContractDefinition::ContractKind inContractKind() const;
- virtual TypePointer type() const override;
+ TypePointer type() const override;
/// @param _internal false indicates external interface is concerned, true indicates internal interface is concerned.
/// @returns null when it is not accessible as a function.
- virtual FunctionTypePointer functionType(bool /*_internal*/) const override;
+ FunctionTypePointer functionType(bool /*_internal*/) const override;
- virtual FunctionDefinitionAnnotation& annotation() const override;
+ FunctionDefinitionAnnotation& annotation() const override;
private:
StateMutability m_stateMutability;
@@ -676,14 +684,14 @@ public:
m_isConstant(_isConstant),
m_location(_referenceLocation) {}
- virtual void accept(ASTVisitor& _visitor) override;
- virtual void accept(ASTConstVisitor& _visitor) const override;
+ void accept(ASTVisitor& _visitor) override;
+ void accept(ASTConstVisitor& _visitor) const override;
TypeName* typeName() const { return m_typeName.get(); }
ASTPointer<Expression> const& value() const { return m_value; }
- virtual bool isLValue() const override;
- virtual bool isPartOfExternalInterface() const override { return isPublic(); }
+ bool isLValue() const override;
+ bool isPartOfExternalInterface() const override { return isPublic(); }
/// @returns true iff this variable is the parameter (or return parameter) of a function
/// (or function type name or event) or declared inside a function body.
@@ -717,13 +725,13 @@ public:
/// @returns a set of allowed storage locations for the variable.
std::set<Location> allowedDataLocations() const;
- virtual TypePointer type() const override;
+ TypePointer type() const override;
/// @param _internal false indicates external interface is concerned, true indicates internal interface is concerned.
/// @returns null when it is not accessible as a function.
- virtual FunctionTypePointer functionType(bool /*_internal*/) const override;
+ FunctionTypePointer functionType(bool /*_internal*/) const override;
- virtual VariableDeclarationAnnotation& annotation() const override;
+ VariableDeclarationAnnotation& annotation() const override;
protected:
Visibility defaultVisibility() const override { return Visibility::Internal; }
@@ -758,14 +766,14 @@ public:
{
}
- virtual void accept(ASTVisitor& _visitor) override;
- virtual void accept(ASTConstVisitor& _visitor) const override;
+ void accept(ASTVisitor& _visitor) override;
+ void accept(ASTConstVisitor& _visitor) const override;
Block const& body() const { return *m_body; }
- virtual TypePointer type() const override;
+ TypePointer type() const override;
- virtual ModifierDefinitionAnnotation& annotation() const override;
+ ModifierDefinitionAnnotation& annotation() const override;
private:
ASTPointer<Block> m_body;
@@ -784,8 +792,8 @@ public:
):
ASTNode(_location), m_modifierName(_name), m_arguments(std::move(_arguments)) {}
- virtual void accept(ASTVisitor& _visitor) override;
- virtual void accept(ASTConstVisitor& _visitor) const override;
+ void accept(ASTVisitor& _visitor) override;
+ void accept(ASTConstVisitor& _visitor) const override;
ASTPointer<Identifier> const& name() const { return m_modifierName; }
// Returns nullptr if no argument list was given (``mod``).
@@ -817,15 +825,15 @@ public:
{
}
- virtual void accept(ASTVisitor& _visitor) override;
- virtual void accept(ASTConstVisitor& _visitor) const override;
+ void accept(ASTVisitor& _visitor) override;
+ void accept(ASTConstVisitor& _visitor) const override;
bool isAnonymous() const { return m_anonymous; }
- virtual TypePointer type() const override;
- virtual FunctionTypePointer functionType(bool /*_internal*/) const override;
+ TypePointer type() const override;
+ FunctionTypePointer functionType(bool /*_internal*/) const override;
- virtual EventDefinitionAnnotation& annotation() const override;
+ EventDefinitionAnnotation& annotation() const override;
private:
bool m_anonymous = false;
@@ -840,21 +848,21 @@ class MagicVariableDeclaration: public Declaration
public:
MagicVariableDeclaration(ASTString const& _name, std::shared_ptr<Type const> const& _type):
Declaration(SourceLocation(), std::make_shared<ASTString>(_name)), m_type(_type) {}
- virtual void accept(ASTVisitor&) override
+ void accept(ASTVisitor&) override
{
solAssert(false, "MagicVariableDeclaration used inside real AST.");
}
- virtual void accept(ASTConstVisitor&) const override
+ void accept(ASTConstVisitor&) const override
{
solAssert(false, "MagicVariableDeclaration used inside real AST.");
}
- virtual FunctionTypePointer functionType(bool) const override
+ FunctionTypePointer functionType(bool) const override
{
solAssert(m_type->category() == Type::Category::Function, "");
return std::dynamic_pointer_cast<FunctionType const>(m_type);
}
- virtual TypePointer type() const override { return m_type; }
+ TypePointer type() const override { return m_type; }
private:
std::shared_ptr<Type const> m_type;
@@ -872,7 +880,7 @@ protected:
explicit TypeName(SourceLocation const& _location): ASTNode(_location) {}
public:
- virtual TypeNameAnnotation& annotation() const override;
+ TypeNameAnnotation& annotation() const override;
};
/**
@@ -891,8 +899,8 @@ public:
solAssert(!_stateMutability.is_initialized() || _elem.token() == Token::Address, "");
}
- virtual void accept(ASTVisitor& _visitor) override;
- virtual void accept(ASTConstVisitor& _visitor) const override;
+ void accept(ASTVisitor& _visitor) override;
+ void accept(ASTConstVisitor& _visitor) const override;
ElementaryTypeNameToken const& typeName() const { return m_type; }
@@ -911,12 +919,12 @@ class UserDefinedTypeName: public TypeName
public:
UserDefinedTypeName(SourceLocation const& _location, std::vector<ASTString> const& _namePath):
TypeName(_location), m_namePath(_namePath) {}
- virtual void accept(ASTVisitor& _visitor) override;
- virtual void accept(ASTConstVisitor& _visitor) const override;
+ void accept(ASTVisitor& _visitor) override;
+ void accept(ASTConstVisitor& _visitor) const override;
std::vector<ASTString> const& namePath() const { return m_namePath; }
- virtual UserDefinedTypeNameAnnotation& annotation() const override;
+ UserDefinedTypeNameAnnotation& annotation() const override;
private:
std::vector<ASTString> m_namePath;
@@ -938,8 +946,8 @@ public:
TypeName(_location), m_parameterTypes(_parameterTypes), m_returnTypes(_returnTypes),
m_visibility(_visibility), m_stateMutability(_stateMutability)
{}
- virtual void accept(ASTVisitor& _visitor) override;
- virtual void accept(ASTConstVisitor& _visitor) const override;
+ void accept(ASTVisitor& _visitor) override;
+ void accept(ASTConstVisitor& _visitor) const override;
std::vector<ASTPointer<VariableDeclaration>> const& parameterTypes() const { return m_parameterTypes->parameters(); }
std::vector<ASTPointer<VariableDeclaration>> const& returnParameterTypes() const { return m_returnTypes->parameters(); }
@@ -972,8 +980,8 @@ public:
ASTPointer<TypeName> const& _valueType
):
TypeName(_location), m_keyType(_keyType), m_valueType(_valueType) {}
- virtual void accept(ASTVisitor& _visitor) override;
- virtual void accept(ASTConstVisitor& _visitor) const override;
+ void accept(ASTVisitor& _visitor) override;
+ void accept(ASTConstVisitor& _visitor) const override;
ElementaryTypeName const& keyType() const { return *m_keyType; }
TypeName const& valueType() const { return *m_valueType; }
@@ -995,8 +1003,8 @@ public:
ASTPointer<Expression> const& _length
):
TypeName(_location), m_baseType(_baseType), m_length(_length) {}
- virtual void accept(ASTVisitor& _visitor) override;
- virtual void accept(ASTConstVisitor& _visitor) const override;
+ void accept(ASTVisitor& _visitor) override;
+ void accept(ASTConstVisitor& _visitor) const override;
TypeName const& baseType() const { return *m_baseType; }
Expression const* length() const { return m_length.get(); }
@@ -1023,15 +1031,9 @@ public:
ASTPointer<ASTString> const& _docString
): ASTNode(_location), Documented(_docString) {}
- virtual StatementAnnotation& annotation() const override;
+ StatementAnnotation& annotation() const override;
};
-namespace assembly
-{
-// Forward-declaration to AsmData.h
-struct Block;
-}
-
/**
* Inline assembly.
*/
@@ -1041,18 +1043,18 @@ public:
InlineAssembly(
SourceLocation const& _location,
ASTPointer<ASTString> const& _docString,
- std::shared_ptr<assembly::Block> const& _operations
+ std::shared_ptr<yul::Block> const& _operations
):
Statement(_location, _docString), m_operations(_operations) {}
- virtual void accept(ASTVisitor& _visitor) override;
- virtual void accept(ASTConstVisitor& _visitor) const override;
+ void accept(ASTVisitor& _visitor) override;
+ void accept(ASTConstVisitor& _visitor) const override;
- assembly::Block const& operations() const { return *m_operations; }
+ yul::Block const& operations() const { return *m_operations; }
- virtual InlineAssemblyAnnotation& annotation() const override;
+ InlineAssemblyAnnotation& annotation() const override;
private:
- std::shared_ptr<assembly::Block> m_operations;
+ std::shared_ptr<yul::Block> m_operations;
};
/**
@@ -1067,8 +1069,8 @@ public:
std::vector<ASTPointer<Statement>> const& _statements
):
Statement(_location, _docString), m_statements(_statements) {}
- virtual void accept(ASTVisitor& _visitor) override;
- virtual void accept(ASTConstVisitor& _visitor) const override;
+ void accept(ASTVisitor& _visitor) override;
+ void accept(ASTConstVisitor& _visitor) const override;
std::vector<ASTPointer<Statement>> const& statements() const { return m_statements; }
@@ -1088,8 +1090,8 @@ public:
ASTPointer<ASTString> const& _docString
): Statement(_location, _docString) {}
- virtual void accept(ASTVisitor& _visitor) override;
- virtual void accept(ASTConstVisitor& _visitor) const override;
+ void accept(ASTVisitor& _visitor) override;
+ void accept(ASTConstVisitor& _visitor) const override;
};
/**
@@ -1111,8 +1113,8 @@ public:
m_trueBody(_trueBody),
m_falseBody(_falseBody)
{}
- virtual void accept(ASTVisitor& _visitor) override;
- virtual void accept(ASTConstVisitor& _visitor) const override;
+ void accept(ASTVisitor& _visitor) override;
+ void accept(ASTConstVisitor& _visitor) const override;
Expression const& condition() const { return *m_condition; }
Statement const& trueStatement() const { return *m_trueBody; }
@@ -1149,8 +1151,8 @@ public:
):
BreakableStatement(_location, _docString), m_condition(_condition), m_body(_body),
m_isDoWhile(_isDoWhile) {}
- virtual void accept(ASTVisitor& _visitor) override;
- virtual void accept(ASTConstVisitor& _visitor) const override;
+ void accept(ASTVisitor& _visitor) override;
+ void accept(ASTConstVisitor& _visitor) const override;
Expression const& condition() const { return *m_condition; }
Statement const& body() const { return *m_body; }
@@ -1182,8 +1184,8 @@ public:
m_loopExpression(_loopExpression),
m_body(_body)
{}
- virtual void accept(ASTVisitor& _visitor) override;
- virtual void accept(ASTConstVisitor& _visitor) const override;
+ void accept(ASTVisitor& _visitor) override;
+ void accept(ASTConstVisitor& _visitor) const override;
Statement const* initializationExpression() const { return m_initExpression.get(); }
Expression const* condition() const { return m_condExpression.get(); }
@@ -1206,8 +1208,8 @@ class Continue: public Statement
public:
explicit Continue(SourceLocation const& _location, ASTPointer<ASTString> const& _docString):
Statement(_location, _docString) {}
- virtual void accept(ASTVisitor& _visitor) override;
- virtual void accept(ASTConstVisitor& _visitor) const override;
+ void accept(ASTVisitor& _visitor) override;
+ void accept(ASTConstVisitor& _visitor) const override;
};
class Break: public Statement
@@ -1215,8 +1217,8 @@ class Break: public Statement
public:
explicit Break(SourceLocation const& _location, ASTPointer<ASTString> const& _docString):
Statement(_location, _docString) {}
- virtual void accept(ASTVisitor& _visitor) override;
- virtual void accept(ASTConstVisitor& _visitor) const override;
+ void accept(ASTVisitor& _visitor) override;
+ void accept(ASTConstVisitor& _visitor) const override;
};
class Return: public Statement
@@ -1227,12 +1229,12 @@ public:
ASTPointer<ASTString> const& _docString,
ASTPointer<Expression> _expression
): Statement(_location, _docString), m_expression(_expression) {}
- virtual void accept(ASTVisitor& _visitor) override;
- virtual void accept(ASTConstVisitor& _visitor) const override;
+ void accept(ASTVisitor& _visitor) override;
+ void accept(ASTConstVisitor& _visitor) const override;
Expression const* expression() const { return m_expression.get(); }
- virtual ReturnAnnotation& annotation() const override;
+ ReturnAnnotation& annotation() const override;
private:
ASTPointer<Expression> m_expression; ///< value to return, optional
@@ -1246,8 +1248,8 @@ class Throw: public Statement
public:
explicit Throw(SourceLocation const& _location, ASTPointer<ASTString> const& _docString):
Statement(_location, _docString) {}
- virtual void accept(ASTVisitor& _visitor) override;
- virtual void accept(ASTConstVisitor& _visitor) const override;
+ void accept(ASTVisitor& _visitor) override;
+ void accept(ASTConstVisitor& _visitor) const override;
};
/**
@@ -1262,8 +1264,8 @@ public:
ASTPointer<FunctionCall> const& _functionCall
):
Statement(_location, _docString), m_eventCall(_functionCall) {}
- virtual void accept(ASTVisitor& _visitor) override;
- virtual void accept(ASTConstVisitor& _visitor) const override;
+ void accept(ASTVisitor& _visitor) override;
+ void accept(ASTConstVisitor& _visitor) const override;
FunctionCall const& eventCall() const { return *m_eventCall; }
@@ -1289,8 +1291,8 @@ public:
ASTPointer<Expression> const& _initialValue
):
Statement(_location, _docString), m_variables(_variables), m_initialValue(_initialValue) {}
- virtual void accept(ASTVisitor& _visitor) override;
- virtual void accept(ASTConstVisitor& _visitor) const override;
+ void accept(ASTVisitor& _visitor) override;
+ void accept(ASTConstVisitor& _visitor) const override;
std::vector<ASTPointer<VariableDeclaration>> const& declarations() const { return m_variables; }
Expression const* initialValue() const { return m_initialValue.get(); }
@@ -1317,8 +1319,8 @@ public:
ASTPointer<Expression> _expression
):
Statement(_location, _docString), m_expression(_expression) {}
- virtual void accept(ASTVisitor& _visitor) override;
- virtual void accept(ASTConstVisitor& _visitor) const override;
+ void accept(ASTVisitor& _visitor) override;
+ void accept(ASTConstVisitor& _visitor) const override;
Expression const& expression() const { return *m_expression; }
@@ -1358,8 +1360,8 @@ public:
m_trueExpression(_trueExpression),
m_falseExpression(_falseExpression)
{}
- virtual void accept(ASTVisitor& _visitor) override;
- virtual void accept(ASTConstVisitor& _visitor) const override;
+ void accept(ASTVisitor& _visitor) override;
+ void accept(ASTConstVisitor& _visitor) const override;
Expression const& condition() const { return *m_condition; }
Expression const& trueExpression() const { return *m_trueExpression; }
@@ -1389,8 +1391,8 @@ public:
{
solAssert(TokenTraits::isAssignmentOp(_assignmentOperator), "");
}
- virtual void accept(ASTVisitor& _visitor) override;
- virtual void accept(ASTConstVisitor& _visitor) const override;
+ void accept(ASTVisitor& _visitor) override;
+ void accept(ASTConstVisitor& _visitor) const override;
Expression const& leftHandSide() const { return *m_leftHandSide; }
Token assignmentOperator() const { return m_assigmentOperator; }
@@ -1421,8 +1423,8 @@ public:
Expression(_location),
m_components(_components),
m_isArray(_isArray) {}
- virtual void accept(ASTVisitor& _visitor) override;
- virtual void accept(ASTConstVisitor& _visitor) const override;
+ void accept(ASTVisitor& _visitor) override;
+ void accept(ASTConstVisitor& _visitor) const override;
std::vector<ASTPointer<Expression>> const& components() const { return m_components; }
bool isInlineArray() const { return m_isArray; }
@@ -1452,8 +1454,8 @@ public:
{
solAssert(TokenTraits::isUnaryOp(_operator), "");
}
- virtual void accept(ASTVisitor& _visitor) override;
- virtual void accept(ASTConstVisitor& _visitor) const override;
+ void accept(ASTVisitor& _visitor) override;
+ void accept(ASTConstVisitor& _visitor) const override;
Token getOperator() const { return m_operator; }
bool isPrefixOperation() const { return m_isPrefix; }
@@ -1482,8 +1484,8 @@ public:
{
solAssert(TokenTraits::isBinaryOp(_operator) || TokenTraits::isCompareOp(_operator), "");
}
- virtual void accept(ASTVisitor& _visitor) override;
- virtual void accept(ASTConstVisitor& _visitor) const override;
+ void accept(ASTVisitor& _visitor) override;
+ void accept(ASTConstVisitor& _visitor) const override;
Expression const& leftExpression() const { return *m_left; }
Expression const& rightExpression() const { return *m_right; }
@@ -1510,14 +1512,14 @@ public:
std::vector<ASTPointer<ASTString>> const& _names
):
Expression(_location), m_expression(_expression), m_arguments(_arguments), m_names(_names) {}
- virtual void accept(ASTVisitor& _visitor) override;
- virtual void accept(ASTConstVisitor& _visitor) const override;
+ void accept(ASTVisitor& _visitor) override;
+ void accept(ASTConstVisitor& _visitor) const override;
Expression const& expression() const { return *m_expression; }
std::vector<ASTPointer<Expression const>> arguments() const { return {m_arguments.begin(), m_arguments.end()}; }
std::vector<ASTPointer<ASTString>> const& names() const { return m_names; }
- virtual FunctionCallAnnotation& annotation() const override;
+ FunctionCallAnnotation& annotation() const override;
private:
ASTPointer<Expression> m_expression;
@@ -1537,8 +1539,8 @@ public:
ASTPointer<TypeName> const& _typeName
):
Expression(_location), m_typeName(_typeName) {}
- virtual void accept(ASTVisitor& _visitor) override;
- virtual void accept(ASTConstVisitor& _visitor) const override;
+ void accept(ASTVisitor& _visitor) override;
+ void accept(ASTConstVisitor& _visitor) const override;
TypeName const& typeName() const { return *m_typeName; }
@@ -1558,12 +1560,12 @@ public:
ASTPointer<ASTString> const& _memberName
):
Expression(_location), m_expression(_expression), m_memberName(_memberName) {}
- virtual void accept(ASTVisitor& _visitor) override;
- virtual void accept(ASTConstVisitor& _visitor) const override;
+ void accept(ASTVisitor& _visitor) override;
+ void accept(ASTConstVisitor& _visitor) const override;
Expression const& expression() const { return *m_expression; }
ASTString const& memberName() const { return *m_memberName; }
- virtual MemberAccessAnnotation& annotation() const override;
+ MemberAccessAnnotation& annotation() const override;
private:
ASTPointer<Expression> m_expression;
@@ -1582,8 +1584,8 @@ public:
ASTPointer<Expression> const& _index
):
Expression(_location), m_base(_base), m_index(_index) {}
- virtual void accept(ASTVisitor& _visitor) override;
- virtual void accept(ASTConstVisitor& _visitor) const override;
+ void accept(ASTVisitor& _visitor) override;
+ void accept(ASTConstVisitor& _visitor) const override;
Expression const& baseExpression() const { return *m_base; }
Expression const* indexExpression() const { return m_index.get(); }
@@ -1614,12 +1616,12 @@ public:
ASTPointer<ASTString> const& _name
):
PrimaryExpression(_location), m_name(_name) {}
- virtual void accept(ASTVisitor& _visitor) override;
- virtual void accept(ASTConstVisitor& _visitor) const override;
+ void accept(ASTVisitor& _visitor) override;
+ void accept(ASTConstVisitor& _visitor) const override;
ASTString const& name() const { return *m_name; }
- virtual IdentifierAnnotation& annotation() const override;
+ IdentifierAnnotation& annotation() const override;
private:
ASTPointer<ASTString> m_name;
@@ -1636,8 +1638,8 @@ public:
ElementaryTypeNameExpression(SourceLocation const& _location, ElementaryTypeNameToken const& _type):
PrimaryExpression(_location), m_typeToken(_type)
{}
- virtual void accept(ASTVisitor& _visitor) override;
- virtual void accept(ASTConstVisitor& _visitor) const override;
+ void accept(ASTVisitor& _visitor) override;
+ void accept(ASTConstVisitor& _visitor) const override;
ElementaryTypeNameToken const& typeName() const { return m_typeToken; }
@@ -1672,8 +1674,8 @@ public:
SubDenomination _sub = SubDenomination::None
):
PrimaryExpression(_location), m_token(_token), m_value(_value), m_subDenomination(_sub) {}
- virtual void accept(ASTVisitor& _visitor) override;
- virtual void accept(ASTConstVisitor& _visitor) const override;
+ void accept(ASTVisitor& _visitor) override;
+ void accept(ASTConstVisitor& _visitor) const override;
Token token() const { return m_token; }
/// @returns the non-parsed value of the literal
diff --git a/libsolidity/ast/ASTAnnotations.h b/libsolidity/ast/ASTAnnotations.h
index e0b3f492..e9cc905e 100644
--- a/libsolidity/ast/ASTAnnotations.h
+++ b/libsolidity/ast/ASTAnnotations.h
@@ -30,6 +30,12 @@
#include <vector>
#include <set>
+namespace yul
+{
+ struct AsmAnalysisInfo;
+ struct Identifier;
+}
+
namespace dev
{
namespace solidity
@@ -120,12 +126,6 @@ struct StatementAnnotation: ASTAnnotation, DocumentedAnnotation
{
};
-namespace assembly
-{
- struct AsmAnalysisInfo;
- struct Identifier;
-}
-
struct InlineAssemblyAnnotation: StatementAnnotation
{
struct ExternalIdentifierInfo
@@ -137,9 +137,9 @@ struct InlineAssemblyAnnotation: StatementAnnotation
};
/// Mapping containing resolved references to external identifiers and their value size
- std::map<assembly::Identifier const*, ExternalIdentifierInfo> externalReferences;
+ std::map<yul::Identifier const*, ExternalIdentifierInfo> externalReferences;
/// Information generated during analysis phase.
- std::shared_ptr<assembly::AsmAnalysisInfo> analysisInfo;
+ std::shared_ptr<yul::AsmAnalysisInfo> analysisInfo;
};
struct ReturnAnnotation: StatementAnnotation
diff --git a/libsolidity/ast/ASTEnums.h b/libsolidity/ast/ASTEnums.h
index 5ba21907..d47a5f05 100644
--- a/libsolidity/ast/ASTEnums.h
+++ b/libsolidity/ast/ASTEnums.h
@@ -21,7 +21,7 @@
#pragma once
-#include <libsolidity/interface/Exceptions.h>
+#include <liblangutil/Exceptions.h>
#include <string>
diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp
index 2d26ce8a..cfb13271 100644
--- a/libsolidity/ast/ASTJsonConverter.cpp
+++ b/libsolidity/ast/ASTJsonConverter.cpp
@@ -23,10 +23,11 @@
#include <boost/algorithm/string/join.hpp>
#include <libdevcore/UTF8.h>
#include <libsolidity/ast/AST.h>
-#include <libsolidity/inlineasm/AsmData.h>
-#include <libsolidity/inlineasm/AsmPrinter.h>
+#include <libyul/AsmData.h>
+#include <libyul/AsmPrinter.h>
using namespace std;
+using namespace langutil;
namespace dev
{
@@ -121,8 +122,8 @@ void ASTJsonConverter::setJsonNode(
string ASTJsonConverter::sourceLocationToString(SourceLocation const& _location) const
{
int sourceIndex{-1};
- if (_location.sourceName && m_sourceIndices.count(*_location.sourceName))
- sourceIndex = m_sourceIndices.at(*_location.sourceName);
+ if (_location.source && m_sourceIndices.count(_location.source->name()))
+ sourceIndex = m_sourceIndices.at(_location.source->name());
int length = -1;
if (_location.start >= 0 && _location.end >= 0)
length = _location.end - _location.start;
@@ -171,7 +172,7 @@ void ASTJsonConverter::appendExpressionAttributes(
_attributes += exprAttributes;
}
-Json::Value ASTJsonConverter::inlineAssemblyIdentifierToJson(pair<assembly::Identifier const* ,InlineAssemblyAnnotation::ExternalIdentifierInfo> _info) const
+Json::Value ASTJsonConverter::inlineAssemblyIdentifierToJson(pair<yul::Identifier const* ,InlineAssemblyAnnotation::ExternalIdentifierInfo> _info) const
{
Json::Value tuple(Json::objectValue);
tuple["src"] = sourceLocationToString(_info.first->location);
@@ -464,7 +465,7 @@ bool ASTJsonConverter::visit(InlineAssembly const& _node)
}
}
setJsonNode(_node, "InlineAssembly", {
- make_pair("operations", Json::Value(assembly::AsmPrinter()(_node.operations()))),
+ make_pair("operations", Json::Value(yul::AsmPrinter()(_node.operations()))),
make_pair("externalReferences", std::move(externalReferences))
});
return false;
diff --git a/libsolidity/ast/ASTJsonConverter.h b/libsolidity/ast/ASTJsonConverter.h
index 8429708c..ef0a217a 100644
--- a/libsolidity/ast/ASTJsonConverter.h
+++ b/libsolidity/ast/ASTJsonConverter.h
@@ -25,10 +25,15 @@
#include <ostream>
#include <stack>
#include <libsolidity/ast/ASTVisitor.h>
-#include <libsolidity/interface/Exceptions.h>
+#include <liblangutil/Exceptions.h>
#include <libsolidity/ast/ASTAnnotations.h>
#include <json/json.h>
+namespace langutil
+{
+struct SourceLocation;
+}
+
namespace dev
{
namespace solidity
@@ -120,7 +125,7 @@ private:
std::string const& _nodeName,
std::vector<std::pair<std::string, Json::Value>>&& _attributes
);
- std::string sourceLocationToString(SourceLocation const& _location) const;
+ std::string sourceLocationToString(langutil::SourceLocation const& _location) const;
static std::string namePathToString(std::vector<ASTString> const& _namePath);
static Json::Value idOrNull(ASTNode const* _pt)
{
@@ -130,7 +135,7 @@ private:
{
return _node ? toJson(*_node) : Json::nullValue;
}
- Json::Value inlineAssemblyIdentifierToJson(std::pair<assembly::Identifier const* , InlineAssemblyAnnotation::ExternalIdentifierInfo> _info) const;
+ Json::Value inlineAssemblyIdentifierToJson(std::pair<yul::Identifier const* , InlineAssemblyAnnotation::ExternalIdentifierInfo> _info) const;
static std::string location(VariableDeclaration::Location _location);
static std::string contractKind(ContractDefinition::ContractKind _kind);
static std::string functionCallKind(FunctionCallKind _kind);
diff --git a/libsolidity/ast/ASTPrinter.cpp b/libsolidity/ast/ASTPrinter.cpp
index 255cb9be..cdc6ae7d 100644
--- a/libsolidity/ast/ASTPrinter.cpp
+++ b/libsolidity/ast/ASTPrinter.cpp
@@ -28,6 +28,7 @@
#include <boost/algorithm/string/join.hpp>
using namespace std;
+using namespace langutil;
namespace dev
{
diff --git a/libsolidity/ast/ASTVisitor.h b/libsolidity/ast/ASTVisitor.h
index 6c0ce6f8..1a761032 100644
--- a/libsolidity/ast/ASTVisitor.h
+++ b/libsolidity/ast/ASTVisitor.h
@@ -262,8 +262,8 @@ public:
): m_onVisit(_onVisit), m_onEndVisit(_onEndVisit) {}
protected:
- virtual bool visitNode(ASTNode const& _n) override { return m_onVisit ? m_onVisit(_n) : true; }
- virtual void endVisitNode(ASTNode const& _n) override { m_onEndVisit(_n); }
+ bool visitNode(ASTNode const& _n) override { return m_onVisit ? m_onVisit(_n) : true; }
+ void endVisitNode(ASTNode const& _n) override { m_onEndVisit(_n); }
private:
std::function<bool(ASTNode const&)> m_onVisit;
diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp
index 4b31d2e8..6cadb5f3 100644
--- a/libsolidity/ast/Types.cpp
+++ b/libsolidity/ast/Types.cpp
@@ -45,6 +45,7 @@
using namespace std;
using namespace dev;
+using namespace langutil;
using namespace dev::solidity;
namespace
@@ -441,10 +442,11 @@ MemberList::MemberMap Type::boundFunctions(Type const& _type, ContractDefinition
if (!function->isVisibleAsLibraryMember() || seenFunctions.count(function))
continue;
seenFunctions.insert(function);
- FunctionType funType(*function, false);
- if (auto fun = funType.asMemberFunction(true, true))
- if (_type.isImplicitlyConvertibleTo(*fun->selfType()))
- members.push_back(MemberList::Member(function->name(), fun, function));
+ if (function->parameters().empty())
+ continue;
+ FunctionTypePointer fun = FunctionType(*function, false).asCallableFunction(true, true);
+ if (_type.isImplicitlyConvertibleTo(*fun->selfType()))
+ members.push_back(MemberList::Member(function->name(), fun, function));
}
}
return members;
@@ -1941,8 +1943,9 @@ MemberList::MemberMap ContractType::nativeMembers(ContractDefinition const* _con
for (ContractDefinition const* base: bases | boost::adaptors::sliced(1, bases.size()))
for (FunctionDefinition const* function: base->definedFunctions())
{
- if (!function->isVisibleInDerivedContracts())
+ if (!function->isVisibleInDerivedContracts() || !function->isImplemented())
continue;
+
auto functionType = make_shared<FunctionType>(*function, true);
bool functionWithEqualArgumentsFound = false;
for (auto const& member: members)
@@ -1969,7 +1972,7 @@ MemberList::MemberMap ContractType::nativeMembers(ContractDefinition const* _con
for (auto const& it: m_contract.interfaceFunctions())
members.push_back(MemberList::Member(
it.second->declaration().name(),
- it.second->asMemberFunction(m_contract.isLibrary()),
+ it.second->asCallableFunction(m_contract.isLibrary()),
&it.second->declaration()
));
}
@@ -2122,9 +2125,15 @@ bool StructType::canBeUsedExternally(bool _inLibrary) const
// We pass "false" to canBeUsedExternally (_inLibrary), because this struct will be
// passed by value and thus the encoding does not differ, but it will disallow
// mappings.
+ // Also return false if at least one struct member does not have a type.
+ // This might happen, for example, if the type of the member does not exist,
+ // which is reported as an error.
for (auto const& var: m_struct.members())
{
- solAssert(var->annotation().type, "");
+ // If the struct member does not have a type return false.
+ // A TypeError is expected in this case.
+ if (!var->annotation().type)
+ return false;
if (!var->annotation().type->canBeUsedExternally(false))
return false;
}
@@ -3058,10 +3067,10 @@ TypePointer FunctionType::copyAndSetGasOrValue(bool _setGas, bool _setValue) con
);
}
-FunctionTypePointer FunctionType::asMemberFunction(bool _inLibrary, bool _bound) const
+FunctionTypePointer FunctionType::asCallableFunction(bool _inLibrary, bool _bound) const
{
- if (_bound && m_parameterTypes.empty())
- return FunctionTypePointer();
+ if (_bound)
+ solAssert(!m_parameterTypes.empty(), "");
TypePointers parameterTypes;
for (auto const& t: m_parameterTypes)
@@ -3200,7 +3209,7 @@ MemberList::MemberMap TypeType::nativeMembers(ContractDefinition const* _current
if (function->isVisibleAsLibraryMember())
members.push_back(MemberList::Member(
function->name(),
- FunctionType(*function).asMemberFunction(true),
+ FunctionType(*function).asCallableFunction(true),
function
));
if (isBase)
diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h
index 24ace447..0f0548d3 100644
--- a/libsolidity/ast/Types.h
+++ b/libsolidity/ast/Types.h
@@ -22,7 +22,7 @@
#pragma once
-#include <libsolidity/interface/Exceptions.h>
+#include <liblangutil/Exceptions.h>
#include <libsolidity/ast/ASTForward.h>
#include <libsolidity/ast/ASTEnums.h>
#include <libsolidity/parsing/Token.h>
@@ -331,31 +331,31 @@ public:
static AddressType& address() { static std::shared_ptr<AddressType> addr(std::make_shared<AddressType>(StateMutability::NonPayable)); return *addr; }
static AddressType& addressPayable() { static std::shared_ptr<AddressType> addr(std::make_shared<AddressType>(StateMutability::Payable)); return *addr; }
- virtual Category category() const override { return Category::Address; }
+ Category category() const override { return Category::Address; }
explicit AddressType(StateMutability _stateMutability);
- virtual std::string richIdentifier() const override;
- virtual bool isImplicitlyConvertibleTo(Type const& _other) const override;
- virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
- virtual TypePointer unaryOperatorResult(Token _operator) const override;
- virtual TypePointer binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
+ std::string richIdentifier() const override;
+ bool isImplicitlyConvertibleTo(Type const& _other) const override;
+ bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
+ TypePointer unaryOperatorResult(Token _operator) const override;
+ TypePointer binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
- virtual bool operator==(Type const& _other) const override;
+ bool operator==(Type const& _other) const override;
- virtual unsigned calldataEncodedSize(bool _padded = true) const override { return _padded ? 32 : 160 / 8; }
- virtual unsigned storageBytes() const override { return 160 / 8; }
- virtual bool isValueType() const override { return true; }
+ unsigned calldataEncodedSize(bool _padded = true) const override { return _padded ? 32 : 160 / 8; }
+ unsigned storageBytes() const override { return 160 / 8; }
+ bool isValueType() const override { return true; }
- virtual MemberList::MemberMap nativeMembers(ContractDefinition const*) const override;
+ MemberList::MemberMap nativeMembers(ContractDefinition const*) const override;
- virtual std::string toString(bool _short) const override;
- virtual std::string canonicalName() const override;
+ std::string toString(bool _short) const override;
+ std::string canonicalName() const override;
- virtual u256 literalValue(Literal const* _literal) const override;
+ u256 literalValue(Literal const* _literal) const override;
- virtual TypePointer encodingType() const override { return shared_from_this(); }
- virtual TypePointer interfaceType(bool) const override { return shared_from_this(); }
+ TypePointer encodingType() const override { return shared_from_this(); }
+ TypePointer interfaceType(bool) const override { return shared_from_this(); }
StateMutability stateMutability(void) const { return m_stateMutability; }
@@ -374,26 +374,28 @@ public:
Unsigned, Signed
};
- virtual Category category() const override { return Category::Integer; }
+ static IntegerType& uint256() { static std::shared_ptr<IntegerType> uint256(std::make_shared<IntegerType>(256)); return *uint256; }
+
+ Category category() const override { return Category::Integer; }
explicit IntegerType(unsigned _bits, Modifier _modifier = Modifier::Unsigned);
- virtual std::string richIdentifier() const override;
- virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
- virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
- virtual TypePointer unaryOperatorResult(Token _operator) const override;
- virtual TypePointer binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
+ std::string richIdentifier() const override;
+ bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
+ bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
+ TypePointer unaryOperatorResult(Token _operator) const override;
+ TypePointer binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
- virtual bool operator==(Type const& _other) const override;
+ bool operator==(Type const& _other) const override;
- virtual unsigned calldataEncodedSize(bool _padded = true) const override { return _padded ? 32 : m_bits / 8; }
- virtual unsigned storageBytes() const override { return m_bits / 8; }
- virtual bool isValueType() const override { return true; }
+ unsigned calldataEncodedSize(bool _padded = true) const override { return _padded ? 32 : m_bits / 8; }
+ unsigned storageBytes() const override { return m_bits / 8; }
+ bool isValueType() const override { return true; }
- virtual std::string toString(bool _short) const override;
+ std::string toString(bool _short) const override;
- virtual TypePointer encodingType() const override { return shared_from_this(); }
- virtual TypePointer interfaceType(bool) const override { return shared_from_this(); }
+ TypePointer encodingType() const override { return shared_from_this(); }
+ TypePointer interfaceType(bool) const override { return shared_from_this(); }
unsigned numBits() const { return m_bits; }
bool isSigned() const { return m_modifier == Modifier::Signed; }
@@ -416,26 +418,26 @@ public:
{
Unsigned, Signed
};
- virtual Category category() const override { return Category::FixedPoint; }
+ Category category() const override { return Category::FixedPoint; }
explicit FixedPointType(unsigned _totalBits, unsigned _fractionalDigits, Modifier _modifier = Modifier::Unsigned);
- virtual std::string richIdentifier() const override;
- virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
- virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
- virtual TypePointer unaryOperatorResult(Token _operator) const override;
- virtual TypePointer binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
+ std::string richIdentifier() const override;
+ bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
+ bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
+ TypePointer unaryOperatorResult(Token _operator) const override;
+ TypePointer binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
- virtual bool operator==(Type const& _other) const override;
+ bool operator==(Type const& _other) const override;
- virtual unsigned calldataEncodedSize(bool _padded = true) const override { return _padded ? 32 : m_totalBits / 8; }
- virtual unsigned storageBytes() const override { return m_totalBits / 8; }
- virtual bool isValueType() const override { return true; }
+ unsigned calldataEncodedSize(bool _padded = true) const override { return _padded ? 32 : m_totalBits / 8; }
+ unsigned storageBytes() const override { return m_totalBits / 8; }
+ bool isValueType() const override { return true; }
- virtual std::string toString(bool _short) const override;
+ std::string toString(bool _short) const override;
- virtual TypePointer encodingType() const override { return shared_from_this(); }
- virtual TypePointer interfaceType(bool) const override { return shared_from_this(); }
+ TypePointer encodingType() const override { return shared_from_this(); }
+ TypePointer interfaceType(bool) const override { return shared_from_this(); }
/// Number of bits used for this type in total.
unsigned numBits() const { return m_totalBits; }
@@ -467,7 +469,7 @@ class RationalNumberType: public Type
{
public:
- virtual Category category() const override { return Category::RationalNumber; }
+ Category category() const override { return Category::RationalNumber; }
static TypePointer forLiteral(Literal const& _literal);
@@ -475,20 +477,20 @@ public:
m_value(_value), m_compatibleBytesType(_compatibleBytesType)
{}
- virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
- virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
- virtual TypePointer unaryOperatorResult(Token _operator) const override;
- virtual TypePointer binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
+ bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
+ bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
+ TypePointer unaryOperatorResult(Token _operator) const override;
+ TypePointer binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
- virtual std::string richIdentifier() const override;
- virtual bool operator==(Type const& _other) const override;
+ std::string richIdentifier() const override;
+ bool operator==(Type const& _other) const override;
- virtual bool canBeStored() const override { return false; }
- virtual bool canLiveOutsideStorage() const override { return false; }
+ bool canBeStored() const override { return false; }
+ bool canLiveOutsideStorage() const override { return false; }
- virtual std::string toString(bool _short) const override;
- virtual u256 literalValue(Literal const* _literal) const override;
- virtual TypePointer mobileType() const override;
+ std::string toString(bool _short) const override;
+ u256 literalValue(Literal const* _literal) const override;
+ TypePointer mobileType() const override;
/// @returns the smallest integer type that can hold the value or an empty pointer if not possible.
std::shared_ptr<IntegerType const> integerType() const;
@@ -530,25 +532,25 @@ private:
class StringLiteralType: public Type
{
public:
- virtual Category category() const override { return Category::StringLiteral; }
+ Category category() const override { return Category::StringLiteral; }
explicit StringLiteralType(Literal const& _literal);
- virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
- virtual TypePointer binaryOperatorResult(Token, TypePointer const&) const override
+ bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
+ TypePointer binaryOperatorResult(Token, TypePointer const&) const override
{
return TypePointer();
}
- virtual std::string richIdentifier() const override;
- virtual bool operator==(Type const& _other) const override;
+ std::string richIdentifier() const override;
+ bool operator==(Type const& _other) const override;
- virtual bool canBeStored() const override { return false; }
- virtual bool canLiveOutsideStorage() const override { return false; }
- virtual unsigned sizeOnStack() const override { return 0; }
+ bool canBeStored() const override { return false; }
+ bool canLiveOutsideStorage() const override { return false; }
+ unsigned sizeOnStack() const override { return 0; }
- virtual std::string toString(bool) const override;
- virtual TypePointer mobileType() const override;
+ std::string toString(bool) const override;
+ TypePointer mobileType() const override;
bool isValidUTF8() const;
@@ -564,25 +566,25 @@ private:
class FixedBytesType: public Type
{
public:
- virtual Category category() const override { return Category::FixedBytes; }
+ Category category() const override { return Category::FixedBytes; }
explicit FixedBytesType(unsigned _bytes);
- virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
- virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
- virtual std::string richIdentifier() const override;
- virtual bool operator==(Type const& _other) const override;
- virtual TypePointer unaryOperatorResult(Token _operator) const override;
- virtual TypePointer binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
+ bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
+ bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
+ std::string richIdentifier() const override;
+ bool operator==(Type const& _other) const override;
+ TypePointer unaryOperatorResult(Token _operator) const override;
+ TypePointer binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
- virtual unsigned calldataEncodedSize(bool _padded) const override { return _padded && m_bytes > 0 ? 32 : m_bytes; }
- virtual unsigned storageBytes() const override { return m_bytes; }
- virtual bool isValueType() const override { return true; }
+ unsigned calldataEncodedSize(bool _padded) const override { return _padded && m_bytes > 0 ? 32 : m_bytes; }
+ unsigned storageBytes() const override { return m_bytes; }
+ bool isValueType() const override { return true; }
- virtual std::string toString(bool) const override { return "bytes" + dev::toString(m_bytes); }
- virtual MemberList::MemberMap nativeMembers(ContractDefinition const*) const override;
- virtual TypePointer encodingType() const override { return shared_from_this(); }
- virtual TypePointer interfaceType(bool) const override { return shared_from_this(); }
+ std::string toString(bool) const override { return "bytes" + dev::toString(m_bytes); }
+ MemberList::MemberMap nativeMembers(ContractDefinition const*) const override;
+ TypePointer encodingType() const override { return shared_from_this(); }
+ TypePointer interfaceType(bool) const override { return shared_from_this(); }
unsigned numBytes() const { return m_bytes; }
@@ -597,19 +599,19 @@ class BoolType: public Type
{
public:
BoolType() {}
- virtual Category category() const override { return Category::Bool; }
- virtual std::string richIdentifier() const override { return "t_bool"; }
- virtual TypePointer unaryOperatorResult(Token _operator) const override;
- virtual TypePointer binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
-
- virtual unsigned calldataEncodedSize(bool _padded) const override{ return _padded ? 32 : 1; }
- virtual unsigned storageBytes() const override { return 1; }
- virtual bool isValueType() const override { return true; }
-
- virtual std::string toString(bool) const override { return "bool"; }
- virtual u256 literalValue(Literal const* _literal) const override;
- virtual TypePointer encodingType() const override { return shared_from_this(); }
- virtual TypePointer interfaceType(bool) const override { return shared_from_this(); }
+ Category category() const override { return Category::Bool; }
+ std::string richIdentifier() const override { return "t_bool"; }
+ TypePointer unaryOperatorResult(Token _operator) const override;
+ TypePointer binaryOperatorResult(Token _operator, TypePointer const& _other) const override;
+
+ unsigned calldataEncodedSize(bool _padded) const override{ return _padded ? 32 : 1; }
+ unsigned storageBytes() const override { return 1; }
+ bool isValueType() const override { return true; }
+
+ std::string toString(bool) const override { return "bool"; }
+ u256 literalValue(Literal const* _literal) const override;
+ TypePointer encodingType() const override { return shared_from_this(); }
+ TypePointer interfaceType(bool) const override { return shared_from_this(); }
};
/**
@@ -622,20 +624,20 @@ public:
explicit ReferenceType(DataLocation _location): m_location(_location) {}
DataLocation location() const { return m_location; }
- virtual TypePointer unaryOperatorResult(Token _operator) const override;
- virtual TypePointer binaryOperatorResult(Token, TypePointer const&) const override
+ TypePointer unaryOperatorResult(Token _operator) const override;
+ TypePointer binaryOperatorResult(Token, TypePointer const&) const override
{
return TypePointer();
}
- virtual unsigned memoryHeadSize() const override { return 32; }
+ unsigned memoryHeadSize() const override { return 32; }
/// @returns a copy of this type with location (recursively) changed to @a _location,
/// whereas isPointer is only shallowly changed - the deep copy is always a bound reference.
virtual TypePointer copyForLocation(DataLocation _location, bool _isPointer) const = 0;
- virtual TypePointer mobileType() const override { return copyForLocation(m_location, true); }
- virtual bool dataStoredIn(DataLocation _location) const override { return m_location == _location; }
- virtual bool hasSimpleZeroValueInMemory() const override { return false; }
+ TypePointer mobileType() const override { return copyForLocation(m_location, true); }
+ bool dataStoredIn(DataLocation _location) const override { return m_location == _location; }
+ bool hasSimpleZeroValueInMemory() const override { return false; }
/// Storage references can be pointers or bound references. In general, local variables are of
/// pointer type, state variables are bound references. Assignments to pointers or deleting
@@ -677,7 +679,7 @@ public:
static ArrayType& bytesMemory() { static std::shared_ptr<ArrayType> addr(std::make_shared<ArrayType>(DataLocation::Memory)); return *addr; }
static ArrayType& stringMemory() { static std::shared_ptr<ArrayType> addr(std::make_shared<ArrayType>(DataLocation::Memory, true)); return *addr; }
- virtual Category category() const override { return Category::Array; }
+ Category category() const override { return Category::Array; }
/// Constructor for a byte array ("bytes") and string.
explicit ArrayType(DataLocation _location, bool _isString = false):
@@ -700,24 +702,24 @@ public:
m_length(_length)
{}
- virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
- virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
- virtual std::string richIdentifier() const override;
- virtual bool operator==(const Type& _other) const override;
- virtual unsigned calldataEncodedSize(bool _padded) const override;
- virtual bool isDynamicallySized() const override { return m_hasDynamicLength; }
- virtual bool isDynamicallyEncoded() const override;
- virtual u256 storageSize() const override;
- virtual bool canLiveOutsideStorage() const override { return m_baseType->canLiveOutsideStorage(); }
- virtual unsigned sizeOnStack() const override;
- virtual std::string toString(bool _short) const override;
- virtual std::string canonicalName() const override;
- virtual std::string signatureInExternalFunction(bool _structsByName) const override;
- virtual MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
- virtual TypePointer encodingType() const override;
- virtual TypePointer decodingType() const override;
- virtual TypePointer interfaceType(bool _inLibrary) const override;
- virtual bool canBeUsedExternally(bool _inLibrary) const override;
+ bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
+ bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
+ std::string richIdentifier() const override;
+ bool operator==(const Type& _other) const override;
+ unsigned calldataEncodedSize(bool _padded) const override;
+ bool isDynamicallySized() const override { return m_hasDynamicLength; }
+ bool isDynamicallyEncoded() const override;
+ u256 storageSize() const override;
+ bool canLiveOutsideStorage() const override { return m_baseType->canLiveOutsideStorage(); }
+ unsigned sizeOnStack() const override;
+ std::string toString(bool _short) const override;
+ std::string canonicalName() const override;
+ std::string signatureInExternalFunction(bool _structsByName) const override;
+ MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
+ TypePointer encodingType() const override;
+ TypePointer decodingType() const override;
+ TypePointer interfaceType(bool _inLibrary) const override;
+ bool canBeUsedExternally(bool _inLibrary) const override;
/// @returns true if this is valid to be stored in calldata
bool validForCalldata() const;
@@ -751,36 +753,36 @@ private:
class ContractType: public Type
{
public:
- virtual Category category() const override { return Category::Contract; }
+ Category category() const override { return Category::Contract; }
explicit ContractType(ContractDefinition const& _contract, bool _super = false):
m_contract(_contract), m_super(_super) {}
/// Contracts can be implicitly converted only to base contracts.
- virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
+ bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
/// Contracts can only be explicitly converted to address types and base contracts.
- virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
- virtual TypePointer unaryOperatorResult(Token _operator) const override;
- virtual std::string richIdentifier() const override;
- virtual bool operator==(Type const& _other) const override;
- virtual unsigned calldataEncodedSize(bool _padded ) const override
+ bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
+ TypePointer unaryOperatorResult(Token _operator) const override;
+ std::string richIdentifier() const override;
+ bool operator==(Type const& _other) const override;
+ unsigned calldataEncodedSize(bool _padded ) const override
{
solAssert(!isSuper(), "");
return encodingType()->calldataEncodedSize(_padded);
}
- virtual unsigned storageBytes() const override { solAssert(!isSuper(), ""); return 20; }
- virtual bool canLiveOutsideStorage() const override { return !isSuper(); }
- virtual unsigned sizeOnStack() const override { return m_super ? 0 : 1; }
- virtual bool isValueType() const override { return !isSuper(); }
- virtual std::string toString(bool _short) const override;
- virtual std::string canonicalName() const override;
-
- virtual MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
- virtual TypePointer encodingType() const override
+ unsigned storageBytes() const override { solAssert(!isSuper(), ""); return 20; }
+ bool canLiveOutsideStorage() const override { return !isSuper(); }
+ unsigned sizeOnStack() const override { return m_super ? 0 : 1; }
+ bool isValueType() const override { return !isSuper(); }
+ std::string toString(bool _short) const override;
+ std::string canonicalName() const override;
+
+ MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
+ TypePointer encodingType() const override
{
if (isSuper())
return TypePointer{};
return std::make_shared<AddressType>(isPayable() ? StateMutability::Payable : StateMutability::NonPayable);
}
- virtual TypePointer interfaceType(bool _inLibrary) const override
+ TypePointer interfaceType(bool _inLibrary) const override
{
if (isSuper())
return TypePointer{};
@@ -816,31 +818,31 @@ private:
class StructType: public ReferenceType
{
public:
- virtual Category category() const override { return Category::Struct; }
+ Category category() const override { return Category::Struct; }
explicit StructType(StructDefinition const& _struct, DataLocation _location = DataLocation::Storage):
ReferenceType(_location), m_struct(_struct) {}
- virtual bool isImplicitlyConvertibleTo(const Type& _convertTo) const override;
- virtual std::string richIdentifier() const override;
- virtual bool operator==(Type const& _other) const override;
- virtual unsigned calldataEncodedSize(bool _padded) const override;
- virtual bool isDynamicallyEncoded() const override;
+ bool isImplicitlyConvertibleTo(const Type& _convertTo) const override;
+ std::string richIdentifier() const override;
+ bool operator==(Type const& _other) const override;
+ unsigned calldataEncodedSize(bool _padded) const override;
+ bool isDynamicallyEncoded() const override;
u256 memorySize() const;
- virtual u256 storageSize() const override;
- virtual bool canLiveOutsideStorage() const override { return true; }
- virtual std::string toString(bool _short) const override;
+ u256 storageSize() const override;
+ bool canLiveOutsideStorage() const override { return true; }
+ std::string toString(bool _short) const override;
- virtual MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
- virtual TypePointer encodingType() const override
+ MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
+ TypePointer encodingType() const override
{
return location() == DataLocation::Storage ? std::make_shared<IntegerType>(256) : shared_from_this();
}
- virtual TypePointer interfaceType(bool _inLibrary) const override;
- virtual bool canBeUsedExternally(bool _inLibrary) const override;
+ TypePointer interfaceType(bool _inLibrary) const override;
+ bool canBeUsedExternally(bool _inLibrary) const override;
TypePointer copyForLocation(DataLocation _location, bool _isPointer) const override;
- virtual std::string canonicalName() const override;
- virtual std::string signatureInExternalFunction(bool _structsByName) const override;
+ std::string canonicalName() const override;
+ std::string signatureInExternalFunction(bool _structsByName) const override;
/// @returns a function that performs the type conversion between a list of struct members
/// and a memory struct of this type.
@@ -872,27 +874,27 @@ private:
class EnumType: public Type
{
public:
- virtual Category category() const override { return Category::Enum; }
+ Category category() const override { return Category::Enum; }
explicit EnumType(EnumDefinition const& _enum): m_enum(_enum) {}
- virtual TypePointer unaryOperatorResult(Token _operator) const override;
- virtual std::string richIdentifier() const override;
- virtual bool operator==(Type const& _other) const override;
- virtual unsigned calldataEncodedSize(bool _padded) const override
+ TypePointer unaryOperatorResult(Token _operator) const override;
+ std::string richIdentifier() const override;
+ bool operator==(Type const& _other) const override;
+ unsigned calldataEncodedSize(bool _padded) const override
{
return encodingType()->calldataEncodedSize(_padded);
}
- virtual unsigned storageBytes() const override;
- virtual bool canLiveOutsideStorage() const override { return true; }
- virtual std::string toString(bool _short) const override;
- virtual std::string canonicalName() const override;
- virtual bool isValueType() const override { return true; }
-
- virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
- virtual TypePointer encodingType() const override
+ unsigned storageBytes() const override;
+ bool canLiveOutsideStorage() const override { return true; }
+ std::string toString(bool _short) const override;
+ std::string canonicalName() const override;
+ bool isValueType() const override { return true; }
+
+ bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
+ TypePointer encodingType() const override
{
return std::make_shared<IntegerType>(8 * int(storageBytes()));
}
- virtual TypePointer interfaceType(bool _inLibrary) const override
+ TypePointer interfaceType(bool _inLibrary) const override
{
return _inLibrary ? shared_from_this() : encodingType();
}
@@ -913,21 +915,21 @@ private:
class TupleType: public Type
{
public:
- virtual Category category() const override { return Category::Tuple; }
+ Category category() const override { return Category::Tuple; }
explicit TupleType(std::vector<TypePointer> const& _types = std::vector<TypePointer>()): m_components(_types) {}
- virtual bool isImplicitlyConvertibleTo(Type const& _other) const override;
- virtual std::string richIdentifier() const override;
- virtual bool operator==(Type const& _other) const override;
- virtual TypePointer binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); }
- virtual std::string toString(bool) const override;
- virtual bool canBeStored() const override { return false; }
- virtual u256 storageSize() const override;
- virtual bool canLiveOutsideStorage() const override { return false; }
- virtual unsigned sizeOnStack() const override;
- virtual bool hasSimpleZeroValueInMemory() const override { return false; }
- virtual TypePointer mobileType() const override;
+ bool isImplicitlyConvertibleTo(Type const& _other) const override;
+ std::string richIdentifier() const override;
+ bool operator==(Type const& _other) const override;
+ TypePointer binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); }
+ std::string toString(bool) const override;
+ bool canBeStored() const override { return false; }
+ u256 storageSize() const override;
+ bool canLiveOutsideStorage() const override { return false; }
+ unsigned sizeOnStack() const override;
+ bool hasSimpleZeroValueInMemory() const override { return false; }
+ TypePointer mobileType() const override;
/// Converts components to their temporary types and performs some wildcard matching.
- virtual TypePointer closestTemporaryType(TypePointer const& _targetType) const override;
+ TypePointer closestTemporaryType(TypePointer const& _targetType) const override;
std::vector<TypePointer> const& components() const { return m_components; }
@@ -987,7 +989,7 @@ public:
GasLeft, ///< gasleft()
};
- virtual Category category() const override { return Category::Function; }
+ Category category() const override { return Category::Function; }
/// Creates the type of a function.
explicit FunctionType(FunctionDefinition const& _function, bool _isInternal = true);
@@ -1061,25 +1063,25 @@ public:
/// @returns the "self" parameter type for a bound function
TypePointer const& selfType() const;
- virtual std::string richIdentifier() const override;
- virtual bool operator==(Type const& _other) const override;
- virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
- virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
- virtual TypePointer unaryOperatorResult(Token _operator) const override;
- virtual TypePointer binaryOperatorResult(Token, TypePointer const&) const override;
- virtual std::string canonicalName() const override;
- virtual std::string toString(bool _short) const override;
- virtual unsigned calldataEncodedSize(bool _padded) const override;
- virtual bool canBeStored() const override { return m_kind == Kind::Internal || m_kind == Kind::External; }
- virtual u256 storageSize() const override;
- virtual unsigned storageBytes() const override;
- virtual bool isValueType() const override { return true; }
- virtual bool canLiveOutsideStorage() const override { return m_kind == Kind::Internal || m_kind == Kind::External; }
- virtual unsigned sizeOnStack() const override;
- virtual bool hasSimpleZeroValueInMemory() const override { return false; }
- virtual MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
- virtual TypePointer encodingType() const override;
- virtual TypePointer interfaceType(bool _inLibrary) const override;
+ std::string richIdentifier() const override;
+ bool operator==(Type const& _other) const override;
+ bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
+ bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
+ TypePointer unaryOperatorResult(Token _operator) const override;
+ TypePointer binaryOperatorResult(Token, TypePointer const&) const override;
+ std::string canonicalName() const override;
+ std::string toString(bool _short) const override;
+ unsigned calldataEncodedSize(bool _padded) const override;
+ bool canBeStored() const override { return m_kind == Kind::Internal || m_kind == Kind::External; }
+ u256 storageSize() const override;
+ unsigned storageBytes() const override;
+ bool isValueType() const override { return true; }
+ bool canLiveOutsideStorage() const override { return m_kind == Kind::Internal || m_kind == Kind::External; }
+ unsigned sizeOnStack() const override;
+ bool hasSimpleZeroValueInMemory() const override { return false; }
+ MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
+ TypePointer encodingType() const override;
+ TypePointer interfaceType(bool _inLibrary) const override;
/// @returns TypePointer of a new FunctionType object. All input/return parameters are an
/// appropriate external types (i.e. the interfaceType()s) of input/return parameters of
@@ -1154,14 +1156,13 @@ public:
/// of the parameters to false.
TypePointer copyAndSetGasOrValue(bool _setGas, bool _setValue) const;
- /// @returns a copy of this function type where all return parameters of dynamic size are
- /// removed and the location of reference types is changed from CallData to Memory.
- /// This is needed if external functions are called on other contracts, as they cannot return
- /// dynamic values.
- /// Returns empty shared pointer on a failure. Namely, if a bound function has no parameters.
+ /// @returns a copy of this function type where the location of reference types is changed
+ /// from CallData to Memory. This is the type that would be used when the function is
+ /// called, as opposed to the parameter types that are available inside the function body.
+ /// Also supports variants to be used for library or bound calls.
/// @param _inLibrary if true, uses DelegateCall as location.
- /// @param _bound if true, the arguments are placed as `arg1.functionName(arg2, ..., argn)`.
- FunctionTypePointer asMemberFunction(bool _inLibrary, bool _bound = false) const;
+ /// @param _bound if true, the function type is set to be bound.
+ FunctionTypePointer asCallableFunction(bool _inLibrary, bool _bound = false) const;
private:
static TypePointers parseElementaryTypeVector(strings const& _types);
@@ -1187,27 +1188,27 @@ private:
class MappingType: public Type
{
public:
- virtual Category category() const override { return Category::Mapping; }
+ Category category() const override { return Category::Mapping; }
MappingType(TypePointer const& _keyType, TypePointer const& _valueType):
m_keyType(_keyType), m_valueType(_valueType) {}
- virtual std::string richIdentifier() const override;
- virtual bool operator==(Type const& _other) const override;
- virtual std::string toString(bool _short) const override;
- virtual std::string canonicalName() const override;
- virtual bool canLiveOutsideStorage() const override { return false; }
- virtual TypePointer binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); }
- virtual TypePointer encodingType() const override
+ std::string richIdentifier() const override;
+ bool operator==(Type const& _other) const override;
+ std::string toString(bool _short) const override;
+ std::string canonicalName() const override;
+ bool canLiveOutsideStorage() const override { return false; }
+ TypePointer binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); }
+ TypePointer encodingType() const override
{
return std::make_shared<IntegerType>(256);
}
- virtual TypePointer interfaceType(bool _inLibrary) const override
+ TypePointer interfaceType(bool _inLibrary) const override
{
return _inLibrary ? shared_from_this() : TypePointer();
}
- virtual bool dataStoredIn(DataLocation _location) const override { return _location == DataLocation::Storage; }
+ bool dataStoredIn(DataLocation _location) const override { return _location == DataLocation::Storage; }
/// Cannot be stored in memory, but just in case.
- virtual bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
+ bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
TypePointer const& keyType() const { return m_keyType; }
TypePointer const& valueType() const { return m_valueType; }
@@ -1225,20 +1226,20 @@ private:
class TypeType: public Type
{
public:
- virtual Category category() const override { return Category::TypeType; }
+ Category category() const override { return Category::TypeType; }
explicit TypeType(TypePointer const& _actualType): m_actualType(_actualType) {}
TypePointer const& actualType() const { return m_actualType; }
- virtual TypePointer binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); }
- virtual std::string richIdentifier() const override;
- virtual bool operator==(Type const& _other) const override;
- virtual bool canBeStored() const override { return false; }
- virtual u256 storageSize() const override;
- virtual bool canLiveOutsideStorage() const override { return false; }
- virtual unsigned sizeOnStack() const override;
- virtual bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
- virtual std::string toString(bool _short) const override { return "type(" + m_actualType->toString(_short) + ")"; }
- virtual MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
+ TypePointer binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); }
+ std::string richIdentifier() const override;
+ bool operator==(Type const& _other) const override;
+ bool canBeStored() const override { return false; }
+ u256 storageSize() const override;
+ bool canLiveOutsideStorage() const override { return false; }
+ unsigned sizeOnStack() const override;
+ bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
+ std::string toString(bool _short) const override { return "type(" + m_actualType->toString(_short) + ")"; }
+ MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
private:
TypePointer m_actualType;
@@ -1251,18 +1252,18 @@ private:
class ModifierType: public Type
{
public:
- virtual Category category() const override { return Category::Modifier; }
+ Category category() const override { return Category::Modifier; }
explicit ModifierType(ModifierDefinition const& _modifier);
- virtual TypePointer binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); }
- virtual bool canBeStored() const override { return false; }
- virtual u256 storageSize() const override;
- virtual bool canLiveOutsideStorage() const override { return false; }
- virtual unsigned sizeOnStack() const override { return 0; }
- virtual bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
- virtual std::string richIdentifier() const override;
- virtual bool operator==(Type const& _other) const override;
- virtual std::string toString(bool _short) const override;
+ TypePointer binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); }
+ bool canBeStored() const override { return false; }
+ u256 storageSize() const override;
+ bool canLiveOutsideStorage() const override { return false; }
+ unsigned sizeOnStack() const override { return 0; }
+ bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
+ std::string richIdentifier() const override;
+ bool operator==(Type const& _other) const override;
+ std::string toString(bool _short) const override;
private:
TypePointers m_parameterTypes;
@@ -1276,20 +1277,20 @@ private:
class ModuleType: public Type
{
public:
- virtual Category category() const override { return Category::Module; }
+ Category category() const override { return Category::Module; }
explicit ModuleType(SourceUnit const& _source): m_sourceUnit(_source) {}
- virtual TypePointer binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); }
- virtual std::string richIdentifier() const override;
- virtual bool operator==(Type const& _other) const override;
- virtual bool canBeStored() const override { return false; }
- virtual bool canLiveOutsideStorage() const override { return true; }
- virtual bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
- virtual unsigned sizeOnStack() const override { return 0; }
- virtual MemberList::MemberMap nativeMembers(ContractDefinition const*) const override;
+ TypePointer binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); }
+ std::string richIdentifier() const override;
+ bool operator==(Type const& _other) const override;
+ bool canBeStored() const override { return false; }
+ bool canLiveOutsideStorage() const override { return true; }
+ bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
+ unsigned sizeOnStack() const override { return 0; }
+ MemberList::MemberMap nativeMembers(ContractDefinition const*) const override;
- virtual std::string toString(bool _short) const override;
+ std::string toString(bool _short) const override;
private:
SourceUnit const& m_sourceUnit;
@@ -1303,24 +1304,24 @@ class MagicType: public Type
{
public:
enum class Kind { Block, Message, Transaction, ABI };
- virtual Category category() const override { return Category::Magic; }
+ Category category() const override { return Category::Magic; }
explicit MagicType(Kind _kind): m_kind(_kind) {}
- virtual TypePointer binaryOperatorResult(Token, TypePointer const&) const override
+ TypePointer binaryOperatorResult(Token, TypePointer const&) const override
{
return TypePointer();
}
- virtual std::string richIdentifier() const override;
- virtual bool operator==(Type const& _other) const override;
- virtual bool canBeStored() const override { return false; }
- virtual bool canLiveOutsideStorage() const override { return true; }
- virtual bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
- virtual unsigned sizeOnStack() const override { return 0; }
- virtual MemberList::MemberMap nativeMembers(ContractDefinition const*) const override;
+ std::string richIdentifier() const override;
+ bool operator==(Type const& _other) const override;
+ bool canBeStored() const override { return false; }
+ bool canLiveOutsideStorage() const override { return true; }
+ bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
+ unsigned sizeOnStack() const override { return 0; }
+ MemberList::MemberMap nativeMembers(ContractDefinition const*) const override;
- virtual std::string toString(bool _short) const override;
+ std::string toString(bool _short) const override;
Kind kind() const { return m_kind; }
@@ -1335,20 +1336,20 @@ private:
class InaccessibleDynamicType: public Type
{
public:
- virtual Category category() const override { return Category::InaccessibleDynamic; }
-
- virtual std::string richIdentifier() const override { return "t_inaccessible"; }
- virtual bool isImplicitlyConvertibleTo(Type const&) const override { return false; }
- virtual bool isExplicitlyConvertibleTo(Type const&) const override { return false; }
- virtual TypePointer binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); }
- virtual unsigned calldataEncodedSize(bool _padded) const override { (void)_padded; return 32; }
- virtual bool canBeStored() const override { return false; }
- virtual bool canLiveOutsideStorage() const override { return false; }
- virtual bool isValueType() const override { return true; }
- virtual unsigned sizeOnStack() const override { return 1; }
- virtual bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
- virtual std::string toString(bool) const override { return "inaccessible dynamic type"; }
- virtual TypePointer decodingType() const override { return std::make_shared<IntegerType>(256); }
+ Category category() const override { return Category::InaccessibleDynamic; }
+
+ std::string richIdentifier() const override { return "t_inaccessible"; }
+ bool isImplicitlyConvertibleTo(Type const&) const override { return false; }
+ bool isExplicitlyConvertibleTo(Type const&) const override { return false; }
+ TypePointer binaryOperatorResult(Token, TypePointer const&) const override { return TypePointer(); }
+ unsigned calldataEncodedSize(bool _padded) const override { (void)_padded; return 32; }
+ bool canBeStored() const override { return false; }
+ bool canLiveOutsideStorage() const override { return false; }
+ bool isValueType() const override { return true; }
+ unsigned sizeOnStack() const override { return 1; }
+ bool hasSimpleZeroValueInMemory() const override { solAssert(false, ""); }
+ std::string toString(bool) const override { return "inaccessible dynamic type"; }
+ TypePointer decodingType() const override { return std::make_shared<IntegerType>(256); }
};
}
diff --git a/libsolidity/codegen/ABIFunctions.cpp b/libsolidity/codegen/ABIFunctions.cpp
index bd29b382..b02623de 100644
--- a/libsolidity/codegen/ABIFunctions.cpp
+++ b/libsolidity/codegen/ABIFunctions.cpp
@@ -558,7 +558,7 @@ string ABIFunctions::abiEncodingFunction(
// special case: convert storage reference type to value type - this is only
// possible for library calls where we just forward the storage reference
solAssert(_encodeAsLibraryTypes, "");
- solAssert(to == IntegerType(256), "");
+ solAssert(to == IntegerType::uint256(), "");
templ("cleanupConvert", "value");
}
else
diff --git a/libsolidity/codegen/ABIFunctions.h b/libsolidity/codegen/ABIFunctions.h
index e9ffe4fb..d2132258 100644
--- a/libsolidity/codegen/ABIFunctions.h
+++ b/libsolidity/codegen/ABIFunctions.h
@@ -22,7 +22,7 @@
#pragma once
-#include <libsolidity/interface/EVMVersion.h>
+#include <liblangutil/EVMVersion.h>
#include <libsolidity/ast/ASTForward.h>
diff --git a/libsolidity/codegen/ArrayUtils.cpp b/libsolidity/codegen/ArrayUtils.cpp
index d33f749c..4878f9f3 100644
--- a/libsolidity/codegen/ArrayUtils.cpp
+++ b/libsolidity/codegen/ArrayUtils.cpp
@@ -25,11 +25,12 @@
#include <libsolidity/codegen/CompilerContext.h>
#include <libsolidity/codegen/CompilerUtils.h>
#include <libsolidity/ast/Types.h>
-#include <libsolidity/interface/Exceptions.h>
+#include <liblangutil/Exceptions.h>
#include <libsolidity/codegen/LValue.h>
using namespace std;
using namespace dev;
+using namespace langutil;
using namespace solidity;
void ArrayUtils::copyArrayToStorage(ArrayType const& _targetType, ArrayType const& _sourceType) const
diff --git a/libsolidity/codegen/Compiler.h b/libsolidity/codegen/Compiler.h
index 4028ae63..48d9e9d6 100644
--- a/libsolidity/codegen/Compiler.h
+++ b/libsolidity/codegen/Compiler.h
@@ -23,7 +23,7 @@
#pragma once
#include <libsolidity/codegen/CompilerContext.h>
-#include <libsolidity/interface/EVMVersion.h>
+#include <liblangutil/EVMVersion.h>
#include <libevmasm/Assembly.h>
diff --git a/libsolidity/codegen/CompilerContext.cpp b/libsolidity/codegen/CompilerContext.cpp
index 6e14d68a..5a3a233c 100644
--- a/libsolidity/codegen/CompilerContext.cpp
+++ b/libsolidity/codegen/CompilerContext.cpp
@@ -25,14 +25,14 @@
#include <libsolidity/ast/AST.h>
#include <libsolidity/codegen/Compiler.h>
#include <libsolidity/interface/Version.h>
-#include <libsolidity/interface/ErrorReporter.h>
-#include <libsolidity/interface/SourceReferenceFormatter.h>
-#include <libsolidity/parsing/Scanner.h>
-#include <libsolidity/inlineasm/AsmParser.h>
-#include <libsolidity/inlineasm/AsmCodeGen.h>
-#include <libsolidity/inlineasm/AsmAnalysis.h>
-#include <libsolidity/inlineasm/AsmAnalysisInfo.h>
+#include <liblangutil/SourceReferenceFormatter.h>
+#include <libyul/AsmParser.h>
+#include <libyul/AsmCodeGen.h>
+#include <libyul/AsmAnalysis.h>
+#include <libyul/AsmAnalysisInfo.h>
#include <libyul/YulString.h>
+#include <liblangutil/ErrorReporter.h>
+#include <liblangutil/Scanner.h>
#include <boost/algorithm/string/replace.hpp>
@@ -42,11 +42,12 @@
// Change to "define" to output all intermediate code
#undef SOL_OUTPUT_ASM
#ifdef SOL_OUTPUT_ASM
-#include <libsolidity/inlineasm/AsmPrinter.h>
+#include <libyul/AsmPrinter.h>
#endif
using namespace std;
+using namespace langutil;
namespace dev
{
@@ -322,7 +323,7 @@ void CompilerContext::appendInlineAssembly(
yul::ExternalIdentifierAccess identifierAccess;
identifierAccess.resolve = [&](
- assembly::Identifier const& _identifier,
+ yul::Identifier const& _identifier,
yul::IdentifierContext,
bool
)
@@ -331,7 +332,7 @@ void CompilerContext::appendInlineAssembly(
return it == _localVariables.end() ? size_t(-1) : 1;
};
identifierAccess.generateCode = [&](
- assembly::Identifier const& _identifier,
+ yul::Identifier const& _identifier,
yul::IdentifierContext _context,
yul::AbstractAssembly& _assembly
)
@@ -359,20 +360,20 @@ void CompilerContext::appendInlineAssembly(
ErrorList errors;
ErrorReporter errorReporter(errors);
- auto scanner = make_shared<Scanner>(CharStream(_assembly), "--CODEGEN--");
- auto parserResult = assembly::Parser(errorReporter, assembly::AsmFlavour::Strict).parse(scanner, false);
+ auto scanner = make_shared<langutil::Scanner>(langutil::CharStream(_assembly, "--CODEGEN--"));
+ auto parserResult = yul::Parser(errorReporter, yul::AsmFlavour::Strict).parse(scanner, false);
#ifdef SOL_OUTPUT_ASM
- cout << assembly::AsmPrinter()(*parserResult) << endl;
+ cout << yul::AsmPrinter()(*parserResult) << endl;
#endif
- assembly::AsmAnalysisInfo analysisInfo;
+ yul::AsmAnalysisInfo analysisInfo;
bool analyzerResult = false;
if (parserResult)
- analyzerResult = assembly::AsmAnalyzer(
+ analyzerResult = yul::AsmAnalyzer(
analysisInfo,
errorReporter,
m_evmVersion,
boost::none,
- assembly::AsmFlavour::Strict,
+ yul::AsmFlavour::Strict,
identifierAccess.resolve
).analyze(*parserResult);
if (!parserResult || !errorReporter.errors().empty() || !analyzerResult)
@@ -394,7 +395,7 @@ void CompilerContext::appendInlineAssembly(
}
solAssert(errorReporter.errors().empty(), "Failed to analyze inline assembly block.");
- assembly::CodeGenerator::assemble(*parserResult, analysisInfo, *m_asm, identifierAccess, _system);
+ yul::CodeGenerator::assemble(*parserResult, analysisInfo, *m_asm, identifierAccess, _system);
// Reset the source location to the one of the node (instead of the CODEGEN source location)
updateSourceLocation();
@@ -413,7 +414,7 @@ FunctionDefinition const& CompilerContext::resolveVirtualFunction(
if (
function->name() == name &&
!function->isConstructor() &&
- FunctionType(*function).hasEqualParameterTypes(functionType)
+ FunctionType(*function).asCallableFunction(false)->hasEqualParameterTypes(functionType)
)
return *function;
solAssert(false, "Super function " + name + " not found.");
diff --git a/libsolidity/codegen/CompilerContext.h b/libsolidity/codegen/CompilerContext.h
index 5bdc1d19..02369813 100644
--- a/libsolidity/codegen/CompilerContext.h
+++ b/libsolidity/codegen/CompilerContext.h
@@ -24,7 +24,7 @@
#include <libsolidity/codegen/ABIFunctions.h>
-#include <libsolidity/interface/EVMVersion.h>
+#include <liblangutil/EVMVersion.h>
#include <libsolidity/ast/ASTForward.h>
#include <libsolidity/ast/Types.h>
@@ -167,7 +167,10 @@ public:
/// the data.
CompilerContext& appendConditionalRevert(bool _forwardReturnData = false);
/// Appends a JUMP to a specific tag
- CompilerContext& appendJumpTo(eth::AssemblyItem const& _tag) { m_asm->appendJump(_tag); return *this; }
+ CompilerContext& appendJumpTo(
+ eth::AssemblyItem const& _tag,
+ eth::AssemblyItem::JumpType _jumpType = eth::AssemblyItem::JumpType::Ordinary
+ ) { *m_asm << _tag.pushTag(); return appendJump(_jumpType); }
/// Appends pushing of a new tag and @returns the new tag.
eth::AssemblyItem pushNewTag() { return m_asm->append(m_asm->newPushTag()).tag(); }
/// @returns a new tag without pushing any opcodes or data
diff --git a/libsolidity/codegen/CompilerUtils.cpp b/libsolidity/codegen/CompilerUtils.cpp
index 90eb74fe..7d2ad9d2 100644
--- a/libsolidity/codegen/CompilerUtils.cpp
+++ b/libsolidity/codegen/CompilerUtils.cpp
@@ -32,6 +32,7 @@
#include <libdevcore/Whiskers.h>
using namespace std;
+using namespace langutil;
namespace dev
{
@@ -135,7 +136,7 @@ void CompilerUtils::loadFromMemoryDynamic(
void CompilerUtils::storeInMemory(unsigned _offset)
{
- unsigned numBytes = prepareMemoryStore(IntegerType(256), true);
+ unsigned numBytes = prepareMemoryStore(IntegerType::uint256(), true);
if (numBytes > 0)
m_context << u256(_offset) << Instruction::MSTORE;
}
@@ -149,7 +150,7 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound
ref->location() == DataLocation::Memory,
"Only in-memory reference type can be stored."
);
- storeInMemoryDynamic(IntegerType(256), _padToWordBoundaries);
+ storeInMemoryDynamic(IntegerType::uint256(), _padToWordBoundaries);
}
else if (auto str = dynamic_cast<StringLiteralType const*>(&_type))
{
@@ -265,7 +266,7 @@ void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMem
if (calldataType->isDynamicallySized())
{
// put on stack: data_pointer length
- loadFromMemoryDynamic(IntegerType(256), !_fromMemory);
+ loadFromMemoryDynamic(IntegerType::uint256(), !_fromMemory);
m_context << Instruction::SWAP1;
// stack: input_end base_offset next_pointer data_offset
m_context.appendInlineAssembly("{ if gt(data_offset, 0x100000000) { revert(0, 0) } }", {"data_offset"});
@@ -276,7 +277,7 @@ void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMem
{"input_end", "base_offset", "next_ptr", "array_head_ptr"}
);
// retrieve length
- loadFromMemoryDynamic(IntegerType(256), !_fromMemory, true);
+ loadFromMemoryDynamic(IntegerType::uint256(), !_fromMemory, true);
// stack: input_end base_offset next_pointer array_length data_pointer
m_context << Instruction::SWAP2;
// stack: input_end base_offset data_pointer array_length next_pointer
@@ -429,7 +430,7 @@ void CompilerUtils::encodeToMemory(
{
auto const& strType = dynamic_cast<StringLiteralType const&>(*_givenTypes[i]);
m_context << u256(strType.value().size());
- storeInMemoryDynamic(IntegerType(256), true);
+ storeInMemoryDynamic(IntegerType::uint256(), true);
// stack: ... <end_of_mem'>
storeInMemoryDynamic(strType, _padToWordBoundaries);
}
@@ -444,7 +445,7 @@ void CompilerUtils::encodeToMemory(
m_context << dupInstruction(1 + arrayType.sizeOnStack());
ArrayUtils(m_context).retrieveLength(arrayType, 1);
// stack: ... <end_of_mem> <value...> <end_of_mem'> <length>
- storeInMemoryDynamic(IntegerType(256), true);
+ storeInMemoryDynamic(IntegerType::uint256(), true);
// stack: ... <end_of_mem> <value...> <end_of_mem''>
// copy the new memory pointer
m_context << swapInstruction(arrayType.sizeOnStack() + 1) << Instruction::POP;
@@ -806,7 +807,7 @@ void CompilerUtils::convertType(
allocateMemory();
// stack: mempos
m_context << Instruction::DUP1 << u256(data.size());
- storeInMemoryDynamic(IntegerType(256));
+ storeInMemoryDynamic(IntegerType::uint256());
// stack: mempos datapos
storeStringData(data);
}
@@ -855,7 +856,7 @@ void CompilerUtils::convertType(
if (targetType.isDynamicallySized())
{
m_context << Instruction::DUP2;
- storeInMemoryDynamic(IntegerType(256));
+ storeInMemoryDynamic(IntegerType::uint256());
}
// stack: <mem start> <source ref> (variably sized) <length> <mem data pos>
if (targetType.baseType()->isValueType())
@@ -1209,7 +1210,7 @@ void CompilerUtils::storeStringData(bytesConstRef _data)
for (unsigned i = 0; i < _data.size(); i += 32)
{
m_context << h256::Arith(h256(_data.cropped(i), h256::AlignLeft));
- storeInMemoryDynamic(IntegerType(256));
+ storeInMemoryDynamic(IntegerType::uint256());
}
m_context << Instruction::POP;
}
@@ -1236,6 +1237,7 @@ unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCallda
}
solAssert(numBytes <= 32, "Static memory load of more than 32 bytes requested.");
m_context << (_fromCalldata ? Instruction::CALLDATALOAD : Instruction::MLOAD);
+ bool cleanupNeeded = true;
if (isExternalFunctionType)
splitExternalFunctionType(true);
else if (numBytes != 32)
@@ -1245,10 +1247,16 @@ unsigned CompilerUtils::loadFromMemoryHelper(Type const& _type, bool _fromCallda
int shiftFactor = (32 - numBytes) * 8;
rightShiftNumberOnStack(shiftFactor);
if (leftAligned)
+ {
leftShiftNumberOnStack(shiftFactor);
+ cleanupNeeded = false;
+ }
+ else if (IntegerType const* intType = dynamic_cast<IntegerType const*>(&_type))
+ if (!intType->isSigned())
+ cleanupNeeded = false;
}
if (_fromCalldata)
- convertType(_type, _type, true, false, true);
+ convertType(_type, _type, cleanupNeeded, false, true);
return numBytes;
}
diff --git a/libsolidity/codegen/CompilerUtils.h b/libsolidity/codegen/CompilerUtils.h
index bd8170ad..5f7dce22 100644
--- a/libsolidity/codegen/CompilerUtils.h
+++ b/libsolidity/codegen/CompilerUtils.h
@@ -69,7 +69,7 @@ public:
/// @returns the number of bytes consumed in memory.
unsigned loadFromMemory(
unsigned _offset,
- Type const& _type = IntegerType(256),
+ Type const& _type = IntegerType::uint256(),
bool _fromCalldata = false,
bool _padToWords = false
);
diff --git a/libsolidity/codegen/ContractCompiler.cpp b/libsolidity/codegen/ContractCompiler.cpp
index 1fdf3483..aabdbb79 100644
--- a/libsolidity/codegen/ContractCompiler.cpp
+++ b/libsolidity/codegen/ContractCompiler.cpp
@@ -21,11 +21,11 @@
*/
#include <libsolidity/codegen/ContractCompiler.h>
-#include <libsolidity/inlineasm/AsmCodeGen.h>
-#include <libsolidity/ast/AST.h>
-#include <libsolidity/interface/ErrorReporter.h>
#include <libsolidity/codegen/ExpressionCompiler.h>
#include <libsolidity/codegen/CompilerUtils.h>
+#include <libsolidity/ast/AST.h>
+#include <libyul/AsmCodeGen.h>
+#include <liblangutil/ErrorReporter.h>
#include <libevmasm/Instruction.h>
#include <libevmasm/Assembly.h>
@@ -37,6 +37,7 @@
using namespace std;
using namespace dev;
+using namespace langutil;
using namespace dev::solidity;
namespace
@@ -343,7 +344,10 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac
m_context << Instruction::DUP1 << Instruction::CALLDATASIZE << Instruction::SUB;
CompilerUtils(m_context).abiDecode(functionType->parameterTypes());
}
- m_context.appendJumpTo(m_context.functionEntryLabel(functionType->declaration()));
+ m_context.appendJumpTo(
+ m_context.functionEntryLabel(functionType->declaration()),
+ eth::AssemblyItem::JumpType::IntoFunction
+ );
m_context << returnTag;
// Return tag and input parameters get consumed.
m_context.adjustStackOffset(
@@ -495,14 +499,14 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
{
unsigned startStackHeight = m_context.stackHeight();
yul::ExternalIdentifierAccess identifierAccess;
- identifierAccess.resolve = [&](assembly::Identifier const& _identifier, yul::IdentifierContext, bool)
+ identifierAccess.resolve = [&](yul::Identifier const& _identifier, yul::IdentifierContext, bool)
{
auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier);
if (ref == _inlineAssembly.annotation().externalReferences.end())
return size_t(-1);
return ref->second.valueSize;
};
- identifierAccess.generateCode = [&](assembly::Identifier const& _identifier, yul::IdentifierContext _context, yul::AbstractAssembly& _assembly)
+ identifierAccess.generateCode = [&](yul::Identifier const& _identifier, yul::IdentifierContext _context, yul::AbstractAssembly& _assembly)
{
auto ref = _inlineAssembly.annotation().externalReferences.find(&_identifier);
solAssert(ref != _inlineAssembly.annotation().externalReferences.end(), "");
@@ -614,7 +618,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
}
};
solAssert(_inlineAssembly.annotation().analysisInfo, "");
- assembly::CodeGenerator::assemble(
+ yul::CodeGenerator::assemble(
_inlineAssembly.operations(),
*_inlineAssembly.annotation().analysisInfo,
m_context.nonConstAssembly(),
diff --git a/libsolidity/codegen/ContractCompiler.h b/libsolidity/codegen/ContractCompiler.h
index 5fa650b1..001aec7c 100644
--- a/libsolidity/codegen/ContractCompiler.h
+++ b/libsolidity/codegen/ContractCompiler.h
@@ -88,22 +88,22 @@ private:
void registerStateVariables(ContractDefinition const& _contract);
void initializeStateVariables(ContractDefinition const& _contract);
- virtual bool visit(VariableDeclaration const& _variableDeclaration) override;
- virtual bool visit(FunctionDefinition const& _function) override;
- virtual bool visit(InlineAssembly const& _inlineAssembly) override;
- virtual bool visit(IfStatement const& _ifStatement) override;
- virtual bool visit(WhileStatement const& _whileStatement) override;
- virtual bool visit(ForStatement const& _forStatement) override;
- virtual bool visit(Continue const& _continueStatement) override;
- virtual bool visit(Break const& _breakStatement) override;
- virtual bool visit(Return const& _return) override;
- virtual bool visit(Throw const& _throw) override;
- virtual bool visit(EmitStatement const& _emit) override;
- virtual bool visit(VariableDeclarationStatement const& _variableDeclarationStatement) override;
- virtual bool visit(ExpressionStatement const& _expressionStatement) override;
- virtual bool visit(PlaceholderStatement const&) override;
- virtual bool visit(Block const& _block) override;
- virtual void endVisit(Block const& _block) override;
+ bool visit(VariableDeclaration const& _variableDeclaration) override;
+ bool visit(FunctionDefinition const& _function) override;
+ bool visit(InlineAssembly const& _inlineAssembly) override;
+ bool visit(IfStatement const& _ifStatement) override;
+ bool visit(WhileStatement const& _whileStatement) override;
+ bool visit(ForStatement const& _forStatement) override;
+ bool visit(Continue const& _continueStatement) override;
+ bool visit(Break const& _breakStatement) override;
+ bool visit(Return const& _return) override;
+ bool visit(Throw const& _throw) override;
+ bool visit(EmitStatement const& _emit) override;
+ bool visit(VariableDeclarationStatement const& _variableDeclarationStatement) override;
+ bool visit(ExpressionStatement const& _expressionStatement) override;
+ bool visit(PlaceholderStatement const&) override;
+ bool visit(Block const& _block) override;
+ void endVisit(Block const& _block) override;
/// Repeatedly visits all function which are referenced but which are not compiled yet.
void appendMissingFunctions();
diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp
index bdf91fbf..121585d9 100644
--- a/libsolidity/codegen/ExpressionCompiler.cpp
+++ b/libsolidity/codegen/ExpressionCompiler.cpp
@@ -36,6 +36,7 @@
#include <libdevcore/Whiskers.h>
using namespace std;
+using namespace langutil;
namespace dev
{
@@ -528,6 +529,8 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
{
bool shortcutTaken = false;
if (auto identifier = dynamic_cast<Identifier const*>(&_functionCall.expression()))
+ {
+ solAssert(!function.bound(), "");
if (auto functionDef = dynamic_cast<FunctionDefinition const*>(identifier->annotation().referencedDeclaration))
{
// Do not directly visit the identifier, because this way, we can avoid
@@ -536,6 +539,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
utils().pushCombinedFunctionEntryLabel(m_context.resolveVirtualFunction(*functionDef), false);
shortcutTaken = true;
}
+ }
if (!shortcutTaken)
_functionCall.expression().accept(*this);
@@ -627,7 +631,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
_functionCall.expression().accept(*this);
arguments.front()->accept(*this);
- utils().convertType(*arguments.front()->annotation().type, IntegerType(256), true);
+ utils().convertType(*arguments.front()->annotation().type, IntegerType::uint256(), true);
// Note that function is not the original function, but the ".gas" function.
// Its values of gasSet and valueSet is equal to the original function's though.
unsigned stackDepth = (function.gasSet() ? 1 : 0) + (function.valueSet() ? 1 : 0);
@@ -810,13 +814,13 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
case FunctionType::Kind::MulMod:
{
arguments[2]->accept(*this);
- utils().convertType(*arguments[2]->annotation().type, IntegerType(256));
+ utils().convertType(*arguments[2]->annotation().type, IntegerType::uint256());
m_context << Instruction::DUP1 << Instruction::ISZERO;
m_context.appendConditionalInvalid();
for (unsigned i = 1; i < 3; i ++)
{
arguments[2 - i]->accept(*this);
- utils().convertType(*arguments[2 - i]->annotation().type, IntegerType(256));
+ utils().convertType(*arguments[2 - i]->annotation().type, IntegerType::uint256());
}
if (function.kind() == FunctionType::Kind::AddMod)
m_context << Instruction::ADDMOD;
@@ -900,7 +904,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
// Fetch requested length.
arguments[0]->accept(*this);
- utils().convertType(*arguments[0]->annotation().type, IntegerType(256));
+ utils().convertType(*arguments[0]->annotation().type, IntegerType::uint256());
// Stack: requested_length
utils().fetchFreeMemoryPointer();
@@ -1149,7 +1153,9 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
if (dynamic_cast<ContractType const*>(type->actualType().get()))
{
solAssert(_memberAccess.annotation().type, "_memberAccess has no type");
- if (auto funType = dynamic_cast<FunctionType const*>(_memberAccess.annotation().type.get()))
+ if (auto variable = dynamic_cast<VariableDeclaration const*>(_memberAccess.annotation().referencedDeclaration))
+ appendVariable(*variable, static_cast<Expression const&>(_memberAccess));
+ else if (auto funType = dynamic_cast<FunctionType const*>(_memberAccess.annotation().type.get()))
{
switch (funType->kind())
{
@@ -1195,8 +1201,6 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
{
// no-op
}
- else if (auto variable = dynamic_cast<VariableDeclaration const*>(_memberAccess.annotation().referencedDeclaration))
- appendVariable(*variable, static_cast<Expression const&>(_memberAccess));
else
_memberAccess.expression().accept(*this);
}
@@ -1448,7 +1452,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
TypePointers{keyType}
);
m_context << Instruction::SWAP1;
- utils().storeInMemoryDynamic(IntegerType(256));
+ utils().storeInMemoryDynamic(IntegerType::uint256());
utils().toSizeAfterFreeMemoryPointer();
}
else
@@ -1457,7 +1461,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
appendExpressionCopyToMemory(*keyType, *_indexAccess.indexExpression());
m_context << Instruction::SWAP1;
solAssert(CompilerUtils::freeMemoryPointer >= 0x40, "");
- utils().storeInMemoryDynamic(IntegerType(256));
+ utils().storeInMemoryDynamic(IntegerType::uint256());
m_context << u256(0);
}
m_context << Instruction::KECCAK256;
@@ -1470,7 +1474,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
solAssert(_indexAccess.indexExpression(), "Index expression expected.");
_indexAccess.indexExpression()->accept(*this);
- utils().convertType(*_indexAccess.indexExpression()->annotation().type, IntegerType(256), true);
+ utils().convertType(*_indexAccess.indexExpression()->annotation().type, IntegerType::uint256(), true);
// stack layout: <base_ref> [<length>] <index>
ArrayUtils(m_context).accessIndex(arrayType);
switch (arrayType.location())
@@ -1506,7 +1510,7 @@ bool ExpressionCompiler::visit(IndexAccess const& _indexAccess)
solAssert(_indexAccess.indexExpression(), "Index expression expected.");
_indexAccess.indexExpression()->accept(*this);
- utils().convertType(*_indexAccess.indexExpression()->annotation().type, IntegerType(256), true);
+ utils().convertType(*_indexAccess.indexExpression()->annotation().type, IntegerType::uint256(), true);
// stack layout: <value> <index>
// check out-of-bounds access
m_context << u256(fixedBytesType.numBytes());
@@ -1869,6 +1873,8 @@ void ExpressionCompiler::appendExternalFunctionCall(
retSize = 0;
break;
}
+ else if (retType->decodingType())
+ retSize += retType->decodingType()->calldataEncodedSize();
else
retSize += retType->calldataEncodedSize();
}
diff --git a/libsolidity/codegen/ExpressionCompiler.h b/libsolidity/codegen/ExpressionCompiler.h
index 3d8e8682..2bfaab43 100644
--- a/libsolidity/codegen/ExpressionCompiler.h
+++ b/libsolidity/codegen/ExpressionCompiler.h
@@ -25,10 +25,10 @@
#include <memory>
#include <boost/noncopyable.hpp>
#include <libdevcore/Common.h>
-#include <libevmasm/SourceLocation.h>
+#include <liblangutil/SourceLocation.h>
#include <libsolidity/ast/ASTVisitor.h>
#include <libsolidity/codegen/LValue.h>
-#include <libsolidity/interface/Exceptions.h>
+#include <liblangutil/Exceptions.h>
namespace dev {
namespace eth
@@ -71,17 +71,17 @@ public:
void appendConstStateVariableAccessor(const VariableDeclaration& _varDecl);
private:
- virtual bool visit(Conditional const& _condition) override;
- virtual bool visit(Assignment const& _assignment) override;
- virtual bool visit(TupleExpression const& _tuple) override;
- virtual bool visit(UnaryOperation const& _unaryOperation) override;
- virtual bool visit(BinaryOperation const& _binaryOperation) override;
- virtual bool visit(FunctionCall const& _functionCall) override;
- virtual bool visit(NewExpression const& _newExpression) override;
- virtual bool visit(MemberAccess const& _memberAccess) override;
- virtual bool visit(IndexAccess const& _indexAccess) override;
- virtual void endVisit(Identifier const& _identifier) override;
- virtual void endVisit(Literal const& _literal) override;
+ bool visit(Conditional const& _condition) override;
+ bool visit(Assignment const& _assignment) override;
+ bool visit(TupleExpression const& _tuple) override;
+ bool visit(UnaryOperation const& _unaryOperation) override;
+ bool visit(BinaryOperation const& _binaryOperation) override;
+ bool visit(FunctionCall const& _functionCall) override;
+ bool visit(NewExpression const& _newExpression) override;
+ bool visit(MemberAccess const& _memberAccess) override;
+ bool visit(IndexAccess const& _indexAccess) override;
+ void endVisit(Identifier const& _identifier) override;
+ void endVisit(Literal const& _literal) override;
///@{
///@name Append code for various operator types
diff --git a/libsolidity/codegen/LValue.cpp b/libsolidity/codegen/LValue.cpp
index 790ab309..6d71d36f 100644
--- a/libsolidity/codegen/LValue.cpp
+++ b/libsolidity/codegen/LValue.cpp
@@ -28,6 +28,7 @@
using namespace std;
using namespace dev;
+using namespace langutil;
using namespace solidity;
diff --git a/libsolidity/codegen/LValue.h b/libsolidity/codegen/LValue.h
index c576f9de..d854857b 100644
--- a/libsolidity/codegen/LValue.h
+++ b/libsolidity/codegen/LValue.h
@@ -24,7 +24,7 @@
#include <memory>
#include <vector>
-#include <libevmasm/SourceLocation.h>
+#include <liblangutil/SourceLocation.h>
#include <libsolidity/codegen/ArrayUtils.h>
namespace dev
@@ -55,17 +55,17 @@ public:
/// Copies the value of the current lvalue to the top of the stack and, if @a _remove is true,
/// also removes the reference from the stack.
/// @a _location source location of the current expression, used for error reporting.
- virtual void retrieveValue(SourceLocation const& _location, bool _remove = false) const = 0;
+ virtual void retrieveValue(langutil::SourceLocation const& _location, bool _remove = false) const = 0;
/// Moves a value from the stack to the lvalue. Removes the value if @a _move is true.
/// @a _location is the source location of the expression that caused this operation.
/// Stack pre: value [lvalue_ref]
/// Stack post: if !_move: value_of(lvalue_ref)
virtual void storeValue(Type const& _sourceType,
- SourceLocation const& _location = SourceLocation(), bool _move = false) const = 0;
+ langutil::SourceLocation const& _location = {}, bool _move = false) const = 0;
/// Stores zero in the lvalue. Removes the reference from the stack if @a _removeReference is true.
/// @a _location is the source location of the requested operation
virtual void setToZero(
- SourceLocation const& _location = SourceLocation(),
+ langutil::SourceLocation const& _location = {},
bool _removeReference = true
) const = 0;
@@ -82,15 +82,15 @@ class StackVariable: public LValue
public:
StackVariable(CompilerContext& _compilerContext, VariableDeclaration const& _declaration);
- virtual unsigned sizeOnStack() const override { return 0; }
- virtual void retrieveValue(SourceLocation const& _location, bool _remove = false) const override;
+ unsigned sizeOnStack() const override { return 0; }
+ void retrieveValue(langutil::SourceLocation const& _location, bool _remove = false) const override;
virtual void storeValue(
Type const& _sourceType,
- SourceLocation const& _location = SourceLocation(),
+ langutil::SourceLocation const& _location = {},
bool _move = false
) const override;
virtual void setToZero(
- SourceLocation const& _location = SourceLocation(),
+ langutil::SourceLocation const& _location = {},
bool _removeReference = true
) const override;
@@ -108,15 +108,15 @@ class MemoryItem: public LValue
{
public:
MemoryItem(CompilerContext& _compilerContext, Type const& _type, bool _padded = true);
- virtual unsigned sizeOnStack() const override { return 1; }
- virtual void retrieveValue(SourceLocation const& _location, bool _remove = false) const override;
+ unsigned sizeOnStack() const override { return 1; }
+ void retrieveValue(langutil::SourceLocation const& _location, bool _remove = false) const override;
virtual void storeValue(
Type const& _sourceType,
- SourceLocation const& _location = SourceLocation(),
+ langutil::SourceLocation const& _location = {},
bool _move = false
) const override;
virtual void setToZero(
- SourceLocation const& _location = SourceLocation(),
+ langutil::SourceLocation const& _location = {},
bool _removeReference = true
) const override;
private:
@@ -136,15 +136,15 @@ public:
StorageItem(CompilerContext& _compilerContext, VariableDeclaration const& _declaration);
/// Constructs the LValue and assumes that the storage reference is already on the stack.
StorageItem(CompilerContext& _compilerContext, Type const& _type);
- virtual unsigned sizeOnStack() const override { return 2; }
- virtual void retrieveValue(SourceLocation const& _location, bool _remove = false) const override;
+ unsigned sizeOnStack() const override { return 2; }
+ void retrieveValue(langutil::SourceLocation const& _location, bool _remove = false) const override;
virtual void storeValue(
Type const& _sourceType,
- SourceLocation const& _location = SourceLocation(),
+ langutil::SourceLocation const& _location = {},
bool _move = false
) const override;
virtual void setToZero(
- SourceLocation const& _location = SourceLocation(),
+ langutil::SourceLocation const& _location = {},
bool _removeReference = true
) const override;
};
@@ -158,15 +158,15 @@ class StorageByteArrayElement: public LValue
public:
/// Constructs the LValue and assumes that the storage reference is already on the stack.
StorageByteArrayElement(CompilerContext& _compilerContext);
- virtual unsigned sizeOnStack() const override { return 2; }
- virtual void retrieveValue(SourceLocation const& _location, bool _remove = false) const override;
+ unsigned sizeOnStack() const override { return 2; }
+ void retrieveValue(langutil::SourceLocation const& _location, bool _remove = false) const override;
virtual void storeValue(
Type const& _sourceType,
- SourceLocation const& _location = SourceLocation(),
+ langutil::SourceLocation const& _location = {},
bool _move = false
) const override;
virtual void setToZero(
- SourceLocation const& _location = SourceLocation(),
+ langutil::SourceLocation const& _location = {},
bool _removeReference = true
) const override;
};
@@ -181,14 +181,14 @@ class StorageArrayLength: public LValue
public:
/// Constructs the LValue, assumes that the reference to the array head is already on the stack.
StorageArrayLength(CompilerContext& _compilerContext, ArrayType const& _arrayType);
- virtual void retrieveValue(SourceLocation const& _location, bool _remove = false) const override;
+ void retrieveValue(langutil::SourceLocation const& _location, bool _remove = false) const override;
virtual void storeValue(
Type const& _sourceType,
- SourceLocation const& _location = SourceLocation(),
+ langutil::SourceLocation const& _location = {},
bool _move = false
) const override;
virtual void setToZero(
- SourceLocation const& _location = SourceLocation(),
+ langutil::SourceLocation const& _location = {},
bool _removeReference = true
) const override;
@@ -205,15 +205,15 @@ public:
/// Constructs the LValue assuming that the other LValues are present on the stack.
/// Empty unique_ptrs are possible if e.g. some values should be ignored during assignment.
TupleObject(CompilerContext& _compilerContext, std::vector<std::unique_ptr<LValue>>&& _lvalues);
- virtual unsigned sizeOnStack() const override;
- virtual void retrieveValue(SourceLocation const& _location, bool _remove = false) const override;
+ unsigned sizeOnStack() const override;
+ void retrieveValue(langutil::SourceLocation const& _location, bool _remove = false) const override;
virtual void storeValue(
Type const& _sourceType,
- SourceLocation const& _location = SourceLocation(),
+ langutil::SourceLocation const& _location = {},
bool _move = false
) const override;
virtual void setToZero(
- SourceLocation const& _location = SourceLocation(),
+ langutil::SourceLocation const& _location = {},
bool _removeReference = true
) const override;
diff --git a/libsolidity/formal/CVC4Interface.cpp b/libsolidity/formal/CVC4Interface.cpp
index 6cb91483..de5e4430 100644
--- a/libsolidity/formal/CVC4Interface.cpp
+++ b/libsolidity/formal/CVC4Interface.cpp
@@ -17,7 +17,7 @@
#include <libsolidity/formal/CVC4Interface.h>
-#include <libsolidity/interface/Exceptions.h>
+#include <liblangutil/Exceptions.h>
#include <libdevcore/CommonIO.h>
@@ -33,8 +33,7 @@ CVC4Interface::CVC4Interface():
void CVC4Interface::reset()
{
- m_constants.clear();
- m_functions.clear();
+ m_variables.clear();
m_solver.reset();
m_solver.setOption("produce-models", true);
m_solver.setTimeLimit(queryTimeout);
@@ -50,25 +49,10 @@ void CVC4Interface::pop()
m_solver.pop();
}
-void CVC4Interface::declareFunction(string _name, Sort _domain, Sort _codomain)
+void CVC4Interface::declareVariable(string const& _name, Sort const& _sort)
{
- if (!m_functions.count(_name))
- {
- CVC4::Type fType = m_context.mkFunctionType(cvc4Sort(_domain), cvc4Sort(_codomain));
- m_functions.insert({_name, m_context.mkVar(_name.c_str(), fType)});
- }
-}
-
-void CVC4Interface::declareInteger(string _name)
-{
- if (!m_constants.count(_name))
- m_constants.insert({_name, m_context.mkVar(_name.c_str(), m_context.integerType())});
-}
-
-void CVC4Interface::declareBool(string _name)
-{
- if (!m_constants.count(_name))
- m_constants.insert({_name, m_context.mkVar(_name.c_str(), m_context.booleanType())});
+ if (!m_variables.count(_name))
+ m_variables.insert({_name, m_context.mkVar(_name.c_str(), cvc4Sort(_sort))});
}
void CVC4Interface::addAssertion(Expression const& _expr)
@@ -129,20 +113,19 @@ pair<CheckResult, vector<string>> CVC4Interface::check(vector<Expression> const&
CVC4::Expr CVC4Interface::toCVC4Expr(Expression const& _expr)
{
- if (_expr.arguments.empty() && m_constants.count(_expr.name))
- return m_constants.at(_expr.name);
+ // Variable
+ if (_expr.arguments.empty() && m_variables.count(_expr.name))
+ return m_variables.at(_expr.name);
+
vector<CVC4::Expr> arguments;
for (auto const& arg: _expr.arguments)
arguments.push_back(toCVC4Expr(arg));
string const& n = _expr.name;
- if (m_functions.count(n))
- return m_context.mkExpr(CVC4::kind::APPLY_UF, m_functions[n], arguments);
- else if (m_constants.count(n))
- {
- solAssert(arguments.empty(), "");
- return m_constants.at(n);
- }
+ // Function application
+ if (!arguments.empty() && m_variables.count(_expr.name))
+ return m_context.mkExpr(CVC4::kind::APPLY_UF, m_variables.at(n), arguments);
+ // Literal
else if (arguments.empty())
{
if (n == "true")
@@ -181,19 +164,33 @@ CVC4::Expr CVC4Interface::toCVC4Expr(Expression const& _expr)
return m_context.mkExpr(CVC4::kind::MULT, arguments[0], arguments[1]);
else if (n == "/")
return m_context.mkExpr(CVC4::kind::INTS_DIVISION_TOTAL, arguments[0], arguments[1]);
+ else if (n == "select")
+ return m_context.mkExpr(CVC4::kind::SELECT, arguments[0], arguments[1]);
+ else if (n == "store")
+ return m_context.mkExpr(CVC4::kind::STORE, arguments[0], arguments[1], arguments[2]);
// Cannot reach here.
solAssert(false, "");
return arguments[0];
}
-CVC4::Type CVC4Interface::cvc4Sort(Sort _sort)
+CVC4::Type CVC4Interface::cvc4Sort(Sort const& _sort)
{
- switch (_sort)
+ switch (_sort.kind)
{
- case Sort::Bool:
+ case Kind::Bool:
return m_context.booleanType();
- case Sort::Int:
+ case Kind::Int:
return m_context.integerType();
+ case Kind::Function:
+ {
+ FunctionSort const& fSort = dynamic_cast<FunctionSort const&>(_sort);
+ return m_context.mkFunctionType(cvc4Sort(fSort.domain), cvc4Sort(*fSort.codomain));
+ }
+ case Kind::Array:
+ {
+ auto const& arraySort = dynamic_cast<ArraySort const&>(_sort);
+ return m_context.mkArrayType(cvc4Sort(*arraySort.domain), cvc4Sort(*arraySort.range));
+ }
default:
break;
}
@@ -201,3 +198,11 @@ CVC4::Type CVC4Interface::cvc4Sort(Sort _sort)
// Cannot be reached.
return m_context.integerType();
}
+
+vector<CVC4::Type> CVC4Interface::cvc4Sort(vector<SortPointer> const& _sorts)
+{
+ vector<CVC4::Type> cvc4Sorts;
+ for (auto const& _sort: _sorts)
+ cvc4Sorts.push_back(cvc4Sort(*_sort));
+ return cvc4Sorts;
+}
diff --git a/libsolidity/formal/CVC4Interface.h b/libsolidity/formal/CVC4Interface.h
index cd6d761d..bbe23855 100644
--- a/libsolidity/formal/CVC4Interface.h
+++ b/libsolidity/formal/CVC4Interface.h
@@ -51,21 +51,19 @@ public:
void push() override;
void pop() override;
- void declareFunction(std::string _name, Sort _domain, Sort _codomain) override;
- void declareInteger(std::string _name) override;
- void declareBool(std::string _name) override;
+ void declareVariable(std::string const&, Sort const&) override;
void addAssertion(Expression const& _expr) override;
std::pair<CheckResult, std::vector<std::string>> check(std::vector<Expression> const& _expressionsToEvaluate) override;
private:
CVC4::Expr toCVC4Expr(Expression const& _expr);
- CVC4::Type cvc4Sort(smt::Sort _sort);
+ CVC4::Type cvc4Sort(smt::Sort const& _sort);
+ std::vector<CVC4::Type> cvc4Sort(std::vector<smt::SortPointer> const& _sorts);
CVC4::ExprManager m_context;
CVC4::SmtEngine m_solver;
- std::map<std::string, CVC4::Expr> m_constants;
- std::map<std::string, CVC4::Expr> m_functions;
+ std::map<std::string, CVC4::Expr> m_variables;
};
}
diff --git a/libsolidity/formal/SMTChecker.cpp b/libsolidity/formal/SMTChecker.cpp
index cc580021..ebb09f0a 100644
--- a/libsolidity/formal/SMTChecker.cpp
+++ b/libsolidity/formal/SMTChecker.cpp
@@ -22,19 +22,29 @@
#include <libsolidity/formal/VariableUsage.h>
#include <libsolidity/formal/SymbolicTypes.h>
-#include <libsolidity/interface/ErrorReporter.h>
+#include <liblangutil/ErrorReporter.h>
#include <boost/range/adaptor/map.hpp>
#include <boost/algorithm/string/replace.hpp>
using namespace std;
using namespace dev;
+using namespace langutil;
using namespace dev::solidity;
-SMTChecker::SMTChecker(ErrorReporter& _errorReporter, ReadCallback::Callback const& _readFileCallback):
- m_interface(make_shared<smt::SMTPortfolio>(_readFileCallback)),
+SMTChecker::SMTChecker(ErrorReporter& _errorReporter, map<h256, string> const& _smtlib2Responses):
+ m_interface(make_shared<smt::SMTPortfolio>(_smtlib2Responses)),
m_errorReporter(_errorReporter)
{
+#if defined (HAVE_Z3) || defined (HAVE_CVC4)
+ if (!_smtlib2Responses.empty())
+ m_errorReporter.warning(
+ "SMT-LIB2 query responses were given in the auxiliary input, "
+ "but this Solidity binary uses an SMT solver (Z3/CVC4) directly."
+ "These responses will be ignored."
+ "Consider disabling Z3/CVC4 at compilation time in order to use SMT-LIB2 responses."
+ );
+#endif
}
void SMTChecker::analyze(SourceUnit const& _source, shared_ptr<Scanner> const& _scanner)
@@ -78,6 +88,9 @@ bool SMTChecker::visit(FunctionDefinition const& _function)
m_interface->reset();
m_pathConditions.clear();
m_expressions.clear();
+ m_specialVariables.clear();
+ m_uninterpretedFunctions.clear();
+ m_uninterpretedTerms.clear();
resetStateVariables();
initializeLocalVariables(_function);
}
@@ -310,9 +323,6 @@ void SMTChecker::endVisit(UnaryOperation const& _op)
);
break;
}
- case Token::Add: // +
- defineExpr(_op, expr(_op.subExpression()));
- break;
case Token::Sub: // -
{
defineExpr(_op, 0 - expr(_op.subExpression()));
@@ -405,16 +415,24 @@ void SMTChecker::visitGasLeft(FunctionCall const& _funCall)
auto const& symbolicVar = m_specialVariables.at(gasLeft);
unsigned index = symbolicVar->index();
// We set the current value to unknown anyway to add type constraints.
- symbolicVar->setUnknownValue();
+ setUnknownValue(*symbolicVar);
if (index > 0)
m_interface->addAssertion(symbolicVar->currentValue() <= symbolicVar->valueAtIndex(index - 1));
}
void SMTChecker::visitBlockHash(FunctionCall const& _funCall)
{
- string blockHash = "blockhash()";
- // TODO Define blockhash as an uninterpreted function
- defineSpecialVariable(blockHash, _funCall);
+ string blockHash = "blockhash";
+ auto const& arguments = _funCall.arguments();
+ solAssert(arguments.size() == 1, "");
+ smt::SortPointer paramSort = smtSort(*arguments.at(0)->annotation().type);
+ smt::SortPointer returnSort = smtSort(*_funCall.annotation().type);
+ defineUninterpretedFunction(
+ blockHash,
+ make_shared<smt::FunctionSort>(vector<smt::SortPointer>{paramSort}, returnSort)
+ );
+ defineExpr(_funCall, m_uninterpretedFunctions.at(blockHash)({expr(*arguments.at(0))}));
+ m_uninterpretedTerms.push_back(&_funCall);
}
void SMTChecker::inlineFunctionCall(FunctionCall const& _funCall)
@@ -451,6 +469,14 @@ void SMTChecker::inlineFunctionCall(FunctionCall const& _funCall)
else if (_funDef && _funDef->isImplemented())
{
vector<smt::Expression> funArgs;
+ auto const& funType = dynamic_cast<FunctionType const*>(_calledExpr->annotation().type.get());
+ solAssert(funType, "");
+ if (funType->bound())
+ {
+ auto const& boundFunction = dynamic_cast<MemberAccess const*>(_calledExpr);
+ solAssert(boundFunction, "");
+ funArgs.push_back(expr(boundFunction->expression()));
+ }
for (auto arg: _funCall.arguments())
funArgs.push_back(expr(*arg));
initializeFunctionCallParameters(*_funDef, funArgs);
@@ -542,6 +568,10 @@ void SMTChecker::endVisit(Return const& _return)
bool SMTChecker::visit(MemberAccess const& _memberAccess)
{
+ auto const& accessType = _memberAccess.annotation().type;
+ if (accessType->category() == Type::Category::Function)
+ return true;
+
auto const& exprType = _memberAccess.expression().annotation().type;
solAssert(exprType, "");
if (exprType->category() == Type::Category::Magic)
@@ -573,7 +603,7 @@ void SMTChecker::defineSpecialVariable(string const& _name, Expression const& _e
{
auto result = newSymbolicVariable(*_expr.annotation().type, _name, *m_interface);
m_specialVariables.emplace(_name, result.second);
- result.second->setUnknownValue();
+ setUnknownValue(*result.second);
if (result.first)
m_errorReporter.warning(
_expr.location(),
@@ -587,6 +617,11 @@ void SMTChecker::defineSpecialVariable(string const& _name, Expression const& _e
defineExpr(_expr, m_specialVariables.at(_name)->currentValue());
}
+void SMTChecker::defineUninterpretedFunction(string const& _name, smt::SortPointer _sort)
+{
+ if (!m_uninterpretedFunctions.count(_name))
+ m_uninterpretedFunctions.emplace(_name, m_interface->newVariable(_name, _sort));
+}
void SMTChecker::arithmeticOperation(BinaryOperation const& _op)
{
@@ -770,6 +805,11 @@ void SMTChecker::checkCondition(
expressionsToEvaluate.emplace_back(var.second->currentValue());
expressionNames.push_back(var.first);
}
+ for (auto const& uf: m_uninterpretedTerms)
+ {
+ expressionsToEvaluate.emplace_back(expr(*uf));
+ expressionNames.push_back(m_scanner->sourceAt(uf->location()));
+ }
}
smt::CheckResult result;
vector<string> values;
@@ -846,6 +886,10 @@ void SMTChecker::checkBooleanNotConstant(Expression const& _condition, string co
{
// everything fine.
}
+ else if (positiveResult == smt::CheckResult::UNKNOWN || negatedResult == smt::CheckResult::UNKNOWN)
+ {
+ // can't do anything.
+ }
else if (positiveResult == smt::CheckResult::UNSATISFIABLE && negatedResult == smt::CheckResult::UNSATISFIABLE)
m_errorReporter.warning(_condition.location(), "Condition unreachable.");
else
@@ -1037,13 +1081,23 @@ smt::Expression SMTChecker::newValue(VariableDeclaration const& _decl)
void SMTChecker::setZeroValue(VariableDeclaration const& _decl)
{
solAssert(knownVariable(_decl), "");
- m_variables.at(&_decl)->setZeroValue();
+ setZeroValue(*m_variables.at(&_decl));
+}
+
+void SMTChecker::setZeroValue(SymbolicVariable& _variable)
+{
+ smt::setSymbolicZeroValue(_variable, *m_interface);
}
void SMTChecker::setUnknownValue(VariableDeclaration const& _decl)
{
solAssert(knownVariable(_decl), "");
- m_variables.at(&_decl)->setUnknownValue();
+ setUnknownValue(*m_variables.at(&_decl));
+}
+
+void SMTChecker::setUnknownValue(SymbolicVariable& _variable)
+{
+ smt::setSymbolicUnknownValue(_variable, *m_interface);
}
smt::Expression SMTChecker::expr(Expression const& _e)
diff --git a/libsolidity/formal/SMTChecker.h b/libsolidity/formal/SMTChecker.h
index a7f955dd..34724848 100644
--- a/libsolidity/formal/SMTChecker.h
+++ b/libsolidity/formal/SMTChecker.h
@@ -25,50 +25,60 @@
#include <libsolidity/interface/ReadFile.h>
-#include <libsolidity/parsing/Scanner.h>
+#include <liblangutil/Scanner.h>
#include <unordered_map>
#include <string>
#include <vector>
+namespace langutil
+{
+class ErrorReporter;
+struct SourceLocation;
+}
+
namespace dev
{
namespace solidity
{
class VariableUsage;
-class ErrorReporter;
class SMTChecker: private ASTConstVisitor
{
public:
- SMTChecker(ErrorReporter& _errorReporter, ReadCallback::Callback const& _readCallback);
+ SMTChecker(langutil::ErrorReporter& _errorReporter, std::map<h256, std::string> const& _smtlib2Responses);
+
+ void analyze(SourceUnit const& _sources, std::shared_ptr<langutil::Scanner> const& _scanner);
- void analyze(SourceUnit const& _sources, std::shared_ptr<Scanner> const& _scanner);
+ /// This is used if the SMT solver is not directly linked into this binary.
+ /// @returns a list of inputs to the SMT solver that were not part of the argument to
+ /// the constructor.
+ std::vector<std::string> unhandledQueries() { return m_interface->unhandledQueries(); }
private:
// TODO: Check that we do not have concurrent reads and writes to a variable,
// because the order of expression evaluation is undefined
// TODO: or just force a certain order, but people might have a different idea about that.
- virtual bool visit(ContractDefinition const& _node) override;
- virtual void endVisit(ContractDefinition const& _node) override;
- virtual void endVisit(VariableDeclaration const& _node) override;
- virtual bool visit(FunctionDefinition const& _node) override;
- virtual void endVisit(FunctionDefinition const& _node) override;
- virtual bool visit(IfStatement const& _node) override;
- virtual bool visit(WhileStatement const& _node) override;
- virtual bool visit(ForStatement const& _node) override;
- virtual void endVisit(VariableDeclarationStatement const& _node) override;
- virtual void endVisit(Assignment const& _node) override;
- virtual void endVisit(TupleExpression const& _node) override;
- virtual void endVisit(UnaryOperation const& _node) override;
- virtual void endVisit(BinaryOperation const& _node) override;
- virtual void endVisit(FunctionCall const& _node) override;
- virtual void endVisit(Identifier const& _node) override;
- virtual void endVisit(Literal const& _node) override;
- virtual void endVisit(Return const& _node) override;
- virtual bool visit(MemberAccess const& _node) override;
+ bool visit(ContractDefinition const& _node) override;
+ void endVisit(ContractDefinition const& _node) override;
+ void endVisit(VariableDeclaration const& _node) override;
+ bool visit(FunctionDefinition const& _node) override;
+ void endVisit(FunctionDefinition const& _node) override;
+ bool visit(IfStatement const& _node) override;
+ bool visit(WhileStatement const& _node) override;
+ bool visit(ForStatement const& _node) override;
+ void endVisit(VariableDeclarationStatement const& _node) override;
+ void endVisit(Assignment const& _node) override;
+ void endVisit(TupleExpression const& _node) override;
+ void endVisit(UnaryOperation const& _node) override;
+ void endVisit(BinaryOperation const& _node) override;
+ void endVisit(FunctionCall const& _node) override;
+ void endVisit(Identifier const& _node) override;
+ void endVisit(Literal const& _node) override;
+ void endVisit(Return const& _node) override;
+ bool visit(MemberAccess const& _node) override;
void arithmeticOperation(BinaryOperation const& _op);
void compareOperation(BinaryOperation const& _op);
@@ -83,13 +93,14 @@ private:
void inlineFunctionCall(FunctionCall const&);
void defineSpecialVariable(std::string const& _name, Expression const& _expr, bool _increaseIndex = false);
+ void defineUninterpretedFunction(std::string const& _name, smt::SortPointer _sort);
/// Division expression in the given type. Requires special treatment because
/// of rounding for signed division.
smt::Expression division(smt::Expression _left, smt::Expression _right, IntegerType const& _type);
- void assignment(VariableDeclaration const& _variable, Expression const& _value, SourceLocation const& _location);
- void assignment(VariableDeclaration const& _variable, smt::Expression const& _value, SourceLocation const& _location);
+ void assignment(VariableDeclaration const& _variable, Expression const& _value, langutil::SourceLocation const& _location);
+ void assignment(VariableDeclaration const& _variable, smt::Expression const& _value, langutil::SourceLocation const& _location);
/// Maps a variable to an SSA index.
using VariableIndices = std::unordered_map<VariableDeclaration const*, int>;
@@ -103,7 +114,7 @@ private:
/// Check that a condition can be satisfied.
void checkCondition(
smt::Expression _condition,
- SourceLocation const& _location,
+ langutil::SourceLocation const& _location,
std::string const& _description,
std::string const& _additionalValueName = "",
smt::Expression* _additionalValue = nullptr
@@ -116,7 +127,7 @@ private:
std::string const& _description
);
/// Checks that the value is in the range given by the type.
- void checkUnderOverflow(smt::Expression _value, IntegerType const& _Type, SourceLocation const& _location);
+ void checkUnderOverflow(smt::Expression _value, IntegerType const& _Type, langutil::SourceLocation const& _location);
std::pair<smt::CheckResult, std::vector<std::string>>
@@ -151,8 +162,10 @@ private:
/// Sets the value of the declaration to zero.
void setZeroValue(VariableDeclaration const& _decl);
+ void setZeroValue(SymbolicVariable& _variable);
/// Resets the variable to an unknown value (in its range).
void setUnknownValue(VariableDeclaration const& decl);
+ void setUnknownValue(SymbolicVariable& _variable);
/// Returns the expression corresponding to the AST node. Throws if the expression does not exist.
smt::Expression expr(Expression const& _e);
@@ -193,9 +206,14 @@ private:
std::unordered_map<Expression const*, std::shared_ptr<SymbolicVariable>> m_expressions;
std::unordered_map<VariableDeclaration const*, std::shared_ptr<SymbolicVariable>> m_variables;
std::unordered_map<std::string, std::shared_ptr<SymbolicVariable>> m_specialVariables;
+ /// Stores the declaration of an Uninterpreted Function.
+ std::unordered_map<std::string, smt::Expression> m_uninterpretedFunctions;
+ /// Stores the instances of an Uninterpreted Function applied to arguments.
+ /// Used to retrieve models.
+ std::vector<Expression const*> m_uninterpretedTerms;
std::vector<smt::Expression> m_pathConditions;
- ErrorReporter& m_errorReporter;
- std::shared_ptr<Scanner> m_scanner;
+ langutil::ErrorReporter& m_errorReporter;
+ std::shared_ptr<langutil::Scanner> m_scanner;
/// Stores the current path of function calls.
std::vector<FunctionDefinition const*> m_functionPath;
diff --git a/libsolidity/formal/SMTLib2Interface.cpp b/libsolidity/formal/SMTLib2Interface.cpp
index a6c1f87c..3cfa01b1 100644
--- a/libsolidity/formal/SMTLib2Interface.cpp
+++ b/libsolidity/formal/SMTLib2Interface.cpp
@@ -17,9 +17,11 @@
#include <libsolidity/formal/SMTLib2Interface.h>
-#include <libsolidity/interface/Exceptions.h>
+#include <liblangutil/Exceptions.h>
#include <libsolidity/interface/ReadFile.h>
+#include <libdevcore/Keccak256.h>
+
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/join.hpp>
#include <boost/filesystem/operations.hpp>
@@ -37,8 +39,8 @@ using namespace dev;
using namespace dev::solidity;
using namespace dev::solidity::smt;
-SMTLib2Interface::SMTLib2Interface(ReadCallback::Callback const& _queryCallback):
- m_queryCallback(_queryCallback)
+SMTLib2Interface::SMTLib2Interface(map<h256, string> const& _queryResponses):
+ m_queryResponses(_queryResponses)
{
reset();
}
@@ -47,8 +49,7 @@ void SMTLib2Interface::reset()
{
m_accumulatedOutput.clear();
m_accumulatedOutput.emplace_back();
- m_constants.clear();
- m_functions.clear();
+ m_variables.clear();
write("(set-option :produce-models true)");
write("(set-logic QF_UFLIA)");
}
@@ -64,42 +65,39 @@ void SMTLib2Interface::pop()
m_accumulatedOutput.pop_back();
}
-void SMTLib2Interface::declareFunction(string _name, Sort _domain, Sort _codomain)
+void SMTLib2Interface::declareVariable(string const& _name, Sort const& _sort)
+{
+ if (_sort.kind == Kind::Function)
+ declareFunction(_name, _sort);
+ else if (!m_variables.count(_name))
+ {
+ m_variables.insert(_name);
+ write("(declare-fun |" + _name + "| () " + toSmtLibSort(_sort) + ')');
+ }
+}
+
+void SMTLib2Interface::declareFunction(string const& _name, Sort const& _sort)
{
+ solAssert(_sort.kind == smt::Kind::Function, "");
// TODO Use domain and codomain as key as well
- if (!m_functions.count(_name))
+ if (!m_variables.count(_name))
{
- m_functions.insert(_name);
+ FunctionSort fSort = dynamic_cast<FunctionSort const&>(_sort);
+ string domain = toSmtLibSort(fSort.domain);
+ string codomain = toSmtLibSort(*fSort.codomain);
+ m_variables.insert(_name);
write(
"(declare-fun |" +
_name +
- "| (" +
- (_domain == Sort::Int ? "Int" : "Bool") +
- ") " +
- (_codomain == Sort::Int ? "Int" : "Bool") +
+ "| " +
+ domain +
+ " " +
+ codomain +
")"
);
}
}
-void SMTLib2Interface::declareInteger(string _name)
-{
- if (!m_constants.count(_name))
- {
- m_constants.insert(_name);
- write("(declare-const |" + _name + "| Int)");
- }
-}
-
-void SMTLib2Interface::declareBool(string _name)
-{
- if (!m_constants.count(_name))
- {
- m_constants.insert(_name);
- write("(declare-const |" + _name + "| Bool)");
- }
-}
-
void SMTLib2Interface::addAssertion(Expression const& _expr)
{
write("(assert " + toSExpr(_expr) + ")");
@@ -140,6 +138,33 @@ string SMTLib2Interface::toSExpr(Expression const& _expr)
return sexpr;
}
+string SMTLib2Interface::toSmtLibSort(Sort const& _sort)
+{
+ switch (_sort.kind)
+ {
+ case Kind::Int:
+ return "Int";
+ case Kind::Bool:
+ return "Bool";
+ case Kind::Array:
+ {
+ auto const& arraySort = dynamic_cast<ArraySort const&>(_sort);
+ return "(Array " + toSmtLibSort(*arraySort.domain) + ' ' + toSmtLibSort(*arraySort.range) + ')';
+ }
+ default:
+ solAssert(false, "Invalid SMT sort");
+ }
+}
+
+string SMTLib2Interface::toSmtLibSort(vector<SortPointer> const& _sorts)
+{
+ string ssort("(");
+ for (auto const& sort: _sorts)
+ ssort += toSmtLibSort(*sort) + " ";
+ ssort += ")";
+ return ssort;
+}
+
void SMTLib2Interface::write(string _data)
{
solAssert(!m_accumulatedOutput.empty(), "");
@@ -157,8 +182,8 @@ string SMTLib2Interface::checkSatAndGetValuesCommand(vector<Expression> const& _
for (size_t i = 0; i < _expressionsToEvaluate.size(); i++)
{
auto const& e = _expressionsToEvaluate.at(i);
- solAssert(e.sort == Sort::Int || e.sort == Sort::Bool, "Invalid sort for expression to evaluate.");
- command += "(declare-const |EVALEXPR_" + to_string(i) + "| " + (e.sort == Sort::Int ? "Int" : "Bool") + ")\n";
+ solAssert(e.sort->kind == Kind::Int || e.sort->kind == Kind::Bool, "Invalid sort for expression to evaluate.");
+ command += "(declare-const |EVALEXPR_" + to_string(i) + "| " + (e.sort->kind == Kind::Int ? "Int" : "Bool") + ")\n";
command += "(assert (= |EVALEXPR_" + to_string(i) + "| " + toSExpr(e) + "))\n";
}
command += "(check-sat)\n";
@@ -189,11 +214,12 @@ vector<string> SMTLib2Interface::parseValues(string::const_iterator _start, stri
string SMTLib2Interface::querySolver(string const& _input)
{
- if (!m_queryCallback)
- BOOST_THROW_EXCEPTION(SolverError() << errinfo_comment("No SMT solver available."));
-
- ReadCallback::Result queryResult = m_queryCallback(_input);
- if (!queryResult.success)
- BOOST_THROW_EXCEPTION(SolverError() << errinfo_comment(queryResult.responseOrErrorMessage));
- return queryResult.responseOrErrorMessage;
+ h256 inputHash = dev::keccak256(_input);
+ if (m_queryResponses.count(inputHash))
+ return m_queryResponses.at(inputHash);
+ else
+ {
+ m_unhandledQueries.push_back(_input);
+ return "unknown\n";
+ }
}
diff --git a/libsolidity/formal/SMTLib2Interface.h b/libsolidity/formal/SMTLib2Interface.h
index eb876a7f..55fc4096 100644
--- a/libsolidity/formal/SMTLib2Interface.h
+++ b/libsolidity/formal/SMTLib2Interface.h
@@ -19,9 +19,11 @@
#include <libsolidity/formal/SolverInterface.h>
-#include <libsolidity/interface/Exceptions.h>
+#include <liblangutil/Exceptions.h>
#include <libsolidity/interface/ReadFile.h>
+#include <libdevcore/FixedHash.h>
+
#include <libdevcore/Common.h>
#include <boost/noncopyable.hpp>
@@ -42,22 +44,26 @@ namespace smt
class SMTLib2Interface: public SolverInterface, public boost::noncopyable
{
public:
- explicit SMTLib2Interface(ReadCallback::Callback const& _queryCallback);
+ explicit SMTLib2Interface(std::map<h256, std::string> const& _queryResponses);
void reset() override;
void push() override;
void pop() override;
- void declareFunction(std::string _name, Sort _domain, Sort _codomain) override;
- void declareInteger(std::string _name) override;
- void declareBool(std::string _name) override;
+ void declareVariable(std::string const&, Sort const&) override;
void addAssertion(Expression const& _expr) override;
std::pair<CheckResult, std::vector<std::string>> check(std::vector<Expression> const& _expressionsToEvaluate) override;
+ std::vector<std::string> unhandledQueries() override { return m_unhandledQueries; }
+
private:
+ void declareFunction(std::string const&, Sort const&);
+
std::string toSExpr(Expression const& _expr);
+ std::string toSmtLibSort(Sort const& _sort);
+ std::string toSmtLibSort(std::vector<SortPointer> const& _sort);
void write(std::string _data);
@@ -67,10 +73,11 @@ private:
/// Communicates with the solver via the callback. Throws SMTSolverError on error.
std::string querySolver(std::string const& _input);
- ReadCallback::Callback m_queryCallback;
std::vector<std::string> m_accumulatedOutput;
- std::set<std::string> m_constants;
- std::set<std::string> m_functions;
+ std::set<std::string> m_variables;
+
+ std::map<h256, std::string> const& m_queryResponses;
+ std::vector<std::string> m_unhandledQueries;
};
}
diff --git a/libsolidity/formal/SMTPortfolio.cpp b/libsolidity/formal/SMTPortfolio.cpp
index 8b9fe9ce..2a109b89 100644
--- a/libsolidity/formal/SMTPortfolio.cpp
+++ b/libsolidity/formal/SMTPortfolio.cpp
@@ -23,27 +23,22 @@
#ifdef HAVE_CVC4
#include <libsolidity/formal/CVC4Interface.h>
#endif
-#if !defined (HAVE_Z3) && !defined (HAVE_CVC4)
#include <libsolidity/formal/SMTLib2Interface.h>
-#endif
using namespace std;
using namespace dev;
using namespace dev::solidity;
using namespace dev::solidity::smt;
-SMTPortfolio::SMTPortfolio(ReadCallback::Callback const& _readCallback)
+SMTPortfolio::SMTPortfolio(map<h256, string> const& _smtlib2Responses)
{
+ m_solvers.emplace_back(make_shared<smt::SMTLib2Interface>(_smtlib2Responses));
#ifdef HAVE_Z3
m_solvers.emplace_back(make_shared<smt::Z3Interface>());
#endif
#ifdef HAVE_CVC4
m_solvers.emplace_back(make_shared<smt::CVC4Interface>());
#endif
-#if !defined (HAVE_Z3) && !defined (HAVE_CVC4)
- m_solvers.emplace_back(make_shared<smt::SMTLib2Interface>(_readCallback)),
-#endif
- (void)_readCallback;
}
void SMTPortfolio::reset()
@@ -64,22 +59,10 @@ void SMTPortfolio::pop()
s->pop();
}
-void SMTPortfolio::declareFunction(string _name, Sort _domain, Sort _codomain)
-{
- for (auto s : m_solvers)
- s->declareFunction(_name, _domain, _codomain);
-}
-
-void SMTPortfolio::declareInteger(string _name)
-{
- for (auto s : m_solvers)
- s->declareInteger(_name);
-}
-
-void SMTPortfolio::declareBool(string _name)
+void SMTPortfolio::declareVariable(string const& _name, Sort const& _sort)
{
for (auto s : m_solvers)
- s->declareBool(_name);
+ s->declareVariable(_name, _sort);
}
void SMTPortfolio::addAssertion(Expression const& _expr)
diff --git a/libsolidity/formal/SMTPortfolio.h b/libsolidity/formal/SMTPortfolio.h
index 96c7ff57..7f5ba37e 100644
--- a/libsolidity/formal/SMTPortfolio.h
+++ b/libsolidity/formal/SMTPortfolio.h
@@ -22,8 +22,11 @@
#include <libsolidity/interface/ReadFile.h>
+#include <libdevcore/FixedHash.h>
+
#include <boost/noncopyable.hpp>
+#include <map>
#include <vector>
namespace dev
@@ -42,20 +45,19 @@ namespace smt
class SMTPortfolio: public SolverInterface, public boost::noncopyable
{
public:
- SMTPortfolio(ReadCallback::Callback const& _readCallback);
+ SMTPortfolio(std::map<h256, std::string> const& _smtlib2Responses);
void reset() override;
void push() override;
void pop() override;
- void declareFunction(std::string _name, Sort _domain, Sort _codomain) override;
- void declareInteger(std::string _name) override;
- void declareBool(std::string _name) override;
+ void declareVariable(std::string const&, Sort const&) override;
void addAssertion(Expression const& _expr) override;
std::pair<CheckResult, std::vector<std::string>> check(std::vector<Expression> const& _expressionsToEvaluate) override;
+ std::vector<std::string> unhandledQueries() override { return m_solvers.at(0)->unhandledQueries(); }
private:
static bool solverAnswered(CheckResult result);
diff --git a/libsolidity/formal/SolverInterface.h b/libsolidity/formal/SolverInterface.h
index af1cc8e4..4a4b3fb1 100644
--- a/libsolidity/formal/SolverInterface.h
+++ b/libsolidity/formal/SolverInterface.h
@@ -17,7 +17,7 @@
#pragma once
-#include <libsolidity/interface/Exceptions.h>
+#include <liblangutil/Exceptions.h>
#include <libsolidity/interface/ReadFile.h>
#include <libdevcore/Common.h>
@@ -42,12 +42,68 @@ enum class CheckResult
SATISFIABLE, UNSATISFIABLE, UNKNOWN, CONFLICTING, ERROR
};
-enum class Sort
+enum class Kind
{
Int,
Bool,
- IntIntFun, // Function of one Int returning a single Int
- IntBoolFun // Function of one Int returning a single Bool
+ Function,
+ Array
+};
+
+struct Sort
+{
+ Sort(Kind _kind):
+ kind(_kind) {}
+ virtual ~Sort() = default;
+ virtual bool operator==(Sort const& _other) const { return kind == _other.kind; }
+
+ Kind const kind;
+};
+using SortPointer = std::shared_ptr<Sort>;
+
+struct FunctionSort: public Sort
+{
+ FunctionSort(std::vector<SortPointer> _domain, SortPointer _codomain):
+ Sort(Kind::Function), domain(std::move(_domain)), codomain(std::move(_codomain)) {}
+ bool operator==(Sort const& _other) const override
+ {
+ if (!Sort::operator==(_other))
+ return false;
+ auto _otherFunction = dynamic_cast<FunctionSort const*>(&_other);
+ solAssert(_otherFunction, "");
+ if (domain.size() != _otherFunction->domain.size())
+ return false;
+ if (!std::equal(
+ domain.begin(),
+ domain.end(),
+ _otherFunction->domain.begin(),
+ [&](SortPointer _a, SortPointer _b) { return *_a == *_b; }
+ ))
+ return false;
+ return *codomain == *_otherFunction->codomain;
+ }
+
+ std::vector<SortPointer> domain;
+ SortPointer codomain;
+};
+
+struct ArraySort: public Sort
+{
+ /// _domain is the sort of the indices
+ /// _range is the sort of the values
+ ArraySort(SortPointer _domain, SortPointer _range):
+ Sort(Kind::Array), domain(std::move(_domain)), range(std::move(_range)) {}
+ bool operator==(Sort const& _other) const override
+ {
+ if (!Sort::operator==(_other))
+ return false;
+ auto _otherArray = dynamic_cast<ArraySort const*>(&_other);
+ solAssert(_otherArray, "");
+ return *domain == *_otherArray->domain && *range == *_otherArray->range;
+ }
+
+ SortPointer domain;
+ SortPointer range;
};
/// C++ representation of an SMTLIB2 expression.
@@ -55,10 +111,10 @@ class Expression
{
friend class SolverInterface;
public:
- explicit Expression(bool _v): name(_v ? "true" : "false"), sort(Sort::Bool) {}
- Expression(size_t _number): name(std::to_string(_number)), sort(Sort::Int) {}
- Expression(u256 const& _number): name(_number.str()), sort(Sort::Int) {}
- Expression(bigint const& _number): name(_number.str()), sort(Sort::Int) {}
+ explicit Expression(bool _v): Expression(_v ? "true" : "false", Kind::Bool) {}
+ Expression(size_t _number): Expression(std::to_string(_number), Kind::Int) {}
+ Expression(u256 const& _number): Expression(_number.str(), Kind::Int) {}
+ Expression(bigint const& _number): Expression(_number.str(), Kind::Int) {}
Expression(Expression const&) = default;
Expression(Expression&&) = default;
@@ -80,17 +136,20 @@ public:
{"+", 2},
{"-", 2},
{"*", 2},
- {"/", 2}
+ {"/", 2},
+ {"select", 2},
+ {"store", 3}
};
return operatorsArity.count(name) && operatorsArity.at(name) == arguments.size();
}
static Expression ite(Expression _condition, Expression _trueValue, Expression _falseValue)
{
- solAssert(_trueValue.sort == _falseValue.sort, "");
+ solAssert(*_trueValue.sort == *_falseValue.sort, "");
+ SortPointer sort = _trueValue.sort;
return Expression("ite", std::vector<Expression>{
std::move(_condition), std::move(_trueValue), std::move(_falseValue)
- }, _trueValue.sort);
+ }, std::move(sort));
}
static Expression implies(Expression _a, Expression _b)
@@ -98,21 +157,51 @@ public:
return !std::move(_a) || std::move(_b);
}
+ /// select is the SMT representation of an array index access.
+ static Expression select(Expression _array, Expression _index)
+ {
+ solAssert(_array.sort->kind == Kind::Array, "");
+ auto const& arraySort = dynamic_cast<ArraySort const*>(_array.sort.get());
+ solAssert(arraySort, "");
+ solAssert(*arraySort->domain == *_index.sort, "");
+ return Expression(
+ "select",
+ std::vector<Expression>{std::move(_array), std::move(_index)},
+ arraySort->range
+ );
+ }
+
+ /// store is the SMT representation of an assignment to array index.
+ /// The function is pure and returns the modified array.
+ static Expression store(Expression _array, Expression _index, Expression _element)
+ {
+ solAssert(_array.sort->kind == Kind::Array, "");
+ auto const& arraySort = dynamic_cast<ArraySort const*>(_array.sort.get());
+ solAssert(arraySort, "");
+ solAssert(*arraySort->domain == *_index.sort, "");
+ solAssert(*arraySort->range == *_element.sort, "");
+ return Expression(
+ "store",
+ std::vector<Expression>{std::move(_array), std::move(_index), std::move(_element)},
+ _array.sort
+ );
+ }
+
friend Expression operator!(Expression _a)
{
- return Expression("not", std::move(_a), Sort::Bool);
+ return Expression("not", std::move(_a), Kind::Bool);
}
friend Expression operator&&(Expression _a, Expression _b)
{
- return Expression("and", std::move(_a), std::move(_b), Sort::Bool);
+ return Expression("and", std::move(_a), std::move(_b), Kind::Bool);
}
friend Expression operator||(Expression _a, Expression _b)
{
- return Expression("or", std::move(_a), std::move(_b), Sort::Bool);
+ return Expression("or", std::move(_a), std::move(_b), Kind::Bool);
}
friend Expression operator==(Expression _a, Expression _b)
{
- return Expression("=", std::move(_a), std::move(_b), Sort::Bool);
+ return Expression("=", std::move(_a), std::move(_b), Kind::Bool);
}
friend Expression operator!=(Expression _a, Expression _b)
{
@@ -120,72 +209,64 @@ public:
}
friend Expression operator<(Expression _a, Expression _b)
{
- return Expression("<", std::move(_a), std::move(_b), Sort::Bool);
+ return Expression("<", std::move(_a), std::move(_b), Kind::Bool);
}
friend Expression operator<=(Expression _a, Expression _b)
{
- return Expression("<=", std::move(_a), std::move(_b), Sort::Bool);
+ return Expression("<=", std::move(_a), std::move(_b), Kind::Bool);
}
friend Expression operator>(Expression _a, Expression _b)
{
- return Expression(">", std::move(_a), std::move(_b), Sort::Bool);
+ return Expression(">", std::move(_a), std::move(_b), Kind::Bool);
}
friend Expression operator>=(Expression _a, Expression _b)
{
- return Expression(">=", std::move(_a), std::move(_b), Sort::Bool);
+ return Expression(">=", std::move(_a), std::move(_b), Kind::Bool);
}
friend Expression operator+(Expression _a, Expression _b)
{
- return Expression("+", std::move(_a), std::move(_b), Sort::Int);
+ return Expression("+", std::move(_a), std::move(_b), Kind::Int);
}
friend Expression operator-(Expression _a, Expression _b)
{
- return Expression("-", std::move(_a), std::move(_b), Sort::Int);
+ return Expression("-", std::move(_a), std::move(_b), Kind::Int);
}
friend Expression operator*(Expression _a, Expression _b)
{
- return Expression("*", std::move(_a), std::move(_b), Sort::Int);
+ return Expression("*", std::move(_a), std::move(_b), Kind::Int);
}
friend Expression operator/(Expression _a, Expression _b)
{
- return Expression("/", std::move(_a), std::move(_b), Sort::Int);
+ return Expression("/", std::move(_a), std::move(_b), Kind::Int);
}
- Expression operator()(Expression _a) const
+ Expression operator()(std::vector<Expression> _arguments) const
{
solAssert(
- arguments.empty(),
+ sort->kind == Kind::Function,
"Attempted function application to non-function."
);
- switch (sort)
- {
- case Sort::IntIntFun:
- return Expression(name, _a, Sort::Int);
- case Sort::IntBoolFun:
- return Expression(name, _a, Sort::Bool);
- default:
- solAssert(
- false,
- "Attempted function application to invalid type."
- );
- break;
- }
+ auto fSort = dynamic_cast<FunctionSort const*>(sort.get());
+ solAssert(fSort, "");
+ return Expression(name, std::move(_arguments), fSort->codomain);
}
std::string name;
std::vector<Expression> arguments;
- Sort sort;
+ SortPointer sort;
private:
- /// Manual constructor, should only be used by SolverInterface and this class itself.
- Expression(std::string _name, std::vector<Expression> _arguments, Sort _sort):
- name(std::move(_name)), arguments(std::move(_arguments)), sort(_sort) {}
-
- explicit Expression(std::string _name, Sort _sort):
- Expression(std::move(_name), std::vector<Expression>{}, _sort) {}
- Expression(std::string _name, Expression _arg, Sort _sort):
- Expression(std::move(_name), std::vector<Expression>{std::move(_arg)}, _sort) {}
- Expression(std::string _name, Expression _arg1, Expression _arg2, Sort _sort):
- Expression(std::move(_name), std::vector<Expression>{std::move(_arg1), std::move(_arg2)}, _sort) {}
+ /// Manual constructors, should only be used by SolverInterface and this class itself.
+ Expression(std::string _name, std::vector<Expression> _arguments, SortPointer _sort):
+ name(std::move(_name)), arguments(std::move(_arguments)), sort(std::move(_sort)) {}
+ Expression(std::string _name, std::vector<Expression> _arguments, Kind _kind):
+ Expression(std::move(_name), std::move(_arguments), std::make_shared<Sort>(_kind)) {}
+
+ explicit Expression(std::string _name, Kind _kind):
+ Expression(std::move(_name), std::vector<Expression>{}, _kind) {}
+ Expression(std::string _name, Expression _arg, Kind _kind):
+ Expression(std::move(_name), std::vector<Expression>{std::move(_arg)}, _kind) {}
+ Expression(std::string _name, Expression _arg1, Expression _arg2, Kind _kind):
+ Expression(std::move(_name), std::vector<Expression>{std::move(_arg1), std::move(_arg2)}, _kind) {}
};
DEV_SIMPLE_EXCEPTION(SolverError);
@@ -199,36 +280,12 @@ public:
virtual void push() = 0;
virtual void pop() = 0;
- virtual void declareFunction(std::string _name, Sort _domain, Sort _codomain) = 0;
- Expression newFunction(std::string _name, Sort _domain, Sort _codomain)
- {
- declareFunction(_name, _domain, _codomain);
- solAssert(_domain == Sort::Int, "Function sort not supported.");
- // Subclasses should do something here
- switch (_codomain)
- {
- case Sort::Int:
- return Expression(std::move(_name), {}, Sort::IntIntFun);
- case Sort::Bool:
- return Expression(std::move(_name), {}, Sort::IntBoolFun);
- default:
- solAssert(false, "Function sort not supported.");
- break;
- }
- }
- virtual void declareInteger(std::string _name) = 0;
- Expression newInteger(std::string _name)
+ virtual void declareVariable(std::string const& _name, Sort const& _sort) = 0;
+ Expression newVariable(std::string _name, SortPointer _sort)
{
// Subclasses should do something here
- declareInteger(_name);
- return Expression(std::move(_name), {}, Sort::Int);
- }
- virtual void declareBool(std::string _name) = 0;
- Expression newBool(std::string _name)
- {
- // Subclasses should do something here
- declareBool(_name);
- return Expression(std::move(_name), {}, Sort::Bool);
+ declareVariable(_name, *_sort);
+ return Expression(std::move(_name), {}, std::move(_sort));
}
virtual void addAssertion(Expression const& _expr) = 0;
@@ -238,6 +295,9 @@ public:
virtual std::pair<CheckResult, std::vector<std::string>>
check(std::vector<Expression> const& _expressionsToEvaluate) = 0;
+ /// @returns a list of queries that the system was not able to respond to.
+ virtual std::vector<std::string> unhandledQueries() { return {}; }
+
protected:
// SMT query timeout in milliseconds.
static int const queryTimeout = 10000;
diff --git a/libsolidity/formal/SymbolicTypes.cpp b/libsolidity/formal/SymbolicTypes.cpp
index 3eb1c1ce..c297c807 100644
--- a/libsolidity/formal/SymbolicTypes.cpp
+++ b/libsolidity/formal/SymbolicTypes.cpp
@@ -24,6 +24,50 @@
using namespace std;
using namespace dev::solidity;
+smt::SortPointer dev::solidity::smtSort(Type const& _type)
+{
+ switch (smtKind(_type.category()))
+ {
+ case smt::Kind::Int:
+ return make_shared<smt::Sort>(smt::Kind::Int);
+ case smt::Kind::Bool:
+ return make_shared<smt::Sort>(smt::Kind::Bool);
+ case smt::Kind::Function:
+ {
+ auto fType = dynamic_cast<FunctionType const*>(&_type);
+ solAssert(fType, "");
+ vector<smt::SortPointer> parameterSorts = smtSort(fType->parameterTypes());
+ auto returnTypes = fType->returnParameterTypes();
+ // TODO remove this when we support tuples.
+ solAssert(returnTypes.size() == 1, "");
+ smt::SortPointer returnSort = smtSort(*returnTypes.at(0));
+ return make_shared<smt::FunctionSort>(parameterSorts, returnSort);
+ }
+ case smt::Kind::Array:
+ {
+ solUnimplementedAssert(false, "Invalid type");
+ }
+ }
+ solAssert(false, "Invalid type");
+}
+
+vector<smt::SortPointer> dev::solidity::smtSort(vector<TypePointer> const& _types)
+{
+ vector<smt::SortPointer> sorts;
+ for (auto const& type: _types)
+ sorts.push_back(smtSort(*type));
+ return sorts;
+}
+
+smt::Kind dev::solidity::smtKind(Type::Category _category)
+{
+ if (isNumber(_category))
+ return smt::Kind::Int;
+ else if (isBool(_category))
+ return smt::Kind::Bool;
+ solAssert(false, "Invalid type");
+}
+
bool dev::solidity::isSupportedType(Type::Category _category)
{
return isNumber(_category) ||
@@ -125,3 +169,32 @@ smt::Expression dev::solidity::maxValue(IntegerType const& _type)
{
return smt::Expression(_type.maxValue());
}
+
+void dev::solidity::smt::setSymbolicZeroValue(SymbolicVariable const& _variable, smt::SolverInterface& _interface)
+{
+ setSymbolicZeroValue(_variable.currentValue(), _variable.type(), _interface);
+}
+
+void dev::solidity::smt::setSymbolicZeroValue(smt::Expression _expr, TypePointer const& _type, smt::SolverInterface& _interface)
+{
+ if (isInteger(_type->category()))
+ _interface.addAssertion(_expr == 0);
+ else if (isBool(_type->category()))
+ _interface.addAssertion(_expr == smt::Expression(false));
+}
+
+void dev::solidity::smt::setSymbolicUnknownValue(SymbolicVariable const& _variable, smt::SolverInterface& _interface)
+{
+ setSymbolicUnknownValue(_variable.currentValue(), _variable.type(), _interface);
+}
+
+void dev::solidity::smt::setSymbolicUnknownValue(smt::Expression _expr, TypePointer const& _type, smt::SolverInterface& _interface)
+{
+ if (isInteger(_type->category()))
+ {
+ auto intType = dynamic_cast<IntegerType const*>(_type.get());
+ solAssert(intType, "");
+ _interface.addAssertion(_expr >= minValue(*intType));
+ _interface.addAssertion(_expr <= maxValue(*intType));
+ }
+}
diff --git a/libsolidity/formal/SymbolicTypes.h b/libsolidity/formal/SymbolicTypes.h
index dcdd9ea4..984653b3 100644
--- a/libsolidity/formal/SymbolicTypes.h
+++ b/libsolidity/formal/SymbolicTypes.h
@@ -28,6 +28,12 @@ namespace dev
namespace solidity
{
+/// Returns the SMT sort that models the Solidity type _type.
+smt::SortPointer smtSort(Type const& _type);
+std::vector<smt::SortPointer> smtSort(std::vector<TypePointer> const& _types);
+/// Returns the SMT kind that models the Solidity type type category _category.
+smt::Kind smtKind(Type::Category _category);
+
/// So far int, bool and address are supported.
/// Returns true if type is supported.
bool isSupportedType(Type::Category _category);
@@ -49,5 +55,15 @@ std::pair<bool, std::shared_ptr<SymbolicVariable>> newSymbolicVariable(Type cons
smt::Expression minValue(IntegerType const& _type);
smt::Expression maxValue(IntegerType const& _type);
+namespace smt
+{
+
+void setSymbolicZeroValue(SymbolicVariable const& _variable, smt::SolverInterface& _interface);
+void setSymbolicZeroValue(smt::Expression _expr, TypePointer const& _type, smt::SolverInterface& _interface);
+void setSymbolicUnknownValue(SymbolicVariable const& _variable, smt::SolverInterface& _interface);
+void setSymbolicUnknownValue(smt::Expression _expr, TypePointer const& _type, smt::SolverInterface& _interface);
+
+}
+
}
}
diff --git a/libsolidity/formal/SymbolicVariables.cpp b/libsolidity/formal/SymbolicVariables.cpp
index 85818ba0..efaeb97a 100644
--- a/libsolidity/formal/SymbolicVariables.cpp
+++ b/libsolidity/formal/SymbolicVariables.cpp
@@ -37,6 +37,11 @@ SymbolicVariable::SymbolicVariable(
{
}
+string SymbolicVariable::currentName() const
+{
+ return uniqueSymbol(m_ssa->index());
+}
+
string SymbolicVariable::uniqueSymbol(unsigned _index) const
{
return m_uniqueName + "_" + to_string(_index);
@@ -54,16 +59,7 @@ SymbolicBoolVariable::SymbolicBoolVariable(
smt::Expression SymbolicBoolVariable::valueAtIndex(int _index) const
{
- return m_interface.newBool(uniqueSymbol(_index));
-}
-
-void SymbolicBoolVariable::setZeroValue()
-{
- m_interface.addAssertion(currentValue() == smt::Expression(false));
-}
-
-void SymbolicBoolVariable::setUnknownValue()
-{
+ return m_interface.newVariable(uniqueSymbol(_index), make_shared<smt::Sort>(smt::Kind::Bool));
}
SymbolicIntVariable::SymbolicIntVariable(
@@ -78,20 +74,7 @@ SymbolicIntVariable::SymbolicIntVariable(
smt::Expression SymbolicIntVariable::valueAtIndex(int _index) const
{
- return m_interface.newInteger(uniqueSymbol(_index));
-}
-
-void SymbolicIntVariable::setZeroValue()
-{
- m_interface.addAssertion(currentValue() == 0);
-}
-
-void SymbolicIntVariable::setUnknownValue()
-{
- auto intType = dynamic_cast<IntegerType const*>(m_type.get());
- solAssert(intType, "");
- m_interface.addAssertion(currentValue() >= minValue(*intType));
- m_interface.addAssertion(currentValue() <= maxValue(*intType));
+ return m_interface.newVariable(uniqueSymbol(_index), make_shared<smt::Sort>(smt::Kind::Int));
}
SymbolicAddressVariable::SymbolicAddressVariable(
diff --git a/libsolidity/formal/SymbolicVariables.h b/libsolidity/formal/SymbolicVariables.h
index 4fd9b245..fcf32760 100644
--- a/libsolidity/formal/SymbolicVariables.h
+++ b/libsolidity/formal/SymbolicVariables.h
@@ -51,6 +51,8 @@ public:
return valueAtIndex(m_ssa->index());
}
+ std::string currentName() const;
+
virtual smt::Expression valueAtIndex(int _index) const = 0;
smt::Expression increaseIndex()
@@ -62,20 +64,15 @@ public:
unsigned index() const { return m_ssa->index(); }
unsigned& index() { return m_ssa->index(); }
- /// Sets the var to the default value of its type.
- /// Inherited types must implement.
- virtual void setZeroValue() = 0;
- /// The unknown value is the full range of valid values.
- /// It is sub-type dependent, but not mandatory.
- virtual void setUnknownValue() {}
+ TypePointer const& type() const { return m_type; }
protected:
std::string uniqueSymbol(unsigned _index) const;
- TypePointer m_type = nullptr;
+ TypePointer m_type;
std::string m_uniqueName;
smt::SolverInterface& m_interface;
- std::shared_ptr<SSAVariable> m_ssa = nullptr;
+ std::shared_ptr<SSAVariable> m_ssa;
};
/**
@@ -90,11 +87,6 @@ public:
smt::SolverInterface& _interface
);
- /// Sets the var to false.
- void setZeroValue();
- /// Does nothing since the SMT solver already knows the valid values for Bool.
- void setUnknownValue();
-
protected:
smt::Expression valueAtIndex(int _index) const;
};
@@ -111,11 +103,6 @@ public:
smt::SolverInterface& _interface
);
- /// Sets the var to 0.
- void setZeroValue();
- /// Sets the variable to the full valid value range.
- void setUnknownValue();
-
protected:
smt::Expression valueAtIndex(int _index) const;
};
diff --git a/libsolidity/formal/Z3Interface.cpp b/libsolidity/formal/Z3Interface.cpp
index 9a0ccf48..cb01dc61 100644
--- a/libsolidity/formal/Z3Interface.cpp
+++ b/libsolidity/formal/Z3Interface.cpp
@@ -17,7 +17,7 @@
#include <libsolidity/formal/Z3Interface.h>
-#include <libsolidity/interface/Exceptions.h>
+#include <liblangutil/Exceptions.h>
#include <libdevcore/CommonIO.h>
@@ -51,22 +51,22 @@ void Z3Interface::pop()
m_solver.pop();
}
-void Z3Interface::declareFunction(string _name, Sort _domain, Sort _codomain)
+void Z3Interface::declareVariable(string const& _name, Sort const& _sort)
{
- if (!m_functions.count(_name))
- m_functions.insert({_name, m_context.function(_name.c_str(), z3Sort(_domain), z3Sort(_codomain))});
-}
-
-void Z3Interface::declareInteger(string _name)
-{
- if (!m_constants.count(_name))
- m_constants.insert({_name, m_context.int_const(_name.c_str())});
+ if (_sort.kind == Kind::Function)
+ declareFunction(_name, _sort);
+ else if (!m_constants.count(_name))
+ m_constants.insert({_name, m_context.constant(_name.c_str(), z3Sort(_sort))});
}
-void Z3Interface::declareBool(string _name)
+void Z3Interface::declareFunction(string const& _name, Sort const& _sort)
{
- if (!m_constants.count(_name))
- m_constants.insert({_name, m_context.bool_const(_name.c_str())});
+ solAssert(_sort.kind == smt::Kind::Function, "");
+ if (!m_functions.count(_name))
+ {
+ FunctionSort fSort = dynamic_cast<FunctionSort const&>(_sort);
+ m_functions.insert({_name, m_context.function(_name.c_str(), z3Sort(fSort.domain), z3Sort(*fSort.codomain))});
+ }
}
void Z3Interface::addAssertion(Expression const& _expr)
@@ -163,19 +163,28 @@ z3::expr Z3Interface::toZ3Expr(Expression const& _expr)
return arguments[0] * arguments[1];
else if (n == "/")
return arguments[0] / arguments[1];
+ else if (n == "select")
+ return z3::select(arguments[0], arguments[1]);
+ else if (n == "store")
+ return z3::store(arguments[0], arguments[1], arguments[2]);
// Cannot reach here.
solAssert(false, "");
return arguments[0];
}
-z3::sort Z3Interface::z3Sort(Sort _sort)
+z3::sort Z3Interface::z3Sort(Sort const& _sort)
{
- switch (_sort)
+ switch (_sort.kind)
{
- case Sort::Bool:
+ case Kind::Bool:
return m_context.bool_sort();
- case Sort::Int:
+ case Kind::Int:
return m_context.int_sort();
+ case Kind::Array:
+ {
+ auto const& arraySort = dynamic_cast<ArraySort const&>(_sort);
+ return m_context.array_sort(z3Sort(*arraySort.domain), z3Sort(*arraySort.range));
+ }
default:
break;
}
@@ -183,3 +192,11 @@ z3::sort Z3Interface::z3Sort(Sort _sort)
// Cannot be reached.
return m_context.int_sort();
}
+
+z3::sort_vector Z3Interface::z3Sort(vector<SortPointer> const& _sorts)
+{
+ z3::sort_vector z3Sorts(m_context);
+ for (auto const& _sort: _sorts)
+ z3Sorts.push_back(z3Sort(*_sort));
+ return z3Sorts;
+}
diff --git a/libsolidity/formal/Z3Interface.h b/libsolidity/formal/Z3Interface.h
index 84880ff3..86e1badd 100644
--- a/libsolidity/formal/Z3Interface.h
+++ b/libsolidity/formal/Z3Interface.h
@@ -40,16 +40,17 @@ public:
void push() override;
void pop() override;
- void declareFunction(std::string _name, Sort _domain, Sort _codomain) override;
- void declareInteger(std::string _name) override;
- void declareBool(std::string _name) override;
+ void declareVariable(std::string const& _name, Sort const& _sort) override;
void addAssertion(Expression const& _expr) override;
std::pair<CheckResult, std::vector<std::string>> check(std::vector<Expression> const& _expressionsToEvaluate) override;
private:
+ void declareFunction(std::string const& _name, Sort const& _sort);
+
z3::expr toZ3Expr(Expression const& _expr);
- z3::sort z3Sort(smt::Sort _sort);
+ z3::sort z3Sort(smt::Sort const& _sort);
+ z3::sort_vector z3Sort(std::vector<smt::SortPointer> const& _sorts);
z3::context m_context;
z3::solver m_solver;
diff --git a/libsolidity/inlineasm/AsmAnalysis.cpp b/libsolidity/inlineasm/AsmAnalysis.cpp
deleted file mode 100644
index ac019c06..00000000
--- a/libsolidity/inlineasm/AsmAnalysis.cpp
+++ /dev/null
@@ -1,630 +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 <libsolidity/interface/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 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 a8673efa..00000000
--- a/libsolidity/inlineasm/AsmAnalysis.h
+++ /dev/null
@@ -1,123 +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 <libsolidity/interface/Exceptions.h>
-#include <libsolidity/interface/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 dev
-{
-namespace solidity
-{
-class ErrorReporter;
-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,
- ErrorReporter& _errorReporter,
- EVMVersion _evmVersion,
- boost::optional<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, 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, SourceLocation const& _location);
- void warnOnInstructions(solidity::Instruction _instr, 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(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;
- ErrorReporter& m_errorReporter;
- EVMVersion m_evmVersion;
- AsmFlavour m_flavour = AsmFlavour::Loose;
- boost::optional<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 3a62b232..00000000
--- a/libsolidity/inlineasm/AsmCodeGen.cpp
+++ /dev/null
@@ -1,161 +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 <libevmasm/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 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 a8d5e327..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 <libevmasm/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 { SourceLocation location; YulString name; Type type; };
-using TypedNameList = std::vector<TypedName>;
-
-/// Direct EVM instruction (except PUSHi and JUMPDEST)
-struct Instruction { SourceLocation location; solidity::Instruction instruction; };
-/// Literal number or string (up to 32 bytes)
-enum class LiteralKind { Number, Boolean, String };
-struct Literal { SourceLocation location; LiteralKind kind; YulString value; Type type; };
-/// External / internal identifier or label reference
-struct Identifier { SourceLocation location; YulString name; };
-/// Jump label ("name:")
-struct Label { SourceLocation location; YulString name; };
-/// Assignment from stack (":= x", moves stack top into x, potentially multiple slots)
-struct StackAssignment { 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 { SourceLocation location; std::vector<Identifier> variableNames; std::shared_ptr<Expression> value; };
-/// Functional instruction, e.g. "mul(mload(20:u256), add(2:u256, x))"
-struct FunctionalInstruction { SourceLocation location; solidity::Instruction instruction; std::vector<Expression> arguments; };
-struct FunctionCall { SourceLocation location; Identifier functionName; std::vector<Expression> arguments; };
-/// Statement that contains only a single expression
-struct ExpressionStatement { SourceLocation location; Expression expression; };
-/// Block-scope variable declaration ("let x:u256 := mload(20:u256)"), non-hoisted
-struct VariableDeclaration { SourceLocation location; TypedNameList variables; std::shared_ptr<Expression> value; };
-/// Block that creates a scope (frees declared stack variables)
-struct Block { SourceLocation location; std::vector<Statement> statements; };
-/// Function definition ("function f(a, b) -> (d, e) { ... }")
-struct FunctionDefinition { SourceLocation location; YulString name; TypedNameList parameters; TypedNameList returnVariables; Block body; };
-/// Conditional execution without "else" part.
-struct If { SourceLocation location; std::shared_ptr<Expression> condition; Block body; };
-/// Switch case or default case
-struct Case { SourceLocation location; std::shared_ptr<Literal> value; Block body; };
-/// Switch statement
-struct Switch { SourceLocation location; std::shared_ptr<Expression> expression; std::vector<Case> cases; };
-struct ForLoop { SourceLocation location; Block pre; std::shared_ptr<Expression> condition; Block post; Block body; };
-
-struct LocationExtractor: boost::static_visitor<SourceLocation>
-{
- template <class T> SourceLocation operator()(T const& _node) const
- {
- return _node.location;
- }
-};
-
-/// Extracts the source location from an inline assembly node.
-template <class T> inline 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 1f399edc..00000000
--- a/libsolidity/inlineasm/AsmParser.cpp
+++ /dev/null
@@ -1,616 +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 <libsolidity/parsing/Scanner.h>
-#include <libsolidity/interface/ErrorReporter.h>
-
-#include <boost/algorithm/string.hpp>
-
-#include <cctype>
-#include <algorithm>
-
-using namespace std;
-using namespace dev;
-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 41117228..00000000
--- a/libsolidity/inlineasm/AsmParser.h
+++ /dev/null
@@ -1,93 +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 <libsolidity/parsing/ParserBase.h>
-
-namespace dev
-{
-namespace solidity
-{
-namespace assembly
-{
-
-class Parser: public ParserBase
-{
-public:
- explicit Parser(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<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(SourceLocation const& _loc = SourceLocation()) 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;
- }
- SourceLocation location() const { return SourceLocation(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 ae0bd1eb..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 <libsolidity/interface/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 65848018..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 <libsolidity/interface/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 d1f98083..00000000
--- a/libsolidity/inlineasm/AsmScopeFiller.cpp
+++ /dev/null
@@ -1,180 +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 <libsolidity/interface/ErrorReporter.h>
-#include <libsolidity/interface/Exceptions.h>
-
-#include <libdevcore/CommonData.h>
-
-#include <boost/range/adaptor/reversed.hpp>
-
-#include <memory>
-#include <functional>
-
-using namespace std;
-using namespace dev;
-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 bb023f61..00000000
--- a/libsolidity/inlineasm/AsmScopeFiller.h
+++ /dev/null
@@ -1,84 +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 dev
-{
-struct SourceLocation;
-namespace solidity
-{
-class ErrorReporter;
-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, 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,
- SourceLocation const& _location,
- Scope& _scope
- );
-
- Scope& scope(assembly::Block const* _block);
-
- Scope* m_currentScope = nullptr;
- AsmAnalysisInfo& m_info;
- ErrorReporter& m_errorReporter;
-};
-
-}
-}
-}
diff --git a/libsolidity/interface/AssemblyStack.cpp b/libsolidity/interface/AssemblyStack.cpp
index 26496de7..f5eb7e41 100644
--- a/libsolidity/interface/AssemblyStack.cpp
+++ b/libsolidity/interface/AssemblyStack.cpp
@@ -22,37 +22,40 @@
#include <libsolidity/interface/AssemblyStack.h>
-#include <libsolidity/parsing/Scanner.h>
-#include <libsolidity/inlineasm/AsmPrinter.h>
-#include <libsolidity/inlineasm/AsmParser.h>
-#include <libsolidity/inlineasm/AsmAnalysis.h>
-#include <libsolidity/inlineasm/AsmAnalysisInfo.h>
-#include <libsolidity/inlineasm/AsmCodeGen.h>
+#include <liblangutil/Scanner.h>
+#include <libyul/AsmPrinter.h>
+#include <libyul/AsmParser.h>
+#include <libyul/AsmAnalysis.h>
+#include <libyul/AsmAnalysisInfo.h>
+#include <libyul/AsmCodeGen.h>
+#include <libyul/backends/evm/EVMCodeTransform.h>
+#include <libyul/backends/evm/EVMAssembly.h>
+#include <libyul/ObjectParser.h>
#include <libevmasm/Assembly.h>
-#include <libyul/backends/evm/EVMCodeTransform.h>
-#include <libyul/backends/evm/EVMAssembly.h>
+#include <libyul/optimiser/Suite.h>
using namespace std;
using namespace dev;
+using namespace langutil;
using namespace dev::solidity;
namespace
{
-assembly::AsmFlavour languageToAsmFlavour(AssemblyStack::Language _language)
+yul::AsmFlavour languageToAsmFlavour(AssemblyStack::Language _language)
{
switch (_language)
{
case AssemblyStack::Language::Assembly:
- return assembly::AsmFlavour::Loose;
+ return yul::AsmFlavour::Loose;
case AssemblyStack::Language::StrictAssembly:
- return assembly::AsmFlavour::Strict;
+ return yul::AsmFlavour::Strict;
case AssemblyStack::Language::Yul:
- return assembly::AsmFlavour::Yul;
+ return yul::AsmFlavour::Yul;
}
solAssert(false, "");
- return assembly::AsmFlavour::Yul;
+ return yul::AsmFlavour::Yul;
}
}
@@ -68,31 +71,30 @@ bool AssemblyStack::parseAndAnalyze(std::string const& _sourceName, std::string
{
m_errors.clear();
m_analysisSuccessful = false;
- m_scanner = make_shared<Scanner>(CharStream(_source), _sourceName);
- m_parserResult = assembly::Parser(m_errorReporter, languageToAsmFlavour(m_language)).parse(m_scanner, false);
+ m_scanner = make_shared<Scanner>(CharStream(_source, _sourceName));
+ m_parserResult = yul::ObjectParser(m_errorReporter, languageToAsmFlavour(m_language)).parse(m_scanner, false);
if (!m_errorReporter.errors().empty())
return false;
solAssert(m_parserResult, "");
+ solAssert(m_parserResult->code, "");
return analyzeParsed();
}
-bool AssemblyStack::analyze(assembly::Block const& _block, Scanner const* _scanner)
+void AssemblyStack::optimize()
{
- m_errors.clear();
- m_analysisSuccessful = false;
- if (_scanner)
- m_scanner = make_shared<Scanner>(*_scanner);
- m_parserResult = make_shared<assembly::Block>(_block);
-
- return analyzeParsed();
+ solAssert(m_language != Language::Assembly, "Optimization requested for loose assembly.");
+ yul::OptimiserSuite::run(*m_parserResult->code, *m_parserResult->analysisInfo);
+ solAssert(analyzeParsed(), "Invalid source code after optimization.");
}
bool AssemblyStack::analyzeParsed()
{
- m_analysisInfo = make_shared<assembly::AsmAnalysisInfo>();
- assembly::AsmAnalyzer analyzer(*m_analysisInfo, m_errorReporter, m_evmVersion, boost::none, languageToAsmFlavour(m_language));
- m_analysisSuccessful = analyzer.analyze(*m_parserResult);
+ solAssert(m_parserResult, "");
+ solAssert(m_parserResult->code, "");
+ m_parserResult->analysisInfo = make_shared<yul::AsmAnalysisInfo>();
+ yul::AsmAnalyzer analyzer(*m_parserResult->analysisInfo, m_errorReporter, m_evmVersion, boost::none, languageToAsmFlavour(m_language));
+ m_analysisSuccessful = analyzer.analyze(*m_parserResult->code);
return m_analysisSuccessful;
}
@@ -100,7 +102,8 @@ MachineAssemblyObject AssemblyStack::assemble(Machine _machine) const
{
solAssert(m_analysisSuccessful, "");
solAssert(m_parserResult, "");
- solAssert(m_analysisInfo, "");
+ solAssert(m_parserResult->code, "");
+ solAssert(m_parserResult->analysisInfo, "");
switch (_machine)
{
@@ -108,7 +111,7 @@ MachineAssemblyObject AssemblyStack::assemble(Machine _machine) const
{
MachineAssemblyObject object;
eth::Assembly assembly;
- assembly::CodeGenerator::assemble(*m_parserResult, *m_analysisInfo, assembly);
+ yul::CodeGenerator::assemble(*m_parserResult->code, *m_parserResult->analysisInfo, assembly);
object.bytecode = make_shared<eth::LinkerObject>(assembly.assemble());
object.assembly = assembly.assemblyString();
return object;
@@ -117,7 +120,7 @@ MachineAssemblyObject AssemblyStack::assemble(Machine _machine) const
{
MachineAssemblyObject object;
yul::EVMAssembly assembly(true);
- yul::CodeTransform(assembly, *m_analysisInfo, m_language == Language::Yul, true)(*m_parserResult);
+ yul::CodeTransform(assembly, *m_parserResult->analysisInfo, m_language == Language::Yul, true)(*m_parserResult->code);
object.bytecode = make_shared<eth::LinkerObject>(assembly.finalize());
/// TODO: fill out text representation
return object;
@@ -132,5 +135,6 @@ MachineAssemblyObject AssemblyStack::assemble(Machine _machine) const
string AssemblyStack::print() const
{
solAssert(m_parserResult, "");
- return assembly::AsmPrinter(m_language == Language::Yul)(*m_parserResult);
+ solAssert(m_parserResult->code, "");
+ return m_parserResult->toString(m_language == Language::Yul) + "\n";
}
diff --git a/libsolidity/interface/AssemblyStack.h b/libsolidity/interface/AssemblyStack.h
index 8132ce63..0d04ffec 100644
--- a/libsolidity/interface/AssemblyStack.h
+++ b/libsolidity/interface/AssemblyStack.h
@@ -21,24 +21,26 @@
#pragma once
-#include <libsolidity/interface/ErrorReporter.h>
-#include <libsolidity/interface/EVMVersion.h>
+#include <liblangutil/ErrorReporter.h>
+#include <liblangutil/EVMVersion.h>
+
+#include <libyul/Object.h>
+#include <libyul/ObjectParser.h>
#include <libevmasm/LinkerObject.h>
#include <string>
#include <memory>
+namespace langutil
+{
+class Scanner;
+}
+
namespace dev
{
namespace solidity
{
-class Scanner;
-namespace assembly
-{
-struct AsmAnalysisInfo;
-struct Block;
-}
struct MachineAssemblyObject
{
@@ -61,21 +63,20 @@ public:
{}
/// @returns the scanner used during parsing
- Scanner const& scanner() const;
+ langutil::Scanner const& scanner() const;
/// Runs parsing and analysis steps, returns false if input cannot be assembled.
/// Multiple calls overwrite the previous state.
bool parseAndAnalyze(std::string const& _sourceName, std::string const& _source);
- /// Runs analysis step on the supplied block, returns false if input cannot be assembled.
- /// Multiple calls overwrite the previous state.
- bool analyze(assembly::Block const& _block, Scanner const* _scanner = nullptr);
+ /// Run the optimizer suite. Can only be used with Yul or strict assembly.
+ void optimize();
/// Run the assembly step (should only be called after parseAndAnalyze).
MachineAssemblyObject assemble(Machine _machine) const;
/// @returns the errors generated during parsing, analysis (and potentially assembly).
- ErrorList const& errors() const { return m_errors; }
+ langutil::ErrorList const& errors() const { return m_errors; }
/// Pretty-print the input after having parsed it.
std::string print() const;
@@ -86,13 +87,12 @@ private:
Language m_language = Language::Assembly;
EVMVersion m_evmVersion;
- std::shared_ptr<Scanner> m_scanner;
+ std::shared_ptr<langutil::Scanner> m_scanner;
bool m_analysisSuccessful = false;
- std::shared_ptr<assembly::Block> m_parserResult;
- std::shared_ptr<assembly::AsmAnalysisInfo> m_analysisInfo;
- ErrorList m_errors;
- ErrorReporter m_errorReporter;
+ std::shared_ptr<yul::Object> m_parserResult;
+ langutil::ErrorList m_errors;
+ langutil::ErrorReporter m_errorReporter;
};
}
diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp
index 441c7897..610caea1 100644
--- a/libsolidity/interface/CompilerStack.cpp
+++ b/libsolidity/interface/CompilerStack.cpp
@@ -27,8 +27,8 @@
#include <libsolidity/interface/Version.h>
#include <libsolidity/analysis/SemVerHandler.h>
#include <libsolidity/ast/AST.h>
-#include <libsolidity/parsing/Scanner.h>
#include <libsolidity/parsing/Parser.h>
+#include <libsolidity/analysis/ContractLevelChecker.h>
#include <libsolidity/analysis/ControlFlowAnalyzer.h>
#include <libsolidity/analysis/ControlFlowGraph.h>
#include <libsolidity/analysis/GlobalContext.h>
@@ -45,10 +45,12 @@
#include <libsolidity/interface/Natspec.h>
#include <libsolidity/interface/GasEstimator.h>
-#include <libevmasm/Exceptions.h>
-
#include <libyul/YulString.h>
+#include <liblangutil/Scanner.h>
+
+#include <libevmasm/Exceptions.h>
+
#include <libdevcore/SwarmHash.h>
#include <libdevcore/JSON.h>
@@ -58,6 +60,7 @@
using namespace std;
using namespace dev;
+using namespace langutil;
using namespace dev::solidity;
boost::optional<CompilerStack::Remapping> CompilerStack::parseRemapping(string const& _remapping)
@@ -106,6 +109,8 @@ void CompilerStack::reset(bool _keepSources)
m_stackState = Empty;
m_sources.clear();
}
+ m_smtlib2Responses.clear();
+ m_unhandledSMTLib2Queries.clear();
m_libraries.clear();
m_evmVersion = EVMVersion();
m_optimize = false;
@@ -121,7 +126,7 @@ bool CompilerStack::addSource(string const& _name, string const& _content, bool
{
bool existed = m_sources.count(_name) != 0;
reset(true);
- m_sources[_name].scanner = make_shared<Scanner>(CharStream(_content), _name);
+ m_sources[_name].scanner = make_shared<Scanner>(CharStream(_content, _name));
m_sources[_name].isLibrary = _isLibrary;
m_stackState = SourcesSet;
return existed;
@@ -156,7 +161,7 @@ bool CompilerStack::parse()
{
string const& newPath = newSource.first;
string const& newContents = newSource.second;
- m_sources[newPath].scanner = make_shared<Scanner>(CharStream(newContents), newPath);
+ m_sources[newPath].scanner = make_shared<Scanner>(CharStream(newContents, newPath));
sourcesToParse.push_back(newPath);
}
}
@@ -221,8 +226,21 @@ bool CompilerStack::analyze()
m_contracts[contract->fullyQualifiedName()].contract = contract;
}
- // This cannot be done in the above loop, because cross-contract types couldn't be resolved.
- // A good example is `LibraryName.TypeName x;`.
+ // Next, we check inheritance, overrides, function collisions and other things at
+ // contract or function level.
+ // This also calculates whether a contract is abstract, which is needed by the
+ // type checker.
+ ContractLevelChecker contractLevelChecker(m_errorReporter);
+ for (Source const* source: m_sourceOrder)
+ for (ASTPointer<ASTNode> const& node: source->ast->nodes())
+ if (ContractDefinition* contract = dynamic_cast<ContractDefinition*>(node.get()))
+ if (!contractLevelChecker.check(*contract))
+ noErrors = false;
+
+ // New we run full type checks that go down to the expression level. This
+ // cannot be done earlier, because we need cross-contract types and information
+ // about whether a contract is abstract for the `new` expression.
+ // This populates the `type` annotation for all expressions.
//
// Note: this does not resolve overloaded functions. In order to do that, types of arguments are needed,
// which is only done one step later.
@@ -282,9 +300,10 @@ bool CompilerStack::analyze()
if (noErrors)
{
- SMTChecker smtChecker(m_errorReporter, m_smtQuery);
+ SMTChecker smtChecker(m_errorReporter, m_smtlib2Responses);
for (Source const* source: m_sourceOrder)
smtChecker.analyze(*source->ast, source->scanner);
+ m_unhandledSMTLib2Queries += smtChecker.unhandledQueries();
}
}
catch(FatalError const&)
@@ -329,13 +348,14 @@ bool CompilerStack::compile()
if (auto contract = dynamic_cast<ContractDefinition const*>(node.get()))
if (isRequestedContract(*contract))
compileContract(*contract, compiledContracts);
- this->link();
m_stackState = CompilationSuccessful;
+ this->link();
return true;
}
void CompilerStack::link()
{
+ solAssert(m_stackState >= CompilationSuccessful, "");
for (auto& contract: m_contracts)
{
contract.second.object.link(m_libraries);
@@ -353,6 +373,19 @@ vector<string> CompilerStack::contractNames() const
return contractNames;
}
+string const CompilerStack::lastContractName() const
+{
+ if (m_stackState < AnalysisSuccessful)
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
+ // try to find some user-supplied contract
+ string contractName;
+ for (auto const& it: m_sources)
+ for (ASTPointer<ASTNode> const& node: it.second.ast->nodes())
+ if (auto contract = dynamic_cast<ContractDefinition const*>(node.get()))
+ contractName = contract->fullyQualifiedName();
+ return contractName;
+}
+
eth::AssemblyItems const* CompilerStack::assemblyItems(string const& _contractName) const
{
Contract const& currentContract = contract(_contractName);
@@ -389,6 +422,9 @@ string const* CompilerStack::runtimeSourceMapping(string const& _contractName) c
std::string const CompilerStack::filesystemFriendlyName(string const& _contractName) const
{
+ if (m_stackState < AnalysisSuccessful)
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("No compiled contracts found."));
+
// Look up the contract (by its fully-qualified name)
Contract const& matchContract = m_contracts.at(_contractName);
// Check to see if it could collide on name
@@ -576,14 +612,15 @@ tuple<int, int, int, int> CompilerStack::positionFromSourceLocation(SourceLocati
int startColumn;
int endLine;
int endColumn;
- tie(startLine, startColumn) = scanner(*_sourceLocation.sourceName).translatePositionToLineColumn(_sourceLocation.start);
- tie(endLine, endColumn) = scanner(*_sourceLocation.sourceName).translatePositionToLineColumn(_sourceLocation.end);
+ tie(startLine, startColumn) = scanner(_sourceLocation.source->name()).translatePositionToLineColumn(_sourceLocation.start);
+ tie(endLine, endColumn) = scanner(_sourceLocation.source->name()).translatePositionToLineColumn(_sourceLocation.end);
return make_tuple(++startLine, ++startColumn, ++endLine, ++endColumn);
}
StringMap CompilerStack::loadMissingSources(SourceUnit const& _ast, std::string const& _sourcePath)
{
+ solAssert(m_stackState < ParsingSuccessful, "");
StringMap newSources;
for (auto const& node: _ast.nodes())
if (ImportDirective const* import = dynamic_cast<ImportDirective*>(node.get()))
@@ -617,6 +654,7 @@ StringMap CompilerStack::loadMissingSources(SourceUnit const& _ast, std::string
string CompilerStack::applyRemapping(string const& _path, string const& _context)
{
+ solAssert(m_stackState < ParsingSuccessful, "");
// Try to find the longest prefix match in all remappings that are active in the current context.
auto isPrefixOf = [](string const& _a, string const& _b)
{
@@ -658,6 +696,8 @@ string CompilerStack::applyRemapping(string const& _path, string const& _context
void CompilerStack::resolveImports()
{
+ solAssert(m_stackState == ParsingSuccessful, "");
+
// topological sorting (depth first search) of the import graph, cutting potential cycles
vector<Source const*> sourceOrder;
set<Source const*> sourcesSeen;
@@ -702,6 +742,8 @@ void CompilerStack::compileContract(
map<ContractDefinition const*, eth::Assembly const*>& _compiledContracts
)
{
+ solAssert(m_stackState >= AnalysisSuccessful, "");
+
if (
_compiledContracts.count(&_contract) ||
!_contract.annotation().unimplementedFunctions.empty() ||
@@ -757,23 +799,9 @@ void CompilerStack::compileContract(
_compiledContracts[compiledContract.contract] = &compiler->assembly();
}
-string const CompilerStack::lastContractName() const
-{
- if (m_contracts.empty())
- BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("No compiled contracts found."));
- // try to find some user-supplied contract
- string contractName;
- for (auto const& it: m_sources)
- for (ASTPointer<ASTNode> const& node: it.second.ast->nodes())
- if (auto contract = dynamic_cast<ContractDefinition const*>(node.get()))
- contractName = contract->fullyQualifiedName();
- return contractName;
-}
-
CompilerStack::Contract const& CompilerStack::contract(string const& _contractName) const
{
- if (m_contracts.empty())
- BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("No compiled contracts found."));
+ solAssert(m_stackState >= AnalysisSuccessful, "");
auto it = m_contracts.find(_contractName);
if (it != m_contracts.end())
@@ -908,8 +936,8 @@ string CompilerStack::computeSourceMapping(eth::AssemblyItems const& _items) con
SourceLocation const& location = item.location();
int length = location.start != -1 && location.end != -1 ? location.end - location.start : -1;
int sourceIndex =
- location.sourceName && sourceIndicesMap.count(*location.sourceName) ?
- sourceIndicesMap.at(*location.sourceName) :
+ location.source && sourceIndicesMap.count(location.source->name()) ?
+ sourceIndicesMap.at(location.source->name()) :
-1;
char jump = '-';
if (item.getJumpType() == eth::AssemblyItem::JumpType::IntoFunction)
diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h
index 9a15fbf0..2c7add3b 100644
--- a/libsolidity/interface/CompilerStack.h
+++ b/libsolidity/interface/CompilerStack.h
@@ -23,11 +23,12 @@
#pragma once
-#include <libsolidity/interface/ErrorReporter.h>
#include <libsolidity/interface/ReadFile.h>
-#include <libsolidity/interface/EVMVersion.h>
-#include <libevmasm/SourceLocation.h>
+#include <liblangutil/ErrorReporter.h>
+#include <liblangutil/EVMVersion.h>
+#include <liblangutil/SourceLocation.h>
+
#include <libevmasm/LinkerObject.h>
#include <libdevcore/Common.h>
@@ -43,6 +44,11 @@
#include <vector>
#include <functional>
+namespace langutil
+{
+class Scanner;
+}
+
namespace dev
{
@@ -57,7 +63,6 @@ namespace solidity
{
// forward declarations
-class Scanner;
class ASTNode;
class ContractDefinition;
class FunctionDefinition;
@@ -65,7 +70,6 @@ class SourceUnit;
class Compiler;
class GlobalContext;
class Natspec;
-class Error;
class DeclarationContainer;
/**
@@ -100,7 +104,7 @@ public:
m_errorReporter(m_errorList) {}
/// @returns the list of errors that occurred during parsing and type checking.
- ErrorList const& errors() const { return m_errorReporter.errors(); }
+ langutil::ErrorList const& errors() const { return m_errorReporter.errors(); }
/// @returns the current state.
State state() const { return m_stackState; }
@@ -149,6 +153,9 @@ public:
/// @returns true if a source object by the name already existed and was replaced.
bool addSource(std::string const& _name, std::string const& _content, bool _isLibrary = false);
+ /// Adds a response to an SMTLib2 query (identified by the hash of the query input).
+ void addSMTLib2Response(h256 const& _hash, std::string const& _response) { m_smtlib2Responses[_hash] = _response; }
+
/// Parses all source units that were added
/// @returns false on error.
bool parse();
@@ -174,7 +181,7 @@ public:
std::map<std::string, unsigned> sourceIndices() const;
/// @returns the previously used scanner, useful for counting lines during error reporting.
- Scanner const& scanner(std::string const& _sourceName) const;
+ langutil::Scanner const& scanner(std::string const& _sourceName) const;
/// @returns the parsed source unit with the supplied name.
SourceUnit const& ast(std::string const& _sourceName) const;
@@ -182,7 +189,11 @@ public:
/// Helper function for logs printing. Do only use in error cases, it's quite expensive.
/// line and columns are numbered starting from 1 with following order:
/// start line, start column, end line, end column
- std::tuple<int, int, int, int> positionFromSourceLocation(SourceLocation const& _sourceLocation) const;
+ std::tuple<int, int, int, int> positionFromSourceLocation(langutil::SourceLocation const& _sourceLocation) const;
+
+ /// @returns a list of unhandled queries to the SMT solver (has to be supplied in a second run
+ /// by calling @a addSMTLib2Response).
+ std::vector<std::string> const& unhandledSMTLib2Queries() const { return m_unhandledSMTLib2Queries; }
/// @returns a list of the contract names in the sources.
std::vector<std::string> contractNames() const;
@@ -248,7 +259,7 @@ private:
/// The state per source unit. Filled gradually during parsing.
struct Source
{
- std::shared_ptr<Scanner> scanner;
+ std::shared_ptr<langutil::Scanner> scanner;
std::shared_ptr<SourceUnit> ast;
bool isLibrary = false;
void reset() { scanner.reset(); ast.reset(); }
@@ -330,7 +341,6 @@ private:
) const;
ReadCallback::Callback m_readFile;
- ReadCallback::Callback m_smtQuery;
bool m_optimize = false;
unsigned m_optimizeRuns = 200;
EVMVersion m_evmVersion;
@@ -340,13 +350,15 @@ private:
/// "context:prefix=target"
std::vector<Remapping> m_remappings;
std::map<std::string const, Source> m_sources;
+ std::vector<std::string> m_unhandledSMTLib2Queries;
+ std::map<h256, std::string> m_smtlib2Responses;
std::shared_ptr<GlobalContext> m_globalContext;
std::vector<Source const*> m_sourceOrder;
/// This is updated during compilation.
std::map<ASTNode const*, std::shared_ptr<DeclarationContainer>> m_scopes;
std::map<std::string const, Contract> m_contracts;
- ErrorList m_errorList;
- ErrorReporter m_errorReporter;
+ langutil::ErrorList m_errorList;
+ langutil::ErrorReporter m_errorReporter;
bool m_metadataLiteralSources = false;
State m_stackState = Empty;
};
diff --git a/libsolidity/interface/EVMVersion.h b/libsolidity/interface/EVMVersion.h
deleted file mode 100644
index 657727ac..00000000
--- a/libsolidity/interface/EVMVersion.h
+++ /dev/null
@@ -1,94 +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/>.
-*/
-/**
- * EVM versioning.
- */
-
-#pragma once
-
-#include <string>
-
-#include <boost/optional.hpp>
-#include <boost/operators.hpp>
-
-namespace dev
-{
-namespace solidity
-{
-
-/**
- * A version specifier of the EVM we want to compile to.
- * Defaults to the latest version.
- */
-class EVMVersion:
- boost::less_than_comparable<EVMVersion>,
- boost::equality_comparable<EVMVersion>
-{
-public:
- EVMVersion() {}
-
- static EVMVersion homestead() { return {Version::Homestead}; }
- static EVMVersion tangerineWhistle() { return {Version::TangerineWhistle}; }
- static EVMVersion spuriousDragon() { return {Version::SpuriousDragon}; }
- static EVMVersion byzantium() { return {Version::Byzantium}; }
- static EVMVersion constantinople() { return {Version::Constantinople}; }
-
- static boost::optional<EVMVersion> fromString(std::string const& _version)
- {
- for (auto const& v: {homestead(), tangerineWhistle(), spuriousDragon(), byzantium(), constantinople()})
- if (_version == v.name())
- return v;
- return {};
- }
-
- bool operator==(EVMVersion const& _other) const { return m_version == _other.m_version; }
- bool operator<(EVMVersion const& _other) const { return m_version < _other.m_version; }
-
- std::string name() const
- {
- switch (m_version)
- {
- case Version::Homestead: return "homestead";
- case Version::TangerineWhistle: return "tangerineWhistle";
- case Version::SpuriousDragon: return "spuriousDragon";
- case Version::Byzantium: return "byzantium";
- case Version::Constantinople: return "constantinople";
- }
- return "INVALID";
- }
-
- /// Has the RETURNDATACOPY and RETURNDATASIZE opcodes.
- bool supportsReturndata() const { return *this >= byzantium(); }
- bool hasStaticCall() const { return *this >= byzantium(); }
- bool hasBitwiseShifting() const { return *this >= constantinople(); }
- bool hasCreate2() const { return *this >= constantinople(); }
-
- /// Whether we have to retain the costs for the call opcode itself (false),
- /// or whether we can just forward easily all remaining gas (true).
- bool canOverchargeGasForCall() const { return *this >= tangerineWhistle(); }
-
-private:
- enum class Version { Homestead, TangerineWhistle, SpuriousDragon, Byzantium, Constantinople };
-
- EVMVersion(Version _version): m_version(_version) {}
-
- Version m_version = Version::Byzantium;
-};
-
-
-}
-}
diff --git a/libsolidity/interface/ErrorReporter.cpp b/libsolidity/interface/ErrorReporter.cpp
deleted file mode 100644
index 368e25e0..00000000
--- a/libsolidity/interface/ErrorReporter.cpp
+++ /dev/null
@@ -1,226 +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 Rhett <roadriverrail@gmail.com>
- * @date 2017
- * Error helper class.
- */
-
-#include <libsolidity/interface/ErrorReporter.h>
-#include <libsolidity/ast/AST.h>
-#include <memory>
-
-using namespace std;
-using namespace dev;
-using namespace dev::solidity;
-
-ErrorReporter& ErrorReporter::operator=(ErrorReporter const& _errorReporter)
-{
- if (&_errorReporter == this)
- return *this;
- m_errorList = _errorReporter.m_errorList;
- return *this;
-}
-
-
-void ErrorReporter::warning(string const& _description)
-{
- error(Error::Type::Warning, SourceLocation(), _description);
-}
-
-void ErrorReporter::warning(
- SourceLocation const& _location,
- string const& _description
-)
-{
- error(Error::Type::Warning, _location, _description);
-}
-
-void ErrorReporter::warning(
- SourceLocation const& _location,
- string const& _description,
- SecondarySourceLocation const& _secondaryLocation
-)
-{
- error(Error::Type::Warning, _location, _secondaryLocation, _description);
-}
-
-void ErrorReporter::error(Error::Type _type, SourceLocation const& _location, string const& _description)
-{
- if (checkForExcessiveErrors(_type))
- return;
-
- auto err = make_shared<Error>(_type);
- *err <<
- errinfo_sourceLocation(_location) <<
- errinfo_comment(_description);
-
- m_errorList.push_back(err);
-}
-
-void ErrorReporter::error(Error::Type _type, SourceLocation const& _location, SecondarySourceLocation const& _secondaryLocation, string const& _description)
-{
- if (checkForExcessiveErrors(_type))
- return;
-
- auto err = make_shared<Error>(_type);
- *err <<
- errinfo_sourceLocation(_location) <<
- errinfo_secondarySourceLocation(_secondaryLocation) <<
- errinfo_comment(_description);
-
- m_errorList.push_back(err);
-}
-
-bool ErrorReporter::checkForExcessiveErrors(Error::Type _type)
-{
- if (_type == Error::Type::Warning)
- {
- m_warningCount++;
-
- if (m_warningCount == c_maxWarningsAllowed)
- {
- auto err = make_shared<Error>(Error::Type::Warning);
- *err << errinfo_comment("There are more than 256 warnings. Ignoring the rest.");
- m_errorList.push_back(err);
- }
-
- if (m_warningCount >= c_maxWarningsAllowed)
- return true;
- }
- else
- {
- m_errorCount++;
-
- if (m_errorCount > c_maxErrorsAllowed)
- {
- auto err = make_shared<Error>(Error::Type::Warning);
- *err << errinfo_comment("There are more than 256 errors. Aborting.");
- m_errorList.push_back(err);
- BOOST_THROW_EXCEPTION(FatalError());
- }
- }
-
- return false;
-}
-
-void ErrorReporter::fatalError(Error::Type _type, SourceLocation const& _location, string const& _description)
-{
- error(_type, _location, _description);
- BOOST_THROW_EXCEPTION(FatalError());
-}
-
-ErrorList const& ErrorReporter::errors() const
-{
- return m_errorList;
-}
-
-void ErrorReporter::clear()
-{
- m_errorList.clear();
-}
-
-void ErrorReporter::declarationError(SourceLocation const& _location, SecondarySourceLocation const&_secondaryLocation, string const& _description)
-{
- error(
- Error::Type::DeclarationError,
- _location,
- _secondaryLocation,
- _description
- );
-}
-
-void ErrorReporter::declarationError(SourceLocation const& _location, string const& _description)
-{
- error(
- Error::Type::DeclarationError,
- _location,
- _description
- );
-}
-
-void ErrorReporter::fatalDeclarationError(SourceLocation const& _location, std::string const& _description)
-{
- fatalError(
- Error::Type::DeclarationError,
- _location,
- _description);
-}
-
-void ErrorReporter::parserError(SourceLocation const& _location, string const& _description)
-{
- error(
- Error::Type::ParserError,
- _location,
- _description
- );
-}
-
-void ErrorReporter::fatalParserError(SourceLocation const& _location, string const& _description)
-{
- fatalError(
- Error::Type::ParserError,
- _location,
- _description
- );
-}
-
-void ErrorReporter::syntaxError(SourceLocation const& _location, string const& _description)
-{
- error(
- Error::Type::SyntaxError,
- _location,
- _description
- );
-}
-
-void ErrorReporter::typeError(SourceLocation const& _location, SecondarySourceLocation const& _secondaryLocation, string const& _description)
-{
- error(
- Error::Type::TypeError,
- _location,
- _secondaryLocation,
- _description
- );
-}
-
-void ErrorReporter::typeError(SourceLocation const& _location, string const& _description)
-{
- error(
- Error::Type::TypeError,
- _location,
- _description
- );
-}
-
-
-void ErrorReporter::fatalTypeError(SourceLocation const& _location, string const& _description)
-{
- fatalError(Error::Type::TypeError,
- _location,
- _description
- );
-}
-
-void ErrorReporter::docstringParsingError(string const& _description)
-{
- error(
- Error::Type::DocstringParsingError,
- SourceLocation(),
- _description
- );
-}
diff --git a/libsolidity/interface/ErrorReporter.h b/libsolidity/interface/ErrorReporter.h
deleted file mode 100644
index fd53587a..00000000
--- a/libsolidity/interface/ErrorReporter.h
+++ /dev/null
@@ -1,126 +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 Rhett <roadriverrail@gmail.com>
- * @date 2017
- * Error reporting helper class.
- */
-
-#pragma once
-
-#include <libsolidity/interface/Exceptions.h>
-#include <libevmasm/SourceLocation.h>
-
-namespace dev
-{
-namespace solidity
-{
-
-class ASTNode;
-
-class ErrorReporter
-{
-public:
-
- explicit ErrorReporter(ErrorList& _errors):
- m_errorList(_errors) { }
-
- ErrorReporter(ErrorReporter const& _errorReporter) noexcept:
- m_errorList(_errorReporter.m_errorList) { }
-
- ErrorReporter& operator=(ErrorReporter const& _errorReporter);
-
- void warning(std::string const& _description);
-
- void warning(SourceLocation const& _location, std::string const& _description);
-
- void warning(
- SourceLocation const& _location,
- std::string const& _description,
- SecondarySourceLocation const& _secondaryLocation
- );
-
- void error(
- Error::Type _type,
- SourceLocation const& _location,
- std::string const& _description
- );
-
- void declarationError(
- SourceLocation const& _location,
- SecondarySourceLocation const& _secondaryLocation,
- std::string const& _description
- );
-
- void declarationError(SourceLocation const& _location, std::string const& _description);
-
- void fatalDeclarationError(SourceLocation const& _location, std::string const& _description);
-
- void parserError(SourceLocation const& _location, std::string const& _description);
-
- void fatalParserError(SourceLocation const& _location, std::string const& _description);
-
- void syntaxError(SourceLocation const& _location, std::string const& _description);
-
- void typeError(
- SourceLocation const& _location,
- SecondarySourceLocation const& _secondaryLocation = SecondarySourceLocation(),
- std::string const& _description = std::string()
- );
-
- void typeError(SourceLocation const& _location, std::string const& _description);
-
- void fatalTypeError(SourceLocation const& _location, std::string const& _description);
-
- void docstringParsingError(std::string const& _description);
-
- ErrorList const& errors() const;
-
- void clear();
-
- /// @returns true iff there is any error (ignores warnings).
- bool hasErrors() const
- {
- return m_errorCount > 0;
- }
-
-private:
- void error(Error::Type _type,
- SourceLocation const& _location,
- SecondarySourceLocation const& _secondaryLocation,
- std::string const& _description = std::string());
-
- void fatalError(Error::Type _type,
- SourceLocation const& _location = SourceLocation(),
- std::string const& _description = std::string());
-
- // @returns true if error shouldn't be stored
- bool checkForExcessiveErrors(Error::Type _type);
-
- ErrorList& m_errorList;
-
- unsigned m_errorCount = 0;
- unsigned m_warningCount = 0;
-
- const unsigned c_maxWarningsAllowed = 256;
- const unsigned c_maxErrorsAllowed = 256;
-};
-
-
-}
-}
-
diff --git a/libsolidity/interface/Exceptions.cpp b/libsolidity/interface/Exceptions.cpp
deleted file mode 100644
index ecadd0b7..00000000
--- a/libsolidity/interface/Exceptions.cpp
+++ /dev/null
@@ -1,66 +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 Liana <liana@ethdev.com>
- * @date 2015
- * Solidity exception hierarchy.
- */
-
-#include <libsolidity/interface/Exceptions.h>
-
-using namespace std;
-using namespace dev;
-using namespace dev::solidity;
-
-Error::Error(Type _type, SourceLocation const& _location, string const& _description):
- m_type(_type)
-{
- switch(m_type)
- {
- case Type::DeclarationError:
- m_typeName = "DeclarationError";
- break;
- case Type::DocstringParsingError:
- m_typeName = "DocstringParsingError";
- break;
- case Type::ParserError:
- m_typeName = "ParserError";
- break;
- case Type::SyntaxError:
- m_typeName = "SyntaxError";
- break;
- case Type::TypeError:
- m_typeName = "TypeError";
- break;
- case Type::Warning:
- m_typeName = "Warning";
- break;
- }
-
- if (!_location.isEmpty())
- *this << errinfo_sourceLocation(_location);
- if (!_description.empty())
- *this << errinfo_comment(_description);
-}
-
-Error::Error(Error::Type _type, const std::string& _description, const SourceLocation& _location):
- Error(_type)
-{
- if (!_location.isEmpty())
- *this << errinfo_sourceLocation(_location);
- *this << errinfo_comment(_description);
-}
diff --git a/libsolidity/interface/Exceptions.h b/libsolidity/interface/Exceptions.h
deleted file mode 100644
index 629b8f3f..00000000
--- a/libsolidity/interface/Exceptions.h
+++ /dev/null
@@ -1,132 +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 2014
- * Solidity exception hierarchy.
- */
-
-#pragma once
-
-#include <string>
-#include <utility>
-#include <libdevcore/Exceptions.h>
-#include <libdevcore/Assertions.h>
-#include <libevmasm/SourceLocation.h>
-
-namespace dev
-{
-namespace solidity
-{
-class Error;
-using ErrorList = std::vector<std::shared_ptr<Error const>>;
-
-struct CompilerError: virtual Exception {};
-struct InternalCompilerError: virtual Exception {};
-struct FatalError: virtual Exception {};
-struct UnimplementedFeatureError: virtual Exception{};
-
-/// Assertion that throws an InternalCompilerError containing the given description if it is not met.
-#define solAssert(CONDITION, DESCRIPTION) \
- assertThrow(CONDITION, ::dev::solidity::InternalCompilerError, DESCRIPTION)
-
-#define solUnimplementedAssert(CONDITION, DESCRIPTION) \
- assertThrow(CONDITION, ::dev::solidity::UnimplementedFeatureError, DESCRIPTION)
-
-#define solUnimplemented(DESCRIPTION) \
- solUnimplementedAssert(false, DESCRIPTION)
-
-class Error: virtual public Exception
-{
-public:
- enum class Type
- {
- DeclarationError,
- DocstringParsingError,
- ParserError,
- TypeError,
- SyntaxError,
- Warning
- };
-
- explicit Error(
- Type _type,
- SourceLocation const& _location = SourceLocation(),
- std::string const& _description = std::string()
- );
-
- Error(Type _type, std::string const& _description, SourceLocation const& _location = SourceLocation());
-
- Type type() const { return m_type; }
- std::string const& typeName() const { return m_typeName; }
-
- /// helper functions
- static Error const* containsErrorOfType(ErrorList const& _list, Error::Type _type)
- {
- for (auto e: _list)
- {
- if (e->type() == _type)
- return e.get();
- }
- return nullptr;
- }
- static bool containsOnlyWarnings(ErrorList const& _list)
- {
- for (auto e: _list)
- {
- if (e->type() != Type::Warning)
- return false;
- }
- return true;
- }
-private:
- Type m_type;
- std::string m_typeName;
-};
-
-
-using errorSourceLocationInfo = std::pair<std::string, SourceLocation>;
-
-class SecondarySourceLocation
-{
-public:
- SecondarySourceLocation& append(std::string const& _errMsg, SourceLocation const& _sourceLocation)
- {
- infos.push_back(std::make_pair(_errMsg, _sourceLocation));
- return *this;
- }
- /// Limits the number of secondary source locations to 32 and appends a notice to the
- /// error message.
- void limitSize(std::string& _message)
- {
- size_t occurrences = infos.size();
- if (occurrences > 32)
- {
- infos.resize(32);
- _message += " Truncated from " + std::to_string(occurrences) + " to the first 32 occurrences.";
- }
- }
-
- std::vector<errorSourceLocationInfo> infos;
-};
-
-
-using errinfo_sourceLocation = boost::error_info<struct tag_sourceLocation, SourceLocation>;
-using errinfo_secondarySourceLocation = boost::error_info<struct tag_secondarySourceLocation, SecondarySourceLocation>;
-
-}
-}
diff --git a/libsolidity/interface/GasEstimator.cpp b/libsolidity/interface/GasEstimator.cpp
index 1f20366e..de6b2ce5 100644
--- a/libsolidity/interface/GasEstimator.cpp
+++ b/libsolidity/interface/GasEstimator.cpp
@@ -35,6 +35,7 @@
using namespace std;
using namespace dev;
using namespace dev::eth;
+using namespace langutil;
using namespace dev::solidity;
GasEstimator::ASTGasConsumptionSelfAccumulated GasEstimator::structuralEstimation(
diff --git a/libsolidity/interface/GasEstimator.h b/libsolidity/interface/GasEstimator.h
index ea94d988..214a3e58 100644
--- a/libsolidity/interface/GasEstimator.h
+++ b/libsolidity/interface/GasEstimator.h
@@ -22,7 +22,7 @@
#pragma once
-#include <libsolidity/interface/EVMVersion.h>
+#include <liblangutil/EVMVersion.h>
#include <libevmasm/GasMeter.h>
#include <libevmasm/Assembly.h>
diff --git a/libsolidity/interface/SourceReferenceFormatter.cpp b/libsolidity/interface/SourceReferenceFormatter.cpp
deleted file mode 100644
index 865907e2..00000000
--- a/libsolidity/interface/SourceReferenceFormatter.cpp
+++ /dev/null
@@ -1,135 +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 2014
- * Formatting functions for errors referencing positions and locations in the source.
- */
-
-#include <libsolidity/interface/SourceReferenceFormatter.h>
-#include <libsolidity/parsing/Scanner.h>
-#include <libsolidity/interface/Exceptions.h>
-
-using namespace std;
-
-namespace dev
-{
-namespace solidity
-{
-
-void SourceReferenceFormatter::printSourceLocation(SourceLocation const* _location)
-{
- if (!_location || !_location->sourceName)
- return; // Nothing we can print here
- auto const& scanner = m_scannerFromSourceName(*_location->sourceName);
- int startLine;
- int startColumn;
- tie(startLine, startColumn) = scanner.translatePositionToLineColumn(_location->start);
- int endLine;
- int endColumn;
- tie(endLine, endColumn) = scanner.translatePositionToLineColumn(_location->end);
- if (startLine == endLine)
- {
- string line = scanner.lineAtPosition(_location->start);
-
- int locationLength = endColumn - startColumn;
- if (locationLength > 150)
- {
- line = line.substr(0, startColumn + 35) + " ... " + line.substr(endColumn - 35);
- endColumn = startColumn + 75;
- locationLength = 75;
- }
- if (line.length() > 150)
- {
- int len = line.length();
- line = line.substr(max(0, startColumn - 35), min(startColumn, 35) + min(locationLength + 35, len - startColumn));
- if (startColumn + locationLength + 35 < len)
- line += " ...";
- if (startColumn > 35)
- {
- line = " ... " + line;
- startColumn = 40;
- }
- endColumn = startColumn + locationLength;
- }
-
- m_stream << line << endl;
-
- for_each(
- line.cbegin(),
- line.cbegin() + startColumn,
- [this](char const& ch) { m_stream << (ch == '\t' ? '\t' : ' '); }
- );
- m_stream << "^";
- if (endColumn > startColumn + 2)
- m_stream << string(endColumn - startColumn - 2, '-');
- if (endColumn > startColumn + 1)
- m_stream << "^";
- m_stream << endl;
- }
- else
- m_stream <<
- scanner.lineAtPosition(_location->start) <<
- endl <<
- string(startColumn, ' ') <<
- "^ (Relevant source part starts here and spans across multiple lines)." <<
- endl;
-}
-
-void SourceReferenceFormatter::printSourceName(SourceLocation const* _location)
-{
- if (!_location || !_location->sourceName)
- return; // Nothing we can print here
- auto const& scanner = m_scannerFromSourceName(*_location->sourceName);
- int startLine;
- int startColumn;
- tie(startLine, startColumn) = scanner.translatePositionToLineColumn(_location->start);
- m_stream << *_location->sourceName << ":" << (startLine + 1) << ":" << (startColumn + 1) << ": ";
-}
-
-void SourceReferenceFormatter::printExceptionInformation(
- Exception const& _exception,
- string const& _name
-)
-{
- SourceLocation const* location = boost::get_error_info<errinfo_sourceLocation>(_exception);
- auto secondarylocation = boost::get_error_info<errinfo_secondarySourceLocation>(_exception);
-
- printSourceName(location);
-
- m_stream << _name;
- if (string const* description = boost::get_error_info<errinfo_comment>(_exception))
- m_stream << ": " << *description << endl;
- else
- m_stream << endl;
-
- printSourceLocation(location);
-
- if (secondarylocation && !secondarylocation->infos.empty())
- {
- for (auto info: secondarylocation->infos)
- {
- printSourceName(&info.second);
- m_stream << info.first << endl;
- printSourceLocation(&info.second);
- }
- m_stream << endl;
- }
-}
-
-}
-}
diff --git a/libsolidity/interface/SourceReferenceFormatter.h b/libsolidity/interface/SourceReferenceFormatter.h
deleted file mode 100644
index a32babdc..00000000
--- a/libsolidity/interface/SourceReferenceFormatter.h
+++ /dev/null
@@ -1,79 +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 2014
- * Formatting functions for errors referencing positions and locations in the source.
- */
-
-#pragma once
-
-#include <ostream>
-#include <sstream>
-#include <functional>
-#include <libevmasm/SourceLocation.h>
-
-namespace dev
-{
-
-struct Exception; // forward
-
-namespace solidity
-{
-
-class Scanner; // forward
-class CompilerStack; // forward
-
-class SourceReferenceFormatter
-{
-public:
- using ScannerFromSourceNameFun = std::function<Scanner const&(std::string const&)>;
-
- explicit SourceReferenceFormatter(
- std::ostream& _stream,
- ScannerFromSourceNameFun _scannerFromSourceName
- ):
- m_stream(_stream),
- m_scannerFromSourceName(std::move(_scannerFromSourceName))
- {}
-
- /// Prints source location if it is given.
- void printSourceLocation(SourceLocation const* _location);
- void printExceptionInformation(Exception const& _exception, std::string const& _name);
-
- static std::string formatExceptionInformation(
- Exception const& _exception,
- std::string const& _name,
- ScannerFromSourceNameFun const& _scannerFromSourceName
- )
- {
- std::ostringstream errorOutput;
-
- SourceReferenceFormatter formatter(errorOutput, _scannerFromSourceName);
- formatter.printExceptionInformation(_exception, _name);
- return errorOutput.str();
- }
-private:
- /// Prints source name if location is given.
- void printSourceName(SourceLocation const* _location);
-
- std::ostream& m_stream;
- ScannerFromSourceNameFun m_scannerFromSourceName;
-};
-
-}
-}
diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp
index c8b03a94..0eef50d2 100644
--- a/libsolidity/interface/StandardCompiler.cpp
+++ b/libsolidity/interface/StandardCompiler.cpp
@@ -21,7 +21,7 @@
*/
#include <libsolidity/interface/StandardCompiler.h>
-#include <libsolidity/interface/SourceReferenceFormatter.h>
+#include <liblangutil/SourceReferenceFormatter.h>
#include <libsolidity/ast/ASTJsonConverter.h>
#include <libevmasm/Instruction.h>
#include <libdevcore/JSON.h>
@@ -31,6 +31,7 @@
using namespace std;
using namespace dev;
+using namespace langutil;
using namespace dev::solidity;
namespace {
@@ -84,9 +85,9 @@ Json::Value formatErrorWithException(
message = _message;
Json::Value sourceLocation;
- if (location && location->sourceName)
+ if (location && location->source && location->source->name() != "")
{
- sourceLocation["file"] = *location->sourceName;
+ sourceLocation["file"] = location->source->name();
sourceLocation["start"] = location->start;
sourceLocation["end"] = location->end;
}
@@ -318,6 +319,27 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
return formatFatalError("JSONError", "Invalid input source specified.");
}
+ Json::Value const& auxInputs = _input["auxiliaryInput"];
+ if (!!auxInputs)
+ {
+ Json::Value const& smtlib2Responses = auxInputs["smtlib2responses"];
+ if (!!smtlib2Responses)
+ for (auto const& hashString: smtlib2Responses.getMemberNames())
+ {
+ h256 hash;
+ try
+ {
+ hash = h256(hashString);
+ }
+ catch (dev::BadHexCharacter const&)
+ {
+ return formatFatalError("JSONError", "Invalid hex encoding of SMTLib2 auxiliary input.");
+ }
+
+ m_compilerStack.addSMTLib2Response(hash, smtlib2Responses[hashString].asString());
+ }
+ }
+
Json::Value const& settings = _input.get("settings", Json::Value());
if (settings.isMember("evmVersion"))
@@ -411,7 +433,7 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
Json::Value outputSelection = settings.get("outputSelection", Json::Value());
m_compilerStack.setRequestedContractNames(requestedContractNames(outputSelection));
- auto scannerFromSourceName = [&](string const& _sourceName) -> solidity::Scanner const& { return m_compilerStack.scanner(_sourceName); };
+ auto scannerFromSourceName = [&](string const& _sourceName) -> Scanner const& { return m_compilerStack.scanner(_sourceName); };
try
{
@@ -517,6 +539,10 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
if (errors.size() > 0)
output["errors"] = errors;
+ if (!m_compilerStack.unhandledSMTLib2Queries().empty())
+ for (string const& query: m_compilerStack.unhandledSMTLib2Queries())
+ output["auxiliaryInputRequested"]["smtlib2queries"]["0x" + keccak256(query).hex()] = query;
+
output["sources"] = Json::objectValue;
unsigned sourceIndex = 0;
for (string const& sourceName: analysisSuccess ? m_compilerStack.sourceNames() : vector<string>())
diff --git a/libsolidity/interface/Version.cpp b/libsolidity/interface/Version.cpp
index b5f68ce8..b785d557 100644
--- a/libsolidity/interface/Version.cpp
+++ b/libsolidity/interface/Version.cpp
@@ -24,7 +24,7 @@
#include <string>
#include <libdevcore/CommonData.h>
#include <libdevcore/Common.h>
-#include <libsolidity/interface/Exceptions.h>
+#include <liblangutil/Exceptions.h>
#include <solidity/BuildInfo.h>
using namespace dev;
diff --git a/libsolidity/parsing/DocStringParser.cpp b/libsolidity/parsing/DocStringParser.cpp
index d9588e5c..d8927fea 100644
--- a/libsolidity/parsing/DocStringParser.cpp
+++ b/libsolidity/parsing/DocStringParser.cpp
@@ -1,13 +1,14 @@
#include <libsolidity/parsing/DocStringParser.h>
-#include <libsolidity/interface/ErrorReporter.h>
-#include <libsolidity/interface/Exceptions.h>
+#include <liblangutil/ErrorReporter.h>
+#include <liblangutil/Exceptions.h>
#include <boost/range/irange.hpp>
#include <boost/range/algorithm.hpp>
using namespace std;
using namespace dev;
+using namespace langutil;
using namespace dev::solidity;
diff --git a/libsolidity/parsing/DocStringParser.h b/libsolidity/parsing/DocStringParser.h
index 5f2819cc..c83b416d 100644
--- a/libsolidity/parsing/DocStringParser.h
+++ b/libsolidity/parsing/DocStringParser.h
@@ -25,19 +25,22 @@
#include <string>
#include <libsolidity/ast/ASTAnnotations.h>
+namespace langutil
+{
+class ErrorReporter;
+}
+
namespace dev
{
namespace solidity
{
-class ErrorReporter;
-
class DocStringParser
{
public:
/// Parse the given @a _docString and stores the parsed components internally.
/// @returns false on error and appends the error to @a _errors.
- bool parse(std::string const& _docString, ErrorReporter& _errorReporter);
+ bool parse(std::string const& _docString, langutil::ErrorReporter& _errorReporter);
std::multimap<std::string, DocTag> const& tags() const { return m_docTags; }
@@ -63,7 +66,7 @@ private:
/// Mapping tag name -> content.
std::multimap<std::string, DocTag> m_docTags;
DocTag* m_lastTag = nullptr;
- ErrorReporter* m_errorReporter = nullptr;
+ langutil::ErrorReporter* m_errorReporter = nullptr;
bool m_errorsOccurred = false;
};
diff --git a/libsolidity/parsing/Parser.cpp b/libsolidity/parsing/Parser.cpp
index b17dad9a..6cab7be3 100644
--- a/libsolidity/parsing/Parser.cpp
+++ b/libsolidity/parsing/Parser.cpp
@@ -22,13 +22,14 @@
#include <cctype>
#include <vector>
-#include <libevmasm/SourceLocation.h>
#include <libsolidity/parsing/Parser.h>
-#include <libsolidity/parsing/Scanner.h>
-#include <libsolidity/inlineasm/AsmParser.h>
-#include <libsolidity/interface/ErrorReporter.h>
+#include <libyul/AsmParser.h>
+#include <liblangutil/SourceLocation.h>
+#include <liblangutil/ErrorReporter.h>
+#include <liblangutil/Scanner.h>
using namespace std;
+using namespace langutil;
namespace dev
{
@@ -41,7 +42,7 @@ class Parser::ASTNodeFactory
{
public:
explicit ASTNodeFactory(Parser const& _parser):
- m_parser(_parser), m_location(_parser.position(), -1, _parser.sourceName()) {}
+ m_parser(_parser), m_location(_parser.position(), -1, _parser.source()) {}
ASTNodeFactory(Parser const& _parser, ASTPointer<ASTNode> const& _childNode):
m_parser(_parser), m_location(_childNode->location()) {}
@@ -54,7 +55,7 @@ public:
template <class NodeType, typename... Args>
ASTPointer<NodeType> createNode(Args&& ... _args)
{
- solAssert(m_location.sourceName, "");
+ solAssert(m_location.source, "");
if (m_location.end < 0)
markEndPosition();
return make_shared<NodeType>(m_location, std::forward<Args>(_args)...);
@@ -1011,8 +1012,8 @@ ASTPointer<InlineAssembly> Parser::parseInlineAssembly(ASTPointer<ASTString> con
m_scanner->next();
}
- assembly::Parser asmParser(m_errorReporter);
- shared_ptr<assembly::Block> block = asmParser.parse(m_scanner, true);
+ yul::Parser asmParser(m_errorReporter);
+ shared_ptr<yul::Block> block = asmParser.parse(m_scanner, true);
nodeFactory.markEndPosition();
return nodeFactory.createNode<InlineAssembly>(_docString, block);
}
@@ -1554,8 +1555,8 @@ ASTPointer<Expression> Parser::parsePrimaryExpression()
expression = nodeFactory.createNode<TupleExpression>(components, isArray);
break;
}
- case Token::IllegalHex:
- fatalParserError("Expected even number of hex-nibbles within double-quotes.");
+ case Token::Illegal:
+ fatalParserError(to_string(m_scanner->currentError()));
break;
default:
if (TokenTraits::isElementaryTypeName(token))
diff --git a/libsolidity/parsing/Parser.h b/libsolidity/parsing/Parser.h
index fa974171..15852096 100644
--- a/libsolidity/parsing/Parser.h
+++ b/libsolidity/parsing/Parser.h
@@ -23,21 +23,24 @@
#pragma once
#include <libsolidity/ast/AST.h>
-#include <libsolidity/parsing/ParserBase.h>
+#include <liblangutil/ParserBase.h>
+
+namespace langutil
+{
+class Scanner;
+}
namespace dev
{
namespace solidity
{
-class Scanner;
-
-class Parser: public ParserBase
+class Parser: public langutil::ParserBase
{
public:
- explicit Parser(ErrorReporter& _errorReporter): ParserBase(_errorReporter) {}
+ explicit Parser(langutil::ErrorReporter& _errorReporter): ParserBase(_errorReporter) {}
- ASTPointer<SourceUnit> parse(std::shared_ptr<Scanner> const& _scanner);
+ ASTPointer<SourceUnit> parse(std::shared_ptr<langutil::Scanner> const& _scanner);
private:
class ASTNodeFactory;
@@ -146,7 +149,7 @@ private:
struct IndexAccessedPath
{
std::vector<ASTPointer<PrimaryExpression>> path;
- std::vector<std::pair<ASTPointer<Expression>, SourceLocation>> indices;
+ std::vector<std::pair<ASTPointer<Expression>, langutil::SourceLocation>> indices;
bool empty() const;
};
diff --git a/libsolidity/parsing/ParserBase.cpp b/libsolidity/parsing/ParserBase.cpp
deleted file mode 100644
index 1d4cb1e2..00000000
--- a/libsolidity/parsing/ParserBase.cpp
+++ /dev/null
@@ -1,115 +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 parser shared functionality.
- */
-
-#include <libsolidity/parsing/ParserBase.h>
-#include <libsolidity/parsing/Scanner.h>
-#include <libsolidity/interface/ErrorReporter.h>
-
-using namespace std;
-using namespace dev;
-using namespace dev::solidity;
-
-std::shared_ptr<string const> const& ParserBase::sourceName() const
-{
- return m_scanner->sourceName();
-}
-
-int ParserBase::position() const
-{
- return m_scanner->currentLocation().start;
-}
-
-int ParserBase::endPosition() const
-{
- return m_scanner->currentLocation().end;
-}
-
-Token ParserBase::currentToken() const
-{
- return m_scanner->currentToken();
-}
-
-Token ParserBase::peekNextToken() const
-{
- return m_scanner->peekNextToken();
-}
-
-std::string ParserBase::currentLiteral() const
-{
- return m_scanner->currentLiteral();
-}
-
-Token ParserBase::advance()
-{
- return m_scanner->next();
-}
-
-void ParserBase::expectToken(Token _value, bool _advance)
-{
- Token tok = m_scanner->currentToken();
- if (tok != _value)
- {
- auto tokenName = [this](Token _token)
- {
- if (_token == Token::Identifier)
- return string("identifier");
- else if (_token == Token::EOS)
- return string("end of source");
- else if (TokenTraits::isReservedKeyword(_token))
- return string("reserved keyword '") + TokenTraits::friendlyName(_token) + "'";
- else if (TokenTraits::isElementaryTypeName(_token)) //for the sake of accuracy in reporting
- {
- ElementaryTypeNameToken elemTypeName = m_scanner->currentElementaryTypeNameToken();
- return string("'") + elemTypeName.toString() + "'";
- }
- else
- return string("'") + TokenTraits::friendlyName(_token) + "'";
- };
-
- fatalParserError(string("Expected ") + tokenName(_value) + string(" but got ") + tokenName(tok));
- }
- if (_advance)
- m_scanner->next();
-}
-
-void ParserBase::increaseRecursionDepth()
-{
- m_recursionDepth++;
- if (m_recursionDepth >= 2560)
- fatalParserError("Maximum recursion depth reached during parsing.");
-}
-
-void ParserBase::decreaseRecursionDepth()
-{
- solAssert(m_recursionDepth > 0, "");
- m_recursionDepth--;
-}
-
-void ParserBase::parserError(string const& _description)
-{
- m_errorReporter.parserError(SourceLocation(position(), endPosition(), sourceName()), _description);
-}
-
-void ParserBase::fatalParserError(string const& _description)
-{
- m_errorReporter.fatalParserError(SourceLocation(position(), endPosition(), sourceName()), _description);
-}
diff --git a/libsolidity/parsing/ParserBase.h b/libsolidity/parsing/ParserBase.h
deleted file mode 100644
index e01f37d8..00000000
--- a/libsolidity/parsing/ParserBase.h
+++ /dev/null
@@ -1,93 +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 parser shared functionality.
- */
-
-#pragma once
-
-#include <memory>
-#include <libsolidity/parsing/Token.h>
-
-namespace dev
-{
-namespace solidity
-{
-
-class ErrorReporter;
-class Scanner;
-
-class ParserBase
-{
-public:
- explicit ParserBase(ErrorReporter& errorReporter): m_errorReporter(errorReporter) {}
-
- std::shared_ptr<std::string const> const& sourceName() const;
-
-protected:
- /// Utility class that creates an error and throws an exception if the
- /// recursion depth is too deep.
- class RecursionGuard
- {
- public:
- explicit RecursionGuard(ParserBase& _parser): m_parser(_parser)
- {
- m_parser.increaseRecursionDepth();
- }
- ~RecursionGuard() { m_parser.decreaseRecursionDepth(); }
- private:
- ParserBase& m_parser;
- };
-
- /// Start position of the current token
- int position() const;
- /// End position of the current token
- int endPosition() const;
-
- ///@{
- ///@name Helper functions
- /// If current token value is not _value, throw exception otherwise advance token.
- void expectToken(Token _value, bool _advance = true);
- Token currentToken() const;
- Token peekNextToken() const;
- std::string currentLiteral() const;
- Token advance();
- ///@}
-
- /// Increases the recursion depth and throws an exception if it is too deep.
- void increaseRecursionDepth();
- void decreaseRecursionDepth();
-
- /// Creates a @ref ParserError and annotates it with the current position and the
- /// given @a _description.
- void parserError(std::string const& _description);
-
- /// Creates a @ref ParserError and annotates it with the current position and the
- /// given @a _description. Throws the FatalError.
- void fatalParserError(std::string const& _description);
-
- std::shared_ptr<Scanner> m_scanner;
- /// The reference to the list of errors and warning to add errors/warnings during parsing
- ErrorReporter& m_errorReporter;
- /// Current recursion depth during parsing.
- size_t m_recursionDepth = 0;
-};
-
-}
-}
diff --git a/libsolidity/parsing/Scanner.cpp b/libsolidity/parsing/Scanner.cpp
deleted file mode 100644
index e9dad2ad..00000000
--- a/libsolidity/parsing/Scanner.cpp
+++ /dev/null
@@ -1,920 +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/>.
-
- This file is derived from the file "scanner.cc", which was part of the
- V8 project. The original copyright header follows:
-
- Copyright 2006-2012, the V8 project authors. All rights reserved.
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are
- met:
-
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the following
- disclaimer in the documentation and/or other materials provided
- with the distribution.
- * Neither the name of Google Inc. nor the names of its
- contributors may be used to endorse or promote products derived
- from this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-/**
- * @author Christian <c@ethdev.com>
- * @date 2014
- * Solidity scanner.
- */
-
-#include <algorithm>
-#include <tuple>
-#include <libsolidity/interface/Exceptions.h>
-#include <libsolidity/parsing/Scanner.h>
-
-using namespace std;
-
-namespace dev
-{
-namespace solidity
-{
-
-namespace
-{
-bool isDecimalDigit(char c)
-{
- return '0' <= c && c <= '9';
-}
-bool isHexDigit(char c)
-{
- return isDecimalDigit(c)
- || ('a' <= c && c <= 'f')
- || ('A' <= c && c <= 'F');
-}
-bool isLineTerminator(char c)
-{
- return c == '\n';
-}
-bool isWhiteSpace(char c)
-{
- return c == ' ' || c == '\n' || c == '\t' || c == '\r';
-}
-bool isIdentifierStart(char c)
-{
- return c == '_' || c == '$' || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
-}
-bool isIdentifierPart(char c)
-{
- return isIdentifierStart(c) || isDecimalDigit(c);
-}
-int hexValue(char c)
-{
- if (c >= '0' && c <= '9')
- return c - '0';
- else if (c >= 'a' && c <= 'f')
- return c - 'a' + 10;
- else if (c >= 'A' && c <= 'F')
- return c - 'A' + 10;
- else return -1;
-}
-} // end anonymous namespace
-
-
-
-/// Scoped helper for literal recording. Automatically drops the literal
-/// if aborting the scanning before it's complete.
-enum LiteralType {
- LITERAL_TYPE_STRING,
- LITERAL_TYPE_NUMBER, // not really different from string type in behaviour
- LITERAL_TYPE_COMMENT
-};
-
-class LiteralScope
-{
-public:
- explicit LiteralScope(Scanner* _self, enum LiteralType _type): m_type(_type)
- , m_scanner(_self)
- , m_complete(false)
- {
- if (_type == LITERAL_TYPE_COMMENT)
- m_scanner->m_nextSkippedComment.literal.clear();
- else
- m_scanner->m_nextToken.literal.clear();
- }
- ~LiteralScope()
- {
- if (!m_complete)
- {
- if (m_type == LITERAL_TYPE_COMMENT)
- m_scanner->m_nextSkippedComment.literal.clear();
- else
- m_scanner->m_nextToken.literal.clear();
- }
- }
- void complete() { m_complete = true; }
-
-private:
- enum LiteralType m_type;
- Scanner* m_scanner;
- bool m_complete;
-}; // end of LiteralScope class
-
-
-void Scanner::reset(CharStream const& _source, string const& _sourceName)
-{
- m_source = _source;
- m_sourceName = make_shared<string const>(_sourceName);
- reset();
-}
-
-void Scanner::reset()
-{
- m_source.reset();
- m_char = m_source.get();
- skipWhitespace();
- scanToken();
- next();
-}
-
-bool Scanner::scanHexByte(char& o_scannedByte)
-{
- char x = 0;
- for (int i = 0; i < 2; i++)
- {
- int d = hexValue(m_char);
- if (d < 0)
- {
- rollback(i);
- return false;
- }
- x = x * 16 + d;
- advance();
- }
- o_scannedByte = x;
- return true;
-}
-
-bool Scanner::scanUnicode(unsigned & o_codepoint)
-{
- unsigned x = 0;
- for (int i = 0; i < 4; i++)
- {
- int d = hexValue(m_char);
- if (d < 0)
- {
- rollback(i);
- return false;
- }
- x = x * 16 + d;
- advance();
- }
- o_codepoint = x;
- return true;
-}
-
-// This supports codepoints between 0000 and FFFF.
-void Scanner::addUnicodeAsUTF8(unsigned codepoint)
-{
- if (codepoint <= 0x7f)
- addLiteralChar(codepoint);
- else if (codepoint <= 0x7ff)
- {
- addLiteralChar(0xc0 | (codepoint >> 6));
- addLiteralChar(0x80 | (codepoint & 0x3f));
- }
- else
- {
- addLiteralChar(0xe0 | (codepoint >> 12));
- addLiteralChar(0x80 | ((codepoint >> 6) & 0x3f));
- addLiteralChar(0x80 | (codepoint & 0x3f));
- }
-}
-
-// Ensure that tokens can be stored in a byte.
-BOOST_STATIC_ASSERT(TokenTraits::count() <= 0x100);
-
-Token Scanner::next()
-{
- m_currentToken = m_nextToken;
- m_skippedComment = m_nextSkippedComment;
- scanToken();
-
- return m_currentToken.token;
-}
-
-Token Scanner::selectToken(char _next, Token _then, Token _else)
-{
- advance();
- if (m_char == _next)
- return selectToken(_then);
- else
- return _else;
-}
-
-bool Scanner::skipWhitespace()
-{
- int const startPosition = sourcePos();
- while (isWhiteSpace(m_char))
- advance();
- // Return whether or not we skipped any characters.
- return sourcePos() != startPosition;
-}
-
-void Scanner::skipWhitespaceExceptUnicodeLinebreak()
-{
- while (isWhiteSpace(m_char) && !isUnicodeLinebreak())
- advance();
-}
-
-Token Scanner::skipSingleLineComment()
-{
- // Line terminator is not part of the comment. If it is a
- // non-ascii line terminator, it will result in a parser error.
- while (!isUnicodeLinebreak())
- if (!advance()) break;
-
- return Token::Whitespace;
-}
-
-Token Scanner::scanSingleLineDocComment()
-{
- LiteralScope literal(this, LITERAL_TYPE_COMMENT);
- advance(); //consume the last '/' at ///
-
- skipWhitespaceExceptUnicodeLinebreak();
-
- while (!isSourcePastEndOfInput())
- {
- if (isLineTerminator(m_char))
- {
- // check if next line is also a documentation comment
- skipWhitespace();
- if (!m_source.isPastEndOfInput(3) &&
- m_source.get(0) == '/' &&
- m_source.get(1) == '/' &&
- m_source.get(2) == '/')
- {
- addCommentLiteralChar('\n');
- m_char = m_source.advanceAndGet(3);
- }
- else
- break; // next line is not a documentation comment, we are done
-
- }
- else if (isUnicodeLinebreak())
- // Any line terminator that is not '\n' is considered to end the
- // comment.
- break;
- addCommentLiteralChar(m_char);
- advance();
- }
- literal.complete();
- return Token::CommentLiteral;
-}
-
-Token Scanner::skipMultiLineComment()
-{
- advance();
- while (!isSourcePastEndOfInput())
- {
- char ch = m_char;
- advance();
-
- // If we have reached the end of the multi-line comment, we
- // consume the '/' and insert a whitespace. This way all
- // multi-line comments are treated as whitespace.
- if (ch == '*' && m_char == '/')
- {
- m_char = ' ';
- return Token::Whitespace;
- }
- }
- // Unterminated multi-line comment.
- return Token::Illegal;
-}
-
-Token Scanner::scanMultiLineDocComment()
-{
- LiteralScope literal(this, LITERAL_TYPE_COMMENT);
- bool endFound = false;
- bool charsAdded = false;
-
- while (isWhiteSpace(m_char) && !isLineTerminator(m_char))
- advance();
-
- while (!isSourcePastEndOfInput())
- {
- //handle newlines in multline comments
- if (isLineTerminator(m_char))
- {
- skipWhitespace();
- if (!m_source.isPastEndOfInput(1) && m_source.get(0) == '*' && m_source.get(1) == '*')
- { // it is unknown if this leads to the end of the comment
- addCommentLiteralChar('*');
- advance();
- }
- else if (!m_source.isPastEndOfInput(1) && m_source.get(0) == '*' && m_source.get(1) != '/')
- { // skip first '*' in subsequent lines
- if (charsAdded)
- addCommentLiteralChar('\n');
- m_char = m_source.advanceAndGet(2);
- }
- else if (!m_source.isPastEndOfInput(1) && m_source.get(0) == '*' && m_source.get(1) == '/')
- { // if after newline the comment ends, don't insert the newline
- m_char = m_source.advanceAndGet(2);
- endFound = true;
- break;
- }
- else if (charsAdded)
- addCommentLiteralChar('\n');
- }
-
- if (!m_source.isPastEndOfInput(1) && m_source.get(0) == '*' && m_source.get(1) == '/')
- {
- m_char = m_source.advanceAndGet(2);
- endFound = true;
- break;
- }
- addCommentLiteralChar(m_char);
- charsAdded = true;
- advance();
- }
- literal.complete();
- if (!endFound)
- return Token::Illegal;
- else
- return Token::CommentLiteral;
-}
-
-Token Scanner::scanSlash()
-{
- int firstSlashPosition = sourcePos();
- advance();
- if (m_char == '/')
- {
- if (!advance()) /* double slash comment directly before EOS */
- return Token::Whitespace;
- else if (m_char == '/')
- {
- // doxygen style /// comment
- Token comment;
- m_nextSkippedComment.location.start = firstSlashPosition;
- comment = scanSingleLineDocComment();
- m_nextSkippedComment.location.end = sourcePos();
- m_nextSkippedComment.token = comment;
- return Token::Whitespace;
- }
- else
- return skipSingleLineComment();
- }
- else if (m_char == '*')
- {
- // doxygen style /** natspec comment
- if (!advance()) /* slash star comment before EOS */
- return Token::Illegal;
- else if (m_char == '*')
- {
- advance(); //consume the last '*' at /**
-
- // "/**/"
- if (m_char == '/')
- {
- advance(); //skip the closing slash
- return Token::Whitespace;
- }
- // we actually have a multiline documentation comment
- Token comment;
- m_nextSkippedComment.location.start = firstSlashPosition;
- comment = scanMultiLineDocComment();
- m_nextSkippedComment.location.end = sourcePos();
- m_nextSkippedComment.token = comment;
- if (comment == Token::Illegal)
- return Token::Illegal;
- else
- return Token::Whitespace;
- }
- else
- return skipMultiLineComment();
- }
- else if (m_char == '=')
- return selectToken(Token::AssignDiv);
- else
- return Token::Div;
-}
-
-void Scanner::scanToken()
-{
- m_nextToken.literal.clear();
- m_nextToken.extendedTokenInfo = make_tuple(0, 0);
- m_nextSkippedComment.literal.clear();
- m_nextSkippedComment.extendedTokenInfo = make_tuple(0, 0);
-
- Token token;
- // M and N are for the purposes of grabbing different type sizes
- unsigned m;
- unsigned n;
- do
- {
- // Remember the position of the next token
- m_nextToken.location.start = sourcePos();
- switch (m_char)
- {
- case '"':
- case '\'':
- token = scanString();
- break;
- case '<':
- // < <= << <<=
- advance();
- if (m_char == '=')
- token = selectToken(Token::LessThanOrEqual);
- else if (m_char == '<')
- token = selectToken('=', Token::AssignShl, Token::SHL);
- else
- token = Token::LessThan;
- break;
- case '>':
- // > >= >> >>= >>> >>>=
- advance();
- if (m_char == '=')
- token = selectToken(Token::GreaterThanOrEqual);
- else if (m_char == '>')
- {
- // >> >>= >>> >>>=
- advance();
- if (m_char == '=')
- token = selectToken(Token::AssignSar);
- else if (m_char == '>')
- token = selectToken('=', Token::AssignShr, Token::SHR);
- else
- token = Token::SAR;
- }
- else
- token = Token::GreaterThan;
- break;
- case '=':
- // = == =>
- advance();
- if (m_char == '=')
- token = selectToken(Token::Equal);
- else if (m_char == '>')
- token = selectToken(Token::Arrow);
- else
- token = Token::Assign;
- break;
- case '!':
- // ! !=
- advance();
- if (m_char == '=')
- token = selectToken(Token::NotEqual);
- else
- token = Token::Not;
- break;
- case '+':
- // + ++ +=
- advance();
- if (m_char == '+')
- token = selectToken(Token::Inc);
- else if (m_char == '=')
- token = selectToken(Token::AssignAdd);
- else
- token = Token::Add;
- break;
- case '-':
- // - -- -=
- advance();
- if (m_char == '-')
- token = selectToken(Token::Dec);
- else if (m_char == '=')
- token = selectToken(Token::AssignSub);
- else
- token = Token::Sub;
- break;
- case '*':
- // * ** *=
- advance();
- if (m_char == '*')
- token = selectToken(Token::Exp);
- else if (m_char == '=')
- token = selectToken(Token::AssignMul);
- else
- token = Token::Mul;
- break;
- case '%':
- // % %=
- token = selectToken('=', Token::AssignMod, Token::Mod);
- break;
- case '/':
- // / // /* /=
- token = scanSlash();
- break;
- case '&':
- // & && &=
- advance();
- if (m_char == '&')
- token = selectToken(Token::And);
- else if (m_char == '=')
- token = selectToken(Token::AssignBitAnd);
- else
- token = Token::BitAnd;
- break;
- case '|':
- // | || |=
- advance();
- if (m_char == '|')
- token = selectToken(Token::Or);
- else if (m_char == '=')
- token = selectToken(Token::AssignBitOr);
- else
- token = Token::BitOr;
- break;
- case '^':
- // ^ ^=
- token = selectToken('=', Token::AssignBitXor, Token::BitXor);
- break;
- case '.':
- // . Number
- advance();
- if (isDecimalDigit(m_char))
- token = scanNumber('.');
- else
- token = Token::Period;
- break;
- case ':':
- token = selectToken(Token::Colon);
- break;
- case ';':
- token = selectToken(Token::Semicolon);
- break;
- case ',':
- token = selectToken(Token::Comma);
- break;
- case '(':
- token = selectToken(Token::LParen);
- break;
- case ')':
- token = selectToken(Token::RParen);
- break;
- case '[':
- token = selectToken(Token::LBrack);
- break;
- case ']':
- token = selectToken(Token::RBrack);
- break;
- case '{':
- token = selectToken(Token::LBrace);
- break;
- case '}':
- token = selectToken(Token::RBrace);
- break;
- case '?':
- token = selectToken(Token::Conditional);
- break;
- case '~':
- token = selectToken(Token::BitNot);
- break;
- default:
- if (isIdentifierStart(m_char))
- {
- tie(token, m, n) = scanIdentifierOrKeyword();
-
- // Special case for hexadecimal literals
- if (token == Token::Hex)
- {
- // reset
- m = 0;
- n = 0;
-
- // Special quoted hex string must follow
- if (m_char == '"' || m_char == '\'')
- token = scanHexString();
- else
- token = Token::IllegalHex;
- }
- }
- else if (isDecimalDigit(m_char))
- token = scanNumber();
- else if (skipWhitespace())
- token = Token::Whitespace;
- else if (isSourcePastEndOfInput())
- token = Token::EOS;
- else
- token = selectToken(Token::Illegal);
- break;
- }
- // Continue scanning for tokens as long as we're just skipping
- // whitespace.
- }
- while (token == Token::Whitespace);
- m_nextToken.location.end = sourcePos();
- m_nextToken.token = token;
- m_nextToken.extendedTokenInfo = make_tuple(m, n);
-}
-
-bool Scanner::scanEscape()
-{
- char c = m_char;
- advance();
- // Skip escaped newlines.
- if (isLineTerminator(c))
- return true;
- switch (c)
- {
- case '\'': // fall through
- case '"': // fall through
- case '\\':
- break;
- case 'b':
- c = '\b';
- break;
- case 'f':
- c = '\f';
- break;
- case 'n':
- c = '\n';
- break;
- case 'r':
- c = '\r';
- break;
- case 't':
- c = '\t';
- break;
- case 'v':
- c = '\v';
- break;
- case 'u':
- {
- unsigned codepoint;
- if (!scanUnicode(codepoint))
- return false;
- addUnicodeAsUTF8(codepoint);
- return true;
- }
- case 'x':
- if (!scanHexByte(c))
- return false;
- break;
- default:
- return false;
- }
-
- addLiteralChar(c);
- return true;
-}
-
-bool Scanner::isUnicodeLinebreak()
-{
- if (0x0a <= m_char && m_char <= 0x0d)
- // line feed, vertical tab, form feed, carriage return
- return true;
- else if (!m_source.isPastEndOfInput(1) && uint8_t(m_source.get(0)) == 0xc2 && uint8_t(m_source.get(1)) == 0x85)
- // NEL - U+0085, C2 85 in utf8
- return true;
- else if (!m_source.isPastEndOfInput(2) && uint8_t(m_source.get(0)) == 0xe2 && uint8_t(m_source.get(1)) == 0x80 && (
- uint8_t(m_source.get(2)) == 0xa8 || uint8_t(m_source.get(2)) == 0xa9
- ))
- // LS - U+2028, E2 80 A8 in utf8
- // PS - U+2029, E2 80 A9 in utf8
- return true;
- else
- return false;
-}
-
-Token Scanner::scanString()
-{
- char const quote = m_char;
- advance(); // consume quote
- LiteralScope literal(this, LITERAL_TYPE_STRING);
- while (m_char != quote && !isSourcePastEndOfInput() && !isUnicodeLinebreak())
- {
- char c = m_char;
- advance();
- if (c == '\\')
- {
- if (isSourcePastEndOfInput() || !scanEscape())
- return Token::Illegal;
- }
- else
- addLiteralChar(c);
- }
- if (m_char != quote)
- return Token::Illegal;
- literal.complete();
- advance(); // consume quote
- return Token::StringLiteral;
-}
-
-Token Scanner::scanHexString()
-{
- char const quote = m_char;
- advance(); // consume quote
- LiteralScope literal(this, LITERAL_TYPE_STRING);
- while (m_char != quote && !isSourcePastEndOfInput())
- {
- char c = m_char;
- if (!scanHexByte(c))
- return Token::IllegalHex;
- addLiteralChar(c);
- }
- if (m_char != quote)
- return Token::IllegalHex;
- literal.complete();
- advance(); // consume quote
- return Token::StringLiteral;
-}
-
-// Parse for regex [:digit:]+(_[:digit:]+)*
-void Scanner::scanDecimalDigits()
-{
- // MUST begin with a decimal digit.
- if (!isDecimalDigit(m_char))
- return;
-
- // May continue with decimal digit or underscore for grouping.
- do addLiteralCharAndAdvance();
- while (!m_source.isPastEndOfInput() && (isDecimalDigit(m_char) || m_char == '_'));
-
- // Defer further validation of underscore to SyntaxChecker.
-}
-
-Token Scanner::scanNumber(char _charSeen)
-{
- enum { DECIMAL, HEX, BINARY } kind = DECIMAL;
- LiteralScope literal(this, LITERAL_TYPE_NUMBER);
- if (_charSeen == '.')
- {
- // we have already seen a decimal point of the float
- addLiteralChar('.');
- if (m_char == '_')
- return Token::Illegal;
- scanDecimalDigits(); // we know we have at least one digit
- }
- else
- {
- solAssert(_charSeen == 0, "");
- // if the first character is '0' we must check for octals and hex
- if (m_char == '0')
- {
- addLiteralCharAndAdvance();
- // either 0, 0exxx, 0Exxx, 0.xxx or a hex number
- if (m_char == 'x')
- {
- // hex number
- kind = HEX;
- addLiteralCharAndAdvance();
- if (!isHexDigit(m_char))
- return Token::Illegal; // we must have at least one hex digit after 'x'
-
- while (isHexDigit(m_char) || m_char == '_') // We keep the underscores for later validation
- addLiteralCharAndAdvance();
- }
- else if (isDecimalDigit(m_char))
- // We do not allow octal numbers
- return Token::Illegal;
- }
- // Parse decimal digits and allow trailing fractional part.
- if (kind == DECIMAL)
- {
- scanDecimalDigits(); // optional
- if (m_char == '.')
- {
- if (!m_source.isPastEndOfInput(1) && m_source.get(1) == '_')
- {
- // Assume the input may be a floating point number with leading '_' in fraction part.
- // Recover by consuming it all but returning `Illegal` right away.
- addLiteralCharAndAdvance(); // '.'
- addLiteralCharAndAdvance(); // '_'
- scanDecimalDigits();
- }
- if (m_source.isPastEndOfInput() || !isDecimalDigit(m_source.get(1)))
- {
- // A '.' has to be followed by a number.
- literal.complete();
- return Token::Number;
- }
- addLiteralCharAndAdvance();
- scanDecimalDigits();
- }
- }
- }
- // scan exponent, if any
- if (m_char == 'e' || m_char == 'E')
- {
- solAssert(kind != HEX, "'e'/'E' must be scanned as part of the hex number");
- if (kind != DECIMAL)
- return Token::Illegal;
- else if (!m_source.isPastEndOfInput(1) && m_source.get(1) == '_')
- {
- // Recover from wrongly placed underscore as delimiter in literal with scientific
- // notation by consuming until the end.
- addLiteralCharAndAdvance(); // 'e'
- addLiteralCharAndAdvance(); // '_'
- scanDecimalDigits();
- literal.complete();
- return Token::Number;
- }
- // scan exponent
- addLiteralCharAndAdvance(); // 'e' | 'E'
- if (m_char == '+' || m_char == '-')
- addLiteralCharAndAdvance();
- if (!isDecimalDigit(m_char))
- return Token::Illegal; // we must have at least one decimal digit after 'e'/'E'
- scanDecimalDigits();
- }
- // The source character immediately following a numeric literal must
- // not be an identifier start or a decimal digit; see ECMA-262
- // section 7.8.3, page 17 (note that we read only one decimal digit
- // if the value is 0).
- if (isDecimalDigit(m_char) || isIdentifierStart(m_char))
- return Token::Illegal;
- literal.complete();
- return Token::Number;
-}
-
-tuple<Token, unsigned, unsigned> Scanner::scanIdentifierOrKeyword()
-{
- solAssert(isIdentifierStart(m_char), "");
- LiteralScope literal(this, LITERAL_TYPE_STRING);
- addLiteralCharAndAdvance();
- // Scan the rest of the identifier characters.
- while (isIdentifierPart(m_char)) //get full literal
- addLiteralCharAndAdvance();
- literal.complete();
- return TokenTraits::fromIdentifierOrKeyword(m_nextToken.literal);
-}
-
-char CharStream::advanceAndGet(size_t _chars)
-{
- if (isPastEndOfInput())
- return 0;
- m_position += _chars;
- if (isPastEndOfInput())
- return 0;
- return m_source[m_position];
-}
-
-char CharStream::rollback(size_t _amount)
-{
- solAssert(m_position >= _amount, "");
- m_position -= _amount;
- return get();
-}
-
-string CharStream::lineAtPosition(int _position) const
-{
- // if _position points to \n, it returns the line before the \n
- using size_type = string::size_type;
- size_type searchStart = min<size_type>(m_source.size(), _position);
- if (searchStart > 0)
- searchStart--;
- size_type lineStart = m_source.rfind('\n', searchStart);
- if (lineStart == string::npos)
- lineStart = 0;
- else
- lineStart++;
- return m_source.substr(lineStart, min(m_source.find('\n', lineStart),
- m_source.size()) - lineStart);
-}
-
-tuple<int, int> CharStream::translatePositionToLineColumn(int _position) const
-{
- using size_type = string::size_type;
- size_type searchPosition = min<size_type>(m_source.size(), _position);
- int lineNumber = count(m_source.begin(), m_source.begin() + searchPosition, '\n');
- size_type lineStart;
- if (searchPosition == 0)
- lineStart = 0;
- else
- {
- lineStart = m_source.rfind('\n', searchPosition - 1);
- lineStart = lineStart == string::npos ? 0 : lineStart + 1;
- }
- return tuple<int, int>(lineNumber, searchPosition - lineStart);
-}
-
-
-}
-}
diff --git a/libsolidity/parsing/Scanner.h b/libsolidity/parsing/Scanner.h
deleted file mode 100644
index 14eeb66e..00000000
--- a/libsolidity/parsing/Scanner.h
+++ /dev/null
@@ -1,249 +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/>.
-
- This file is derived from the file "scanner.h", which was part of the
- V8 project. The original copyright header follows:
-
- Copyright 2006-2012, the V8 project authors. All rights reserved.
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are
- met:
-
- * Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above
- copyright notice, this list of conditions and the following
- disclaimer in the documentation and/or other materials provided
- with the distribution.
- * Neither the name of Google Inc. nor the names of its
- contributors may be used to endorse or promote products derived
- from this software without specific prior written permission.
-
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-*/
-/**
- * @author Christian <c@ethdev.com>
- * @date 2014
- * Solidity scanner.
- */
-
-#pragma once
-
-#include <libdevcore/Common.h>
-#include <libdevcore/CommonData.h>
-#include <libevmasm/SourceLocation.h>
-#include <libsolidity/parsing/Token.h>
-
-namespace dev
-{
-namespace solidity
-{
-
-
-class AstRawString;
-class AstValueFactory;
-class ParserRecorder;
-
-class CharStream
-{
-public:
- CharStream(): m_position(0) {}
- explicit CharStream(std::string const& _source): m_source(_source), m_position(0) {}
- int position() const { return m_position; }
- bool isPastEndOfInput(size_t _charsForward = 0) const { return (m_position + _charsForward) >= m_source.size(); }
- char get(size_t _charsForward = 0) const { return m_source[m_position + _charsForward]; }
- char advanceAndGet(size_t _chars = 1);
- char rollback(size_t _amount);
-
- void reset() { m_position = 0; }
-
- std::string const& source() const { return m_source; }
-
- ///@{
- ///@name Error printing helper functions
- /// Functions that help pretty-printing parse errors
- /// Do only use in error cases, they are quite expensive.
- std::string lineAtPosition(int _position) const;
- std::tuple<int, int> translatePositionToLineColumn(int _position) const;
- ///@}
-
-private:
- std::string m_source;
- size_t m_position;
-};
-
-
-
-class Scanner
-{
- friend class LiteralScope;
-public:
-
- explicit Scanner(CharStream const& _source = CharStream(), std::string const& _sourceName = "") { reset(_source, _sourceName); }
-
- std::string source() const { return m_source.source(); }
-
- /// Resets the scanner as if newly constructed with _source and _sourceName as input.
- void reset(CharStream const& _source, std::string const& _sourceName);
- /// Resets scanner to the start of input.
- void reset();
-
- /// @returns the next token and advances input
- Token next();
-
- ///@{
- ///@name Information about the current token
-
- /// @returns the current token
- Token currentToken() const
- {
- return m_currentToken.token;
- }
- ElementaryTypeNameToken currentElementaryTypeNameToken() const
- {
- unsigned firstSize;
- unsigned secondSize;
- std::tie(firstSize, secondSize) = m_currentToken.extendedTokenInfo;
- return ElementaryTypeNameToken(m_currentToken.token, firstSize, secondSize);
- }
-
- SourceLocation currentLocation() const { return m_currentToken.location; }
- std::string const& currentLiteral() const { return m_currentToken.literal; }
- std::tuple<unsigned, unsigned> const& currentTokenInfo() const { return m_currentToken.extendedTokenInfo; }
- ///@}
-
- ///@{
- ///@name Information about the current comment token
-
- SourceLocation currentCommentLocation() const { return m_skippedComment.location; }
- std::string const& currentCommentLiteral() const { return m_skippedComment.literal; }
- /// Called by the parser during FunctionDefinition parsing to clear the current comment
- void clearCurrentCommentLiteral() { m_skippedComment.literal.clear(); }
-
- ///@}
-
- ///@{
- ///@name Information about the next token
-
- /// @returns the next token without advancing input.
- Token peekNextToken() const { return m_nextToken.token; }
- SourceLocation peekLocation() const { return m_nextToken.location; }
- std::string const& peekLiteral() const { return m_nextToken.literal; }
- ///@}
-
- std::shared_ptr<std::string const> const& sourceName() const { return m_sourceName; }
-
- ///@{
- ///@name Error printing helper functions
- /// Functions that help pretty-printing parse errors
- /// Do only use in error cases, they are quite expensive.
- std::string lineAtPosition(int _position) const { return m_source.lineAtPosition(_position); }
- std::tuple<int, int> translatePositionToLineColumn(int _position) const { return m_source.translatePositionToLineColumn(_position); }
- std::string sourceAt(SourceLocation const& _location) const
- {
- solAssert(!_location.isEmpty(), "");
- solAssert(m_sourceName && _location.sourceName, "");
- solAssert(*m_sourceName == *_location.sourceName, "");
- return m_source.source().substr(_location.start, _location.end - _location.start);
- }
- ///@}
-
-private:
- /// Used for the current and look-ahead token and comments
- struct TokenDesc
- {
- Token token;
- SourceLocation location;
- std::string literal;
- std::tuple<unsigned, unsigned> extendedTokenInfo;
- };
-
- ///@{
- ///@name Literal buffer support
- inline void addLiteralChar(char c) { m_nextToken.literal.push_back(c); }
- inline void addCommentLiteralChar(char c) { m_nextSkippedComment.literal.push_back(c); }
- inline void addLiteralCharAndAdvance() { addLiteralChar(m_char); advance(); }
- void addUnicodeAsUTF8(unsigned codepoint);
- ///@}
-
- bool advance() { m_char = m_source.advanceAndGet(); return !m_source.isPastEndOfInput(); }
- void rollback(int _amount) { m_char = m_source.rollback(_amount); }
-
- inline Token selectToken(Token _tok) { advance(); return _tok; }
- /// If the next character is _next, advance and return _then, otherwise return _else.
- inline Token selectToken(char _next, Token _then, Token _else);
-
- bool scanHexByte(char& o_scannedByte);
- bool scanUnicode(unsigned& o_codepoint);
-
- /// Scans a single Solidity token.
- void scanToken();
-
- /// Skips all whitespace and @returns true if something was skipped.
- bool skipWhitespace();
- /// Skips all whitespace that are neither '\r' nor '\n'.
- void skipWhitespaceExceptUnicodeLinebreak();
- Token skipSingleLineComment();
- Token skipMultiLineComment();
-
- void scanDecimalDigits();
- Token scanNumber(char _charSeen = 0);
- std::tuple<Token, unsigned, unsigned> scanIdentifierOrKeyword();
-
- Token scanString();
- Token scanHexString();
- Token scanSingleLineDocComment();
- Token scanMultiLineDocComment();
- /// Scans a slash '/' and depending on the characters returns the appropriate token
- Token scanSlash();
-
- /// Scans an escape-sequence which is part of a string and adds the
- /// decoded character to the current literal. Returns true if a pattern
- /// is scanned.
- bool scanEscape();
-
- /// @returns true iff we are currently positioned at a unicode line break.
- bool isUnicodeLinebreak();
-
- /// Return the current source position.
- int sourcePos() const { return m_source.position(); }
- bool isSourcePastEndOfInput() const { return m_source.isPastEndOfInput(); }
-
- TokenDesc m_skippedComment; // desc for current skipped comment
- TokenDesc m_nextSkippedComment; // desc for next skipped comment
-
- TokenDesc m_currentToken; // desc for current token (as returned by Next())
- TokenDesc m_nextToken; // desc for next token (one token look-ahead)
-
- CharStream m_source;
- std::shared_ptr<std::string const> m_sourceName;
-
- /// one character look-ahead, equals 0 at end of input
- char m_char;
-};
-
-}
-}
diff --git a/libsolidity/parsing/Token.cpp b/libsolidity/parsing/Token.cpp
deleted file mode 100644
index dccd9037..00000000
--- a/libsolidity/parsing/Token.cpp
+++ /dev/null
@@ -1,207 +0,0 @@
-// Copyright 2006-2012, the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Modifications as part of solidity under the following license:
-//
-// 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 <map>
-#include <libsolidity/parsing/Token.h>
-#include <boost/range/iterator_range.hpp>
-
-using namespace std;
-
-namespace dev
-{
-namespace solidity
-{
-
-void ElementaryTypeNameToken::assertDetails(Token _baseType, unsigned const& _first, unsigned const& _second)
-{
- solAssert(TokenTraits::isElementaryTypeName(_baseType), "Expected elementary type name: " + string(TokenTraits::toString(_baseType)));
- if (_baseType == Token::BytesM)
- {
- solAssert(_second == 0, "There should not be a second size argument to type bytesM.");
- solAssert(_first <= 32, "No elementary type bytes" + to_string(_first) + ".");
- }
- else if (_baseType == Token::UIntM || _baseType == Token::IntM)
- {
- solAssert(_second == 0, "There should not be a second size argument to type " + string(TokenTraits::toString(_baseType)) + ".");
- solAssert(
- _first <= 256 && _first % 8 == 0,
- "No elementary type " + string(TokenTraits::toString(_baseType)) + to_string(_first) + "."
- );
- }
- else if (_baseType == Token::UFixedMxN || _baseType == Token::FixedMxN)
- {
- solAssert(
- _first >= 8 && _first <= 256 && _first % 8 == 0 && _second <= 80,
- "No elementary type " + string(TokenTraits::toString(_baseType)) + to_string(_first) + "x" + to_string(_second) + "."
- );
- }
- m_token = _baseType;
- m_firstNumber = _first;
- m_secondNumber = _second;
-}
-
-namespace TokenTraits
-{
-
-char const* toString(Token tok)
-{
- switch (tok)
- {
-#define T(name, string, precedence) case Token::name: return string;
- TOKEN_LIST(T, T)
-#undef T
- default: // Token::NUM_TOKENS:
- return "";
- }
-}
-
-char const* name(Token tok)
-{
-#define T(name, string, precedence) #name,
- static char const* const names[TokenTraits::count()] = { TOKEN_LIST(T, T) };
-#undef T
-
- solAssert(static_cast<size_t>(tok) < TokenTraits::count(), "");
- return names[static_cast<size_t>(tok)];
-}
-
-std::string friendlyName(Token tok)
-{
- char const* ret = toString(tok);
- if (ret)
- return std::string(ret);
-
- ret = name(tok);
- solAssert(ret != nullptr, "");
- return std::string(ret);
-}
-
-#define T(name, string, precedence) precedence,
-int precedence(Token tok)
-{
- int8_t const static precs[TokenTraits::count()] =
- {
- TOKEN_LIST(T, T)
- };
- return precs[static_cast<size_t>(tok)];
-}
-#undef T
-
-int parseSize(string::const_iterator _begin, string::const_iterator _end)
-{
- try
- {
- unsigned int m = boost::lexical_cast<int>(boost::make_iterator_range(_begin, _end));
- return m;
- }
- catch(boost::bad_lexical_cast const&)
- {
- return -1;
- }
-}
-
-static Token keywordByName(string const& _name)
-{
- // The following macros are used inside TOKEN_LIST and cause non-keyword tokens to be ignored
- // and keywords to be put inside the keywords variable.
-#define KEYWORD(name, string, precedence) {string, Token::name},
-#define TOKEN(name, string, precedence)
- static const map<string, Token> keywords({TOKEN_LIST(TOKEN, KEYWORD)});
-#undef KEYWORD
-#undef TOKEN
- auto it = keywords.find(_name);
- return it == keywords.end() ? Token::Identifier : it->second;
-}
-
-tuple<Token, unsigned int, unsigned int> fromIdentifierOrKeyword(string const& _literal)
-{
- auto positionM = find_if(_literal.begin(), _literal.end(), ::isdigit);
- if (positionM != _literal.end())
- {
- string baseType(_literal.begin(), positionM);
- auto positionX = find_if_not(positionM, _literal.end(), ::isdigit);
- int m = parseSize(positionM, positionX);
- Token keyword = keywordByName(baseType);
- if (keyword == Token::Bytes)
- {
- if (0 < m && m <= 32 && positionX == _literal.end())
- return make_tuple(Token::BytesM, m, 0);
- }
- else if (keyword == Token::UInt || keyword == Token::Int)
- {
- if (0 < m && m <= 256 && m % 8 == 0 && positionX == _literal.end())
- {
- if (keyword == Token::UInt)
- return make_tuple(Token::UIntM, m, 0);
- else
- return make_tuple(Token::IntM, m, 0);
- }
- }
- else if (keyword == Token::UFixed || keyword == Token::Fixed)
- {
- if (
- positionM < positionX &&
- positionX < _literal.end() &&
- *positionX == 'x' &&
- all_of(positionX + 1, _literal.end(), ::isdigit)
- ) {
- int n = parseSize(positionX + 1, _literal.end());
- if (
- 8 <= m && m <= 256 && m % 8 == 0 &&
- 0 <= n && n <= 80
- ) {
- if (keyword == Token::UFixed)
- return make_tuple(Token::UFixedMxN, m, n);
- else
- return make_tuple(Token::FixedMxN, m, n);
- }
- }
- }
- return make_tuple(Token::Identifier, 0, 0);
- }
-
- return make_tuple(keywordByName(_literal), 0, 0);
-}
-
-}
-}
-}
diff --git a/libsolidity/parsing/Token.h b/libsolidity/parsing/Token.h
index 81e8dd98..d61aefb6 100644
--- a/libsolidity/parsing/Token.h
+++ b/libsolidity/parsing/Token.h
@@ -1,378 +1,36 @@
-// Copyright 2006-2012, the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-// Modifications as part of solidity under the following license:
-//
-// 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/>.
-
+/*
+ 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/>.
+*/
+/**
+ * Solidity and Yul both share the same Token (and Scanner) API.
+ *
+ * This may (or may not) change in the future. But for the time being, we've put both
+ * at a shared place, and *just* import them.
+*/
#pragma once
-#include <libdevcore/Common.h>
-#include <libsolidity/interface/Exceptions.h>
-#include <libsolidity/parsing/UndefMacros.h>
-#include <iosfwd>
+#include <liblangutil/Token.h>
namespace dev
{
namespace solidity
{
+namespace TokenTraits = ::langutil::TokenTraits;
-// TOKEN_LIST takes a list of 3 macros M, all of which satisfy the
-// same signature M(name, string, precedence), where name is the
-// symbolic token name, string is the corresponding syntactic symbol
-// (or NULL, for literals), and precedence is the precedence (or 0).
-// The parameters are invoked for token categories as follows:
-//
-// T: Non-keyword tokens
-// K: Keyword tokens
-
-// IGNORE_TOKEN is a convenience macro that can be supplied as
-// an argument (at any position) for a TOKEN_LIST call. It does
-// nothing with tokens belonging to the respective category.
-
-#define IGNORE_TOKEN(name, string, precedence)
-
-#define TOKEN_LIST(T, K) \
- /* End of source indicator. */ \
- T(EOS, "EOS", 0) \
- \
- /* Punctuators (ECMA-262, section 7.7, page 15). */ \
- T(LParen, "(", 0) \
- T(RParen, ")", 0) \
- T(LBrack, "[", 0) \
- T(RBrack, "]", 0) \
- T(LBrace, "{", 0) \
- T(RBrace, "}", 0) \
- T(Colon, ":", 0) \
- T(Semicolon, ";", 0) \
- T(Period, ".", 0) \
- T(Conditional, "?", 3) \
- T(Arrow, "=>", 0) \
- \
- /* Assignment operators. */ \
- /* IsAssignmentOp() relies on this block of enum values being */ \
- /* contiguous and sorted in the same order!*/ \
- T(Assign, "=", 2) \
- /* The following have to be in exactly the same order as the simple binary operators*/ \
- T(AssignBitOr, "|=", 2) \
- T(AssignBitXor, "^=", 2) \
- T(AssignBitAnd, "&=", 2) \
- T(AssignShl, "<<=", 2) \
- T(AssignSar, ">>=", 2) \
- T(AssignShr, ">>>=", 2) \
- T(AssignAdd, "+=", 2) \
- T(AssignSub, "-=", 2) \
- T(AssignMul, "*=", 2) \
- T(AssignDiv, "/=", 2) \
- T(AssignMod, "%=", 2) \
- \
- /* Binary operators sorted by precedence. */ \
- /* IsBinaryOp() relies on this block of enum values */ \
- /* being contiguous and sorted in the same order! */ \
- T(Comma, ",", 1) \
- T(Or, "||", 4) \
- T(And, "&&", 5) \
- T(BitOr, "|", 8) \
- T(BitXor, "^", 9) \
- T(BitAnd, "&", 10) \
- T(SHL, "<<", 11) \
- T(SAR, ">>", 11) \
- T(SHR, ">>>", 11) \
- T(Add, "+", 12) \
- T(Sub, "-", 12) \
- T(Mul, "*", 13) \
- T(Div, "/", 13) \
- T(Mod, "%", 13) \
- T(Exp, "**", 14) \
- \
- /* Compare operators sorted by precedence. */ \
- /* IsCompareOp() relies on this block of enum values */ \
- /* being contiguous and sorted in the same order! */ \
- T(Equal, "==", 6) \
- T(NotEqual, "!=", 6) \
- T(LessThan, "<", 7) \
- T(GreaterThan, ">", 7) \
- T(LessThanOrEqual, "<=", 7) \
- T(GreaterThanOrEqual, ">=", 7) \
- \
- /* Unary operators. */ \
- /* IsUnaryOp() relies on this block of enum values */ \
- /* being contiguous and sorted in the same order! */ \
- T(Not, "!", 0) \
- T(BitNot, "~", 0) \
- T(Inc, "++", 0) \
- T(Dec, "--", 0) \
- K(Delete, "delete", 0) \
- \
- /* Keywords */ \
- K(Anonymous, "anonymous", 0) \
- K(As, "as", 0) \
- K(Assembly, "assembly", 0) \
- K(Break, "break", 0) \
- K(Constant, "constant", 0) \
- K(Constructor, "constructor", 0) \
- K(Continue, "continue", 0) \
- K(Contract, "contract", 0) \
- K(Do, "do", 0) \
- K(Else, "else", 0) \
- K(Enum, "enum", 0) \
- K(Emit, "emit", 0) \
- K(Event, "event", 0) \
- K(External, "external", 0) \
- K(For, "for", 0) \
- K(Function, "function", 0) \
- K(Hex, "hex", 0) \
- K(If, "if", 0) \
- K(Indexed, "indexed", 0) \
- K(Interface, "interface", 0) \
- K(Internal, "internal", 0) \
- K(Import, "import", 0) \
- K(Is, "is", 0) \
- K(Library, "library", 0) \
- K(Mapping, "mapping", 0) \
- K(Memory, "memory", 0) \
- K(Modifier, "modifier", 0) \
- K(New, "new", 0) \
- K(Payable, "payable", 0) \
- K(Public, "public", 0) \
- K(Pragma, "pragma", 0) \
- K(Private, "private", 0) \
- K(Pure, "pure", 0) \
- K(Return, "return", 0) \
- K(Returns, "returns", 0) \
- K(Storage, "storage", 0) \
- K(CallData, "calldata", 0) \
- K(Struct, "struct", 0) \
- K(Throw, "throw", 0) \
- K(Using, "using", 0) \
- K(Var, "var", 0) \
- K(View, "view", 0) \
- K(While, "while", 0) \
- \
- /* Ether subdenominations */ \
- K(SubWei, "wei", 0) \
- K(SubSzabo, "szabo", 0) \
- K(SubFinney, "finney", 0) \
- K(SubEther, "ether", 0) \
- K(SubSecond, "seconds", 0) \
- K(SubMinute, "minutes", 0) \
- K(SubHour, "hours", 0) \
- K(SubDay, "days", 0) \
- K(SubWeek, "weeks", 0) \
- K(SubYear, "years", 0) \
- /* type keywords*/ \
- K(Int, "int", 0) \
- K(UInt, "uint", 0) \
- K(Bytes, "bytes", 0) \
- K(Byte, "byte", 0) \
- K(String, "string", 0) \
- K(Address, "address", 0) \
- K(Bool, "bool", 0) \
- K(Fixed, "fixed", 0) \
- K(UFixed, "ufixed", 0) \
- T(IntM, "intM", 0) \
- T(UIntM, "uintM", 0) \
- T(BytesM, "bytesM", 0) \
- T(FixedMxN, "fixedMxN", 0) \
- T(UFixedMxN, "ufixedMxN", 0) \
- T(TypesEnd, NULL, 0) /* used as type enum end marker */ \
- \
- /* Literals */ \
- K(TrueLiteral, "true", 0) \
- K(FalseLiteral, "false", 0) \
- T(Number, NULL, 0) \
- T(StringLiteral, NULL, 0) \
- T(CommentLiteral, NULL, 0) \
- \
- /* Identifiers (not keywords or future reserved words). */ \
- T(Identifier, NULL, 0) \
- \
- /* Keywords reserved for future use. */ \
- K(Abstract, "abstract", 0) \
- K(After, "after", 0) \
- K(Alias, "alias", 0) \
- K(Apply, "apply", 0) \
- K(Auto, "auto", 0) \
- K(Case, "case", 0) \
- K(Catch, "catch", 0) \
- K(CopyOf, "copyof", 0) \
- K(Default, "default", 0) \
- K(Define, "define", 0) \
- K(Final, "final", 0) \
- K(Immutable, "immutable", 0) \
- K(Implements, "implements", 0) \
- K(In, "in", 0) \
- K(Inline, "inline", 0) \
- K(Let, "let", 0) \
- K(Macro, "macro", 0) \
- K(Match, "match", 0) \
- K(Mutable, "mutable", 0) \
- K(NullLiteral, "null", 0) \
- K(Of, "of", 0) \
- K(Override, "override", 0) \
- K(Partial, "partial", 0) \
- K(Promise, "promise", 0) \
- K(Reference, "reference", 0) \
- K(Relocatable, "relocatable", 0) \
- K(Sealed, "sealed", 0) \
- K(Sizeof, "sizeof", 0) \
- K(Static, "static", 0) \
- K(Supports, "supports", 0) \
- K(Switch, "switch", 0) \
- K(Try, "try", 0) \
- K(Type, "type", 0) \
- K(Typedef, "typedef", 0) \
- K(TypeOf, "typeof", 0) \
- K(Unchecked, "unchecked", 0) \
- \
- /* Illegal token - not able to scan. */ \
- T(Illegal, "ILLEGAL", 0) \
- /* Illegal hex token */ \
- T(IllegalHex, "ILLEGAL_HEX", 0) \
- \
- /* Scanner-internal use only. */ \
- T(Whitespace, NULL, 0)
-
-// All token values.
-// attention! msvc issue:
-// http://stackoverflow.com/questions/9567868/compile-errors-after-adding-v8-to-my-project-c2143-c2059
-// @todo: avoid TOKEN_LIST macro
-enum class Token : unsigned int {
-#define T(name, string, precedence) name,
- TOKEN_LIST(T, T)
- NUM_TOKENS
-#undef T
-};
-
-namespace TokenTraits
-{
- constexpr size_t count() { return static_cast<size_t>(Token::NUM_TOKENS); }
-
- // Predicates
- constexpr bool isElementaryTypeName(Token tok) { return Token::Int <= tok && tok < Token::TypesEnd; }
- constexpr bool isAssignmentOp(Token tok) { return Token::Assign <= tok && tok <= Token::AssignMod; }
- constexpr bool isBinaryOp(Token op) { return Token::Comma <= op && op <= Token::Exp; }
- constexpr bool isCommutativeOp(Token op) { return op == Token::BitOr || op == Token::BitXor || op == Token::BitAnd ||
- op == Token::Add || op == Token::Mul || op == Token::Equal || op == Token::NotEqual; }
- constexpr bool isArithmeticOp(Token op) { return Token::Add <= op && op <= Token::Exp; }
- constexpr bool isCompareOp(Token op) { return Token::Equal <= op && op <= Token::GreaterThanOrEqual; }
-
- constexpr bool isBitOp(Token op) { return (Token::BitOr <= op && op <= Token::BitAnd) || op == Token::BitNot; }
- constexpr bool isBooleanOp(Token op) { return (Token::Or <= op && op <= Token::And) || op == Token::Not; }
- constexpr bool isUnaryOp(Token op) { return (Token::Not <= op && op <= Token::Delete) || op == Token::Add || op == Token::Sub; }
- constexpr bool isCountOp(Token op) { return op == Token::Inc || op == Token::Dec; }
- constexpr bool isShiftOp(Token op) { return (Token::SHL <= op) && (op <= Token::SHR); }
- constexpr bool isVariableVisibilitySpecifier(Token op) { return op == Token::Public || op == Token::Private || op == Token::Internal; }
- constexpr bool isVisibilitySpecifier(Token op) { return isVariableVisibilitySpecifier(op) || op == Token::External; }
- constexpr bool isLocationSpecifier(Token op) { return op == Token::Memory || op == Token::Storage || op == Token::CallData; }
-
- constexpr bool isStateMutabilitySpecifier(Token op, bool _allowConstant = true)
- {
- return (op == Token::Constant && _allowConstant)
- || op == Token::Pure || op == Token::View || op == Token::Payable;
- }
-
- constexpr bool isEtherSubdenomination(Token op) { return op == Token::SubWei || op == Token::SubSzabo || op == Token::SubFinney || op == Token::SubEther; }
- constexpr bool isTimeSubdenomination(Token op) { return op == Token::SubSecond || op == Token::SubMinute || op == Token::SubHour || op == Token::SubDay || op == Token::SubWeek || op == Token::SubYear; }
- constexpr bool isReservedKeyword(Token op) { return (Token::Abstract <= op && op <= Token::Unchecked); }
-
- inline Token AssignmentToBinaryOp(Token op)
- {
- solAssert(isAssignmentOp(op) && op != Token::Assign, "");
- return static_cast<Token>(static_cast<int>(op) + (static_cast<int>(Token::BitOr) - static_cast<int>(Token::AssignBitOr)));
- }
-
- // @returns the precedence > 0 for binary and compare
- // operators; returns 0 otherwise.
- int precedence(Token tok);
-
- std::tuple<Token, unsigned int, unsigned int> fromIdentifierOrKeyword(std::string const& _literal);
-
- // @returns a string corresponding to the C++ token name
- // (e.g. "LT" for the token LT).
- char const* name(Token tok);
-
- // @returns a string corresponding to the JS token string
- // (.e., "<" for the token LT) or NULL if the token doesn't
- // have a (unique) string (e.g. an IDENTIFIER).
- char const* toString(Token tok);
-
- std::string friendlyName(Token tok);
-}
-
-inline std::ostream& operator<<(std::ostream& os, Token token)
-{
- os << TokenTraits::friendlyName(token);
- return os;
-}
-
-class ElementaryTypeNameToken
-{
-public:
- ElementaryTypeNameToken(Token _token, unsigned const& _firstNumber, unsigned const& _secondNumber)
- {
- assertDetails(_token, _firstNumber, _secondNumber);
- }
-
- unsigned int firstNumber() const { return m_firstNumber; }
- unsigned int secondNumber() const { return m_secondNumber; }
- Token token() const { return m_token; }
-
- ///if tokValue is set to true, then returns the actual token type name, otherwise, returns full type
- std::string toString(bool const& tokenValue = false) const
- {
- std::string name = TokenTraits::toString(m_token);
- if (tokenValue || (firstNumber() == 0 && secondNumber() == 0))
- return name;
- solAssert(name.size() >= 3, "Token name size should be greater than 3. Should not reach here.");
- if (m_token == Token::FixedMxN || m_token == Token::UFixedMxN)
- return name.substr(0, name.size() - 3) + std::to_string(m_firstNumber) + "x" + std::to_string(m_secondNumber);
- else
- return name.substr(0, name.size() - 1) + std::to_string(m_firstNumber);
- }
-
-private:
- Token m_token;
- unsigned int m_firstNumber;
- unsigned int m_secondNumber;
- /// throws if type is not properly sized
- void assertDetails(Token _baseType, unsigned const& _first, unsigned const& _second);
-};
-
+using ::langutil::Token;
+using ::langutil::ElementaryTypeNameToken;
}
}
diff --git a/libsolidity/parsing/UndefMacros.h b/libsolidity/parsing/UndefMacros.h
deleted file mode 100644
index d96e242e..00000000
--- a/libsolidity/parsing/UndefMacros.h
+++ /dev/null
@@ -1,46 +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/>.
-*/
-/** @file UndefMacros.h
- * @author Lefteris <lefteris@ethdev.com>
- * @date 2015
- *
- * This header should be used to #undef some really evil macros defined by
- * windows.h which result in conflict with our Token.h
- */
-#pragma once
-
-#if defined(_MSC_VER) || defined(__MINGW32__)
-
-#undef DELETE
-#undef IN
-#undef VOID
-#undef THIS
-#undef CONST
-
-// Conflicting define on MinGW in windows.h
-// windows.h(19): #define interface struct
-#ifdef interface
-#undef interface
-#endif
-
-#elif defined(DELETE) || defined(IN) || defined(VOID) || defined(THIS) || defined(CONST) || defined(interface)
-
-#error "The preceding macros in this header file are reserved for V8's "\
-"TOKEN_LIST. Please add a platform specific define above to undefine "\
-"overlapping macros."
-
-#endif