2017-02-09 21:56:49 +00:00
/*
This file is part of solidity .
solidity is free software : you can redistribute it and / or modify
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 .
solidity is distributed in the hope that it will be useful ,
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
along with solidity . If not , see < http : //www.gnu.org/licenses/>.
*/
2020-07-17 14:54:12 +00:00
// SPDX-License-Identifier: GPL-3.0
2017-02-09 21:56:49 +00:00
/**
* @ author Alex Beregszaszi
* @ date 2016
* Standard JSON compiler interface .
*/
# include <libsolidity/interface/StandardCompiler.h>
2021-03-29 12:46:19 +00:00
# include <libsolidity/interface/ImportRemapper.h>
2018-12-17 18:24:42 +00:00
2022-06-16 16:05:51 +00:00
# include <libsolidity/ast/ASTJsonExporter.h>
2022-03-28 04:27:11 +00:00
# include <libyul/YulStack.h>
2019-12-03 18:05:58 +00:00
# include <libyul/Exceptions.h>
2020-04-24 12:26:31 +00:00
# include <libyul/optimiser/Suite.h>
2021-09-17 18:15:19 +00:00
2022-03-02 12:47:04 +00:00
# include <libevmasm/Disassemble.h>
2021-09-17 18:15:19 +00:00
2020-05-20 10:55:12 +00:00
# include <libsmtutil/Exceptions.h>
2021-09-17 18:15:19 +00:00
# include <liblangutil/SourceReferenceFormatter.h>
2020-01-06 10:52:23 +00:00
# include <libsolutil/JSON.h>
# include <libsolutil/Keccak256.h>
2020-05-12 14:33:05 +00:00
# include <libsolutil/CommonData.h>
2017-02-09 21:56:49 +00:00
2020-05-11 11:38:49 +00:00
# include <boost/algorithm/string/predicate.hpp>
2019-10-28 10:39:30 +00:00
2018-12-17 18:24:42 +00:00
# include <algorithm>
2019-10-28 10:39:30 +00:00
# include <optional>
2018-02-28 15:57:35 +00:00
2017-02-09 21:56:49 +00:00
using namespace std ;
2019-12-11 16:31:36 +00:00
using namespace solidity ;
using namespace solidity : : yul ;
using namespace solidity : : frontend ;
using namespace solidity : : langutil ;
2017-02-09 21:56:49 +00:00
2019-07-03 12:21:09 +00:00
namespace
{
2017-04-19 13:11:31 +00:00
2017-03-29 14:40:15 +00:00
Json : : Value formatError (
2022-06-17 03:25:52 +00:00
Error : : Type _type ,
2017-03-29 14:40:15 +00:00
string const & _component ,
string const & _message ,
string const & _formattedMessage = " " ,
2019-07-03 12:21:09 +00:00
Json : : Value const & _sourceLocation = Json : : Value ( ) ,
Json : : Value const & _secondarySourceLocation = Json : : Value ( )
2017-03-29 14:40:15 +00:00
)
2017-03-21 11:18:00 +00:00
{
2021-09-15 18:09:03 +00:00
Json : : Value error { Json : : objectValue } ;
2022-06-17 03:25:52 +00:00
error [ " type " ] = Error : : formatErrorType ( _type ) ;
2017-03-29 14:40:15 +00:00
error [ " component " ] = _component ;
2022-06-17 03:25:52 +00:00
error [ " severity " ] = Error : : formatErrorSeverityLowercase ( Error : : errorSeverity ( _type ) ) ;
2017-03-29 14:40:15 +00:00
error [ " message " ] = _message ;
error [ " formattedMessage " ] = ( _formattedMessage . length ( ) > 0 ) ? _formattedMessage : _message ;
if ( _sourceLocation . isObject ( ) )
error [ " sourceLocation " ] = _sourceLocation ;
2019-07-03 12:21:09 +00:00
if ( _secondarySourceLocation . isArray ( ) )
error [ " secondarySourceLocations " ] = _secondarySourceLocation ;
2017-03-29 14:40:15 +00:00
return error ;
}
2017-03-21 11:18:00 +00:00
2022-06-17 03:25:52 +00:00
Json : : Value formatFatalError ( Error : : Type _type , string const & _message )
2017-03-29 14:40:15 +00:00
{
2021-09-15 18:09:03 +00:00
Json : : Value output { Json : : objectValue } ;
2017-03-21 11:18:00 +00:00
output [ " errors " ] = Json : : arrayValue ;
2022-06-17 03:25:52 +00:00
output [ " errors " ] . append ( formatError ( _type , " general " , _message ) ) ;
2017-03-21 11:18:00 +00:00
return output ;
}
2019-07-03 12:21:09 +00:00
Json : : Value formatSourceLocation ( SourceLocation const * location )
{
2021-09-15 18:09:03 +00:00
if ( ! location | | ! location - > sourceName )
return Json : : nullValue ;
2019-07-03 12:21:09 +00:00
2021-09-15 18:09:03 +00:00
Json : : Value sourceLocation { Json : : objectValue } ;
sourceLocation [ " file " ] = * location - > sourceName ;
sourceLocation [ " start " ] = location - > start ;
sourceLocation [ " end " ] = location - > end ;
2019-07-03 12:21:09 +00:00
return sourceLocation ;
}
Json : : Value formatSecondarySourceLocation ( SecondarySourceLocation const * _secondaryLocation )
{
if ( ! _secondaryLocation )
2021-09-15 18:09:03 +00:00
return Json : : nullValue ;
2019-07-03 12:21:09 +00:00
2021-09-15 18:09:03 +00:00
Json : : Value secondarySourceLocation { Json : : arrayValue } ;
2019-07-03 12:21:09 +00:00
for ( auto const & location : _secondaryLocation - > infos )
{
Json : : Value msg = formatSourceLocation ( & location . second ) ;
msg [ " message " ] = location . first ;
secondarySourceLocation . append ( msg ) ;
}
return secondarySourceLocation ;
}
2017-03-29 20:50:53 +00:00
Json : : Value formatErrorWithException (
2021-06-29 12:38:59 +00:00
CharStreamProvider const & _charStreamProvider ,
2019-12-11 16:31:36 +00:00
util : : Exception const & _exception ,
2022-06-17 03:25:52 +00:00
Error : : Type _type ,
2017-03-29 20:50:53 +00:00
string const & _component ,
2020-05-29 23:42:36 +00:00
string const & _message ,
optional < ErrorId > _errorId = nullopt
2017-03-29 20:50:53 +00:00
)
{
string message ;
2020-11-02 14:29:33 +00:00
// TODO: consider enabling color
2021-06-29 12:38:59 +00:00
string formattedMessage = SourceReferenceFormatter : : formatExceptionInformation (
_exception ,
_type ,
2022-06-17 03:25:52 +00:00
_charStreamProvider ,
false , // colored
2022-09-06 10:12:15 +00:00
false // _withErrorIds
2021-06-29 12:38:59 +00:00
) ;
2017-03-29 20:50:53 +00:00
2021-12-01 11:30:36 +00:00
if ( string const * description = _exception . comment ( ) )
2017-03-29 20:50:53 +00:00
message = ( ( _message . length ( ) > 0 ) ? ( _message + " : " ) : " " ) + * description ;
else
message = _message ;
2020-05-29 23:42:36 +00:00
Json : : Value error = formatError (
2019-07-03 12:21:09 +00:00
_type ,
_component ,
message ,
formattedMessage ,
formatSourceLocation ( boost : : get_error_info < errinfo_sourceLocation > ( _exception ) ) ,
formatSecondarySourceLocation ( boost : : get_error_info < errinfo_secondarySourceLocation > ( _exception ) )
) ;
2020-05-29 23:42:36 +00:00
if ( _errorId )
error [ " errorCode " ] = to_string ( _errorId . value ( ) . error ) ;
return error ;
2017-03-29 20:50:53 +00:00
}
2019-06-28 14:14:31 +00:00
map < string , set < string > > requestedContractNames ( Json : : Value const & _outputSelection )
2017-09-29 18:05:39 +00:00
{
2019-06-28 14:14:31 +00:00
map < string , set < string > > contracts ;
2017-09-29 18:05:39 +00:00
for ( auto const & sourceName : _outputSelection . getMemberNames ( ) )
{
2019-06-28 14:14:31 +00:00
string key = ( sourceName = = " * " ) ? " " : sourceName ;
2017-09-29 18:05:39 +00:00
for ( auto const & contractName : _outputSelection [ sourceName ] . getMemberNames ( ) )
{
2019-06-28 14:14:31 +00:00
string value = ( contractName = = " * " ) ? " " : contractName ;
contracts [ key ] . insert ( value ) ;
2017-09-29 18:05:39 +00:00
}
}
2019-06-28 14:14:31 +00:00
return contracts ;
2017-09-29 18:05:39 +00:00
}
2017-04-22 13:43:10 +00:00
/// Returns true iff @a _hash (hex with 0x prefix) is the Keccak256 hash of the binary data in @a _content.
bool hashMatchesContent ( string const & _hash , string const & _content )
{
try
{
2019-12-11 16:31:36 +00:00
return util : : h256 ( _hash ) = = util : : keccak256 ( _content ) ;
2017-04-22 13:43:10 +00:00
}
2019-12-11 16:31:36 +00:00
catch ( util : : BadHexCharacter const & )
2017-04-22 13:43:10 +00:00
{
return false ;
}
}
2019-06-18 16:11:04 +00:00
bool isArtifactRequested ( Json : : Value const & _outputSelection , string const & _artifact , bool _wildcardMatchesExperimental )
2017-03-30 10:16:28 +00:00
{
2023-05-02 13:34:12 +00:00
static set < string > experimental { " ir " , " irAst " , " irOptimized " , " irOptimizedAst " } ;
2020-12-03 10:27:21 +00:00
for ( auto const & selectedArtifactJson : _outputSelection )
{
string const & selectedArtifact = selectedArtifactJson . asString ( ) ;
if (
_artifact = = selectedArtifact | |
boost : : algorithm : : starts_with ( _artifact , selectedArtifact + " . " )
)
2017-03-30 10:16:28 +00:00
return true ;
2020-12-03 10:27:21 +00:00
else if ( selectedArtifact = = " * " )
2019-03-04 22:26:46 +00:00
{
2023-02-22 15:32:29 +00:00
// "ir", "irOptimized" can only be matched by "*" if activated.
2019-06-18 16:11:04 +00:00
if ( experimental . count ( _artifact ) = = 0 | | _wildcardMatchesExperimental )
2019-03-04 22:26:46 +00:00
return true ;
}
2020-12-03 10:27:21 +00:00
}
2017-03-30 10:16:28 +00:00
return false ;
}
///
2020-05-24 17:41:15 +00:00
/// @a _outputSelection is a JSON object containing a two-level hashmap, where the first level is the filename,
2017-11-22 12:55:44 +00:00
/// the second level is the contract name and the value is an array of artifact names to be requested for that contract.
2017-03-30 10:16:28 +00:00
/// @a _file is the current file
/// @a _contract is the current contract
2017-11-22 12:55:44 +00:00
/// @a _artifact is the current artifact name
2017-03-30 10:16:28 +00:00
///
2017-11-22 12:55:44 +00:00
/// @returns true if the @a _outputSelection has a match for the requested target in the specific file / contract.
2017-03-30 10:16:28 +00:00
///
2017-11-22 12:55:44 +00:00
/// In @a _outputSelection the use of '*' as a wildcard is permitted.
2017-03-30 10:16:28 +00:00
///
/// @TODO optimise this. Perhaps flatten the structure upfront.
///
2019-06-18 16:11:04 +00:00
bool isArtifactRequested ( Json : : Value const & _outputSelection , string const & _file , string const & _contract , string const & _artifact , bool _wildcardMatchesExperimental )
2017-03-30 10:16:28 +00:00
{
2017-11-22 12:55:44 +00:00
if ( ! _outputSelection . isObject ( ) )
2017-03-30 10:16:28 +00:00
return false ;
for ( auto const & file : { _file , string ( " * " ) } )
2017-11-22 12:55:44 +00:00
if ( _outputSelection . isMember ( file ) & & _outputSelection [ file ] . isObject ( ) )
2017-03-30 10:16:28 +00:00
{
2017-11-22 13:35:01 +00:00
/// For SourceUnit-level targets (such as AST) only allow empty name, otherwise
/// for Contract-level targets try both contract name and wildcard
vector < string > contracts { _contract } ;
if ( ! _contract . empty ( ) )
2020-04-01 02:39:38 +00:00
contracts . emplace_back ( " * " ) ;
2017-11-22 13:35:01 +00:00
for ( auto const & contract : contracts )
2017-03-30 10:16:28 +00:00
if (
2017-11-22 13:35:01 +00:00
_outputSelection [ file ] . isMember ( contract ) & &
_outputSelection [ file ] [ contract ] . isArray ( ) & &
2019-06-18 16:11:04 +00:00
isArtifactRequested ( _outputSelection [ file ] [ contract ] , _artifact , _wildcardMatchesExperimental )
2017-03-30 10:16:28 +00:00
)
return true ;
}
return false ;
}
2019-06-18 16:11:04 +00:00
bool isArtifactRequested ( Json : : Value const & _outputSelection , string const & _file , string const & _contract , vector < string > const & _artifacts , bool _wildcardMatchesExperimental )
2017-10-19 13:09:40 +00:00
{
2017-11-22 12:55:44 +00:00
for ( auto const & artifact : _artifacts )
2019-06-18 16:11:04 +00:00
if ( isArtifactRequested ( _outputSelection , _file , _contract , artifact , _wildcardMatchesExperimental ) )
2017-10-19 13:09:40 +00:00
return true ;
return false ;
}
2020-09-15 09:21:13 +00:00
/// @returns all artifact names of the EVM object, either for creation or deploy time.
vector < string > evmObjectComponents ( string const & _objectKind )
{
solAssert ( _objectKind = = " bytecode " | | _objectKind = = " deployedBytecode " , " " ) ;
2020-05-07 12:46:47 +00:00
vector < string > components { " " , " .object " , " .opcodes " , " .sourceMap " , " .functionDebugData " , " .generatedSources " , " .linkReferences " } ;
2020-09-15 09:21:13 +00:00
if ( _objectKind = = " deployedBytecode " )
components . push_back ( " .immutableReferences " ) ;
return util : : applyMap ( components , [ & ] ( auto const & _s ) { return " evm. " + _objectKind + _s ; } ) ;
}
2018-12-18 17:28:14 +00:00
/// @returns true if any binary was requested, i.e. we actually have to perform compilation.
bool isBinaryRequested ( Json : : Value const & _outputSelection )
{
if ( ! _outputSelection . isObject ( ) )
return false ;
2020-05-24 17:41:15 +00:00
// This does not include "evm.methodIdentifiers" on purpose!
2020-09-15 09:21:13 +00:00
static vector < string > const outputsThatRequireBinaries = vector < string > {
2018-12-18 17:28:14 +00:00
" * " ,
2023-05-02 13:34:12 +00:00
" ir " , " irAst " , " irOptimized " , " irOptimizedAst " ,
2018-12-18 17:28:14 +00:00
" evm.gasEstimates " , " evm.legacyAssembly " , " evm.assembly "
2020-09-15 09:21:13 +00:00
} + evmObjectComponents ( " bytecode " ) + evmObjectComponents ( " deployedBytecode " ) ;
2018-12-18 17:28:14 +00:00
for ( auto const & fileRequests : _outputSelection )
for ( auto const & requests : fileRequests )
for ( auto const & output : outputsThatRequireBinaries )
2019-03-04 22:26:46 +00:00
if ( isArtifactRequested ( requests , output , false ) )
return true ;
return false ;
}
2020-08-06 09:43:36 +00:00
/// @returns true if EVM bytecode was requested, i.e. we have to run the old code generator.
bool isEvmBytecodeRequested ( Json : : Value const & _outputSelection )
{
if ( ! _outputSelection . isObject ( ) )
return false ;
2020-09-15 09:21:13 +00:00
static vector < string > const outputsThatRequireEvmBinaries = vector < string > {
2020-08-06 09:43:36 +00:00
" * " ,
" evm.gasEstimates " , " evm.legacyAssembly " , " evm.assembly "
2020-09-15 09:21:13 +00:00
} + evmObjectComponents ( " bytecode " ) + evmObjectComponents ( " deployedBytecode " ) ;
2020-08-06 09:43:36 +00:00
for ( auto const & fileRequests : _outputSelection )
for ( auto const & requests : fileRequests )
for ( auto const & output : outputsThatRequireEvmBinaries )
if ( isArtifactRequested ( requests , output , false ) )
return true ;
return false ;
}
2019-03-04 22:26:46 +00:00
/// @returns true if any Yul IR was requested. Note that as an exception, '*' does not
2023-05-02 13:34:12 +00:00
/// yet match "ir", "irAst", "irOptimized" or "irOptimizedAst"
2019-03-04 22:26:46 +00:00
bool isIRRequested ( Json : : Value const & _outputSelection )
{
if ( ! _outputSelection . isObject ( ) )
return false ;
for ( auto const & fileRequests : _outputSelection )
for ( auto const & requests : fileRequests )
for ( auto const & request : requests )
2023-05-02 13:34:12 +00:00
if (
request = = " ir " | |
request = = " irAst " | |
request = = " irOptimized " | |
request = = " irOptimizedAst "
)
2018-12-18 17:28:14 +00:00
return true ;
2019-03-04 22:26:46 +00:00
2018-12-18 17:28:14 +00:00
return false ;
}
2017-03-30 01:09:42 +00:00
Json : : Value formatLinkReferences ( std : : map < size_t , std : : string > const & linkReferences )
{
2021-09-15 18:09:03 +00:00
Json : : Value ret { Json : : objectValue } ;
2017-03-30 01:09:42 +00:00
for ( auto const & ref : linkReferences )
{
string const & fullname = ref . second ;
2020-11-13 13:15:59 +00:00
// If the link reference does not contain a colon, assume that the file name is missing and
// the whole string represents the library name.
2018-01-05 13:24:07 +00:00
size_t colon = fullname . rfind ( ' : ' ) ;
2020-11-13 13:15:59 +00:00
string file = ( colon ! = string : : npos ? fullname . substr ( 0 , colon ) : " " ) ;
string name = ( colon ! = string : : npos ? fullname . substr ( colon + 1 ) : fullname ) ;
2017-03-30 01:09:42 +00:00
Json : : Value fileObject = ret . get ( file , Json : : objectValue ) ;
Json : : Value libraryArray = fileObject . get ( name , Json : : arrayValue ) ;
2021-09-15 18:09:03 +00:00
Json : : Value entry { Json : : objectValue } ;
2017-03-30 01:09:42 +00:00
entry [ " start " ] = Json : : UInt ( ref . first ) ;
entry [ " length " ] = 20 ;
libraryArray . append ( entry ) ;
fileObject [ name ] = libraryArray ;
ret [ file ] = fileObject ;
}
return ret ;
}
2020-04-02 15:27:35 +00:00
Json : : Value formatImmutableReferences ( map < u256 , pair < string , vector < size_t > > > const & _immutableReferences )
{
2021-09-15 18:09:03 +00:00
Json : : Value ret { Json : : objectValue } ;
2020-04-02 15:27:35 +00:00
for ( auto const & immutableReference : _immutableReferences )
{
auto const & [ identifier , byteOffsets ] = immutableReference . second ;
Json : : Value array ( Json : : arrayValue ) ;
for ( size_t byteOffset : byteOffsets )
{
2021-09-15 18:09:03 +00:00
Json : : Value byteRange { Json : : objectValue } ;
2020-04-06 09:21:53 +00:00
byteRange [ " start " ] = Json : : UInt ( byteOffset ) ;
byteRange [ " length " ] = Json : : UInt ( 32 ) ; // immutable references are currently always 32 bytes wide
2020-04-02 15:27:35 +00:00
array . append ( byteRange ) ;
}
ret [ identifier ] = array ;
}
return ret ;
}
2020-05-28 11:17:16 +00:00
Json : : Value collectEVMObject (
2022-11-23 10:51:34 +00:00
langutil : : EVMVersion _evmVersion ,
2020-05-28 11:17:16 +00:00
evmasm : : LinkerObject const & _object ,
string const * _sourceMap ,
Json : : Value _generatedSources ,
2020-12-03 10:27:21 +00:00
bool _runtimeObject ,
function < bool ( string ) > const & _artifactRequested
2020-05-28 11:17:16 +00:00
)
2017-04-19 14:52:54 +00:00
{
2021-09-15 18:09:03 +00:00
Json : : Value output { Json : : objectValue } ;
2020-12-03 10:27:21 +00:00
if ( _artifactRequested ( " object " ) )
output [ " object " ] = _object . toHex ( ) ;
if ( _artifactRequested ( " opcodes " ) )
2022-11-23 10:51:34 +00:00
output [ " opcodes " ] = evmasm : : disassemble ( _object . bytecode , _evmVersion ) ;
2020-12-03 10:27:21 +00:00
if ( _artifactRequested ( " sourceMap " ) )
output [ " sourceMap " ] = _sourceMap ? * _sourceMap : " " ;
2020-05-07 12:46:47 +00:00
if ( _artifactRequested ( " functionDebugData " ) )
output [ " functionDebugData " ] = StandardCompiler : : formatFunctionDebugData ( _object . functionDebugData ) ;
2020-12-03 10:27:21 +00:00
if ( _artifactRequested ( " linkReferences " ) )
output [ " linkReferences " ] = formatLinkReferences ( _object . linkReferences ) ;
if ( _runtimeObject & & _artifactRequested ( " immutableReferences " ) )
2020-04-02 15:27:35 +00:00
output [ " immutableReferences " ] = formatImmutableReferences ( _object . immutableReferences ) ;
2020-12-03 10:27:21 +00:00
if ( _artifactRequested ( " generatedSources " ) )
2022-08-23 17:28:45 +00:00
output [ " generatedSources " ] = std : : move ( _generatedSources ) ;
2017-04-19 14:52:54 +00:00
return output ;
}
2019-10-28 10:39:30 +00:00
std : : optional < Json : : Value > checkKeys ( Json : : Value const & _input , set < string > const & _keys , string const & _name )
2018-12-11 14:47:19 +00:00
{
2018-12-12 14:49:10 +00:00
if ( ! ! _input & & ! _input . isObject ( ) )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " \" " + _name + " \" must be an object " ) ;
2018-12-12 14:49:10 +00:00
2018-12-11 14:47:19 +00:00
for ( auto const & member : _input . getMemberNames ( ) )
if ( ! _keys . count ( member ) )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " Unknown key \" " + member + " \" " ) ;
2018-12-12 14:49:10 +00:00
2019-10-28 10:39:30 +00:00
return std : : nullopt ;
2018-12-11 14:47:19 +00:00
}
2019-10-28 10:39:30 +00:00
std : : optional < Json : : Value > checkRootKeys ( Json : : Value const & _input )
2018-12-11 14:47:19 +00:00
{
2020-12-09 14:15:49 +00:00
static set < string > keys { " auxiliaryInput " , " language " , " settings " , " sources " } ;
2018-12-12 14:49:10 +00:00
return checkKeys ( _input , keys , " root " ) ;
2018-12-11 14:47:19 +00:00
}
2019-10-28 10:39:30 +00:00
std : : optional < Json : : Value > checkSourceKeys ( Json : : Value const & _input , string const & _name )
2018-12-11 14:47:19 +00:00
{
static set < string > keys { " content " , " keccak256 " , " urls " } ;
2018-12-12 14:49:10 +00:00
return checkKeys ( _input , keys , " sources. " + _name ) ;
2018-12-11 14:47:19 +00:00
}
2019-10-28 10:39:30 +00:00
std : : optional < Json : : Value > checkAuxiliaryInputKeys ( Json : : Value const & _input )
2018-12-11 14:47:19 +00:00
{
static set < string > keys { " smtlib2responses " } ;
2018-12-12 14:49:10 +00:00
return checkKeys ( _input , keys , " auxiliaryInput " ) ;
2018-12-11 14:47:19 +00:00
}
2019-10-28 10:39:30 +00:00
std : : optional < Json : : Value > checkSettingsKeys ( Json : : Value const & _input )
2018-12-11 14:47:19 +00:00
{
2020-12-09 14:15:49 +00:00
static set < string > keys { " parserErrorRecovery " , " debug " , " evmVersion " , " libraries " , " metadata " , " modelChecker " , " optimizer " , " outputSelection " , " remappings " , " stopAfter " , " viaIR " } ;
2018-12-12 14:49:10 +00:00
return checkKeys ( _input , keys , " settings " ) ;
2018-12-11 14:47:19 +00:00
}
2020-10-19 09:37:23 +00:00
std : : optional < Json : : Value > checkModelCheckerSettingsKeys ( Json : : Value const & _input )
{
2023-04-26 10:50:36 +00:00
static set < string > keys { " bmcLoopIterations " , " contracts " , " divModNoSlacks " , " engine " , " extCalls " , " invariants " , " printQuery " , " showProvedSafe " , " showUnproved " , " showUnsupported " , " solvers " , " targets " , " timeout " } ;
2020-12-09 14:15:49 +00:00
return checkKeys ( _input , keys , " modelChecker " ) ;
2020-10-19 09:37:23 +00:00
}
2019-10-28 10:39:30 +00:00
std : : optional < Json : : Value > checkOptimizerKeys ( Json : : Value const & _input )
2018-12-11 14:47:19 +00:00
{
2019-02-21 16:39:47 +00:00
static set < string > keys { " details " , " enabled " , " runs " } ;
2018-12-12 14:49:10 +00:00
return checkKeys ( _input , keys , " settings.optimizer " ) ;
2018-12-11 14:47:19 +00:00
}
2019-10-28 10:39:30 +00:00
std : : optional < Json : : Value > checkOptimizerDetailsKeys ( Json : : Value const & _input )
2019-02-21 16:39:47 +00:00
{
2021-05-20 19:21:54 +00:00
static set < string > keys { " peephole " , " inliner " , " jumpdestRemover " , " orderLiterals " , " deduplicate " , " cse " , " constantOptimizer " , " yul " , " yulDetails " } ;
2019-02-21 16:39:47 +00:00
return checkKeys ( _input , keys , " settings.optimizer.details " ) ;
}
2019-10-28 10:39:30 +00:00
std : : optional < Json : : Value > checkOptimizerDetail ( Json : : Value const & _details , std : : string const & _name , bool & _setting )
2019-02-21 16:39:47 +00:00
{
if ( _details . isMember ( _name ) )
{
if ( ! _details [ _name ] . isBool ( ) )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " \" settings.optimizer.details. " + _name + " \" must be Boolean " ) ;
2019-02-21 16:39:47 +00:00
_setting = _details [ _name ] . asBool ( ) ;
}
return { } ;
}
2022-08-10 13:57:01 +00:00
std : : optional < Json : : Value > checkOptimizerDetailSteps ( Json : : Value const & _details , std : : string const & _name , string & _optimiserSetting , string & _cleanupSetting )
2020-04-24 12:26:31 +00:00
{
if ( _details . isMember ( _name ) )
{
if ( _details [ _name ] . isString ( ) )
{
try
{
yul : : OptimiserSuite : : validateSequence ( _details [ _name ] . asString ( ) ) ;
}
catch ( yul : : OptimizerException const & _exception )
{
return formatFatalError (
2022-06-17 03:25:52 +00:00
Error : : Type : : JSONError ,
2020-04-24 12:26:31 +00:00
" Invalid optimizer step sequence in \" settings.optimizer.details. " + _name + " \" : " + _exception . what ( )
) ;
}
2022-08-23 09:58:12 +00:00
string const fullSequence = _details [ _name ] . asString ( ) ;
2022-08-10 13:57:01 +00:00
auto const delimiterPos = fullSequence . find ( " : " ) ;
_optimiserSetting = fullSequence . substr ( 0 , delimiterPos ) ;
if ( delimiterPos ! = string : : npos )
_cleanupSetting = fullSequence . substr ( delimiterPos + 1 ) ;
2022-09-12 08:57:02 +00:00
else
solAssert ( _cleanupSetting = = OptimiserSettings : : DefaultYulOptimiserCleanupSteps ) ;
2020-04-24 12:26:31 +00:00
}
else
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " \" settings.optimizer.details. " + _name + " \" must be a string " ) ;
2020-04-24 12:26:31 +00:00
}
return { } ;
}
2019-10-28 10:39:30 +00:00
std : : optional < Json : : Value > checkMetadataKeys ( Json : : Value const & _input )
2018-12-11 14:47:19 +00:00
{
2019-09-06 17:11:07 +00:00
if ( _input . isObject ( ) )
{
2022-07-11 22:50:32 +00:00
if ( _input . isMember ( " appendCBOR " ) & & ! _input [ " appendCBOR " ] . isBool ( ) )
return formatFatalError ( Error : : Type : : JSONError , " \" settings.metadata.appendCBOR \" must be Boolean " ) ;
2019-09-06 17:11:07 +00:00
if ( _input . isMember ( " useLiteralContent " ) & & ! _input [ " useLiteralContent " ] . isBool ( ) )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " \" settings.metadata.useLiteralContent \" must be Boolean " ) ;
2019-09-06 17:11:07 +00:00
static set < string > hashes { " ipfs " , " bzzr1 " , " none " } ;
if ( _input . isMember ( " bytecodeHash " ) & & ! hashes . count ( _input [ " bytecodeHash " ] . asString ( ) ) )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " \" settings.metadata.bytecodeHash \" must be \" ipfs \" , \" bzzr1 \" or \" none \" " ) ;
2019-09-06 17:11:07 +00:00
}
2022-07-11 22:50:32 +00:00
static set < string > keys { " appendCBOR " , " useLiteralContent " , " bytecodeHash " } ;
2018-12-12 14:49:10 +00:00
return checkKeys ( _input , keys , " settings.metadata " ) ;
}
2019-10-28 10:39:30 +00:00
std : : optional < Json : : Value > checkOutputSelection ( Json : : Value const & _outputSelection )
2018-12-12 14:49:10 +00:00
{
if ( ! ! _outputSelection & & ! _outputSelection . isObject ( ) )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " \" settings.outputSelection \" must be an object " ) ;
2018-12-12 14:49:10 +00:00
for ( auto const & sourceName : _outputSelection . getMemberNames ( ) )
{
auto const & sourceVal = _outputSelection [ sourceName ] ;
if ( ! sourceVal . isObject ( ) )
return formatFatalError (
2022-06-17 03:25:52 +00:00
Error : : Type : : JSONError ,
2018-12-12 14:49:10 +00:00
" \" settings.outputSelection. " + sourceName + " \" must be an object "
) ;
for ( auto const & contractName : sourceVal . getMemberNames ( ) )
{
auto const & contractVal = sourceVal [ contractName ] ;
if ( ! contractVal . isArray ( ) )
return formatFatalError (
2022-06-17 03:25:52 +00:00
Error : : Type : : JSONError ,
2018-12-12 14:49:10 +00:00
" \" settings.outputSelection. " +
sourceName +
" . " +
contractName +
" \" must be a string array "
) ;
for ( auto const & output : contractVal )
if ( ! output . isString ( ) )
return formatFatalError (
2022-06-17 03:25:52 +00:00
Error : : Type : : JSONError ,
2018-12-12 14:49:10 +00:00
" \" settings.outputSelection. " +
sourceName +
" . " +
contractName +
" \" must be a string array "
) ;
}
}
2019-10-28 10:39:30 +00:00
return std : : nullopt ;
2018-12-11 14:47:19 +00:00
}
2020-10-14 15:44:40 +00:00
2019-03-07 14:35:31 +00:00
/// Validates the optimizer settings and returns them in a parsed object.
/// On error returns the json-formatted error message.
2020-05-11 11:38:49 +00:00
std : : variant < OptimiserSettings , Json : : Value > parseOptimizerSettings ( Json : : Value const & _jsonInput )
2019-02-21 16:39:47 +00:00
{
if ( auto result = checkOptimizerKeys ( _jsonInput ) )
return * result ;
2021-06-14 15:15:40 +00:00
OptimiserSettings settings = OptimiserSettings : : minimal ( ) ;
2019-02-21 16:39:47 +00:00
if ( _jsonInput . isMember ( " enabled " ) )
{
if ( ! _jsonInput [ " enabled " ] . isBool ( ) )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " The \" enabled \" setting must be a Boolean. " ) ;
2019-02-21 16:39:47 +00:00
2021-06-14 15:15:40 +00:00
if ( _jsonInput [ " enabled " ] . asBool ( ) )
settings = OptimiserSettings : : standard ( ) ;
2019-02-21 16:39:47 +00:00
}
if ( _jsonInput . isMember ( " runs " ) )
{
if ( ! _jsonInput [ " runs " ] . isUInt ( ) )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " The \" runs \" setting must be an unsigned number. " ) ;
2019-02-21 16:39:47 +00:00
settings . expectedExecutionsPerDeployment = _jsonInput [ " runs " ] . asUInt ( ) ;
}
if ( _jsonInput . isMember ( " details " ) )
{
Json : : Value const & details = _jsonInput [ " details " ] ;
if ( auto result = checkOptimizerDetailsKeys ( details ) )
return * result ;
if ( auto error = checkOptimizerDetail ( details , " peephole " , settings . runPeephole ) )
return * error ;
2021-01-14 12:02:14 +00:00
if ( auto error = checkOptimizerDetail ( details , " inliner " , settings . runInliner ) )
return * error ;
2019-02-21 16:39:47 +00:00
if ( auto error = checkOptimizerDetail ( details , " jumpdestRemover " , settings . runJumpdestRemover ) )
return * error ;
if ( auto error = checkOptimizerDetail ( details , " orderLiterals " , settings . runOrderLiterals ) )
return * error ;
if ( auto error = checkOptimizerDetail ( details , " deduplicate " , settings . runDeduplicate ) )
return * error ;
if ( auto error = checkOptimizerDetail ( details , " cse " , settings . runCSE ) )
return * error ;
if ( auto error = checkOptimizerDetail ( details , " constantOptimizer " , settings . runConstantOptimiser ) )
return * error ;
if ( auto error = checkOptimizerDetail ( details , " yul " , settings . runYulOptimiser ) )
return * error ;
2019-11-26 15:41:58 +00:00
settings . optimizeStackAllocation = settings . runYulOptimiser ;
2019-02-21 16:39:47 +00:00
if ( details . isMember ( " yulDetails " ) )
{
2019-02-26 18:55:13 +00:00
if ( ! settings . runYulOptimiser )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " \" Providing yulDetails requires Yul optimizer to be enabled. " ) ;
2019-02-26 18:55:13 +00:00
2020-04-24 12:26:31 +00:00
if ( auto result = checkKeys ( details [ " yulDetails " ] , { " stackAllocation " , " optimizerSteps " } , " settings.optimizer.details.yulDetails " ) )
2019-02-26 18:55:13 +00:00
return * result ;
if ( auto error = checkOptimizerDetail ( details [ " yulDetails " ] , " stackAllocation " , settings . optimizeStackAllocation ) )
return * error ;
2022-08-10 13:57:01 +00:00
if ( auto error = checkOptimizerDetailSteps ( details [ " yulDetails " ] , " optimizerSteps " , settings . yulOptimiserSteps , settings . yulOptimiserCleanupSteps ) )
2020-04-24 12:26:31 +00:00
return * error ;
2019-02-21 16:39:47 +00:00
}
}
2019-05-14 14:44:28 +00:00
return { std : : move ( settings ) } ;
2019-02-21 16:39:47 +00:00
}
2019-03-07 14:35:31 +00:00
}
2019-02-21 16:39:47 +00:00
2020-05-07 12:46:47 +00:00
2020-05-11 11:38:49 +00:00
std : : variant < StandardCompiler : : InputsAndSettings , Json : : Value > StandardCompiler : : parseInput ( Json : : Value const & _input )
2017-02-10 13:18:21 +00:00
{
2019-03-07 14:35:31 +00:00
InputsAndSettings ret ;
2017-02-10 13:18:21 +00:00
2017-04-19 14:53:11 +00:00
if ( ! _input . isObject ( ) )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " Input is not a JSON object. " ) ;
2017-04-19 14:53:11 +00:00
2018-12-11 14:47:19 +00:00
if ( auto result = checkRootKeys ( _input ) )
return * result ;
2017-04-21 14:34:40 +00:00
ret . language = _input [ " language " ] . asString ( ) ;
2017-04-19 14:53:11 +00:00
2017-02-10 13:18:21 +00:00
Json : : Value const & sources = _input [ " sources " ] ;
2018-02-13 20:40:16 +00:00
if ( ! sources . isObject ( ) & & ! sources . isNull ( ) )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " \" sources \" is not a JSON object. " ) ;
2018-02-13 20:40:16 +00:00
if ( sources . empty ( ) )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " No input sources specified. " ) ;
2017-02-10 13:18:21 +00:00
2019-03-07 14:35:31 +00:00
ret . errors = Json : : arrayValue ;
2017-04-19 15:45:36 +00:00
2023-04-28 16:29:59 +00:00
if ( ret . language = = " Solidity " | | ret . language = = " Yul " )
2017-04-22 13:43:10 +00:00
{
2023-04-28 16:29:59 +00:00
for ( auto const & sourceName : sources . getMemberNames ( ) )
{
string hash ;
2017-04-24 21:38:03 +00:00
2023-04-28 16:29:59 +00:00
if ( auto result = checkSourceKeys ( sources [ sourceName ] , sourceName ) )
return * result ;
2018-12-11 14:47:19 +00:00
2023-04-28 16:29:59 +00:00
if ( sources [ sourceName ] [ " keccak256 " ] . isString ( ) )
hash = sources [ sourceName ] [ " keccak256 " ] . asString ( ) ;
2017-04-22 13:43:10 +00:00
2023-04-28 16:29:59 +00:00
if ( sources [ sourceName ] [ " content " ] . isString ( ) )
{
string content = sources [ sourceName ] [ " content " ] . asString ( ) ;
if ( ! hash . empty ( ) & & ! hashMatchesContent ( hash , content ) )
ret . errors . append ( formatError (
Error : : Type : : IOError ,
" general " ,
" Mismatch between content and supplied hash for \" " + sourceName + " \" "
) ) ;
else
ret . sources [ sourceName ] = content ;
}
else if ( sources [ sourceName ] [ " urls " ] . isArray ( ) )
{
if ( ! m_readFile )
return formatFatalError (
Error : : Type : : JSONError , " No import callback supplied, but URL is requested. "
) ;
2017-04-19 15:45:36 +00:00
2023-04-28 16:29:59 +00:00
vector < string > failures ;
bool found = false ;
2017-04-19 15:45:36 +00:00
2023-04-28 16:29:59 +00:00
for ( auto const & url : sources [ sourceName ] [ " urls " ] )
2017-04-19 15:45:36 +00:00
{
2023-04-28 16:29:59 +00:00
if ( ! url . isString ( ) )
return formatFatalError ( Error : : Type : : JSONError , " URL must be a string. " ) ;
ReadCallback : : Result result = m_readFile ( ReadCallback : : kindString ( ReadCallback : : Kind : : ReadFile ) , url . asString ( ) ) ;
if ( result . success )
2017-04-22 13:43:10 +00:00
{
2023-04-28 16:29:59 +00:00
if ( ! hash . empty ( ) & & ! hashMatchesContent ( hash , result . responseOrErrorMessage ) )
ret . errors . append ( formatError (
Error : : Type : : IOError ,
" general " ,
" Mismatch between content and supplied hash for \" " + sourceName + " \" at \" " + url . asString ( ) + " \" "
) ) ;
else
{
ret . sources [ sourceName ] = result . responseOrErrorMessage ;
found = true ;
break ;
}
2017-04-22 13:43:10 +00:00
}
2023-04-28 16:29:59 +00:00
else
failures . push_back (
" Cannot import url ( \" " + url . asString ( ) + " \" ): " + result . responseOrErrorMessage
) ;
2017-04-19 15:45:36 +00:00
}
2023-04-28 16:29:59 +00:00
for ( auto const & failure : failures )
{
/// If the import succeeded, let mark all the others as warnings, otherwise all of them are errors.
ret . errors . append ( formatError (
found ? Error : : Type : : Warning : Error : : Type : : IOError ,
" general " ,
failure
) ) ;
}
2017-04-19 15:45:36 +00:00
}
2023-04-28 16:29:59 +00:00
else
return formatFatalError ( Error : : Type : : JSONError , " Invalid input source specified. " ) ;
2017-04-19 15:45:36 +00:00
}
2023-04-28 16:29:59 +00:00
}
else if ( ret . language = = " SolidityAST " )
{
for ( auto const & sourceName : sources . getMemberNames ( ) )
ret . sources [ sourceName ] = util : : jsonCompactPrint ( sources [ sourceName ] ) ;
2017-04-22 13:43:10 +00:00
}
2017-02-10 13:18:21 +00:00
2017-10-13 13:19:53 +00:00
Json : : Value const & auxInputs = _input [ " auxiliaryInput " ] ;
2018-12-11 14:47:19 +00:00
if ( auto result = checkAuxiliaryInputKeys ( auxInputs ) )
return * result ;
2017-10-13 13:19:53 +00:00
if ( ! ! auxInputs )
{
2018-08-03 14:48:20 +00:00
Json : : Value const & smtlib2Responses = auxInputs [ " smtlib2responses " ] ;
2017-10-13 13:19:53 +00:00
if ( ! ! smtlib2Responses )
2018-12-12 14:49:10 +00:00
{
if ( ! smtlib2Responses . isObject ( ) )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " \" auxiliaryInput.smtlib2responses \" must be an object. " ) ;
2018-12-12 14:49:10 +00:00
2017-10-13 13:19:53 +00:00
for ( auto const & hashString : smtlib2Responses . getMemberNames ( ) )
{
2019-12-11 16:31:36 +00:00
util : : h256 hash ;
2017-10-13 13:19:53 +00:00
try
{
2019-12-11 16:31:36 +00:00
hash = util : : h256 ( hashString ) ;
2017-10-13 13:19:53 +00:00
}
2019-12-11 16:31:36 +00:00
catch ( util : : BadHexCharacter const & )
2017-10-13 13:19:53 +00:00
{
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " Invalid hex encoding of SMTLib2 auxiliary input. " ) ;
2017-10-13 13:19:53 +00:00
}
2018-12-12 14:49:10 +00:00
if ( ! smtlib2Responses [ hashString ] . isString ( ) )
return formatFatalError (
2022-06-17 03:25:52 +00:00
Error : : Type : : JSONError ,
2018-12-12 14:49:10 +00:00
" \" smtlib2Responses. " + hashString + " \" must be a string. "
) ;
2019-03-07 14:35:31 +00:00
ret . smtLib2Responses [ hash ] = smtlib2Responses [ hashString ] . asString ( ) ;
2017-10-13 13:19:53 +00:00
}
2018-12-12 14:49:10 +00:00
}
2017-10-13 13:19:53 +00:00
}
2017-03-17 12:29:57 +00:00
Json : : Value const & settings = _input . get ( " settings " , Json : : Value ( ) ) ;
2018-12-11 14:47:19 +00:00
if ( auto result = checkSettingsKeys ( settings ) )
return * result ;
2020-07-08 20:08:50 +00:00
if ( settings . isMember ( " stopAfter " ) )
{
if ( ! settings [ " stopAfter " ] . isString ( ) )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " \" settings.stopAfter \" must be a string. " ) ;
2020-07-08 20:08:50 +00:00
if ( settings [ " stopAfter " ] . asString ( ) ! = " parsing " )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " Invalid value for \" settings.stopAfter \" . Only valid value is \" parsing \" . " ) ;
2020-07-08 20:08:50 +00:00
ret . stopAfter = CompilerStack : : State : : Parsed ;
}
2019-05-30 14:35:42 +00:00
if ( settings . isMember ( " parserErrorRecovery " ) )
{
if ( ! settings [ " parserErrorRecovery " ] . isBool ( ) )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " \" settings.parserErrorRecovery \" must be a Boolean. " ) ;
2019-05-30 14:35:42 +00:00
ret . parserErrorRecovery = settings [ " parserErrorRecovery " ] . asBool ( ) ;
}
2020-11-12 01:31:06 +00:00
if ( settings . isMember ( " viaIR " ) )
{
if ( ! settings [ " viaIR " ] . isBool ( ) )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " \" settings.viaIR \" must be a Boolean. " ) ;
2020-11-12 01:31:06 +00:00
ret . viaIR = settings [ " viaIR " ] . asBool ( ) ;
}
2018-02-21 22:43:40 +00:00
if ( settings . isMember ( " evmVersion " ) )
{
2018-09-21 13:51:45 +00:00
if ( ! settings [ " evmVersion " ] . isString ( ) )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " evmVersion must be a string. " ) ;
2019-10-28 10:39:30 +00:00
std : : optional < langutil : : EVMVersion > version = langutil : : EVMVersion : : fromString ( settings [ " evmVersion " ] . asString ( ) ) ;
2018-02-21 22:43:40 +00:00
if ( ! version )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " Invalid EVM version requested. " ) ;
2019-03-07 14:35:31 +00:00
ret . evmVersion = * version ;
2018-02-21 22:43:40 +00:00
}
2022-11-22 12:05:20 +00:00
if ( settings . isMember ( " eofVersion " ) )
{
if ( ! settings [ " eofVersion " ] . isUInt ( ) )
return formatFatalError ( Error : : Type : : JSONError , " eofVersion must be an unsigned integer. " ) ;
auto eofVersion = settings [ " evmVersion " ] . asUInt ( ) ;
if ( eofVersion ! = 1 )
return formatFatalError ( Error : : Type : : JSONError , " Invalid EOF version requested. " ) ;
ret . eofVersion = 1 ;
}
2019-09-18 14:44:36 +00:00
if ( settings . isMember ( " debug " ) )
{
2021-09-13 12:17:05 +00:00
if ( auto result = checkKeys ( settings [ " debug " ] , { " revertStrings " , " debugInfo " } , " settings.debug " ) )
2019-09-18 14:44:36 +00:00
return * result ;
if ( settings [ " debug " ] . isMember ( " revertStrings " ) )
{
if ( ! settings [ " debug " ] [ " revertStrings " ] . isString ( ) )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " settings.debug.revertStrings must be a string. " ) ;
2019-09-18 14:44:36 +00:00
std : : optional < RevertStrings > revertStrings = revertStringsFromString ( settings [ " debug " ] [ " revertStrings " ] . asString ( ) ) ;
if ( ! revertStrings )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " Invalid value for settings.debug.revertStrings. " ) ;
2020-01-22 14:48:56 +00:00
if ( * revertStrings = = RevertStrings : : VerboseDebug )
2019-09-18 14:44:36 +00:00
return formatFatalError (
2022-06-17 03:25:52 +00:00
Error : : Type : : UnimplementedFeatureError ,
2020-01-22 14:48:56 +00:00
" Only \" default \" , \" strip \" and \" debug \" are implemented for settings.debug.revertStrings for now. "
2019-09-18 14:44:36 +00:00
) ;
ret . revertStrings = * revertStrings ;
}
2021-09-13 12:17:05 +00:00
if ( settings [ " debug " ] . isMember ( " debugInfo " ) )
{
if ( ! settings [ " debug " ] [ " debugInfo " ] . isArray ( ) )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " settings.debug.debugInfo must be an array. " ) ;
2021-09-13 12:17:05 +00:00
vector < string > components ;
for ( Json : : Value const & arrayValue : settings [ " debug " ] [ " debugInfo " ] )
components . push_back ( arrayValue . asString ( ) ) ;
optional < DebugInfoSelection > debugInfoSelection = DebugInfoSelection : : fromComponents (
components ,
true /* _acceptWildcards */
) ;
if ( ! debugInfoSelection . has_value ( ) )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " Invalid value in settings.debug.debugInfo. " ) ;
2021-09-13 12:17:05 +00:00
if ( debugInfoSelection - > snippet & & ! debugInfoSelection - > location )
return formatFatalError (
2022-06-17 03:25:52 +00:00
Error : : Type : : JSONError ,
2021-09-13 12:17:05 +00:00
" To use 'snippet' with settings.debug.debugInfo you must select also 'location'. "
) ;
ret . debugInfoSelection = debugInfoSelection . value ( ) ;
}
2019-09-18 14:44:36 +00:00
}
2018-12-12 14:49:10 +00:00
if ( settings . isMember ( " remappings " ) & & ! settings [ " remappings " ] . isArray ( ) )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " \" settings.remappings \" must be an array of strings. " ) ;
2018-12-12 14:49:10 +00:00
2017-03-17 12:30:50 +00:00
for ( auto const & remapping : settings . get ( " remappings " , Json : : Value ( ) ) )
2018-08-09 18:37:49 +00:00
{
2018-09-21 13:51:45 +00:00
if ( ! remapping . isString ( ) )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " \" settings.remappings \" must be an array of strings " ) ;
2021-03-29 12:46:19 +00:00
if ( auto r = ImportRemapper : : parseRemapping ( remapping . asString ( ) ) )
2019-03-07 14:35:31 +00:00
ret . remappings . emplace_back ( std : : move ( * r ) ) ;
2018-08-09 18:37:49 +00:00
else
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " Invalid remapping: \" " + remapping . asString ( ) + " \" " ) ;
2018-08-09 18:37:49 +00:00
}
2017-03-17 12:30:50 +00:00
2018-09-24 10:48:25 +00:00
if ( settings . isMember ( " optimizer " ) )
2019-03-07 14:35:31 +00:00
{
auto optimiserSettings = parseOptimizerSettings ( settings [ " optimizer " ] ) ;
2020-05-11 11:38:49 +00:00
if ( std : : holds_alternative < Json : : Value > ( optimiserSettings ) )
return std : : get < Json : : Value > ( std : : move ( optimiserSettings ) ) ; // was an error
2019-03-07 14:35:31 +00:00
else
2020-05-11 11:38:49 +00:00
ret . optimiserSettings = std : : get < OptimiserSettings > ( std : : move ( optimiserSettings ) ) ;
2019-03-07 14:35:31 +00:00
}
2018-12-11 14:47:19 +00:00
2018-02-28 09:36:07 +00:00
Json : : Value jsonLibraries = settings . get ( " libraries " , Json : : Value ( Json : : objectValue ) ) ;
if ( ! jsonLibraries . isObject ( ) )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " \" libraries \" is not a JSON object. " ) ;
2017-03-17 12:30:29 +00:00
for ( auto const & sourceName : jsonLibraries . getMemberNames ( ) )
{
auto const & jsonSourceName = jsonLibraries [ sourceName ] ;
2018-02-28 09:36:07 +00:00
if ( ! jsonSourceName . isObject ( ) )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " Library entry is not a JSON object. " ) ;
2017-03-17 12:30:29 +00:00
for ( auto const & library : jsonSourceName . getMemberNames ( ) )
2018-02-28 09:44:48 +00:00
{
2018-09-21 13:51:45 +00:00
if ( ! jsonSourceName [ library ] . isString ( ) )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " Library address must be a string. " ) ;
2018-02-28 15:57:35 +00:00
string address = jsonSourceName [ library ] . asString ( ) ;
if ( ! boost : : starts_with ( address , " 0x " ) )
return formatFatalError (
2022-06-17 03:25:52 +00:00
Error : : Type : : JSONError ,
2018-02-28 15:57:35 +00:00
" Library address is not prefixed with \" 0x \" . "
) ;
if ( address . length ( ) ! = 42 )
return formatFatalError (
2022-06-17 03:25:52 +00:00
Error : : Type : : JSONError ,
2018-02-28 15:57:35 +00:00
" Library address is of invalid length. "
) ;
2018-02-28 09:44:48 +00:00
try
{
2020-11-13 21:30:50 +00:00
ret . libraries [ sourceName + " : " + library ] = util : : h160 ( address ) ;
2018-02-28 09:44:48 +00:00
}
2019-12-11 16:31:36 +00:00
catch ( util : : BadHexCharacter const & )
2018-02-28 09:44:48 +00:00
{
return formatFatalError (
2022-06-17 03:25:52 +00:00
Error : : Type : : JSONError ,
2018-02-28 15:57:35 +00:00
" Invalid library address ( \" " + address + " \" ) supplied. "
2018-02-28 09:44:48 +00:00
) ;
}
}
2017-03-17 12:30:29 +00:00
}
2017-02-10 13:18:21 +00:00
2017-03-30 01:41:38 +00:00
Json : : Value metadataSettings = settings . get ( " metadata " , Json : : Value ( ) ) ;
2018-12-11 14:47:19 +00:00
if ( auto result = checkMetadataKeys ( metadataSettings ) )
return * result ;
2022-07-11 22:50:32 +00:00
solAssert ( CompilerStack : : defaultMetadataFormat ( ) ! = CompilerStack : : MetadataFormat : : NoMetadata , " " ) ;
ret . metadataFormat =
metadataSettings . get ( " appendCBOR " , Json : : Value ( true ) ) . asBool ( ) ?
CompilerStack : : defaultMetadataFormat ( ) :
CompilerStack : : MetadataFormat : : NoMetadata ;
2019-03-07 14:35:31 +00:00
ret . metadataLiteralSources = metadataSettings . get ( " useLiteralContent " , Json : : Value ( false ) ) . asBool ( ) ;
2019-09-06 17:11:07 +00:00
if ( metadataSettings . isMember ( " bytecodeHash " ) )
{
auto metadataHash = metadataSettings [ " bytecodeHash " ] . asString ( ) ;
ret . metadataHash =
metadataHash = = " ipfs " ?
CompilerStack : : MetadataHash : : IPFS :
metadataHash = = " bzzr1 " ?
CompilerStack : : MetadataHash : : Bzzr1 :
CompilerStack : : MetadataHash : : None ;
2022-10-13 00:04:48 +00:00
if ( ret . metadataFormat = = CompilerStack : : MetadataFormat : : NoMetadata & & ret . metadataHash ! = CompilerStack : : MetadataHash : : None )
return formatFatalError (
Error : : Type : : JSONError ,
" When the parameter \" appendCBOR \" is set to false, the parameter \" bytecodeHash \" cannot be set to \" " +
metadataHash +
" \" . The parameter \" bytecodeHash \" should either be skipped, or set to \" none \" . "
) ;
2019-09-06 17:11:07 +00:00
}
2017-03-30 01:41:38 +00:00
2017-09-29 18:05:39 +00:00
Json : : Value outputSelection = settings . get ( " outputSelection " , Json : : Value ( ) ) ;
2018-12-12 14:49:10 +00:00
if ( auto jsonError = checkOutputSelection ( outputSelection ) )
return * jsonError ;
2019-03-07 14:35:31 +00:00
ret . outputSelection = std : : move ( outputSelection ) ;
2017-09-29 18:05:39 +00:00
2020-07-08 20:08:50 +00:00
if ( ret . stopAfter ! = CompilerStack : : State : : CompilationSuccessful & & isBinaryRequested ( ret . outputSelection ) )
return formatFatalError (
2022-06-17 03:25:52 +00:00
Error : : Type : : JSONError ,
2020-07-08 20:08:50 +00:00
" Requested output selection conflicts with \" settings.stopAfter \" . "
) ;
2020-12-09 14:15:49 +00:00
Json : : Value const & modelCheckerSettings = settings . get ( " modelChecker " , Json : : Value ( ) ) ;
2020-10-19 09:37:23 +00:00
if ( auto result = checkModelCheckerSettingsKeys ( modelCheckerSettings ) )
return * result ;
2021-04-15 10:31:45 +00:00
if ( modelCheckerSettings . isMember ( " contracts " ) )
{
auto const & sources = modelCheckerSettings [ " contracts " ] ;
if ( ! sources . isObject ( ) & & ! sources . isNull ( ) )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " settings.modelChecker.contracts is not a JSON object. " ) ;
2021-04-15 10:31:45 +00:00
map < string , set < string > > sourceContracts ;
for ( auto const & source : sources . getMemberNames ( ) )
{
if ( source . empty ( ) )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " Source name cannot be empty. " ) ;
2021-04-15 10:31:45 +00:00
auto const & contracts = sources [ source ] ;
if ( ! contracts . isArray ( ) )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " Source contracts must be an array. " ) ;
2021-04-15 10:31:45 +00:00
for ( auto const & contract : contracts )
{
if ( ! contract . isString ( ) )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " Every contract in settings.modelChecker.contracts must be a string. " ) ;
2021-04-15 10:31:45 +00:00
if ( contract . asString ( ) . empty ( ) )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " Contract name cannot be empty. " ) ;
2021-04-15 10:31:45 +00:00
sourceContracts [ source ] . insert ( contract . asString ( ) ) ;
}
if ( sourceContracts [ source ] . empty ( ) )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " Source contracts must be a non-empty array. " ) ;
2021-04-15 10:31:45 +00:00
}
2022-08-23 17:28:45 +00:00
ret . modelCheckerSettings . contracts = { std : : move ( sourceContracts ) } ;
2021-04-15 10:31:45 +00:00
}
2021-07-15 15:39:01 +00:00
if ( modelCheckerSettings . isMember ( " divModNoSlacks " ) )
{
auto const & divModNoSlacks = modelCheckerSettings [ " divModNoSlacks " ] ;
if ( ! divModNoSlacks . isBool ( ) )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " settings.modelChecker.divModNoSlacks must be a Boolean. " ) ;
2021-07-15 15:39:01 +00:00
ret . modelCheckerSettings . divModNoSlacks = divModNoSlacks . asBool ( ) ;
}
2020-10-19 09:37:23 +00:00
if ( modelCheckerSettings . isMember ( " engine " ) )
2020-10-14 15:44:40 +00:00
{
2020-10-19 09:37:23 +00:00
if ( ! modelCheckerSettings [ " engine " ] . isString ( ) )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " settings.modelChecker.engine must be a string. " ) ;
2020-10-19 09:37:23 +00:00
std : : optional < ModelCheckerEngine > engine = ModelCheckerEngine : : fromString ( modelCheckerSettings [ " engine " ] . asString ( ) ) ;
2020-10-14 15:44:40 +00:00
if ( ! engine )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " Invalid model checker engine requested. " ) ;
2020-11-02 20:20:20 +00:00
ret . modelCheckerSettings . engine = * engine ;
}
2023-02-23 18:22:46 +00:00
if ( modelCheckerSettings . isMember ( " bmcLoopIterations " ) )
{
if ( ! ret . modelCheckerSettings . engine . bmc )
return formatFatalError ( Error : : Type : : JSONError , " settings.modelChecker.bmcLoopIterations requires the BMC engine to be enabled. " ) ;
if ( modelCheckerSettings [ " bmcLoopIterations " ] . isUInt ( ) )
ret . modelCheckerSettings . bmcLoopIterations = modelCheckerSettings [ " bmcLoopIterations " ] . asUInt ( ) ;
else
return formatFatalError ( Error : : Type : : JSONError , " settings.modelChecker.bmcLoopIterations must be an unsigned integer. " ) ;
}
2021-10-12 09:12:18 +00:00
if ( modelCheckerSettings . isMember ( " extCalls " ) )
{
if ( ! modelCheckerSettings [ " extCalls " ] . isString ( ) )
return formatFatalError ( Error : : Type : : JSONError , " settings.modelChecker.extCalls must be a string. " ) ;
std : : optional < ModelCheckerExtCalls > extCalls = ModelCheckerExtCalls : : fromString ( modelCheckerSettings [ " extCalls " ] . asString ( ) ) ;
if ( ! extCalls )
return formatFatalError ( Error : : Type : : JSONError , " Invalid model checker extCalls requested. " ) ;
ret . modelCheckerSettings . externalCalls = * extCalls ;
}
2021-10-06 09:51:22 +00:00
if ( modelCheckerSettings . isMember ( " invariants " ) )
{
auto const & invariantsArray = modelCheckerSettings [ " invariants " ] ;
if ( ! invariantsArray . isArray ( ) )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " settings.modelChecker.invariants must be an array. " ) ;
2021-10-06 09:51:22 +00:00
ModelCheckerInvariants invariants ;
for ( auto const & i : invariantsArray )
{
if ( ! i . isString ( ) )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " Every invariant type in settings.modelChecker.invariants must be a string. " ) ;
2021-10-06 09:51:22 +00:00
if ( ! invariants . setFromString ( i . asString ( ) ) )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " Invalid model checker invariants requested. " ) ;
2021-10-06 09:51:22 +00:00
}
if ( invariants . invariants . empty ( ) )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " settings.modelChecker.invariants must be a non-empty array. " ) ;
2021-10-06 09:51:22 +00:00
ret . modelCheckerSettings . invariants = invariants ;
}
2023-02-09 16:07:13 +00:00
if ( modelCheckerSettings . isMember ( " showProvedSafe " ) )
{
auto const & showProvedSafe = modelCheckerSettings [ " showProvedSafe " ] ;
if ( ! showProvedSafe . isBool ( ) )
return formatFatalError ( Error : : Type : : JSONError , " settings.modelChecker.showProvedSafe must be a Boolean value. " ) ;
ret . modelCheckerSettings . showProvedSafe = showProvedSafe . asBool ( ) ;
}
2021-07-02 12:43:20 +00:00
if ( modelCheckerSettings . isMember ( " showUnproved " ) )
{
auto const & showUnproved = modelCheckerSettings [ " showUnproved " ] ;
if ( ! showUnproved . isBool ( ) )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " settings.modelChecker.showUnproved must be a Boolean value. " ) ;
2021-07-02 12:43:20 +00:00
ret . modelCheckerSettings . showUnproved = showUnproved . asBool ( ) ;
}
2021-07-02 13:05:24 +00:00
2023-03-06 13:19:58 +00:00
if ( modelCheckerSettings . isMember ( " showUnsupported " ) )
{
auto const & showUnsupported = modelCheckerSettings [ " showUnsupported " ] ;
if ( ! showUnsupported . isBool ( ) )
return formatFatalError ( Error : : Type : : JSONError , " settings.modelChecker.showUnsupported must be a Boolean value. " ) ;
ret . modelCheckerSettings . showUnsupported = showUnsupported . asBool ( ) ;
}
2021-05-19 15:35:19 +00:00
if ( modelCheckerSettings . isMember ( " solvers " ) )
{
auto const & solversArray = modelCheckerSettings [ " solvers " ] ;
if ( ! solversArray . isArray ( ) )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " settings.modelChecker.solvers must be an array. " ) ;
2021-05-19 15:35:19 +00:00
smtutil : : SMTSolverChoice solvers ;
for ( auto const & s : solversArray )
{
if ( ! s . isString ( ) )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " Every target in settings.modelChecker.solvers must be a string. " ) ;
2021-05-19 15:35:19 +00:00
if ( ! solvers . setSolver ( s . asString ( ) ) )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " Invalid model checker solvers requested. " ) ;
2021-05-19 15:35:19 +00:00
}
ret . modelCheckerSettings . solvers = solvers ;
}
2023-04-26 10:50:36 +00:00
if ( modelCheckerSettings . isMember ( " printQuery " ) )
{
auto const & printQuery = modelCheckerSettings [ " printQuery " ] ;
if ( ! printQuery . isBool ( ) )
return formatFatalError ( Error : : Type : : JSONError , " settings.modelChecker.printQuery must be a Boolean value. " ) ;
if ( ! ( ret . modelCheckerSettings . solvers = = smtutil : : SMTSolverChoice : : SMTLIB2 ( ) ) )
return formatFatalError ( Error : : Type : : JSONError , " Only SMTLib2 solver can be enabled to print queries " ) ;
ret . modelCheckerSettings . printQuery = printQuery . asBool ( ) ;
}
2021-01-19 11:56:22 +00:00
if ( modelCheckerSettings . isMember ( " targets " ) )
{
2021-04-14 10:56:43 +00:00
auto const & targetsArray = modelCheckerSettings [ " targets " ] ;
if ( ! targetsArray . isArray ( ) )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " settings.modelChecker.targets must be an array. " ) ;
2021-04-14 10:56:43 +00:00
ModelCheckerTargets targets ;
for ( auto const & t : targetsArray )
{
if ( ! t . isString ( ) )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " Every target in settings.modelChecker.targets must be a string. " ) ;
2021-04-14 10:56:43 +00:00
if ( ! targets . setFromString ( t . asString ( ) ) )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " Invalid model checker targets requested. " ) ;
2021-04-14 10:56:43 +00:00
}
if ( targets . targets . empty ( ) )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " settings.modelChecker.targets must be a non-empty array. " ) ;
2021-04-14 10:56:43 +00:00
ret . modelCheckerSettings . targets = targets ;
2021-01-19 11:56:22 +00:00
}
2020-11-02 20:20:20 +00:00
if ( modelCheckerSettings . isMember ( " timeout " ) )
{
if ( ! modelCheckerSettings [ " timeout " ] . isUInt ( ) )
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : JSONError , " settings.modelChecker.timeout must be an unsigned integer. " ) ;
2020-11-02 20:20:20 +00:00
ret . modelCheckerSettings . timeout = modelCheckerSettings [ " timeout " ] . asUInt ( ) ;
2020-10-14 15:44:40 +00:00
}
2023-04-28 16:29:59 +00:00
return { std : : move ( ret ) } ;
}
map < string , Json : : Value > StandardCompiler : : parseAstFromInput ( StringMap const & _sources )
{
map < string , Json : : Value > sourceJsons ;
for ( auto const & [ sourceName , sourceCode ] : _sources )
{
Json : : Value ast ;
astAssert ( util : : jsonParseStrict ( sourceCode , ast ) , " Input file could not be parsed to JSON " ) ;
string astKey = ast . isMember ( " ast " ) ? " ast " : " AST " ;
astAssert ( ast . isMember ( astKey ) , " astkey is not member " ) ;
astAssert ( ast [ astKey ] [ " nodeType " ] . asString ( ) = = " SourceUnit " , " Top-level node should be a 'SourceUnit' " ) ;
astAssert ( sourceJsons . count ( sourceName ) = = 0 , " All sources must have unique names " ) ;
sourceJsons . emplace ( sourceName , std : : move ( ast [ astKey ] ) ) ;
}
return sourceJsons ;
2019-03-07 14:35:31 +00:00
}
Json : : Value StandardCompiler : : compileSolidity ( StandardCompiler : : InputsAndSettings _inputsAndSettings )
{
CompilerStack compilerStack ( m_readFile ) ;
StringMap sourceList = std : : move ( _inputsAndSettings . sources ) ;
2023-04-28 16:29:59 +00:00
if ( _inputsAndSettings . language = = " Solidity " )
compilerStack . setSources ( sourceList ) ;
2019-03-07 14:35:31 +00:00
for ( auto const & smtLib2Response : _inputsAndSettings . smtLib2Responses )
compilerStack . addSMTLib2Response ( smtLib2Response . first , smtLib2Response . second ) ;
2020-11-12 01:31:06 +00:00
compilerStack . setViaIR ( _inputsAndSettings . viaIR ) ;
2019-03-07 14:35:31 +00:00
compilerStack . setEVMVersion ( _inputsAndSettings . evmVersion ) ;
2019-05-30 14:35:42 +00:00
compilerStack . setParserErrorRecovery ( _inputsAndSettings . parserErrorRecovery ) ;
2022-08-23 17:28:45 +00:00
compilerStack . setRemappings ( std : : move ( _inputsAndSettings . remappings ) ) ;
2019-03-07 14:35:31 +00:00
compilerStack . setOptimiserSettings ( std : : move ( _inputsAndSettings . optimiserSettings ) ) ;
2019-09-18 14:44:36 +00:00
compilerStack . setRevertStringBehaviour ( _inputsAndSettings . revertStrings ) ;
2021-09-13 12:17:05 +00:00
if ( _inputsAndSettings . debugInfoSelection . has_value ( ) )
compilerStack . selectDebugInfo ( _inputsAndSettings . debugInfoSelection . value ( ) ) ;
2019-03-07 14:35:31 +00:00
compilerStack . setLibraries ( _inputsAndSettings . libraries ) ;
compilerStack . useMetadataLiteralSources ( _inputsAndSettings . metadataLiteralSources ) ;
2022-07-11 22:50:32 +00:00
compilerStack . setMetadataFormat ( _inputsAndSettings . metadataFormat ) ;
2019-09-06 17:11:07 +00:00
compilerStack . setMetadataHash ( _inputsAndSettings . metadataHash ) ;
2019-03-07 14:35:31 +00:00
compilerStack . setRequestedContractNames ( requestedContractNames ( _inputsAndSettings . outputSelection ) ) ;
2020-11-02 20:20:20 +00:00
compilerStack . setModelCheckerSettings ( _inputsAndSettings . modelCheckerSettings ) ;
2019-03-07 14:35:31 +00:00
2020-08-06 09:43:36 +00:00
compilerStack . enableEvmBytecodeGeneration ( isEvmBytecodeRequested ( _inputsAndSettings . outputSelection ) ) ;
2019-06-18 16:11:04 +00:00
compilerStack . enableIRGeneration ( isIRRequested ( _inputsAndSettings . outputSelection ) ) ;
2019-03-04 22:26:46 +00:00
2019-03-07 14:35:31 +00:00
Json : : Value errors = std : : move ( _inputsAndSettings . errors ) ;
bool const binariesRequested = isBinaryRequested ( _inputsAndSettings . outputSelection ) ;
2018-12-18 17:28:14 +00:00
2017-02-10 13:18:21 +00:00
try
{
2023-04-28 16:29:59 +00:00
if ( _inputsAndSettings . language = = " SolidityAST " )
{
try
{
compilerStack . importASTs ( parseAstFromInput ( sourceList ) ) ;
if ( ! compilerStack . analyze ( ) )
errors . append ( formatError ( Error : : Type : : FatalError , " general " , " Analysis of the AST failed. " ) ) ;
if ( binariesRequested )
compilerStack . compile ( ) ;
}
catch ( util : : Exception const & _exc )
{
solThrow ( util : : Exception , " Failed to import AST: " s + _exc . what ( ) ) ;
}
}
2018-12-18 17:28:14 +00:00
else
2017-03-29 20:50:53 +00:00
{
2023-04-28 16:29:59 +00:00
if ( binariesRequested )
compilerStack . compile ( ) ;
else
compilerStack . parseAndAnalyze ( _inputsAndSettings . stopAfter ) ;
2017-03-29 20:50:53 +00:00
2023-04-28 16:29:59 +00:00
for ( auto const & error : compilerStack . errors ( ) )
errors . append ( formatErrorWithException (
compilerStack ,
* error ,
error - > type ( ) ,
" general " ,
" " ,
error - > errorId ( )
) ) ;
2017-03-29 20:50:53 +00:00
}
2017-02-10 13:18:21 +00:00
}
2017-07-26 21:52:11 +00:00
/// This is only thrown in a very few locations.
2017-02-10 13:18:21 +00:00
catch ( Error const & _error )
{
2017-07-26 21:53:54 +00:00
errors . append ( formatErrorWithException (
2021-06-29 12:38:59 +00:00
compilerStack ,
2017-07-26 21:53:54 +00:00
_error ,
2022-06-17 03:25:52 +00:00
_error . type ( ) ,
2017-07-26 21:53:54 +00:00
" general " ,
2018-11-30 13:34:08 +00:00
" Uncaught error: "
2017-07-26 21:53:54 +00:00
) ) ;
2017-02-10 13:18:21 +00:00
}
2017-07-26 21:52:11 +00:00
/// This should not be leaked from compile().
catch ( FatalError const & _exception )
{
errors . append ( formatError (
2022-06-17 03:25:52 +00:00
Error : : Type : : FatalError ,
2017-07-26 21:52:11 +00:00
" general " ,
" Uncaught fatal error: " + boost : : diagnostic_information ( _exception )
) ) ;
}
2017-02-10 13:18:21 +00:00
catch ( CompilerError const & _exception )
{
2017-03-29 20:50:53 +00:00
errors . append ( formatErrorWithException (
2021-06-29 12:38:59 +00:00
compilerStack ,
2017-03-29 20:50:53 +00:00
_exception ,
2022-06-17 03:25:52 +00:00
Error : : Type : : CompilerError ,
2017-03-29 20:50:53 +00:00
" general " ,
2018-11-30 13:34:08 +00:00
" Compiler error ( " + _exception . lineInfo ( ) + " ) "
2017-03-29 20:50:53 +00:00
) ) ;
2017-02-10 13:18:21 +00:00
}
catch ( InternalCompilerError const & _exception )
{
2017-03-29 20:50:53 +00:00
errors . append ( formatErrorWithException (
2021-06-29 12:38:59 +00:00
compilerStack ,
2017-03-29 20:50:53 +00:00
_exception ,
2022-06-17 03:25:52 +00:00
Error : : Type : : InternalCompilerError ,
2017-03-29 20:50:53 +00:00
" general " ,
2018-11-30 13:34:08 +00:00
" Internal compiler error ( " + _exception . lineInfo ( ) + " ) "
2017-03-29 20:50:53 +00:00
) ) ;
2017-02-10 13:18:21 +00:00
}
catch ( UnimplementedFeatureError const & _exception )
{
2017-03-29 20:50:53 +00:00
errors . append ( formatErrorWithException (
2021-06-29 12:38:59 +00:00
compilerStack ,
2017-03-29 20:50:53 +00:00
_exception ,
2022-06-17 03:25:52 +00:00
Error : : Type : : UnimplementedFeatureError ,
2017-03-29 20:50:53 +00:00
" general " ,
2018-11-30 13:34:08 +00:00
" Unimplemented feature ( " + _exception . lineInfo ( ) + " ) "
2017-07-26 21:52:11 +00:00
) ) ;
2017-02-10 13:18:21 +00:00
}
2019-12-03 18:05:58 +00:00
catch ( yul : : YulException const & _exception )
{
errors . append ( formatErrorWithException (
2021-06-29 12:38:59 +00:00
compilerStack ,
2019-12-03 18:05:58 +00:00
_exception ,
2022-06-17 03:25:52 +00:00
Error : : Type : : YulException ,
2019-12-03 18:05:58 +00:00
" general " ,
" Yul exception "
) ) ;
}
2020-05-20 10:55:12 +00:00
catch ( smtutil : : SMTLogicError const & _exception )
{
errors . append ( formatErrorWithException (
2021-06-29 12:38:59 +00:00
compilerStack ,
2020-05-20 10:55:12 +00:00
_exception ,
2022-06-17 03:25:52 +00:00
Error : : Type : : SMTLogicException ,
2020-05-20 10:55:12 +00:00
" general " ,
" SMT logic exception "
) ) ;
}
2019-12-11 16:31:36 +00:00
catch ( util : : Exception const & _exception )
2017-02-10 13:18:21 +00:00
{
2017-03-29 20:50:53 +00:00
errors . append ( formatError (
2022-06-17 03:25:52 +00:00
Error : : Type : : Exception ,
2017-03-29 20:50:53 +00:00
" general " ,
" Exception during compilation: " + boost : : diagnostic_information ( _exception )
) ) ;
2017-02-10 13:18:21 +00:00
}
2021-10-07 15:40:57 +00:00
catch ( std : : exception const & _exception )
2019-05-29 20:26:18 +00:00
{
errors . append ( formatError (
2022-06-17 03:25:52 +00:00
Error : : Type : : Exception ,
2019-05-29 20:26:18 +00:00
" general " ,
2021-10-07 15:40:57 +00:00
" Unknown exception during compilation: " + boost : : diagnostic_information ( _exception )
2019-05-29 20:26:18 +00:00
) ) ;
}
2017-02-10 13:18:21 +00:00
catch ( . . . )
{
2017-03-29 20:50:53 +00:00
errors . append ( formatError (
2022-06-17 03:25:52 +00:00
Error : : Type : : Exception ,
2017-03-29 20:50:53 +00:00
" general " ,
2021-10-07 15:40:57 +00:00
" Unknown exception during compilation: " + boost : : current_exception_diagnostic_information ( )
2017-03-29 20:50:53 +00:00
) ) ;
2017-02-10 13:18:21 +00:00
}
2023-06-14 10:02:24 +00:00
bool parsingSuccess = compilerStack . state ( ) > = CompilerStack : : State : : Parsed ;
2019-05-28 15:24:54 +00:00
bool analysisPerformed = compilerStack . state ( ) > = CompilerStack : : State : : AnalysisPerformed ;
2023-06-14 10:02:24 +00:00
bool compilationSuccess = compilerStack . state ( ) = = CompilerStack : : State : : CompilationSuccessful ;
2017-07-03 11:02:06 +00:00
2019-05-28 15:24:54 +00:00
if ( compilerStack . hasError ( ) & & ! _inputsAndSettings . parserErrorRecovery )
analysisPerformed = false ;
2023-06-14 10:02:24 +00:00
// If analysis fails, the artifacts inside CompilerStack are potentially incomplete and must not be returned.
// Note that not completing analysis due to stopAfter does not count as a failure. It's neither failure nor success.
bool analysisFailed = ! analysisPerformed & & _inputsAndSettings . stopAfter > = CompilerStack : : State : : AnalysisPerformed ;
bool compilationFailed = ! compilationSuccess & & binariesRequested ;
2017-03-29 20:50:53 +00:00
/// Inconsistent state - stop here to receive error reports from users
2020-07-08 20:08:50 +00:00
if (
2023-06-14 10:02:24 +00:00
( compilationFailed | | ! analysisPerformed ) & &
2020-07-08 20:08:50 +00:00
( errors . empty ( ) & & _inputsAndSettings . stopAfter > = CompilerStack : : State : : AnalysisPerformed )
)
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : InternalCompilerError , " No error reported, but compilation failed. " ) ;
2017-03-29 20:50:53 +00:00
2017-07-18 13:43:10 +00:00
Json : : Value output = Json : : objectValue ;
if ( errors . size ( ) > 0 )
2019-03-07 14:35:31 +00:00
output [ " errors " ] = std : : move ( errors ) ;
2017-07-18 13:43:10 +00:00
2019-03-07 14:35:31 +00:00
if ( ! compilerStack . unhandledSMTLib2Queries ( ) . empty ( ) )
for ( string const & query : compilerStack . unhandledSMTLib2Queries ( ) )
2019-12-11 16:31:36 +00:00
output [ " auxiliaryInputRequested " ] [ " smtlib2queries " ] [ " 0x " + util : : keccak256 ( query ) . hex ( ) ] = query ;
2017-10-13 13:19:53 +00:00
2019-06-18 16:11:04 +00:00
bool const wildcardMatchesExperimental = false ;
2019-03-04 22:26:46 +00:00
2017-03-29 13:54:34 +00:00
output [ " sources " ] = Json : : objectValue ;
unsigned sourceIndex = 0 ;
2023-06-14 10:02:24 +00:00
if ( parsingSuccess & & ! analysisFailed & & ( ! compilerStack . hasError ( ) | | _inputsAndSettings . parserErrorRecovery ) )
2020-07-08 20:08:50 +00:00
for ( string const & sourceName : compilerStack . sourceNames ( ) )
{
Json : : Value sourceResult = Json : : objectValue ;
sourceResult [ " id " ] = sourceIndex + + ;
if ( isArtifactRequested ( _inputsAndSettings . outputSelection , sourceName , " " , " ast " , wildcardMatchesExperimental ) )
2022-06-16 16:05:51 +00:00
sourceResult [ " ast " ] = ASTJsonExporter ( compilerStack . state ( ) , compilerStack . sourceIndices ( ) ) . toJson ( compilerStack . ast ( sourceName ) ) ;
2020-07-08 20:08:50 +00:00
output [ " sources " ] [ sourceName ] = sourceResult ;
}
2017-03-29 13:54:34 +00:00
2017-02-10 13:18:21 +00:00
Json : : Value contractsOutput = Json : : objectValue ;
2019-05-28 15:24:54 +00:00
for ( string const & contractName : analysisPerformed ? compilerStack . contractNames ( ) : vector < string > ( ) )
2017-02-10 13:18:21 +00:00
{
2018-01-03 11:34:48 +00:00
size_t colon = contractName . rfind ( ' : ' ) ;
2017-03-30 01:32:43 +00:00
solAssert ( colon ! = string : : npos , " " ) ;
string file = contractName . substr ( 0 , colon ) ;
string name = contractName . substr ( colon + 1 ) ;
2019-10-30 17:11:33 +00:00
// ABI, storage layout, documentation and metadata
2017-02-10 13:18:21 +00:00
Json : : Value contractData ( Json : : objectValue ) ;
2019-06-18 16:11:04 +00:00
if ( isArtifactRequested ( _inputsAndSettings . outputSelection , file , name , " abi " , wildcardMatchesExperimental ) )
2019-03-07 14:35:31 +00:00
contractData [ " abi " ] = compilerStack . contractABI ( contractName ) ;
2019-10-30 17:11:33 +00:00
if ( isArtifactRequested ( _inputsAndSettings . outputSelection , file , name , " storageLayout " , false ) )
contractData [ " storageLayout " ] = compilerStack . storageLayout ( contractName ) ;
2019-06-18 16:11:04 +00:00
if ( isArtifactRequested ( _inputsAndSettings . outputSelection , file , name , " metadata " , wildcardMatchesExperimental ) )
2019-03-07 14:35:31 +00:00
contractData [ " metadata " ] = compilerStack . metadata ( contractName ) ;
2019-06-18 16:11:04 +00:00
if ( isArtifactRequested ( _inputsAndSettings . outputSelection , file , name , " userdoc " , wildcardMatchesExperimental ) )
2019-03-07 14:35:31 +00:00
contractData [ " userdoc " ] = compilerStack . natspecUser ( contractName ) ;
2019-06-18 16:11:04 +00:00
if ( isArtifactRequested ( _inputsAndSettings . outputSelection , file , name , " devdoc " , wildcardMatchesExperimental ) )
2019-03-07 14:35:31 +00:00
contractData [ " devdoc " ] = compilerStack . natspecDev ( contractName ) ;
2017-02-10 13:18:21 +00:00
2019-03-04 22:26:46 +00:00
// IR
2019-06-18 16:11:04 +00:00
if ( compilationSuccess & & isArtifactRequested ( _inputsAndSettings . outputSelection , file , name , " ir " , wildcardMatchesExperimental ) )
2019-03-04 22:26:46 +00:00
contractData [ " ir " ] = compilerStack . yulIR ( contractName ) ;
2023-05-02 13:34:12 +00:00
if ( compilationSuccess & & isArtifactRequested ( _inputsAndSettings . outputSelection , file , name , " irAst " , wildcardMatchesExperimental ) )
contractData [ " irAst " ] = compilerStack . yulIRAst ( contractName ) ;
2019-06-18 16:11:04 +00:00
if ( compilationSuccess & & isArtifactRequested ( _inputsAndSettings . outputSelection , file , name , " irOptimized " , wildcardMatchesExperimental ) )
2019-03-04 22:26:46 +00:00
contractData [ " irOptimized " ] = compilerStack . yulIROptimized ( contractName ) ;
2023-05-02 13:34:12 +00:00
if ( compilationSuccess & & isArtifactRequested ( _inputsAndSettings . outputSelection , file , name , " irOptimizedAst " , wildcardMatchesExperimental ) )
contractData [ " irOptimizedAst " ] = compilerStack . yulIROptimizedAst ( contractName ) ;
2019-03-04 22:26:46 +00:00
2017-02-10 13:18:21 +00:00
// EVM
Json : : Value evmData ( Json : : objectValue ) ;
2019-06-18 16:11:04 +00:00
if ( compilationSuccess & & isArtifactRequested ( _inputsAndSettings . outputSelection , file , name , " evm.assembly " , wildcardMatchesExperimental ) )
2019-03-07 14:35:31 +00:00
evmData [ " assembly " ] = compilerStack . assemblyString ( contractName , sourceList ) ;
2019-06-18 16:11:04 +00:00
if ( compilationSuccess & & isArtifactRequested ( _inputsAndSettings . outputSelection , file , name , " evm.legacyAssembly " , wildcardMatchesExperimental ) )
2020-02-18 09:22:34 +00:00
evmData [ " legacyAssembly " ] = compilerStack . assemblyJSON ( contractName ) ;
2019-06-18 16:11:04 +00:00
if ( isArtifactRequested ( _inputsAndSettings . outputSelection , file , name , " evm.methodIdentifiers " , wildcardMatchesExperimental ) )
2022-02-01 14:42:08 +00:00
evmData [ " methodIdentifiers " ] = compilerStack . interfaceSymbols ( contractName ) [ " methods " ] ;
2019-06-18 16:11:04 +00:00
if ( compilationSuccess & & isArtifactRequested ( _inputsAndSettings . outputSelection , file , name , " evm.gasEstimates " , wildcardMatchesExperimental ) )
2019-03-07 14:35:31 +00:00
evmData [ " gasEstimates " ] = compilerStack . gasEstimates ( contractName ) ;
2017-04-12 09:37:04 +00:00
2018-12-18 17:28:14 +00:00
if ( compilationSuccess & & isArtifactRequested (
2019-03-07 14:35:31 +00:00
_inputsAndSettings . outputSelection ,
2017-10-19 13:09:40 +00:00
file ,
name ,
2020-09-15 09:21:13 +00:00
evmObjectComponents ( " bytecode " ) ,
2019-06-18 16:11:04 +00:00
wildcardMatchesExperimental
2017-10-19 13:09:40 +00:00
) )
2017-04-12 09:37:04 +00:00
evmData [ " bytecode " ] = collectEVMObject (
2022-11-23 10:51:34 +00:00
_inputsAndSettings . evmVersion ,
2019-03-07 14:35:31 +00:00
compilerStack . object ( contractName ) ,
2020-04-02 15:27:35 +00:00
compilerStack . sourceMapping ( contractName ) ,
2020-05-28 11:17:16 +00:00
compilerStack . generatedSources ( contractName ) ,
2020-12-03 10:27:21 +00:00
false ,
[ & ] ( string const & _element ) { return isArtifactRequested (
_inputsAndSettings . outputSelection ,
file ,
name ,
" evm.bytecode. " + _element ,
wildcardMatchesExperimental
) ; }
2017-04-12 09:37:04 +00:00
) ;
2018-12-18 17:28:14 +00:00
if ( compilationSuccess & & isArtifactRequested (
2019-03-07 14:35:31 +00:00
_inputsAndSettings . outputSelection ,
2017-10-19 13:09:40 +00:00
file ,
name ,
2020-09-15 09:21:13 +00:00
evmObjectComponents ( " deployedBytecode " ) ,
2019-06-18 16:11:04 +00:00
wildcardMatchesExperimental
2017-10-19 13:09:40 +00:00
) )
2017-04-12 09:37:04 +00:00
evmData [ " deployedBytecode " ] = collectEVMObject (
2022-11-23 10:51:34 +00:00
_inputsAndSettings . evmVersion ,
2019-03-07 14:35:31 +00:00
compilerStack . runtimeObject ( contractName ) ,
2020-04-02 15:27:35 +00:00
compilerStack . runtimeSourceMapping ( contractName ) ,
2020-05-28 11:17:16 +00:00
compilerStack . generatedSources ( contractName , true ) ,
2020-12-03 10:27:21 +00:00
true ,
[ & ] ( string const & _element ) { return isArtifactRequested (
_inputsAndSettings . outputSelection ,
file ,
name ,
" evm.deployedBytecode. " + _element ,
wildcardMatchesExperimental
) ; }
2017-04-12 09:37:04 +00:00
) ;
2017-02-10 13:18:21 +00:00
2018-12-19 11:22:19 +00:00
if ( ! evmData . empty ( ) )
contractData [ " evm " ] = evmData ;
2017-02-10 13:18:21 +00:00
2018-12-19 11:22:19 +00:00
if ( ! contractData . empty ( ) )
{
if ( ! contractsOutput . isMember ( file ) )
contractsOutput [ file ] = Json : : objectValue ;
contractsOutput [ file ] [ name ] = contractData ;
}
2017-02-10 13:18:21 +00:00
}
2018-12-19 11:22:19 +00:00
if ( ! contractsOutput . empty ( ) )
output [ " contracts " ] = contractsOutput ;
2017-02-10 13:18:21 +00:00
return output ;
}
2017-04-21 14:34:40 +00:00
Json : : Value StandardCompiler : : compileYul ( InputsAndSettings _inputsAndSettings )
{
2021-09-16 11:09:08 +00:00
Json : : Value output = Json : : objectValue ;
output [ " errors " ] = std : : move ( _inputsAndSettings . errors ) ;
2017-04-21 14:34:40 +00:00
if ( _inputsAndSettings . sources . size ( ) ! = 1 )
2021-09-16 11:09:08 +00:00
{
output [ " errors " ] . append ( formatError (
2022-06-17 03:25:52 +00:00
Error : : Type : : JSONError ,
2021-09-16 11:09:08 +00:00
" general " ,
" Yul mode only supports exactly one input file. "
) ) ;
return output ;
}
2017-04-21 14:34:40 +00:00
if ( ! _inputsAndSettings . smtLib2Responses . empty ( ) )
2021-09-16 11:09:08 +00:00
{
output [ " errors " ] . append ( formatError (
2022-06-17 03:25:52 +00:00
Error : : Type : : JSONError ,
2021-09-16 11:09:08 +00:00
" general " ,
" Yul mode does not support smtlib2responses. "
) ) ;
return output ;
}
2017-04-21 14:34:40 +00:00
if ( ! _inputsAndSettings . remappings . empty ( ) )
2021-09-16 11:09:08 +00:00
{
output [ " errors " ] . append ( formatError (
2022-06-17 03:25:52 +00:00
Error : : Type : : JSONError ,
2021-09-16 11:09:08 +00:00
" general " ,
" Field \" settings.remappings \" cannot be used for Yul. "
) ) ;
return output ;
}
2019-09-18 14:44:36 +00:00
if ( _inputsAndSettings . revertStrings ! = RevertStrings : : Default )
2021-09-16 11:09:08 +00:00
{
output [ " errors " ] . append ( formatError (
2022-06-17 03:25:52 +00:00
Error : : Type : : JSONError ,
2021-09-16 11:09:08 +00:00
" general " ,
" Field \" settings.debug.revertStrings \" cannot be used for Yul. "
) ) ;
return output ;
}
2017-04-21 14:34:40 +00:00
2022-03-28 04:27:11 +00:00
YulStack stack (
2019-03-27 11:49:50 +00:00
_inputsAndSettings . evmVersion ,
2022-11-22 12:05:20 +00:00
_inputsAndSettings . eofVersion ,
2022-03-28 04:27:11 +00:00
YulStack : : Language : : StrictAssembly ,
2021-09-17 18:15:19 +00:00
_inputsAndSettings . optimiserSettings ,
2021-09-13 12:17:05 +00:00
_inputsAndSettings . debugInfoSelection . has_value ( ) ?
_inputsAndSettings . debugInfoSelection . value ( ) :
DebugInfoSelection : : Default ( )
2019-03-27 11:49:50 +00:00
) ;
2017-04-21 14:34:40 +00:00
string const & sourceName = _inputsAndSettings . sources . begin ( ) - > first ;
string const & sourceContents = _inputsAndSettings . sources . begin ( ) - > second ;
2019-03-25 13:09:18 +00:00
// Inconsistent state - stop here to receive error reports from users
if ( ! stack . parseAndAnalyze ( sourceName , sourceContents ) & & stack . errors ( ) . empty ( ) )
2021-09-16 11:09:08 +00:00
{
output [ " errors " ] . append ( formatError (
2022-06-17 03:25:52 +00:00
Error : : Type : : InternalCompilerError ,
2021-09-16 11:09:08 +00:00
" general " ,
" No error reported, but compilation failed. "
) ) ;
return output ;
}
2019-03-25 13:09:18 +00:00
if ( ! stack . errors ( ) . empty ( ) )
2017-04-21 14:34:40 +00:00
{
for ( auto const & error : stack . errors ( ) )
{
auto err = dynamic_pointer_cast < Error const > ( error ) ;
2021-09-16 11:09:08 +00:00
output [ " errors " ] . append ( formatErrorWithException (
2021-06-29 12:38:59 +00:00
stack ,
2017-04-21 14:34:40 +00:00
* error ,
2022-06-17 03:25:52 +00:00
err - > type ( ) ,
2017-04-21 14:34:40 +00:00
" general " ,
" "
) ) ;
}
return output ;
}
string contractName = stack . parserResult ( ) - > name . str ( ) ;
2019-06-18 16:11:04 +00:00
bool const wildcardMatchesExperimental = true ;
if ( isArtifactRequested ( _inputsAndSettings . outputSelection , sourceName , contractName , " ir " , wildcardMatchesExperimental ) )
2017-04-21 14:34:40 +00:00
output [ " contracts " ] [ sourceName ] [ contractName ] [ " ir " ] = stack . print ( ) ;
2023-05-02 13:34:12 +00:00
if ( isArtifactRequested ( _inputsAndSettings . outputSelection , sourceName , contractName , " ast " , wildcardMatchesExperimental ) )
{
Json : : Value sourceResult = Json : : objectValue ;
sourceResult [ " id " ] = 1 ;
sourceResult [ " ast " ] = stack . astJson ( ) ;
output [ " sources " ] [ sourceName ] = sourceResult ;
}
2019-03-27 11:49:50 +00:00
stack . optimize ( ) ;
2017-04-21 14:34:40 +00:00
2020-05-12 14:33:05 +00:00
MachineAssemblyObject object ;
2022-01-27 13:07:50 +00:00
MachineAssemblyObject deployedObject ;
tie ( object , deployedObject ) = stack . assembleWithDeployed ( ) ;
2017-04-21 14:34:40 +00:00
2020-11-05 13:40:51 +00:00
if ( object . bytecode )
object . bytecode - > link ( _inputsAndSettings . libraries ) ;
2022-01-27 13:07:50 +00:00
if ( deployedObject . bytecode )
deployedObject . bytecode - > link ( _inputsAndSettings . libraries ) ;
2020-11-05 13:40:51 +00:00
2022-01-27 13:07:50 +00:00
for ( auto & & [ kind , isDeployed ] : { make_pair ( " bytecode " s , false ) , make_pair ( " deployedBytecode " s , true ) } )
2020-05-12 14:33:05 +00:00
if ( isArtifactRequested (
_inputsAndSettings . outputSelection ,
sourceName ,
contractName ,
2022-01-27 13:07:50 +00:00
evmObjectComponents ( kind ) ,
2020-05-12 14:33:05 +00:00
wildcardMatchesExperimental
) )
{
2022-01-27 13:07:50 +00:00
MachineAssemblyObject const & o = isDeployed ? deployedObject : object ;
2020-05-12 14:33:05 +00:00
if ( o . bytecode )
2022-01-27 13:07:50 +00:00
output [ " contracts " ] [ sourceName ] [ contractName ] [ " evm " ] [ kind ] =
2020-12-03 10:27:21 +00:00
collectEVMObject (
2022-11-23 10:51:34 +00:00
_inputsAndSettings . evmVersion ,
2020-12-03 10:27:21 +00:00
* o . bytecode ,
o . sourceMappings . get ( ) ,
Json : : arrayValue ,
2022-01-27 13:07:50 +00:00
isDeployed ,
[ & , kind = kind ] ( string const & _element ) { return isArtifactRequested (
2020-12-03 10:27:21 +00:00
_inputsAndSettings . outputSelection ,
sourceName ,
contractName ,
2022-01-27 13:07:50 +00:00
" evm. " + kind + " . " + _element ,
2020-12-03 10:27:21 +00:00
wildcardMatchesExperimental
) ; }
) ;
2020-05-12 14:33:05 +00:00
}
2017-04-21 14:34:40 +00:00
2019-06-18 16:11:04 +00:00
if ( isArtifactRequested ( _inputsAndSettings . outputSelection , sourceName , contractName , " irOptimized " , wildcardMatchesExperimental ) )
2017-04-21 14:34:40 +00:00
output [ " contracts " ] [ sourceName ] [ contractName ] [ " irOptimized " ] = stack . print ( ) ;
2019-06-18 16:11:04 +00:00
if ( isArtifactRequested ( _inputsAndSettings . outputSelection , sourceName , contractName , " evm.assembly " , wildcardMatchesExperimental ) )
2017-04-21 14:34:40 +00:00
output [ " contracts " ] [ sourceName ] [ contractName ] [ " evm " ] [ " assembly " ] = object . assembly ;
return output ;
}
2018-08-08 12:22:33 +00:00
Json : : Value StandardCompiler : : compile ( Json : : Value const & _input ) noexcept
2017-03-17 12:08:12 +00:00
{
2019-04-24 12:03:09 +00:00
YulStringRepository : : reset ( ) ;
2017-03-17 12:08:12 +00:00
try
{
2019-03-07 14:35:31 +00:00
auto parsed = parseInput ( _input ) ;
2020-05-11 11:38:49 +00:00
if ( std : : holds_alternative < Json : : Value > ( parsed ) )
return std : : get < Json : : Value > ( std : : move ( parsed ) ) ;
InputsAndSettings settings = std : : get < InputsAndSettings > ( std : : move ( parsed ) ) ;
2017-04-21 14:34:40 +00:00
if ( settings . language = = " Solidity " )
return compileSolidity ( std : : move ( settings ) ) ;
else if ( settings . language = = " Yul " )
return compileYul ( std : : move ( settings ) ) ;
2023-04-28 16:29:59 +00:00
else if ( settings . language = = " SolidityAST " )
return compileSolidity ( std : : move ( settings ) ) ;
2017-04-21 14:34:40 +00:00
else
2023-04-28 16:29:59 +00:00
return formatFatalError ( Error : : Type : : JSONError , " Only \" Solidity \" , \" Yul \" or \" SolidityAST \" is supported as a language. " ) ;
2017-03-17 12:08:12 +00:00
}
2017-04-24 21:49:50 +00:00
catch ( Json : : LogicError const & _exception )
{
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : InternalCompilerError , string ( " JSON logic exception: " ) + _exception . what ( ) ) ;
2017-04-24 21:49:50 +00:00
}
catch ( Json : : RuntimeError const & _exception )
{
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : InternalCompilerError , string ( " JSON runtime exception: " ) + _exception . what ( ) ) ;
2017-04-24 21:49:50 +00:00
}
2019-12-11 16:31:36 +00:00
catch ( util : : Exception const & _exception )
2017-04-23 18:43:06 +00:00
{
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : InternalCompilerError , " Internal exception in StandardCompiler::compile: " + boost : : diagnostic_information ( _exception ) ) ;
2017-04-23 18:43:06 +00:00
}
2017-03-17 12:08:12 +00:00
catch ( . . . )
{
2022-06-17 03:25:52 +00:00
return formatFatalError ( Error : : Type : : InternalCompilerError , " Internal exception in StandardCompiler::compile: " + boost : : current_exception_diagnostic_information ( ) ) ;
2017-03-17 12:08:12 +00:00
}
}
2018-08-08 12:22:33 +00:00
string StandardCompiler : : compile ( string const & _input ) noexcept
2017-02-09 21:56:49 +00:00
{
2017-02-10 13:18:21 +00:00
Json : : Value input ;
2018-02-07 01:05:20 +00:00
string errors ;
2017-03-29 12:34:16 +00:00
try
{
2019-12-11 16:31:36 +00:00
if ( ! util : : jsonParseStrict ( _input , input , & errors ) )
2022-06-17 03:25:52 +00:00
return util : : jsonPrint ( formatFatalError ( Error : : Type : : JSONError , errors ) , m_jsonPrintingFormat ) ;
2017-03-29 12:34:16 +00:00
}
2018-05-17 12:57:21 +00:00
catch ( . . . )
2017-02-10 13:18:21 +00:00
{
2018-09-21 21:43:57 +00:00
return " { \" errors \" :[{ \" type \" : \" JSONError \" , \" component \" : \" general \" , \" severity \" : \" error \" , \" message \" : \" Error parsing input JSON. \" }]} " ;
2017-02-10 13:18:21 +00:00
}
// cout << "Input: " << input.toStyledString() << endl;
Json : : Value output = compile ( input ) ;
// cout << "Output: " << output.toStyledString() << endl;
try
{
2021-07-07 11:18:24 +00:00
return util : : jsonPrint ( output , m_jsonPrintingFormat ) ;
2017-02-10 13:18:21 +00:00
}
2018-05-17 12:57:21 +00:00
catch ( . . . )
2017-02-10 13:18:21 +00:00
{
2018-09-21 21:43:57 +00:00
return " { \" errors \" :[{ \" type \" : \" JSONError \" , \" component \" : \" general \" , \" severity \" : \" error \" , \" message \" : \" Error writing output JSON. \" }]} " ;
2017-02-10 13:18:21 +00:00
}
2017-02-09 21:56:49 +00:00
}
2020-05-07 12:46:47 +00:00
Json : : Value StandardCompiler : : formatFunctionDebugData (
map < string , evmasm : : LinkerObject : : FunctionDebugData > const & _debugInfo
)
{
Json : : Value ret ( Json : : objectValue ) ;
for ( auto const & [ name , info ] : _debugInfo )
{
Json : : Value fun ;
if ( info . sourceID )
fun [ " id " ] = Json : : UInt64 ( * info . sourceID ) ;
else
fun [ " id " ] = Json : : nullValue ;
if ( info . bytecodeOffset )
fun [ " entryPoint " ] = Json : : UInt64 ( * info . bytecodeOffset ) ;
else
fun [ " entryPoint " ] = Json : : nullValue ;
fun [ " parameterSlots " ] = Json : : UInt64 ( info . params ) ;
fun [ " returnSlots " ] = Json : : UInt64 ( info . returns ) ;
2022-08-23 17:28:45 +00:00
ret [ name ] = std : : move ( fun ) ;
2020-05-07 12:46:47 +00:00
}
return ret ;
}