From d37e6ba1c7ade678644b5669b120bd76b72f39ea Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Thu, 30 Mar 2017 11:16:28 +0100 Subject: Add target selection helpers to StandardCompiler --- libsolidity/interface/StandardCompiler.cpp | 56 ++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 430739ac..9aec7abb 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -131,6 +131,62 @@ StringMap createSourceList(Json::Value const& _input) return sources; } +bool isTargetRequired(Json::Value const& _targets, string const& _target) +{ + for (auto const& target: _targets) + /// @TODO support sub-matching, e.g "evm" matches "evm.assembly" + if (target == "*" || target == _target) + return true; + return false; +} + +/// +/// @a _targets 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 target names to be requested for that contract. +/// @a _file is the current file +/// @a _contract is the current contract +/// @a _target is the current target name +/// +/// @returns true if the @a _targets has a match for the requested target in the specific file / contract. +/// +/// In @a _targets the use of '*' as a wildcard is permitted. +/// +/// @TODO optimise this. Perhaps flatten the structure upfront. +/// +bool isTargetRequired(Json::Value const& _targets, string const& _file, string const& _contract, string const& _target) +{ + if (!_targets.isObject()) + return false; + + for (auto const& file: { _file, string("*") }) + if (_targets.isMember(file) && _targets[file].isObject()) + { + if (_contract.empty()) + { + /// Special case for SourceUnit-level targets (such as AST) + if ( + _targets[file].isMember("") && + _targets[file][""].isArray() && + isTargetRequired(_targets[file][""], _target) + ) + return true; + } + else + { + /// Regular case for Contract-level targets + for (auto const& contract: { _contract, string("*") }) + if ( + _targets[file].isMember(contract) && + _targets[file][contract].isArray() && + isTargetRequired(_targets[file][contract], _target) + ) + return true; + } + } + + return false; +} + Json::Value formatLinkReferences(std::map const& linkReferences) { Json::Value ret(Json::objectValue); -- cgit From 8da245cca3228be3e8d7908f184a327dcaf16b29 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Wed, 12 Apr 2017 10:37:04 +0100 Subject: Limit output according to the selected targets in StandardCompiler --- Changelog.md | 1 + libsolidity/interface/StandardCompiler.cpp | 52 ++++++++++++++++++------------ 2 files changed, 33 insertions(+), 20 deletions(-) diff --git a/Changelog.md b/Changelog.md index f69a39ce..8f610a53 100644 --- a/Changelog.md +++ b/Changelog.md @@ -4,6 +4,7 @@ Features: * Allow constant variables to be used as array length * Code Generator: New ABI decoder which supports structs and arbitrarily nested arrays and checks input size (activate using ``pragma experimental ABIEncoderV2;``. + * Standard JSON: Support the ``outputSelection`` field for selective compilation of target artifacts. * Syntax Checker: Turn the usage of ``callcode`` into an error as experimental 0.5.0 feature. * Type Checker: Improve address checksum warning. * Type Checker: More detailed errors for invalid array lengths (such as division by zero). diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 9aec7abb..8a4e81e4 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -452,8 +452,10 @@ 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 (isTargetRequired(outputSelection, sourceName, "", "ast")) + sourceResult["ast"] = ASTJsonConverter(false, m_compilerStack.sourceIndices()).toJson(m_compilerStack.ast(sourceName)); + if (isTargetRequired(outputSelection, sourceName, "", "legacyAST")) + sourceResult["legacyAST"] = ASTJsonConverter(true, m_compilerStack.sourceIndices()).toJson(m_compilerStack.ast(sourceName)); output["sources"][sourceName] = sourceResult; } @@ -467,28 +469,38 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) // 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 (isTargetRequired(outputSelection, file, name, "abi")) + contractData["abi"] = m_compilerStack.contractABI(contractName); + if (isTargetRequired(outputSelection, file, name, "metadata")) + contractData["metadata"] = m_compilerStack.metadata(contractName); + if (isTargetRequired(outputSelection, file, name, "userdoc")) + contractData["userdoc"] = m_compilerStack.natspecUser(contractName); + if (isTargetRequired(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 (isTargetRequired(outputSelection, file, name, "evm.assembly")) + evmData["assembly"] = m_compilerStack.assemblyString(contractName, createSourceList(_input)); + if (isTargetRequired(outputSelection, file, name, "evm.legacyAssembly")) + evmData["legacyAssembly"] = m_compilerStack.assemblyJSON(contractName, createSourceList(_input)); + if (isTargetRequired(outputSelection, file, name, "evm.methodIdentifiers")) + evmData["methodIdentifiers"] = m_compilerStack.methodIdentifiers(contractName); + if (isTargetRequired(outputSelection, file, name, "evm.gasEstimates")) + evmData["gasEstimates"] = m_compilerStack.gasEstimates(contractName); + + if (isTargetRequired(outputSelection, file, name, "evm.bytecode")) + evmData["bytecode"] = collectEVMObject( + m_compilerStack.object(contractName), + m_compilerStack.sourceMapping(contractName) + ); + + if (isTargetRequired(outputSelection, file, name, "evm.deployedBytecode")) + evmData["deployedBytecode"] = collectEVMObject( + m_compilerStack.runtimeObject(contractName), + m_compilerStack.runtimeSourceMapping(contractName) + ); contractData["evm"] = evmData; -- cgit From 73d25c883fddaa961a8276f1e892f935c3f6b2db Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Thu, 20 Apr 2017 23:34:12 +0100 Subject: Specify output selection in tests --- test/libsolidity/StandardCompiler.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/libsolidity/StandardCompiler.cpp b/test/libsolidity/StandardCompiler.cpp index 4504946b..091207e8 100644 --- a/test/libsolidity/StandardCompiler.cpp +++ b/test/libsolidity/StandardCompiler.cpp @@ -179,6 +179,14 @@ BOOST_AUTO_TEST_CASE(basic_compilation) "fileA": { "content": "contract A { }" } + }, + "settings": { + "outputSelection": { + "fileA": { + "A": [ "abi", "devdoc", "userdoc", "evm.bytecode", "evm.assembly", "evm.gasEstimates", "metadata" ], + "": [ "legacyAST" ] + } + } } } )"; -- cgit From 123d85a19e7f20f06d07fd9a0e4201a3d38ce252 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Thu, 10 Aug 2017 21:34:21 +0100 Subject: Request all outputs in JSONCompiler --- solc/jsonCompiler.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/solc/jsonCompiler.cpp b/solc/jsonCompiler.cpp index 7e797a62..23feaa2a 100644 --- a/solc/jsonCompiler.cpp +++ b/solc/jsonCompiler.cpp @@ -128,6 +128,11 @@ string compile(StringMap const& _sources, bool _optimize, CStyleReadFileCallback input["settings"]["optimizer"]["enabled"] = _optimize; input["settings"]["optimizer"]["runs"] = 200; + // Enable all SourceUnit-level outputs. + input["settings"]["outputSelection"]["*"][""][0] = "*"; + // Enable all Contract-level outputs. + input["settings"]["outputSelection"]["*"]["*"][0] = "*"; + StandardCompiler compiler(wrapReadCallback(_readCallback)); Json::Value ret = compiler.compile(input); -- cgit From bbcec95bac84314d947814ace7da85f69168df94 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Thu, 19 Oct 2017 14:09:40 +0100 Subject: Add workaround for bytecode/deployedBytecode selection --- libsolidity/interface/StandardCompiler.cpp | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 8a4e81e4..d9ad0759 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -187,6 +187,14 @@ bool isTargetRequired(Json::Value const& _targets, string const& _file, string c return false; } +bool isTargetRequired(Json::Value const& _targets, string const& _file, string const& _contract, vector const& _requested) +{ + for (auto const& requested: _requested) + if (isTargetRequired(_targets, _file, _contract, requested)) + return true; + return false; +} + Json::Value formatLinkReferences(std::map const& linkReferences) { Json::Value ret(Json::objectValue); @@ -490,13 +498,23 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) if (isTargetRequired(outputSelection, file, name, "evm.gasEstimates")) evmData["gasEstimates"] = m_compilerStack.gasEstimates(contractName); - if (isTargetRequired(outputSelection, file, name, "evm.bytecode")) + if (isTargetRequired( + 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 (isTargetRequired(outputSelection, file, name, "evm.deployedBytecode")) + if (isTargetRequired( + 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) -- cgit From 59bed63dbcad9c813f621ec1f49eb9207286fd33 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Thu, 19 Oct 2017 14:24:33 +0100 Subject: Update standard json documentation --- docs/using-the-compiler.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/using-the-compiler.rst b/docs/using-the-compiler.rst index 7f82df70..c12750c8 100644 --- a/docs/using-the-compiler.rst +++ b/docs/using-the-compiler.rst @@ -138,7 +138,7 @@ Input Description // ewasm.wasm - eWASM binary format (not supported atm) // // Note that using a using `evm`, `evm.bytecode`, `ewasm`, etc. will select every - // target part of that output. + // target part of that output. Additionally, `*` can be used as a wildcard to request everything. // outputSelection: { // Enable the metadata and bytecode outputs of every single contract. -- cgit From b2023196a295a0e41bdc5c2b848b5c09fc581691 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Wed, 22 Nov 2017 12:55:44 +0000 Subject: Rename target selection to use the word artifact --- libsolidity/interface/StandardCompiler.cpp | 64 +++++++++++++++--------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index d9ad0759..6fb70584 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -131,43 +131,43 @@ StringMap createSourceList(Json::Value const& _input) return sources; } -bool isTargetRequired(Json::Value const& _targets, string const& _target) +bool isArtifactRequested(Json::Value const& _outputSelection, string const& _artifact) { - for (auto const& target: _targets) + for (auto const& artifact: _outputSelection) /// @TODO support sub-matching, e.g "evm" matches "evm.assembly" - if (target == "*" || target == _target) + if (artifact == "*" || artifact == _artifact) return true; return false; } /// -/// @a _targets 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 target names to be requested for that contract. +/// @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 _target is the current target name +/// @a _artifact is the current artifact name /// -/// @returns true if the @a _targets has a match for the requested target in the specific file / contract. +/// @returns true if the @a _outputSelection has a match for the requested target in the specific file / contract. /// -/// In @a _targets the use of '*' as a wildcard is permitted. +/// In @a _outputSelection the use of '*' as a wildcard is permitted. /// /// @TODO optimise this. Perhaps flatten the structure upfront. /// -bool isTargetRequired(Json::Value const& _targets, string const& _file, string const& _contract, string const& _target) +bool isArtifactRequested(Json::Value const& _outputSelection, string const& _file, string const& _contract, string const& _artifact) { - if (!_targets.isObject()) + if (!_outputSelection.isObject()) return false; for (auto const& file: { _file, string("*") }) - if (_targets.isMember(file) && _targets[file].isObject()) + if (_outputSelection.isMember(file) && _outputSelection[file].isObject()) { if (_contract.empty()) { /// Special case for SourceUnit-level targets (such as AST) if ( - _targets[file].isMember("") && - _targets[file][""].isArray() && - isTargetRequired(_targets[file][""], _target) + _outputSelection[file].isMember("") && + _outputSelection[file][""].isArray() && + isArtifactRequested(_outputSelection[file][""], _artifact) ) return true; } @@ -176,9 +176,9 @@ bool isTargetRequired(Json::Value const& _targets, string const& _file, string c /// Regular case for Contract-level targets for (auto const& contract: { _contract, string("*") }) if ( - _targets[file].isMember(contract) && - _targets[file][contract].isArray() && - isTargetRequired(_targets[file][contract], _target) + _outputSelection[file].isMember(contract) && + _outputSelection[file][contract].isArray() && + isArtifactRequested(_outputSelection[file][contract], _artifact) ) return true; } @@ -187,10 +187,10 @@ bool isTargetRequired(Json::Value const& _targets, string const& _file, string c return false; } -bool isTargetRequired(Json::Value const& _targets, string const& _file, string const& _contract, vector const& _requested) +bool isArtifactRequested(Json::Value const& _outputSelection, string const& _file, string const& _contract, vector const& _artifacts) { - for (auto const& requested: _requested) - if (isTargetRequired(_targets, _file, _contract, requested)) + for (auto const& artifact: _artifacts) + if (isArtifactRequested(_outputSelection, _file, _contract, artifact)) return true; return false; } @@ -460,9 +460,9 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) { Json::Value sourceResult = Json::objectValue; sourceResult["id"] = sourceIndex++; - if (isTargetRequired(outputSelection, sourceName, "", "ast")) + if (isArtifactRequested(outputSelection, sourceName, "", "ast")) sourceResult["ast"] = ASTJsonConverter(false, m_compilerStack.sourceIndices()).toJson(m_compilerStack.ast(sourceName)); - if (isTargetRequired(outputSelection, sourceName, "", "legacyAST")) + if (isArtifactRequested(outputSelection, sourceName, "", "legacyAST")) sourceResult["legacyAST"] = ASTJsonConverter(true, m_compilerStack.sourceIndices()).toJson(m_compilerStack.ast(sourceName)); output["sources"][sourceName] = sourceResult; } @@ -477,28 +477,28 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) // ABI, documentation and metadata Json::Value contractData(Json::objectValue); - if (isTargetRequired(outputSelection, file, name, "abi")) + if (isArtifactRequested(outputSelection, file, name, "abi")) contractData["abi"] = m_compilerStack.contractABI(contractName); - if (isTargetRequired(outputSelection, file, name, "metadata")) + if (isArtifactRequested(outputSelection, file, name, "metadata")) contractData["metadata"] = m_compilerStack.metadata(contractName); - if (isTargetRequired(outputSelection, file, name, "userdoc")) + if (isArtifactRequested(outputSelection, file, name, "userdoc")) contractData["userdoc"] = m_compilerStack.natspecUser(contractName); - if (isTargetRequired(outputSelection, file, name, "devdoc")) + if (isArtifactRequested(outputSelection, file, name, "devdoc")) contractData["devdoc"] = m_compilerStack.natspecDev(contractName); // EVM Json::Value evmData(Json::objectValue); // @TODO: add ir - if (isTargetRequired(outputSelection, file, name, "evm.assembly")) + if (isArtifactRequested(outputSelection, file, name, "evm.assembly")) evmData["assembly"] = m_compilerStack.assemblyString(contractName, createSourceList(_input)); - if (isTargetRequired(outputSelection, file, name, "evm.legacyAssembly")) + if (isArtifactRequested(outputSelection, file, name, "evm.legacyAssembly")) evmData["legacyAssembly"] = m_compilerStack.assemblyJSON(contractName, createSourceList(_input)); - if (isTargetRequired(outputSelection, file, name, "evm.methodIdentifiers")) + if (isArtifactRequested(outputSelection, file, name, "evm.methodIdentifiers")) evmData["methodIdentifiers"] = m_compilerStack.methodIdentifiers(contractName); - if (isTargetRequired(outputSelection, file, name, "evm.gasEstimates")) + if (isArtifactRequested(outputSelection, file, name, "evm.gasEstimates")) evmData["gasEstimates"] = m_compilerStack.gasEstimates(contractName); - if (isTargetRequired( + if (isArtifactRequested( outputSelection, file, name, @@ -509,7 +509,7 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) m_compilerStack.sourceMapping(contractName) ); - if (isTargetRequired( + if (isArtifactRequested( outputSelection, file, name, -- cgit From 3576ccf5b36f41d36898919eee7316b9c7c49d41 Mon Sep 17 00:00:00 2001 From: Alex Beregszaszi Date: Wed, 22 Nov 2017 13:35:01 +0000 Subject: Simplify target selection code --- libsolidity/interface/StandardCompiler.cpp | 27 +++++++++------------------ 1 file changed, 9 insertions(+), 18 deletions(-) diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 6fb70584..ad01821e 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -161,27 +161,18 @@ bool isArtifactRequested(Json::Value const& _outputSelection, string const& _fil for (auto const& file: { _file, string("*") }) if (_outputSelection.isMember(file) && _outputSelection[file].isObject()) { - if (_contract.empty()) - { - /// Special case for SourceUnit-level targets (such as AST) + /// For SourceUnit-level targets (such as AST) only allow empty name, otherwise + /// for Contract-level targets try both contract name and wildcard + vector contracts{ _contract }; + if (!_contract.empty()) + contracts.push_back("*"); + for (auto const& contract: contracts) if ( - _outputSelection[file].isMember("") && - _outputSelection[file][""].isArray() && - isArtifactRequested(_outputSelection[file][""], _artifact) + _outputSelection[file].isMember(contract) && + _outputSelection[file][contract].isArray() && + isArtifactRequested(_outputSelection[file][contract], _artifact) ) return true; - } - else - { - /// Regular case for Contract-level targets - for (auto const& contract: { _contract, string("*") }) - if ( - _outputSelection[file].isMember(contract) && - _outputSelection[file][contract].isArray() && - isArtifactRequested(_outputSelection[file][contract], _artifact) - ) - return true; - } } return false; -- cgit