#include "externals.hh" #include "opast.hh" #include #include #include using namespace ebcl; using namespace opast; namespace { /*============================================================================*/ 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"; } /*============================================================================*/ 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; } /*============================================================================*/ } // 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( ) ) ) { 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; } 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; } }