diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index 182015709..2d8720371 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -27,6 +27,7 @@ #include #include +#include #include "BuildInfo.h" #include @@ -50,6 +51,7 @@ namespace dev namespace solidity { + // LTODO: Maybe some argument class pairing names with // extensions and other attributes would be a better choice here? static string const g_argAbiStr = "json-abi"; @@ -64,6 +66,18 @@ static string const g_argNatspecDevStr = "natspec-dev"; static string const g_argNatspecUserStr = "natspec-user"; static string const g_argAddStandard = "add-std"; +/// Possible arguments to for --combined-json +static set const g_combinedJsonArgs{ + "binary", + "opcodes", + "json-abi", + "sol-abi", + "asm", + "ast", + "natspec-user", + "natspec-dev" +}; + static void version() { cout << "solc, the solidity compiler commandline interface " << dev::Version << endl @@ -72,24 +86,24 @@ static void version() exit(0); } -static inline bool argToStdout(po::variables_map const& _args, string const& _name) +static inline bool humanTargetedStdout(po::variables_map const& _args, string const& _name) { return _args.count(_name) && _args[_name].as() != OutputType::FILE; } -static bool needStdout(po::variables_map const& _args) +static bool needsHumanTargetedStdout(po::variables_map const& _args) { return - argToStdout(_args, g_argAbiStr) || - argToStdout(_args, g_argSolAbiStr) || - argToStdout(_args, g_argNatspecUserStr) || - argToStdout(_args, g_argAstJson) || - argToStdout(_args, g_argNatspecDevStr) || - argToStdout(_args, g_argAsmStr) || - argToStdout(_args, g_argAsmJsonStr) || - argToStdout(_args, g_argOpcodesStr) || - argToStdout(_args, g_argBinaryStr); + humanTargetedStdout(_args, g_argAbiStr) || + humanTargetedStdout(_args, g_argSolAbiStr) || + humanTargetedStdout(_args, g_argNatspecUserStr) || + humanTargetedStdout(_args, g_argAstJson) || + humanTargetedStdout(_args, g_argNatspecDevStr) || + humanTargetedStdout(_args, g_argAsmStr) || + humanTargetedStdout(_args, g_argAsmJsonStr) || + humanTargetedStdout(_args, g_argOpcodesStr) || + humanTargetedStdout(_args, g_argBinaryStr); } static inline bool outputToFile(OutputType type) @@ -220,6 +234,11 @@ bool CommandLineInterface::parseArguments(int argc, char** argv) ("optimize", po::value()->default_value(false), "Optimize bytecode for size") ("add-std", po::value()->default_value(false), "Add standard contracts") ("input-file", po::value>(), "input file") + ( + "combined-json", + po::value()->value_name(boost::join(g_combinedJsonArgs, ",")), + "Output a single json document containing the specified information, can be combined." + ) (g_argAstStr.c_str(), po::value()->value_name("stdout|file|both"), "Request to output the AST of the contract.") (g_argAstJson.c_str(), po::value()->value_name("stdout|file|both"), @@ -255,6 +274,16 @@ bool CommandLineInterface::parseArguments(int argc, char** argv) cout << _exception.what() << endl; return false; } + if (m_args.count("combined-json")) + { + vector requests; + for (string const& item: boost::split(requests, m_args["combined-json"].as(), boost::is_any_of(","))) + if (!g_combinedJsonArgs.count(item)) + { + cout << "Invalid option to --combined-json: " << item << endl; + return false; + } + } po::notify(m_args); if (m_args.count("help")) @@ -350,6 +379,52 @@ bool CommandLineInterface::processInput() return true; } +void CommandLineInterface::handleCombinedJSON() +{ + Json::Value output(Json::objectValue); + + set requests; + boost::split(requests, m_args["combined-json"].as(), boost::is_any_of(",")); + vector contracts = m_compiler->getContractNames(); + + if (!contracts.empty()) + output["contracts"] = Json::Value(Json::objectValue); + for (string const& contractName: contracts) + { + Json::Value contractData(Json::objectValue); + if (requests.count("sol-abi")) + contractData["sol-abi"] = m_compiler->getSolidityInterface(contractName); + if (requests.count("json-abi")) + contractData["json-abi"] = m_compiler->getInterface(contractName); + if (requests.count("binary")) + contractData["binary"] = toHex(m_compiler->getBytecode(contractName)); + if (requests.count("opcodes")) + contractData["opcodes"] = eth::disassemble(m_compiler->getBytecode(contractName)); + if (requests.count("asm")) + { + ostringstream unused; + contractData["asm"] = m_compiler->streamAssembly(unused, contractName, m_sourceCodes, true); + } + if (requests.count("natspec-dev")) + contractData["natspec-dev"] = m_compiler->getMetadata(contractName, DocumentationType::NatspecDev); + if (requests.count("natspec-user")) + contractData["natspec-user"] = m_compiler->getMetadata(contractName, DocumentationType::NatspecUser); + output["contracts"][contractName] = contractData; + } + + if (requests.count("ast")) + { + output["sources"] = Json::Value(Json::objectValue); + for (auto const& sourceCode: m_sourceCodes) + { + ASTJsonConverter converter(m_compiler->getAST(sourceCode.first)); + output["sources"][sourceCode.first] = Json::Value(Json::objectValue); + output["sources"][sourceCode.first]["AST"] = converter.json(); + } + } + cout << Json::FastWriter().write(output) << endl; +} + void CommandLineInterface::handleAst(string const& _argStr) { string title; @@ -408,6 +483,8 @@ void CommandLineInterface::handleAst(string const& _argStr) void CommandLineInterface::actOnInput() { + handleCombinedJSON(); + // do we need AST output? handleAst(g_argAstStr); handleAst(g_argAstJson); @@ -415,7 +492,7 @@ void CommandLineInterface::actOnInput() vector contracts = m_compiler->getContractNames(); for (string const& contract: contracts) { - if (needStdout(m_args)) + if (needsHumanTargetedStdout(m_args)) cout << endl << "======= " << contract << " =======" << endl; // do we need EVM assembly? diff --git a/solc/CommandLineInterface.h b/solc/CommandLineInterface.h index 79029f9d1..459f17d3e 100644 --- a/solc/CommandLineInterface.h +++ b/solc/CommandLineInterface.h @@ -53,6 +53,7 @@ public: void actOnInput(); private: + void handleCombinedJSON(); void handleAst(std::string const& _argStr); void handleBinary(std::string const& _contract); void handleOpcode(std::string const& _contract);