Support "standardised" JSON compiler input/output#1639
Conversation
eda1ab2 to
b0ed329
Compare
af166fa to
a7502ff
Compare
|
Working on this next. |
|
Added (locally) the JS interface: Any better naming? |
a16d202 to
6f07bd0
Compare
|
To keep this PR simple, it will not change the CLI to use StandardCompiler internally. Should be handled in a following PR. |
chriseth
left a comment
There was a problem hiding this comment.
Did not yet review all of it.
| { | ||
|
|
||
| /** | ||
| * Easy to use and self-contained Solidity compiler with as few header dependencies as possible. |
| #include <boost/filesystem.hpp> | ||
| #include <json/json.h> | ||
| #include <libdevcore/Common.h> | ||
| #include <libdevcore/FixedHash.h> |
There was a problem hiding this comment.
I think most of the headers can go, CompilerStack should suffice.
| /// File reading callback. | ||
| using ReadFileCallback = std::function<ReadFileResult(std::string const&)>; | ||
|
|
||
| /// Creates a new compiler stack. |
|
Added error reporting of JSON parsing using It looks a bit weird since it uses asterisk for the list, and maybe we could consider using the |
38d500c to
9d449df
Compare
| using namespace dev::solidity; | ||
|
|
||
| Json::Value formatError( | ||
| bool const& _warning, |
There was a problem hiding this comment.
"small" types are usually passed by value and not by const reference.
| class StandardCompiler: boost::noncopyable | ||
| { | ||
| public: | ||
| struct ReadFileResult |
There was a problem hiding this comment.
We have the same in CompilerStack.h, right? Can you pull both out into another file? (Likewise with ReadFileCallback)
chriseth
left a comment
There was a problem hiding this comment.
Still not finished reviewing everything.
| /// @param _readFile callback to used to read files for import statements. Should return | ||
| StandardCompiler(ReadFileCallback const& _readFile = ReadFileCallback()) | ||
| { | ||
| CompilerStack::ReadFileCallback fileReader = [this,_readFile](std::string const& _path) |
There was a problem hiding this comment.
Is the only thing that this lambda does converting between this ReadFileResult and CompilerStack::ReadFileResult?
There was a problem hiding this comment.
Yes. Though I wanted to change separate the string into error / result, but that is not so important.
Basically we'd need to pull out struct ReadFileResult {} into its own header which feels rather slim.
| return CompilerStack::ReadFileResult{ret.success, ret.contentsOrErrorMessage}; | ||
| }; | ||
|
|
||
| m_compilerStack.reset(new CompilerStack(fileReader)); |
There was a problem hiding this comment.
If you can get rid of the lambda, you can use
StandardCompiler(ReadFileCallback const& _readFile = ReadFileCallback())
: m_compilerStack(_readFile)
{
}
| m_compilerStack.reset(new CompilerStack(fileReader)); | ||
| } | ||
|
|
||
| /// Sets all input parameters according to @a _input which conforms to the standardized input |
There was a problem hiding this comment.
And performs compilation and returns the result.
| /// Sets all input parameters according to @a _input which conforms to the standardized input | ||
| /// format. | ||
| Json::Value compile(Json::Value const& _input); | ||
| std::string compile(std::string const& _input); |
There was a problem hiding this comment.
Please document: Parses input as json, compiles and formats output json as string. Json decoding errors are reported in the same way as regular compiler errors.
| using namespace dev; | ||
| using namespace dev::solidity; | ||
|
|
||
| Json::Value formatError( |
There was a problem hiding this comment.
For added C++ishness, you can move those functions into an anonymous namespace:
namespace {
... functions...
}
It makes them translation-unit local (similar to static in C).
There was a problem hiding this comment.
Thanks, will add those.
| Json::Value input; | ||
| Json::Reader reader; | ||
|
|
||
| try { |
|
|
||
| try { | ||
| if (!reader.parse(_input, input, false)) | ||
| { |
There was a problem hiding this comment.
No braces for single statement.
| } | ||
| catch(...) | ||
| { | ||
| return "{\"errors\":\"[{\"type\":\"JSONError\",\"component\":\"general\",\"severity\":\"error\",\"message\":\"Error parsing input JSON.\"}]}"; |
There was a problem hiding this comment.
Can you also use a utility function for this? Or do you want to avoid using the json formatter?
There was a problem hiding this comment.
I have a hardcoded text in two places to avoid endless exception catching of jsonCompactPrint.
| for (auto const& ref: linkReferences) | ||
| { | ||
| string const& fullname = ref.second; | ||
| size_t colon = fullname.find(':'); |
There was a problem hiding this comment.
Please assert that colon != string::npos
| string const& name = fullname.substr(colon + 1); | ||
|
|
||
| Json::Value fileObject = ret.get(file, Json::objectValue); | ||
| Json::Value libraryArray = fileObject.get(name, Json::arrayValue); |
There was a problem hiding this comment.
I think if you use Json::Value& libraryArray here, you do not need the assignment in line 169
There was a problem hiding this comment.
This didn't yet work, would be nice to avoid the current way.
solc/CommandLineInterface.cpp
Outdated
| ) | ||
| (g_argMetadataLiteral.c_str(), "Store referenced sources are literal data in the metadata output."); | ||
| (g_argMetadataLiteral.c_str(), "Store referenced sources are literal data in the metadata output.") | ||
| (g_argStandardJSON.c_str(), "Process standard JSON input / output."); |
There was a problem hiding this comment.
Process seems a bit too technical for me. Also, this disables some other options, does it? Perhaps we should make it more prominent (i.e. put it in the firstline) and say Switches the compiler into JSON input/output mode.
There was a problem hiding this comment.
What is the "JSON input/output mode"?
Shouldn't it be irrelevant to the user how it operates internally? Ideally the CLI should go through the JSON IO to reduce the number of APIs we have, but that shouldn't have any effect on the user.
The current --standard-json is only an interface to directly interact with the API.
There was a problem hiding this comment.
I thought the idea was to expose the json/io API on all implementations of the compiler, in order to get a unified interface and to avoid the problems we currently have with the filesystem.
There was a problem hiding this comment.
I am a bit confused, but do not really see a point of having two implementations internally in the CLI, one using CompilerStack and the other using StandardCompiler.
I would just change it to use StandardCompiler only.
The above option though is not for switching between these implementation, but to accept a raw JSON input and output a raw JSON output.
| if (m_args.count(g_argStandardJSON)) | ||
| { | ||
| string input; | ||
| while (!cin.eof()) |
There was a problem hiding this comment.
There should be something in CommonIO.h to do exactly this.
There was a problem hiding this comment.
Or do you want to convert \r\n to \n? I don't think this is a good idea.
There was a problem hiding this comment.
There's none in CommonIO. If there's a sample code somewhere I'm happy to use that. This came from CommandLineInterface::readInputFilesAndConfigureRemappings.
There was a problem hiding this comment.
(2) istream& getline (istream& is, string& str);
Extracts characters from is and stores them into str until the delimitation character delim is found (or the newline character, '\n', for (2)).
According to this, it won't cut off \r? And the \n is pushed back:
string input;
while (!cin.eof())
{
string tmp;
getline(cin, tmp);
input.append(tmp + "\n");
}
There was a problem hiding this comment.
You are right, my mistake, there are only functions for files. cin is not opened in binary mode, so I think it will convert \r\n into \n. But actually, this should be irrelevant, since everything is json-encoded and whitespace should be just ignored anyway. So, yes, just leave it like that!
solc/CommandLineInterface.cpp
Outdated
| string output = compiler.compile(input); | ||
| cout << "Standard Input JSON: " << input << endl << endl; | ||
| cout << "Standard Output JSON: " << output << endl; | ||
| return false; |
There was a problem hiding this comment.
The CLI is split into processInput and actOnInput. I'm not sure if this division makes sense here, but I think we should only run the compile step in the actOnInput function.
There was a problem hiding this comment.
Oh and perhaps we should flag an error if --standard-json is combined with anything else.
There was a problem hiding this comment.
It turns out that distinction of processInput vs. actOnInput is already broken by assemble and link in processInput. In that case it makes sense there. I would say at this point of time probably the distinction is not useful, because exception catching is handled mostly in actOnInput anyway.
solc/jsonCompiler.cpp
Outdated
| { | ||
| readCallback = [=](string const& _path) | ||
| { | ||
| char* contents_c = nullptr; |
There was a problem hiding this comment.
This code should be duplicated above. Can you reuse it?
|
Woooohooo!!!! 🍰 ! |
Implements #1387. Replaces #712.
Fixes #579, #863, #1645, #1809.
Todo:
StandardCompiler.cppjsonCompilerworks)gasEstimatesoutput (depends on Move gasEstimate into CompilerStack #2114)methodIdentifiersoutputlinkReferencesoutputmetadata.useLiteralContent