aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity/interface
diff options
context:
space:
mode:
authorchriseth <chris@ethereum.org>2018-12-20 01:06:13 +0800
committerGitHub <noreply@github.com>2018-12-20 01:06:13 +0800
commit1df8f40cd2fd7b47698d847907b8ca7b47eb488d (patch)
tree5ed5816fe2d1a8a207e750d39884aca7957c8289 /libsolidity/interface
parentc8a2cb62832afb2dc09ccee6fd42c1516dfdb981 (diff)
parentddf54b21d1d002903624f61173ab4af197f50053 (diff)
downloaddexon-solidity-1df8f40cd2fd7b47698d847907b8ca7b47eb488d.tar
dexon-solidity-1df8f40cd2fd7b47698d847907b8ca7b47eb488d.tar.gz
dexon-solidity-1df8f40cd2fd7b47698d847907b8ca7b47eb488d.tar.bz2
dexon-solidity-1df8f40cd2fd7b47698d847907b8ca7b47eb488d.tar.lz
dexon-solidity-1df8f40cd2fd7b47698d847907b8ca7b47eb488d.tar.xz
dexon-solidity-1df8f40cd2fd7b47698d847907b8ca7b47eb488d.tar.zst
dexon-solidity-1df8f40cd2fd7b47698d847907b8ca7b47eb488d.zip
Merge pull request #5697 from ethereum/develop
Merge develop into release for 0.5.2
Diffstat (limited to 'libsolidity/interface')
-rw-r--r--libsolidity/interface/ABI.cpp1
-rw-r--r--libsolidity/interface/ABI.h4
-rw-r--r--libsolidity/interface/AssemblyStack.cpp82
-rw-r--r--libsolidity/interface/AssemblyStack.h14
-rw-r--r--libsolidity/interface/CompilerStack.cpp99
-rw-r--r--libsolidity/interface/CompilerStack.h15
-rw-r--r--libsolidity/interface/GasEstimator.cpp19
-rw-r--r--libsolidity/interface/GasEstimator.h6
-rw-r--r--libsolidity/interface/Natspec.cpp3
-rw-r--r--libsolidity/interface/Natspec.h4
-rw-r--r--libsolidity/interface/ReadFile.h4
-rw-r--r--libsolidity/interface/StandardCompiler.cpp225
-rw-r--r--libsolidity/interface/Version.cpp5
-rw-r--r--libsolidity/interface/Version.h2
14 files changed, 380 insertions, 103 deletions
diff --git a/libsolidity/interface/ABI.cpp b/libsolidity/interface/ABI.cpp
index aefb34af..0d27109e 100644
--- a/libsolidity/interface/ABI.cpp
+++ b/libsolidity/interface/ABI.cpp
@@ -19,6 +19,7 @@
*/
#include <libsolidity/interface/ABI.h>
+
#include <libsolidity/ast/AST.h>
using namespace std;
diff --git a/libsolidity/interface/ABI.h b/libsolidity/interface/ABI.h
index db70729d..082f3900 100644
--- a/libsolidity/interface/ABI.h
+++ b/libsolidity/interface/ABI.h
@@ -20,9 +20,9 @@
#pragma once
-#include <string>
-#include <memory>
#include <json/json.h>
+#include <memory>
+#include <string>
namespace dev
{
diff --git a/libsolidity/interface/AssemblyStack.cpp b/libsolidity/interface/AssemblyStack.cpp
index f5eb7e41..69bceefc 100644
--- a/libsolidity/interface/AssemblyStack.cpp
+++ b/libsolidity/interface/AssemblyStack.cpp
@@ -22,18 +22,19 @@
#include <libsolidity/interface/AssemblyStack.h>
+#include <libsolidity/codegen/AsmCodeGen.h>
+#include <libevmasm/Assembly.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/AsmParser.h>
+#include <libyul/AsmPrinter.h>
#include <libyul/backends/evm/EVMAssembly.h>
+#include <libyul/backends/evm/EVMCodeTransform.h>
+#include <libyul/backends/evm/EVMDialect.h>
+#include <libyul/backends/evm/EVMObjectCompiler.h>
#include <libyul/ObjectParser.h>
-
-#include <libevmasm/Assembly.h>
-
#include <libyul/optimiser/Suite.h>
using namespace std;
@@ -43,19 +44,19 @@ using namespace dev::solidity;
namespace
{
-yul::AsmFlavour languageToAsmFlavour(AssemblyStack::Language _language)
+shared_ptr<yul::Dialect> languageToDialect(AssemblyStack::Language _language)
{
switch (_language)
{
case AssemblyStack::Language::Assembly:
- return yul::AsmFlavour::Loose;
+ return yul::EVMDialect::looseAssemblyForEVM();
case AssemblyStack::Language::StrictAssembly:
- return yul::AsmFlavour::Strict;
+ return yul::EVMDialect::strictAssemblyForEVMObjects();
case AssemblyStack::Language::Yul:
- return yul::AsmFlavour::Yul;
+ return yul::Dialect::yul();
}
solAssert(false, "");
- return yul::AsmFlavour::Yul;
+ return yul::Dialect::yul();
}
}
@@ -72,7 +73,7 @@ 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 = yul::ObjectParser(m_errorReporter, languageToAsmFlavour(m_language)).parse(m_scanner, false);
+ m_parserResult = yul::ObjectParser(m_errorReporter, languageToDialect(m_language)).parse(m_scanner, false);
if (!m_errorReporter.errors().empty())
return false;
solAssert(m_parserResult, "");
@@ -84,21 +85,59 @@ bool AssemblyStack::parseAndAnalyze(std::string const& _sourceName, std::string
void AssemblyStack::optimize()
{
solAssert(m_language != Language::Assembly, "Optimization requested for loose assembly.");
- yul::OptimiserSuite::run(*m_parserResult->code, *m_parserResult->analysisInfo);
+ solAssert(m_analysisSuccessful, "Analysis was not successful.");
+ m_analysisSuccessful = false;
+ optimize(*m_parserResult);
solAssert(analyzeParsed(), "Invalid source code after optimization.");
}
bool AssemblyStack::analyzeParsed()
{
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);
+ m_analysisSuccessful = analyzeParsed(*m_parserResult);
return m_analysisSuccessful;
}
-MachineAssemblyObject AssemblyStack::assemble(Machine _machine) const
+bool AssemblyStack::analyzeParsed(yul::Object& _object)
+{
+ solAssert(_object.code, "");
+ _object.analysisInfo = make_shared<yul::AsmAnalysisInfo>();
+ yul::AsmAnalyzer analyzer(*_object.analysisInfo, m_errorReporter, m_evmVersion, boost::none, languageToDialect(m_language));
+ bool success = analyzer.analyze(*_object.code);
+ for (auto& subNode: _object.subObjects)
+ if (auto subObject = dynamic_cast<yul::Object*>(subNode.get()))
+ if (!analyzeParsed(*subObject))
+ success = false;
+ return success;
+}
+
+void AssemblyStack::compileEVM(yul::AbstractAssembly& _assembly, bool _evm15, bool _optimize) const
+{
+ shared_ptr<yul::EVMDialect> dialect;
+
+ if (m_language == Language::Assembly)
+ dialect = yul::EVMDialect::looseAssemblyForEVM();
+ else if (m_language == AssemblyStack::Language::StrictAssembly)
+ dialect = yul::EVMDialect::strictAssemblyForEVMObjects();
+ else if (m_language == AssemblyStack::Language::Yul)
+ dialect = yul::EVMDialect::yulForEVM();
+ else
+ solAssert(false, "Invalid language.");
+
+ yul::EVMObjectCompiler::compile(*m_parserResult, _assembly, *dialect, _evm15, _optimize);
+}
+
+void AssemblyStack::optimize(yul::Object& _object)
+{
+ solAssert(_object.code, "");
+ solAssert(_object.analysisInfo, "");
+ for (auto& subNode: _object.subObjects)
+ if (auto subObject = dynamic_cast<yul::Object*>(subNode.get()))
+ optimize(*subObject);
+ yul::OptimiserSuite::run(*_object.code, *_object.analysisInfo);
+}
+
+MachineAssemblyObject AssemblyStack::assemble(Machine _machine, bool _optimize) const
{
solAssert(m_analysisSuccessful, "");
solAssert(m_parserResult, "");
@@ -111,7 +150,8 @@ MachineAssemblyObject AssemblyStack::assemble(Machine _machine) const
{
MachineAssemblyObject object;
eth::Assembly assembly;
- yul::CodeGenerator::assemble(*m_parserResult->code, *m_parserResult->analysisInfo, assembly);
+ EthAssemblyAdapter adapter(assembly);
+ compileEVM(adapter, false, _optimize);
object.bytecode = make_shared<eth::LinkerObject>(assembly.assemble());
object.assembly = assembly.assemblyString();
return object;
@@ -120,7 +160,7 @@ MachineAssemblyObject AssemblyStack::assemble(Machine _machine) const
{
MachineAssemblyObject object;
yul::EVMAssembly assembly(true);
- yul::CodeTransform(assembly, *m_parserResult->analysisInfo, m_language == Language::Yul, true)(*m_parserResult->code);
+ compileEVM(assembly, true, _optimize);
object.bytecode = make_shared<eth::LinkerObject>(assembly.finalize());
/// TODO: fill out text representation
return object;
diff --git a/libsolidity/interface/AssemblyStack.h b/libsolidity/interface/AssemblyStack.h
index 0d04ffec..01db6b61 100644
--- a/libsolidity/interface/AssemblyStack.h
+++ b/libsolidity/interface/AssemblyStack.h
@@ -29,13 +29,17 @@
#include <libevmasm/LinkerObject.h>
-#include <string>
#include <memory>
+#include <string>
namespace langutil
{
class Scanner;
}
+namespace yul
+{
+class AbstractAssembly;
+}
namespace dev
{
@@ -73,7 +77,8 @@ public:
void optimize();
/// Run the assembly step (should only be called after parseAndAnalyze).
- MachineAssemblyObject assemble(Machine _machine) const;
+ /// @param _optimize does not run the optimizer but performs optimized code generation.
+ MachineAssemblyObject assemble(Machine _machine, bool _optimize = false) const;
/// @returns the errors generated during parsing, analysis (and potentially assembly).
langutil::ErrorList const& errors() const { return m_errors; }
@@ -83,6 +88,11 @@ public:
private:
bool analyzeParsed();
+ bool analyzeParsed(yul::Object& _object);
+
+ void compileEVM(yul::AbstractAssembly& _assembly, bool _evm15, bool _optimize) const;
+
+ void optimize(yul::Object& _object);
Language m_language = Language::Assembly;
EVMVersion m_evmVersion;
diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp
index 610caea1..f9d889e7 100644
--- a/libsolidity/interface/CompilerStack.cpp
+++ b/libsolidity/interface/CompilerStack.cpp
@@ -24,26 +24,27 @@
#include <libsolidity/interface/CompilerStack.h>
-#include <libsolidity/interface/Version.h>
-#include <libsolidity/analysis/SemVerHandler.h>
-#include <libsolidity/ast/AST.h>
-#include <libsolidity/parsing/Parser.h>
-#include <libsolidity/analysis/ContractLevelChecker.h>
#include <libsolidity/analysis/ControlFlowAnalyzer.h>
#include <libsolidity/analysis/ControlFlowGraph.h>
+#include <libsolidity/analysis/ContractLevelChecker.h>
+#include <libsolidity/analysis/DocStringAnalyser.h>
#include <libsolidity/analysis/GlobalContext.h>
#include <libsolidity/analysis/NameAndTypeResolver.h>
-#include <libsolidity/analysis/TypeChecker.h>
-#include <libsolidity/analysis/DocStringAnalyser.h>
-#include <libsolidity/analysis/StaticAnalyzer.h>
#include <libsolidity/analysis/PostTypeChecker.h>
+#include <libsolidity/analysis/SemVerHandler.h>
+#include <libsolidity/analysis/StaticAnalyzer.h>
#include <libsolidity/analysis/SyntaxChecker.h>
+#include <libsolidity/analysis/TypeChecker.h>
#include <libsolidity/analysis/ViewPureChecker.h>
+
+#include <libsolidity/ast/AST.h>
#include <libsolidity/codegen/Compiler.h>
#include <libsolidity/formal/SMTChecker.h>
#include <libsolidity/interface/ABI.h>
#include <libsolidity/interface/Natspec.h>
#include <libsolidity/interface/GasEstimator.h>
+#include <libsolidity/interface/Version.h>
+#include <libsolidity/parsing/Parser.h>
#include <libyul/YulString.h>
@@ -388,18 +389,27 @@ string const CompilerStack::lastContractName() const
eth::AssemblyItems const* CompilerStack::assemblyItems(string const& _contractName) const
{
+ if (m_stackState != CompilationSuccessful)
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful."));
+
Contract const& currentContract = contract(_contractName);
return currentContract.compiler ? &contract(_contractName).compiler->assemblyItems() : nullptr;
}
eth::AssemblyItems const* CompilerStack::runtimeAssemblyItems(string const& _contractName) const
{
+ if (m_stackState != CompilationSuccessful)
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful."));
+
Contract const& currentContract = contract(_contractName);
return currentContract.compiler ? &contract(_contractName).compiler->runtimeAssemblyItems() : nullptr;
}
string const* CompilerStack::sourceMapping(string const& _contractName) const
{
+ if (m_stackState != CompilationSuccessful)
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful."));
+
Contract const& c = contract(_contractName);
if (!c.sourceMapping)
{
@@ -411,6 +421,9 @@ string const* CompilerStack::sourceMapping(string const& _contractName) const
string const* CompilerStack::runtimeSourceMapping(string const& _contractName) const
{
+ if (m_stackState != CompilationSuccessful)
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful."));
+
Contract const& c = contract(_contractName);
if (!c.runtimeSourceMapping)
{
@@ -446,17 +459,26 @@ std::string const CompilerStack::filesystemFriendlyName(string const& _contractN
eth::LinkerObject const& CompilerStack::object(string const& _contractName) const
{
+ if (m_stackState != CompilationSuccessful)
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful."));
+
return contract(_contractName).object;
}
eth::LinkerObject const& CompilerStack::runtimeObject(string const& _contractName) const
{
+ if (m_stackState != CompilationSuccessful)
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful."));
+
return contract(_contractName).runtimeObject;
}
/// FIXME: cache this string
string CompilerStack::assemblyString(string const& _contractName, StringMap _sourceCodes) const
{
+ if (m_stackState != CompilationSuccessful)
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful."));
+
Contract const& currentContract = contract(_contractName);
if (currentContract.compiler)
return currentContract.compiler->assemblyString(_sourceCodes);
@@ -467,6 +489,9 @@ string CompilerStack::assemblyString(string const& _contractName, StringMap _sou
/// FIXME: cache the JSON
Json::Value CompilerStack::assemblyJSON(string const& _contractName, StringMap _sourceCodes) const
{
+ if (m_stackState != CompilationSuccessful)
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful."));
+
Contract const& currentContract = contract(_contractName);
if (currentContract.compiler)
return currentContract.compiler->assemblyJSON(_sourceCodes);
@@ -493,13 +518,16 @@ map<string, unsigned> CompilerStack::sourceIndices() const
Json::Value const& CompilerStack::contractABI(string const& _contractName) const
{
+ if (m_stackState < AnalysisSuccessful)
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Analysis was not successful."));
+
return contractABI(contract(_contractName));
}
Json::Value const& CompilerStack::contractABI(Contract const& _contract) const
{
if (m_stackState < AnalysisSuccessful)
- BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Analysis was not successful."));
solAssert(_contract.contract, "");
@@ -512,13 +540,16 @@ Json::Value const& CompilerStack::contractABI(Contract const& _contract) const
Json::Value const& CompilerStack::natspecUser(string const& _contractName) const
{
+ if (m_stackState < AnalysisSuccessful)
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Analysis was not successful."));
+
return natspecUser(contract(_contractName));
}
Json::Value const& CompilerStack::natspecUser(Contract const& _contract) const
{
if (m_stackState < AnalysisSuccessful)
- BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Analysis was not successful."));
solAssert(_contract.contract, "");
@@ -531,13 +562,16 @@ Json::Value const& CompilerStack::natspecUser(Contract const& _contract) const
Json::Value const& CompilerStack::natspecDev(string const& _contractName) const
{
+ if (m_stackState < AnalysisSuccessful)
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Analysis was not successful."));
+
return natspecDev(contract(_contractName));
}
Json::Value const& CompilerStack::natspecDev(Contract const& _contract) const
{
if (m_stackState < AnalysisSuccessful)
- BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Parsing was not successful."));
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Analysis was not successful."));
solAssert(_contract.contract, "");
@@ -550,9 +584,12 @@ Json::Value const& CompilerStack::natspecDev(Contract const& _contract) const
Json::Value CompilerStack::methodIdentifiers(string const& _contractName) const
{
+ if (m_stackState < AnalysisSuccessful)
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Analysis was not successful."));
+
Json::Value methodIdentifiers(Json::objectValue);
for (auto const& it: contractDefinition(_contractName).interfaceFunctions())
- methodIdentifiers[it.second->externalSignature()] = toHex(it.first.ref());
+ methodIdentifiers[it.second->externalSignature()] = it.first.hex();
return methodIdentifiers;
}
@@ -582,8 +619,8 @@ SourceUnit const& CompilerStack::ast(string const& _sourceName) const
ContractDefinition const& CompilerStack::contractDefinition(string const& _contractName) const
{
- if (m_stackState != CompilationSuccessful)
- BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful."));
+ if (m_stackState < AnalysisSuccessful)
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Analysis was not successful."));
return *contract(_contractName).contract;
}
@@ -593,6 +630,9 @@ size_t CompilerStack::functionEntryPoint(
FunctionDefinition const& _function
) const
{
+ if (m_stackState != CompilationSuccessful)
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful."));
+
shared_ptr<Compiler> const& compiler = contract(_contractName).compiler;
if (!compiler)
return 0;
@@ -618,6 +658,22 @@ tuple<int, int, int, int> CompilerStack::positionFromSourceLocation(SourceLocati
return make_tuple(++startLine, ++startColumn, ++endLine, ++endColumn);
}
+
+h256 const& CompilerStack::Source::keccak256() const
+{
+ if (keccak256HashCached == h256{})
+ keccak256HashCached = dev::keccak256(scanner->source());
+ return keccak256HashCached;
+}
+
+h256 const& CompilerStack::Source::swarmHash() const
+{
+ if (swarmHashCached == h256{})
+ swarmHashCached = dev::swarmHash(scanner->source());
+ return swarmHashCached;
+}
+
+
StringMap CompilerStack::loadMissingSources(SourceUnit const& _ast, std::string const& _sourcePath)
{
solAssert(m_stackState < ParsingSuccessful, "");
@@ -859,16 +915,13 @@ string CompilerStack::createMetadata(Contract const& _contract) const
continue;
solAssert(s.second.scanner, "Scanner not available");
- meta["sources"][s.first]["keccak256"] =
- "0x" + toHex(dev::keccak256(s.second.scanner->source()).asBytes());
+ meta["sources"][s.first]["keccak256"] = "0x" + toHex(s.second.keccak256().asBytes());
if (m_metadataLiteralSources)
meta["sources"][s.first]["content"] = s.second.scanner->source();
else
{
meta["sources"][s.first]["urls"] = Json::arrayValue;
- meta["sources"][s.first]["urls"].append(
- "bzzr://" + toHex(dev::swarmHash(s.second.scanner->source()).asBytes())
- );
+ meta["sources"][s.first]["urls"].append("bzzr://" + toHex(s.second.swarmHash().asBytes()));
}
}
meta["settings"]["optimizer"]["enabled"] = m_optimize;
@@ -895,7 +948,7 @@ string CompilerStack::createMetadata(Contract const& _contract) const
return jsonCompactPrint(meta);
}
-bytes CompilerStack::createCBORMetadata(string _metadata, bool _experimentalMode)
+bytes CompilerStack::createCBORMetadata(string const& _metadata, bool _experimentalMode)
{
bytes cborEncodedHash =
// CBOR-encoding of the key "bzzr0"
@@ -922,6 +975,9 @@ bytes CompilerStack::createCBORMetadata(string _metadata, bool _experimentalMode
string CompilerStack::computeSourceMapping(eth::AssemblyItems const& _items) const
{
+ if (m_stackState != CompilationSuccessful)
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful."));
+
string ret;
map<string, unsigned> sourceIndicesMap = sourceIndices();
int prevStart = -1;
@@ -1008,6 +1064,9 @@ Json::Value gasToJson(GasEstimator::GasConsumption const& _gas)
Json::Value CompilerStack::gasEstimates(string const& _contractName) const
{
+ if (m_stackState != CompilationSuccessful)
+ BOOST_THROW_EXCEPTION(CompilerError() << errinfo_comment("Compilation was not successful."));
+
if (!assemblyItems(_contractName) && !runtimeAssemblyItems(_contractName))
return Json::Value();
diff --git a/libsolidity/interface/CompilerStack.h b/libsolidity/interface/CompilerStack.h
index 2c7add3b..81d5009f 100644
--- a/libsolidity/interface/CompilerStack.h
+++ b/libsolidity/interface/CompilerStack.h
@@ -34,15 +34,14 @@
#include <libdevcore/Common.h>
#include <libdevcore/FixedHash.h>
-#include <json/json.h>
-
#include <boost/noncopyable.hpp>
+#include <json/json.h>
+#include <functional>
+#include <memory>
#include <ostream>
#include <string>
-#include <memory>
#include <vector>
-#include <functional>
namespace langutil
{
@@ -262,7 +261,11 @@ private:
std::shared_ptr<langutil::Scanner> scanner;
std::shared_ptr<SourceUnit> ast;
bool isLibrary = false;
- void reset() { scanner.reset(); ast.reset(); }
+ h256 mutable keccak256HashCached;
+ h256 mutable swarmHashCached;
+ void reset() { *this = Source(); }
+ h256 const& keccak256() const;
+ h256 const& swarmHash() const;
};
/// The state per contract. Filled gradually during compilation.
@@ -316,7 +319,7 @@ private:
std::string createMetadata(Contract const& _contract) const;
/// @returns the metadata CBOR for the given serialised metadata JSON.
- static bytes createCBORMetadata(std::string _metadata, bool _experimentalMode);
+ static bytes createCBORMetadata(std::string const& _metadata, bool _experimentalMode);
/// @returns the computer source mapping string.
std::string computeSourceMapping(eth::AssemblyItems const& _items) const;
diff --git a/libsolidity/interface/GasEstimator.cpp b/libsolidity/interface/GasEstimator.cpp
index de6b2ce5..8ffcf951 100644
--- a/libsolidity/interface/GasEstimator.cpp
+++ b/libsolidity/interface/GasEstimator.cpp
@@ -20,18 +20,21 @@
* Gas consumption estimator working alongside the AST.
*/
-#include "GasEstimator.h"
-#include <map>
-#include <functional>
-#include <memory>
-#include <libdevcore/Keccak256.h>
-#include <libevmasm/ControlFlowGraph.h>
-#include <libevmasm/KnownState.h>
-#include <libevmasm/PathGasMeter.h>
+#include <libsolidity/interface/GasEstimator.h>
+
#include <libsolidity/ast/AST.h>
#include <libsolidity/ast/ASTVisitor.h>
#include <libsolidity/codegen/CompilerUtils.h>
+#include <libevmasm/ControlFlowGraph.h>
+#include <libevmasm/KnownState.h>
+#include <libevmasm/PathGasMeter.h>
+#include <libdevcore/Keccak256.h>
+
+#include <functional>
+#include <map>
+#include <memory>
+
using namespace std;
using namespace dev;
using namespace dev::eth;
diff --git a/libsolidity/interface/GasEstimator.h b/libsolidity/interface/GasEstimator.h
index 214a3e58..f40cffeb 100644
--- a/libsolidity/interface/GasEstimator.h
+++ b/libsolidity/interface/GasEstimator.h
@@ -24,12 +24,12 @@
#include <liblangutil/EVMVersion.h>
-#include <libevmasm/GasMeter.h>
#include <libevmasm/Assembly.h>
+#include <libevmasm/GasMeter.h>
-#include <vector>
-#include <map>
#include <array>
+#include <map>
+#include <vector>
namespace dev
{
diff --git a/libsolidity/interface/Natspec.cpp b/libsolidity/interface/Natspec.cpp
index 11dde349..7a89abae 100644
--- a/libsolidity/interface/Natspec.cpp
+++ b/libsolidity/interface/Natspec.cpp
@@ -24,8 +24,9 @@
*/
#include <libsolidity/interface/Natspec.h>
-#include <boost/range/irange.hpp>
+
#include <libsolidity/ast/AST.h>
+#include <boost/range/irange.hpp>
using namespace std;
using namespace dev;
diff --git a/libsolidity/interface/Natspec.h b/libsolidity/interface/Natspec.h
index 0be4dda2..fbaa6d4d 100644
--- a/libsolidity/interface/Natspec.h
+++ b/libsolidity/interface/Natspec.h
@@ -25,9 +25,9 @@
#pragma once
-#include <string>
-#include <memory>
#include <json/json.h>
+#include <memory>
+#include <string>
namespace dev
{
diff --git a/libsolidity/interface/ReadFile.h b/libsolidity/interface/ReadFile.h
index 7068629d..3b3d747e 100644
--- a/libsolidity/interface/ReadFile.h
+++ b/libsolidity/interface/ReadFile.h
@@ -17,9 +17,9 @@
#pragma once
-#include <string>
-#include <functional>
#include <boost/noncopyable.hpp>
+#include <functional>
+#include <string>
namespace dev
{
diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp
index 0eef50d2..137a4439 100644
--- a/libsolidity/interface/StandardCompiler.cpp
+++ b/libsolidity/interface/StandardCompiler.cpp
@@ -21,13 +21,17 @@
*/
#include <libsolidity/interface/StandardCompiler.h>
-#include <liblangutil/SourceReferenceFormatter.h>
+
#include <libsolidity/ast/ASTJsonConverter.h>
+#include <liblangutil/SourceReferenceFormatter.h>
#include <libevmasm/Instruction.h>
#include <libdevcore/JSON.h>
#include <libdevcore/Keccak256.h>
+#include <boost/algorithm/cxx11/any_of.hpp>
#include <boost/algorithm/string.hpp>
+#include <boost/optional.hpp>
+#include <algorithm>
using namespace std;
using namespace dev;
@@ -69,12 +73,11 @@ Json::Value formatErrorWithException(
bool const& _warning,
string const& _type,
string const& _component,
- string const& _message,
- function<Scanner const&(string const&)> const& _scannerFromSourceName
+ string const& _message
)
{
string message;
- string formattedMessage = SourceReferenceFormatter::formatExceptionInformation(_exception, _type, _scannerFromSourceName);
+ string formattedMessage = SourceReferenceFormatter::formatExceptionInformation(_exception, _type);
// NOTE: the below is partially a copy from SourceReferenceFormatter
SourceLocation const* location = boost::get_error_info<errinfo_sourceLocation>(_exception);
@@ -189,6 +192,31 @@ bool isArtifactRequested(Json::Value const& _outputSelection, string const& _fil
return false;
}
+/// @returns true if any binary was requested, i.e. we actually have to perform compilation.
+bool isBinaryRequested(Json::Value const& _outputSelection)
+{
+ if (!_outputSelection.isObject())
+ return false;
+
+ // This does not inculde "evm.methodIdentifiers" on purpose!
+ static vector<string> const outputsThatRequireBinaries{
+ "*",
+ "metadata", // This is only generated at the end of compilation, but could be generated earlier.
+ "evm.deployedBytecode", "evm.deployedBytecode.object", "evm.deployedBytecode.opcodes",
+ "evm.deployedBytecode.sourceMap", "evm.deployedBytecode.linkReferences",
+ "evm.bytecode", "evm.bytecode.object", "evm.bytecode.opcodes", "evm.bytecode.sourceMap",
+ "evm.bytecode.linkReferences",
+ "evm.gasEstimates", "evm.legacyAssembly", "evm.assembly"
+ };
+
+ for (auto const& fileRequests: _outputSelection)
+ for (auto const& requests: fileRequests)
+ for (auto const& output: outputsThatRequireBinaries)
+ if (isArtifactRequested(requests, output))
+ return true;
+ return false;
+}
+
Json::Value formatLinkReferences(std::map<size_t, std::string> const& linkReferences)
{
Json::Value ret(Json::objectValue);
@@ -226,6 +254,99 @@ Json::Value collectEVMObject(eth::LinkerObject const& _object, string const* _so
return output;
}
+boost::optional<Json::Value> checkKeys(Json::Value const& _input, set<string> const& _keys, string const& _name)
+{
+ if (!!_input && !_input.isObject())
+ return formatFatalError("JSONError", "\"" + _name + "\" must be an object");
+
+ for (auto const& member: _input.getMemberNames())
+ if (!_keys.count(member))
+ return formatFatalError("JSONError", "Unknown key \"" + member + "\"");
+
+ return boost::none;
+}
+
+boost::optional<Json::Value> checkRootKeys(Json::Value const& _input)
+{
+ static set<string> keys{"auxiliaryInput", "language", "settings", "sources"};
+ return checkKeys(_input, keys, "root");
+}
+
+boost::optional<Json::Value> checkSourceKeys(Json::Value const& _input, string const& _name)
+{
+ static set<string> keys{"content", "keccak256", "urls"};
+ return checkKeys(_input, keys, "sources." + _name);
+}
+
+boost::optional<Json::Value> checkAuxiliaryInputKeys(Json::Value const& _input)
+{
+ static set<string> keys{"smtlib2responses"};
+ return checkKeys(_input, keys, "auxiliaryInput");
+}
+
+boost::optional<Json::Value> checkSettingsKeys(Json::Value const& _input)
+{
+ static set<string> keys{"evmVersion", "libraries", "metadata", "optimizer", "outputSelection", "remappings"};
+ return checkKeys(_input, keys, "settings");
+}
+
+boost::optional<Json::Value> checkOptimizerKeys(Json::Value const& _input)
+{
+ static set<string> keys{"enabled", "runs"};
+ return checkKeys(_input, keys, "settings.optimizer");
+}
+
+boost::optional<Json::Value> checkMetadataKeys(Json::Value const& _input)
+{
+ static set<string> keys{"useLiteralContent"};
+ return checkKeys(_input, keys, "settings.metadata");
+}
+
+boost::optional<Json::Value> checkOutputSelection(Json::Value const& _outputSelection)
+{
+ if (!!_outputSelection && !_outputSelection.isObject())
+ return formatFatalError("JSONError", "\"settings.outputSelection\" must be an object");
+
+ for (auto const& sourceName: _outputSelection.getMemberNames())
+ {
+ auto const& sourceVal = _outputSelection[sourceName];
+
+ if (!sourceVal.isObject())
+ return formatFatalError(
+ "JSONError",
+ "\"settings.outputSelection." + sourceName + "\" must be an object"
+ );
+
+ for (auto const& contractName: sourceVal.getMemberNames())
+ {
+ auto const& contractVal = sourceVal[contractName];
+
+ if (!contractVal.isArray())
+ return formatFatalError(
+ "JSONError",
+ "\"settings.outputSelection." +
+ sourceName +
+ "." +
+ contractName +
+ "\" must be a string array"
+ );
+
+ for (auto const& output: contractVal)
+ if (!output.isString())
+ return formatFatalError(
+ "JSONError",
+ "\"settings.outputSelection." +
+ sourceName +
+ "." +
+ contractName +
+ "\" must be a string array"
+ );
+ }
+ }
+
+ return boost::none;
+}
+
}
Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
@@ -235,6 +356,9 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
if (!_input.isObject())
return formatFatalError("JSONError", "Input is not a JSON object.");
+ if (auto result = checkRootKeys(_input))
+ return *result;
+
if (_input["language"] != "Solidity")
return formatFatalError("JSONError", "Only \"Solidity\" is supported as a language.");
@@ -252,8 +376,8 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
{
string hash;
- if (!sources[sourceName].isObject())
- return formatFatalError("JSONError", "Source input is not a JSON object.");
+ if (auto result = checkSourceKeys(sources[sourceName], sourceName))
+ return *result;
if (sources[sourceName]["keccak256"].isString())
hash = sources[sourceName]["keccak256"].asString();
@@ -320,10 +444,18 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
}
Json::Value const& auxInputs = _input["auxiliaryInput"];
+
+ if (auto result = checkAuxiliaryInputKeys(auxInputs))
+ return *result;
+
if (!!auxInputs)
{
Json::Value const& smtlib2Responses = auxInputs["smtlib2responses"];
if (!!smtlib2Responses)
+ {
+ if (!smtlib2Responses.isObject())
+ return formatFatalError("JSONError", "\"auxiliaryInput.smtlib2responses\" must be an object.");
+
for (auto const& hashString: smtlib2Responses.getMemberNames())
{
h256 hash;
@@ -336,12 +468,22 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
return formatFatalError("JSONError", "Invalid hex encoding of SMTLib2 auxiliary input.");
}
+ if (!smtlib2Responses[hashString].isString())
+ return formatFatalError(
+ "JSONError",
+ "\"smtlib2Responses." + hashString + "\" must be a string."
+ );
+
m_compilerStack.addSMTLib2Response(hash, smtlib2Responses[hashString].asString());
}
+ }
}
Json::Value const& settings = _input.get("settings", Json::Value());
+ if (auto result = checkSettingsKeys(settings))
+ return *result;
+
if (settings.isMember("evmVersion"))
{
if (!settings["evmVersion"].isString())
@@ -352,11 +494,14 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
m_compilerStack.setEVMVersion(*version);
}
+ if (settings.isMember("remappings") && !settings["remappings"].isArray())
+ return formatFatalError("JSONError", "\"settings.remappings\" must be an array of strings.");
+
vector<CompilerStack::Remapping> remappings;
for (auto const& remapping: settings.get("remappings", Json::Value()))
{
if (!remapping.isString())
- return formatFatalError("JSONError", "Remapping entry must be a string.");
+ return formatFatalError("JSONError", "\"settings.remappings\" must be an array of strings");
if (auto r = CompilerStack::parseRemapping(remapping.asString()))
remappings.emplace_back(std::move(*r));
else
@@ -367,6 +512,10 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
if (settings.isMember("optimizer"))
{
Json::Value optimizerSettings = settings["optimizer"];
+
+ if (auto result = checkOptimizerKeys(optimizerSettings))
+ return *result;
+
if (optimizerSettings.isMember("enabled"))
{
if (!optimizerSettings["enabled"].isBool())
@@ -428,16 +577,27 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
m_compilerStack.setLibraries(libraries);
Json::Value metadataSettings = settings.get("metadata", Json::Value());
+
+ if (auto result = checkMetadataKeys(metadataSettings))
+ return *result;
+
m_compilerStack.useMetadataLiteralSources(metadataSettings.get("useLiteralContent", Json::Value(false)).asBool());
Json::Value outputSelection = settings.get("outputSelection", Json::Value());
+
+ if (auto jsonError = checkOutputSelection(outputSelection))
+ return *jsonError;
+
m_compilerStack.setRequestedContractNames(requestedContractNames(outputSelection));
- auto scannerFromSourceName = [&](string const& _sourceName) -> Scanner const& { return m_compilerStack.scanner(_sourceName); };
+ bool const binariesRequested = isBinaryRequested(outputSelection);
try
{
- m_compilerStack.compile();
+ if (binariesRequested)
+ m_compilerStack.compile();
+ else
+ m_compilerStack.parseAndAnalyze();
for (auto const& error: m_compilerStack.errors())
{
@@ -448,8 +608,7 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
err.type() == Error::Type::Warning,
err.typeName(),
"general",
- "",
- scannerFromSourceName
+ ""
));
}
}
@@ -461,8 +620,7 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
false,
_error.typeName(),
"general",
- "Uncaught error: ",
- scannerFromSourceName
+ "Uncaught error: "
));
}
/// This should not be leaked from compile().
@@ -482,8 +640,7 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
false,
"CompilerError",
"general",
- "Compiler error (" + _exception.lineInfo() + ")",
- scannerFromSourceName
+ "Compiler error (" + _exception.lineInfo() + ")"
));
}
catch (InternalCompilerError const& _exception)
@@ -493,8 +650,7 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
false,
"InternalCompilerError",
"general",
- "Internal compiler error (" + _exception.lineInfo() + ")",
- scannerFromSourceName
+ "Internal compiler error (" + _exception.lineInfo() + ")"
));
}
catch (UnimplementedFeatureError const& _exception)
@@ -504,8 +660,7 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
false,
"UnimplementedFeatureError",
"general",
- "Unimplemented feature (" + _exception.lineInfo() + ")",
- scannerFromSourceName
+ "Unimplemented feature (" + _exception.lineInfo() + ")"
));
}
catch (Exception const& _exception)
@@ -531,7 +686,7 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
bool const compilationSuccess = m_compilerStack.state() == CompilerStack::State::CompilationSuccessful;
/// Inconsistent state - stop here to receive error reports from users
- if (!compilationSuccess && errors.empty())
+ if (((binariesRequested && !compilationSuccess) || !analysisSuccess) && errors.empty())
return formatFatalError("InternalCompilerError", "No error reported, but compilation failed.");
Json::Value output = Json::objectValue;
@@ -557,7 +712,7 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
}
Json::Value contractsOutput = Json::objectValue;
- for (string const& contractName: compilationSuccess ? m_compilerStack.contractNames() : vector<string>())
+ for (string const& contractName: analysisSuccess ? m_compilerStack.contractNames() : vector<string>())
{
size_t colon = contractName.rfind(':');
solAssert(colon != string::npos, "");
@@ -568,7 +723,7 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
Json::Value contractData(Json::objectValue);
if (isArtifactRequested(outputSelection, file, name, "abi"))
contractData["abi"] = m_compilerStack.contractABI(contractName);
- if (isArtifactRequested(outputSelection, file, name, "metadata"))
+ if (compilationSuccess && isArtifactRequested(outputSelection, file, name, "metadata"))
contractData["metadata"] = m_compilerStack.metadata(contractName);
if (isArtifactRequested(outputSelection, file, name, "userdoc"))
contractData["userdoc"] = m_compilerStack.natspecUser(contractName);
@@ -578,16 +733,16 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
// EVM
Json::Value evmData(Json::objectValue);
// @TODO: add ir
- if (isArtifactRequested(outputSelection, file, name, "evm.assembly"))
+ if (compilationSuccess && isArtifactRequested(outputSelection, file, name, "evm.assembly"))
evmData["assembly"] = m_compilerStack.assemblyString(contractName, createSourceList(_input));
- if (isArtifactRequested(outputSelection, file, name, "evm.legacyAssembly"))
+ if (compilationSuccess && isArtifactRequested(outputSelection, file, name, "evm.legacyAssembly"))
evmData["legacyAssembly"] = m_compilerStack.assemblyJSON(contractName, createSourceList(_input));
if (isArtifactRequested(outputSelection, file, name, "evm.methodIdentifiers"))
evmData["methodIdentifiers"] = m_compilerStack.methodIdentifiers(contractName);
- if (isArtifactRequested(outputSelection, file, name, "evm.gasEstimates"))
+ if (compilationSuccess && isArtifactRequested(outputSelection, file, name, "evm.gasEstimates"))
evmData["gasEstimates"] = m_compilerStack.gasEstimates(contractName);
- if (isArtifactRequested(
+ if (compilationSuccess && isArtifactRequested(
outputSelection,
file,
name,
@@ -598,7 +753,7 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
m_compilerStack.sourceMapping(contractName)
);
- if (isArtifactRequested(
+ if (compilationSuccess && isArtifactRequested(
outputSelection,
file,
name,
@@ -609,14 +764,18 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input)
m_compilerStack.runtimeSourceMapping(contractName)
);
- contractData["evm"] = evmData;
-
- if (!contractsOutput.isMember(file))
- contractsOutput[file] = Json::objectValue;
+ if (!evmData.empty())
+ contractData["evm"] = evmData;
- contractsOutput[file][name] = contractData;
+ if (!contractData.empty())
+ {
+ if (!contractsOutput.isMember(file))
+ contractsOutput[file] = Json::objectValue;
+ contractsOutput[file][name] = contractData;
+ }
}
- output["contracts"] = contractsOutput;
+ if (!contractsOutput.empty())
+ output["contracts"] = contractsOutput;
return output;
}
diff --git a/libsolidity/interface/Version.cpp b/libsolidity/interface/Version.cpp
index b785d557..efd46d40 100644
--- a/libsolidity/interface/Version.cpp
+++ b/libsolidity/interface/Version.cpp
@@ -21,11 +21,12 @@
*/
#include <libsolidity/interface/Version.h>
-#include <string>
+
+#include <liblangutil/Exceptions.h>
#include <libdevcore/CommonData.h>
#include <libdevcore/Common.h>
-#include <liblangutil/Exceptions.h>
#include <solidity/BuildInfo.h>
+#include <string>
using namespace dev;
using namespace dev::solidity;
diff --git a/libsolidity/interface/Version.h b/libsolidity/interface/Version.h
index 24c3555d..38d63ec6 100644
--- a/libsolidity/interface/Version.h
+++ b/libsolidity/interface/Version.h
@@ -22,8 +22,8 @@
#pragma once
-#include <string>
#include <libdevcore/Common.h>
+#include <string>
namespace dev
{