2017-11-06 10:56:19 +01:00
|
|
|
#include "externals.hh"
|
|
|
|
#include "opast.hh"
|
|
|
|
#include <ebcl/Files.hh>
|
|
|
|
#include <ebcl/SRDText.hh>
|
2017-11-10 14:29:36 +01:00
|
|
|
#include <ebcl/Algorithms.hh>
|
2017-11-06 10:56:19 +01:00
|
|
|
|
|
|
|
using namespace ebcl;
|
|
|
|
using namespace opast;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2017-11-07 13:24:01 +01:00
|
|
|
/*============================================================================*/
|
|
|
|
|
|
|
|
|
|
|
|
void PrintStreamError(
|
|
|
|
char const* const prefix ,
|
|
|
|
T_String const& name ,
|
|
|
|
X_StreamError const& error )
|
|
|
|
{
|
|
|
|
T_StringBuilder sb;
|
|
|
|
sb << prefix << " '" << name << "': " << 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 )
|
|
|
|
{
|
|
|
|
sb << error.location( ) << " - " << error.error( ) << "\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-11-07 09:10:17 +01:00
|
|
|
/*============================================================================*/
|
|
|
|
|
2017-11-10 14:29:36 +01:00
|
|
|
T_Array< T_SRDError > parserPrototypes(
|
|
|
|
T_OwnPtr< T_RootNode > const& root )
|
|
|
|
{
|
|
|
|
T_Visitor< opast::A_Node > visitor{ ASTVisitorBrowser };
|
|
|
|
T_Array< T_SRDError > errors;
|
|
|
|
|
|
|
|
enum class E_DataType {
|
|
|
|
UNKNOWN ,
|
|
|
|
ALIAS ,
|
|
|
|
VARIABLE ,
|
|
|
|
FRAMEBUFFER ,
|
|
|
|
INPUT ,
|
|
|
|
PIPELINE ,
|
|
|
|
PROGRAM ,
|
|
|
|
TEXTURE ,
|
|
|
|
};
|
|
|
|
struct T_Decl_ {
|
|
|
|
E_DataType type;
|
|
|
|
T_SRDLocation location;
|
|
|
|
|
|
|
|
T_Decl_( const E_DataType dt ,
|
|
|
|
T_SRDLocation const& loc ) noexcept
|
|
|
|
: type( dt ) , location( loc )
|
|
|
|
{ }
|
|
|
|
};
|
|
|
|
T_KeyValueTable< T_String , T_Decl_ > type;
|
|
|
|
|
|
|
|
visitor.visit( *root , [&]( A_Node& node , bool exit ) -> bool {
|
|
|
|
if ( exit ) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
E_DataType dt{ E_DataType::UNKNOWN };
|
|
|
|
T_String id;
|
|
|
|
T_SRDLocation location;
|
|
|
|
switch ( node.type( ) ) {
|
|
|
|
|
|
|
|
case A_Node::OP_FRAMEBUFFER:
|
|
|
|
dt = E_DataType::FRAMEBUFFER;
|
|
|
|
id = dynamic_cast< T_FramebufferInstrNode& >( node ).id( );
|
|
|
|
location = dynamic_cast< T_FramebufferInstrNode& >( node ).idLocation( );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case A_Node::OP_INPUT:
|
|
|
|
dt = E_DataType::INPUT;
|
|
|
|
id = dynamic_cast< T_InputInstrNode& >( node ).name( );
|
|
|
|
location = dynamic_cast< T_InputInstrNode& >( node ).nameLocation( );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case A_Node::OP_PIPELINE:
|
|
|
|
dt = E_DataType::PIPELINE;
|
|
|
|
id = dynamic_cast< T_PipelineInstrNode& >( node ).id( );
|
|
|
|
location = dynamic_cast< T_PipelineInstrNode& >( node ).idLocation( );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case A_Node::OP_PROGRAM:
|
|
|
|
dt = E_DataType::PROGRAM;
|
|
|
|
id = dynamic_cast< T_ProgramInstrNode& >( node ).id( );
|
|
|
|
location = dynamic_cast< T_ProgramInstrNode& >( node ).idLocation( );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case A_Node::OP_SET:
|
|
|
|
dt = E_DataType::VARIABLE;
|
|
|
|
id = dynamic_cast< T_SetInstrNode& >( node ).id( );
|
|
|
|
location = dynamic_cast< T_SetInstrNode& >( node ).idLocation( );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case A_Node::OP_TEXTURE:
|
|
|
|
dt = E_DataType::TEXTURE;
|
|
|
|
id = dynamic_cast< T_TextureInstrNode& >( node ).id( );
|
|
|
|
location = dynamic_cast< T_TextureInstrNode& >( node ).idLocation( );
|
|
|
|
break;
|
|
|
|
|
|
|
|
// TODO: samplers
|
|
|
|
|
|
|
|
default:
|
|
|
|
return !dynamic_cast< A_ExpressionNode* >( &node );
|
|
|
|
}
|
|
|
|
|
|
|
|
assert( dt != E_DataType::UNKNOWN );
|
|
|
|
T_Decl_ const* const existing( type.get( id ) );
|
|
|
|
if ( !existing ) {
|
|
|
|
type.add( id , T_Decl_{ dt , location } );
|
|
|
|
} else if ( existing->type != dt ) {
|
|
|
|
T_StringBuilder sb;
|
|
|
|
sb << "'" << id << "' redeclared as ";
|
|
|
|
switch ( dt ) {
|
|
|
|
case E_DataType::VARIABLE: sb << "variable"; break;
|
|
|
|
case E_DataType::FRAMEBUFFER: sb << "framebuffer"; break;
|
|
|
|
case E_DataType::INPUT: sb << "input"; break;
|
|
|
|
case E_DataType::PIPELINE: sb << "pipeline"; break;
|
|
|
|
case E_DataType::PROGRAM: sb << "program"; break;
|
|
|
|
case E_DataType::TEXTURE: sb << "texture"; break;
|
|
|
|
default: std::abort( );
|
|
|
|
}
|
|
|
|
sb << "; previous declaration as ";
|
|
|
|
switch ( existing->type ) {
|
|
|
|
case E_DataType::VARIABLE: sb << "variable"; break;
|
|
|
|
case E_DataType::FRAMEBUFFER: sb << "framebuffer"; break;
|
|
|
|
case E_DataType::INPUT: sb << "input"; break;
|
|
|
|
case E_DataType::PIPELINE: sb << "pipeline"; break;
|
|
|
|
case E_DataType::PROGRAM: sb << "program"; break;
|
|
|
|
case E_DataType::TEXTURE: sb << "texture"; break;
|
|
|
|
default: std::abort( );
|
|
|
|
}
|
|
|
|
sb << " at " << existing->location;
|
|
|
|
errors.addNew( std::move( sb ) , location );
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
} );
|
|
|
|
|
|
|
|
return errors;
|
|
|
|
}
|
|
|
|
|
2017-11-06 10:56:19 +01:00
|
|
|
|
2017-11-07 13:24:01 +01:00
|
|
|
/*============================================================================*/
|
2017-11-06 10:56:19 +01:00
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
int main( int argc , char** argv )
|
|
|
|
{
|
|
|
|
// Open file
|
|
|
|
const T_String inputName( argc >= 2 ? argv[ 1 ] : "demo.srd" );
|
|
|
|
T_File input( inputName , E_FileMode::READ_ONLY );
|
|
|
|
try {
|
|
|
|
input.open( );
|
|
|
|
} catch ( X_StreamError const& e ) {
|
|
|
|
PrintStreamError( "Could not open" , inputName , e );
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Load SRD data
|
|
|
|
T_SRDMemoryTarget srdOut;
|
|
|
|
srdOut.clearComments( true ).clearFlushToken( true );
|
|
|
|
try {
|
|
|
|
T_SRDTextReader srdReader{ srdOut };
|
|
|
|
T_FileInputStream fis{ input };
|
|
|
|
srdReader.read( inputName , fis );
|
|
|
|
} catch ( X_StreamError const& e ) {
|
|
|
|
PrintStreamError( "Could not open" , inputName , e );
|
|
|
|
return 1;
|
|
|
|
} catch ( X_SRDErrors const& e ) {
|
|
|
|
T_StringBuilder sb;
|
|
|
|
const auto nErrors( e.errors.size( ) );
|
|
|
|
for ( auto i = 0u ; i < nErrors ; i ++ ) {
|
|
|
|
WriteSRDError( sb , e.errors[ i ] );
|
|
|
|
}
|
|
|
|
sb << "No parsing happened due to format errors\n" << '\0';
|
|
|
|
fprintf( stderr , "%s" , sb.data( ) );
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse the fuck
|
|
|
|
T_Parser parser;
|
|
|
|
if ( parser.parse( srdOut.list( ) ) ) {
|
2017-11-10 14:29:36 +01:00
|
|
|
printf( "Success - now running prototypes\n" );
|
|
|
|
T_Array< T_SRDError > errors{ parserPrototypes( parser.result( ) ) };
|
|
|
|
if ( errors.empty( ) ) {
|
|
|
|
printf( "Success!\n" );
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
T_StringBuilder sb;
|
|
|
|
for ( auto const& err : errors ) {
|
|
|
|
WriteSRDError( sb , err );
|
|
|
|
}
|
|
|
|
sb << "Parser prototypes failed\n" << '\0';
|
|
|
|
fprintf( stderr , "%s" , sb.data( ) );
|
|
|
|
return 4;
|
2017-11-06 10:56:19 +01:00
|
|
|
} else {
|
|
|
|
T_StringBuilder sb;
|
|
|
|
for ( auto const& err : parser.errors( ) ) {
|
|
|
|
WriteSRDError( sb , err );
|
|
|
|
}
|
|
|
|
sb << "Parser failed\n" << '\0';
|
|
|
|
fprintf( stderr , "%s" , sb.data( ) );
|
|
|
|
return 3;
|
|
|
|
}
|
2017-11-06 10:33:18 +01:00
|
|
|
}
|