#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/Support/InitLLVM.h"
#include "llvm/Support/TargetSelect.h"
using namespace goose;
using namespace goose::util;
using namespace goose::ir;
using namespace goose::sema;
using namespace goose::diagnostics;
namespace goose::compile
{
Compiler::Compiler( int argc, char** argv ) :
m_pEnv( make_shared< sema::Env >() )
{
llvm::InitLLVM( argc, argv );
string cmdArgs;
for( size_t i = 1; i < static_cast< size_t >( argc ); ++i )
{
if( i > 1 )
cmdArgs = cmdArgs + ' ';
cmdArgs = cmdArgs + argv[i];
}
builtins::SetupBuiltins( *m_pEnv );
builtins::RegisterBuiltinFunc< string() >( *m_pEnv, "Args"_sid,
[cmdArgs]()
{
return cmdArgs;
} );
builtins::RegisterBuiltinFunc< void ( string ) >( *m_pEnv, "Print"_sid,
[]( const string& str )
{
cout << str;
} );
llvm::InitializeAllTargetInfos();
llvm::InitializeAllTargets();
llvm::InitializeAllTargetMCs();
llvm::InitializeAllAsmParsers();
llvm::InitializeAllAsmPrinters();
}
uint32_t Compiler::execute( const string& filename )
{
auto identity = sema::InjectDomainIntoIdentity( builtins::RootIdentity(), sema::DomainCompileTime() );
auto result = LoadAndExecuteFile( m_pEnv, filename, identity, GetValueType< uint32_t >() );
if( DiagnosticsManager::GetInstance().errorsWereEmitted() )
return 0;
if( !result )
return 1;
if( result->isPoison() )
return 0;
return *FromValue< uint32_t >( *result );
}
optional< Value > Compiler::LoadAndExecuteFile( const ptr< Env >& e, const string& filename, const Term& identity, optional< Term > returnType )
{
auto cfg = LoadAndParseFile( e, filename, identity, returnType );
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< llr::CFG > Compiler::LoadAndParseFile( const ptr< Env >& e, const string& filename, const Term& identity, optional< Term > returnType )
{
ifstream sourcefile( filename.c_str() );
if( !sourcefile.good() )
{
DiagnosticsManager::GetInstance().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 r = make_shared< parse::Resolver >(
make_shared< lex::Lexer >( sourcefile, filename ), c );
parse::Parser p( r );
auto cfg = make_shared< llr::CFG >( 0 );
cfg->createBB();
p.setCFG( cfg );
p.cfg()->setCurrentBB( cfg->entryBB() );
p.parseSequence();
if( cfg->isPoisoned() )
return cfg;
if( !r->eos() )
{
DiagnosticsManager::GetInstance().emitSyntaxErrorMessage(
r->getCurrentLocation(), "syntax error." );
}
if( p.cfg()->currentBB() && !cfg->currentBB()->terminator() )
{
p.emitTerminator( llr::Ret() );
if( returnType == GetValueType< void >() )
p.emitTerminator( llr::Ret() );
}
verify::Func fv( cfg );
if( !fv.verify() )
return nullptr;
return cfg;
}
}