diff options
Diffstat (limited to 'libsolidity/interface')
-rw-r--r-- | libsolidity/interface/AssemblyStack.cpp | 23 | ||||
-rw-r--r-- | libsolidity/interface/AssemblyStack.h | 2 | ||||
-rw-r--r-- | libsolidity/interface/Exceptions.h | 12 | ||||
-rw-r--r-- | libsolidity/interface/StandardCompiler.cpp | 125 |
4 files changed, 135 insertions, 27 deletions
diff --git a/libsolidity/interface/AssemblyStack.cpp b/libsolidity/interface/AssemblyStack.cpp index 504ad92c..1b4bd270 100644 --- a/libsolidity/interface/AssemblyStack.cpp +++ b/libsolidity/interface/AssemblyStack.cpp @@ -38,6 +38,25 @@ using namespace std; using namespace dev; using namespace dev::solidity; +namespace +{ +assembly::AsmFlavour languageToAsmFlavour(AssemblyStack::Language _language) +{ + switch (_language) + { + case AssemblyStack::Language::Assembly: + return assembly::AsmFlavour::Loose; + case AssemblyStack::Language::StrictAssembly: + return assembly::AsmFlavour::Strict; + case AssemblyStack::Language::JULIA: + return assembly::AsmFlavour::IULIA; + } + solAssert(false, ""); + return assembly::AsmFlavour::IULIA; +} + +} + Scanner const& AssemblyStack::scanner() const { @@ -50,7 +69,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 = assembly::Parser(m_errorReporter, m_language == Language::JULIA).parse(m_scanner); + m_parserResult = assembly::Parser(m_errorReporter, languageToAsmFlavour(m_language)).parse(m_scanner); if (!m_errorReporter.errors().empty()) return false; solAssert(m_parserResult, ""); @@ -72,7 +91,7 @@ bool AssemblyStack::analyze(assembly::Block const& _block, Scanner const* _scann bool AssemblyStack::analyzeParsed() { m_analysisInfo = make_shared<assembly::AsmAnalysisInfo>(); - assembly::AsmAnalyzer analyzer(*m_analysisInfo, m_errorReporter, m_language == Language::JULIA); + assembly::AsmAnalyzer analyzer(*m_analysisInfo, m_errorReporter, languageToAsmFlavour(m_language)); m_analysisSuccessful = analyzer.analyze(*m_parserResult); return m_analysisSuccessful; } diff --git a/libsolidity/interface/AssemblyStack.h b/libsolidity/interface/AssemblyStack.h index 2ae596ed..6ae7e8d1 100644 --- a/libsolidity/interface/AssemblyStack.h +++ b/libsolidity/interface/AssemblyStack.h @@ -51,7 +51,7 @@ struct MachineAssemblyObject class AssemblyStack { public: - enum class Language { JULIA, Assembly }; + enum class Language { JULIA, Assembly, StrictAssembly }; enum class Machine { EVM, EVM15, eWasm }; explicit AssemblyStack(Language _language = Language::Assembly): diff --git a/libsolidity/interface/Exceptions.h b/libsolidity/interface/Exceptions.h index 09301b10..7c66d572 100644 --- a/libsolidity/interface/Exceptions.h +++ b/libsolidity/interface/Exceptions.h @@ -109,6 +109,18 @@ public: 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 " + boost::lexical_cast<std::string>(occurrences) + " to the first 32 occurrences."; + } + } + std::vector<errorSourceLocationInfo> infos; }; diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 430739ac..04f5bd25 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -81,15 +81,15 @@ Json::Value formatErrorWithException( else message = _message; + Json::Value sourceLocation; if (location && location->sourceName) { - Json::Value sourceLocation = Json::objectValue; sourceLocation["file"] = *location->sourceName; sourceLocation["start"] = location->start; sourceLocation["end"] = location->end; } - return formatError(_warning, _type, _component, message, formattedMessage, location); + return formatError(_warning, _type, _component, message, formattedMessage, sourceLocation); } set<string> requestedContractNames(Json::Value const& _outputSelection) @@ -131,6 +131,61 @@ StringMap createSourceList(Json::Value const& _input) return sources; } +bool isArtifactRequested(Json::Value const& _outputSelection, string const& _artifact) +{ + for (auto const& artifact: _outputSelection) + /// @TODO support sub-matching, e.g "evm" matches "evm.assembly" + if (artifact == "*" || artifact == _artifact) + return true; + return false; +} + +/// +/// @a _outputSelection is a JSON object containining a two-level hashmap, where the first level is the filename, +/// the second level is the contract name and the value is an array of artifact names to be requested for that contract. +/// @a _file is the current file +/// @a _contract is the current contract +/// @a _artifact is the current artifact name +/// +/// @returns true if the @a _outputSelection has a match for the requested target in the specific file / contract. +/// +/// In @a _outputSelection the use of '*' as a wildcard is permitted. +/// +/// @TODO optimise this. Perhaps flatten the structure upfront. +/// +bool isArtifactRequested(Json::Value const& _outputSelection, string const& _file, string const& _contract, string const& _artifact) +{ + if (!_outputSelection.isObject()) + return false; + + for (auto const& file: { _file, string("*") }) + if (_outputSelection.isMember(file) && _outputSelection[file].isObject()) + { + /// For SourceUnit-level targets (such as AST) only allow empty name, otherwise + /// for Contract-level targets try both contract name and wildcard + vector<string> contracts{ _contract }; + if (!_contract.empty()) + contracts.push_back("*"); + for (auto const& contract: contracts) + if ( + _outputSelection[file].isMember(contract) && + _outputSelection[file][contract].isArray() && + isArtifactRequested(_outputSelection[file][contract], _artifact) + ) + return true; + } + + return false; +} + +bool isArtifactRequested(Json::Value const& _outputSelection, string const& _file, string const& _contract, vector<string> const& _artifacts) +{ + for (auto const& artifact: _artifacts) + if (isArtifactRequested(_outputSelection, _file, _contract, artifact)) + return true; + return false; +} + Json::Value formatLinkReferences(std::map<size_t, std::string> const& linkReferences) { Json::Value ret(Json::objectValue); @@ -138,7 +193,7 @@ Json::Value formatLinkReferences(std::map<size_t, std::string> const& linkRefere for (auto const& ref: linkReferences) { string const& fullname = ref.second; - size_t colon = fullname.find(':'); + size_t colon = fullname.rfind(':'); solAssert(colon != string::npos, ""); string file = fullname.substr(0, colon); string name = fullname.substr(colon + 1); @@ -396,43 +451,65 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) { Json::Value sourceResult = Json::objectValue; sourceResult["id"] = sourceIndex++; - sourceResult["ast"] = ASTJsonConverter(false, m_compilerStack.sourceIndices()).toJson(m_compilerStack.ast(sourceName)); - sourceResult["legacyAST"] = ASTJsonConverter(true, m_compilerStack.sourceIndices()).toJson(m_compilerStack.ast(sourceName)); + if (isArtifactRequested(outputSelection, sourceName, "", "ast")) + sourceResult["ast"] = ASTJsonConverter(false, m_compilerStack.sourceIndices()).toJson(m_compilerStack.ast(sourceName)); + if (isArtifactRequested(outputSelection, sourceName, "", "legacyAST")) + sourceResult["legacyAST"] = ASTJsonConverter(true, m_compilerStack.sourceIndices()).toJson(m_compilerStack.ast(sourceName)); output["sources"][sourceName] = sourceResult; } Json::Value contractsOutput = Json::objectValue; for (string const& contractName: compilationSuccess ? m_compilerStack.contractNames() : vector<string>()) { - size_t colon = contractName.find(':'); + size_t colon = contractName.rfind(':'); solAssert(colon != string::npos, ""); string file = contractName.substr(0, colon); string name = contractName.substr(colon + 1); // ABI, documentation and metadata Json::Value contractData(Json::objectValue); - contractData["abi"] = m_compilerStack.contractABI(contractName); - contractData["metadata"] = m_compilerStack.metadata(contractName); - contractData["userdoc"] = m_compilerStack.natspecUser(contractName); - contractData["devdoc"] = m_compilerStack.natspecDev(contractName); + if (isArtifactRequested(outputSelection, file, name, "abi")) + contractData["abi"] = m_compilerStack.contractABI(contractName); + if (isArtifactRequested(outputSelection, file, name, "metadata")) + contractData["metadata"] = m_compilerStack.metadata(contractName); + if (isArtifactRequested(outputSelection, file, name, "userdoc")) + contractData["userdoc"] = m_compilerStack.natspecUser(contractName); + if (isArtifactRequested(outputSelection, file, name, "devdoc")) + contractData["devdoc"] = m_compilerStack.natspecDev(contractName); // EVM Json::Value evmData(Json::objectValue); // @TODO: add ir - evmData["assembly"] = m_compilerStack.assemblyString(contractName, createSourceList(_input)); - evmData["legacyAssembly"] = m_compilerStack.assemblyJSON(contractName, createSourceList(_input)); - evmData["methodIdentifiers"] = m_compilerStack.methodIdentifiers(contractName); - evmData["gasEstimates"] = m_compilerStack.gasEstimates(contractName); - - evmData["bytecode"] = collectEVMObject( - m_compilerStack.object(contractName), - m_compilerStack.sourceMapping(contractName) - ); - - evmData["deployedBytecode"] = collectEVMObject( - m_compilerStack.runtimeObject(contractName), - m_compilerStack.runtimeSourceMapping(contractName) - ); + if (isArtifactRequested(outputSelection, file, name, "evm.assembly")) + evmData["assembly"] = m_compilerStack.assemblyString(contractName, createSourceList(_input)); + if (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")) + evmData["gasEstimates"] = m_compilerStack.gasEstimates(contractName); + + if (isArtifactRequested( + outputSelection, + file, + name, + { "evm.bytecode", "evm.bytecode.object", "evm.bytecode.opcodes", "evm.bytecode.sourceMap", "evm.bytecode.linkReferences" } + )) + evmData["bytecode"] = collectEVMObject( + m_compilerStack.object(contractName), + m_compilerStack.sourceMapping(contractName) + ); + + if (isArtifactRequested( + outputSelection, + file, + name, + { "evm.deployedBytecode", "evm.deployedBytecode.object", "evm.deployedBytecode.opcodes", "evm.deployedBytecode.sourceMap", "evm.deployedBytecode.linkReferences" } + )) + evmData["deployedBytecode"] = collectEVMObject( + m_compilerStack.runtimeObject(contractName), + m_compilerStack.runtimeSourceMapping(contractName) + ); contractData["evm"] = evmData; |