diff --git a/parsercheck.cc b/parsercheck.cc index a1a8cc1..63b7c7b 100644 --- a/parsercheck.cc +++ b/parsercheck.cc @@ -2,6 +2,7 @@ #include "opast.hh" #include #include +#include using namespace ebcl; using namespace opast; @@ -35,6 +36,121 @@ void WriteSRDError( /*============================================================================*/ +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; +} + /*============================================================================*/ @@ -76,8 +192,20 @@ int main( int argc , char** argv ) // Parse the fuck T_Parser parser; if ( parser.parse( srdOut.list( ) ) ) { - printf( "Success!\n" ); - return 0; + 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( ) ) {