mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
[solc] Add --import-asm-json input mode.
This commit is contained in:
parent
7334420423
commit
235af2b4d1
@ -634,6 +634,7 @@ bool CommandLineInterface::processInput()
|
||||
break;
|
||||
case InputMode::Compiler:
|
||||
case InputMode::CompilerWithASTImport:
|
||||
case InputMode::CompilerWithEvmAssemblyJsonImport:
|
||||
if (!compile())
|
||||
return false;
|
||||
outputCompilationResults();
|
||||
@ -657,105 +658,112 @@ void CommandLineInterface::printLicense()
|
||||
|
||||
bool CommandLineInterface::compile()
|
||||
{
|
||||
solAssert(m_options.input.mode == InputMode::Compiler || m_options.input.mode == InputMode::CompilerWithASTImport, "");
|
||||
solAssert(
|
||||
m_options.input.mode == InputMode::Compiler ||
|
||||
m_options.input.mode == InputMode::CompilerWithASTImport ||
|
||||
m_options.input.mode == InputMode::CompilerWithEvmAssemblyJsonImport, ""
|
||||
);
|
||||
|
||||
m_compiler = make_unique<CompilerStack>(m_fileReader.reader());
|
||||
|
||||
SourceReferenceFormatter formatter(serr(false), *m_compiler, coloredOutput(m_options), m_options.formatting.withErrorIds);
|
||||
|
||||
try
|
||||
if (m_options.input.mode == InputMode::CompilerWithEvmAssemblyJsonImport)
|
||||
{
|
||||
if (m_options.metadata.literalSources)
|
||||
m_compiler->useMetadataLiteralSources(true);
|
||||
m_compiler->setMetadataHash(m_options.metadata.hash);
|
||||
if (m_options.modelChecker.initialize)
|
||||
m_compiler->setModelCheckerSettings(m_options.modelChecker.settings);
|
||||
m_compiler->setRemappings(m_options.input.remappings);
|
||||
m_compiler->setLibraries(m_options.linker.libraries);
|
||||
m_compiler->setViaIR(m_options.output.experimentalViaIR);
|
||||
m_compiler->setEVMVersion(m_options.output.evmVersion);
|
||||
m_compiler->setRevertStringBehaviour(m_options.output.revertStrings);
|
||||
if (m_options.output.debugInfoSelection.has_value())
|
||||
m_compiler->selectDebugInfo(m_options.output.debugInfoSelection.value());
|
||||
// TODO: Perhaps we should not compile unless requested
|
||||
|
||||
m_compiler->enableIRGeneration(m_options.compiler.outputs.ir || m_options.compiler.outputs.irOptimized);
|
||||
m_compiler->enableEwasmGeneration(m_options.compiler.outputs.ewasm);
|
||||
m_compiler->enableEvmBytecodeGeneration(
|
||||
m_options.compiler.estimateGas ||
|
||||
m_options.compiler.outputs.asm_ ||
|
||||
m_options.compiler.outputs.asmJson ||
|
||||
m_options.compiler.outputs.opcodes ||
|
||||
m_options.compiler.outputs.binary ||
|
||||
m_options.compiler.outputs.binaryRuntime ||
|
||||
(m_options.compiler.combinedJsonRequests && (
|
||||
m_options.compiler.combinedJsonRequests->binary ||
|
||||
m_options.compiler.combinedJsonRequests->binaryRuntime ||
|
||||
m_options.compiler.combinedJsonRequests->opcodes ||
|
||||
m_options.compiler.combinedJsonRequests->asm_ ||
|
||||
m_options.compiler.combinedJsonRequests->generatedSources ||
|
||||
m_options.compiler.combinedJsonRequests->generatedSourcesRuntime ||
|
||||
m_options.compiler.combinedJsonRequests->srcMap ||
|
||||
m_options.compiler.combinedJsonRequests->srcMapRuntime ||
|
||||
m_options.compiler.combinedJsonRequests->funDebug ||
|
||||
m_options.compiler.combinedJsonRequests->funDebugRuntime
|
||||
))
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
SourceReferenceFormatter
|
||||
formatter(serr(false), *m_compiler, coloredOutput(m_options), m_options.formatting.withErrorIds);
|
||||
|
||||
m_compiler->setOptimiserSettings(m_options.optimiserSettings());
|
||||
|
||||
if (m_options.input.mode == InputMode::CompilerWithASTImport)
|
||||
try
|
||||
{
|
||||
try
|
||||
{
|
||||
m_compiler->importASTs(parseAstFromInput());
|
||||
if (m_options.metadata.literalSources)
|
||||
m_compiler->useMetadataLiteralSources(true);
|
||||
m_compiler->setMetadataHash(m_options.metadata.hash);
|
||||
if (m_options.modelChecker.initialize)
|
||||
m_compiler->setModelCheckerSettings(m_options.modelChecker.settings);
|
||||
m_compiler->setRemappings(m_options.input.remappings);
|
||||
m_compiler->setLibraries(m_options.linker.libraries);
|
||||
m_compiler->setViaIR(m_options.output.experimentalViaIR);
|
||||
m_compiler->setEVMVersion(m_options.output.evmVersion);
|
||||
m_compiler->setRevertStringBehaviour(m_options.output.revertStrings);
|
||||
if (m_options.output.debugInfoSelection.has_value())
|
||||
m_compiler->selectDebugInfo(m_options.output.debugInfoSelection.value());
|
||||
// TODO: Perhaps we should not compile unless requested
|
||||
|
||||
if (!m_compiler->analyze())
|
||||
m_compiler->enableIRGeneration(m_options.compiler.outputs.ir || m_options.compiler.outputs.irOptimized);
|
||||
m_compiler->enableEwasmGeneration(m_options.compiler.outputs.ewasm);
|
||||
m_compiler->enableEvmBytecodeGeneration(
|
||||
m_options.compiler.estimateGas || m_options.compiler.outputs.asm_ || m_options.compiler.outputs.asmJson
|
||||
|| m_options.compiler.outputs.opcodes || m_options.compiler.outputs.binary
|
||||
|| m_options.compiler.outputs.binaryRuntime
|
||||
|| (m_options.compiler.combinedJsonRequests
|
||||
&& (m_options.compiler.combinedJsonRequests->binary
|
||||
|| m_options.compiler.combinedJsonRequests->binaryRuntime
|
||||
|| m_options.compiler.combinedJsonRequests->opcodes
|
||||
|| m_options.compiler.combinedJsonRequests->asm_
|
||||
|| m_options.compiler.combinedJsonRequests->generatedSources
|
||||
|| m_options.compiler.combinedJsonRequests->generatedSourcesRuntime
|
||||
|| m_options.compiler.combinedJsonRequests->srcMap
|
||||
|| m_options.compiler.combinedJsonRequests->srcMapRuntime
|
||||
|| m_options.compiler.combinedJsonRequests->funDebug
|
||||
|| m_options.compiler.combinedJsonRequests->funDebugRuntime)));
|
||||
|
||||
m_compiler->setOptimiserSettings(m_options.optimiserSettings());
|
||||
|
||||
if (m_options.input.mode == InputMode::CompilerWithASTImport)
|
||||
{
|
||||
try
|
||||
{
|
||||
formatter.printErrorInformation(m_compiler->errors());
|
||||
astAssert(false, "Analysis of the AST failed");
|
||||
m_compiler->importASTs(parseAstFromInput());
|
||||
|
||||
if (!m_compiler->analyze())
|
||||
{
|
||||
formatter.printErrorInformation(m_compiler->errors());
|
||||
astAssert(false, "Analysis of the AST failed");
|
||||
}
|
||||
}
|
||||
catch (Exception const& _exc)
|
||||
{
|
||||
serr() << string("Failed to import AST: ") << _exc.what() << endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (Exception const& _exc)
|
||||
else
|
||||
{
|
||||
serr() << string("Failed to import AST: ") << _exc.what() << endl;
|
||||
return false;
|
||||
m_compiler->setSources(m_fileReader.sourceCodes());
|
||||
m_compiler->setParserErrorRecovery(m_options.input.errorRecovery);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_compiler->setSources(m_fileReader.sourceCodes());
|
||||
m_compiler->setParserErrorRecovery(m_options.input.errorRecovery);
|
||||
}
|
||||
|
||||
bool successful = m_compiler->compile(m_options.output.stopAfter);
|
||||
bool successful = m_compiler->compile(m_options.output.stopAfter);
|
||||
|
||||
for (auto const& error: m_compiler->errors())
|
||||
for (auto const& error: m_compiler->errors())
|
||||
{
|
||||
m_hasOutput = true;
|
||||
formatter.printErrorInformation(*error);
|
||||
}
|
||||
|
||||
if (!successful)
|
||||
return m_options.input.errorRecovery;
|
||||
}
|
||||
catch (CompilerError const& _exception)
|
||||
{
|
||||
m_hasOutput = true;
|
||||
formatter.printErrorInformation(*error);
|
||||
formatter.printExceptionInformation(_exception, "Compiler error");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!successful)
|
||||
return m_options.input.errorRecovery;
|
||||
}
|
||||
catch (CompilerError const& _exception)
|
||||
{
|
||||
m_hasOutput = true;
|
||||
formatter.printExceptionInformation(_exception, "Compiler error");
|
||||
return false;
|
||||
}
|
||||
catch (Error const& _error)
|
||||
{
|
||||
if (_error.type() == Error::Type::DocstringParsingError)
|
||||
serr() << "Documentation parsing error: " << *boost::get_error_info<errinfo_comment>(_error) << endl;
|
||||
else
|
||||
catch (Error const& _error)
|
||||
{
|
||||
m_hasOutput = true;
|
||||
formatter.printExceptionInformation(_error, _error.typeName());
|
||||
}
|
||||
if (_error.type() == Error::Type::DocstringParsingError)
|
||||
serr() << "Documentation parsing error: " << *boost::get_error_info<errinfo_comment>(_error) << endl;
|
||||
else
|
||||
{
|
||||
m_hasOutput = true;
|
||||
formatter.printExceptionInformation(_error, _error.typeName());
|
||||
}
|
||||
|
||||
return false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -763,7 +771,11 @@ bool CommandLineInterface::compile()
|
||||
|
||||
void CommandLineInterface::handleCombinedJSON()
|
||||
{
|
||||
solAssert(m_options.input.mode == InputMode::Compiler || m_options.input.mode == InputMode::CompilerWithASTImport, "");
|
||||
solAssert(
|
||||
m_options.input.mode == InputMode::Compiler ||
|
||||
m_options.input.mode == InputMode::CompilerWithEvmAssemblyJsonImport ||
|
||||
m_options.input.mode == InputMode::CompilerWithASTImport, ""
|
||||
);
|
||||
|
||||
if (!m_options.compiler.combinedJsonRequests.has_value())
|
||||
return;
|
||||
@ -1095,68 +1107,77 @@ bool CommandLineInterface::assemble(yul::AssemblyStack::Language _language, yul:
|
||||
|
||||
void CommandLineInterface::outputCompilationResults()
|
||||
{
|
||||
solAssert(m_options.input.mode == InputMode::Compiler || m_options.input.mode == InputMode::CompilerWithASTImport, "");
|
||||
solAssert(
|
||||
m_options.input.mode == InputMode::Compiler ||
|
||||
m_options.input.mode == InputMode::CompilerWithEvmAssemblyJsonImport ||
|
||||
m_options.input.mode == InputMode::CompilerWithASTImport, ""
|
||||
);
|
||||
|
||||
handleCombinedJSON();
|
||||
|
||||
// do we need AST output?
|
||||
handleAst();
|
||||
|
||||
if (
|
||||
!m_compiler->compilationSuccessful() &&
|
||||
m_options.output.stopAfter == CompilerStack::State::CompilationSuccessful
|
||||
)
|
||||
if (m_options.input.mode == InputMode::CompilerWithEvmAssemblyJsonImport)
|
||||
{
|
||||
serr() << endl << "Compilation halted after AST generation due to errors." << endl;
|
||||
return;
|
||||
handleBytecode("");
|
||||
}
|
||||
|
||||
vector<string> contracts = m_compiler->contractNames();
|
||||
for (string const& contract: contracts)
|
||||
else
|
||||
{
|
||||
if (needsHumanTargetedStdout(m_options))
|
||||
sout() << endl << "======= " << contract << " =======" << endl;
|
||||
// do we need AST output?
|
||||
handleAst();
|
||||
|
||||
// do we need EVM assembly?
|
||||
if (m_options.compiler.outputs.asm_ || m_options.compiler.outputs.asmJson)
|
||||
if (!m_compiler->compilationSuccessful()
|
||||
&& m_options.output.stopAfter == CompilerStack::State::CompilationSuccessful)
|
||||
{
|
||||
string ret;
|
||||
if (m_options.compiler.outputs.asmJson)
|
||||
ret = jsonPrettyPrint(removeNullMembers(m_compiler->assemblyJSON(contract)));
|
||||
else
|
||||
ret = m_compiler->assemblyString(contract, m_fileReader.sourceCodes());
|
||||
|
||||
if (!m_options.output.dir.empty())
|
||||
{
|
||||
createFile(m_compiler->filesystemFriendlyName(contract) + (m_options.compiler.outputs.asmJson ? "_evm.json" : ".evm"), ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
sout() << "EVM assembly:" << endl << ret << endl;
|
||||
}
|
||||
serr() << endl << "Compilation halted after AST generation due to errors." << endl;
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_options.compiler.estimateGas)
|
||||
handleGasEstimation(contract);
|
||||
vector<string> contracts = m_compiler->contractNames();
|
||||
for (string const& contract: contracts)
|
||||
{
|
||||
if (needsHumanTargetedStdout(m_options))
|
||||
sout() << endl << "======= " << contract << " =======" << endl;
|
||||
|
||||
handleBytecode(contract);
|
||||
handleIR(contract);
|
||||
handleIROptimized(contract);
|
||||
handleEwasm(contract);
|
||||
handleSignatureHashes(contract);
|
||||
handleMetadata(contract);
|
||||
handleABI(contract);
|
||||
handleStorageLayout(contract);
|
||||
handleNatspec(true, contract);
|
||||
handleNatspec(false, contract);
|
||||
} // end of contracts iteration
|
||||
// do we need EVM assembly?
|
||||
if (m_options.compiler.outputs.asm_ || m_options.compiler.outputs.asmJson)
|
||||
{
|
||||
string ret;
|
||||
if (m_options.compiler.outputs.asmJson)
|
||||
ret = jsonPrettyPrint(removeNullMembers(m_compiler->assemblyJSON(contract)));
|
||||
else
|
||||
ret = m_compiler->assemblyString(contract, m_fileReader.sourceCodes());
|
||||
|
||||
if (!m_hasOutput)
|
||||
{
|
||||
if (!m_options.output.dir.empty())
|
||||
sout() << "Compiler run successful. Artifact(s) can be found in directory " << m_options.output.dir << "." << endl;
|
||||
else
|
||||
serr() << "Compiler run successful, no output requested." << endl;
|
||||
if (!m_options.output.dir.empty())
|
||||
{
|
||||
createFile(m_compiler->filesystemFriendlyName(contract) + (m_options.compiler.outputs.asmJson ? "_evm.json" : ".evm"), ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
sout() << "EVM assembly:" << endl << ret << endl;
|
||||
}
|
||||
}
|
||||
|
||||
if (m_options.compiler.estimateGas)
|
||||
handleGasEstimation(contract);
|
||||
|
||||
handleBytecode(contract);
|
||||
handleIR(contract);
|
||||
handleIROptimized(contract);
|
||||
handleEwasm(contract);
|
||||
handleSignatureHashes(contract);
|
||||
handleMetadata(contract);
|
||||
handleABI(contract);
|
||||
handleStorageLayout(contract);
|
||||
handleNatspec(true, contract);
|
||||
handleNatspec(false, contract);
|
||||
} // end of contracts iteration
|
||||
|
||||
if (!m_hasOutput)
|
||||
{
|
||||
if (!m_options.output.dir.empty())
|
||||
sout() << "Compiler run successful. Artifact(s) can be found in directory " << m_options.output.dir << "." << endl;
|
||||
else
|
||||
serr() << "Compiler run successful, no output requested." << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -46,6 +46,7 @@ static string const g_strAllowPaths = "allow-paths";
|
||||
static string const g_strBasePath = "base-path";
|
||||
static string const g_strIncludePath = "include-path";
|
||||
static string const g_strAssemble = "assemble";
|
||||
static string const g_strImportEvmAssemblerJson = "import-asm-json";
|
||||
static string const g_strCombinedJson = "combined-json";
|
||||
static string const g_strErrorRecovery = "error-recovery";
|
||||
static string const g_strEVM = "evm";
|
||||
@ -134,6 +135,7 @@ static map<InputMode, string> const g_inputModeName = {
|
||||
{InputMode::Compiler, "compiler"},
|
||||
{InputMode::CompilerWithASTImport, "compiler (AST import)"},
|
||||
{InputMode::Assembler, "assembler"},
|
||||
{InputMode::CompilerWithEvmAssemblyJsonImport, "assembler (EVM ASM JSON import)"},
|
||||
{InputMode::StandardJson, "standard JSON"},
|
||||
{InputMode::Linker, "linker"},
|
||||
};
|
||||
@ -321,7 +323,20 @@ bool CommandLineParser::parseInputPathsAndRemappings()
|
||||
m_options.input.paths.insert(positionalArg);
|
||||
}
|
||||
|
||||
if (m_options.input.mode == InputMode::StandardJson)
|
||||
if (m_options.input.mode == InputMode::CompilerWithEvmAssemblyJsonImport)
|
||||
{
|
||||
if (m_options.input.paths.size() > 1 || (m_options.input.paths.size() == 1 && m_options.input.addStdin))
|
||||
{
|
||||
serr() << "Too many input files for --" << g_strImportEvmAssemblerJson << "." << endl;
|
||||
serr() << "Please either specify a single file name or provide its content on standard input." << endl;
|
||||
return false;
|
||||
}
|
||||
else if (m_options.input.paths.size() == 0)
|
||||
// Standard JSON mode input used to be handled separately and zero files meant "read from stdin".
|
||||
// Keep it working that way for backwards-compatibility.
|
||||
m_options.input.addStdin = true;
|
||||
}
|
||||
else if (m_options.input.mode == InputMode::StandardJson)
|
||||
{
|
||||
if (m_options.input.paths.size() > 1 || (m_options.input.paths.size() == 1 && m_options.input.addStdin))
|
||||
{
|
||||
@ -466,6 +481,7 @@ bool CommandLineParser::parseOutputSelection()
|
||||
case InputMode::Version:
|
||||
solAssert(false);
|
||||
case InputMode::Compiler:
|
||||
case InputMode::CompilerWithEvmAssemblyJsonImport:
|
||||
case InputMode::CompilerWithASTImport:
|
||||
return contains(compilerModeOutputs, _outputName);
|
||||
case InputMode::Assembler:
|
||||
@ -641,8 +657,12 @@ General Information)").c_str(),
|
||||
(
|
||||
g_strImportAst.c_str(),
|
||||
("Import ASTs to be compiled, assumes input holds the AST in compact JSON format. "
|
||||
"Supported Inputs is the output of the --" + g_strStandardJSON + " or the one produced by "
|
||||
"--" + g_strCombinedJson + " " + CombinedJsonRequests::componentName(&CombinedJsonRequests::ast)).c_str()
|
||||
"Supported Inputs is the output of the --" + g_strStandardJSON + " or the one produced by "
|
||||
"--" + g_strCombinedJson + " " + CombinedJsonRequests::componentName(&CombinedJsonRequests::ast)).c_str()
|
||||
)
|
||||
(
|
||||
g_strImportEvmAssemblerJson.c_str(),
|
||||
"Import evm assembler json to be compiled, assumes input holds the evm assembly in JSON format."
|
||||
)
|
||||
;
|
||||
desc.add(alternativeInputModes);
|
||||
@ -879,6 +899,7 @@ bool CommandLineParser::processArgs()
|
||||
g_strStrictAssembly,
|
||||
g_strYul,
|
||||
g_strImportAst,
|
||||
g_strImportEvmAssemblerJson,
|
||||
}))
|
||||
return false;
|
||||
|
||||
@ -892,6 +913,8 @@ bool CommandLineParser::processArgs()
|
||||
m_options.input.mode = InputMode::StandardJson;
|
||||
else if (m_args.count(g_strAssemble) > 0 || m_args.count(g_strStrictAssembly) > 0 || m_args.count(g_strYul) > 0)
|
||||
m_options.input.mode = InputMode::Assembler;
|
||||
else if (m_args.count(g_strImportEvmAssemblerJson) > 0)
|
||||
m_options.input.mode = InputMode::CompilerWithEvmAssemblyJsonImport;
|
||||
else if (m_args.count(g_strLink) > 0)
|
||||
m_options.input.mode = InputMode::Linker;
|
||||
else if (m_args.count(g_strImportAst) > 0)
|
||||
@ -946,8 +969,8 @@ bool CommandLineParser::processArgs()
|
||||
if (
|
||||
m_options.input.mode != InputMode::Compiler &&
|
||||
m_options.input.mode != InputMode::CompilerWithASTImport &&
|
||||
m_options.input.mode != InputMode::Assembler
|
||||
)
|
||||
m_options.input.mode != InputMode::Assembler &&
|
||||
m_options.input.mode != InputMode::CompilerWithEvmAssemblyJsonImport)
|
||||
{
|
||||
if (!m_args[g_strOptimizeRuns].defaulted())
|
||||
{
|
||||
@ -1127,16 +1150,18 @@ bool CommandLineParser::processArgs()
|
||||
m_options.optimizer.yulSteps = m_args[g_strYulOptimizations].as<string>();
|
||||
}
|
||||
|
||||
if (m_options.input.mode == InputMode::Assembler)
|
||||
if (m_options.input.mode == InputMode::Assembler ||
|
||||
m_options.input.mode == InputMode::CompilerWithEvmAssemblyJsonImport)
|
||||
{
|
||||
vector<string> const nonAssemblyModeOptions = {
|
||||
vector<string> nonAssemblyModeOptions = {
|
||||
// TODO: The list is not complete. Add more.
|
||||
g_strOutputDir,
|
||||
g_strGas,
|
||||
g_strCombinedJson,
|
||||
g_strOptimizeYul,
|
||||
g_strNoOptimizeYul,
|
||||
};
|
||||
if (m_options.input.mode == InputMode::Assembler)
|
||||
nonAssemblyModeOptions.emplace_back(g_strCombinedJson);
|
||||
if (countEnabledOptions(nonAssemblyModeOptions) >= 1)
|
||||
{
|
||||
auto optionEnabled = [&](string const& name){ return m_args.count(name) > 0; };
|
||||
@ -1206,9 +1231,10 @@ bool CommandLineParser::processArgs()
|
||||
serr() << "and automatic translation is not available." << endl;
|
||||
return false;
|
||||
}
|
||||
serr() <<
|
||||
"Warning: Yul is still experimental. Please use the output with care." <<
|
||||
endl;
|
||||
if (m_options.input.mode == InputMode::Assembler)
|
||||
serr() <<
|
||||
"Warning: Yul is still experimental. Please use the output with care." <<
|
||||
endl;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -56,6 +56,7 @@ enum class InputMode
|
||||
StandardJson,
|
||||
Linker,
|
||||
Assembler,
|
||||
CompilerWithEvmAssemblyJsonImport,
|
||||
};
|
||||
|
||||
struct CompilerOutputs
|
||||
|
@ -157,7 +157,7 @@ BOOST_AUTO_TEST_CASE(multiple_input_modes)
|
||||
};
|
||||
string expectedMessage =
|
||||
"The following options are mutually exclusive: "
|
||||
"--help, --license, --version, --standard-json, --link, --assemble, --strict-assembly, --yul, --import-ast. "
|
||||
"--help, --license, --version, --standard-json, --link, --assemble, --strict-assembly, --yul, --import-ast, --import-asm-json. "
|
||||
"Select at most one.\n";
|
||||
|
||||
for (string const& mode1: inputModeOptions)
|
||||
|
Loading…
Reference in New Issue
Block a user