297 lines
7 KiB
C++
297 lines
7 KiB
C++
#include "externals.hh"
|
|
|
|
#include "common.hh"
|
|
#include "c-opast.hh"
|
|
#include "c-ops.hh"
|
|
#include "c-opcomp.hh"
|
|
#include "c-opopt.hh"
|
|
|
|
#include <getopt.h>
|
|
|
|
#include <ebcl/Files.hh>
|
|
#include <ebcl/SRDText.hh>
|
|
#include <ebcl/Algorithms.hh>
|
|
|
|
using namespace ebcl;
|
|
using namespace opast;
|
|
|
|
#define M_LOGSTR( S , L ) \
|
|
logger( [](){ return T_StringBuilder{ S }; } , L )
|
|
|
|
namespace {
|
|
|
|
const struct option CmdLineOpts_[] = {
|
|
{ "log-level" , required_argument , 0 , 'L' } ,
|
|
{ "source-path" , required_argument , 0 , 's' } ,
|
|
{ "config" , required_argument , 0 , 'c' } ,
|
|
{ 0 , 0 , 0 , 0 }
|
|
};
|
|
|
|
/*============================================================================*/
|
|
|
|
|
|
void PrintStreamError(
|
|
char const* const prefix ,
|
|
T_FSPath const& name ,
|
|
X_StreamError const& error ) noexcept
|
|
{
|
|
const T_FSPath rp{ ([&]() {
|
|
if ( error.path( ) ) {
|
|
return *( error.path( ) );
|
|
}
|
|
return name;
|
|
}()).makeRelative( Filesystem::Cwd( ) ) };
|
|
|
|
T_StringBuilder sb;
|
|
sb << prefix << " '" << rp << "': " << error.what( );
|
|
if ( error.code( ) == E_StreamError::SYSTEM_ERROR ) {
|
|
sb << " (error code " << error.systemError( ) << ")";
|
|
}
|
|
sb << '\n' << '\0';
|
|
fprintf( stderr , "%s" , sb.data( ) );
|
|
}
|
|
|
|
void WriteSRDError(
|
|
T_StringBuilder& sb ,
|
|
T_SRDError const& error ) noexcept
|
|
{
|
|
switch ( error.type( ) ) {
|
|
case E_SRDErrorType::ERROR:
|
|
sb << "[ERROR";
|
|
break;
|
|
case E_SRDErrorType::WARNING:
|
|
sb << " [WARN";
|
|
break;
|
|
case E_SRDErrorType::NOTE:
|
|
sb << " [NOTE";
|
|
break;
|
|
}
|
|
sb << '(' << error.location( ) << ")] " << error.error( ) << '\n';
|
|
}
|
|
|
|
void WriteSRDErrors(
|
|
char const* const title ,
|
|
T_SRDErrors const& errors ) noexcept
|
|
{
|
|
T_StringBuilder sb;
|
|
sb << "===== " << title << '\n';
|
|
const auto nErrors( errors.size( ) );
|
|
for ( auto i = 0u ; i < nErrors ; i ++ ) {
|
|
WriteSRDError( sb , errors[ i ] );
|
|
}
|
|
sb << '\0';
|
|
fprintf( stderr , "%s" , sb.data( ) );
|
|
}
|
|
|
|
void WriteSRDErrors(
|
|
char const* const title ,
|
|
T_Array< T_SRDError > const& errors ) noexcept
|
|
{
|
|
T_StringBuilder sb;
|
|
sb << "===== " << title << '\n';
|
|
const auto nErrors( errors.size( ) );
|
|
for ( auto i = 0u ; i < nErrors ; i ++ ) {
|
|
WriteSRDError( sb , errors[ i ] );
|
|
}
|
|
sb << '\0';
|
|
fprintf( stderr , "%s" , sb.data( ) );
|
|
}
|
|
|
|
T_FSPath FilePath(
|
|
T_FSPath const& path ,
|
|
char const* const name ) noexcept
|
|
{
|
|
const T_FSPath fp{ name };
|
|
if ( fp.isAbsolute( ) ) {
|
|
return fp.canonical( );
|
|
}
|
|
return ( path + fp ).canonical( );
|
|
}
|
|
|
|
|
|
/*============================================================================*/
|
|
|
|
} // namespace
|
|
|
|
int main( int argc , char** argv )
|
|
{
|
|
// Parse command line
|
|
T_Optional< uint32_t > oLogLevel;
|
|
T_String oSrcPath;
|
|
T_String oBuildCfg;
|
|
int c;
|
|
while ( ( c = getopt_long( argc , argv , "L:s:c:" , CmdLineOpts_ , nullptr ) ) != -1 ) {
|
|
switch ( c ) {
|
|
|
|
case 'L':
|
|
oLogLevel = uint32_t( atoi( optarg ) );
|
|
break;
|
|
|
|
case 's':
|
|
if ( oSrcPath ) {
|
|
fprintf( stderr , "Duplicate source path\n" );
|
|
return EXIT_FAILURE;
|
|
}
|
|
oSrcPath = optarg;
|
|
break;
|
|
|
|
case 'c':
|
|
if ( oBuildCfg ) {
|
|
fprintf( stderr , "Duplicate build configuration\n" );
|
|
return EXIT_FAILURE;
|
|
}
|
|
oBuildCfg = optarg;
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
// Initialise common layer
|
|
const T_FSPath srcPath{ ([&](){
|
|
const T_FSPath raw{ oSrcPath };
|
|
if ( !raw.isAbsolute( ) ) {
|
|
return ( Filesystem::Cwd( ) + raw ).canonical( );
|
|
}
|
|
return raw.canonical( );
|
|
})() };
|
|
if ( !srcPath.isValid( ) ) {
|
|
fprintf( stderr , "Invalid source path\n" );
|
|
return EXIT_FAILURE;
|
|
}
|
|
Common common{ srcPath };
|
|
|
|
// Logger setup
|
|
const uint32_t logLevel{ oLogLevel ? *oLogLevel : 0 };
|
|
const auto logger{ [=]( F_OPGenLog func , uint32_t level ) {
|
|
if ( level > logLevel ) {
|
|
return;
|
|
}
|
|
auto sb{ func( ) };
|
|
sb << '\0';
|
|
printf( "(%d) %s\n" , level , sb.data( ) );
|
|
} };
|
|
|
|
// Build configurations
|
|
M_LOGSTR( "Loading build configurations" , 1 );
|
|
const T_BuildConfiguration cfg{ [&]() {
|
|
try {
|
|
T_BuildConfigurations cfs{
|
|
T_BuildConfigurationLoader{ }.load( )
|
|
};
|
|
if ( oBuildCfg && !cfs.contains( oBuildCfg ) ) {
|
|
fprintf( stderr , "===== BUILD CONFIGURATIONS\n" );
|
|
fprintf( stderr , "Build configuration not found\n" );
|
|
exit( EXIT_FAILURE );
|
|
}
|
|
if ( oBuildCfg ) {
|
|
return *cfs.get( oBuildCfg );
|
|
}
|
|
if ( cfs.size( ) ) {
|
|
return cfs[ 0 ];
|
|
}
|
|
return T_BuildConfiguration{ };
|
|
|
|
} catch ( X_StreamError const& e ) {
|
|
fprintf( stderr , "===== BUILD CONFIGURATIONS\n" );
|
|
PrintStreamError( "Could not open" ,
|
|
Common::Project( ).pathOf( "build.srd" ) ,
|
|
e );
|
|
exit( EXIT_FAILURE );
|
|
|
|
} catch ( X_SRDErrors const& e ) {
|
|
WriteSRDErrors( "BUILD CONFIGURATIONS" , e.errors );
|
|
exit( EXIT_FAILURE );
|
|
}
|
|
} () };
|
|
|
|
// Load curves
|
|
M_LOGSTR( "Loading curves data" , 1 );
|
|
const auto curvesFile{ FilePath( srcPath , "curves.srd" ) };
|
|
T_SyncCurvesIO::T_Data p;
|
|
try {
|
|
p = T_SyncCurvesIO{}.load( curvesFile.toString( ) );
|
|
} catch ( ebcl::X_StreamError const& e ) {
|
|
fprintf( stderr , "===== CURVES DATA\n" );
|
|
PrintStreamError( "Could not open" , curvesFile , e );
|
|
exit( EXIT_FAILURE );
|
|
|
|
} catch ( ebcl::X_SRDErrors const& e ) {
|
|
WriteSRDErrors( "CURVES DATA" , e.errors );
|
|
exit( EXIT_FAILURE );
|
|
}
|
|
|
|
// Open and load script
|
|
M_LOGSTR( "Loading script" , 1 );
|
|
char const* const scriptName{ "demo.srd" };
|
|
const auto scriptPath{ Common::Project( ).pathOf( scriptName ) };
|
|
T_SRDMemoryTarget srdOut;
|
|
{
|
|
T_File input( scriptPath , E_FileMode::READ_ONLY );
|
|
try {
|
|
input.open( );
|
|
} catch ( X_StreamError const& e ) {
|
|
PrintStreamError( "Could not open" , scriptPath , e );
|
|
return 1;
|
|
}
|
|
srdOut.clearComments( true ).clearFlushToken( true );
|
|
try {
|
|
T_SRDTextReader srdReader{ srdOut };
|
|
T_FileInputStream fis{ input };
|
|
srdReader.read( scriptName , fis );
|
|
} catch ( X_StreamError const& e ) {
|
|
fprintf( stderr , "===== SCRIPT\n" );
|
|
PrintStreamError( "Could not open" , scriptPath , e );
|
|
exit( EXIT_FAILURE );
|
|
} catch ( X_SRDErrors const& e ) {
|
|
WriteSRDErrors( "SCRIPT" , e.errors );
|
|
exit( EXIT_FAILURE );
|
|
}
|
|
}
|
|
|
|
// Parse script
|
|
M_LOGSTR( "Parsing script" , 1 );
|
|
T_OpsParser parser;
|
|
parser.setLogger( logger );
|
|
if ( !parser.parse( scriptPath , srdOut.list( ) ) ) {
|
|
WriteSRDErrors( "SCRIPT" , parser.errors( ) );
|
|
exit( EXIT_FAILURE );
|
|
}
|
|
auto parsed{ parser.result( ) };
|
|
|
|
// Optimize
|
|
if ( cfg.optimize ) {
|
|
M_LOGSTR( "Optimizing script tree" , 1 );
|
|
opopt::T_OptData od;
|
|
od.logger = logger;
|
|
if ( !cfg.resolutionChooser && cfg.cfFixedSize ) {
|
|
od.fixedSize = cfg.resolutions[ 0 ]; // FIXME
|
|
}
|
|
if ( cfg.cfInputs ) {
|
|
od.curves = &p.curves;
|
|
}
|
|
|
|
bool didStuff;
|
|
do {
|
|
didStuff = false;
|
|
if ( cfg.constantFolding && opopt::FoldConstants( *parsed , od ) ) {
|
|
didStuff = true;
|
|
}
|
|
if ( cfg.constantPropagation && opopt::PropagateConstants( *parsed , od ) ) {
|
|
didStuff = true;
|
|
}
|
|
if ( cfg.deadCodeElimination && opopt::RemoveDeadCode( *parsed , od ) ) {
|
|
didStuff = true;
|
|
}
|
|
if ( cfg.inlineFunctions && opopt::InlineFunctions( *parsed , od ) ) {
|
|
didStuff = true;
|
|
}
|
|
} while ( didStuff );
|
|
}
|
|
|
|
// Compile
|
|
M_LOGSTR( "Compiling script" , 1 );
|
|
T_OpsCompiler compiler( true );
|
|
compiler.setLogger( logger );
|
|
compiler.compile( *parsed );
|
|
return 0;
|
|
}
|