2014-12-09 12:43:08 +00:00
/*
2016-11-18 23:13:20 +00:00
This file is part of solidity .
2014-12-09 12:43:08 +00:00
2016-11-18 23:13:20 +00:00
solidity is free software : you can redistribute it and / or modify
2014-12-09 12:43:08 +00:00
it under the terms of the GNU General Public License as published by
the Free Software Foundation , either version 3 of the License , or
( at your option ) any later version .
2016-11-18 23:13:20 +00:00
solidity is distributed in the hope that it will be useful ,
2014-12-09 12:43:08 +00:00
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
2016-11-18 23:13:20 +00:00
along with solidity . If not , see < http : //www.gnu.org/licenses/>.
2014-12-09 12:43:08 +00:00
*/
2020-07-17 14:54:12 +00:00
// SPDX-License-Identifier: GPL-3.0
2014-12-09 12:43:08 +00:00
/**
* @ author Lefteris < lefteris @ ethdev . com >
2015-01-09 07:05:52 +00:00
* @ author Gav Wood < g @ ethdev . com >
2014-12-09 12:43:08 +00:00
* @ date 2014
2014-12-09 16:39:34 +00:00
* Solidity command line interface .
2014-12-09 12:43:08 +00:00
*/
2019-02-13 11:07:20 +00:00
# include <solc/CommandLineInterface.h>
2014-12-09 12:43:08 +00:00
2015-09-16 13:55:25 +00:00
# include "solidity/BuildInfo.h"
2017-06-08 09:56:14 +00:00
# include "license.h"
2017-01-26 12:47:57 +00:00
2015-10-20 22:21:52 +00:00
# include <libsolidity/interface/Version.h>
# include <libsolidity/parsing/Parser.h>
# include <libsolidity/ast/ASTJsonConverter.h>
2019-09-11 19:16:35 +00:00
# include <libsolidity/ast/ASTJsonImporter.h>
2015-10-20 22:21:52 +00:00
# include <libsolidity/analysis/NameAndTypeResolver.h>
# include <libsolidity/interface/CompilerStack.h>
2017-02-09 14:55:57 +00:00
# include <libsolidity/interface/StandardCompiler.h>
2015-10-20 22:21:52 +00:00
# include <libsolidity/interface/GasEstimator.h>
2019-09-18 14:44:36 +00:00
# include <libsolidity/interface/DebugSettings.h>
2020-03-24 12:22:25 +00:00
# include <libsolidity/interface/StorageLayout.h>
2019-02-13 11:07:20 +00:00
# include <libyul/AssemblyStack.h>
2020-04-24 12:24:48 +00:00
# include <libyul/optimiser/Suite.h>
2014-12-09 12:43:08 +00:00
2017-01-26 12:47:57 +00:00
# include <libevmasm/Instruction.h>
# include <libevmasm/GasMeter.h>
2019-02-13 11:07:20 +00:00
# include <liblangutil/Exceptions.h>
# include <liblangutil/Scanner.h>
# include <liblangutil/SourceReferenceFormatter.h>
# include <liblangutil/SourceReferenceFormatterHuman.h>
2020-05-20 10:55:12 +00:00
# include <libsmtutil/Exceptions.h>
2020-01-06 10:52:23 +00:00
# include <libsolutil/Common.h>
# include <libsolutil/CommonData.h>
# include <libsolutil/CommonIO.h>
# include <libsolutil/JSON.h>
2017-01-26 12:47:57 +00:00
2018-11-26 23:21:53 +00:00
# include <memory>
2017-01-26 12:47:57 +00:00
# include <boost/filesystem.hpp>
# include <boost/filesystem/operations.hpp>
2020-05-29 22:25:06 +00:00
# include <boost/range/adaptor/transformed.hpp>
2020-06-29 13:11:33 +00:00
# include <boost/range/adaptor/filtered.hpp>
2017-01-26 12:47:57 +00:00
# include <boost/algorithm/string.hpp>
# ifdef _WIN32 // windows
# include <io.h>
# define isatty _isatty
# define fileno _fileno
# else // unix
# include <unistd.h>
# endif
2019-02-11 14:27:08 +00:00
2017-01-26 12:47:57 +00:00
# include <string>
# include <iostream>
# include <fstream>
2019-02-11 14:27:08 +00:00
# if !defined(STDERR_FILENO)
# define STDERR_FILENO 2
# endif
2014-12-09 12:43:08 +00:00
using namespace std ;
2019-12-11 16:31:36 +00:00
using namespace solidity ;
using namespace solidity : : util ;
using namespace solidity : : langutil ;
2014-12-09 12:43:08 +00:00
namespace po = boost : : program_options ;
2019-12-11 16:31:36 +00:00
namespace solidity : : frontend
2014-12-09 12:43:08 +00:00
{
2018-09-13 02:36:14 +00:00
bool g_hasOutput = false ;
std : : ostream & sout ( )
{
g_hasOutput = true ;
return cout ;
}
std : : ostream & serr ( bool _used = true )
{
if ( _used )
g_hasOutput = true ;
return cerr ;
}
# define cout
# define cerr
2017-05-22 13:47:09 +00:00
static string const g_stdinFileNameStr = " <stdin> " ;
2016-10-22 15:02:28 +00:00
static string const g_strAbi = " abi " ;
2017-05-22 13:47:09 +00:00
static string const g_strAllowPaths = " allow-paths " ;
2020-05-13 11:51:49 +00:00
static string const g_strBasePath = " base-path " ;
2016-10-22 15:02:28 +00:00
static string const g_strAsm = " asm " ;
static string const g_strAsmJson = " asm-json " ;
2016-10-22 15:17:49 +00:00
static string const g_strAssemble = " assemble " ;
2016-10-22 15:02:28 +00:00
static string const g_strAst = " ast " ;
static string const g_strAstJson = " ast-json " ;
2017-05-22 13:47:09 +00:00
static string const g_strAstCompactJson = " ast-compact-json " ;
2016-10-22 15:02:28 +00:00
static string const g_strBinary = " bin " ;
static string const g_strBinaryRuntime = " bin-runtime " ;
2016-10-22 15:17:49 +00:00
static string const g_strCombinedJson = " combined-json " ;
2017-05-22 13:47:09 +00:00
static string const g_strCompactJSON = " compact-format " ;
2016-10-22 15:17:49 +00:00
static string const g_strContracts = " contracts " ;
2019-05-27 14:13:27 +00:00
static string const g_strErrorRecovery = " error-recovery " ;
2017-05-23 08:37:51 +00:00
static string const g_strEVM = " evm " ;
static string const g_strEVM15 = " evm15 " ;
2018-02-21 22:43:40 +00:00
static string const g_strEVMVersion = " evm-version " ;
2019-12-09 16:36:12 +00:00
static string const g_strEwasm = " ewasm " ;
2020-05-28 11:17:16 +00:00
static string const g_strGeneratedSources = " generated-sources " ;
static string const g_strGeneratedSourcesRuntime = " generated-sources-runtime " ;
2016-10-22 15:17:49 +00:00
static string const g_strGas = " gas " ;
2016-10-22 15:02:28 +00:00
static string const g_strHelp = " help " ;
2019-09-11 19:16:35 +00:00
static string const g_strImportAst = " import-ast " ;
2016-10-22 15:17:49 +00:00
static string const g_strInputFile = " input-file " ;
static string const g_strInterface = " interface " ;
2018-06-12 17:42:12 +00:00
static string const g_strYul = " yul " ;
2019-11-26 18:12:44 +00:00
static string const g_strYulDialect = " yul-dialect " ;
2019-03-04 22:26:46 +00:00
static string const g_strIR = " ir " ;
2020-02-26 14:50:34 +00:00
static string const g_strIROptimized = " ir-optimized " ;
2019-09-06 17:11:07 +00:00
static string const g_strIPFS = " ipfs " ;
2017-06-08 09:56:14 +00:00
static string const g_strLicense = " license " ;
2016-10-22 15:02:28 +00:00
static string const g_strLibraries = " libraries " ;
static string const g_strLink = " link " ;
2018-01-05 23:09:29 +00:00
static string const g_strMachine = " machine " ;
2016-10-22 15:17:49 +00:00
static string const g_strMetadata = " metadata " ;
2019-09-06 17:11:07 +00:00
static string const g_strMetadataHash = " metadata-hash " ;
2017-05-22 13:47:09 +00:00
static string const g_strMetadataLiteral = " metadata-literal " ;
2020-10-14 15:44:40 +00:00
static string const g_strModelCheckerEngine = " model-checker-engine " ;
2020-11-02 20:20:20 +00:00
static string const g_strModelCheckerTimeout = " model-checker-timeout " ;
2016-10-22 15:17:49 +00:00
static string const g_strNatspecDev = " devdoc " ;
static string const g_strNatspecUser = " userdoc " ;
2019-09-06 17:11:07 +00:00
static string const g_strNone = " none " ;
2019-11-26 15:41:58 +00:00
static string const g_strNoOptimizeYul = " no-optimize-yul " ;
2016-10-22 15:17:49 +00:00
static string const g_strOpcodes = " opcodes " ;
static string const g_strOptimize = " optimize " ;
static string const g_strOptimizeRuns = " optimize-runs " ;
2019-02-21 17:35:41 +00:00
static string const g_strOptimizeYul = " optimize-yul " ;
2020-04-24 12:24:48 +00:00
static string const g_strYulOptimizations = " yul-optimizations " ;
2016-10-22 15:17:49 +00:00
static string const g_strOutputDir = " output-dir " ;
2017-03-10 18:11:01 +00:00
static string const g_strOverwrite = " overwrite " ;
2019-09-18 14:44:36 +00:00
static string const g_strRevertStrings = " revert-strings " ;
2020-03-24 12:22:25 +00:00
static string const g_strStorageLayout = " storage-layout " ;
2020-07-08 20:08:50 +00:00
static string const g_strStopAfter = " stop-after " ;
static string const g_strParsing = " parsing " ;
2019-09-18 14:44:36 +00:00
/// Possible arguments to for --revert-strings
static set < string > const g_revertStringsArgs
{
revertStringsToString ( RevertStrings : : Default ) ,
revertStringsToString ( RevertStrings : : Strip ) ,
revertStringsToString ( RevertStrings : : Debug ) ,
revertStringsToString ( RevertStrings : : VerboseDebug )
} ;
2016-10-22 15:17:49 +00:00
static string const g_strSignatureHashes = " hashes " ;
2016-10-22 15:02:28 +00:00
static string const g_strSources = " sources " ;
static string const g_strSourceList = " sourceList " ;
2016-10-22 15:17:49 +00:00
static string const g_strSrcMap = " srcmap " ;
static string const g_strSrcMapRuntime = " srcmap-runtime " ;
2017-02-09 14:55:57 +00:00
static string const g_strStandardJSON = " standard-json " ;
2018-01-05 23:09:29 +00:00
static string const g_strStrictAssembly = " strict-assembly " ;
2019-09-06 17:11:07 +00:00
static string const g_strSwarm = " swarm " ;
2017-07-03 23:46:30 +00:00
static string const g_strPrettyJson = " pretty-json " ;
2017-05-22 13:47:09 +00:00
static string const g_strVersion = " version " ;
2018-03-16 15:52:04 +00:00
static string const g_strIgnoreMissingFiles = " ignore-missing " ;
2018-11-26 23:21:53 +00:00
static string const g_strColor = " color " ;
static string const g_strNoColor = " no-color " ;
2020-06-04 01:19:47 +00:00
static string const g_strErrorIds = " error-codes " ;
2019-09-06 09:27:06 +00:00
static string const g_strOldReporter = " old-reporter " ;
2016-10-22 15:02:28 +00:00
static string const g_argAbi = g_strAbi ;
2017-07-03 23:46:30 +00:00
static string const g_argPrettyJson = g_strPrettyJson ;
2017-05-22 13:47:09 +00:00
static string const g_argAllowPaths = g_strAllowPaths ;
2020-05-13 11:51:49 +00:00
static string const g_argBasePath = g_strBasePath ;
2016-10-22 15:02:28 +00:00
static string const g_argAsm = g_strAsm ;
static string const g_argAsmJson = g_strAsmJson ;
2016-10-22 15:17:49 +00:00
static string const g_argAssemble = g_strAssemble ;
2017-05-22 13:47:09 +00:00
static string const g_argAstCompactJson = g_strAstCompactJson ;
2016-10-22 15:02:28 +00:00
static string const g_argAstJson = g_strAstJson ;
static string const g_argBinary = g_strBinary ;
static string const g_argBinaryRuntime = g_strBinaryRuntime ;
2016-10-22 15:17:49 +00:00
static string const g_argCombinedJson = g_strCombinedJson ;
2017-05-22 13:47:09 +00:00
static string const g_argCompactJSON = g_strCompactJSON ;
2019-05-27 14:13:27 +00:00
static string const g_argErrorRecovery = g_strErrorRecovery ;
2016-10-22 15:17:49 +00:00
static string const g_argGas = g_strGas ;
static string const g_argHelp = g_strHelp ;
2019-09-11 19:16:35 +00:00
static string const g_argImportAst = g_strImportAst ;
2016-10-22 15:17:49 +00:00
static string const g_argInputFile = g_strInputFile ;
2018-06-12 17:42:12 +00:00
static string const g_argYul = g_strYul ;
2019-03-04 22:26:46 +00:00
static string const g_argIR = g_strIR ;
2020-02-26 14:50:34 +00:00
static string const g_argIROptimized = g_strIROptimized ;
2019-12-09 16:36:12 +00:00
static string const g_argEwasm = g_strEwasm ;
2016-10-22 15:17:49 +00:00
static string const g_argLibraries = g_strLibraries ;
static string const g_argLink = g_strLink ;
2018-01-05 23:09:29 +00:00
static string const g_argMachine = g_strMachine ;
2016-10-22 15:02:28 +00:00
static string const g_argMetadata = g_strMetadata ;
2019-09-06 17:11:07 +00:00
static string const g_argMetadataHash = g_strMetadataHash ;
2017-05-22 13:47:09 +00:00
static string const g_argMetadataLiteral = g_strMetadataLiteral ;
2020-10-14 15:44:40 +00:00
static string const g_argModelCheckerEngine = g_strModelCheckerEngine ;
2020-11-02 20:20:20 +00:00
static string const g_argModelCheckerTimeout = g_strModelCheckerTimeout ;
2016-10-22 15:02:28 +00:00
static string const g_argNatspecDev = g_strNatspecDev ;
static string const g_argNatspecUser = g_strNatspecUser ;
2016-10-22 15:17:49 +00:00
static string const g_argOpcodes = g_strOpcodes ;
2016-10-22 15:02:28 +00:00
static string const g_argOptimize = g_strOptimize ;
static string const g_argOptimizeRuns = g_strOptimizeRuns ;
2016-10-22 15:17:49 +00:00
static string const g_argOutputDir = g_strOutputDir ;
static string const g_argSignatureHashes = g_strSignatureHashes ;
2017-05-22 13:47:09 +00:00
static string const g_argStandardJSON = g_strStandardJSON ;
2020-03-24 12:22:25 +00:00
static string const g_argStorageLayout = g_strStorageLayout ;
2018-01-05 23:09:29 +00:00
static string const g_argStrictAssembly = g_strStrictAssembly ;
2016-10-22 15:17:49 +00:00
static string const g_argVersion = g_strVersion ;
2016-10-22 15:02:28 +00:00
static string const g_stdinFileName = g_stdinFileNameStr ;
2018-03-16 15:52:04 +00:00
static string const g_argIgnoreMissingFiles = g_strIgnoreMissingFiles ;
2018-11-26 23:21:53 +00:00
static string const g_argColor = g_strColor ;
static string const g_argNoColor = g_strNoColor ;
2020-06-04 01:19:47 +00:00
static string const g_argErrorIds = g_strErrorIds ;
2019-09-06 09:27:06 +00:00
static string const g_argOldReporter = g_strOldReporter ;
2014-12-16 22:55:38 +00:00
2015-04-23 12:40:42 +00:00
/// Possible arguments to for --combined-json
2017-05-22 13:47:09 +00:00
static set < string > const g_combinedJsonArgs
{
2016-10-22 15:17:49 +00:00
g_strAbi ,
g_strAsm ,
g_strAst ,
2016-10-22 15:02:28 +00:00
g_strBinary ,
g_strBinaryRuntime ,
2017-05-22 13:47:09 +00:00
g_strCompactJSON ,
2020-05-28 11:17:16 +00:00
g_strGeneratedSources ,
g_strGeneratedSourcesRuntime ,
2016-10-22 15:02:28 +00:00
g_strInterface ,
g_strMetadata ,
g_strNatspecUser ,
2016-10-22 15:17:49 +00:00
g_strNatspecDev ,
g_strOpcodes ,
2017-06-13 16:02:57 +00:00
g_strSignatureHashes ,
2016-10-22 15:17:49 +00:00
g_strSrcMap ,
2020-03-24 12:22:25 +00:00
g_strSrcMapRuntime ,
g_strStorageLayout
2015-04-23 12:40:42 +00:00
} ;
2017-05-23 08:37:51 +00:00
/// Possible arguments to for --machine
static set < string > const g_machineArgs
{
g_strEVM ,
g_strEVM15 ,
2019-12-09 16:36:12 +00:00
g_strEwasm
2017-05-23 08:37:51 +00:00
} ;
2019-11-26 18:12:44 +00:00
/// Possible arguments to for --yul-dialect
static set < string > const g_yulDialectArgs
{
g_strEVM ,
2019-12-09 16:36:12 +00:00
g_strEwasm
2019-11-26 18:12:44 +00:00
} ;
2019-09-06 17:11:07 +00:00
/// Possible arguments to for --metadata-hash
static set < string > const g_metadataHashArgs
{
g_strIPFS ,
g_strSwarm ,
g_strNone
} ;
2014-12-09 12:43:08 +00:00
static void version ( )
{
2018-09-13 02:36:14 +00:00
sout ( ) < <
2015-07-08 17:32:43 +00:00
" solc, the solidity compiler commandline interface " < <
endl < <
" Version: " < <
2019-12-11 16:31:36 +00:00
solidity : : frontend : : VersionString < <
2015-07-08 17:32:43 +00:00
endl ;
2014-12-09 12:43:08 +00:00
exit ( 0 ) ;
}
2017-06-08 09:56:14 +00:00
static void license ( )
{
2018-09-13 02:36:14 +00:00
sout ( ) < < otherLicenses < < endl ;
2017-06-08 09:56:14 +00:00
// This is a static variable generated by cmake from LICENSE.txt
2018-09-13 02:36:14 +00:00
sout ( ) < < licenseText < < endl ;
2017-06-08 09:56:14 +00:00
exit ( 0 ) ;
}
2015-04-23 12:40:42 +00:00
static bool needsHumanTargetedStdout ( po : : variables_map const & _args )
2014-12-09 12:43:08 +00:00
{
2015-10-21 14:43:31 +00:00
if ( _args . count ( g_argGas ) )
return true ;
2016-10-22 15:02:28 +00:00
if ( _args . count ( g_argOutputDir ) )
2015-10-21 14:43:31 +00:00
return false ;
for ( string const & arg : {
2016-10-22 15:02:28 +00:00
g_argAbi ,
g_argAsm ,
g_argAsmJson ,
2015-10-21 14:43:31 +00:00
g_argAstJson ,
2016-10-22 15:02:28 +00:00
g_argBinary ,
g_argBinaryRuntime ,
2016-10-22 15:17:49 +00:00
g_argMetadata ,
g_argNatspecUser ,
g_argNatspecDev ,
g_argOpcodes ,
2020-03-24 12:22:25 +00:00
g_argSignatureHashes ,
g_argStorageLayout
2015-10-21 14:43:31 +00:00
} )
if ( _args . count ( arg ) )
return true ;
return false ;
2014-12-09 12:43:08 +00:00
}
2020-07-08 20:08:50 +00:00
bool checkMutuallyExclusive ( boost : : program_options : : variables_map const & args , std : : string const & _optionA , std : : string const & _optionB )
{
if ( args . count ( _optionA ) & & args . count ( _optionB ) )
{
serr ( ) < < " Option " < < _optionA < < " and " < < _optionB < < " are mutually exclusive. " < < endl ;
return false ;
}
return true ;
}
2014-12-09 19:29:29 +00:00
void CommandLineInterface : : handleBinary ( string const & _contract )
2014-12-09 12:43:08 +00:00
{
2016-10-22 15:02:28 +00:00
if ( m_args . count ( g_argBinary ) )
2014-12-09 12:43:08 +00:00
{
2017-01-06 01:08:34 +00:00
if ( m_args . count ( g_argOutputDir ) )
2018-10-04 12:55:02 +00:00
createFile ( m_compiler - > filesystemFriendlyName ( _contract ) + " .bin " , objectWithLinkRefsHex ( m_compiler - > object ( _contract ) ) ) ;
2015-08-10 10:40:02 +00:00
else
{
2019-11-21 19:08:50 +00:00
sout ( ) < < " Binary: " < < endl ;
2018-09-13 02:36:14 +00:00
sout ( ) < < objectWithLinkRefsHex ( m_compiler - > object ( _contract ) ) < < endl ;
2015-08-10 10:40:02 +00:00
}
2014-12-09 19:29:29 +00:00
}
2016-10-22 15:02:28 +00:00
if ( m_args . count ( g_argBinaryRuntime ) )
2015-08-24 15:24:48 +00:00
{
2016-10-22 15:02:28 +00:00
if ( m_args . count ( g_argOutputDir ) )
2018-10-04 12:55:02 +00:00
createFile ( m_compiler - > filesystemFriendlyName ( _contract ) + " .bin-runtime " , objectWithLinkRefsHex ( m_compiler - > runtimeObject ( _contract ) ) ) ;
2015-08-24 15:24:48 +00:00
else
{
2019-11-21 19:08:50 +00:00
sout ( ) < < " Binary of the runtime part: " < < endl ;
2018-09-13 02:36:14 +00:00
sout ( ) < < objectWithLinkRefsHex ( m_compiler - > runtimeObject ( _contract ) ) < < endl ;
2015-08-24 15:24:48 +00:00
}
}
2014-12-09 19:29:29 +00:00
}
2014-12-09 17:17:54 +00:00
2014-12-09 19:29:29 +00:00
void CommandLineInterface : : handleOpcode ( string const & _contract )
{
2016-10-22 15:02:28 +00:00
if ( m_args . count ( g_argOutputDir ) )
2019-12-11 16:31:36 +00:00
createFile ( m_compiler - > filesystemFriendlyName ( _contract ) + " .opcode " , evmasm : : disassemble ( m_compiler - > object ( _contract ) . bytecode ) ) ;
2015-08-10 10:40:02 +00:00
else
2014-12-09 19:29:29 +00:00
{
2019-11-21 19:08:50 +00:00
sout ( ) < < " Opcodes: " < < endl ;
2019-12-11 16:31:36 +00:00
sout ( ) < < std : : uppercase < < evmasm : : disassemble ( m_compiler - > object ( _contract ) . bytecode ) ;
2018-09-13 02:36:14 +00:00
sout ( ) < < endl ;
2014-12-09 19:29:29 +00:00
}
2014-12-09 12:43:08 +00:00
}
2019-03-04 22:26:46 +00:00
void CommandLineInterface : : handleIR ( string const & _contractName )
{
2020-02-26 14:50:34 +00:00
if ( ! m_args . count ( g_argIR ) )
return ;
if ( m_args . count ( g_argOutputDir ) )
createFile ( m_compiler - > filesystemFriendlyName ( _contractName ) + " .yul " , m_compiler - > yulIR ( _contractName ) ) ;
else
2019-03-04 22:26:46 +00:00
{
2020-02-26 14:50:34 +00:00
sout ( ) < < " IR: " < < endl ;
sout ( ) < < m_compiler - > yulIR ( _contractName ) < < endl ;
}
}
void CommandLineInterface : : handleIROptimized ( string const & _contractName )
{
if ( ! m_args . count ( g_argIROptimized ) )
return ;
if ( m_args . count ( g_argOutputDir ) )
createFile ( m_compiler - > filesystemFriendlyName ( _contractName ) + " _opt.yul " , m_compiler - > yulIROptimized ( _contractName ) ) ;
else
{
sout ( ) < < " Optimized IR: " < < endl ;
sout ( ) < < m_compiler - > yulIROptimized ( _contractName ) < < endl ;
2019-03-04 22:26:46 +00:00
}
}
2019-12-09 16:36:12 +00:00
void CommandLineInterface : : handleEwasm ( string const & _contractName )
2019-06-18 16:11:04 +00:00
{
2020-02-26 14:50:34 +00:00
if ( ! m_args . count ( g_argEwasm ) )
return ;
if ( m_args . count ( g_argOutputDir ) )
2019-06-18 16:11:04 +00:00
{
2020-02-26 14:50:34 +00:00
createFile ( m_compiler - > filesystemFriendlyName ( _contractName ) + " .wast " , m_compiler - > ewasm ( _contractName ) ) ;
createFile (
m_compiler - > filesystemFriendlyName ( _contractName ) + " .wasm " ,
asString ( m_compiler - > ewasmObject ( _contractName ) . bytecode )
) ;
}
else
{
sout ( ) < < " Ewasm text: " < < endl ;
sout ( ) < < m_compiler - > ewasm ( _contractName ) < < endl ;
sout ( ) < < " Ewasm binary (hex): " < < m_compiler - > ewasmObject ( _contractName ) . toHex ( ) < < endl ;
2019-06-18 16:11:04 +00:00
}
}
2014-12-09 19:29:29 +00:00
void CommandLineInterface : : handleBytecode ( string const & _contract )
{
2016-10-22 15:02:28 +00:00
if ( m_args . count ( g_argOpcodes ) )
2014-12-09 19:29:29 +00:00
handleOpcode ( _contract ) ;
2018-08-06 16:32:18 +00:00
if ( m_args . count ( g_argBinary ) | | m_args . count ( g_argBinaryRuntime ) )
2014-12-09 19:29:29 +00:00
handleBinary ( _contract ) ;
}
2015-05-04 14:21:44 +00:00
void CommandLineInterface : : handleSignatureHashes ( string const & _contract )
{
2015-05-05 15:08:30 +00:00
if ( ! m_args . count ( g_argSignatureHashes ) )
return ;
2017-06-15 10:35:30 +00:00
Json : : Value methodIdentifiers = m_compiler - > methodIdentifiers ( _contract ) ;
2015-05-04 14:21:44 +00:00
string out ;
2017-06-15 10:35:30 +00:00
for ( auto const & name : methodIdentifiers . getMemberNames ( ) )
out + = methodIdentifiers [ name ] . asString ( ) + " : " + name + " \n " ;
2015-05-04 14:21:44 +00:00
2016-10-22 15:02:28 +00:00
if ( m_args . count ( g_argOutputDir ) )
2017-02-05 19:19:29 +00:00
createFile ( m_compiler - > filesystemFriendlyName ( _contract ) + " .signatures " , out ) ;
2015-08-10 10:40:02 +00:00
else
2019-11-21 19:08:50 +00:00
sout ( ) < < " Function signatures: " < < endl < < out ;
2015-05-04 14:21:44 +00:00
}
2017-05-19 15:10:32 +00:00
void CommandLineInterface : : handleMetadata ( string const & _contract )
2016-11-14 10:46:43 +00:00
{
if ( ! m_args . count ( g_argMetadata ) )
return ;
2017-05-19 15:10:32 +00:00
string data = m_compiler - > metadata ( _contract ) ;
2017-05-06 17:02:56 +00:00
if ( m_args . count ( g_argOutputDir ) )
2017-02-05 19:19:29 +00:00
createFile ( m_compiler - > filesystemFriendlyName ( _contract ) + " _meta.json " , data ) ;
2016-11-14 10:46:43 +00:00
else
2019-11-21 19:08:50 +00:00
sout ( ) < < " Metadata: " < < endl < < data < < endl ;
2016-11-14 10:46:43 +00:00
}
2017-05-06 17:02:56 +00:00
void CommandLineInterface : : handleABI ( string const & _contract )
{
if ( ! m_args . count ( g_argAbi ) )
return ;
2020-04-27 08:28:54 +00:00
string data = jsonCompactPrint ( removeNullMembers ( m_compiler - > contractABI ( _contract ) ) ) ;
2017-05-06 17:02:56 +00:00
if ( m_args . count ( g_argOutputDir ) )
createFile ( m_compiler - > filesystemFriendlyName ( _contract ) + " .abi " , data ) ;
else
2019-11-21 19:08:50 +00:00
sout ( ) < < " Contract JSON ABI " < < endl < < data < < endl ;
2017-05-06 17:02:56 +00:00
}
2020-03-24 12:22:25 +00:00
void CommandLineInterface : : handleStorageLayout ( string const & _contract )
{
if ( ! m_args . count ( g_argStorageLayout ) )
return ;
2020-04-27 08:28:54 +00:00
string data = jsonCompactPrint ( removeNullMembers ( m_compiler - > storageLayout ( _contract ) ) ) ;
2020-03-24 12:22:25 +00:00
if ( m_args . count ( g_argOutputDir ) )
createFile ( m_compiler - > filesystemFriendlyName ( _contract ) + " _storage.json " , data ) ;
else
sout ( ) < < " Contract Storage Layout: " < < endl < < data < < endl ;
}
2017-07-27 10:28:04 +00:00
void CommandLineInterface : : handleNatspec ( bool _natspecDev , string const & _contract )
2014-12-09 12:43:08 +00:00
{
std : : string argName ;
std : : string suffix ;
std : : string title ;
2017-07-27 10:28:04 +00:00
if ( _natspecDev )
2014-12-09 12:43:08 +00:00
{
2016-10-22 15:02:28 +00:00
argName = g_argNatspecDev ;
2014-12-09 12:43:08 +00:00
suffix = " .docdev " ;
title = " Developer Documentation " ;
2017-07-27 10:28:04 +00:00
}
else
{
argName = g_argNatspecUser ;
suffix = " .docuser " ;
title = " User Documentation " ;
2014-12-09 12:43:08 +00:00
}
if ( m_args . count ( argName ) )
{
2019-12-11 16:31:36 +00:00
std : : string output = jsonPrettyPrint (
2020-04-27 08:28:54 +00:00
removeNullMembers (
_natspecDev ?
m_compiler - > natspecDev ( _contract ) :
m_compiler - > natspecUser ( _contract )
)
2017-07-27 10:28:04 +00:00
) ;
2016-11-15 01:04:00 +00:00
2016-10-22 15:02:28 +00:00
if ( m_args . count ( g_argOutputDir ) )
2017-02-05 19:19:29 +00:00
createFile ( m_compiler - > filesystemFriendlyName ( _contract ) + suffix , output ) ;
2015-08-10 10:40:02 +00:00
else
{
2018-09-13 02:36:14 +00:00
sout ( ) < < title < < endl ;
sout ( ) < < output < < endl ;
2015-08-10 10:40:02 +00:00
}
2014-12-09 12:43:08 +00:00
}
}
2015-05-22 12:19:58 +00:00
void CommandLineInterface : : handleGasEstimation ( string const & _contract )
{
2017-04-10 13:52:13 +00:00
Json : : Value estimates = m_compiler - > gasEstimates ( _contract ) ;
2018-09-13 02:36:14 +00:00
sout ( ) < < " Gas estimation: " < < endl ;
2017-04-10 13:52:13 +00:00
if ( estimates [ " creation " ] . isObject ( ) )
2015-05-22 12:19:58 +00:00
{
2017-04-10 13:52:13 +00:00
Json : : Value creation = estimates [ " creation " ] ;
2018-09-13 02:36:14 +00:00
sout ( ) < < " construction: " < < endl ;
sout ( ) < < " " < < creation [ " executionCost " ] . asString ( ) ;
sout ( ) < < " + " < < creation [ " codeDepositCost " ] . asString ( ) ;
sout ( ) < < " = " < < creation [ " totalCost " ] . asString ( ) < < endl ;
2015-05-22 12:19:58 +00:00
}
2017-04-10 13:52:13 +00:00
if ( estimates [ " external " ] . isObject ( ) )
2015-05-26 09:27:59 +00:00
{
2017-04-10 13:52:13 +00:00
Json : : Value externalFunctions = estimates [ " external " ] ;
2018-09-13 02:36:14 +00:00
sout ( ) < < " external: " < < endl ;
2017-04-10 13:52:13 +00:00
for ( auto const & name : externalFunctions . getMemberNames ( ) )
2015-05-22 12:19:58 +00:00
{
2017-04-10 13:52:13 +00:00
if ( name . empty ( ) )
2018-09-13 02:36:14 +00:00
sout ( ) < < " fallback: \t " ;
2017-04-10 13:52:13 +00:00
else
2018-09-13 02:36:14 +00:00
sout ( ) < < " " < < name < < " : \t " ;
sout ( ) < < externalFunctions [ name ] . asString ( ) < < endl ;
2015-06-18 15:38:26 +00:00
}
2017-04-10 13:52:13 +00:00
}
if ( estimates [ " internal " ] . isObject ( ) )
{
Json : : Value internalFunctions = estimates [ " internal " ] ;
2018-09-13 02:36:14 +00:00
sout ( ) < < " internal: " < < endl ;
2017-04-10 13:52:13 +00:00
for ( auto const & name : internalFunctions . getMemberNames ( ) )
2015-05-26 09:27:59 +00:00
{
2018-09-13 02:36:14 +00:00
sout ( ) < < " " < < name < < " : \t " ;
sout ( ) < < internalFunctions [ name ] . asString ( ) < < endl ;
2015-05-22 12:19:58 +00:00
}
2015-05-26 09:27:59 +00:00
}
2015-05-22 12:19:58 +00:00
}
2018-03-16 15:52:04 +00:00
bool CommandLineInterface : : readInputFilesAndConfigureRemappings ( )
2016-01-25 18:42:17 +00:00
{
2018-03-16 15:52:04 +00:00
bool ignoreMissing = m_args . count ( g_argIgnoreMissingFiles ) ;
2016-08-16 15:06:56 +00:00
bool addStdin = false ;
2018-04-24 13:18:12 +00:00
if ( m_args . count ( g_argInputFile ) )
2016-10-22 15:02:28 +00:00
for ( string path : m_args [ g_argInputFile ] . as < vector < string > > ( ) )
2016-01-25 18:42:17 +00:00
{
2016-06-07 17:44:32 +00:00
auto eq = find ( path . begin ( ) , path . end ( ) , ' = ' ) ;
if ( eq ! = path . end ( ) )
2018-08-09 18:37:49 +00:00
{
if ( auto r = CompilerStack : : parseRemapping ( path ) )
{
m_remappings . emplace_back ( std : : move ( * r ) ) ;
path = string ( eq + 1 , path . end ( ) ) ;
}
else
{
2018-09-13 02:36:14 +00:00
serr ( ) < < " Invalid remapping: \" " < < path < < " \" . " < < endl ;
2018-08-09 18:37:49 +00:00
return false ;
}
}
2016-08-16 15:06:56 +00:00
else if ( path = = " - " )
addStdin = true ;
2016-01-25 18:42:17 +00:00
else
{
2016-06-07 17:44:32 +00:00
auto infile = boost : : filesystem : : path ( path ) ;
if ( ! boost : : filesystem : : exists ( infile ) )
2016-01-25 18:42:17 +00:00
{
2018-03-16 15:52:04 +00:00
if ( ! ignoreMissing )
{
2018-09-13 02:36:14 +00:00
serr ( ) < < infile < < " is not found. " < < endl ;
2018-03-16 15:52:04 +00:00
return false ;
}
else
2018-09-13 02:36:14 +00:00
serr ( ) < < infile < < " is not found. Skipping. " < < endl ;
2018-03-16 15:52:04 +00:00
2016-01-25 18:42:17 +00:00
continue ;
}
2016-06-07 17:44:32 +00:00
if ( ! boost : : filesystem : : is_regular_file ( infile ) )
2016-01-25 18:42:17 +00:00
{
2018-03-16 15:52:04 +00:00
if ( ! ignoreMissing )
{
2018-09-13 02:36:14 +00:00
serr ( ) < < infile < < " is not a valid file. " < < endl ;
2018-03-16 15:52:04 +00:00
return false ;
}
else
2018-09-13 02:36:14 +00:00
serr ( ) < < infile < < " is not a valid file. Skipping. " < < endl ;
2018-03-16 15:52:04 +00:00
2016-01-25 18:42:17 +00:00
continue ;
}
2019-12-11 16:31:36 +00:00
m_sourceCodes [ infile . generic_string ( ) ] = readFileAsString ( infile . string ( ) ) ;
2016-06-07 17:44:32 +00:00
path = boost : : filesystem : : canonical ( infile ) . string ( ) ;
2016-01-25 18:42:17 +00:00
}
2016-06-07 17:44:32 +00:00
m_allowedDirectories . push_back ( boost : : filesystem : : path ( path ) . remove_filename ( ) ) ;
2016-01-25 18:42:17 +00:00
}
2016-08-16 15:06:56 +00:00
if ( addStdin )
2019-12-11 16:31:36 +00:00
m_sourceCodes [ g_stdinFileName ] = readStandardInput ( ) ;
2018-04-24 13:18:12 +00:00
if ( m_sourceCodes . size ( ) = = 0 )
{
2018-09-13 02:36:14 +00:00
serr ( ) < < " No input files given. If you wish to use the standard input please specify \" - \" explicitly. " < < endl ;
2018-04-24 13:18:12 +00:00
return false ;
}
2018-03-16 15:52:04 +00:00
return true ;
2016-01-25 18:42:17 +00:00
}
2015-09-11 17:35:01 +00:00
bool CommandLineInterface : : parseLibraryOption ( string const & _input )
{
namespace fs = boost : : filesystem ;
2017-03-14 10:58:43 +00:00
string data = _input ;
try
{
if ( fs : : is_regular_file ( _input ) )
2017-10-18 11:34:29 +00:00
data = readFileAsString ( _input ) ;
2017-03-14 10:58:43 +00:00
}
catch ( fs : : filesystem_error const & )
{
// Thrown e.g. if path is too long.
}
2015-09-11 17:35:01 +00:00
vector < string > libraries ;
boost : : split ( libraries , data , boost : : is_space ( ) | | boost : : is_any_of ( " , " ) , boost : : token_compress_on ) ;
for ( string const & lib : libraries )
if ( ! lib . empty ( ) )
{
2017-01-30 19:41:33 +00:00
//search for last colon in string as our binaries output placeholders in the form of file:Name
//so we need to search for the second `:` in the string
auto colon = lib . rfind ( ' : ' ) ;
2015-09-11 17:35:01 +00:00
if ( colon = = string : : npos )
{
2018-09-13 02:36:14 +00:00
serr ( ) < < " Colon separator missing in library address specifier \" " < < lib < < " \" " < < endl ;
2015-09-11 17:35:01 +00:00
return false ;
}
2020-06-03 08:27:23 +00:00
string libName ( lib . begin ( ) , lib . begin ( ) + static_cast < ptrdiff_t > ( colon ) ) ;
string addrString ( lib . begin ( ) + static_cast < ptrdiff_t > ( colon ) + 1 , lib . end ( ) ) ;
2015-09-11 17:35:01 +00:00
boost : : trim ( libName ) ;
boost : : trim ( addrString ) ;
2018-10-08 20:31:08 +00:00
if ( addrString . substr ( 0 , 2 ) = = " 0x " )
addrString = addrString . substr ( 2 ) ;
if ( addrString . empty ( ) )
{
2019-11-21 19:08:50 +00:00
serr ( ) < < " Empty address provided for library \" " < < libName < < " \" : " < < endl ;
2018-09-13 02:36:14 +00:00
serr ( ) < < " Note that there should not be any whitespace after the colon. " < < endl ;
2018-10-08 20:31:08 +00:00
return false ;
}
else if ( addrString . length ( ) ! = 40 )
{
2018-09-13 02:36:14 +00:00
serr ( ) < < " Invalid length for address for library \" " < < libName < < " \" : " < < addrString . length ( ) < < " instead of 40 characters. " < < endl ;
2018-10-08 20:31:08 +00:00
return false ;
}
2017-01-24 22:36:07 +00:00
if ( ! passesAddressChecksum ( addrString , false ) )
{
2018-09-13 02:36:14 +00:00
serr ( ) < < " Invalid checksum on address for library \" " < < libName < < " \" : " < < addrString < < endl ;
2019-12-11 16:31:36 +00:00
serr ( ) < < " The correct checksum is " < < getChecksummedAddress ( addrString ) < < endl ;
2017-01-24 22:36:07 +00:00
return false ;
}
2015-09-11 17:35:01 +00:00
bytes binAddr = fromHex ( addrString ) ;
h160 address ( binAddr , h160 : : AlignRight ) ;
if ( binAddr . size ( ) > 20 | | address = = h160 ( ) )
{
2018-09-13 02:36:14 +00:00
serr ( ) < < " Invalid address for library \" " < < libName < < " \" : " < < addrString < < endl ;
2015-09-11 17:35:01 +00:00
return false ;
}
m_libraries [ libName ] = address ;
}
return true ;
}
2019-09-11 19:16:35 +00:00
map < string , Json : : Value > CommandLineInterface : : parseAstFromInput ( )
{
map < string , Json : : Value > sourceJsons ;
map < string , string > tmpSources ;
for ( auto const & srcPair : m_sourceCodes )
{
Json : : Value ast ;
astAssert ( jsonParseStrict ( srcPair . second , ast ) , " Input file could not be parsed to JSON " ) ;
astAssert ( ast . isMember ( " sources " ) , " Invalid Format for import-JSON: Must have 'sources'-object " ) ;
for ( auto & src : ast [ " sources " ] . getMemberNames ( ) )
{
std : : string astKey = ast [ " sources " ] [ src ] . isMember ( " ast " ) ? " ast " : " AST " ;
astAssert ( ast [ " sources " ] [ src ] . isMember ( astKey ) , " astkey is not member " ) ;
astAssert ( ast [ " sources " ] [ src ] [ astKey ] [ " nodeType " ] . asString ( ) = = " SourceUnit " , " Top-level node should be a 'SourceUnit' " ) ;
astAssert ( sourceJsons . count ( src ) = = 0 , " All sources must have unique names " ) ;
sourceJsons . emplace ( src , move ( ast [ " sources " ] [ src ] [ astKey ] ) ) ;
tmpSources [ src ] = util : : jsonCompactPrint ( ast ) ;
}
}
m_sourceCodes = std : : move ( tmpSources ) ;
return sourceJsons ;
}
2015-08-10 10:44:59 +00:00
void CommandLineInterface : : createFile ( string const & _fileName , string const & _data )
{
namespace fs = boost : : filesystem ;
// create directory if not existent
2016-10-22 15:02:28 +00:00
fs : : path p ( m_args . at ( g_argOutputDir ) . as < string > ( ) ) ;
2017-02-05 19:39:30 +00:00
// Do not try creating the directory if the first item is . or ..
if ( p . filename ( ) ! = " . " & & p . filename ( ) ! = " .. " )
fs : : create_directories ( p ) ;
2015-08-19 23:09:39 +00:00
string pathName = ( p / _fileName ) . string ( ) ;
2017-03-10 18:11:01 +00:00
if ( fs : : exists ( pathName ) & & ! m_args . count ( g_strOverwrite ) )
{
2020-05-08 13:54:17 +00:00
serr ( ) < < " Refusing to overwrite existing file \" " < < pathName < < " \" (use -- " < < g_strOverwrite < < " to force). " < < endl ;
2017-03-10 18:11:01 +00:00
m_error = true ;
return ;
}
2015-08-19 23:09:39 +00:00
ofstream outFile ( pathName ) ;
2015-07-21 13:29:15 +00:00
outFile < < _data ;
2015-08-10 10:44:59 +00:00
if ( ! outFile )
2015-08-19 23:09:39 +00:00
BOOST_THROW_EXCEPTION ( FileError ( ) < < errinfo_comment ( " Could not write to file: " + pathName ) ) ;
2015-08-10 10:44:59 +00:00
}
2017-07-03 23:46:30 +00:00
void CommandLineInterface : : createJson ( string const & _fileName , string const & _json )
2017-05-22 20:39:38 +00:00
{
2017-07-03 23:46:30 +00:00
createFile ( boost : : filesystem : : basename ( _fileName ) + string ( " .json " ) , _json ) ;
2017-05-22 20:39:38 +00:00
}
2015-08-10 10:44:59 +00:00
bool CommandLineInterface : : parseArguments ( int _argc , char * * _argv )
2014-12-09 16:39:34 +00:00
{
2018-09-13 02:36:14 +00:00
g_hasOutput = false ;
2014-12-09 16:39:34 +00:00
// Declare the supported options.
2020-05-08 13:54:17 +00:00
po : : options_description desc ( ( R " (solc, the Solidity commandline compiler.
2017-06-08 09:56:14 +00:00
This program comes with ABSOLUTELY NO WARRANTY . This is free software , and you
2020-05-08 13:54:17 +00:00
are welcome to redistribute it under certain conditions . See ' solc - - ) " + g_strLicense + R " ( '
2017-06-08 09:56:14 +00:00
for details .
2015-08-19 23:09:39 +00:00
Usage : solc [ options ] [ input_file . . . ]
2016-08-16 15:06:56 +00:00
Compiles the given Solidity input files ( or the standard input if none given or
" - " is used as a file name ) and outputs the components specified in the options
at standard output or in files in the output directory , if specified .
2016-10-15 06:36:40 +00:00
Imports are automatically read from the filesystem , but it is also possible to
remap paths using the context : prefix = path syntax .
Example :
2020-05-08 13:54:17 +00:00
solc - - ) " + g_argBinary + R " ( - o / tmp / solcoutput dapp - bin = / usr / local / lib / dapp - bin contract . sol
2015-08-19 23:09:39 +00:00
2020-05-29 20:28:07 +00:00
General Information ) " ).c_str(),
2015-08-19 23:09:39 +00:00
po : : options_description : : m_default_line_length ,
2017-06-08 09:56:14 +00:00
po : : options_description : : m_default_line_length - 23
) ;
2014-12-09 16:39:34 +00:00
desc . add_options ( )
2016-10-22 15:02:28 +00:00
( g_argHelp . c_str ( ) , " Show help message and exit. " )
( g_argVersion . c_str ( ) , " Show version and exit. " )
2017-06-08 09:56:14 +00:00
( g_strLicense . c_str ( ) , " Show licensing information and exit. " )
2020-05-29 20:28:07 +00:00
;
po : : options_description inputOptions ( " Input Options " ) ;
inputOptions . add_options ( )
2018-02-21 22:43:40 +00:00
(
2020-05-29 20:28:07 +00:00
g_argBasePath . c_str ( ) ,
po : : value < string > ( ) - > value_name ( " path " ) ,
" Use the given path as the root of the source tree instead of the root of the filesystem. "
2018-02-21 22:43:40 +00:00
)
2015-09-11 17:35:01 +00:00
(
2020-05-29 20:28:07 +00:00
g_argAllowPaths . c_str ( ) ,
po : : value < string > ( ) - > value_name ( " path(s) " ) ,
" Allow a given path for imports. A list of paths can be supplied by separating them with a comma. "
2015-09-11 17:35:01 +00:00
)
2019-09-18 14:44:36 +00:00
(
2020-05-29 20:28:07 +00:00
g_argIgnoreMissingFiles . c_str ( ) ,
" Ignore missing files. "
2015-09-11 17:35:01 +00:00
)
2019-09-18 14:44:36 +00:00
(
2020-05-29 20:28:07 +00:00
g_argErrorRecovery . c_str ( ) ,
" Enables additional parser error recovery. "
2019-09-18 14:44:36 +00:00
)
2020-05-29 20:28:07 +00:00
;
desc . add ( inputOptions ) ;
po : : options_description outputOptions ( " Output Options " ) ;
outputOptions . add_options ( )
2015-08-19 23:09:39 +00:00
(
2016-10-22 15:02:28 +00:00
( g_argOutputDir + " ,o " ) . c_str ( ) ,
2015-08-19 23:09:39 +00:00
po : : value < string > ( ) - > value_name ( " path " ) ,
" If given, creates one file per component and contract/file at the specified directory. "
)
2015-04-23 12:40:42 +00:00
(
2020-06-05 22:13:01 +00:00
g_strOverwrite . c_str ( ) ,
" Overwrite existing files (used together with -o). "
)
2015-04-23 12:40:42 +00:00
(
2020-05-29 20:28:07 +00:00
g_strEVMVersion . c_str ( ) ,
po : : value < string > ( ) - > value_name ( " version " ) ,
" Select desired EVM version. Either homestead, tangerineWhistle, spuriousDragon, "
" byzantium, constantinople, petersburg, istanbul (default) or berlin. "
2015-04-23 12:40:42 +00:00
)
2020-06-05 22:13:01 +00:00
(
2020-05-29 20:28:07 +00:00
g_strRevertStrings . c_str ( ) ,
po : : value < string > ( ) - > value_name ( boost : : join ( g_revertStringsArgs , " , " ) ) ,
" Strip revert (and require) reason strings or add additional debugging information. "
2020-06-05 22:13:01 +00:00
)
2020-07-08 20:08:50 +00:00
(
g_strStopAfter . c_str ( ) ,
po : : value < string > ( ) - > value_name ( " stage " ) ,
" Stop execution after the given compiler stage. Valid options: \" parsing \" . "
)
2020-05-29 20:28:07 +00:00
;
desc . add ( outputOptions ) ;
po : : options_description alternativeInputModes ( " Alternative Input Modes " ) ;
alternativeInputModes . add_options ( )
2017-02-09 14:55:57 +00:00
(
g_argStandardJSON . c_str ( ) ,
2017-04-24 12:22:39 +00:00
" Switch to Standard JSON input / output mode, ignoring all options. "
2020-02-04 02:50:18 +00:00
" It reads from standard input, if no input file was given, otherwise it reads from the provided input file. The result will be written to standard output. "
2017-02-09 14:55:57 +00:00
)
2019-09-11 19:16:35 +00:00
(
2020-05-29 20:28:07 +00:00
g_argLink . c_str ( ) ,
( " Switch to linker mode, ignoring all options apart from -- " + g_argLibraries + " "
" and modify binaries in place. " ) . c_str ( )
2019-09-11 19:16:35 +00:00
)
2016-02-22 01:13:41 +00:00
(
2016-10-22 15:02:28 +00:00
g_argAssemble . c_str ( ) ,
2020-05-08 13:54:17 +00:00
( " Switch to assembly mode, ignoring all options except "
2020-05-08 16:20:14 +00:00
" -- " + g_argMachine + " , -- " + g_strYulDialect + " , -- " + g_argOptimize + " and -- " + g_strYulOptimizations + " "
2020-05-08 13:54:17 +00:00
" and assumes input is assembly. " ) . c_str ( )
2017-05-23 08:37:51 +00:00
)
(
2018-06-12 17:42:12 +00:00
g_argYul . c_str ( ) ,
2020-05-08 13:54:17 +00:00
( " Switch to Yul mode, ignoring all options except "
2020-05-08 16:20:14 +00:00
" -- " + g_argMachine + " , -- " + g_strYulDialect + " , -- " + g_argOptimize + " and -- " + g_strYulOptimizations + " "
2020-05-08 13:54:17 +00:00
" and assumes input is Yul. " ) . c_str ( )
2017-05-23 08:37:51 +00:00
)
2018-01-05 23:09:29 +00:00
(
g_argStrictAssembly . c_str ( ) ,
2020-05-08 13:54:17 +00:00
( " Switch to strict assembly mode, ignoring all options except "
2020-05-08 16:20:14 +00:00
" -- " + g_argMachine + " , -- " + g_strYulDialect + " , -- " + g_argOptimize + " and -- " + g_strYulOptimizations + " "
2020-05-08 13:54:17 +00:00
" and assumes input is strict assembly. " ) . c_str ( )
2019-11-26 18:12:44 +00:00
)
(
2020-05-29 20:28:07 +00:00
g_argImportAst . c_str ( ) ,
( " Import ASTs to be compiled, assumes input holds the AST in compact JSON format. "
" Supported Inputs is the output of the -- " + g_argStandardJSON + " or the one produced by "
" -- " + g_argCombinedJson + " " + g_strAst + " , " + g_strCompactJSON ) . c_str ( )
2018-01-05 23:09:29 +00:00
)
2020-05-29 20:28:07 +00:00
;
desc . add ( alternativeInputModes ) ;
po : : options_description assemblyModeOptions ( " Assembly Mode Options " ) ;
assemblyModeOptions . add_options ( )
2017-05-23 08:37:51 +00:00
(
g_argMachine . c_str ( ) ,
po : : value < string > ( ) - > value_name ( boost : : join ( g_machineArgs , " , " ) ) ,
2018-06-12 17:42:12 +00:00
" Target machine in assembly or Yul mode. "
2016-02-22 01:13:41 +00:00
)
2015-09-11 17:35:01 +00:00
(
2020-05-29 20:28:07 +00:00
g_strYulDialect . c_str ( ) ,
po : : value < string > ( ) - > value_name ( boost : : join ( g_yulDialectArgs , " , " ) ) ,
" Input dialect to use in assembly or yul mode. "
2017-01-25 12:45:18 +00:00
)
2020-05-29 20:28:07 +00:00
;
desc . add ( assemblyModeOptions ) ;
po : : options_description linkerModeOptions ( " Linker Mode Options " ) ;
linkerModeOptions . add_options ( )
2019-09-06 17:11:07 +00:00
(
2020-05-29 20:28:07 +00:00
g_argLibraries . c_str ( ) ,
po : : value < vector < string > > ( ) - > value_name ( " libs " ) ,
" Direct string or file containing library addresses. Syntax: "
" <libraryName>:<address> [, or whitespace] ... \n "
" Address is interpreted as a hex string optionally prefixed by 0x. "
2019-09-06 17:11:07 +00:00
)
2020-05-29 20:28:07 +00:00
;
desc . add ( linkerModeOptions ) ;
po : : options_description outputFormatting ( " Output Formatting " ) ;
outputFormatting . add_options ( )
2017-04-19 15:59:03 +00:00
(
2020-05-29 20:28:07 +00:00
g_argPrettyJson . c_str ( ) ,
" Output JSON in pretty format. Currently it only works with the combined JSON output. "
2018-03-16 15:52:04 +00:00
)
2020-05-13 11:51:49 +00:00
(
2020-06-05 22:13:01 +00:00
g_argColor . c_str ( ) ,
" Force colored output. "
2020-05-13 11:51:49 +00:00
)
2020-04-16 16:12:53 +00:00
(
2020-06-05 22:13:01 +00:00
g_argNoColor . c_str ( ) ,
" Explicitly disable colored output, disabling terminal auto-detection. "
2020-04-16 16:12:53 +00:00
)
2020-06-04 01:19:47 +00:00
(
g_argErrorIds . c_str ( ) ,
" Output error codes. "
)
2020-04-24 12:24:48 +00:00
(
2020-06-05 22:13:01 +00:00
g_argOldReporter . c_str ( ) ,
2020-06-05 22:27:43 +00:00
" Enables old diagnostics reporter (legacy option, will be removed). "
2020-06-05 22:13:01 +00:00
)
2020-05-29 20:28:07 +00:00
;
desc . add ( outputFormatting ) ;
2015-08-19 23:09:39 +00:00
po : : options_description outputComponents ( " Output Components " ) ;
outputComponents . add_options ( )
( g_argAstJson . c_str ( ) , " AST of all source files in JSON format. " )
2017-05-22 13:47:09 +00:00
( g_argAstCompactJson . c_str ( ) , " AST of all source files in a compact JSON format. " )
2016-10-22 15:02:28 +00:00
( g_argAsm . c_str ( ) , " EVM assembly of the contracts. " )
( g_argAsmJson . c_str ( ) , " EVM assembly of the contracts in JSON format. " )
( g_argOpcodes . c_str ( ) , " Opcodes of the contracts. " )
( g_argBinary . c_str ( ) , " Binary of the contracts in hex. " )
( g_argBinaryRuntime . c_str ( ) , " Binary of the runtime part of the contracts in hex. " )
( g_argAbi . c_str ( ) , " ABI specification of the contracts. " )
2019-03-04 22:26:46 +00:00
( g_argIR . c_str ( ) , " Intermediate Representation (IR) of all contracts (EXPERIMENTAL). " )
2020-02-26 14:50:34 +00:00
( g_argIROptimized . c_str ( ) , " Optimized intermediate Representation (IR) of all contracts (EXPERIMENTAL). " )
2019-12-09 16:36:12 +00:00
( g_argEwasm . c_str ( ) , " Ewasm text representation of all contracts (EXPERIMENTAL). " )
2015-08-19 23:09:39 +00:00
( g_argSignatureHashes . c_str ( ) , " Function signature hashes of the contracts. " )
2016-10-22 15:02:28 +00:00
( g_argNatspecUser . c_str ( ) , " Natspec user documentation of all contracts. " )
( g_argNatspecDev . c_str ( ) , " Natspec developer documentation of all contracts. " )
2020-03-24 12:22:25 +00:00
( g_argMetadata . c_str ( ) , " Combined Metadata JSON whose Swarm hash is stored on-chain. " )
2020-05-29 20:28:07 +00:00
( g_argStorageLayout . c_str ( ) , " Slots, offsets and types of the contract's state variables. " )
;
2015-08-19 23:09:39 +00:00
desc . add ( outputComponents ) ;
2020-05-29 20:28:07 +00:00
po : : options_description extraOutput ( " Extra Output " ) ;
extraOutput . add_options ( )
2020-06-05 22:13:01 +00:00
(
2020-05-29 20:28:07 +00:00
g_argGas . c_str ( ) ,
" Print an estimate of the maximal gas usage for each function. "
2020-06-05 22:13:01 +00:00
)
(
2020-05-29 20:28:07 +00:00
g_argCombinedJson . c_str ( ) ,
po : : value < string > ( ) - > value_name ( boost : : join ( g_combinedJsonArgs , " , " ) ) ,
" Output a single json document containing the specified information. "
)
;
desc . add ( extraOutput ) ;
po : : options_description metadataOptions ( " Metadata Options " ) ;
metadataOptions . add_options ( )
(
g_argMetadataHash . c_str ( ) ,
po : : value < string > ( ) - > value_name ( boost : : join ( g_metadataHashArgs , " , " ) ) ,
" Choose hash method for the bytecode metadata or disable it. "
)
(
g_argMetadataLiteral . c_str ( ) ,
" Store referenced sources as literal data in the metadata output. "
2020-06-05 22:13:01 +00:00
)
;
2020-05-29 20:28:07 +00:00
desc . add ( metadataOptions ) ;
2020-06-05 22:13:01 +00:00
2020-05-29 20:28:07 +00:00
po : : options_description optimizerOptions ( " Optimizer Options " ) ;
2020-04-16 16:12:53 +00:00
optimizerOptions . add_options ( )
2020-05-29 20:28:07 +00:00
(
g_argOptimize . c_str ( ) ,
" Enable bytecode optimizer. "
)
2020-04-16 16:12:53 +00:00
(
g_argOptimizeRuns . c_str ( ) ,
po : : value < unsigned > ( ) - > value_name ( " n " ) - > default_value ( 200 ) ,
2020-04-16 16:20:28 +00:00
" Set for how many contract runs to optimize. "
2020-04-16 16:12:53 +00:00
" Lower values will optimize more for initial deployment cost, higher values will optimize more for high-frequency usage. "
)
2020-06-05 22:13:01 +00:00
(
g_strOptimizeYul . c_str ( ) ,
( " Legacy option, ignored. Use the general -- " + g_argOptimize + " to enable Yul optimizer. " ) . c_str ( )
)
(
g_strNoOptimizeYul . c_str ( ) ,
" Disable Yul optimizer in Solidity. "
)
2020-04-24 12:24:48 +00:00
(
g_strYulOptimizations . c_str ( ) ,
po : : value < string > ( ) - > value_name ( " steps " ) ,
" Forces yul optimizer to use the specified sequence of optimization steps instead of the built-in one. "
2020-06-05 22:13:01 +00:00
)
;
2020-04-16 16:12:53 +00:00
desc . add ( optimizerOptions ) ;
2020-06-05 22:13:01 +00:00
2020-10-14 15:44:40 +00:00
po : : options_description smtCheckerOptions ( " Model Checker Options " ) ;
smtCheckerOptions . add_options ( )
(
g_strModelCheckerEngine . c_str ( ) ,
po : : value < string > ( ) - > value_name ( " all,bmc,chc,none " ) - > default_value ( " all " ) ,
" Select model checker engine. "
)
2020-11-02 20:20:20 +00:00
(
g_strModelCheckerTimeout . c_str ( ) ,
po : : value < unsigned > ( ) - > value_name ( " ms " ) ,
" Set model checker timeout per query in milliseconds. "
" The default is a deterministic resource limit. "
" A timeout of 0 means no resource/time restrictions for any query. "
)
2020-10-14 15:44:40 +00:00
;
desc . add ( smtCheckerOptions ) ;
2015-08-19 23:09:39 +00:00
po : : options_description allOptions = desc ;
2016-10-22 15:02:28 +00:00
allOptions . add_options ( ) ( g_argInputFile . c_str ( ) , po : : value < vector < string > > ( ) , " input file " ) ;
2014-12-09 12:43:08 +00:00
2014-12-09 16:39:34 +00:00
// All positional options should be interpreted as input files
2015-08-10 10:44:59 +00:00
po : : positional_options_description filesPositions ;
2016-10-22 15:02:28 +00:00
filesPositions . add ( g_argInputFile . c_str ( ) , - 1 ) ;
2014-12-09 12:43:08 +00:00
2014-12-09 16:39:34 +00:00
// parse the compiler arguments
try
{
2015-08-19 23:09:39 +00:00
po : : command_line_parser cmdLineParser ( _argc , _argv ) ;
2018-02-27 04:31:09 +00:00
cmdLineParser . style ( po : : command_line_style : : default_style & ( ~ po : : command_line_style : : allow_guessing ) ) ;
2016-10-06 11:23:05 +00:00
cmdLineParser . options ( allOptions ) . positional ( filesPositions ) ;
2015-08-19 23:09:39 +00:00
po : : store ( cmdLineParser . run ( ) , m_args ) ;
2014-12-09 16:39:34 +00:00
}
2014-12-17 16:08:57 +00:00
catch ( po : : error const & _exception )
2014-12-09 16:39:34 +00:00
{
2018-09-13 02:36:14 +00:00
serr ( ) < < _exception . what ( ) < < endl ;
2014-12-09 16:39:34 +00:00
return false ;
}
2015-08-10 10:40:02 +00:00
2020-07-08 20:08:50 +00:00
if ( ! checkMutuallyExclusive ( m_args , g_argColor , g_argNoColor ) )
2018-11-26 23:21:53 +00:00
return false ;
2020-07-08 20:08:50 +00:00
static vector < string > const conflictingWithStopAfter {
g_argBinary ,
g_argIR ,
g_argIROptimized ,
g_argEwasm ,
g_argGas ,
g_argAsm ,
g_argAsmJson ,
g_argOpcodes
} ;
for ( auto & option : conflictingWithStopAfter )
if ( ! checkMutuallyExclusive ( m_args , g_strStopAfter , option ) )
return false ;
2018-11-26 23:21:53 +00:00
m_coloredOutput = ! m_args . count ( g_argNoColor ) & & ( isatty ( STDERR_FILENO ) | | m_args . count ( g_argColor ) ) ;
2020-06-04 01:19:47 +00:00
m_withErrorIds = m_args . count ( g_argErrorIds ) ;
2016-10-22 15:02:28 +00:00
if ( m_args . count ( g_argHelp ) | | ( isatty ( fileno ( stdin ) ) & & _argc = = 1 ) )
2014-12-09 16:39:34 +00:00
{
2018-09-13 02:36:14 +00:00
sout ( ) < < desc ;
2014-12-09 16:39:34 +00:00
return false ;
}
2014-12-09 12:43:08 +00:00
2016-10-22 15:02:28 +00:00
if ( m_args . count ( g_argVersion ) )
2014-12-09 16:39:34 +00:00
{
version ( ) ;
return false ;
}
2014-12-09 12:43:08 +00:00
2017-06-08 09:56:14 +00:00
if ( m_args . count ( g_strLicense ) )
{
license ( ) ;
return false ;
}
2019-09-18 14:44:36 +00:00
if ( m_args . count ( g_strRevertStrings ) )
{
string revertStringsString = m_args [ g_strRevertStrings ] . as < string > ( ) ;
std : : optional < RevertStrings > revertStrings = revertStringsFromString ( revertStringsString ) ;
if ( ! revertStrings )
{
serr ( ) < < " Invalid option for -- " < < g_strRevertStrings < < " : " < < revertStringsString < < endl ;
return false ;
}
2020-01-22 14:48:56 +00:00
if ( * revertStrings = = RevertStrings : : VerboseDebug )
2019-09-18 14:44:36 +00:00
{
2020-01-22 14:48:56 +00:00
serr ( ) < < " Only \" default \" , \" strip \" and \" debug \" are implemented for -- " < < g_strRevertStrings < < " for now. " < < endl ;
2019-09-18 14:44:36 +00:00
return false ;
}
m_revertStrings = * revertStrings ;
}
2016-10-22 15:02:28 +00:00
if ( m_args . count ( g_argCombinedJson ) )
2015-08-19 23:09:39 +00:00
{
vector < string > requests ;
2016-10-22 15:02:28 +00:00
for ( string const & item : boost : : split ( requests , m_args [ g_argCombinedJson ] . as < string > ( ) , boost : : is_any_of ( " , " ) ) )
2015-08-19 23:09:39 +00:00
if ( ! g_combinedJsonArgs . count ( item ) )
{
2020-05-08 13:54:17 +00:00
serr ( ) < < " Invalid option to -- " < < g_argCombinedJson < < " : " < < item < < endl ;
2015-08-19 23:09:39 +00:00
return false ;
}
}
po : : notify ( m_args ) ;
2014-12-09 16:39:34 +00:00
return true ;
2014-12-09 12:43:08 +00:00
}
2014-12-09 16:39:34 +00:00
bool CommandLineInterface : : processInput ( )
2014-12-09 12:43:08 +00:00
{
2019-09-17 14:06:43 +00:00
ReadCallback : : Callback fileReader = [ this ] ( string const & _kind , string const & _path )
2017-04-19 15:45:36 +00:00
{
2017-04-20 22:32:42 +00:00
try
2017-04-19 15:45:36 +00:00
{
2019-09-17 14:06:43 +00:00
if ( _kind ! = ReadCallback : : kindString ( ReadCallback : : Kind : : ReadFile ) )
BOOST_THROW_EXCEPTION ( InternalCompilerError ( ) < < errinfo_comment (
" ReadFile callback used as callback kind " +
_kind
) ) ;
2020-04-16 20:29:40 +00:00
string validPath = _path ;
if ( validPath . find ( " file:// " ) = = 0 )
validPath . erase ( 0 , 7 ) ;
2020-05-13 11:51:49 +00:00
auto const path = m_basePath / validPath ;
2019-01-18 17:59:32 +00:00
auto canonicalPath = boost : : filesystem : : weakly_canonical ( path ) ;
2017-04-20 22:32:42 +00:00
bool isAllowed = false ;
for ( auto const & allowedDir : m_allowedDirectories )
2017-04-19 15:45:36 +00:00
{
2017-04-20 22:32:42 +00:00
// If dir is a prefix of boostPath, we are fine.
if (
std : : distance ( allowedDir . begin ( ) , allowedDir . end ( ) ) < = std : : distance ( canonicalPath . begin ( ) , canonicalPath . end ( ) ) & &
std : : equal ( allowedDir . begin ( ) , allowedDir . end ( ) , canonicalPath . begin ( ) )
)
{
isAllowed = true ;
break ;
}
}
if ( ! isAllowed )
2017-07-13 19:06:04 +00:00
return ReadCallback : : Result { false , " File outside of allowed directories. " } ;
2017-10-03 17:48:53 +00:00
2018-04-05 12:25:14 +00:00
if ( ! boost : : filesystem : : exists ( canonicalPath ) )
return ReadCallback : : Result { false , " File not found. " } ;
if ( ! boost : : filesystem : : is_regular_file ( canonicalPath ) )
return ReadCallback : : Result { false , " Not a valid file. " } ;
2019-12-11 16:31:36 +00:00
auto contents = readFileAsString ( canonicalPath . string ( ) ) ;
2018-07-27 06:49:51 +00:00
m_sourceCodes [ path . generic_string ( ) ] = contents ;
2017-10-03 17:48:53 +00:00
return ReadCallback : : Result { true , contents } ;
2017-04-19 15:45:36 +00:00
}
2017-04-20 22:32:42 +00:00
catch ( Exception const & _exception )
{
2017-07-13 19:06:04 +00:00
return ReadCallback : : Result { false , " Exception in read callback: " + boost : : diagnostic_information ( _exception ) } ;
2017-04-20 22:32:42 +00:00
}
catch ( . . . )
2017-04-19 15:45:36 +00:00
{
2017-07-13 19:06:04 +00:00
return ReadCallback : : Result { false , " Unknown exception in read callback. " } ;
2017-04-19 15:45:36 +00:00
}
} ;
2020-05-13 11:51:49 +00:00
if ( m_args . count ( g_argBasePath ) )
{
boost : : filesystem : : path const fspath { m_args [ g_argBasePath ] . as < string > ( ) } ;
if ( ! boost : : filesystem : : is_directory ( fspath ) )
{
serr ( ) < < " Base path must be a directory: \" " < < fspath < < " \" \n " ;
return false ;
}
m_basePath = fspath ;
if ( ! contains ( m_allowedDirectories , fspath ) )
m_allowedDirectories . push_back ( fspath ) ;
}
2017-04-19 15:59:03 +00:00
if ( m_args . count ( g_argAllowPaths ) )
{
vector < string > paths ;
2018-09-20 09:41:59 +00:00
for ( string const & path : boost : : split ( paths , m_args [ g_argAllowPaths ] . as < string > ( ) , boost : : is_any_of ( " , " ) ) )
{
2017-10-05 10:53:32 +00:00
auto filesystem_path = boost : : filesystem : : path ( path ) ;
// If the given path had a trailing slash, the Boost filesystem
// path will have it's last component set to '.'. This breaks
// path comparison in later parts of the code, so we need to strip
// it.
2018-09-18 16:04:11 +00:00
if ( filesystem_path . filename ( ) = = " . " )
2017-10-05 10:53:32 +00:00
filesystem_path . remove_filename ( ) ;
m_allowedDirectories . push_back ( filesystem_path ) ;
}
2017-04-19 15:59:03 +00:00
}
2020-07-08 20:08:50 +00:00
if ( m_args . count ( g_strStopAfter ) )
{
if ( m_args [ g_strStopAfter ] . as < string > ( ) ! = " parsing " )
{
serr ( ) < < " Valid options for -- " < < g_strStopAfter < < " are: \" parsing \" . \n " ;
return false ;
}
else
m_stopAfter = CompilerStack : : State : : Parsed ;
}
2020-05-29 19:38:19 +00:00
vector < string > const exclusiveModes = {
g_argStandardJSON ,
g_argLink ,
g_argAssemble ,
g_argStrictAssembly ,
g_argYul ,
g_argImportAst ,
} ;
if ( countEnabledOptions ( exclusiveModes ) > 1 )
{
serr ( ) < < " The following options are mutually exclusive: " < < joinOptionNames ( exclusiveModes ) < < " . " ;
serr ( ) < < " Select at most one. " < < endl ;
return false ;
}
2017-02-09 14:55:57 +00:00
if ( m_args . count ( g_argStandardJSON ) )
{
2020-02-04 02:50:18 +00:00
vector < string > inputFiles ;
string jsonFile ;
if ( m_args . count ( g_argInputFile ) )
inputFiles = m_args [ g_argInputFile ] . as < vector < string > > ( ) ;
if ( inputFiles . size ( ) = = 1 )
jsonFile = inputFiles [ 0 ] ;
else if ( inputFiles . size ( ) > 1 )
{
serr ( ) < < " If -- " < < g_argStandardJSON < < " is used, only zero or one input files are supported. " < < endl ;
return false ;
}
string input ;
if ( jsonFile . empty ( ) )
input = readStandardInput ( ) ;
else
input = readFileAsString ( jsonFile ) ;
2017-04-19 15:45:36 +00:00
StandardCompiler compiler ( fileReader ) ;
2019-04-06 23:48:37 +00:00
sout ( ) < < compiler . compile ( std : : move ( input ) ) < < endl ;
2017-02-09 14:55:57 +00:00
return true ;
}
2018-03-16 15:52:04 +00:00
if ( ! readInputFilesAndConfigureRemappings ( ) )
return false ;
2014-12-09 12:43:08 +00:00
2016-10-22 15:02:28 +00:00
if ( m_args . count ( g_argLibraries ) )
for ( string const & library : m_args [ g_argLibraries ] . as < vector < string > > ( ) )
2015-09-11 17:35:01 +00:00
if ( ! parseLibraryOption ( library ) )
return false ;
2018-02-23 10:42:53 +00:00
if ( m_args . count ( g_strEVMVersion ) )
{
string versionOptionStr = m_args [ g_strEVMVersion ] . as < string > ( ) ;
2019-10-28 10:39:30 +00:00
std : : optional < langutil : : EVMVersion > versionOption = langutil : : EVMVersion : : fromString ( versionOptionStr ) ;
2018-02-23 10:42:53 +00:00
if ( ! versionOption )
{
2020-05-08 13:54:17 +00:00
serr ( ) < < " Invalid option for -- " < < g_strEVMVersion < < " : " < < versionOptionStr < < endl ;
2018-02-23 10:42:53 +00:00
return false ;
}
2018-03-01 11:06:36 +00:00
m_evmVersion = * versionOption ;
2018-02-23 10:42:53 +00:00
}
2018-06-12 17:42:12 +00:00
if ( m_args . count ( g_argAssemble ) | | m_args . count ( g_argStrictAssembly ) | | m_args . count ( g_argYul ) )
2016-02-22 01:13:41 +00:00
{
2020-05-29 22:32:35 +00:00
vector < string > const nonAssemblyModeOptions = {
// TODO: The list is not complete. Add more.
g_argOutputDir ,
g_argGas ,
g_argCombinedJson ,
g_strOptimizeYul ,
g_strNoOptimizeYul ,
} ;
if ( countEnabledOptions ( nonAssemblyModeOptions ) > = 1 )
{
2020-06-29 13:11:33 +00:00
auto optionEnabled = [ & ] ( string const & name ) { return m_args . count ( name ) > 0 ; } ;
auto enabledOptions = boost : : copy_range < vector < string > > ( nonAssemblyModeOptions | boost : : adaptors : : filtered ( optionEnabled ) ) ;
2020-05-29 22:32:35 +00:00
serr ( ) < < " The following options are invalid in assembly mode: " ;
2020-06-29 13:11:33 +00:00
serr ( ) < < joinOptionNames ( enabledOptions ) < < " . " ;
if ( m_args . count ( g_strOptimizeYul ) | | m_args . count ( g_strNoOptimizeYul ) )
serr ( ) < < " Optimization is disabled by default and can be enabled with -- " < < g_argOptimize < < " . " < < endl ;
serr ( ) < < endl ;
2020-05-29 22:32:35 +00:00
return false ;
}
2016-02-22 01:13:41 +00:00
// switch to assembly mode
m_onlyAssemble = true ;
2019-02-13 11:07:20 +00:00
using Input = yul : : AssemblyStack : : Language ;
using Machine = yul : : AssemblyStack : : Machine ;
2018-06-12 17:36:38 +00:00
Input inputLanguage = m_args . count ( g_argYul ) ? Input : : Yul : ( m_args . count ( g_argStrictAssembly ) ? Input : : StrictAssembly : Input : : Assembly ) ;
2017-05-23 16:57:06 +00:00
Machine targetMachine = Machine : : EVM ;
2019-11-26 15:41:58 +00:00
bool optimize = m_args . count ( g_argOptimize ) ;
2020-05-08 16:20:14 +00:00
optional < string > yulOptimiserSteps ;
if ( m_args . count ( g_strYulOptimizations ) )
{
if ( ! optimize )
{
serr ( ) < < " -- " < < g_strYulOptimizations < < " is invalid if Yul optimizer is disabled " < < endl ;
return false ;
}
try
{
yul : : OptimiserSuite : : validateSequence ( m_args [ g_strYulOptimizations ] . as < string > ( ) ) ;
}
catch ( yul : : OptimizerException const & _exception )
{
serr ( ) < < " Invalid optimizer step sequence in -- " < < g_strYulOptimizations < < " : " < < _exception . what ( ) < < endl ;
return false ;
}
yulOptimiserSteps = m_args [ g_strYulOptimizations ] . as < string > ( ) ;
}
2017-05-23 08:37:51 +00:00
if ( m_args . count ( g_argMachine ) )
{
string machine = m_args [ g_argMachine ] . as < string > ( ) ;
if ( machine = = g_strEVM )
2017-05-23 16:57:06 +00:00
targetMachine = Machine : : EVM ;
2017-05-23 08:37:51 +00:00
else if ( machine = = g_strEVM15 )
2017-05-23 16:57:06 +00:00
targetMachine = Machine : : EVM15 ;
2019-12-09 16:36:12 +00:00
else if ( machine = = g_strEwasm )
targetMachine = Machine : : Ewasm ;
2017-05-23 08:37:51 +00:00
else
{
2020-05-08 13:54:17 +00:00
serr ( ) < < " Invalid option for -- " < < g_argMachine < < " : " < < machine < < endl ;
2017-05-23 08:37:51 +00:00
return false ;
}
}
2019-12-09 16:36:12 +00:00
if ( targetMachine = = Machine : : Ewasm & & inputLanguage = = Input : : StrictAssembly )
inputLanguage = Input : : Ewasm ;
2019-11-26 18:12:44 +00:00
if ( m_args . count ( g_strYulDialect ) )
{
string dialect = m_args [ g_strYulDialect ] . as < string > ( ) ;
if ( dialect = = g_strEVM )
inputLanguage = Input : : StrictAssembly ;
2019-12-09 16:36:12 +00:00
else if ( dialect = = g_strEwasm )
2019-11-26 18:12:44 +00:00
{
2019-12-09 16:36:12 +00:00
inputLanguage = Input : : Ewasm ;
if ( targetMachine ! = Machine : : Ewasm )
2019-11-26 18:12:44 +00:00
{
2020-05-08 13:54:17 +00:00
serr ( ) < < " If you select Ewasm as -- " < < g_strYulDialect < < " , " ;
serr ( ) < < " -- " < < g_argMachine < < " has to be Ewasm as well. " < < endl ;
2019-11-26 18:12:44 +00:00
return false ;
}
}
else
{
2020-05-08 13:54:17 +00:00
serr ( ) < < " Invalid option for -- " < < g_strYulDialect < < " : " < < dialect < < endl ;
2019-11-26 18:12:44 +00:00
return false ;
}
}
2019-12-09 16:36:12 +00:00
if ( optimize & & ( inputLanguage ! = Input : : StrictAssembly & & inputLanguage ! = Input : : Ewasm ) )
2018-11-03 15:05:08 +00:00
{
serr ( ) < <
2019-02-06 13:39:43 +00:00
" Optimizer can only be used for strict assembly. Use -- " < <
2018-11-03 15:05:08 +00:00
g_strStrictAssembly < <
" . " < <
endl ;
return false ;
}
2020-05-29 19:21:42 +00:00
if ( targetMachine = = Machine : : Ewasm & & inputLanguage ! = Input : : StrictAssembly & & inputLanguage ! = Input : : Ewasm )
{
serr ( ) < < " The selected input language is not directly supported when targeting the Ewasm machine " ;
serr ( ) < < " and automatic translation is not available. " < < endl ;
return false ;
}
2019-03-25 13:41:37 +00:00
serr ( ) < <
2019-11-26 15:41:58 +00:00
" Warning: Yul is still experimental. Please use the output with care. " < <
2019-03-25 13:41:37 +00:00
endl ;
2020-05-08 16:20:14 +00:00
return assemble ( inputLanguage , targetMachine , optimize , yulOptimiserSteps ) ;
2016-02-22 01:13:41 +00:00
}
2020-05-29 21:28:09 +00:00
else if ( countEnabledOptions ( { g_strYulDialect , g_argMachine } ) > = 1 )
{
serr ( ) < < " -- " < < g_strYulDialect < < " and -- " < < g_argMachine < < " " ;
serr ( ) < < " are only valid in assembly mode. " < < endl ;
return false ;
}
2016-10-22 15:02:28 +00:00
if ( m_args . count ( g_argLink ) )
2015-09-11 17:35:01 +00:00
{
// switch to linker mode
m_onlyLink = true ;
return link ( ) ;
}
2019-09-06 17:11:07 +00:00
if ( m_args . count ( g_argMetadataHash ) )
{
string hashStr = m_args [ g_argMetadataHash ] . as < string > ( ) ;
if ( hashStr = = g_strIPFS )
m_metadataHash = CompilerStack : : MetadataHash : : IPFS ;
else if ( hashStr = = g_strSwarm )
m_metadataHash = CompilerStack : : MetadataHash : : Bzzr1 ;
else if ( hashStr = = g_strNone )
m_metadataHash = CompilerStack : : MetadataHash : : None ;
else
{
2020-05-08 13:54:17 +00:00
serr ( ) < < " Invalid option for -- " < < g_argMetadataHash < < " : " < < hashStr < < endl ;
2019-09-06 17:11:07 +00:00
return false ;
}
}
2020-10-14 15:44:40 +00:00
if ( m_args . count ( g_argModelCheckerEngine ) )
{
string engineStr = m_args [ g_argModelCheckerEngine ] . as < string > ( ) ;
optional < ModelCheckerEngine > engine = ModelCheckerEngine : : fromString ( engineStr ) ;
if ( ! engine )
{
serr ( ) < < " Invalid option for -- " < < g_argModelCheckerEngine < < " : " < < engineStr < < endl ;
return false ;
}
2020-11-02 20:20:20 +00:00
m_modelCheckerSettings . engine = * engine ;
2020-10-14 15:44:40 +00:00
}
2020-11-02 20:20:20 +00:00
if ( m_args . count ( g_argModelCheckerTimeout ) )
m_modelCheckerSettings . timeout = m_args [ g_argModelCheckerTimeout ] . as < unsigned > ( ) ;
2019-11-27 16:24:21 +00:00
m_compiler = make_unique < CompilerStack > ( fileReader ) ;
2017-10-26 20:56:00 +00:00
2018-11-26 23:21:53 +00:00
unique_ptr < SourceReferenceFormatter > formatter ;
2019-09-06 09:27:06 +00:00
if ( m_args . count ( g_argOldReporter ) )
2018-11-26 23:21:53 +00:00
formatter = make_unique < SourceReferenceFormatter > ( serr ( false ) ) ;
2019-09-06 09:27:06 +00:00
else
2020-06-04 01:19:47 +00:00
formatter = make_unique < SourceReferenceFormatterHuman > ( serr ( false ) , m_coloredOutput , m_withErrorIds ) ;
2017-10-26 20:56:00 +00:00
2014-12-09 12:43:08 +00:00
try
{
2017-01-25 12:45:18 +00:00
if ( m_args . count ( g_argMetadataLiteral ) > 0 )
m_compiler - > useMetadataLiteralSources ( true ) ;
2019-09-06 17:11:07 +00:00
if ( m_args . count ( g_argMetadataHash ) )
m_compiler - > setMetadataHash ( m_metadataHash ) ;
2020-11-02 20:20:20 +00:00
if ( m_args . count ( g_argModelCheckerEngine ) | | m_args . count ( g_argModelCheckerTimeout ) )
m_compiler - > setModelCheckerSettings ( m_modelCheckerSettings ) ;
2016-10-22 15:02:28 +00:00
if ( m_args . count ( g_argInputFile ) )
2018-08-09 18:37:49 +00:00
m_compiler - > setRemappings ( m_remappings ) ;
2019-09-11 19:16:35 +00:00
2017-07-17 10:49:45 +00:00
if ( m_args . count ( g_argLibraries ) )
m_compiler - > setLibraries ( m_libraries ) ;
2018-03-01 11:06:36 +00:00
m_compiler - > setEVMVersion ( m_evmVersion ) ;
2019-09-18 14:44:36 +00:00
m_compiler - > setRevertStringBehaviour ( m_revertStrings ) ;
2014-12-09 16:39:34 +00:00
// TODO: Perhaps we should not compile unless requested
2019-02-21 17:35:41 +00:00
2020-02-26 14:50:34 +00:00
m_compiler - > enableIRGeneration ( m_args . count ( g_argIR ) | | m_args . count ( g_argIROptimized ) ) ;
2019-12-09 16:36:12 +00:00
m_compiler - > enableEwasmGeneration ( m_args . count ( g_argEwasm ) ) ;
2019-03-04 22:26:46 +00:00
2019-03-20 15:15:07 +00:00
OptimiserSettings settings = m_args . count ( g_argOptimize ) ? OptimiserSettings : : standard ( ) : OptimiserSettings : : minimal ( ) ;
2019-02-21 17:35:41 +00:00
settings . expectedExecutionsPerDeployment = m_args [ g_argOptimizeRuns ] . as < unsigned > ( ) ;
2020-01-15 17:34:38 +00:00
if ( m_args . count ( g_strNoOptimizeYul ) )
settings . runYulOptimiser = false ;
2020-04-24 12:24:48 +00:00
if ( m_args . count ( g_strYulOptimizations ) )
{
if ( ! settings . runYulOptimiser )
{
serr ( ) < < " -- " < < g_strYulOptimizations < < " is invalid if Yul optimizer is disabled " < < endl ;
return false ;
}
try
{
yul : : OptimiserSuite : : validateSequence ( m_args [ g_strYulOptimizations ] . as < string > ( ) ) ;
}
catch ( yul : : OptimizerException const & _exception )
{
serr ( ) < < " Invalid optimizer step sequence in -- " < < g_strYulOptimizations < < " : " < < _exception . what ( ) < < endl ;
return false ;
}
settings . yulOptimiserSteps = m_args [ g_strYulOptimizations ] . as < string > ( ) ;
}
2019-02-26 18:55:13 +00:00
settings . optimizeStackAllocation = settings . runYulOptimiser ;
2019-02-21 17:35:41 +00:00
m_compiler - > setOptimiserSettings ( settings ) ;
2017-07-17 10:54:02 +00:00
2019-09-11 19:16:35 +00:00
if ( m_args . count ( g_argImportAst ) )
{
try
{
m_compiler - > importASTs ( parseAstFromInput ( ) ) ;
if ( ! m_compiler - > analyze ( ) )
{
for ( auto const & error : m_compiler - > errors ( ) )
formatter - > printErrorInformation ( * error ) ;
astAssert ( false , " Analysis of the AST failed " ) ;
}
}
catch ( Exception const & _exc )
{
serr ( ) < < string ( " Failed to import AST: " ) < < _exc . what ( ) < < endl ;
return false ;
}
}
else
{
m_compiler - > setSources ( m_sourceCodes ) ;
if ( m_args . count ( g_argErrorRecovery ) )
m_compiler - > setParserErrorRecovery ( true ) ;
}
2020-07-08 20:08:50 +00:00
bool successful = m_compiler - > compile ( m_stopAfter ) ;
2015-10-21 14:43:31 +00:00
2015-10-01 15:59:01 +00:00
for ( auto const & error : m_compiler - > errors ( ) )
2018-09-13 02:36:14 +00:00
{
g_hasOutput = true ;
2019-04-05 15:49:39 +00:00
formatter - > printErrorInformation ( * error ) ;
2018-09-13 02:36:14 +00:00
}
2015-10-21 14:43:31 +00:00
2015-10-01 15:59:01 +00:00
if ( ! successful )
2019-05-28 15:24:54 +00:00
{
if ( m_args . count ( g_argErrorRecovery ) )
return true ;
else
return false ;
}
2014-12-09 12:43:08 +00:00
}
2014-12-17 16:08:57 +00:00
catch ( CompilerError const & _exception )
2014-12-09 12:43:08 +00:00
{
2018-09-13 02:36:14 +00:00
g_hasOutput = true ;
2018-11-26 23:21:53 +00:00
formatter - > printExceptionInformation ( _exception , " Compiler error " ) ;
2014-12-09 12:43:08 +00:00
return false ;
}
2014-12-17 16:08:57 +00:00
catch ( InternalCompilerError const & _exception )
2014-12-09 12:43:08 +00:00
{
2019-02-13 15:56:46 +00:00
serr ( ) < <
" Internal compiler error during compilation: " < <
endl < <
boost : : diagnostic_information ( _exception ) ;
2014-12-09 12:43:08 +00:00
return false ;
}
2016-11-14 20:41:58 +00:00
catch ( UnimplementedFeatureError const & _exception )
{
2019-02-13 15:56:46 +00:00
serr ( ) < <
" Unimplemented feature: " < <
endl < <
boost : : diagnostic_information ( _exception ) ;
2016-11-14 20:41:58 +00:00
return false ;
}
2020-05-20 10:55:12 +00:00
catch ( smtutil : : SMTLogicError const & _exception )
{
serr ( ) < <
" SMT logic error during analysis: " < <
endl < <
boost : : diagnostic_information ( _exception ) ;
2016-11-14 20:41:58 +00:00
return false ;
}
2015-10-02 12:41:40 +00:00
catch ( Error const & _error )
2015-06-15 13:21:23 +00:00
{
2015-10-02 12:41:40 +00:00
if ( _error . type ( ) = = Error : : Type : : DocstringParsingError )
2018-09-13 02:36:14 +00:00
serr ( ) < < " Documentation parsing error: " < < * boost : : get_error_info < errinfo_comment > ( _error ) < < endl ;
2015-10-02 12:41:40 +00:00
else
2018-09-13 02:36:14 +00:00
{
g_hasOutput = true ;
2018-11-26 23:21:53 +00:00
formatter - > printExceptionInformation ( _error , _error . typeName ( ) ) ;
2018-09-13 02:36:14 +00:00
}
2015-10-02 12:41:40 +00:00
2015-06-15 13:21:23 +00:00
return false ;
}
2014-12-17 16:08:57 +00:00
catch ( Exception const & _exception )
2014-12-09 12:43:08 +00:00
{
2018-09-13 02:36:14 +00:00
serr ( ) < < " Exception during compilation: " < < boost : : diagnostic_information ( _exception ) < < endl ;
2014-12-09 12:43:08 +00:00
return false ;
}
2019-05-29 20:26:18 +00:00
catch ( std : : exception const & _e )
{
serr ( ) < < " Unknown exception during compilation " < < (
_e . what ( ) ? " : " + string ( _e . what ( ) ) : " . "
) < < endl ;
return false ;
}
2014-12-09 12:43:08 +00:00
catch ( . . . )
{
2018-09-13 02:36:14 +00:00
serr ( ) < < " Unknown exception during compilation. " < < endl ;
2014-12-09 12:43:08 +00:00
return false ;
}
2014-12-09 16:39:34 +00:00
return true ;
2014-12-09 12:43:08 +00:00
}
2015-04-23 12:40:42 +00:00
void CommandLineInterface : : handleCombinedJSON ( )
{
2016-10-22 15:02:28 +00:00
if ( ! m_args . count ( g_argCombinedJson ) )
2015-04-24 09:48:23 +00:00
return ;
2015-04-23 12:40:42 +00:00
Json : : Value output ( Json : : objectValue ) ;
2019-12-11 16:31:36 +00:00
output [ g_strVersion ] = frontend : : VersionString ;
2015-04-23 12:40:42 +00:00
set < string > requests ;
2016-10-22 15:02:28 +00:00
boost : : split ( requests , m_args [ g_argCombinedJson ] . as < string > ( ) , boost : : is_any_of ( " , " ) ) ;
2015-08-31 16:44:29 +00:00
vector < string > contracts = m_compiler - > contractNames ( ) ;
2015-04-23 12:40:42 +00:00
if ( ! contracts . empty ( ) )
2016-10-22 15:02:28 +00:00
output [ g_strContracts ] = Json : : Value ( Json : : objectValue ) ;
2015-04-23 12:40:42 +00:00
for ( string const & contractName : contracts )
{
2017-07-27 14:40:01 +00:00
Json : : Value & contractData = output [ g_strContracts ] [ contractName ] = Json : : objectValue ;
2016-10-22 15:02:28 +00:00
if ( requests . count ( g_strAbi ) )
2019-12-11 16:31:36 +00:00
contractData [ g_strAbi ] = jsonCompactPrint ( m_compiler - > contractABI ( contractName ) ) ;
2016-11-14 10:46:43 +00:00
if ( requests . count ( " metadata " ) )
2017-05-19 15:10:32 +00:00
contractData [ " metadata " ] = m_compiler - > metadata ( contractName ) ;
2019-05-28 15:24:54 +00:00
if ( requests . count ( g_strBinary ) & & m_compiler - > compilationSuccessful ( ) )
2016-10-22 15:02:28 +00:00
contractData [ g_strBinary ] = m_compiler - > object ( contractName ) . toHex ( ) ;
2019-05-28 15:24:54 +00:00
if ( requests . count ( g_strBinaryRuntime ) & & m_compiler - > compilationSuccessful ( ) )
2016-10-22 15:02:28 +00:00
contractData [ g_strBinaryRuntime ] = m_compiler - > runtimeObject ( contractName ) . toHex ( ) ;
2019-05-28 15:24:54 +00:00
if ( requests . count ( g_strOpcodes ) & & m_compiler - > compilationSuccessful ( ) )
2019-12-11 16:31:36 +00:00
contractData [ g_strOpcodes ] = evmasm : : disassemble ( m_compiler - > object ( contractName ) . bytecode ) ;
2019-05-28 15:24:54 +00:00
if ( requests . count ( g_strAsm ) & & m_compiler - > compilationSuccessful ( ) )
2020-02-18 09:22:34 +00:00
contractData [ g_strAsm ] = m_compiler - > assemblyJSON ( contractName ) ;
2020-03-24 12:22:25 +00:00
if ( requests . count ( g_strStorageLayout ) & & m_compiler - > compilationSuccessful ( ) )
contractData [ g_strStorageLayout ] = jsonCompactPrint ( m_compiler - > storageLayout ( contractName ) ) ;
2020-05-28 11:17:16 +00:00
if ( requests . count ( g_strGeneratedSources ) & & m_compiler - > compilationSuccessful ( ) )
contractData [ g_strGeneratedSources ] = m_compiler - > generatedSources ( contractName , false ) ;
if ( requests . count ( g_strGeneratedSourcesRuntime ) & & m_compiler - > compilationSuccessful ( ) )
contractData [ g_strGeneratedSourcesRuntime ] = m_compiler - > generatedSources ( contractName , true ) ;
2019-05-28 15:24:54 +00:00
if ( requests . count ( g_strSrcMap ) & & m_compiler - > compilationSuccessful ( ) )
2016-07-01 08:14:50 +00:00
{
auto map = m_compiler - > sourceMapping ( contractName ) ;
2016-10-22 15:02:28 +00:00
contractData [ g_strSrcMap ] = map ? * map : " " ;
2016-07-01 08:14:50 +00:00
}
2019-05-28 15:24:54 +00:00
if ( requests . count ( g_strSrcMapRuntime ) & & m_compiler - > compilationSuccessful ( ) )
2016-07-01 08:14:50 +00:00
{
auto map = m_compiler - > runtimeSourceMapping ( contractName ) ;
2016-10-22 15:02:28 +00:00
contractData [ g_strSrcMapRuntime ] = map ? * map : " " ;
2016-07-01 08:14:50 +00:00
}
2017-06-13 16:02:57 +00:00
if ( requests . count ( g_strSignatureHashes ) )
2017-06-15 10:33:01 +00:00
contractData [ g_strSignatureHashes ] = m_compiler - > methodIdentifiers ( contractName ) ;
2016-10-22 15:02:28 +00:00
if ( requests . count ( g_strNatspecDev ) )
2019-12-11 16:31:36 +00:00
contractData [ g_strNatspecDev ] = jsonCompactPrint ( m_compiler - > natspecDev ( contractName ) ) ;
2016-10-22 15:02:28 +00:00
if ( requests . count ( g_strNatspecUser ) )
2019-12-11 16:31:36 +00:00
contractData [ g_strNatspecUser ] = jsonCompactPrint ( m_compiler - > natspecUser ( contractName ) ) ;
2015-04-23 12:40:42 +00:00
}
2016-10-22 15:02:28 +00:00
bool needsSourceList = requests . count ( g_strAst ) | | requests . count ( g_strSrcMap ) | | requests . count ( g_strSrcMapRuntime ) ;
2016-07-01 08:14:50 +00:00
if ( needsSourceList )
{
// Indices into this array are used to abbreviate source names in source locations.
2016-10-22 15:02:28 +00:00
output [ g_strSourceList ] = Json : : Value ( Json : : arrayValue ) ;
2016-07-01 08:14:50 +00:00
for ( auto const & source : m_compiler - > sourceNames ( ) )
2016-10-22 15:02:28 +00:00
output [ g_strSourceList ] . append ( source ) ;
2016-07-01 08:14:50 +00:00
}
2016-10-22 15:02:28 +00:00
if ( requests . count ( g_strAst ) )
2015-04-23 12:40:42 +00:00
{
2017-05-22 13:47:09 +00:00
bool legacyFormat = ! requests . count ( g_strCompactJSON ) ;
2016-10-22 15:02:28 +00:00
output [ g_strSources ] = Json : : Value ( Json : : objectValue ) ;
2015-04-23 12:40:42 +00:00
for ( auto const & sourceCode : m_sourceCodes )
{
2020-07-08 20:08:50 +00:00
ASTJsonConverter converter ( legacyFormat , m_compiler - > state ( ) , m_compiler - > sourceIndices ( ) ) ;
2016-10-22 15:02:28 +00:00
output [ g_strSources ] [ sourceCode . first ] = Json : : Value ( Json : : objectValue ) ;
2017-03-20 18:06:17 +00:00
output [ g_strSources ] [ sourceCode . first ] [ " AST " ] = converter . toJson ( m_compiler - > ast ( sourceCode . first ) ) ;
2015-04-23 12:40:42 +00:00
}
}
2017-05-22 20:44:19 +00:00
2020-04-27 08:28:54 +00:00
string json = m_args . count ( g_argPrettyJson ) ? jsonPrettyPrint ( removeNullMembers ( std : : move ( output ) ) ) :
jsonCompactPrint ( removeNullMembers ( std : : move ( output ) ) ) ;
2017-07-03 23:46:30 +00:00
2017-05-22 20:44:19 +00:00
if ( m_args . count ( g_argOutputDir ) )
2017-07-03 23:46:30 +00:00
createJson ( " combined " , json ) ;
2017-05-22 20:44:19 +00:00
else
2018-09-13 02:36:14 +00:00
sout ( ) < < json < < endl ;
2015-04-23 12:40:42 +00:00
}
2015-01-16 10:44:55 +00:00
void CommandLineInterface : : handleAst ( string const & _argStr )
2014-12-09 12:43:08 +00:00
{
2015-01-16 10:44:55 +00:00
string title ;
2015-01-05 14:46:40 +00:00
2019-09-06 10:38:55 +00:00
if ( _argStr = = g_argAstJson )
2015-01-05 14:46:40 +00:00
title = " JSON AST: " ;
2017-05-22 13:47:09 +00:00
else if ( _argStr = = g_argAstCompactJson )
title = " JSON AST (compact format): " ;
2015-01-05 14:46:40 +00:00
else
BOOST_THROW_EXCEPTION ( InternalCompilerError ( ) < < errinfo_comment ( " Illegal argStr for AST " ) ) ;
2014-12-09 12:43:08 +00:00
// do we need AST output?
2015-01-05 14:46:40 +00:00
if ( m_args . count ( _argStr ) )
2014-12-09 12:43:08 +00:00
{
2015-05-06 08:43:59 +00:00
vector < ASTNode const * > asts ;
for ( auto const & sourceCode : m_sourceCodes )
2015-09-08 12:30:21 +00:00
asts . push_back ( & m_compiler - > ast ( sourceCode . first ) ) ;
2018-11-28 13:32:26 +00:00
2017-05-22 13:47:09 +00:00
bool legacyFormat = ! m_args . count ( g_argAstCompactJson ) ;
2016-10-22 15:02:28 +00:00
if ( m_args . count ( g_argOutputDir ) )
2014-12-09 12:43:08 +00:00
{
for ( auto const & sourceCode : m_sourceCodes )
{
2015-08-10 10:44:59 +00:00
stringstream data ;
2015-08-10 10:49:28 +00:00
string postfix = " " ;
2020-07-08 20:08:50 +00:00
ASTJsonConverter ( legacyFormat , m_compiler - > state ( ) , m_compiler - > sourceIndices ( ) ) . print ( data , m_compiler - > ast ( sourceCode . first ) ) ;
2019-09-06 10:38:55 +00:00
postfix + = " _json " ;
2015-08-19 23:09:39 +00:00
boost : : filesystem : : path path ( sourceCode . first ) ;
createFile ( path . filename ( ) . string ( ) + postfix + " .ast " , data . str ( ) ) ;
2014-12-09 12:43:08 +00:00
}
}
2015-08-10 10:40:02 +00:00
else
2014-12-09 12:43:08 +00:00
{
2018-09-13 02:36:14 +00:00
sout ( ) < < title < < endl < < endl ;
2014-12-09 12:43:08 +00:00
for ( auto const & sourceCode : m_sourceCodes )
{
2018-09-13 02:36:14 +00:00
sout ( ) < < endl < < " ======= " < < sourceCode . first < < " ======= " < < endl ;
2020-07-08 20:08:50 +00:00
ASTJsonConverter ( legacyFormat , m_compiler - > state ( ) , m_compiler - > sourceIndices ( ) ) . print ( sout ( ) , m_compiler - > ast ( sourceCode . first ) ) ;
2014-12-09 12:43:08 +00:00
}
}
}
2015-01-05 14:46:40 +00:00
}
2017-03-10 18:11:01 +00:00
bool CommandLineInterface : : actOnInput ( )
2015-09-11 17:35:01 +00:00
{
2017-05-23 10:13:34 +00:00
if ( m_args . count ( g_argStandardJSON ) | | m_onlyAssemble )
// Already done in "processInput" phase.
2017-02-09 14:55:57 +00:00
return true ;
2016-02-22 01:13:41 +00:00
else if ( m_onlyLink )
2015-09-11 17:35:01 +00:00
writeLinkedFiles ( ) ;
else
outputCompilationResults ( ) ;
2017-03-10 18:11:01 +00:00
return ! m_error ;
2015-09-11 17:35:01 +00:00
}
bool CommandLineInterface : : link ( )
{
2016-09-06 09:12:55 +00:00
// Map from how the libraries will be named inside the bytecode to their addresses.
2016-09-01 23:16:03 +00:00
map < string , h160 > librariesReplacements ;
2016-09-06 09:57:21 +00:00
int const placeholderSize = 40 ; // 20 bytes or 40 hex characters
2016-09-01 23:16:03 +00:00
for ( auto const & library : m_libraries )
{
string const & name = library . first ;
2016-09-06 09:12:55 +00:00
// Library placeholders are 40 hex digits (20 bytes) that start and end with '__'.
2018-10-04 12:55:02 +00:00
// This leaves 36 characters for the library identifier. The identifier used to
// be just the cropped or '_'-padded library name, but this changed to
// the cropped hex representation of the hash of the library name.
// We support both ways of linking here.
2019-12-11 16:31:36 +00:00
librariesReplacements [ " __ " + evmasm : : LinkerObject : : libraryPlaceholder ( name ) + " __ " ] = library . second ;
2018-10-04 12:55:02 +00:00
2016-09-01 23:16:03 +00:00
string replacement = " __ " ;
2016-09-06 09:12:55 +00:00
for ( size_t i = 0 ; i < placeholderSize - 4 ; + + i )
2016-09-01 23:16:03 +00:00
replacement . push_back ( i < name . size ( ) ? name [ i ] : ' _ ' ) ;
replacement + = " __ " ;
librariesReplacements [ replacement ] = library . second ;
}
2015-09-11 17:35:01 +00:00
for ( auto & src : m_sourceCodes )
{
auto end = src . second . end ( ) ;
for ( auto it = src . second . begin ( ) ; it ! = end ; )
{
while ( it ! = end & & * it ! = ' _ ' ) + + it ;
2016-09-01 23:16:03 +00:00
if ( it = = end ) break ;
2016-09-06 09:12:55 +00:00
if ( end - it < placeholderSize )
2015-09-11 17:35:01 +00:00
{
2018-09-13 02:36:14 +00:00
serr ( ) < < " Error in binary object file " < < src . first < < " at position " < < ( end - src . second . begin ( ) ) < < endl ;
2015-09-11 17:35:01 +00:00
return false ;
}
2016-09-06 09:12:55 +00:00
string name ( it , it + placeholderSize ) ;
2016-09-01 23:16:03 +00:00
if ( librariesReplacements . count ( name ) )
2015-09-11 17:35:01 +00:00
{
2016-09-01 23:16:03 +00:00
string hexStr ( toHex ( librariesReplacements . at ( name ) . asBytes ( ) ) ) ;
copy ( hexStr . begin ( ) , hexStr . end ( ) , it ) ;
2015-09-11 17:35:01 +00:00
}
else
2018-09-13 02:36:14 +00:00
serr ( ) < < " Reference \" " < < name < < " \" in file \" " < < src . first < < " \" still unresolved. " < < endl ;
2016-09-06 09:12:55 +00:00
it + = placeholderSize ;
2015-09-11 17:35:01 +00:00
}
2018-10-04 12:55:02 +00:00
// Remove hints for resolved libraries.
for ( auto const & library : m_libraries )
boost : : algorithm : : erase_all ( src . second , " \n " + libraryPlaceholderHint ( library . first ) ) ;
while ( ! src . second . empty ( ) & & * prev ( src . second . end ( ) ) = = ' \n ' )
2019-02-13 15:56:46 +00:00
src . second . resize ( src . second . size ( ) - 1 ) ;
2015-09-11 17:35:01 +00:00
}
return true ;
}
void CommandLineInterface : : writeLinkedFiles ( )
{
for ( auto const & src : m_sourceCodes )
if ( src . first = = g_stdinFileName )
2018-09-13 02:36:14 +00:00
sout ( ) < < src . second < < endl ;
2015-09-11 17:35:01 +00:00
else
2018-10-17 22:48:07 +00:00
{
ofstream outFile ( src . first ) ;
outFile < < src . second ;
if ( ! outFile )
{
2018-09-13 02:36:14 +00:00
serr ( ) < < " Could not write to file " < < src . first < < " . Aborting. " < < endl ;
2018-10-17 22:48:07 +00:00
return ;
}
}
2018-09-13 02:36:14 +00:00
sout ( ) < < " Linking completed. " < < endl ;
2015-09-11 17:35:01 +00:00
}
2018-10-04 12:55:02 +00:00
string CommandLineInterface : : libraryPlaceholderHint ( string const & _libraryName )
{
2019-12-11 16:31:36 +00:00
return " // " + evmasm : : LinkerObject : : libraryPlaceholder ( _libraryName ) + " -> " + _libraryName ;
2018-10-04 12:55:02 +00:00
}
2019-12-11 16:31:36 +00:00
string CommandLineInterface : : objectWithLinkRefsHex ( evmasm : : LinkerObject const & _obj )
2018-10-04 12:55:02 +00:00
{
string out = _obj . toHex ( ) ;
if ( ! _obj . linkReferences . empty ( ) )
{
out + = " \n " ;
for ( auto const & linkRef : _obj . linkReferences )
out + = " \n " + libraryPlaceholderHint ( linkRef . second ) ;
}
return out ;
}
2017-05-23 16:57:06 +00:00
bool CommandLineInterface : : assemble (
2019-02-13 11:07:20 +00:00
yul : : AssemblyStack : : Language _language ,
yul : : AssemblyStack : : Machine _targetMachine ,
2020-05-08 16:20:14 +00:00
bool _optimize ,
optional < string > _yulOptimiserSteps
2017-05-23 16:57:06 +00:00
)
2016-02-22 01:13:41 +00:00
{
2020-05-08 16:20:14 +00:00
solAssert ( _optimize | | ! _yulOptimiserSteps . has_value ( ) , " " ) ;
2016-02-22 01:13:41 +00:00
bool successful = true ;
2019-02-13 11:07:20 +00:00
map < string , yul : : AssemblyStack > assemblyStacks ;
2016-02-22 01:13:41 +00:00
for ( auto const & src : m_sourceCodes )
{
2020-05-08 16:20:14 +00:00
OptimiserSettings settings = _optimize ? OptimiserSettings : : full ( ) : OptimiserSettings : : minimal ( ) ;
if ( _yulOptimiserSteps . has_value ( ) )
settings . yulOptimiserSteps = _yulOptimiserSteps . value ( ) ;
auto & stack = assemblyStacks [ src . first ] = yul : : AssemblyStack ( m_evmVersion , _language , settings ) ;
2017-05-02 17:55:39 +00:00
try
{
2017-05-23 16:57:06 +00:00
if ( ! stack . parseAndAnalyze ( src . first , src . second ) )
2017-05-02 17:55:39 +00:00
successful = false ;
2019-03-27 11:49:50 +00:00
else
2018-11-03 15:05:08 +00:00
stack . optimize ( ) ;
2017-05-02 17:55:39 +00:00
}
catch ( Exception const & _exception )
{
2018-09-13 02:36:14 +00:00
serr ( ) < < " Exception in assembler: " < < boost : : diagnostic_information ( _exception ) < < endl ;
2017-05-02 17:55:39 +00:00
return false ;
}
2019-05-29 20:26:18 +00:00
catch ( std : : exception const & _e )
{
serr ( ) < <
" Unknown exception during compilation " < <
( _e . what ( ) ? " : " + string ( _e . what ( ) ) : " . " ) < <
endl ;
return false ;
}
2017-05-02 17:55:39 +00:00
catch ( . . . )
{
2018-09-13 02:36:14 +00:00
serr ( ) < < " Unknown exception in assembler. " < < endl ;
2017-05-02 17:55:39 +00:00
return false ;
}
2016-02-22 01:13:41 +00:00
}
2017-10-26 20:56:00 +00:00
2017-05-23 16:57:06 +00:00
for ( auto const & sourceAndStack : assemblyStacks )
2017-01-26 12:45:23 +00:00
{
2017-05-23 16:57:06 +00:00
auto const & stack = sourceAndStack . second ;
2018-11-26 23:21:53 +00:00
unique_ptr < SourceReferenceFormatter > formatter ;
2019-09-06 09:27:06 +00:00
if ( m_args . count ( g_argOldReporter ) )
2018-11-26 23:21:53 +00:00
formatter = make_unique < SourceReferenceFormatter > ( serr ( false ) ) ;
2019-09-06 09:27:06 +00:00
else
2020-06-04 01:19:47 +00:00
formatter = make_unique < SourceReferenceFormatterHuman > ( serr ( false ) , m_coloredOutput , m_withErrorIds ) ;
2017-10-26 20:56:00 +00:00
2017-05-23 16:57:06 +00:00
for ( auto const & error : stack . errors ( ) )
2018-09-13 02:36:14 +00:00
{
g_hasOutput = true ;
2019-04-05 15:49:39 +00:00
formatter - > printErrorInformation ( * error ) ;
2018-09-13 02:36:14 +00:00
}
2017-05-23 16:57:06 +00:00
if ( ! Error : : containsOnlyWarnings ( stack . errors ( ) ) )
2017-01-26 12:45:23 +00:00
successful = false ;
}
2016-02-22 01:13:41 +00:00
2017-05-23 10:13:34 +00:00
if ( ! successful )
return false ;
2016-02-22 01:13:41 +00:00
2016-03-01 21:56:39 +00:00
for ( auto const & src : m_sourceCodes )
{
2017-05-23 16:57:06 +00:00
string machine =
2019-02-13 11:07:20 +00:00
_targetMachine = = yul : : AssemblyStack : : Machine : : EVM ? " EVM " :
_targetMachine = = yul : : AssemblyStack : : Machine : : EVM15 ? " EVM 1.5 " :
2019-12-09 16:36:12 +00:00
" Ewasm " ;
2018-09-13 02:36:14 +00:00
sout ( ) < < endl < < " ======= " < < src . first < < " ( " < < machine < < " ) ======= " < < endl ;
2019-11-27 18:36:58 +00:00
2019-02-13 11:07:20 +00:00
yul : : AssemblyStack & stack = assemblyStacks [ src . first ] ;
2017-05-29 23:12:38 +00:00
2018-09-13 02:36:14 +00:00
sout ( ) < < endl < < " Pretty printed source: " < < endl ;
sout ( ) < < stack . print ( ) < < endl ;
2017-05-29 23:12:38 +00:00
2019-12-09 16:36:12 +00:00
if ( _language ! = yul : : AssemblyStack : : Language : : Ewasm & & _targetMachine = = yul : : AssemblyStack : : Machine : : Ewasm )
2019-11-27 18:36:58 +00:00
{
2020-11-09 18:11:44 +00:00
try
{
stack . translate ( yul : : AssemblyStack : : Language : : Ewasm ) ;
stack . optimize ( ) ;
}
catch ( Exception const & _exception )
{
serr ( ) < < " Exception in assembler: " < < boost : : diagnostic_information ( _exception ) < < endl ;
return false ;
}
catch ( std : : exception const & _e )
{
serr ( ) < <
" Unknown exception during compilation " < <
( _e . what ( ) ? " : " + string ( _e . what ( ) ) : " . " ) < <
endl ;
return false ;
}
catch ( . . . )
{
serr ( ) < < " Unknown exception in assembler. " < < endl ;
return false ;
}
2019-11-27 18:36:58 +00:00
sout ( ) < < endl < < " ========================== " < < endl ;
sout ( ) < < endl < < " Translated source: " < < endl ;
sout ( ) < < stack . print ( ) < < endl ;
}
2019-02-13 11:07:20 +00:00
yul : : MachineAssemblyObject object ;
2017-05-23 16:57:06 +00:00
try
{
2019-03-27 11:49:50 +00:00
object = stack . assemble ( _targetMachine ) ;
2020-11-05 13:40:51 +00:00
object . bytecode - > link ( m_libraries ) ;
2017-05-23 16:57:06 +00:00
}
catch ( Exception const & _exception )
{
2018-09-13 02:36:14 +00:00
serr ( ) < < " Exception while assembling: " < < boost : : diagnostic_information ( _exception ) < < endl ;
2019-05-29 20:26:18 +00:00
return false ;
}
catch ( std : : exception const & _e )
{
serr ( ) < < " Unknown exception during compilation " < < (
_e . what ( ) ? " : " + string ( _e . what ( ) ) : " . "
) < < endl ;
2017-05-23 16:57:06 +00:00
return false ;
}
catch ( . . . )
{
2018-09-13 02:36:14 +00:00
serr ( ) < < " Unknown exception while assembling. " < < endl ;
2017-05-23 16:57:06 +00:00
return false ;
}
2017-05-29 23:12:38 +00:00
2018-09-13 02:36:14 +00:00
sout ( ) < < endl < < " Binary representation: " < < endl ;
2017-05-29 22:50:46 +00:00
if ( object . bytecode )
2018-09-13 02:36:14 +00:00
sout ( ) < < object . bytecode - > toHex ( ) < < endl ;
2017-05-29 22:50:46 +00:00
else
2018-09-13 02:36:14 +00:00
serr ( ) < < " No binary representation found. " < < endl ;
2017-05-29 23:12:38 +00:00
2018-09-13 02:36:14 +00:00
sout ( ) < < endl < < " Text representation: " < < endl ;
2017-05-29 22:58:03 +00:00
if ( ! object . assembly . empty ( ) )
2018-09-13 02:36:14 +00:00
sout ( ) < < object . assembly < < endl ;
2017-05-29 22:58:03 +00:00
else
2018-09-13 02:36:14 +00:00
serr ( ) < < " No text representation found. " < < endl ;
2016-03-01 21:56:39 +00:00
}
2017-05-23 10:13:34 +00:00
return true ;
2016-03-01 21:56:39 +00:00
}
2015-09-11 17:35:01 +00:00
void CommandLineInterface : : outputCompilationResults ( )
2015-01-05 14:46:40 +00:00
{
2015-04-23 12:40:42 +00:00
handleCombinedJSON ( ) ;
2015-01-05 14:46:40 +00:00
// do we need AST output?
handleAst ( g_argAstJson ) ;
2017-05-22 13:47:09 +00:00
handleAst ( g_argAstCompactJson ) ;
2014-12-09 12:43:08 +00:00
2020-07-08 20:08:50 +00:00
if (
! m_compiler - > compilationSuccessful ( ) & &
m_stopAfter = = CompilerStack : : State : : CompilationSuccessful
)
2019-05-28 15:24:54 +00:00
{
serr ( ) < < endl < < " Compilation halted after AST generation due to errors. " < < endl ;
return ;
}
2015-08-31 16:44:29 +00:00
vector < string > contracts = m_compiler - > contractNames ( ) ;
2014-12-09 12:43:08 +00:00
for ( string const & contract : contracts )
{
2015-04-23 12:40:42 +00:00
if ( needsHumanTargetedStdout ( m_args ) )
2018-09-13 02:36:14 +00:00
sout ( ) < < endl < < " ======= " < < contract < < " ======= " < < endl ;
2014-12-09 12:43:08 +00:00
// do we need EVM assembly?
2016-10-22 15:02:28 +00:00
if ( m_args . count ( g_argAsm ) | | m_args . count ( g_argAsmJson ) )
2014-12-09 12:43:08 +00:00
{
2017-09-11 14:18:56 +00:00
string ret ;
if ( m_args . count ( g_argAsmJson ) )
2020-04-27 08:28:54 +00:00
ret = jsonPrettyPrint ( removeNullMembers ( m_compiler - > assemblyJSON ( contract ) ) ) ;
2017-09-11 14:18:56 +00:00
else
ret = m_compiler - > assemblyString ( contract , m_sourceCodes ) ;
2016-10-22 15:02:28 +00:00
if ( m_args . count ( g_argOutputDir ) )
2014-12-09 12:43:08 +00:00
{
2017-09-11 14:18:56 +00:00
createFile ( m_compiler - > filesystemFriendlyName ( contract ) + ( m_args . count ( g_argAsmJson ) ? " _evm.json " : " .evm " ) , ret ) ;
2014-12-09 12:43:08 +00:00
}
2015-08-10 10:40:02 +00:00
else
{
2018-09-13 02:36:14 +00:00
sout ( ) < < " EVM assembly: " < < endl < < ret < < endl ;
2015-08-10 10:40:02 +00:00
}
2014-12-09 12:43:08 +00:00
}
2015-05-22 12:19:58 +00:00
if ( m_args . count ( g_argGas ) )
handleGasEstimation ( contract ) ;
2014-12-09 19:29:29 +00:00
handleBytecode ( contract ) ;
2019-03-04 22:26:46 +00:00
handleIR ( contract ) ;
2020-02-26 14:50:34 +00:00
handleIROptimized ( contract ) ;
2019-12-09 16:36:12 +00:00
handleEwasm ( contract ) ;
2015-05-04 14:21:44 +00:00
handleSignatureHashes ( contract ) ;
2017-05-19 15:10:32 +00:00
handleMetadata ( contract ) ;
2017-05-06 17:02:56 +00:00
handleABI ( contract ) ;
2020-03-24 12:22:25 +00:00
handleStorageLayout ( contract ) ;
2017-07-27 10:28:04 +00:00
handleNatspec ( true , contract ) ;
handleNatspec ( false , contract ) ;
2014-12-09 12:43:08 +00:00
} // end of contracts iteration
2018-09-13 02:36:14 +00:00
if ( ! g_hasOutput )
{
if ( m_args . count ( g_argOutputDir ) )
sout ( ) < < " Compiler run successful. Artifact(s) can be found in directory " < < m_args . at ( g_argOutputDir ) . as < string > ( ) < < " . " < < endl ;
else
serr ( ) < < " Compiler run successful, no output requested. " < < endl ;
}
2014-12-09 12:43:08 +00:00
}
2020-05-29 22:25:06 +00:00
size_t CommandLineInterface : : countEnabledOptions ( vector < string > const & _optionNames ) const
{
size_t count = 0 ;
for ( string const & _option : _optionNames )
count + = m_args . count ( _option ) ;
return count ;
}
string CommandLineInterface : : joinOptionNames ( vector < string > const & _optionNames , string _separator )
{
return boost : : algorithm : : join (
_optionNames | boost : : adaptors : : transformed ( [ ] ( string const & _option ) { return " -- " + _option ; } ) ,
_separator
) ;
}
2014-12-09 12:43:08 +00:00
}