mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Make --pretty-json work with Standard JSON output
This commit is contained in:
parent
7041b87c3b
commit
9bbeea58c8
@ -8,6 +8,7 @@ Compiler Features:
|
||||
* Yul EVM Code Transform: Do not reuse stack slots that immediately become unreachable.
|
||||
* Yul EVM Code Transform: Also pop unused argument slots for functions without return variables (under the same restrictions as for functions with return variables).
|
||||
* Yul Optimizer: Move function arguments and return variables to memory with the experimental Stack Limit Evader (which is not enabled by default).
|
||||
* Commandline Interface: option ``--pretty-json`` works also with ``--standard--json``.
|
||||
|
||||
|
||||
Bugfixes:
|
||||
|
@ -1420,7 +1420,7 @@ string StandardCompiler::compile(string const& _input) noexcept
|
||||
try
|
||||
{
|
||||
if (!util::jsonParseStrict(_input, input, &errors))
|
||||
return util::jsonCompactPrint(formatFatalError("JSONError", errors));
|
||||
return util::jsonPrint(formatFatalError("JSONError", errors), m_jsonPrintingFormat);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
@ -1433,7 +1433,7 @@ string StandardCompiler::compile(string const& _input) noexcept
|
||||
|
||||
try
|
||||
{
|
||||
return util::jsonCompactPrint(output);
|
||||
return util::jsonPrint(output, m_jsonPrintingFormat);
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
|
@ -24,6 +24,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <libsolidity/interface/CompilerStack.h>
|
||||
#include <libsolutil/JSON.h>
|
||||
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
@ -46,8 +47,10 @@ public:
|
||||
/// Creates a new StandardCompiler.
|
||||
/// @param _readFile callback used to read files for import statements. Must return
|
||||
/// and must not emit exceptions.
|
||||
explicit StandardCompiler(ReadCallback::Callback _readFile = ReadCallback::Callback()):
|
||||
m_readFile(std::move(_readFile))
|
||||
explicit StandardCompiler(ReadCallback::Callback _readFile = ReadCallback::Callback(),
|
||||
util::JsonFormat const& _format = {}):
|
||||
m_readFile(std::move(_readFile)),
|
||||
m_jsonPrintingFormat(std::move(_format))
|
||||
{
|
||||
}
|
||||
|
||||
@ -91,6 +94,8 @@ private:
|
||||
Json::Value compileYul(InputsAndSettings _inputsAndSettings);
|
||||
|
||||
ReadCallback::Callback m_readFile;
|
||||
|
||||
util::JsonFormat m_jsonPrintingFormat;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -115,18 +115,29 @@ Json::Value removeNullMembers(Json::Value _json)
|
||||
|
||||
string jsonPrettyPrint(Json::Value const& _input)
|
||||
{
|
||||
static map<string, Json::Value> settings{{"indentation", " "}, {"enableYAMLCompatibility", true}};
|
||||
static StreamWriterBuilder writerBuilder(settings);
|
||||
string result = print(_input, writerBuilder);
|
||||
boost::replace_all(result, " \n", "\n");
|
||||
return result;
|
||||
return jsonPrint(_input, JsonFormat{ JsonFormat::Pretty });
|
||||
}
|
||||
|
||||
string jsonCompactPrint(Json::Value const& _input)
|
||||
{
|
||||
static map<string, Json::Value> settings{{"indentation", ""}};
|
||||
static StreamWriterBuilder writerBuilder(settings);
|
||||
return print(_input, writerBuilder);
|
||||
return jsonPrint(_input, JsonFormat{ JsonFormat::Compact });
|
||||
}
|
||||
|
||||
string jsonPrint(Json::Value const& _input, JsonFormat const& _format)
|
||||
{
|
||||
map<string, Json::Value> settings;
|
||||
if (_format.format == JsonFormat::Pretty)
|
||||
{
|
||||
settings["indentation"] = string(_format.indent, ' ');
|
||||
settings["enableYAMLCompatibility"] = true;
|
||||
}
|
||||
else
|
||||
settings["indentation"] = "";
|
||||
StreamWriterBuilder writerBuilder(settings);
|
||||
string result = print(_input, writerBuilder);
|
||||
if (_format.format == JsonFormat::Pretty)
|
||||
boost::replace_all(result, " \n", "\n");
|
||||
return result;
|
||||
}
|
||||
|
||||
bool jsonParseStrict(string const& _input, Json::Value& _json, string* _errs /* = nullptr */)
|
||||
|
@ -33,12 +33,33 @@ namespace solidity::util
|
||||
/// Removes members with null value recursively from (@a _json).
|
||||
Json::Value removeNullMembers(Json::Value _json);
|
||||
|
||||
/// JSON printing format.
|
||||
struct JsonFormat
|
||||
{
|
||||
enum Format
|
||||
{
|
||||
Compact,
|
||||
Pretty
|
||||
};
|
||||
|
||||
static constexpr uint32_t defaultIndent = 2;
|
||||
|
||||
bool operator==(JsonFormat const& _other) const noexcept { return (format == _other.format) && (indent == _other.indent); }
|
||||
bool operator!=(JsonFormat const& _other) const noexcept { return !(*this == _other); }
|
||||
|
||||
Format format = Compact;
|
||||
uint32_t indent = defaultIndent;
|
||||
};
|
||||
|
||||
/// Serialise the JSON object (@a _input) with indentation
|
||||
std::string jsonPrettyPrint(Json::Value const& _input);
|
||||
|
||||
/// Serialise the JSON object (@a _input) without indentation
|
||||
std::string jsonCompactPrint(Json::Value const& _input);
|
||||
|
||||
/// Serialise the JSON object (@a _input) using specified format (@a _format)
|
||||
std::string jsonPrint(Json::Value const& _input, JsonFormat const& _format);
|
||||
|
||||
/// Parse a JSON string (@a _input) with enabled strict-mode and writes resulting JSON object to (@a _json)
|
||||
/// \param _input JSON input string
|
||||
/// \param _json [out] resulting JSON object
|
||||
|
@ -532,7 +532,7 @@ bool CommandLineInterface::processInput()
|
||||
return false;
|
||||
}
|
||||
}
|
||||
StandardCompiler compiler(m_fileReader.reader());
|
||||
StandardCompiler compiler(m_fileReader.reader(), m_options.formatting.json);
|
||||
sout() << compiler.compile(std::move(input)) << endl;
|
||||
return true;
|
||||
}
|
||||
@ -771,9 +771,7 @@ void CommandLineInterface::handleCombinedJSON()
|
||||
}
|
||||
}
|
||||
|
||||
string json = m_options.formatting.prettyJson ? jsonPrettyPrint(removeNullMembers(std::move(output))) :
|
||||
jsonCompactPrint(removeNullMembers(std::move(output)));
|
||||
|
||||
string json = jsonPrint(removeNullMembers(std::move(output)), m_options.formatting.json);
|
||||
if (!m_options.output.dir.empty())
|
||||
createJson("combined", json);
|
||||
else
|
||||
|
@ -125,6 +125,7 @@ static string const g_strStandardJSON = "standard-json";
|
||||
static string const g_strStrictAssembly = "strict-assembly";
|
||||
static string const g_strSwarm = "swarm";
|
||||
static string const g_strPrettyJson = "pretty-json";
|
||||
static string const g_strJsonIndent = "json-indent";
|
||||
static string const g_strVersion = "version";
|
||||
static string const g_strIgnoreMissingFiles = "ignore-missing";
|
||||
static string const g_strColor = "color";
|
||||
@ -281,7 +282,7 @@ bool CommandLineOptions::operator==(CommandLineOptions const& _other) const noex
|
||||
assembly.targetMachine == _other.assembly.targetMachine &&
|
||||
assembly.inputLanguage == _other.assembly.inputLanguage &&
|
||||
linker.libraries == _other.linker.libraries &&
|
||||
formatting.prettyJson == _other.formatting.prettyJson &&
|
||||
formatting.json == _other.formatting.json &&
|
||||
formatting.coloredOutput == _other.formatting.coloredOutput &&
|
||||
formatting.withErrorIds == _other.formatting.withErrorIds &&
|
||||
compiler.outputs == _other.compiler.outputs &&
|
||||
@ -582,7 +583,12 @@ General Information)").c_str(),
|
||||
outputFormatting.add_options()
|
||||
(
|
||||
g_strPrettyJson.c_str(),
|
||||
"Output JSON in pretty format. Currently it only works with the combined JSON output."
|
||||
"Output JSON in pretty format."
|
||||
)
|
||||
(
|
||||
g_strJsonIndent.c_str(),
|
||||
po::value<uint32_t>()->value_name("N")->default_value(util::JsonFormat::defaultIndent),
|
||||
"Indent pretty-printed JSON with N spaces. Enables '--pretty-json' automatically."
|
||||
)
|
||||
(
|
||||
g_strColor.c_str(),
|
||||
@ -790,7 +796,16 @@ General Information)").c_str(),
|
||||
m_options.output.dir = m_args.at(g_strOutputDir).as<string>();
|
||||
|
||||
m_options.output.overwriteFiles = (m_args.count(g_strOverwrite) > 0);
|
||||
m_options.formatting.prettyJson = (m_args.count(g_strPrettyJson) > 0);
|
||||
|
||||
if (m_args.count(g_strPrettyJson) > 0)
|
||||
{
|
||||
m_options.formatting.json.format = JsonFormat::Pretty;
|
||||
}
|
||||
if (!m_args[g_strJsonIndent].defaulted())
|
||||
{
|
||||
m_options.formatting.json.format = JsonFormat::Pretty;
|
||||
m_options.formatting.json.indent = m_args[g_strJsonIndent].as<uint32_t>();
|
||||
}
|
||||
|
||||
static_assert(
|
||||
sizeof(m_options.compiler.outputs) == 15 * sizeof(bool),
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <libsolidity/interface/ImportRemapper.h>
|
||||
#include <libyul/AssemblyStack.h>
|
||||
#include <liblangutil/EVMVersion.h>
|
||||
#include <libsolutil/JSON.h>
|
||||
|
||||
#include <boost/program_options.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
@ -101,6 +102,7 @@ struct CommandLineOptions
|
||||
bool operator==(CommandLineOptions const& _other) const noexcept;
|
||||
bool operator!=(CommandLineOptions const& _other) const noexcept { return !(*this == _other); }
|
||||
|
||||
|
||||
struct
|
||||
{
|
||||
InputMode mode = InputMode::Compiler;
|
||||
@ -137,7 +139,7 @@ struct CommandLineOptions
|
||||
|
||||
struct
|
||||
{
|
||||
bool prettyJson = false;
|
||||
util::JsonFormat json;
|
||||
std::optional<bool> coloredOutput;
|
||||
bool withErrorIds = false;
|
||||
} formatting;
|
||||
@ -168,6 +170,7 @@ struct CommandLineOptions
|
||||
bool initialize = false;
|
||||
ModelCheckerSettings settings;
|
||||
} modelChecker;
|
||||
|
||||
};
|
||||
|
||||
/// Parses the command-line arguments and produces a filled-out CommandLineOptions structure.
|
||||
|
@ -141,9 +141,16 @@ function test_solc_behaviour()
|
||||
|
||||
if [[ " ${solc_args[*]} " == *" --standard-json "* ]]
|
||||
then
|
||||
sed -i.bak -e 's/{[^{]*Warning: This is a pre-release compiler version[^}]*},\{0,1\}//' "$stdout_path"
|
||||
python3 - <<EOF
|
||||
import re, sys
|
||||
json = open("$stdout_path", "r").read()
|
||||
json = re.sub(r"{[^{}]*Warning: This is a pre-release compiler version[^{}]*},?", "", json)
|
||||
json = re.sub(r"},\s*]", "}]", json) # },] -> }]
|
||||
json = re.sub(r"\"errors\":\s*\[\s*\],?\s*","",json) # Remove "errors" array if it's not empty
|
||||
json = re.sub("\n\\s+\n", "\n\n", json) # Remove any leftover trailing whitespace
|
||||
open("$stdout_path", "w").write(json)
|
||||
EOF
|
||||
sed -i.bak -E -e 's/ Consider adding \\"pragma solidity \^[0-9.]*;\\"//g' "$stdout_path"
|
||||
sed -i.bak -e 's/"errors":\[\],\{0,1\}//' "$stdout_path"
|
||||
sed -i.bak -E -e 's/\"opcodes\":\"[^"]+\"/\"opcodes\":\"<OPCODES REMOVED>\"/g' "$stdout_path"
|
||||
sed -i.bak -E -e 's/\"sourceMap\":\"[0-9:;-]+\"/\"sourceMap\":\"<SOURCEMAP REMOVED>\"/g' "$stdout_path"
|
||||
|
||||
|
1
test/cmdlineTests/pretty_json_combined/args
Normal file
1
test/cmdlineTests/pretty_json_combined/args
Normal file
@ -0,0 +1 @@
|
||||
--combined-json abi --pretty-json --json-indent 3
|
3
test/cmdlineTests/pretty_json_combined/input.sol
Normal file
3
test/cmdlineTests/pretty_json_combined/input.sol
Normal file
@ -0,0 +1,3 @@
|
||||
// SPDX-License-Identifier: GPL-3.0
|
||||
pragma solidity >=0.0;
|
||||
contract C {}
|
10
test/cmdlineTests/pretty_json_combined/output
Normal file
10
test/cmdlineTests/pretty_json_combined/output
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"contracts":
|
||||
{
|
||||
"pretty_json_combined/input.sol:C":
|
||||
{
|
||||
"abi": []
|
||||
}
|
||||
},
|
||||
"version": "<VERSION REMOVED>"
|
||||
}
|
1
test/cmdlineTests/pretty_json_indent_only/args
Normal file
1
test/cmdlineTests/pretty_json_indent_only/args
Normal file
@ -0,0 +1 @@
|
||||
--json-indent 7
|
10
test/cmdlineTests/pretty_json_indent_only/input.json
Normal file
10
test/cmdlineTests/pretty_json_indent_only/input.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"language": "Solidity",
|
||||
"sources":
|
||||
{
|
||||
"A":
|
||||
{
|
||||
"content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C {}"
|
||||
}
|
||||
}
|
||||
}
|
1
test/cmdlineTests/pretty_json_indent_only/output
Normal file
1
test/cmdlineTests/pretty_json_indent_only/output
Normal file
@ -0,0 +1 @@
|
||||
|
9
test/cmdlineTests/pretty_json_indent_only/output.json
Normal file
9
test/cmdlineTests/pretty_json_indent_only/output.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"sources":
|
||||
{
|
||||
"A":
|
||||
{
|
||||
"id": 0
|
||||
}
|
||||
}
|
||||
}
|
1
test/cmdlineTests/pretty_json_standard/args
Normal file
1
test/cmdlineTests/pretty_json_standard/args
Normal file
@ -0,0 +1 @@
|
||||
--pretty-json
|
10
test/cmdlineTests/pretty_json_standard/input.json
Normal file
10
test/cmdlineTests/pretty_json_standard/input.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"language": "Solidity",
|
||||
"sources":
|
||||
{
|
||||
"A":
|
||||
{
|
||||
"content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C {}"
|
||||
}
|
||||
}
|
||||
}
|
9
test/cmdlineTests/pretty_json_standard/output.json
Normal file
9
test/cmdlineTests/pretty_json_standard/output.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"sources":
|
||||
{
|
||||
"A":
|
||||
{
|
||||
"id": 0
|
||||
}
|
||||
}
|
||||
}
|
1
test/cmdlineTests/pretty_json_standard_indent/args
Normal file
1
test/cmdlineTests/pretty_json_standard_indent/args
Normal file
@ -0,0 +1 @@
|
||||
--pretty-json --json-indent 7
|
10
test/cmdlineTests/pretty_json_standard_indent/input.json
Normal file
10
test/cmdlineTests/pretty_json_standard_indent/input.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"language": "Solidity",
|
||||
"sources":
|
||||
{
|
||||
"A":
|
||||
{
|
||||
"content": "// SPDX-License-Identifier: GPL-3.0\npragma solidity >=0.0; contract C { }"
|
||||
}
|
||||
}
|
||||
}
|
9
test/cmdlineTests/pretty_json_standard_indent/output
Normal file
9
test/cmdlineTests/pretty_json_standard_indent/output
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"sources":
|
||||
{
|
||||
"A":
|
||||
{
|
||||
"id": 0
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
{
|
||||
"sources":
|
||||
{
|
||||
"A":
|
||||
{
|
||||
"id": 0
|
||||
}
|
||||
}
|
||||
}
|
@ -138,6 +138,7 @@ BOOST_AUTO_TEST_CASE(cli_mode_options)
|
||||
"--experimental-via-ir",
|
||||
"--revert-strings=strip",
|
||||
"--pretty-json",
|
||||
"--json-indent=7",
|
||||
"--no-color",
|
||||
"--error-codes",
|
||||
"--libraries="
|
||||
@ -173,6 +174,7 @@ BOOST_AUTO_TEST_CASE(cli_mode_options)
|
||||
{"a", "b", "c/d"},
|
||||
{"", "contract.sol", ""},
|
||||
};
|
||||
|
||||
expectedOptions.input.addStdin = true;
|
||||
expectedOptions.input.basePath = "/home/user/";
|
||||
expectedOptions.input.allowedDirectories = {"/tmp", "/home", "project", "../contracts", "", "c", "/usr/lib"};
|
||||
@ -183,11 +185,11 @@ BOOST_AUTO_TEST_CASE(cli_mode_options)
|
||||
expectedOptions.output.evmVersion = EVMVersion::spuriousDragon();
|
||||
expectedOptions.output.experimentalViaIR = true;
|
||||
expectedOptions.output.revertStrings = RevertStrings::Strip;
|
||||
expectedOptions.formatting.json = JsonFormat{JsonFormat::Pretty, 7};
|
||||
expectedOptions.linker.libraries = {
|
||||
{"dir1/file1.sol:L", h160("1234567890123456789012345678901234567890")},
|
||||
{"dir2/file2.sol:L", h160("1111122222333334444455555666667777788888")},
|
||||
};
|
||||
expectedOptions.formatting.prettyJson = true;
|
||||
expectedOptions.formatting.coloredOutput = false;
|
||||
expectedOptions.formatting.withErrorIds = true;
|
||||
expectedOptions.compiler.outputs = {
|
||||
@ -269,6 +271,7 @@ BOOST_AUTO_TEST_CASE(assembly_mode_options)
|
||||
"--experimental-via-ir", // Ignored in assembly mode
|
||||
"--revert-strings=strip", // Accepted but has no effect in assembly mode
|
||||
"--pretty-json",
|
||||
"--json-indent=1",
|
||||
"--no-color",
|
||||
"--error-codes",
|
||||
"--libraries="
|
||||
@ -313,13 +316,13 @@ BOOST_AUTO_TEST_CASE(assembly_mode_options)
|
||||
expectedOptions.output.overwriteFiles = true;
|
||||
expectedOptions.output.evmVersion = EVMVersion::spuriousDragon();
|
||||
expectedOptions.output.revertStrings = RevertStrings::Strip;
|
||||
expectedOptions.formatting.json = JsonFormat {JsonFormat::Pretty, 1};
|
||||
expectedOptions.assembly.targetMachine = expectedMachine;
|
||||
expectedOptions.assembly.inputLanguage = expectedLanguage;
|
||||
expectedOptions.linker.libraries = {
|
||||
{"dir1/file1.sol:L", h160("1234567890123456789012345678901234567890")},
|
||||
{"dir2/file2.sol:L", h160("1111122222333334444455555666667777788888")},
|
||||
};
|
||||
expectedOptions.formatting.prettyJson = true;
|
||||
expectedOptions.formatting.coloredOutput = false;
|
||||
expectedOptions.formatting.withErrorIds = true;
|
||||
expectedOptions.compiler.outputs = {
|
||||
@ -359,7 +362,8 @@ BOOST_AUTO_TEST_CASE(standard_json_mode_options)
|
||||
"--evm-version=spuriousDragon", // Ignored in Standard JSON mode
|
||||
"--experimental-via-ir", // Ignored in Standard JSON mode
|
||||
"--revert-strings=strip", // Accepted but has no effect in Standard JSON mode
|
||||
"--pretty-json", // Accepted but has no effect in Standard JSON mode
|
||||
"--pretty-json",
|
||||
"--json-indent=1",
|
||||
"--no-color", // Accepted but has no effect in Standard JSON mode
|
||||
"--error-codes", // Accepted but has no effect in Standard JSON mode
|
||||
"--libraries=" // Ignored in Standard JSON mode
|
||||
@ -387,6 +391,7 @@ BOOST_AUTO_TEST_CASE(standard_json_mode_options)
|
||||
};
|
||||
|
||||
CommandLineOptions expectedOptions;
|
||||
|
||||
expectedOptions.input.mode = InputMode::StandardJson;
|
||||
expectedOptions.input.paths = {};
|
||||
expectedOptions.input.standardJsonFile = "input.json";
|
||||
@ -395,7 +400,7 @@ BOOST_AUTO_TEST_CASE(standard_json_mode_options)
|
||||
expectedOptions.output.dir = "/tmp/out";
|
||||
expectedOptions.output.overwriteFiles = true;
|
||||
expectedOptions.output.revertStrings = RevertStrings::Strip;
|
||||
expectedOptions.formatting.prettyJson = true;
|
||||
expectedOptions.formatting.json = JsonFormat {JsonFormat::Pretty, 1};
|
||||
expectedOptions.formatting.coloredOutput = false;
|
||||
expectedOptions.formatting.withErrorIds = true;
|
||||
expectedOptions.compiler.outputs = {
|
||||
|
Loading…
Reference in New Issue
Block a user