[solc] Add --import-asm-json input mode.

This commit is contained in:
Alexander Arlt 2021-11-04 16:53:32 -05:00
parent 7334420423
commit 235af2b4d1
4 changed files with 190 additions and 142 deletions

View File

@ -634,6 +634,7 @@ bool CommandLineInterface::processInput()
break; break;
case InputMode::Compiler: case InputMode::Compiler:
case InputMode::CompilerWithASTImport: case InputMode::CompilerWithASTImport:
case InputMode::CompilerWithEvmAssemblyJsonImport:
if (!compile()) if (!compile())
return false; return false;
outputCompilationResults(); outputCompilationResults();
@ -657,11 +658,22 @@ void CommandLineInterface::printLicense()
bool CommandLineInterface::compile() 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()); m_compiler = make_unique<CompilerStack>(m_fileReader.reader());
SourceReferenceFormatter formatter(serr(false), *m_compiler, coloredOutput(m_options), m_options.formatting.withErrorIds); if (m_options.input.mode == InputMode::CompilerWithEvmAssemblyJsonImport)
{
}
else
{
SourceReferenceFormatter
formatter(serr(false), *m_compiler, coloredOutput(m_options), m_options.formatting.withErrorIds);
try try
{ {
@ -682,25 +694,20 @@ bool CommandLineInterface::compile()
m_compiler->enableIRGeneration(m_options.compiler.outputs.ir || m_options.compiler.outputs.irOptimized); m_compiler->enableIRGeneration(m_options.compiler.outputs.ir || m_options.compiler.outputs.irOptimized);
m_compiler->enableEwasmGeneration(m_options.compiler.outputs.ewasm); m_compiler->enableEwasmGeneration(m_options.compiler.outputs.ewasm);
m_compiler->enableEvmBytecodeGeneration( m_compiler->enableEvmBytecodeGeneration(
m_options.compiler.estimateGas || m_options.compiler.estimateGas || m_options.compiler.outputs.asm_ || m_options.compiler.outputs.asmJson
m_options.compiler.outputs.asm_ || || m_options.compiler.outputs.opcodes || m_options.compiler.outputs.binary
m_options.compiler.outputs.asmJson || || m_options.compiler.outputs.binaryRuntime
m_options.compiler.outputs.opcodes || || (m_options.compiler.combinedJsonRequests
m_options.compiler.outputs.binary || && (m_options.compiler.combinedJsonRequests->binary
m_options.compiler.outputs.binaryRuntime || || m_options.compiler.combinedJsonRequests->binaryRuntime
(m_options.compiler.combinedJsonRequests && ( || m_options.compiler.combinedJsonRequests->opcodes
m_options.compiler.combinedJsonRequests->binary || || m_options.compiler.combinedJsonRequests->asm_
m_options.compiler.combinedJsonRequests->binaryRuntime || || m_options.compiler.combinedJsonRequests->generatedSources
m_options.compiler.combinedJsonRequests->opcodes || || m_options.compiler.combinedJsonRequests->generatedSourcesRuntime
m_options.compiler.combinedJsonRequests->asm_ || || m_options.compiler.combinedJsonRequests->srcMap
m_options.compiler.combinedJsonRequests->generatedSources || || m_options.compiler.combinedJsonRequests->srcMapRuntime
m_options.compiler.combinedJsonRequests->generatedSourcesRuntime || || m_options.compiler.combinedJsonRequests->funDebug
m_options.compiler.combinedJsonRequests->srcMap || || m_options.compiler.combinedJsonRequests->funDebugRuntime)));
m_options.compiler.combinedJsonRequests->srcMapRuntime ||
m_options.compiler.combinedJsonRequests->funDebug ||
m_options.compiler.combinedJsonRequests->funDebugRuntime
))
);
m_compiler->setOptimiserSettings(m_options.optimiserSettings()); m_compiler->setOptimiserSettings(m_options.optimiserSettings());
@ -757,13 +764,18 @@ bool CommandLineInterface::compile()
return false; return false;
} }
}
return true; return true;
} }
void CommandLineInterface::handleCombinedJSON() 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()) if (!m_options.compiler.combinedJsonRequests.has_value())
return; return;
@ -1095,17 +1107,25 @@ bool CommandLineInterface::assemble(yul::AssemblyStack::Language _language, yul:
void CommandLineInterface::outputCompilationResults() 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(); handleCombinedJSON();
if (m_options.input.mode == InputMode::CompilerWithEvmAssemblyJsonImport)
{
handleBytecode("");
}
else
{
// do we need AST output? // do we need AST output?
handleAst(); handleAst();
if ( if (!m_compiler->compilationSuccessful()
!m_compiler->compilationSuccessful() && && m_options.output.stopAfter == CompilerStack::State::CompilationSuccessful)
m_options.output.stopAfter == CompilerStack::State::CompilationSuccessful
)
{ {
serr() << endl << "Compilation halted after AST generation due to errors." << endl; serr() << endl << "Compilation halted after AST generation due to errors." << endl;
return; return;
@ -1159,5 +1179,6 @@ void CommandLineInterface::outputCompilationResults()
serr() << "Compiler run successful, no output requested." << endl; serr() << "Compiler run successful, no output requested." << endl;
} }
} }
}
} }

View File

@ -46,6 +46,7 @@ static string const g_strAllowPaths = "allow-paths";
static string const g_strBasePath = "base-path"; static string const g_strBasePath = "base-path";
static string const g_strIncludePath = "include-path"; static string const g_strIncludePath = "include-path";
static string const g_strAssemble = "assemble"; 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_strCombinedJson = "combined-json";
static string const g_strErrorRecovery = "error-recovery"; static string const g_strErrorRecovery = "error-recovery";
static string const g_strEVM = "evm"; static string const g_strEVM = "evm";
@ -134,6 +135,7 @@ static map<InputMode, string> const g_inputModeName = {
{InputMode::Compiler, "compiler"}, {InputMode::Compiler, "compiler"},
{InputMode::CompilerWithASTImport, "compiler (AST import)"}, {InputMode::CompilerWithASTImport, "compiler (AST import)"},
{InputMode::Assembler, "assembler"}, {InputMode::Assembler, "assembler"},
{InputMode::CompilerWithEvmAssemblyJsonImport, "assembler (EVM ASM JSON import)"},
{InputMode::StandardJson, "standard JSON"}, {InputMode::StandardJson, "standard JSON"},
{InputMode::Linker, "linker"}, {InputMode::Linker, "linker"},
}; };
@ -321,7 +323,20 @@ bool CommandLineParser::parseInputPathsAndRemappings()
m_options.input.paths.insert(positionalArg); 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)) 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: case InputMode::Version:
solAssert(false); solAssert(false);
case InputMode::Compiler: case InputMode::Compiler:
case InputMode::CompilerWithEvmAssemblyJsonImport:
case InputMode::CompilerWithASTImport: case InputMode::CompilerWithASTImport:
return contains(compilerModeOutputs, _outputName); return contains(compilerModeOutputs, _outputName);
case InputMode::Assembler: case InputMode::Assembler:
@ -644,6 +660,10 @@ General Information)").c_str(),
"Supported Inputs is the output of the --" + g_strStandardJSON + " or the one produced by " "Supported Inputs is the output of the --" + g_strStandardJSON + " or the one produced by "
"--" + g_strCombinedJson + " " + CombinedJsonRequests::componentName(&CombinedJsonRequests::ast)).c_str() "--" + 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); desc.add(alternativeInputModes);
@ -879,6 +899,7 @@ bool CommandLineParser::processArgs()
g_strStrictAssembly, g_strStrictAssembly,
g_strYul, g_strYul,
g_strImportAst, g_strImportAst,
g_strImportEvmAssemblerJson,
})) }))
return false; return false;
@ -892,6 +913,8 @@ bool CommandLineParser::processArgs()
m_options.input.mode = InputMode::StandardJson; 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) 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; 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) else if (m_args.count(g_strLink) > 0)
m_options.input.mode = InputMode::Linker; m_options.input.mode = InputMode::Linker;
else if (m_args.count(g_strImportAst) > 0) else if (m_args.count(g_strImportAst) > 0)
@ -946,8 +969,8 @@ bool CommandLineParser::processArgs()
if ( if (
m_options.input.mode != InputMode::Compiler && m_options.input.mode != InputMode::Compiler &&
m_options.input.mode != InputMode::CompilerWithASTImport && 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()) if (!m_args[g_strOptimizeRuns].defaulted())
{ {
@ -1127,16 +1150,18 @@ bool CommandLineParser::processArgs()
m_options.optimizer.yulSteps = m_args[g_strYulOptimizations].as<string>(); 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. // TODO: The list is not complete. Add more.
g_strOutputDir, g_strOutputDir,
g_strGas, g_strGas,
g_strCombinedJson,
g_strOptimizeYul, g_strOptimizeYul,
g_strNoOptimizeYul, g_strNoOptimizeYul,
}; };
if (m_options.input.mode == InputMode::Assembler)
nonAssemblyModeOptions.emplace_back(g_strCombinedJson);
if (countEnabledOptions(nonAssemblyModeOptions) >= 1) if (countEnabledOptions(nonAssemblyModeOptions) >= 1)
{ {
auto optionEnabled = [&](string const& name){ return m_args.count(name) > 0; }; auto optionEnabled = [&](string const& name){ return m_args.count(name) > 0; };
@ -1206,6 +1231,7 @@ bool CommandLineParser::processArgs()
serr() << "and automatic translation is not available." << endl; serr() << "and automatic translation is not available." << endl;
return false; return false;
} }
if (m_options.input.mode == InputMode::Assembler)
serr() << serr() <<
"Warning: Yul is still experimental. Please use the output with care." << "Warning: Yul is still experimental. Please use the output with care." <<
endl; endl;

View File

@ -56,6 +56,7 @@ enum class InputMode
StandardJson, StandardJson,
Linker, Linker,
Assembler, Assembler,
CompilerWithEvmAssemblyJsonImport,
}; };
struct CompilerOutputs struct CompilerOutputs

View File

@ -157,7 +157,7 @@ BOOST_AUTO_TEST_CASE(multiple_input_modes)
}; };
string expectedMessage = string expectedMessage =
"The following options are mutually exclusive: " "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"; "Select at most one.\n";
for (string const& mode1: inputModeOptions) for (string const& mode1: inputModeOptions)