2014-10-30 21:52:15 +00:00
/*
This file is part of cpp - ethereum .
cpp - ethereum 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 .
cpp - ethereum 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 cpp - ethereum . If not , see < http : //www.gnu.org/licenses/>.
*/
/**
* @ author Christian < c @ ethdev . com >
2015-01-09 06:39:30 +00:00
* @ author Gav Wood < g @ ethdev . com >
2014-10-30 21:52:15 +00:00
* @ date 2014
* Full - stack compiler that converts a source code string to bytecode .
*/
2015-01-21 19:31:14 +00:00
# include <boost/algorithm/string.hpp>
2015-12-09 16:35:20 +00:00
# include <boost/filesystem.hpp>
2015-10-20 22:21:52 +00:00
# include <libsolidity/ast/AST.h>
# include <libsolidity/parsing/Scanner.h>
# include <libsolidity/parsing/Parser.h>
# include <libsolidity/analysis/GlobalContext.h>
# include <libsolidity/analysis/NameAndTypeResolver.h>
# include <libsolidity/analysis/TypeChecker.h>
2015-10-26 14:13:36 +00:00
# include <libsolidity/analysis/DocStringAnalyser.h>
2016-01-14 01:58:09 +00:00
# include <libsolidity/analysis/SyntaxChecker.h>
2015-10-20 22:21:52 +00:00
# include <libsolidity/codegen/Compiler.h>
# include <libsolidity/interface/CompilerStack.h>
# include <libsolidity/interface/InterfaceHandler.h>
2015-10-21 14:43:31 +00:00
# include <libsolidity/formal/Why3Translator.h>
2014-10-30 21:52:15 +00:00
2015-05-19 17:51:38 +00:00
# include <libdevcore/SHA3.h>
2015-01-13 14:59:42 +00:00
2014-10-30 21:52:15 +00:00
using namespace std ;
2016-01-12 00:04:39 +00:00
using namespace dev ;
using namespace dev : : solidity ;
2014-10-30 21:52:15 +00:00
2015-01-28 12:39:04 +00:00
const map < string , string > StandardSources = map < string , string > {
2015-03-09 16:48:33 +00:00
{ " coin " , R " (import " CoinReg " ;import " Config " ;import " configUser " ;contract coin is configUser{function coin(bytes3 name, uint denom) {CoinReg(Config(configAddr()).lookup(3)).register(name, denom);}}) " } ,
2015-01-28 12:39:04 +00:00
{ " Coin " , R " (contract Coin{function isApprovedFor(address _target,address _proxy)constant returns(bool _r){}function isApproved(address _proxy)constant returns(bool _r){}function sendCoinFrom(address _from,uint256 _val,address _to){}function coinBalanceOf(address _a)constant returns(uint256 _r){}function sendCoin(uint256 _val,address _to){}function coinBalance()constant returns(uint256 _r){}function approve(address _a){}}) " } ,
2015-03-09 16:48:33 +00:00
{ " CoinReg " , R " (contract CoinReg{function count()constant returns(uint256 r){}function info(uint256 i)constant returns(address addr,bytes3 name,uint256 denom){}function register(bytes3 name,uint256 denom){}function unregister(){}}) " } ,
2015-01-28 12:39:04 +00:00
{ " configUser " , R " (contract configUser{function configAddr()constant returns(address a){ return 0xc6d9d2cd449a754c494264e1809c50e34d64562b;}}) " } ,
{ " Config " , R " (contract Config{function lookup(uint256 service)constant returns(address a){}function kill(){}function unregister(uint256 id){}function register(uint256 id,address service){}}) " } ,
{ " mortal " , R " (import " owned " ;contract mortal is owned {function kill() { if (msg.sender == owner) suicide(owner); }}) " } ,
2015-03-09 16:48:33 +00:00
{ " named " , R " (import " Config " ;import " NameReg " ;import " configUser " ;contract named is configUser {function named(bytes32 name) {NameReg(Config(configAddr()).lookup(1)).register(name);}}) " } ,
{ " NameReg " , R " (contract NameReg{function register(bytes32 name){}function addressOf(bytes32 name)constant returns(address addr){}function unregister(){}function nameOf(address addr)constant returns(bytes32 name){}}) " } ,
2015-01-28 12:39:04 +00:00
{ " owned " , R " (contract owned{function owned(){owner = msg.sender;}modifier onlyowner(){if(msg.sender==owner)_}address owner;}) " } ,
{ " service " , R " (import " Config " ;import " configUser " ;contract service is configUser{function service(uint _n){Config(configAddr()).register(_n, this);}}) " } ,
2015-01-30 12:57:23 +00:00
{ " std " , R " (import " owned " ;import " mortal " ;import " Config " ;import " configUser " ;import " NameReg " ;import " named " ;) " }
2015-01-28 12:39:04 +00:00
} ;
2016-01-12 00:04:39 +00:00
CompilerStack : : CompilerStack ( bool _addStandardSources , ReadFileCallback const & _readFile ) :
m_readFile ( _readFile ) , m_parseSuccessful ( false )
2015-01-28 12:39:04 +00:00
{
2015-05-19 22:27:07 +00:00
if ( _addStandardSources )
2015-02-20 17:15:34 +00:00
addSources ( StandardSources , true ) ; // add them as libraries
2015-01-28 12:39:04 +00:00
}
2016-06-07 17:44:32 +00:00
void CompilerStack : : setRemappings ( vector < string > const & _remappings )
{
vector < Remapping > remappings ;
for ( auto const & remapping : _remappings )
{
auto eq = find ( remapping . begin ( ) , remapping . end ( ) , ' = ' ) ;
if ( eq = = remapping . end ( ) )
continue ; // ignore
auto colon = find ( remapping . begin ( ) , eq , ' : ' ) ;
Remapping r ;
r . context = colon = = eq ? string ( ) : string ( remapping . begin ( ) , colon ) ;
r . prefix = colon = = eq ? string ( remapping . begin ( ) , eq ) : string ( colon + 1 , eq ) ;
r . target = string ( eq + 1 , remapping . end ( ) ) ;
remappings . push_back ( r ) ;
}
swap ( m_remappings , remappings ) ;
}
2015-05-19 22:27:07 +00:00
void CompilerStack : : reset ( bool _keepSources , bool _addStandardSources )
{
m_parseSuccessful = false ;
if ( _keepSources )
for ( auto sourcePair : m_sources )
sourcePair . second . reset ( ) ;
else
{
m_sources . clear ( ) ;
if ( _addStandardSources )
addSources ( StandardSources , true ) ;
}
m_globalContext . reset ( ) ;
m_sourceOrder . clear ( ) ;
m_contracts . clear ( ) ;
2015-09-21 17:43:56 +00:00
m_errors . clear ( ) ;
2015-05-19 22:27:07 +00:00
}
2015-02-20 17:15:34 +00:00
bool CompilerStack : : addSource ( string const & _name , string const & _content , bool _isLibrary )
2014-12-03 16:45:12 +00:00
{
2015-01-13 10:18:08 +00:00
bool existed = m_sources . count ( _name ) ! = 0 ;
2014-12-03 16:45:12 +00:00
reset ( true ) ;
2015-02-21 15:25:28 +00:00
m_sources [ _name ] . scanner = make_shared < Scanner > ( CharStream ( _content ) , _name ) ;
2015-02-20 17:15:34 +00:00
m_sources [ _name ] . isLibrary = _isLibrary ;
2014-12-18 13:39:16 +00:00
return existed ;
2014-12-03 16:45:12 +00:00
}
2014-11-11 16:41:48 +00:00
void CompilerStack : : setSource ( string const & _sourceCode )
2014-10-30 21:52:15 +00:00
{
2014-11-11 16:41:48 +00:00
reset ( ) ;
2015-02-21 15:25:28 +00:00
addSource ( " " , _sourceCode ) ;
2014-11-11 16:41:48 +00:00
}
2015-09-21 17:43:56 +00:00
bool CompilerStack : : parse ( )
2014-11-11 16:41:48 +00:00
{
2015-10-15 14:08:02 +00:00
//reset
2015-09-21 17:43:56 +00:00
m_errors . clear ( ) ;
2015-10-15 14:08:02 +00:00
m_parseSuccessful = false ;
2015-09-21 17:43:56 +00:00
2016-01-12 00:04:39 +00:00
vector < string > sourcesToParse ;
for ( auto const & s : m_sources )
sourcesToParse . push_back ( s . first ) ;
2015-12-05 02:09:47 +00:00
map < string , SourceUnit const * > sourceUnitsByName ;
2016-01-12 00:04:39 +00:00
for ( size_t i = 0 ; i < sourcesToParse . size ( ) ; + + i )
2014-12-03 16:45:12 +00:00
{
2016-01-12 00:04:39 +00:00
string const & path = sourcesToParse [ i ] ;
Source & source = m_sources [ path ] ;
source . scanner - > reset ( ) ;
source . ast = Parser ( m_errors ) . parse ( source . scanner ) ;
sourceUnitsByName [ path ] = source . ast . get ( ) ;
if ( ! source . ast )
2015-10-16 12:52:01 +00:00
solAssert ( ! Error : : containsOnlyWarnings ( m_errors ) , " Parser returned null but did not report error. " ) ;
2015-12-15 14:46:03 +00:00
else
2016-01-12 00:04:39 +00:00
{
source . ast - > annotation ( ) . path = path ;
for ( auto const & newSource : loadMissingSources ( * source . ast , path ) )
{
string const & newPath = newSource . first ;
string const & newContents = newSource . second ;
m_sources [ newPath ] . scanner = make_shared < Scanner > ( CharStream ( newContents ) , newPath ) ;
sourcesToParse . push_back ( newPath ) ;
}
}
2014-12-03 16:45:12 +00:00
}
2015-10-14 18:37:41 +00:00
if ( ! Error : : containsOnlyWarnings ( m_errors ) )
// errors while parsing. sould stop before type checking
return false ;
2014-12-03 16:45:12 +00:00
resolveImports ( ) ;
2015-10-26 14:13:36 +00:00
bool noErrors = true ;
2016-01-14 01:58:09 +00:00
SyntaxChecker syntaxChecker ( m_errors ) ;
for ( Source const * source : m_sourceOrder )
if ( ! syntaxChecker . checkSyntax ( * source - > ast ) )
2016-01-19 02:16:13 +00:00
noErrors = false ;
2016-01-14 01:58:09 +00:00
2015-10-26 14:13:36 +00:00
DocStringAnalyser docStringAnalyser ( m_errors ) ;
for ( Source const * source : m_sourceOrder )
if ( ! docStringAnalyser . analyseDocStrings ( * source - > ast ) )
noErrors = false ;
2014-11-20 17:33:23 +00:00
m_globalContext = make_shared < GlobalContext > ( ) ;
2015-10-02 12:41:40 +00:00
NameAndTypeResolver resolver ( m_globalContext - > declarations ( ) , m_errors ) ;
2014-12-03 16:45:12 +00:00
for ( Source const * source : m_sourceOrder )
2015-10-15 14:08:02 +00:00
if ( ! resolver . registerDeclarations ( * source - > ast ) )
return false ;
2014-12-03 16:45:12 +00:00
for ( Source const * source : m_sourceOrder )
2015-12-05 02:09:47 +00:00
if ( ! resolver . performImports ( * source - > ast , sourceUnitsByName ) )
return false ;
for ( Source const * source : m_sourceOrder )
2015-08-31 16:44:29 +00:00
for ( ASTPointer < ASTNode > const & node : source - > ast - > nodes ( ) )
2014-12-03 16:45:12 +00:00
if ( ContractDefinition * contract = dynamic_cast < ContractDefinition * > ( node . get ( ) ) )
{
m_globalContext - > setCurrentContract ( * contract ) ;
2015-10-15 16:15:52 +00:00
if ( ! resolver . updateDeclaration ( * m_globalContext - > currentThis ( ) ) ) return false ;
if ( ! resolver . updateDeclaration ( * m_globalContext - > currentSuper ( ) ) ) return false ;
if ( ! resolver . resolveNamesAndTypes ( * contract ) ) return false ;
2015-08-31 16:44:29 +00:00
m_contracts [ contract - > name ( ) ] . contract = contract ;
2014-12-03 16:45:12 +00:00
}
2015-09-21 17:43:56 +00:00
2016-01-11 18:40:15 +00:00
if ( ! checkLibraryNameClashes ( ) )
noErrors = false ;
2014-12-16 22:45:24 +00:00
for ( Source const * source : m_sourceOrder )
2015-08-31 16:44:29 +00:00
for ( ASTPointer < ASTNode > const & node : source - > ast - > nodes ( ) )
2014-12-16 22:45:24 +00:00
if ( ContractDefinition * contract = dynamic_cast < ContractDefinition * > ( node . get ( ) ) )
{
m_globalContext - > setCurrentContract ( * contract ) ;
2015-08-31 16:44:29 +00:00
resolver . updateDeclaration ( * m_globalContext - > currentThis ( ) ) ;
2015-10-15 09:10:55 +00:00
TypeChecker typeChecker ( m_errors ) ;
2015-10-05 15:19:23 +00:00
if ( typeChecker . checkTypeRequirements ( * contract ) )
{
2015-10-26 14:13:36 +00:00
contract - > setDevDocumentation ( InterfaceHandler : : devDocumentation ( * contract ) ) ;
contract - > setUserDocumentation ( InterfaceHandler : : userDocumentation ( * contract ) ) ;
2015-10-05 15:19:23 +00:00
}
else
2015-10-26 14:13:36 +00:00
noErrors = false ;
2015-10-14 18:37:41 +00:00
2015-08-31 16:44:29 +00:00
m_contracts [ contract - > name ( ) ] . contract = contract ;
2014-12-16 22:45:24 +00:00
}
2015-10-26 14:13:36 +00:00
m_parseSuccessful = noErrors ;
2015-09-21 17:43:56 +00:00
return m_parseSuccessful ;
2014-11-11 16:41:48 +00:00
}
2015-09-21 17:43:56 +00:00
bool CompilerStack : : parse ( string const & _sourceCode )
2014-11-11 16:41:48 +00:00
{
setSource ( _sourceCode ) ;
2015-09-21 17:43:56 +00:00
return parse ( ) ;
2014-11-11 16:41:48 +00:00
}
2015-08-31 16:44:29 +00:00
vector < string > CompilerStack : : contractNames ( ) const
2014-11-11 16:41:48 +00:00
{
if ( ! m_parseSuccessful )
BOOST_THROW_EXCEPTION ( CompilerError ( ) < < errinfo_comment ( " Parsing was not successful. " ) ) ;
2014-12-03 17:52:28 +00:00
vector < string > contractNames ;
for ( auto const & contract : m_contracts )
contractNames . push_back ( contract . first ) ;
return contractNames ;
}
2015-01-29 01:34:57 +00:00
2015-09-21 17:43:56 +00:00
bool CompilerStack : : compile ( bool _optimize , unsigned _runs )
2014-12-03 17:52:28 +00:00
{
if ( ! m_parseSuccessful )
2015-09-21 17:43:56 +00:00
if ( ! parse ( ) )
return false ;
2015-09-16 14:56:30 +00:00
2015-09-10 10:01:05 +00:00
map < ContractDefinition const * , eth : : Assembly const * > compiledContracts ;
2014-12-03 16:45:12 +00:00
for ( Source const * source : m_sourceOrder )
2015-08-31 16:44:29 +00:00
for ( ASTPointer < ASTNode > const & node : source - > ast - > nodes ( ) )
2015-10-07 13:57:17 +00:00
if ( auto contract = dynamic_cast < ContractDefinition const * > ( node . get ( ) ) )
compileContract ( _optimize , _runs , * contract , compiledContracts ) ;
2015-09-21 17:43:56 +00:00
return true ;
2014-11-11 16:41:48 +00:00
}
2014-10-30 21:52:15 +00:00
2015-09-21 17:43:56 +00:00
bool CompilerStack : : compile ( string const & _sourceCode , bool _optimize )
2014-11-11 16:41:48 +00:00
{
2015-09-21 17:43:56 +00:00
return parse ( _sourceCode ) & & compile ( _optimize ) ;
2014-10-30 21:52:15 +00:00
}
2015-09-11 17:35:01 +00:00
void CompilerStack : : link ( const std : : map < string , h160 > & _libraries )
{
for ( auto & contract : m_contracts )
{
contract . second . object . link ( _libraries ) ;
contract . second . runtimeObject . link ( _libraries ) ;
contract . second . cloneObject . link ( _libraries ) ;
}
}
2016-07-18 16:16:22 +00:00
bool CompilerStack : : prepareFormalAnalysis ( ErrorList * _errors )
2015-10-21 14:43:31 +00:00
{
2016-07-18 16:16:22 +00:00
if ( ! _errors )
_errors = & m_errors ;
Why3Translator translator ( * _errors ) ;
2015-10-21 14:43:31 +00:00
for ( Source const * source : m_sourceOrder )
if ( ! translator . process ( * source - > ast ) )
return false ;
m_formalTranslation = translator . translation ( ) ;
return true ;
}
2015-08-31 16:44:29 +00:00
eth : : AssemblyItems const * CompilerStack : : assemblyItems ( string const & _contractName ) const
2015-03-02 00:13:10 +00:00
{
2015-08-31 16:44:29 +00:00
Contract const & currentContract = contract ( _contractName ) ;
return currentContract . compiler ? & contract ( _contractName ) . compiler - > assemblyItems ( ) : nullptr ;
2015-03-02 00:13:10 +00:00
}
2015-08-31 16:44:29 +00:00
eth : : AssemblyItems const * CompilerStack : : runtimeAssemblyItems ( string const & _contractName ) const
2015-03-02 00:13:10 +00:00
{
2015-08-31 16:44:29 +00:00
Contract const & currentContract = contract ( _contractName ) ;
return currentContract . compiler ? & contract ( _contractName ) . compiler - > runtimeAssemblyItems ( ) : nullptr ;
2015-03-02 00:13:10 +00:00
}
2016-07-01 08:14:50 +00:00
string const * CompilerStack : : sourceMapping ( string const & _contractName ) const
{
Contract const & c = contract ( _contractName ) ;
if ( ! c . sourceMapping )
{
if ( auto items = assemblyItems ( _contractName ) )
c . sourceMapping . reset ( new string ( computeSourceMapping ( * items ) ) ) ;
}
return c . sourceMapping . get ( ) ;
}
string const * CompilerStack : : runtimeSourceMapping ( string const & _contractName ) const
{
Contract const & c = contract ( _contractName ) ;
if ( ! c . runtimeSourceMapping )
{
if ( auto items = runtimeAssemblyItems ( _contractName ) )
c . runtimeSourceMapping . reset ( new string ( computeSourceMapping ( * items ) ) ) ;
}
return c . runtimeSourceMapping . get ( ) ;
}
2015-09-10 10:01:05 +00:00
eth : : LinkerObject const & CompilerStack : : object ( string const & _contractName ) const
2014-11-11 16:41:48 +00:00
{
2015-09-10 10:01:05 +00:00
return contract ( _contractName ) . object ;
2014-11-11 16:41:48 +00:00
}
2015-09-10 10:01:05 +00:00
eth : : LinkerObject const & CompilerStack : : runtimeObject ( string const & _contractName ) const
2015-01-13 14:59:42 +00:00
{
2015-09-10 10:01:05 +00:00
return contract ( _contractName ) . runtimeObject ;
2015-01-13 14:59:42 +00:00
}
2015-09-10 10:01:05 +00:00
eth : : LinkerObject const & CompilerStack : : cloneObject ( string const & _contractName ) const
2015-07-31 17:23:31 +00:00
{
2015-09-10 10:01:05 +00:00
return contract ( _contractName ) . cloneObject ;
2015-07-31 17:23:31 +00:00
}
2015-08-31 16:44:29 +00:00
dev : : h256 CompilerStack : : contractCodeHash ( string const & _contractName ) const
2015-01-13 14:59:42 +00:00
{
2015-09-10 10:01:05 +00:00
auto const & obj = runtimeObject ( _contractName ) ;
if ( obj . bytecode . empty ( ) | | ! obj . linkReferences . empty ( ) )
return dev : : h256 ( ) ;
else
return dev : : sha3 ( obj . bytecode ) ;
2015-01-13 14:59:42 +00:00
}
2015-01-28 07:50:53 +00:00
Json : : Value CompilerStack : : streamAssembly ( ostream & _outStream , string const & _contractName , StringMap _sourceCodes , bool _inJsonFormat ) const
2014-11-11 16:41:48 +00:00
{
2015-08-31 16:44:29 +00:00
Contract const & currentContract = contract ( _contractName ) ;
if ( currentContract . compiler )
return currentContract . compiler - > streamAssembly ( _outStream , _sourceCodes , _inJsonFormat ) ;
2015-04-02 13:10:35 +00:00
else
2015-01-28 07:50:53 +00:00
{
2015-04-02 13:10:35 +00:00
_outStream < < " Contract not fully implemented " < < endl ;
2015-01-28 07:50:53 +00:00
return Json : : Value ( ) ;
}
2014-12-03 16:45:12 +00:00
}
2016-07-01 08:14:50 +00:00
vector < string > CompilerStack : : sourceNames ( ) const
{
vector < string > names ;
for ( auto const & s : m_sources )
names . push_back ( s . first ) ;
return names ;
}
map < string , unsigned > CompilerStack : : sourceIndices ( ) const
{
map < string , unsigned > indices ;
for ( auto const & s : m_sources )
indices [ s . first ] = indices . size ( ) ;
return indices ;
}
2015-08-31 16:44:29 +00:00
string const & CompilerStack : : interface ( string const & _contractName ) const
2014-12-03 16:45:12 +00:00
{
2015-08-31 16:44:29 +00:00
return metadata ( _contractName , DocumentationType : : ABIInterface ) ;
2014-12-05 14:27:07 +00:00
}
2015-08-31 16:44:29 +00:00
string const & CompilerStack : : solidityInterface ( string const & _contractName ) const
2015-01-08 23:22:06 +00:00
{
2015-08-31 16:44:29 +00:00
return metadata ( _contractName , DocumentationType : : ABISolidityInterface ) ;
2015-01-08 23:22:06 +00:00
}
2015-08-31 16:44:29 +00:00
string const & CompilerStack : : metadata ( string const & _contractName , DocumentationType _type ) const
2014-12-01 16:03:04 +00:00
{
if ( ! m_parseSuccessful )
BOOST_THROW_EXCEPTION ( CompilerError ( ) < < errinfo_comment ( " Parsing was not successful. " ) ) ;
2014-12-01 17:01:42 +00:00
2014-12-06 01:39:58 +00:00
std : : unique_ptr < string const > * doc ;
2015-10-14 18:37:41 +00:00
Contract const & currentContract = contract ( _contractName ) ;
2015-07-15 14:23:10 +00:00
// checks wheather we already have the documentation
2014-12-03 15:40:37 +00:00
switch ( _type )
2014-11-11 16:41:48 +00:00
{
2015-02-09 13:12:36 +00:00
case DocumentationType : : NatspecUser :
2015-08-31 16:44:29 +00:00
doc = & currentContract . userDocumentation ;
2014-12-05 14:27:07 +00:00
break ;
2015-02-09 13:12:36 +00:00
case DocumentationType : : NatspecDev :
2015-08-31 16:44:29 +00:00
doc = & currentContract . devDocumentation ;
2014-12-05 14:27:07 +00:00
break ;
2015-02-09 13:12:36 +00:00
case DocumentationType : : ABIInterface :
2015-08-31 16:44:29 +00:00
doc = & currentContract . interface ;
2014-12-05 14:27:07 +00:00
break ;
2015-02-09 13:12:36 +00:00
case DocumentationType : : ABISolidityInterface :
2015-08-31 16:44:29 +00:00
doc = & currentContract . solidityInterface ;
2015-01-08 23:22:06 +00:00
break ;
2014-12-05 14:27:07 +00:00
default :
BOOST_THROW_EXCEPTION ( InternalCompilerError ( ) < < errinfo_comment ( " Illegal documentation type. " ) ) ;
2014-11-11 16:41:48 +00:00
}
2015-06-19 13:40:09 +00:00
2015-07-15 14:23:10 +00:00
// caches the result
2014-12-05 14:27:07 +00:00
if ( ! * doc )
2015-10-26 14:13:36 +00:00
doc - > reset ( new string ( InterfaceHandler : : documentation ( * currentContract . contract , _type ) ) ) ;
2015-06-19 13:40:09 +00:00
2014-12-05 14:27:07 +00:00
return * ( * doc ) ;
2014-12-03 16:45:12 +00:00
}
2015-08-31 16:44:29 +00:00
Scanner const & CompilerStack : : scanner ( string const & _sourceName ) const
2014-12-03 16:45:12 +00:00
{
2015-08-31 16:44:29 +00:00
return * source ( _sourceName ) . scanner ;
2014-12-03 16:45:12 +00:00
}
2015-09-08 12:30:21 +00:00
SourceUnit const & CompilerStack : : ast ( string const & _sourceName ) const
2014-12-03 16:45:12 +00:00
{
2015-08-31 16:44:29 +00:00
return * source ( _sourceName ) . ast ;
2014-11-11 16:41:48 +00:00
}
2015-08-31 16:44:29 +00:00
ContractDefinition const & CompilerStack : : contractDefinition ( string const & _contractName ) const
2014-12-18 13:39:16 +00:00
{
2015-08-31 16:44:29 +00:00
return * contract ( _contractName ) . contract ;
2014-12-18 13:39:16 +00:00
}
2015-08-31 16:44:29 +00:00
size_t CompilerStack : : functionEntryPoint (
2015-05-26 09:27:59 +00:00
std : : string const & _contractName ,
FunctionDefinition const & _function
) const
{
2015-08-31 16:44:29 +00:00
shared_ptr < Compiler > const & compiler = contract ( _contractName ) . compiler ;
2015-05-26 09:27:59 +00:00
if ( ! compiler )
return 0 ;
2015-08-31 16:44:29 +00:00
eth : : AssemblyItem tag = compiler - > functionEntryLabel ( _function ) ;
2015-05-26 09:27:59 +00:00
if ( tag . type ( ) = = eth : : UndefinedItem )
return 0 ;
2015-08-31 16:44:29 +00:00
eth : : AssemblyItems const & items = compiler - > runtimeAssemblyItems ( ) ;
2015-05-26 09:27:59 +00:00
for ( size_t i = 0 ; i < items . size ( ) ; + + i )
if ( items . at ( i ) . type ( ) = = eth : : Tag & & items . at ( i ) . data ( ) = = tag . data ( ) )
return i ;
return 0 ;
}
2015-05-07 15:22:24 +00:00
tuple < int , int , int , int > CompilerStack : : positionFromSourceLocation ( SourceLocation const & _sourceLocation ) const
2015-05-07 11:32:26 +00:00
{
2015-05-07 15:22:24 +00:00
int startLine ;
int startColumn ;
int endLine ;
int endColumn ;
2015-08-31 16:44:29 +00:00
tie ( startLine , startColumn ) = scanner ( * _sourceLocation . sourceName ) . translatePositionToLineColumn ( _sourceLocation . start ) ;
tie ( endLine , endColumn ) = scanner ( * _sourceLocation . sourceName ) . translatePositionToLineColumn ( _sourceLocation . end ) ;
2015-05-07 15:22:24 +00:00
return make_tuple ( + + startLine , + + startColumn , + + endLine , + + endColumn ) ;
2015-05-07 11:32:26 +00:00
}
2016-06-07 17:44:32 +00:00
StringMap CompilerStack : : loadMissingSources ( SourceUnit const & _ast , std : : string const & _sourcePath )
2016-01-12 00:04:39 +00:00
{
StringMap newSources ;
for ( auto const & node : _ast . nodes ( ) )
if ( ImportDirective const * import = dynamic_cast < ImportDirective * > ( node . get ( ) ) )
{
2016-06-07 17:44:32 +00:00
string importPath = absolutePath ( import - > path ( ) , _sourcePath ) ;
// The current value of `path` is the absolute path as seen from this source file.
// We first have to apply remappings before we can store the actual absolute path
// as seen globally.
importPath = applyRemapping ( importPath , _sourcePath ) ;
import - > annotation ( ) . absolutePath = importPath ;
if ( m_sources . count ( importPath ) | | newSources . count ( importPath ) )
2016-01-12 00:04:39 +00:00
continue ;
2016-06-07 17:44:32 +00:00
ReadFileResult result { false , string ( " File not supplied initially. " ) } ;
if ( m_readFile )
result = m_readFile ( importPath ) ;
if ( result . success )
newSources [ importPath ] = result . contentsOrErrorMesage ;
2016-01-12 00:04:39 +00:00
else
{
auto err = make_shared < Error > ( Error : : Type : : ParserError ) ;
* err < <
errinfo_sourceLocation ( import - > location ( ) ) < <
2016-06-07 17:44:32 +00:00
errinfo_comment ( " Source \" " + importPath + " \" not found: " + result . contentsOrErrorMesage ) ;
2016-01-14 13:47:32 +00:00
m_errors . push_back ( std : : move ( err ) ) ;
2016-01-12 00:04:39 +00:00
continue ;
}
}
return newSources ;
}
2016-06-07 17:44:32 +00:00
string CompilerStack : : applyRemapping ( string const & _path , string const & _context )
{
// Try to find the longest prefix match in all remappings that are active in the current context.
auto isPrefixOf = [ ] ( string const & _a , string const & _b )
{
if ( _a . length ( ) > _b . length ( ) )
return false ;
return std : : equal ( _a . begin ( ) , _a . end ( ) , _b . begin ( ) ) ;
} ;
size_t longestPrefix = 0 ;
string longestPrefixTarget ;
for ( auto const & redir : m_remappings )
{
// Skip if we already have a closer match.
if ( longestPrefix > 0 & & redir . prefix . length ( ) < = longestPrefix )
continue ;
// Skip if redir.context is not a prefix of _context
if ( ! isPrefixOf ( redir . context , _context ) )
continue ;
// Skip if the prefix does not match.
if ( ! isPrefixOf ( redir . prefix , _path ) )
continue ;
longestPrefix = redir . prefix . length ( ) ;
longestPrefixTarget = redir . target ;
}
string path = longestPrefixTarget ;
path . append ( _path . begin ( ) + longestPrefix , _path . end ( ) ) ;
return path ;
}
2014-12-03 16:45:12 +00:00
void CompilerStack : : resolveImports ( )
{
// topological sorting (depth first search) of the import graph, cutting potential cycles
vector < Source const * > sourceOrder ;
set < Source const * > sourcesSeen ;
2016-01-12 00:04:39 +00:00
function < void ( Source const * ) > toposort = [ & ] ( Source const * _source )
2014-12-03 16:45:12 +00:00
{
if ( sourcesSeen . count ( _source ) )
return ;
sourcesSeen . insert ( _source ) ;
2015-08-31 16:44:29 +00:00
for ( ASTPointer < ASTNode > const & node : _source - > ast - > nodes ( ) )
2014-12-03 16:45:12 +00:00
if ( ImportDirective const * import = dynamic_cast < ImportDirective * > ( node . get ( ) ) )
{
2016-01-12 00:04:39 +00:00
string const & path = import - > annotation ( ) . absolutePath ;
solAssert ( ! path . empty ( ) , " " ) ;
solAssert ( m_sources . count ( path ) , " " ) ;
import - > annotation ( ) . sourceUnit = m_sources [ path ] . ast . get ( ) ;
toposort ( & m_sources [ path ] ) ;
2014-12-03 16:45:12 +00:00
}
sourceOrder . push_back ( _source ) ;
} ;
for ( auto const & sourcePair : m_sources )
2015-02-20 17:15:34 +00:00
if ( ! sourcePair . second . isLibrary )
2016-01-12 00:04:39 +00:00
toposort ( & sourcePair . second ) ;
2014-11-11 16:41:48 +00:00
2014-12-03 16:45:12 +00:00
swap ( m_sourceOrder , sourceOrder ) ;
}
2014-11-11 16:41:48 +00:00
2016-01-11 18:40:15 +00:00
bool CompilerStack : : checkLibraryNameClashes ( )
{
bool clashFound = false ;
map < string , SourceLocation > libraries ;
for ( Source const * source : m_sourceOrder )
for ( ASTPointer < ASTNode > const & node : source - > ast - > nodes ( ) )
if ( ContractDefinition * contract = dynamic_cast < ContractDefinition * > ( node . get ( ) ) )
if ( contract - > isLibrary ( ) )
{
if ( libraries . count ( contract - > name ( ) ) )
{
auto err = make_shared < Error > ( Error : : Type : : DeclarationError ) ;
* err < <
errinfo_sourceLocation ( contract - > location ( ) ) < <
errinfo_comment (
" Library \" " + contract - > name ( ) + " \" declared twice "
" (will create ambiguities during linking). "
) < <
errinfo_secondarySourceLocation ( SecondarySourceLocation ( ) . append (
" The other declaration is here: " , libraries [ contract - > name ( ) ]
) ) ;
m_errors . push_back ( err ) ;
2016-01-13 16:28:27 +00:00
clashFound = true ;
2016-01-11 18:40:15 +00:00
}
else
libraries [ contract - > name ( ) ] = contract - > location ( ) ;
}
return ! clashFound ;
}
2015-12-09 16:35:20 +00:00
string CompilerStack : : absolutePath ( string const & _path , string const & _reference ) const
{
// Anything that does not start with `.` is an absolute path.
if ( _path . empty ( ) | | _path . front ( ) ! = ' . ' )
return _path ;
using path = boost : : filesystem : : path ;
path p ( _path ) ;
path result ( _reference ) ;
result . remove_filename ( ) ;
for ( path : : iterator it = p . begin ( ) ; it ! = p . end ( ) ; + + it )
if ( * it = = " .. " )
result = result . parent_path ( ) ;
else if ( * it ! = " . " )
result / = * it ;
return result . string ( ) ;
}
2015-10-07 13:57:17 +00:00
void CompilerStack : : compileContract (
bool _optimize ,
unsigned _runs ,
ContractDefinition const & _contract ,
map < ContractDefinition const * , eth : : Assembly const * > & _compiledContracts
)
{
if ( _compiledContracts . count ( & _contract ) | | ! _contract . annotation ( ) . isFullyImplemented )
return ;
for ( auto const * dependency : _contract . annotation ( ) . contractDependencies )
compileContract ( _optimize , _runs , * dependency , _compiledContracts ) ;
shared_ptr < Compiler > compiler = make_shared < Compiler > ( _optimize , _runs ) ;
compiler - > compileContract ( _contract , _compiledContracts ) ;
Contract & compiledContract = m_contracts . at ( _contract . name ( ) ) ;
compiledContract . compiler = compiler ;
compiledContract . object = compiler - > assembledObject ( ) ;
compiledContract . runtimeObject = compiler - > runtimeObject ( ) ;
_compiledContracts [ compiledContract . contract ] = & compiler - > assembly ( ) ;
Compiler cloneCompiler ( _optimize , _runs ) ;
cloneCompiler . compileClone ( _contract , _compiledContracts ) ;
compiledContract . cloneObject = cloneCompiler . assembledObject ( ) ;
}
2015-02-15 00:00:09 +00:00
std : : string CompilerStack : : defaultContractName ( ) const
{
2015-08-31 16:44:29 +00:00
return contract ( " " ) . contract - > name ( ) ;
2015-02-15 00:00:09 +00:00
}
2015-08-31 16:44:29 +00:00
CompilerStack : : Contract const & CompilerStack : : contract ( string const & _contractName ) const
2014-12-03 16:45:12 +00:00
{
if ( m_contracts . empty ( ) )
BOOST_THROW_EXCEPTION ( CompilerError ( ) < < errinfo_comment ( " No compiled contracts found. " ) ) ;
2014-12-17 17:33:55 +00:00
string contractName = _contractName ;
2014-12-03 16:45:12 +00:00
if ( _contractName . empty ( ) )
2015-01-28 13:16:15 +00:00
// try to find some user-supplied contract
for ( auto const & it : m_sources )
if ( ! StandardSources . count ( it . first ) )
2015-08-31 16:44:29 +00:00
for ( ASTPointer < ASTNode > const & node : it . second . ast - > nodes ( ) )
2015-01-28 13:16:15 +00:00
if ( auto contract = dynamic_cast < ContractDefinition const * > ( node . get ( ) ) )
2015-08-31 16:44:29 +00:00
contractName = contract - > name ( ) ;
2014-12-17 17:33:55 +00:00
auto it = m_contracts . find ( contractName ) ;
2014-12-03 16:45:12 +00:00
if ( it = = m_contracts . end ( ) )
BOOST_THROW_EXCEPTION ( CompilerError ( ) < < errinfo_comment ( " Contract " + _contractName + " not found. " ) ) ;
return it - > second ;
}
2015-08-31 16:44:29 +00:00
CompilerStack : : Source const & CompilerStack : : source ( string const & _sourceName ) const
2014-12-03 16:45:12 +00:00
{
auto it = m_sources . find ( _sourceName ) ;
if ( it = = m_sources . end ( ) )
BOOST_THROW_EXCEPTION ( CompilerError ( ) < < errinfo_comment ( " Given source file not found. " ) ) ;
2015-10-14 18:37:41 +00:00
2014-12-03 16:45:12 +00:00
return it - > second ;
}
2016-07-01 08:14:50 +00:00
string CompilerStack : : computeSourceMapping ( eth : : AssemblyItems const & _items ) const
{
string ret ;
map < string , unsigned > sourceIndicesMap = sourceIndices ( ) ;
int prevStart = - 1 ;
int prevLength = - 1 ;
int prevSourceIndex = - 1 ;
char prevJump = 0 ;
for ( auto const & item : _items )
{
if ( ! ret . empty ( ) )
ret + = " ; " ;
SourceLocation const & location = item . location ( ) ;
int length = location . start ! = - 1 & & location . end ! = - 1 ? location . end - location . start : - 1 ;
int sourceIndex =
location . sourceName & & sourceIndicesMap . count ( * location . sourceName ) ?
sourceIndicesMap . at ( * location . sourceName ) :
- 1 ;
char jump = ' - ' ;
if ( item . getJumpType ( ) = = eth : : AssemblyItem : : JumpType : : IntoFunction )
jump = ' i ' ;
else if ( item . getJumpType ( ) = = eth : : AssemblyItem : : JumpType : : OutOfFunction )
jump = ' o ' ;
unsigned components = 4 ;
if ( jump = = prevJump )
{
components - - ;
if ( sourceIndex = = prevSourceIndex )
{
components - - ;
if ( length = = prevLength )
{
components - - ;
if ( location . start = = prevStart )
components - - ;
}
}
}
if ( components - - > 0 )
{
if ( location . start ! = prevStart )
ret + = std : : to_string ( location . start ) ;
if ( components - - > 0 )
{
ret + = ' : ' ;
if ( length ! = prevLength )
ret + = std : : to_string ( length ) ;
if ( components - - > 0 )
{
ret + = ' : ' ;
if ( sourceIndex ! = prevSourceIndex )
ret + = std : : to_string ( sourceIndex ) ;
if ( components - - > 0 )
{
ret + = ' : ' ;
if ( jump ! = prevJump )
ret + = jump ;
}
}
}
}
prevStart = location . start ;
prevLength = length ;
prevSourceIndex = sourceIndex ;
prevJump = jump ;
}
return ret ;
}