#include "compiler.h"
#include "builtins/builtins.h"
#include "builtins/helpers.h"
#include "sema/sema.h"
#include "verify/verify.h"
#include "execute/execute.h"
#include "diagnostics/diagnostics.h"
#include "llvm/InitializePasses.h"
#include "llvm/Support/InitLLVM.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Signals.h"
using namespace goose;
using namespace goose::util;
using namespace goose::eir;
using namespace goose::sema;
using namespace goose::diagnostics;
using namespace goose::builtins;
namespace goose::compile
{
Compiler::Compiler( int argc, char** argv ) :
m_pEnv( make_shared< sema::Env >() )
{
llvm::sys::PrintStackTraceOnErrorSignal(*argv);
string cmdArgs;
for( size_t i = 1; i < static_cast< size_t >( argc ); ++i )
{
if( i > 1 )
cmdArgs = cmdArgs + ' ';
cmdArgs = cmdArgs + argv[i];
}
SetupBuiltins( *m_pEnv );
RegisterBuiltinFunc< string() >( *m_pEnv, "Args"_sid,
[cmdArgs]()
{
return cmdArgs;
} );
RegisterBuiltinFunc< void ( string ) >( *m_pEnv, "Print"_sid,
[]( const string& str )
{
cout << str;
} );
llvm::InitializeAllTargets();
llvm::InitializeAllTargetMCs();
llvm::InitializeAllAsmPrinters();
llvm::InitializeAllAsmParsers();
}
uint32_t Compiler::execute( const string& filename )
{
auto result = LoadAndExecuteFile( m_pEnv, filename, builtins::RootIdentity(), GetValueType< uint32_t >(), ToValue< uint32_t >( 1 ) );
if( DiagnosticsManager::GetInstance().errorsWereEmitted() )
return 1;
if( !result )
{
DiagnosticsManager::GetInstance().emitErrorMessage( 0,
format( "{}: coult not be executed.", filename ) );
return 1;
}
if( result->isPoison() )
return 1;
return *FromValue< uint32_t >( *result );
}
optional< Value > Compiler::LoadAndExecuteFile( const ptr< Env >& e, const string& filename, const Term& identity,
const Term& returnType, optional< Value > defRetVal )
{
auto cfg = LoadAndParseFile( e, filename, identity, returnType, defRetVal );
if( !cfg )
return PoisonValue();
if( !cfg->entryBB()->canBeExecuted() )
{
DiagnosticsManager::GetInstance().emitErrorMessage( 0,
format( "{}: can not be executed.", filename ) );
return PoisonValue();
}
execute::VM vm;
return vm.execute( cfg->entryBB() );
}
ptr< cir::CFG > Compiler::LoadAndParseFile( const ptr< Env >& e, const string& filename, const Term& identity,
const Term& returnType, optional< Value > defRetVal )
{
auto& dm = DiagnosticsManager::GetInstance();
assert( returnType == GetValueType< void >() || defRetVal );
ifstream sourcefile( filename.c_str() );
if( !sourcefile.good() )
{
dm.emitErrorMessage( 0,
format( "can't open '{}'.", filename ) );
return nullptr;
}
sema::Context c( e, identity, returnType );
DiagnosticsContext dc( 0, true );
VerbosityContext vc( Verbosity::Normal, true );
auto cfg = make_shared< cir::CFG >( 0 );
cfg->createBB();
cfg->setCurrentBB( cfg->entryBB() );
auto cb = make_shared< CodeBuilder >( cfg );
c.setBuilder( cb );
auto r = make_shared< parse::Resolver >(
make_shared< lex::Lexer >( sourcefile, filename ), c );
parse::Parser p( r );
p.parseSequence();
if( cfg->isPoisoned() )
return cfg;
if( !r->eos() )
{
dm.emitSyntaxErrorMessage( r->currentLocation(), "syntax error." );
return nullptr;
}
if( cfg->currentBB() && !cfg->currentBB()->terminator() )
{
p.flushValue();
cb->destroyAllLiveValues( c );
if( returnType == GetValueType< void >() )
cb->emitTerminator( r->currentLocation(), cir::Ret() );
else if( !defRetVal )
{
dm.emitSyntaxErrorMessage( r->currentLocation(), "missing return statement." );
return nullptr;
}
else
{
auto converted = ConvertValueToType( c, *defRetVal, returnType );
if( holds_alternative< ValUnifyError >( converted ) )
{
switch( get< ValUnifyError >( converted ) )
{
case ValUnifyError::NoSolution:
dm.emitErrorMessage( defRetVal->locationId(), "default return value type mismatch." );
break;
case ValUnifyError::Ambiguous:
dm.emitErrorMessage( defRetVal->locationId(), "ambiguous default return value conversion." );
break;
}
return nullptr;
}
cb->emitTerminator( r->currentLocation(), cir::Ret( get< Value >( converted ) ) );
}
}
verify::Func fv( c, cfg );
if( !fv.verify() )
return nullptr;
return cfg;
}
}