#include "compiler.h"
#include "builtins/builtins.h"
#include "g0api/g0api.h"
#include "sema/sema.h"
// TODO_SSA reenable
// #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 >() )
{
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 );
parse::SetupParsingBuiltins( *m_pEnv );
g0api::SetupG0Api( *m_pEnv );
RegisterBuiltinFunc< string() >( *m_pEnv, "Args"_sid, [cmdArgs]() { return cmdArgs; } );
RegisterBuiltinFunc< void( string ) >(
*m_pEnv, "Print"_sid, []( const string& str ) { cout << str; } );
llvm::InitializeNativeTarget();
llvm::InitializeNativeTargetAsmPrinter();
}
uint32_t Compiler::execute( const string& filename )
{
auto locVarsIdentity = AppendToVectorTerm( builtins::RootG0Identity(), TSID( 0_locvars ) );
m_pEnv->addVisibilityRule( builtins::RootG0Identity(), locVarsIdentity );
auto result = LoadAndExecuteFile( m_pEnv, filename, locVarsIdentity,
GetValueType< uint32_t >(), ToValue< uint32_t >( 1 ) );
if( DiagnosticsManager::GetInstance().errorsWereEmitted() )
return 1;
if( !result )
{
DiagnosticsManager::GetInstance().emitErrorMessage(
0, format( "{}: could 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 )
{
ProfileZoneScoped;
ProfileZoneName( filename.c_str(), filename.size() );
auto cfg = LoadAndParseFile( e, filename, identity, returnType, defRetVal );
if( !cfg || cfg->isPoisoned() )
return PoisonValue();
// ofstream out( "gg.txt" );
cout << *cfg;
if( !cfg->entryBB()->canBeExecuted() )
{
DiagnosticsManager::GetInstance().emitErrorMessage(
0, format( "{}: can not be executed.", filename ) );
return PoisonValue();
}
sema::Context c( e, identity, returnType );
Context::DefaultContextGuard dfg( c );
execute::VM vm;
return vm.execute( *cfg );
}
ptr< cir::CFG > Compiler::LoadAndParseFile( const ptr< Env >& e, const string& filename,
const Term& identity, const Term& returnType, optional< Value > defRetVal )
{
ProfileZoneScoped;
ProfileZoneName( filename.c_str(), filename.size() );
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 );
Context::DefaultContextGuard dfg( c );
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( ToValue( TypeWrapper< ptr< CodeBuilder > >( 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 >() )
cfg->emitTerminator( r->currentLocation(), cir::RetVoid( r->currentLocation() ) );
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;
}
cfg->currentBB()->append( get< Value >( converted ) );
cfg->emitTerminator( r->currentLocation(), cir::Ret( r->currentLocation() ) );
}
}
// TODO_SSA reenable or not
// ReindexVars( cfg );
// TODO_SSA reenable
/*verify::Func fv( c, cfg, returnType );
if( !fv.verify() )
return nullptr;*/
return cfg;
}
} // namespace goose::compile